Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -492,6 +492,8 @@ def err_decomp_decl_type : Error< "decomposition declaration cannot be declared with type %0; " "declared type must be 'auto' or reference to 'auto'">; +def err_decomp_decl_constraint : Error<"decomposition declaration cannot be " + "declared with constrained 'auto'">; def err_decomp_decl_parens : Error< "decomposition declaration cannot be declared with parentheses">; def err_decomp_decl_template : Error< Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -760,11 +760,13 @@ // C++17 [dcl.dcl]/8: // The decl-specifier-seq shall contain only the type-specifier auto // and cv-qualifiers. - // C++2a [dcl.dcl]/8: - // If decl-specifier-seq contains any decl-specifier other than static, - // thread_local, auto, or cv-qualifiers, the program is ill-formed. + // C++2a [dcl.pre]/6: + // Each decl-specifier in the decl-specifier-seq shall be static, + // thread_local, auto (9.2.9.6 [dcl.spec.auto]), or a cv-qualifier. auto &DS = D.getDeclSpec(); { + // Note: While constrained-auto needs to be checked, we do so separately so + // we can emit a better diagnostic. SmallVector BadSpecifiers; SmallVector BadSpecifierLocs; SmallVector CPlusPlus20Specifiers; @@ -791,6 +793,7 @@ BadSpecifiers.push_back("inline"); BadSpecifierLocs.push_back(DS.getInlineSpecLoc()); } + if (!BadSpecifiers.empty()) { auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec); Err << (int)BadSpecifiers.size() @@ -851,6 +854,20 @@ D.setInvalidType(); } + // Constrained auto is prohibited by [decl.pre]p6, so check that here. + if (DS.isConstrainedAuto()) { + TemplateIdAnnotation *TemplRep = DS.getRepAsTemplateId(); + assert(TemplRep->Kind == TNK_Concept_template && + "No other template kind should be possible for a constrained auto"); + + SourceRange TemplRange{TemplRep->TemplateNameLoc, + TemplRep->RAngleLoc.isValid() + ? TemplRep->RAngleLoc + : TemplRep->TemplateNameLoc}; + Diag(TemplRep->TemplateNameLoc, diag::err_decomp_decl_constraint) + << TemplRange << FixItHint::CreateRemoval(TemplRange); + } + // Build the BindingDecls. SmallVector Bindings; Index: clang/test/CXX/drs/dr26xx.cpp =================================================================== --- clang/test/CXX/drs/dr26xx.cpp +++ clang/test/CXX/drs/dr26xx.cpp @@ -28,3 +28,32 @@ } } + +namespace dr2635 { // dr2635: yes +template +concept UnaryC = true; +template +concept BinaryC = true; + +struct S{ int i, j; }; +S get_S(); + +template +T get_T(); + +void use() { + // expected-error@+1{{decomposition declaration cannot be declared with constrained 'auto'}} + UnaryC auto [a, b] = get_S(); + // expected-error@+1{{decomposition declaration cannot be declared with constrained 'auto'}} + BinaryC auto [c, d] = get_S(); +} + +template +void TemplUse() { + // expected-error@+1{{decomposition declaration cannot be declared with constrained 'auto'}} + UnaryC auto [a, b] = get_T(); + // expected-error@+1{{decomposition declaration cannot be declared with constrained 'auto'}} + BinaryC auto [c, d] = get_T(); +} + +} Index: clang/www/cxx_dr_status.html =================================================================== --- clang/www/cxx_dr_status.html +++ clang/www/cxx_dr_status.html @@ -15618,7 +15618,7 @@ 2635 DR Constrained structured bindings - Unknown + Clang 16 2636