https://github.com/Megan0704-1 created https://github.com/llvm/llvm-project/pull/131100
This PR fixes formatting issues in `constructor-template.cpp` introduced in #130866. Changes: - Ran `clang-format` to adhere to LLVM style guidelines. - No functional changes. CC: @cor3ntin @shafik Thanks >From 80e764fcfa1912e9d3771f4edb354569741010b7 Mon Sep 17 00:00:00 2001 From: Megan <megan...@asu.edu> Date: Tue, 11 Mar 2025 17:09:04 -0700 Subject: [PATCH 1/5] [Sema] Diagnose by-value copy constructors in template instantiations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #80963 Previously, Clang skipped diagnosing a constructor if it was implicitly instantiated from a template class (TSK_ImplicitInstantiation). This allowed ill-formed “copy” constructors taking the class by value (e.g. A(A)) to slip through without a diagnostic. However, the C++ standard mandates that copy constructors must take their class type parameter by reference (e.g., A(const A&)). Furthermore, a constructor template that *would* form a copy-by-value signature is not treated as a copy constructor and should never be chosen for copying. This patch replaces the check on TSK_ImplicitInstantiation with a check to see if the constructor is a function template specialization (i.e., isFunctionTemplateSpecialization()). That ensures proper diagnosis of non-template copy-by-value constructors, while still allowing valid template constructors that might appear to have a copy-like signature but should be SFINAEd out or simply not selected as a copy constructor. --- clang/lib/Sema/SemaDeclCXX.cpp | 4 ++-- clang/test/SemaCXX/copy-ctor-template.cpp | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/copy-ctor-template.cpp diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 96aac7871db1e..1c62a551ee732 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10921,8 +10921,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { // parameters have default arguments. if (!Constructor->isInvalidDecl() && Constructor->hasOneParamOrDefaultArgs() && - Constructor->getTemplateSpecializationKind() != - TSK_ImplicitInstantiation) { + !Constructor->isFunctionTemplateSpecialization() + ) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { diff --git a/clang/test/SemaCXX/copy-ctor-template.cpp b/clang/test/SemaCXX/copy-ctor-template.cpp new file mode 100644 index 0000000000000..a46a167038cf7 --- /dev/null +++ b/clang/test/SemaCXX/copy-ctor-template.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template<class T, class V> +struct A{ + A(); + A(A&); + A(A<V, T>); // expected-error{{copy constructor must pass its first argument by reference}} +}; + +void f() { + A<int, int> a = A<int, int>(); // expected-note{{in instantiation of template class 'A<int, int>'}} +} + +template<class T, class V> +struct B{ + B(); + template<class U> B(U); // No error (templated constructor) +}; + +void g() { + B<int, int> b = B<int, int>(); // should use implicit copy constructor +} >From 4fe1d934e7a688c346d5218e213decc67b261d70 Mon Sep 17 00:00:00 2001 From: Megan <megan...@asu.edu> Date: Wed, 12 Mar 2025 00:47:56 -0700 Subject: [PATCH 2/5] [Docs] Add release note for #80963 fix --- clang/docs/ReleaseNotes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 004f78f22ac36..8bae0d6e99ae0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -293,6 +293,7 @@ Bug Fixes to Attribute Support Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ +- Clang now diagnoses copy constructors taking the class by value in template instantiations. (#GH130866) - Clang is now better at keeping track of friend function template instance contexts. (#GH55509) - Clang now prints the correct instantiation context for diagnostics suppressed by template argument deduction. >From 12d9237d7a0650328f6167b1951195cd851f6234 Mon Sep 17 00:00:00 2001 From: Megan <megan...@asu.edu> Date: Wed, 12 Mar 2025 01:24:35 -0700 Subject: [PATCH 3/5] [Sema] Fix test diagnostics for copy-ctor-template --- clang/test/SemaCXX/copy-ctor-template.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/clang/test/SemaCXX/copy-ctor-template.cpp b/clang/test/SemaCXX/copy-ctor-template.cpp index a46a167038cf7..c58bd7c0c5e10 100644 --- a/clang/test/SemaCXX/copy-ctor-template.cpp +++ b/clang/test/SemaCXX/copy-ctor-template.cpp @@ -2,13 +2,20 @@ template<class T, class V> struct A{ - A(); - A(A&); + A(); // expected-note{{candidate constructor not viable: requires 0 arguments, but 1 was provided}} + A(A&); // expected-note{{candidate constructor not viable: expects an lvalue for 1st argument}} A(A<V, T>); // expected-error{{copy constructor must pass its first argument by reference}} }; void f() { - A<int, int> a = A<int, int>(); // expected-note{{in instantiation of template class 'A<int, int>'}} + A<int, int> a = A<int, int>(); // expected-note{{in instantiation of template class 'A<int, int>'}} + A<int, double> a1 = A<double, int>(); // No error (not a copy constructor) +} + +// Test rvalue-to-lvalue conversion in copy constructor +A<int, int> &&a(void); +void g() { + A<int, int> a2 = a(); // expected-error{{no matching constructor}} } template<class T, class V> @@ -17,6 +24,6 @@ struct B{ template<class U> B(U); // No error (templated constructor) }; -void g() { +void h() { B<int, int> b = B<int, int>(); // should use implicit copy constructor } >From 790d151975c9ce4f5f823484d100d9460077b971 Mon Sep 17 00:00:00 2001 From: Megan <megan...@asu.edu> Date: Wed, 12 Mar 2025 14:14:31 -0700 Subject: [PATCH 4/5] [SemaCXX] Update constructor-template.cpp test for #80963 Adjust the test to account for new diagnostics emitted when a class template constructor takes the class by value after instantiation. - Add expected-error annotations to lines 142, 159, 172 (invalid by-value constructors when T = U). - Add expected-note annotations to lines 147, 164, 176 (template instantiation points). - Remove expected-error from line 76 (valid template specialization). --- clang/test/SemaTemplate/constructor-template.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/test/SemaTemplate/constructor-template.cpp b/clang/test/SemaTemplate/constructor-template.cpp index a89dc60cfa347..13f00beb1ffc5 100644 --- a/clang/test/SemaTemplate/constructor-template.cpp +++ b/clang/test/SemaTemplate/constructor-template.cpp @@ -73,7 +73,7 @@ struct X3 { template<typename T> X3(T); }; -template<> X3::X3(X3); // expected-error{{must pass its first argument by reference}} +template<> X3::X3(X3); // No error (template constructor) struct X4 { X4(); @@ -139,12 +139,12 @@ namespace self_by_value { template <class T, class U> struct A { A() {} A(const A<T,U> &o) {} - A(A<T,T> o) {} + A(A<T,T> o) {} // expected-error{{copy constructor must pass its first argument by reference}} }; void helper(A<int,float>); - void test1(A<int,int> a) { + void test1(A<int,int> a) { // expected-note{{in instantiation of template class 'self_by_value::A<int, int>'}} helper(a); } void test2() { @@ -156,12 +156,13 @@ namespace self_by_value_2 { template <class T, class U> struct A { A() {} // precxx17-note {{not viable: requires 0 arguments}} A(A<T,U> &o) {} // precxx17-note {{not viable: expects an lvalue}} - A(A<T,T> o) {} // precxx17-note {{ignored: instantiation takes its own class type by value}} + A(A<T,T> o) {} // expected-error{{copy constructor must pass its first argument by reference}} }; void helper_A(A<int,int>); // precxx17-note {{passing argument to parameter here}} void test_A() { - helper_A(A<int,int>()); // precxx17-error {{no matching constructor}} + helper_A(A<int,int>()); // precxx17-error {{no matching constructor}} \ + // expected-note{{in instantiation of template class 'self_by_value_2::A<int, int>'}} } } @@ -169,11 +170,11 @@ namespace self_by_value_3 { template <class T, class U> struct A { A() {} A(A<T,U> &o) {} - A(A<T,T> o) {} + A(A<T,T> o) {} // expected-error{{copy constructor must pass its first argument by reference}} }; void helper_A(A<int,int>); - void test_A(A<int,int> b) { + void test_A(A<int,int> b) { // expected-note{{in instantiation of template class 'self_by_value_3::A<int, int>'}} helper_A(b); } } >From 08c74230dbbafb635522798a48ee0c0a33864fc0 Mon Sep 17 00:00:00 2001 From: Megan <megan...@asu.edu> Date: Thu, 13 Mar 2025 01:24:01 -0700 Subject: [PATCH 5/5] [NFC] Run clang-format on constructor-template.cpp --- clang/lib/Sema/SemaDeclCXX.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 1c62a551ee732..00b4006b5eb43 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10921,8 +10921,7 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { // parameters have default arguments. if (!Constructor->isInvalidDecl() && Constructor->hasOneParamOrDefaultArgs() && - !Constructor->isFunctionTemplateSpecialization() - ) { + !Constructor->isFunctionTemplateSpecialization()) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits