[cfe-commits] r79658 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp lib/Parse/ParseDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/constructor-template.cpp test/SemaTemplate/member-function-template.cpp

Douglas Gregor dgregor at apple.com
Fri Aug 21 11:42:58 PDT 2009


Author: dgregor
Date: Fri Aug 21 13:42:58 2009
New Revision: 79658

URL: http://llvm.org/viewvc/llvm-project?rev=79658&view=rev
Log:
Introduce support for constructor templates, which can now be declared
and will participate in overload resolution. Unify the instantiation
of CXXMethodDecls and CXXConstructorDecls, which had already gotten
out-of-sync.


Added:
    cfe/trunk/test/SemaTemplate/constructor-template.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/member-function-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=79658&r1=79657&r2=79658&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri Aug 21 13:42:58 2009
@@ -161,6 +161,8 @@
   OverloadIterator(OverloadedFunctionDecl *Ovl) 
     : D(Ovl), Iter(Ovl->function_begin()) { }
   
+  OverloadIterator(NamedDecl *ND);
+  
   reference operator*() const;
   
   pointer operator->() const { return (**this).get(); }

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

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri Aug 21 13:42:58 2009
@@ -712,6 +712,18 @@
   return new (C) OverloadedFunctionDecl(DC, N);
 }
 
+OverloadIterator::OverloadIterator(NamedDecl *ND) : D(0) {
+  if (!ND)
+    return;
+  
+  if (isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND))
+    D = ND;
+  else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(ND)) {
+    D = ND;
+    Iter = Ovl->function_begin();
+  }
+}
+
 void OverloadedFunctionDecl::addOverload(AnyFunctionDecl F) {
   Functions.push_back(F);
   this->setLocation(F.get()->getLocation());

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=79658&r1=79657&r2=79658&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Aug 21 13:42:58 2009
@@ -844,7 +844,10 @@
       // being defined and the next token is a '(', then this is a
       // constructor declaration. We're done with the decl-specifiers
       // and will treat this token as an identifier.
-      if (getLang().CPlusPlus && CurScope->isClassScope() &&
+      if (getLang().CPlusPlus && 
+          (CurScope->isClassScope() || 
+           (CurScope->isTemplateParamScope() && 
+            CurScope->getParent()->isClassScope())) &&
           Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope) && 
           NextToken().getKind() == tok::l_paren)
         goto DoneWithDeclSpec;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Aug 21 13:42:58 2009
@@ -2599,11 +2599,24 @@
   DeclContext::lookup_const_iterator Con, ConEnd;
   for (llvm::tie(Con, ConEnd) = ClassDecl->lookup(ConstructorName);
        Con != ConEnd; ++Con) {
-    CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+    // Find the constructor (which may be a template).
+    CXXConstructorDecl *Constructor = 0;
+    FunctionTemplateDecl *ConstructorTmpl= dyn_cast<FunctionTemplateDecl>(*Con);
+    if (ConstructorTmpl)
+      Constructor 
+        = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+    else
+      Constructor = cast<CXXConstructorDecl>(*Con);
+
     if ((Kind == IK_Direct) ||
         (Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
-        (Kind == IK_Default && Constructor->isDefaultConstructor()))
-      AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+        (Kind == IK_Default && Constructor->isDefaultConstructor())) {
+      if (ConstructorTmpl)
+        AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, 
+                                     Args, NumArgs, CandidateSet);
+      else
+        AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+    }
   }
 
   // FIXME: When we decide not to synthesize the implicitly-declared

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Aug 21 13:42:58 2009
@@ -1343,11 +1343,27 @@
       for (llvm::tie(Con, ConEnd) 
              = ToRecordDecl->lookup(ConstructorName);
            Con != ConEnd; ++Con) {
-        CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+        // Find the constructor (which may be a template).
+        CXXConstructorDecl *Constructor = 0;
+        FunctionTemplateDecl *ConstructorTmpl
+          = dyn_cast<FunctionTemplateDecl>(*Con);
+        if (ConstructorTmpl)
+          Constructor 
+            = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
+        else
+          Constructor = cast<CXXConstructorDecl>(*Con);
+        
         if (!Constructor->isInvalidDecl() &&
-            Constructor->isConvertingConstructor())
-          AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
-                               /*SuppressUserConversions=*/true, ForceRValue);
+            Constructor->isConvertingConstructor()) {
+          if (ConstructorTmpl)
+            AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From, 
+                                         1, CandidateSet,
+                                         /*SuppressUserConversions=*/true, 
+                                         ForceRValue);
+          else
+            AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
+                                 /*SuppressUserConversions=*/true, ForceRValue);
+        }
       }
     }
   }
@@ -4324,29 +4340,18 @@
     OverloadCandidateSet CandidateSet;
     DeclarationName DeclName = MemExpr->getMemberDecl()->getDeclName();
     
-    if (OverloadedFunctionDecl *Ovl 
-          = dyn_cast<OverloadedFunctionDecl>(MemExpr->getMemberDecl())) {
-      for (OverloadedFunctionDecl::function_iterator 
-                Func = Ovl->function_begin(),
-             FuncEnd = Ovl->function_end();
-           Func != FuncEnd; ++Func) {
-        if ((Method = dyn_cast<CXXMethodDecl>(*Func)))
-          AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, 
-                             /*SuppressUserConversions=*/false);
-        else
-          AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func), 
-                                     /*FIXME:*/false, /*FIXME:*/0, 
-                                     /*FIXME:*/0, ObjectArg, Args, NumArgs,
-                                     CandidateSet,
-                                     /*SuppressUsedConversions=*/false);
-      }
-    } else
-      AddMethodTemplateCandidate(
-                          cast<FunctionTemplateDecl>(MemExpr->getMemberDecl()), 
-                                 /*FIXME:*/false, /*FIXME:*/0, 
-                                 /*FIXME:*/0, ObjectArg, Args, NumArgs,
-                                 CandidateSet,
-                                 /*SuppressUsedConversions=*/false);
+    for (OverloadIterator Func(MemExpr->getMemberDecl()), FuncEnd;
+         Func != FuncEnd; ++Func) {
+      if ((Method = dyn_cast<CXXMethodDecl>(*Func)))
+        AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet, 
+                           /*SuppressUserConversions=*/false);
+      else
+        AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(*Func), 
+                                   /*FIXME:*/false, /*FIXME:*/0, 
+                                   /*FIXME:*/0, ObjectArg, Args, NumArgs,
+                                   CandidateSet,
+                                   /*SuppressUsedConversions=*/false);
+    }
       
     OverloadCandidateSet::iterator Best;
     switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Aug 21 13:42:58 2009
@@ -485,10 +485,25 @@
 
   // Build the instantiated method declaration.
   CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
-  CXXMethodDecl *Method
-    = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), 
-                            D->getDeclName(), T, D->getDeclaratorInfo(),
-                            D->isStatic(), D->isInline());
+  CXXMethodDecl *Method = 0;
+  
+  DeclarationName Name = D->getDeclName();
+  CXXConstructorDecl *ConstructorD = dyn_cast<CXXConstructorDecl>(D);
+  if (ConstructorD) {
+    QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+    Name = SemaRef.Context.DeclarationNames.getCXXConstructorName(
+                                    SemaRef.Context.getCanonicalType(ClassTy));
+    Method = CXXConstructorDecl::Create(SemaRef.Context, Record, 
+                                        ConstructorD->getLocation(), 
+                                        Name, T, 
+                                        ConstructorD->getDeclaratorInfo(),
+                                        ConstructorD->isExplicit(), 
+                                        ConstructorD->isInline(), false);
+  } else {
+    Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), 
+                                   D->getDeclName(), T, D->getDeclaratorInfo(),
+                                   D->isStatic(), D->isInline());
+  }
 
   if (!FunctionTemplate)
     Method->setInstantiationOfMemberFunction(D);
@@ -507,15 +522,20 @@
   if (InitMethodInstantiation(Method, D))
     Method->setInvalidDecl();
 
-  NamedDecl *PrevDecl 
-    = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(), 
-                                  Sema::LookupOrdinaryName, true);
-  // In C++, the previous declaration we find might be a tag type
-  // (class or enum). In this case, the new declaration will hide the
-  // tag type. Note that this does does not apply if we're declaring a
-  // typedef (C++ [dcl.typedef]p4).
-  if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
-    PrevDecl = 0;
+  NamedDecl *PrevDecl = 0;
+  
+  if (!FunctionTemplate) {
+    PrevDecl = SemaRef.LookupQualifiedName(Owner, Name, 
+                                           Sema::LookupOrdinaryName, true);
+  
+    // In C++, the previous declaration we find might be a tag type
+    // (class or enum). In this case, the new declaration will hide the
+    // tag type. Note that this does does not apply if we're declaring a
+    // typedef (C++ [dcl.typedef]p4).
+    if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+      PrevDecl = 0;
+  }
+  
   bool Redeclaration = false;
   bool OverloadableAttrRequired = false;
   SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
@@ -528,60 +548,16 @@
                                               &TemplateArgs,
                                               InsertPos);
   else if (!Method->isInvalidDecl() || !PrevDecl)
-      Owner->addDecl(Method);
+    Owner->addDecl(Method);
+  
   return Method;
 }
 
 Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  // FIXME: Look for existing, explicit specializations.
-  Sema::LocalInstantiationScope Scope(SemaRef);
-
-  llvm::SmallVector<ParmVarDecl *, 4> Params;
-  QualType T = InstantiateFunctionType(D, Params);
-  if (T.isNull())
-    return 0;
-
-  // Build the instantiated method declaration.
-  CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
-  QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
-  DeclarationName Name
-    = SemaRef.Context.DeclarationNames.getCXXConstructorName(
-                                 SemaRef.Context.getCanonicalType(ClassTy));
-  CXXConstructorDecl *Constructor
-    = CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(), 
-                                 Name, T, D->getDeclaratorInfo(),
-                                 D->isExplicit(), D->isInline(), false);
-  Constructor->setInstantiationOfMemberFunction(D);
-
-  // Attach the parameters
-  for (unsigned P = 0; P < Params.size(); ++P)
-    Params[P]->setOwningFunction(Constructor);
-  Constructor->setParams(SemaRef.Context, Params.data(), Params.size());
-
-  if (InitMethodInstantiation(Constructor, D))
-    Constructor->setInvalidDecl();
-
-  NamedDecl *PrevDecl 
-    = SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true);
-
-  // In C++, the previous declaration we find might be a tag type
-  // (class or enum). In this case, the new declaration will hide the
-  // tag type. Note that this does does not apply if we're declaring a
-  // typedef (C++ [dcl.typedef]p4).
-  if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
-    PrevDecl = 0;
-  bool Redeclaration = false;
-  bool OverloadableAttrRequired = false;
-  SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration,
-                                   /*FIXME:*/OverloadableAttrRequired);
-
-  Record->addedConstructor(SemaRef.Context, Constructor);
-  Owner->addDecl(Constructor);
-  return Constructor;
+  return VisitCXXMethodDecl(D);
 }
 
 Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
-  // FIXME: Look for existing, explicit specializations.
   Sema::LocalInstantiationScope Scope(SemaRef);
 
   llvm::SmallVector<ParmVarDecl *, 4> Params;

Added: cfe/trunk/test/SemaTemplate/constructor-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constructor-template.cpp?rev=79658&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (added)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Fri Aug 21 13:42:58 2009
@@ -0,0 +1,24 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+struct X0 { // expected-note{{candidate}}
+  X0(int); // expected-note{{candidate}}
+  template<typename T> X0(T);
+  template<typename T, typename U> X0(T*, U*);
+};
+
+void accept_X0(X0);
+
+void test_X0(int i, float f) {
+  X0 x0a(i);
+  X0 x0b(f);
+  X0 x0c = i;
+  X0 x0d = f;
+  accept_X0(i);
+  accept_X0(&i);
+  accept_X0(f);
+  accept_X0(&f);
+  X0 x0e(&i, &f);
+  X0 x0f(&f, &i);
+  
+  X0 x0g(f, &i); // expected-error{{no matching constructor}}
+}

Modified: cfe/trunk/test/SemaTemplate/member-function-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/member-function-template.cpp?rev=79658&r1=79657&r2=79658&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/member-function-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/member-function-template.cpp Fri Aug 21 13:42:58 2009
@@ -27,4 +27,4 @@
   int &ir1 = x.f1(i);
   int &ir2 = x.f1(f, i);
   int &ir3 = x.f1(i, i);
-}
\ No newline at end of file
+}





More information about the cfe-commits mailing list