Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -952,6 +952,10 @@ "multiple ellipses in pack capture">; def err_capture_default_first : Error< "capture default must be first">; +def ext_decl_attrs_on_lambda : ExtWarn< + "an attribute specifier sequence in this position is a Clang extension">, + InGroup>; + // C++17 lambda expressions def err_expected_star_this_capture : Error< "expected 'this' following '*' in lambda capture list">; Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ clang/lib/Parse/ParseExprCXX.cpp @@ -1302,6 +1302,17 @@ } } + // Implement WG21 P2173, which allows attributes immediately before the + // lambda declarator and applies them to the corresponding function operator + // or operator template declaration. We accept this as a conforming extension + // in all language modes that support lambdas. + if (isCXX11AttributeSpecifier()) { + // FIXME: if the paper is adopted by WG21, this diagnostic should be + // replaced with one about it being an extension in older standard modes. + Diag(Tok.getLocation(), diag::ext_decl_attrs_on_lambda); + MaybeParseCXX11Attributes(D); + } + TypeResult TrailingReturnType; SourceLocation TrailingReturnTypeLoc; if (Tok.is(tok::l_paren)) { Index: clang/test/AST/ast-dump-lambda.cpp =================================================================== --- clang/test/AST/ast-dump-lambda.cpp +++ clang/test/AST/ast-dump-lambda.cpp @@ -33,13 +33,14 @@ []() mutable {}; []() noexcept {}; []() -> int { return 0; }; + [] [[noreturn]] () {}; } // CHECK:Dumping test: -// CHECK-NEXT:FunctionTemplateDecl {{.*}} <{{.*}}ast-dump-lambda.cpp:15:1, line:36:1> line:15:32{{( imported)?}} test +// CHECK-NEXT:FunctionTemplateDecl {{.*}} <{{.*}}ast-dump-lambda.cpp:15:1, line:37:1> line:15:32{{( imported)?}} test // CHECK-NEXT:|-TemplateTypeParmDecl {{.*}} col:23{{( imported)?}} referenced typename depth 0 index 0 ... Ts -// CHECK-NEXT:`-FunctionDecl {{.*}} line:15:32{{( imported)?}} test 'void (Ts...)' +// CHECK-NEXT:`-FunctionDecl {{.*}} line:15:32{{( imported)?}} test 'void (Ts...)' // CHECK-NEXT: |-ParmVarDecl {{.*}} col:43{{( imported)?}} referenced a 'Ts...' pack -// CHECK-NEXT: `-CompoundStmt {{.*}} +// CHECK-NEXT: `-CompoundStmt {{.*}} // CHECK-NEXT: |-DeclStmt {{.*}} // CHECK-NEXT: | `-CXXRecordDecl {{.*}} line:16:10{{( imported)?}}{{( )?}} struct V definition // CHECK-NEXT: | |-DefinitionData empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init @@ -275,7 +276,25 @@ // CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)() noexcept 'auto (*() const noexcept)() noexcept' inline // CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto () noexcept' static inline // CHECK-NEXT: | `-CompoundStmt {{.*}} -// CHECK-NEXT: `-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:35:3)' +// CHECK-NEXT: |-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:35:3)' +// CHECK-NEXT: | |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition +// CHECK-NEXT: | | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init +// CHECK-NEXT: | | | |-DefaultConstructor defaulted_is_constexpr +// CHECK-NEXT: | | | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveConstructor exists simple trivial needs_implicit +// CHECK-NEXT: | | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param +// CHECK-NEXT: | | | |-MoveAssignment +// CHECK-NEXT: | | | `-Destructor simple irrelevant trivial needs_implicit +// CHECK-NEXT: | | |-CXXMethodDecl {{.*}} col:3{{( imported)?}} operator() 'auto () const -> int' inline +// CHECK-NEXT: | | | `-CompoundStmt {{.*}} +// CHECK-NEXT: | | | `-ReturnStmt {{.*}} +// CHECK-NEXT: | | | `-IntegerLiteral {{.*}} 'int' 0 +// CHECK-NEXT: | | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline +// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto () -> int' static inline +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | `-ReturnStmt {{.*}} +// CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 0 +// CHECK-NEXT: `-LambdaExpr {{.*}} '(lambda at {{.*}}ast-dump-lambda.cpp:36:3)' // CHECK-NEXT: |-CXXRecordDecl {{.*}} col:3{{( imported)?}} implicit{{( )?}} class definition // CHECK-NEXT: | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init // CHECK-NEXT: | | |-DefaultConstructor defaulted_is_constexpr @@ -284,12 +303,9 @@ // CHECK-NEXT: | | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param // CHECK-NEXT: | | |-MoveAssignment // CHECK-NEXT: | | `-Destructor simple irrelevant trivial needs_implicit -// CHECK-NEXT: | |-CXXMethodDecl {{.*}} col:3{{( imported)?}} operator() 'auto () const -> int' inline -// CHECK-NEXT: | | `-CompoundStmt {{.*}} -// CHECK-NEXT: | | `-ReturnStmt {{.*}} -// CHECK-NEXT: | | `-IntegerLiteral {{.*}} 'int' 0 -// CHECK-NEXT: | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline -// CHECK-NEXT: | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto () -> int' static inline -// CHECK-NEXT: `-CompoundStmt {{.*}} -// CHECK-NEXT: `-ReturnStmt {{.*}} -// CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 0 +// CHECK-NEXT: | |-CXXMethodDecl {{.*}} col:3{{( imported)?}} operator() 'auto () const' inline +// CHECK-NEXT: | | |-CompoundStmt {{.*}} +// CHECK-NEXT: | | `-CXX11NoReturnAttr {{.*}} +// CHECK-NEXT: | |-CXXConversionDecl {{.*}} col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline +// CHECK-NEXT: | `-CXXMethodDecl {{.*}} col:3{{( imported)?}} implicit __invoke 'auto ()' static inline +// CHECK-NEXT: `-CompoundStmt {{.*}} Index: clang/test/Parser/cxx0x-lambda-expressions.cpp =================================================================== --- clang/test/Parser/cxx0x-lambda-expressions.cpp +++ clang/test/Parser/cxx0x-lambda-expressions.cpp @@ -101,7 +101,6 @@ } 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}} @@ -116,6 +115,14 @@ []() __attribute__((noreturn)) mutable { while(1); }; []() mutable __attribute__((noreturn)) { while(1); }; // expected-error {{expected body of lambda expression}} + + // Testing support for P2173 on adding attributes to the declaration + // rather than the type. + [] [[]] () {}; // expected-warning {{an attribute specifier sequence in this position is a Clang extension}} +#if __cplusplus > 201703L + [] [[]] () {}; // expected-warning {{an attribute specifier sequence in this position is a Clang extension}} +#endif + [] [[]] {}; // expected-warning {{an attribute specifier sequence in this position is a Clang extension}} } };