[cfe-commits] r88718 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/AST/DeclCXX.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaCXX/constructor-recovery.cpp test/SemaCXX/copy-constructor-error.cpp test/SemaTemplate/constructor-template.cpp test/SemaTemplate/operator-template.cpp

Douglas Gregor dgregor at apple.com
Fri Nov 13 15:14:54 PST 2009


Author: dgregor
Date: Fri Nov 13 17:14:53 2009
New Revision: 88718

URL: http://llvm.org/viewvc/llvm-project?rev=88718&view=rev
Log:
A constructor template cannot be instantiated to a copy
constructor. Make sure that such declarations can never be formed.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaCXX/constructor-recovery.cpp
    cfe/trunk/test/SemaCXX/copy-constructor-error.cpp
    cfe/trunk/test/SemaTemplate/constructor-template.cpp
    cfe/trunk/test/SemaTemplate/operator-template.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=88718&r1=88717&r2=88718&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Nov 13 17:14:53 2009
@@ -487,6 +487,8 @@
 def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
 def err_constructor_byvalue_arg : Error<
   "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
 def err_destructor_not_member : Error<

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

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Nov 13 17:14:53 2009
@@ -707,23 +707,23 @@
   //   if its first parameter is of type X&, const X&, volatile X& or
   //   const volatile X&, and either there are no other parameters
   //   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) ||
       (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
-      (getPrimaryTemplate() != 0) ||
       (getDescribedFunctionTemplate() != 0))
     return false;
 
   const ParmVarDecl *Param = getParamDecl(0);
 
   // Do we have a reference type? Rvalue references don't count.
-  const LValueReferenceType *ParamRefType =
-    Param->getType()->getAs<LValueReferenceType>();
-  if (!ParamRefType)
-    return false;
+  CanQualType PointeeType = Context.getCanonicalType(Param->getType());
+  if (CanQual<LValueReferenceType> ParamRefType =
+                                     PointeeType->getAs<LValueReferenceType>())
+    PointeeType = ParamRefType->getPointeeType();
 
-  // Is it a reference to our class type?
-  CanQualType PointeeType
-    = Context.getCanonicalType(ParamRefType->getPointeeType());
+  // Do we have our class type?
   CanQualType ClassTy 
     = Context.getCanonicalType(Context.getTagDeclType(getParent()));
   if (PointeeType.getUnqualifiedType() != ClassTy)

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Nov 13 17:14:53 2009
@@ -3909,6 +3909,9 @@
         << FD->getNameAsCString() << "dllimport";
     }
   }
+  
+  assert(ExprTemporaries.empty() && "Leftover temporaries before starting");
+
   return DeclPtrTy::make(FD);
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Nov 13 17:14:53 2009
@@ -2237,7 +2237,9 @@
     // 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;
     
   // Add this candidate

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Nov 13 17:14:53 2009
@@ -1247,7 +1247,7 @@
   for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
     if (Deduced[I].isNull()) {
       Info.Param = makeTemplateParameter(
-                            const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+                          const_cast<NamedDecl *>(TemplateParams->getParam(I)));
       return TDK_Incomplete;
     }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Nov 13 17:14:53 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 this 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.
@@ -825,6 +831,20 @@
     Params[P]->setOwningFunction(Method);
   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))
     Method->setInvalidDecl();
 
@@ -843,13 +863,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/SemaCXX/constructor-recovery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constructor-recovery.cpp?rev=88718&r1=88717&r2=88718&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/constructor-recovery.cpp (original)
+++ cfe/trunk/test/SemaCXX/constructor-recovery.cpp Fri Nov 13 17:14:53 2009
@@ -1,10 +1,9 @@
 // RUN: clang-cc -fsyntax-only -verify %s
 
-struct C {  // expected-note {{candidate function}}
-  virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}} \
-                      expected-note {{candidate function}}
+struct C {
+  virtual C() = 0; // expected-error{{constructor cannot be declared 'virtual'}}
 };
 
 void f() {
- C c;  // expected-error {{call to constructor of 'c' is ambiguous}}
+ C c;
 }

Modified: cfe/trunk/test/SemaCXX/copy-constructor-error.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/copy-constructor-error.cpp?rev=88718&r1=88717&r2=88718&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/copy-constructor-error.cpp (original)
+++ cfe/trunk/test/SemaCXX/copy-constructor-error.cpp Fri Nov 13 17:14:53 2009
@@ -1,13 +1,11 @@
 // RUN: clang-cc -fsyntax-only -verify %s 
 
-struct S { // expected-note {{candidate function}} 
-   S (S);  // expected-error {{copy constructor must pass its first argument by reference}} \\
-           // expected-note {{candidate function}}
+struct S {
+   S (S);  // expected-error {{copy constructor must pass its first argument by reference}}
 };
 
 S f();
 
 void g() { 
-  S a( f() );  // expected-error {{call to constructor of 'a' is ambiguous}}
+  S a( f() );  // expected-error {{no matching constructor}}
 }
-

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Fri Nov 13 17:14:53 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,22 @@
 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, 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}}
+

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/operator-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/operator-template.cpp Fri Nov 13 17:14:53 2009
@@ -11,6 +11,8 @@
 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}}
-int a(B<int> x) { return operator==(&x,1); }
+expected-note{{in instantiation of function template specialization}}
+int a(B<int> x) { 
+  return operator==(&x,1);  // expected-error{{no matching function}}
+}
 





More information about the cfe-commits mailing list