A constructor template cannot be instantiated to a copy

constructor. Make sure that such declarations can never be formed.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@88718 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-11-13 23:14:53 +00:00
Родитель 65d0e28583
Коммит cad84b7c12
10 изменённых файлов: 76 добавлений и 39 удалений

Просмотреть файл

@ -487,6 +487,8 @@ def err_constructor_return_type : Error<
def err_constructor_redeclared : Error<"constructor cannot be redeclared">; def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
def err_constructor_byvalue_arg : Error< def err_constructor_byvalue_arg : Error<
"copy constructor must pass its first argument by reference">; "copy constructor must pass its first argument by reference">;
def err_constructor_template_is_copy_constructor : Error<
"constructor template %0 instantiates to a copy constructor">;
// C++ destructors // C++ destructors
def err_destructor_not_member : Error< def err_destructor_not_member : Error<

Просмотреть файл

@ -707,23 +707,23 @@ CXXConstructorDecl::isCopyConstructor(ASTContext &Context,
// if its first parameter is of type X&, const X&, volatile X& or // if its first parameter is of type X&, const X&, volatile X& or
// const volatile X&, and either there are no other parameters // const volatile X&, and either there are no other parameters
// or else all other parameters have default arguments (8.3.6). // or else all other parameters have default arguments (8.3.6).
//
// Note that we also test cv 'X' as a copy constructor, even though it is
// ill-formed, because this helps enforce C++ [class.copy]p3.
if ((getNumParams() < 1) || if ((getNumParams() < 1) ||
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
(getPrimaryTemplate() != 0) ||
(getDescribedFunctionTemplate() != 0)) (getDescribedFunctionTemplate() != 0))
return false; return false;
const ParmVarDecl *Param = getParamDecl(0); const ParmVarDecl *Param = getParamDecl(0);
// Do we have a reference type? Rvalue references don't count. // Do we have a reference type? Rvalue references don't count.
const LValueReferenceType *ParamRefType = CanQualType PointeeType = Context.getCanonicalType(Param->getType());
Param->getType()->getAs<LValueReferenceType>(); if (CanQual<LValueReferenceType> ParamRefType =
if (!ParamRefType) PointeeType->getAs<LValueReferenceType>())
return false; PointeeType = ParamRefType->getPointeeType();
// Is it a reference to our class type? // Do we have our class type?
CanQualType PointeeType
= Context.getCanonicalType(ParamRefType->getPointeeType());
CanQualType ClassTy CanQualType ClassTy
= Context.getCanonicalType(Context.getTagDeclType(getParent())); = Context.getCanonicalType(Context.getTagDeclType(getParent()));
if (PointeeType.getUnqualifiedType() != ClassTy) if (PointeeType.getUnqualifiedType() != ClassTy)

Просмотреть файл

@ -3909,6 +3909,9 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
<< FD->getNameAsCString() << "dllimport"; << FD->getNameAsCString() << "dllimport";
} }
} }
assert(ExprTemporaries.empty() && "Leftover temporaries before starting");
return DeclPtrTy::make(FD); return DeclPtrTy::make(FD);
} }

Просмотреть файл

@ -2237,7 +2237,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// argument doesn't participate in overload resolution. // argument doesn't participate in overload resolution.
} }
if (!CandidateSet.isNewCandidate(Function)) // FIXME: It would be nice if it were safe to keep invalid methods in the
// overload set (but it isn't due to broken copy constructors).
if (!CandidateSet.isNewCandidate(Function) || Function->isInvalidDecl())
return; return;
// Add this candidate // Add this candidate

Просмотреть файл

@ -1247,7 +1247,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) { if (Deduced[I].isNull()) {
Info.Param = makeTemplateParameter( Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I))); const_cast<NamedDecl *>(TemplateParams->getParam(I)));
return TDK_Incomplete; return TDK_Incomplete;
} }

Просмотреть файл

@ -658,6 +658,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
TemplateParams, Function); TemplateParams, Function);
Function->setDescribedFunctionTemplate(FunctionTemplate); Function->setDescribedFunctionTemplate(FunctionTemplate);
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
} else if (FunctionTemplate) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
} }
if (InitFunctionInstantiation(Function, D)) if (InitFunctionInstantiation(Function, D))
@ -709,14 +715,6 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
} }
if (FunctionTemplate && !TemplateParams) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
}
return Function; return Function;
} }
@ -811,9 +809,17 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isOutOfLine()) if (D->isOutOfLine())
FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
Method->setDescribedFunctionTemplate(FunctionTemplate); Method->setDescribedFunctionTemplate(FunctionTemplate);
} else if (!FunctionTemplate) } else if (FunctionTemplate) {
// Record this function template specialization.
Method->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
} else {
// Record this instantiation of a member function.
Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
// If we are instantiating a member function defined // If we are instantiating a member function defined
// out-of-line, the instantiation will have the same lexical // out-of-line, the instantiation will have the same lexical
// context (which will be a namespace scope) as the template. // context (which will be a namespace scope) as the template.
@ -825,6 +831,20 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Params[P]->setOwningFunction(Method); Params[P]->setOwningFunction(Method);
Method->setParams(SemaRef.Context, Params.data(), Params.size()); Method->setParams(SemaRef.Context, Params.data(), Params.size());
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Method)) {
// C++ [class.copy]p3:
// [...] A member function template is never instantiated to perform the
// copy of a class object to an object of its class type.
if (FunctionTemplate && !TemplateParams &&
Constructor->isCopyConstructor(SemaRef.Context)) {
SemaRef.Diag(Constructor->getLocation(),
diag::err_constructor_template_is_copy_constructor)
<< Constructor;
Method->setInvalidDecl();
return Method;
}
}
if (InitMethodInstantiation(Method, D)) if (InitMethodInstantiation(Method, D))
Method->setInvalidDecl(); Method->setInvalidDecl();
@ -843,13 +863,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
PrevDecl = 0; PrevDecl = 0;
} }
if (FunctionTemplate && !TemplateParams)
// Record this function template specialization.
Method->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
&TemplateArgs.getInnermost(),
InsertPos);
bool Redeclaration = false; bool Redeclaration = false;
bool OverloadableAttrRequired = false; bool OverloadableAttrRequired = false;
SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration, SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration,

Просмотреть файл

@ -1,10 +1,9 @@
// RUN: clang-cc -fsyntax-only -verify %s // RUN: clang-cc -fsyntax-only -verify %s
struct C { // expected-note {{candidate function}} struct C {
virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}} \ virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}}
expected-note {{candidate function}}
}; };
void f() { void f() {
C c; // expected-error {{call to constructor of 'c' is ambiguous}} C c;
} }

Просмотреть файл

@ -1,13 +1,11 @@
// RUN: clang-cc -fsyntax-only -verify %s // RUN: clang-cc -fsyntax-only -verify %s
struct S { // expected-note {{candidate function}} struct S {
S (S); // expected-error {{copy constructor must pass its first argument by reference}} \\ S (S); // expected-error {{copy constructor must pass its first argument by reference}}
// expected-note {{candidate function}}
}; };
S f(); S f();
void g() { void g() {
S a( f() ); // expected-error {{call to constructor of 'a' is ambiguous}} S a( f() ); // expected-error {{no matching constructor}}
} }

Просмотреть файл

@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s // RUN: clang-cc -fsyntax-only -verify %s
struct X0 { // expected-note{{candidate}} struct X0 { // expected-note{{candidate}}
X0(int); // expected-note{{candidate}} X0(int); // expected-note{{candidate}}
template<typename T> X0(T); template<typename T> X0(T);
@ -52,3 +51,22 @@ template<class C> struct A {};
template <> struct A<int>{A(const A<int>&);}; template <> struct A<int>{A(const A<int>&);};
struct B { A<int> x; B(B& a) : x(a.x) {} }; struct B { A<int> x; B(B& a) : x(a.x) {} };
struct X2 {
X2();
X2(X2&);
template<typename T> X2(T, int = 17);
};
X2 test(bool Cond, X2 x2) {
if (Cond)
return x2; // okay, uses copy constructor
return X2(); // expected-error{{incompatible type}}
}
struct X3 {
template<typename T> X3(T);
};
template<> X3::X3(X3); // expected-error{{no function template matches}}

Просмотреть файл

@ -11,6 +11,8 @@ int a0(A<int> x) { return x == 1; }
template<class X>struct B{typedef X Y;}; template<class X>struct B{typedef X Y;};
template<class X>bool operator==(B<X>*,typename B<X>::Y); // \ template<class X>bool operator==(B<X>*,typename B<X>::Y); // \
expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \ expected-error{{overloaded 'operator==' must have at least one parameter of class or enumeration type}} \
expected-note{{in instantiation of member function}} expected-note{{in instantiation of function template specialization}}
int a(B<int> x) { return operator==(&x,1); } int a(B<int> x) {
return operator==(&x,1); // expected-error{{no matching function}}
}