Skip to content

[clang] Allow parentheses around CTAD declarators #132829

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,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
Expand Down
7 changes: 3 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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{<error>|function template|variable template|alias template|"
"template template parameter|concept|template}0 %1 requires template "
Expand Down
9 changes: 2 additions & 7 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<DeducedType>()) {
const AutoType *AT = T->getAs<AutoType>();
bool IsClassTemplateDeduction = isa<DeducedTemplateSpecializationType>(DT);
Expand All @@ -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) {
Expand Down
14 changes: 14 additions & 0 deletions clang/test/CXX/drs/cwg23xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,20 @@ class C {
};
} // namespace cwg2370

namespace cwg2376 { // cwg2376: 21
#if __cplusplus >= 201703L
template<int = 0> 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<E> names a complete class
// type **with a member value**, the expression std::tuple_size<E>::value shall
Expand Down
8 changes: 4 additions & 4 deletions clang/test/Parser/cxx1z-class-template-argument-deduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace template_template_arg_pack {
template<typename...> struct YP {};

struct Z { template<typename T> struct Q {}; }; // expected-note 2{{here}}

template<typename T> using ZId = Z;

template<typename ...Ts> struct A {
Expand Down Expand Up @@ -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}}
Expand All @@ -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}}
Expand Down Expand Up @@ -217,7 +217,7 @@ namespace typename_specifier {
}

namespace parenthesized {
template<typename T> struct X { X(T); };
template<typename T> struct X { X(T); };
auto n = (X([]{}));
}

Expand Down
26 changes: 26 additions & 0 deletions clang/test/SemaCXX/ctad.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -std=c++20 %s

namespace GH39811 {

template<int = 0> class C {};

C (a);
C (b) = C();
C (c) {};
C (((((d)))));

template<C (e)> class X;
template<C (...f)> 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<typename X, typename Y> struct A { X x; Y y;};
Expand Down
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -14091,7 +14091,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2376.html">2376</a></td>
<td>CD5</td>
<td>Class template argument deduction with array declarator</td>
<td class="unknown" align="center">Unknown</td>
<td class="unreleased" align="center">Clang 21</td>
</tr>
<tr id="2377">
<td><a href="https://cplusplus.github.io/CWG/issues/2377.html">2377</a></td>
Expand Down