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<"pre-c++2b-compat">;
+def CXXPre2bCompatPedantic :
+ DiagGroup<"pre-c++2b-compat-pedantic", [CXXPre2bCompat]>;
def CXX98CompatBindToTemporaryCopy :
DiagGroup<"c++98-compat-bind-to-temporary-copy">;
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,
CXX98CompatExtraSemi,
CXXPre14CompatPedantic,
CXXPre17CompatPedantic,
- CXXPre20CompatPedantic]>;
+ CXXPre20CompatPedantic,
+ CXXPre2bCompatPedantic]>;
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
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]>;
// 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]>;
"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<CXX2b>;
+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<CXXPre2bCompat>, DefaultIgnore;
+
// C++17 lambda expressions
def err_expected_star_this_capture : Error<
"expected 'this' following '*' in lambda capture list">;
}
}
+ // 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)) {
[]() 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:11, col:23> col:23{{( imported)?}} referenced typename depth 0 index 0 ... Ts
-// CHECK-NEXT:`-FunctionDecl {{.*}} <col:27, line:36:1> line:15:32{{( imported)?}} test 'void (Ts...)'
+// CHECK-NEXT:`-FunctionDecl {{.*}} <col:27, line:37:1> line:15:32{{( imported)?}} test 'void (Ts...)'
// CHECK-NEXT: |-ParmVarDecl {{.*}} <col:37, col:43> col:43{{( imported)?}} referenced a 'Ts...' pack
-// CHECK-NEXT: `-CompoundStmt {{.*}} <col:46, line:36:1>
+// CHECK-NEXT: `-CompoundStmt {{.*}} <col:46, line:37:1>
// CHECK-NEXT: |-DeclStmt {{.*}} <line:16:3, line:21:4>
// CHECK-NEXT: | `-CXXRecordDecl {{.*}} <line:16:3, line:21:3> line:16:10{{( imported)?}}{{( <undeserialized declarations>)?}} 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
// CHECK-NEXT: | | |-CXXConversionDecl {{.*}} <col:3, col:18> col:3{{( imported)?}} implicit constexpr operator auto (*)() noexcept 'auto (*() const noexcept)() noexcept' inline
// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} <col:3, col:18> col:3{{( imported)?}} implicit __invoke 'auto () noexcept' static inline
// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:17, col:18>
-// CHECK-NEXT: `-LambdaExpr {{.*}} <line:35:3, col:27> '(lambda at {{.*}}ast-dump-lambda.cpp:35:3)'
+// CHECK-NEXT: |-LambdaExpr {{.*}} <line:35:3, col:27> '(lambda at {{.*}}ast-dump-lambda.cpp:35:3)'
+// CHECK-NEXT: | |-CXXRecordDecl {{.*}} <col:3> col:3{{( imported)?}} implicit{{( <undeserialized declarations>)?}} 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:11, col:27> col:3{{( imported)?}} operator() 'auto () const -> int' inline
+// CHECK-NEXT: | | | `-CompoundStmt {{.*}} <col:15, col:27>
+// CHECK-NEXT: | | | `-ReturnStmt {{.*}} <col:17, col:24>
+// CHECK-NEXT: | | | `-IntegerLiteral {{.*}} <col:24> 'int' 0
+// CHECK-NEXT: | | |-CXXConversionDecl {{.*}} <col:3, col:27> col:3{{( imported)?}} implicit constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline
+// CHECK-NEXT: | | `-CXXMethodDecl {{.*}} <col:3, col:27> col:3{{( imported)?}} implicit __invoke 'auto () -> int' static inline
+// CHECK-NEXT: | `-CompoundStmt {{.*}} <col:15, col:27>
+// CHECK-NEXT: | `-ReturnStmt {{.*}} <col:17, col:24>
+// CHECK-NEXT: | `-IntegerLiteral {{.*}} <col:24> 'int' 0
+// CHECK-NEXT: `-LambdaExpr {{.*}} <line:36:3, col:23> '(lambda at {{.*}}ast-dump-lambda.cpp:36:3)'
// CHECK-NEXT: |-CXXRecordDecl {{.*}} <col:3> col:3{{( imported)?}} implicit{{( <undeserialized declarations>)?}} class definition
// CHECK-NEXT: | |-DefinitionData lambda empty standard_layout trivially_copyable literal can_const_default_init
// CHECK-NEXT: | | |-DefaultConstructor defaulted_is_constexpr
// 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:11, col:27> col:3{{( imported)?}} operator() 'auto () const -> int' inline
-// CHECK-NEXT: | | `-CompoundStmt {{.*}} <col:15, col:27>
-// CHECK-NEXT: | | `-ReturnStmt {{.*}} <col:17, col:24>
-// CHECK-NEXT: | | `-IntegerLiteral {{.*}} <col:24> 'int' 0
-// CHECK-NEXT: | |-CXXConversionDecl {{.*}} <col:3, col:27> col:3{{( imported)?}} implicit constexpr operator int (*)() 'auto (*() const noexcept)() -> int' inline
-// CHECK-NEXT: | `-CXXMethodDecl {{.*}} <col:3, col:27> col:3{{( imported)?}} implicit __invoke 'auto () -> int' static inline
-// CHECK-NEXT: `-CompoundStmt {{.*}} <col:15, col:27>
-// CHECK-NEXT: `-ReturnStmt {{.*}} <col:17, col:24>
-// CHECK-NEXT: `-IntegerLiteral {{.*}} <col:24> 'int' 0
+// CHECK-NEXT: | |-CXXMethodDecl {{.*}} <col:20, col:23> col:3{{( imported)?}} operator() 'auto () const' inline
+// CHECK-NEXT: | | |-CompoundStmt {{.*}} <col:22, col:23>
+// CHECK-NEXT: | | `-CXX11NoReturnAttr {{.*}} <col:8>
+// CHECK-NEXT: | |-CXXConversionDecl {{.*}} <col:3, col:23> col:3{{( imported)?}} implicit constexpr operator auto (*)() 'auto (*() const noexcept)()' inline
+// CHECK-NEXT: | `-CXXMethodDecl {{.*}} <col:3, col:23> col:3{{( imported)?}} implicit __invoke 'auto ()' static inline
+// CHECK-NEXT: `-CompoundStmt {{.*}} <col:22, col:23>
}
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}}
[]() __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
+ [] <typename> [[]] () {}; // 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}}
}
};