diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 5 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 33 | ||||
-rw-r--r-- | test/SemaTemplate/constructor-template.cpp | 32 | ||||
-rw-r--r-- | test/SemaTemplate/operator-template.cpp | 2 |
8 files changed, 104 insertions, 24 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index cc95390338..eb3205f00f 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1247,6 +1247,11 @@ public: /// used for user-defined conversions. bool isConvertingConstructor(bool AllowExplicit) const; + /// \brief Determine whether this is a member template specialization that + /// looks like a copy constructor. Such constructors are never used to copy + /// an object. + bool isCopyConstructorLikeSpecialization() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == CXXConstructor; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index e325a25c76..9867e5a880 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -752,6 +752,33 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); } +bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { + if ((getNumParams() < 1) || + (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || + (getPrimaryTemplate() == 0) || + (getDescribedFunctionTemplate() != 0)) + return false; + + const ParmVarDecl *Param = getParamDecl(0); + + ASTContext &Context = getASTContext(); + CanQualType ParamType = Context.getCanonicalType(Param->getType()); + + // Strip off the lvalue reference, if any. + if (CanQual<LValueReferenceType> ParamRefType + = ParamType->getAs<LValueReferenceType>()) + ParamType = ParamRefType->getPointeeType(); + + + // Is it the same as our our class type? + CanQualType ClassTy + = Context.getCanonicalType(Context.getTagDeclType(getParent())); + if (ParamType.getUnqualifiedType() != ClassTy) + return false; + + return true; +} + CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation L, DeclarationName N, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c3f3367d2d..f040aafc2e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2362,13 +2362,18 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { if (!Constructor->isInvalidDecl() && ((Constructor->getNumParams() == 1) || (Constructor->getNumParams() > 1 && - Constructor->getParamDecl(1)->hasDefaultArg()))) { + Constructor->getParamDecl(1)->hasDefaultArg())) && + Constructor->getTemplateSpecializationKind() + != TSK_ImplicitInstantiation) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { SourceLocation ParamLoc = Constructor->getParamDecl(0)->getLocation(); Diag(ParamLoc, diag::err_constructor_byvalue_arg) << CodeModificationHint::CreateInsertion(ParamLoc, " const &"); + + // FIXME: Rather that making the constructor invalid, we should endeavor + // to fix the type. Constructor->setInvalidDecl(); } } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 3948b22f7b..53e64dfc68 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1422,7 +1422,7 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); else Constructor = cast<CXXConstructorDecl>(*Con); - + if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) @@ -2239,7 +2239,18 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, if (!CandidateSet.isNewCandidate(Function)) return; - + + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Function)){ + // 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. + QualType ClassType = Context.getTypeDeclType(Constructor->getParent()); + if (NumArgs == 1 && + Constructor->isCopyConstructorLikeSpecialization() && + Context.hasSameUnqualifiedType(ClassType, Args[0]->getType())) + return; + } + // Add this candidate CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6a65bd1dd1..e9061b8ac2 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -965,9 +965,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. // FIXME: Leaks RetValExp on error. - if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)) + if (PerformCopyInitialization(RetValExp, FnRetType, "returning", Elidable)){ + // We should still clean up our temporaries, even when we're failing! + RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp, true); return StmtError(); - + } + if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 47d2701bcd..5d50d51df9 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -658,6 +658,12 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { TemplateParams, Function); Function->setDescribedFunctionTemplate(FunctionTemplate); FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + } else if (FunctionTemplate) { + // Record this function template specialization. + Function->setFunctionTemplateSpecialization(SemaRef.Context, + FunctionTemplate, + &TemplateArgs.getInnermost(), + InsertPos); } if (InitFunctionInstantiation(Function, D)) @@ -709,14 +715,6 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); } - if (FunctionTemplate && !TemplateParams) { - // Record this function template specialization. - Function->setFunctionTemplateSpecialization(SemaRef.Context, - FunctionTemplate, - &TemplateArgs.getInnermost(), - InsertPos); - } - return Function; } @@ -811,9 +809,17 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (D->isOutOfLine()) FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); Method->setDescribedFunctionTemplate(FunctionTemplate); - } else if (!FunctionTemplate) + } else if (FunctionTemplate) { + // Record this function template specialization. + Method->setFunctionTemplateSpecialization(SemaRef.Context, + FunctionTemplate, + &TemplateArgs.getInnermost(), + InsertPos); + } else { + // Record that this is an instantiation of a member function. Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); - + } + // If we are instantiating a member function defined // out-of-line, the instantiation will have the same lexical // context (which will be a namespace scope) as the template. @@ -843,13 +849,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, PrevDecl = 0; } - if (FunctionTemplate && !TemplateParams) - // Record this function template specialization. - Method->setFunctionTemplateSpecialization(SemaRef.Context, - FunctionTemplate, - &TemplateArgs.getInnermost(), - InsertPos); - bool Redeclaration = false; bool OverloadableAttrRequired = false; SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration, diff --git a/test/SemaTemplate/constructor-template.cpp b/test/SemaTemplate/constructor-template.cpp index 79bf7c585e..12c6f8b9c1 100644 --- a/test/SemaTemplate/constructor-template.cpp +++ b/test/SemaTemplate/constructor-template.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - struct X0 { // expected-note{{candidate}} X0(int); // expected-note{{candidate}} template<typename T> X0(T); @@ -52,3 +51,34 @@ template<class C> struct A {}; template <> struct A<int>{A(const A<int>&);}; struct B { A<int> x; B(B& a) : x(a.x) {} }; +struct X2 { + X2(); + X2(X2&); + template<typename T> X2(T); +}; + +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{{must pass its first argument by reference}} + +struct X4 { + X4(); + ~X4(); + X4(X4&); + template<typename T> X4(const T&, int = 17); +}; + +X4 test_X4(bool Cond, X4 x4) { + X4 a(x4, 17); // okay, constructor template + X4 b(x4); // okay, copy constructor + return X4(); // expected-error{{incompatible type}} +} diff --git a/test/SemaTemplate/operator-template.cpp b/test/SemaTemplate/operator-template.cpp index 7039e0ec83..dc44d04b68 100644 --- a/test/SemaTemplate/operator-template.cpp +++ b/test/SemaTemplate/operator-template.cpp @@ -11,6 +11,6 @@ int a0(A<int> x) { return x == 1; } template<class X>struct B{typedef 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-note{{in instantiation of member function}} +expected-note{{in instantiation of function template specialization}} int a(B<int> x) { return operator==(&x,1); } |