From 9604bdf1180950c04f194584fdd2cca0f0668971 Mon Sep 17 00:00:00 2001 From: offsetof Date: Fri, 11 Apr 2025 06:47:07 +0000 Subject: [PATCH] [clang] Allow parentheses around CTAD declarators (#132829) Fixes #39811 --- clang/docs/ReleaseNotes.rst | 2 ++ .../clang/Basic/DiagnosticSemaKinds.td | 7 +++-- clang/lib/Sema/SemaType.cpp | 9 ++----- clang/test/CXX/drs/cwg23xx.cpp | 14 ++++++++++ ...xx1z-class-template-argument-deduction.cpp | 8 +++--- clang/test/SemaCXX/ctad.cpp | 26 +++++++++++++++++++ clang/www/cxx_dr_status.html | 2 +- 7 files changed, 52 insertions(+), 16 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5983621a7a87..46d2debec362 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -452,6 +452,8 @@ Bug Fixes to C++ Support - Fixed a Clang regression in C++20 mode where unresolved dependent call expressions were created inside non-dependent contexts (#GH122892) - Clang now emits the ``-Wunused-variable`` warning when some structured bindings are unused and the ``[[maybe_unused]]`` attribute is not applied. (#GH125810) +- Declarations using class template argument deduction with redundant + parentheses around the declarator are no longer rejected. (#GH39811) - Fixed a crash caused by invalid declarations of ``std::initializer_list``. (#GH132256) - Clang no longer crashes when establishing subsumption between some constraint expressions. (#GH122581) - Clang now issues an error when placement new is used to modify a const-qualified variable diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b0972541cb4a..180ca39bc07e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2617,10 +2617,9 @@ def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; // C++17 deduced class template specialization types -def err_deduced_class_template_compound_type : Error< - "cannot %select{form pointer to|form reference to|form array of|" - "form function returning|use parentheses when declaring variable with}0 " - "deduced class template specialization type">; +def err_deduced_class_template_compound_type + : Error<"cannot form %select{pointer to|reference to|array of|function " + "returning}0 deduced class template specialization type">; def err_deduced_non_class_or_alias_template_specialization_type : Error< "%select{|function template|variable template|alias template|" "template template parameter|concept|template}0 %1 requires template " diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 4e7726e25811..e711a5c5d2a1 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4281,8 +4281,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If T is 'decltype(auto)', the only declarators we can have are parens // and at most one function declarator if this is a function declaration. - // If T is a deduced class template specialization type, we can have no - // declarator chunks at all. + // If T is a deduced class template specialization type, only parentheses + // are allowed. if (auto *DT = T->getAs()) { const AutoType *AT = T->getAs(); bool IsClassTemplateDeduction = isa(DT); @@ -4296,11 +4296,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, unsigned DiagKind = 0; switch (DeclChunk.Kind) { case DeclaratorChunk::Paren: - // FIXME: Rejecting this is a little silly. - if (IsClassTemplateDeduction) { - DiagKind = 4; - break; - } continue; case DeclaratorChunk::Function: { if (IsClassTemplateDeduction) { diff --git a/clang/test/CXX/drs/cwg23xx.cpp b/clang/test/CXX/drs/cwg23xx.cpp index d144cf9e4e86..78cecb8b71bc 100644 --- a/clang/test/CXX/drs/cwg23xx.cpp +++ b/clang/test/CXX/drs/cwg23xx.cpp @@ -379,6 +379,20 @@ class C { }; } // namespace cwg2370 +namespace cwg2376 { // cwg2376: 21 +#if __cplusplus >= 201703L +template class C {}; + +C a; +const volatile C b = C<2>(); +C (c) = {}; +C* d; +// expected-error@-1 {{cannot form pointer to deduced class template specialization type}} +C e[1]; +// expected-error@-1 {{cannot form array of deduced class template specialization type}} +#endif +} + namespace cwg2386 { // cwg2386: 9 // Otherwise, if the qualified-id std::tuple_size names a complete class // type **with a member value**, the expression std::tuple_size::value shall diff --git a/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp b/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp index a1594333abae..d29eed40b186 100644 --- a/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp +++ b/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp @@ -39,7 +39,7 @@ namespace template_template_arg_pack { template struct YP {}; struct Z { template struct Q {}; }; // expected-note 2{{here}} - + template using ZId = Z; template struct A { @@ -152,7 +152,7 @@ namespace decl { A a; A b = 0; const A c = 0; - A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}} + A (parens) = 0; A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}} A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}} A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}} @@ -179,7 +179,7 @@ namespace typename_specifier { } typename ::A a = 0; const typename ::A b = 0; - typename ::A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}} + typename ::A (parens) = 0; typename ::A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}} typename ::A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}} typename ::A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}} @@ -217,7 +217,7 @@ namespace typename_specifier { } namespace parenthesized { - template struct X { X(T); }; + template struct X { X(T); }; auto n = (X([]{})); } diff --git a/clang/test/SemaCXX/ctad.cpp b/clang/test/SemaCXX/ctad.cpp index 00a861d0f567..d727c7e66c34 100644 --- a/clang/test/SemaCXX/ctad.cpp +++ b/clang/test/SemaCXX/ctad.cpp @@ -1,5 +1,31 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -std=c++20 %s +namespace GH39811 { + +template class C {}; + +C (a); +C (b) = C(); +C (c) {}; +C (((((d))))); + +template class X; +template class Y; + +void test() { + C (g); + C (h) = C(); + C (i) {}; + (void)g; + (void)h; + (void)i; +} + +C* (bad1); // expected-error {{cannot form pointer to deduced class template specialization type}} +C (*bad2); // expected-error {{cannot form pointer to deduced class template specialization type}} + +} + namespace GH64347 { template struct A { X x; Y y;}; diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index eeb1d9d74bf0..8fe53ad46aca 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -14091,7 +14091,7 @@ and POD class 2376 CD5 Class template argument deduction with array declarator - Unknown + Clang 21 2377