Skip to content

Commit 80e764f

Browse files
committed
[Sema] Diagnose by-value copy constructors in template instantiations
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.
1 parent c2ed840 commit 80e764f

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10921,8 +10921,8 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) {
1092110921
// parameters have default arguments.
1092210922
if (!Constructor->isInvalidDecl() &&
1092310923
Constructor->hasOneParamOrDefaultArgs() &&
10924-
Constructor->getTemplateSpecializationKind() !=
10925-
TSK_ImplicitInstantiation) {
10924+
!Constructor->isFunctionTemplateSpecialization()
10925+
) {
1092610926
QualType ParamType = Constructor->getParamDecl(0)->getType();
1092710927
QualType ClassTy = Context.getTagDeclType(ClassDecl);
1092810928
if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
template<class T, class V>
4+
struct A{
5+
A();
6+
A(A&);
7+
A(A<V, T>); // expected-error{{copy constructor must pass its first argument by reference}}
8+
};
9+
10+
void f() {
11+
A<int, int> a = A<int, int>(); // expected-note{{in instantiation of template class 'A<int, int>'}}
12+
}
13+
14+
template<class T, class V>
15+
struct B{
16+
B();
17+
template<class U> B(U); // No error (templated constructor)
18+
};
19+
20+
void g() {
21+
B<int, int> b = B<int, int>(); // should use implicit copy constructor
22+
}

0 commit comments

Comments
 (0)