mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 19:16:43 +00:00
[Sema] Diagnose by-value copy constructors in template instantiations (#130866)
Fixes #80963 This PR ensures Clang diagnoses by-value copy constructors in implicitly instantiated class templates (e.g., `A<int, int>(A<int, int>)`), per [class.copy.ctor]. Changes: - Remove `TSK_ImplicitInstantiation` check in `SemaDeclCXX.cpp`. - Add `!isFunctionTemplateSpecialization()` to skip templated constructors. - Add regression tests.
This commit is contained in:
parent
646a6e7f10
commit
fe0d3e3764
@ -292,6 +292,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.
|
||||
|
@ -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) {
|
||||
|
29
clang/test/SemaCXX/copy-ctor-template.cpp
Normal file
29
clang/test/SemaCXX/copy-ctor-template.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
template<class T, class V>
|
||||
struct 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, 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>
|
||||
struct B{
|
||||
B();
|
||||
template<class U> B(U); // No error (templated constructor)
|
||||
};
|
||||
|
||||
void h() {
|
||||
B<int, int> b = B<int, int>(); // should use implicit copy constructor
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user