diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 439fb077da2a..f10ca6ab784e 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -995,7 +995,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( ParsedAttributes Attr(AttrFactory); SmallVector ParamInfo; SourceLocation EllipsisLoc; - if (Tok.isNot(tok::r_paren)) { Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth); @@ -1009,6 +1008,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( SourceLocation RParenLoc = T.getCloseLocation(); DeclEndLoc = RParenLoc; + // GNU-style attributes must be parsed before the mutable specifier to be + // compatible with GCC. + MaybeParseGNUAttributes(Attr, &DeclEndLoc); + // Parse 'mutable'[opt]. SourceLocation MutableLoc; if (TryConsumeToken(tok::kw_mutable, MutableLoc)) @@ -1067,6 +1070,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( TrailingReturnType), Attr, DeclEndLoc); } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow) || + Tok.is(tok::kw___attribute) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute // specifier, or the result type. Deal with this. @@ -1074,6 +1078,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( switch (Tok.getKind()) { case tok::kw_mutable: TokKind = 0; break; case tok::arrow: TokKind = 1; break; + case tok::kw___attribute: case tok::l_square: TokKind = 2; break; default: llvm_unreachable("Unknown token kind"); } @@ -1083,7 +1088,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( << FixItHint::CreateInsertion(Tok.getLocation(), "() "); SourceLocation DeclLoc = Tok.getLocation(); SourceLocation DeclEndLoc = DeclLoc; - + + // GNU-style attributes must be parsed before the mutable specifier to be + // compatible with GCC. + ParsedAttributes Attr(AttrFactory); + MaybeParseGNUAttributes(Attr, &DeclEndLoc); + // Parse 'mutable', if it's there. SourceLocation MutableLoc; if (Tok.is(tok::kw_mutable)) { @@ -1092,7 +1102,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } // Parse attribute-specifier[opt]. - ParsedAttributes Attr(AttrFactory); MaybeParseCXX11Attributes(Attr, &DeclEndLoc); // Parse the return type, if there is one. diff --git a/clang/test/Misc/ast-dump-attr.cpp b/clang/test/Misc/ast-dump-attr.cpp index bb4be5b057a0..dde7ba3e094f 100644 --- a/clang/test/Misc/ast-dump-attr.cpp +++ b/clang/test/Misc/ast-dump-attr.cpp @@ -114,3 +114,18 @@ extern "C" int printf(const char *format, ...); int __attribute__((cdecl)) TestOne(void), TestTwo(void); // CHECK: FunctionDecl{{.*}}TestOne{{.*}}__attribute__((cdecl)) // CHECK: FunctionDecl{{.*}}TestTwo{{.*}}__attribute__((cdecl)) + +void func() { + auto Test = []() __attribute__((no_thread_safety_analysis)) {}; + // CHECK: CXXMethodDecl{{.*}}operator() 'void (void) const' + // CHECK: NoThreadSafetyAnalysisAttr + + // Because GNU's noreturn applies to the function type, and this lambda does + // not have a capture list, the call operator and the function pointer + // conversion should both be noreturn, but the method should not contain a + // NoReturnAttr because the attribute applied to the type. + auto Test2 = []() __attribute__((noreturn)) { while(1); }; + // CHECK: CXXMethodDecl{{.*}}operator() 'void (void) __attribute__((noreturn)) const' + // CHECK-NOT: NoReturnAttr + // CHECK: CXXConversionDecl{{.*}}operator void (*)() __attribute__((noreturn)) +} diff --git a/clang/test/Parser/cxx0x-lambda-expressions.cpp b/clang/test/Parser/cxx0x-lambda-expressions.cpp index e4151dc8888f..9ce24cbb04ae 100644 --- a/clang/test/Parser/cxx0x-lambda-expressions.cpp +++ b/clang/test/Parser/cxx0x-lambda-expressions.cpp @@ -67,6 +67,7 @@ class C { void attributes() { [] [[]] {}; // expected-error {{lambda requires '()' before attribute specifier}} + [] __attribute__((noreturn)) {}; // expected-error {{lambda requires '()' before attribute specifier}} []() [[]] mutable {}; // expected-error {{expected body of lambda expression}} @@ -75,5 +76,10 @@ class C { []() mutable [[]] -> void {}; []() mutable noexcept [[]] -> void {}; -} + // Testing GNU-style attributes on lambdas -- the attribute is specified + // before the mutable specifier instead of after (unlike C++11). + []() __attribute__((noreturn)) mutable { while(1); }; + []() mutable + __attribute__((noreturn)) { while(1); }; // expected-error {{expected body of lambda expression}} + } };