Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -264,6 +264,9 @@ def CXXPre20Compat : DiagGroup<"c++98-c++11-c++14-c++17-compat">; def CXXPre20CompatPedantic : DiagGroup<"c++98-c++11-c++14-c++17-compat-pedantic", [CXXPre20Compat]>; +def CXXPre2BCompat : DiagGroup<"c++98-c++11-c++14-c++17-c++20-compat">; +def CXXPre2BCompatPedantic : + DiagGroup<"c++98-c++11-c++14-c++17-c++20-compat-pedantic", [CXXPre2BCompat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -277,7 +280,8 @@ CXX98CompatUnnamedTypeTemplateArgs, CXXPre14Compat, CXXPre17Compat, - CXXPre20Compat]>; + CXXPre20Compat, + CXXPre2BCompat]>; // Warnings for C++11 features which are Extensions in C++98 mode. def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat, @@ -285,7 +289,8 @@ CXX98CompatExtraSemi, CXXPre14CompatPedantic, CXXPre17CompatPedantic, - CXXPre20CompatPedantic]>; + CXXPre20CompatPedantic, + CXXPre2BCompatPedantic]>; def CXX11Narrowing : DiagGroup<"c++11-narrowing">; @@ -314,33 +319,40 @@ CXX11CompatDeprecatedWritableStr, CXXPre14Compat, CXXPre17Compat, - CXXPre20Compat]>; + CXXPre20Compat, + CXXPre2BCompat]>; def : DiagGroup<"c++0x-compat", [CXX11Compat]>; def CXX11CompatPedantic : DiagGroup<"c++11-compat-pedantic", [CXX11Compat, CXXPre14CompatPedantic, CXXPre17CompatPedantic, - CXXPre20CompatPedantic]>; + CXXPre20CompatPedantic, + CXXPre2BCompatPedantic]>; def CXX14Compat : DiagGroup<"c++14-compat", [CXXPre17Compat, - CXXPre20Compat]>; + CXXPre20Compat, + CXXPre2BCompat]>; def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", [CXX14Compat, CXXPre17CompatPedantic, - CXXPre20CompatPedantic]>; + CXXPre20CompatPedantic, + CXXPre2BCompatPedantic]>; def CXX17Compat : DiagGroup<"c++17-compat", [DeprecatedRegister, DeprecatedIncrementBool, CXX17CompatMangling, - CXXPre20Compat]>; + CXXPre20Compat, + CXXPre2BCompat]>; def CXX17CompatPedantic : DiagGroup<"c++17-compat-pedantic", [CXX17Compat, - CXXPre20CompatPedantic]>; + CXXPre20CompatPedantic, + CXXPre2BCompatPedantic]>; def : DiagGroup<"c++1z-compat", [CXX17Compat]>; -def CXX20Compat : DiagGroup<"c++20-compat">; +def CXX20Compat : DiagGroup<"c++20-compat", [CXXPre2BCompat]>; def CXX20CompatPedantic : DiagGroup<"c++20-compat-pedantic", - [CXX20Compat]>; + [CXX20Compat, + CXXPre2BCompatPedantic]>; def : DiagGroup<"c++2a-compat", [CXX20Compat]>; def : DiagGroup<"c++2a-compat-pedantic", [CXX20CompatPedantic]>; @@ -1006,6 +1018,10 @@ // earlier C++ versions. def CXX20 : DiagGroup<"c++20-extensions", [CXX20Designator]>; +// A warning group for warnings about using C++2b features as extensions in +// earlier C++ versions. +def CXX2B : DiagGroup<"c++2b-extensions">; + def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; def : DiagGroup<"c++1z-extensions", [CXX17]>; Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -952,6 +952,13 @@ "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 C++2b extension">, + InGroup; +def warn_cxx20_compat_decl_attrs_on_lambda : Warning< + "an attribute specifier sequence in this position is incompatible with C++ " + "standards before C++2b">, InGroup, DefaultIgnore; + // 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()) { + Diag(Tok, getLangOpts().CPlusPlus2b + ? diag::warn_cxx20_compat_decl_attrs_on_lambda + : 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 C++2b extension}} +#if __cplusplus > 201703L + [] [[]] () {}; // expected-warning {{an attribute specifier sequence in this position is a C++2b extension}} +#endif + [] [[]] {}; // expected-warning {{an attribute specifier sequence in this position is a C++2b extension}} } };