зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
65d0e28583
Коммит
cad84b7c12
|
@ -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}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче