diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -655,6 +655,7 @@ - Do not hide templated base members introduced via using-decl in derived class (useful specially for constrained members). Fixes `GH50886 `_. +- Implemented CWG2635 as a Defect Report, which prohibits structured bindings from being constrained. C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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< diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -760,11 +760,16 @@ // C++17 [dcl.dcl]/8: // The decl-specifier-seq shall contain only the type-specifier auto // and cv-qualifiers. - // C++2a [dcl.dcl]/8: + // C++20 [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++2b [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 +796,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 +857,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; diff --git a/clang/test/CXX/drs/dr26xx.cpp b/clang/test/CXX/drs/dr26xx.cpp --- a/clang/test/CXX/drs/dr26xx.cpp +++ b/clang/test/CXX/drs/dr26xx.cpp @@ -27,6 +27,34 @@ // expected-note@#DR2628_CTOR {{marked deleted here}} } +} + +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(); +} } // dr2636: na diff --git a/clang/test/FixIt/fixit-constrained-structured-binding.cpp b/clang/test/FixIt/fixit-constrained-structured-binding.cpp new file mode 100644 --- /dev/null +++ b/clang/test/FixIt/fixit-constrained-structured-binding.cpp @@ -0,0 +1,33 @@ +// RUN: not %clang_cc1 -std=c++20 -fdiagnostics-parseable-fixits -x c++ %s 2> %t +// RUN: FileCheck %s < %t + +template +concept UnaryC = true; +template +concept BinaryC = true; + +struct S{ int i, j; }; +S get_S(); + +template +T get_T(); + +void use() { + UnaryC auto [a, b] = get_S(); + // CHECK: error: decomposition declaration cannot be declared with constrained 'auto' + // CHECK: fix-it:{{.*}}:{16:3-16:10}:"" + BinaryC auto [c, d] = get_S(); + // CHECK: error: decomposition declaration cannot be declared with constrained 'auto' + // CHECK: fix-it:{{.*}}:{19:3-19:16}:"" +} + +template +void TemplUse() { + UnaryC auto [a, b] = get_T(); + // CHECK: error: decomposition declaration cannot be declared with constrained 'auto' + // XCHECK: fix-it:{{.*}}:{26:3-26:10}:"" + BinaryC auto [c, d] = get_T(); + // CHECK: error: decomposition declaration cannot be declared with constrained 'auto' + // XCHECK: fix-it:{{.*}}:{29:3-29:14}:"" +} + diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -15618,7 +15618,7 @@ 2635 DR Constrained structured bindings - Unknown + Clang 16 2636