[cfe-commits] r88733 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaStmt.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/constructor-template.cpp test/SemaTemplate/operator-template.cpp

Douglas Gregor dgregor at apple.com
Fri Nov 13 17:20:54 PST 2009


Author: dgregor
Date: Fri Nov 13 19:20:54 2009
New Revision: 88733

URL: http://llvm.org/viewvc/llvm-project?rev=88733&view=rev
Log:
If we attempt to add a constructor template specialization that looks
like a copy constructor to the overload set, just ignore it. This
ensures that we don't try to use such a constructor as a copy
constructor *without* triggering diagnostics at the point of
declaration.

Note that we *do* diagnose such copy constructors when explicitly
written by the user (e.g., as an explicit specialization).


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/constructor-template.cpp
    cfe/trunk/test/SemaTemplate/operator-template.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Nov 13 19:20:54 2009
@@ -1247,6 +1247,11 @@
   /// 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;

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Nov 13 19:20:54 2009
@@ -752,6 +752,33 @@
          (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,

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Nov 13 19:20:54 2009
@@ -2362,13 +2362,18 @@
   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();
     }
   }

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Nov 13 19:20:54 2009
@@ -1422,7 +1422,7 @@
             = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
         else
           Constructor = cast<CXXConstructorDecl>(*Con);
-
+        
         if (!Constructor->isInvalidDecl() &&
             Constructor->isConvertingConstructor(AllowExplicit)) {
           if (ConstructorTmpl)
@@ -2239,7 +2239,18 @@
 
   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();

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri Nov 13 19:20:54 2009
@@ -965,9 +965,12 @@
     // 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);
   }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Nov 13 19:20:54 2009
@@ -658,6 +658,12 @@
                                                     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 @@
       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 @@
     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 @@
       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,

Modified: cfe/trunk/test/SemaTemplate/constructor-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constructor-template.cpp?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Fri Nov 13 19:20:54 2009
@@ -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 <> 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}}
+}

Modified: cfe/trunk/test/SemaTemplate/operator-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/operator-template.cpp?rev=88733&r1=88732&r2=88733&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/operator-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/operator-template.cpp Fri Nov 13 19:20:54 2009
@@ -11,6 +11,6 @@
 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); }
 





More information about the cfe-commits mailing list