diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d2ec7aa48b..08519410dd 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4038,7 +4038,8 @@ void Parser::ParseParenDeclarator(Declarator &D) { } else if (Tok.is(tok::r_paren) || // 'int()' is a function. (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) && NextToken().is(tok::r_paren)) || // C++ int(...) - isDeclarationSpecifier()) { // 'int(int)' is a function. + isDeclarationSpecifier() || // 'int(int)' is a function. + isCXX11AttributeSpecifier()) { // 'int([[]]int)' is a function. // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is // considered to be a type, not a K&R identifier-list. isGrouping = false; @@ -4318,9 +4319,9 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// after the opening parenthesis. This function will not parse a K&R-style /// identifier list. /// -/// D is the declarator being parsed. If attrs is non-null, then the caller -/// parsed those arguments immediately after the open paren - they should be -/// considered to be the first argument of a parameter. +/// D is the declarator being parsed. If FirstArgAttrs is non-null, then the +/// caller parsed those arguments immediately after the open paren - they should +/// be considered to be part of the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will /// be the location of the ellipsis, if any was parsed. @@ -4343,15 +4344,18 @@ void Parser::ParseFunctionDeclaratorIdentifierList( /// [C++] declaration-specifiers abstract-declarator[opt] /// '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes +/// [C++11] attribute-specifier-seq parameter-declaration /// void Parser::ParseParameterDeclarationClause( Declarator &D, - ParsedAttributes &attrs, + ParsedAttributes &FirstArgAttrs, SmallVector &ParamInfo, SourceLocation &EllipsisLoc) { while (1) { if (Tok.is(tok::ellipsis)) { + // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq + // before deciding this was a parameter-declaration-clause. EllipsisLoc = ConsumeToken(); // Consume the ellipsis. break; } @@ -4360,6 +4364,9 @@ void Parser::ParseParameterDeclarationClause( // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS(AttrFactory); + // Parse any C++11 attributes. + MaybeParseCXX0XAttributes(DS.getAttributes()); + // Skip any Microsoft attributes before a param. if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) ParseMicrosoftAttributes(DS.getAttributes()); @@ -4368,12 +4375,10 @@ void Parser::ParseParameterDeclarationClause( // If the caller parsed attributes for the first argument, add them now. // Take them so that we only apply the attributes to the first parameter. - // FIXME: If we saw an ellipsis first, this code is not reached. Are the - // attributes lost? Should they even be allowed? // FIXME: If we can leave the attributes in the token stream somehow, we can - // get rid of a parameter (attrs) and this statement. It might be too much - // hassle. - DS.takeAttributesFrom(attrs); + // get rid of a parameter (FirstArgAttrs) and this statement. It might be + // too much hassle. + DS.takeAttributesFrom(FirstArgAttrs); ParseDeclarationSpecifiers(DS); diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 5ce6b2b91c..28c5e8b673 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -1322,6 +1322,11 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { return TPResult::False(); } + // An attribute-specifier-seq here is a sign of a function declarator. + if (isCXX11AttributeSpecifier(/*Disambiguate*/false, + /*OuterMightBeMessageSend*/true)) + return TPResult::True(); + ParsedAttributes attrs(AttrFactory); MaybeParseMicrosoftAttributes(attrs); diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp index bf73e0845a..f97995e975 100644 --- a/test/Parser/cxx0x-attributes.cpp +++ b/test/Parser/cxx0x-attributes.cpp @@ -71,6 +71,10 @@ void foo () { (void)s.arr[ [] { return 0; }() ]; // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} int n = __builtin_offsetof(S, arr[ [] { return 0; }() ]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} + void bar [[noreturn]] ([[]] int i, [[]] int j); + using FuncType = void ([[]] int); + void baz([[]]...); // expected-error {{expected parameter declarator}} + [[]] return; } diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm index fead1d1b46..0875b66e21 100644 --- a/test/Parser/objcxx11-attributes.mm +++ b/test/Parser/objcxx11-attributes.mm @@ -34,6 +34,18 @@ void f(X *noreturn) { [[int(), noreturn]]; [[class, test(foo 'x' bar),,,]]; [[bitand, noreturn]]; + + [[noreturn]]int(e)(); + + // A function taking a noreturn function. + int(f)([[noreturn]] int()); + f(e); + + // Variables initialized by a message send. + int(g)([[noreturn getSelf] getSize]); + int(h)([[noreturn]{return noreturn;}() getSize]); + + int i = g + h; } template void f(Ts ...x) {