[cfe-commits] r73915 - in /cfe/trunk: lib/Parse/ParseDecl.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CodeGenCXX/implicit-instantiation-1.cpp test/SemaTemplate/example-dynarray.cpp

Douglas Gregor dgregor at apple.com
Mon Jun 22 16:06:13 PDT 2009


Author: dgregor
Date: Mon Jun 22 18:06:13 2009
New Revision: 73915

URL: http://llvm.org/viewvc/llvm-project?rev=73915&view=rev
Log:
Implement implicit instantiation of the member functions of a class template
specialization. At present, all implicit instantiations occur at the
end of the translation unit.

Added:
    cfe/trunk/test/CodeGenCXX/implicit-instantiation-1.cpp
Modified:
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/example-dynarray.cpp

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jun 22 18:06:13 2009
@@ -273,7 +273,7 @@
 /// [C++]   template-declaration
 /// [C++]   namespace-definition
 /// [C++]   using-directive
-/// [C++]   using-declaration [TODO]
+/// [C++]   using-declaration
 /// [C++0x] static_assert-declaration
 ///         others... [FIXME]
 ///

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Mon Jun 22 18:06:13 2009
@@ -235,6 +235,18 @@
 /// translation unit when EOF is reached and all but the top-level scope is
 /// popped.
 void Sema::ActOnEndOfTranslationUnit() {
+  // C++: Perform implicit template instantiations.
+  //
+  // FIXME: When we perform these implicit instantiations, we do not carefully
+  // keep track of the point of instantiation (C++ [temp.point]). This means
+  // that name lookup that occurs within the template instantiation will
+  // always happen at the end of the translation unit, so it will find
+  // some names that should not be found. Although this is common behavior 
+  // for C++ compilers, it is technically wrong. In the future, we either need
+  // to be able to filter the results of name lookup or we need to perform
+  // template instantiations earlier.
+  PerformPendingImplicitInstantiations();
+  
   if (!CompleteTranslationUnit)
     return;
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=73915&r1=73914&r2=73915&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Jun 22 18:06:13 2009
@@ -31,6 +31,7 @@
 #include "llvm/ADT/OwningPtr.h"
 #include <list>
 #include <string>
+#include <queue>
 #include <vector>
 
 namespace llvm {
@@ -2504,6 +2505,22 @@
   /// variables.
   LocalInstantiationScope *CurrentInstantiationScope;
 
+  /// \brief An entity for which implicit template instantiation is required.
+  ///
+  /// The source location associated with the declaration is the first place in 
+  /// the source code where the declaration was "used". It is not necessarily
+  /// the point of instantiation (which will be either before or after the 
+  /// namespace-scope declaration that triggered this implicit instantiation),
+  /// However, it is the location that diagnostics should generally refer to,
+  /// because users will need to know what code triggered the instantiation.
+  typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation;
+  
+  /// \brief The queue of implicit template instantiations that are required
+  /// but have not yet been performed.
+  std::queue<PendingImplicitInstantiation> PendingImplicitInstantiations;
+
+  void PerformPendingImplicitInstantiations();
+  
   QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs,
                            SourceLocation Loc, DeclarationName Entity);
   
@@ -2559,7 +2576,7 @@
   void InstantiateVariableDefinition(VarDecl *Var);
 
   NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D);
-  
+    
   // Simple function for cloning expressions.
   template<typename T> 
   OwningExprResult Clone(T *E) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jun 22 18:06:13 2009
@@ -1921,6 +1921,7 @@
                                         Expr **Exprs, unsigned NumExprs) {
   Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor, 
                                         false, Exprs, NumExprs);
+  MarkDeclarationReferenced(VD->getLocation(), Constructor);
   VD->setInit(Context, Temp);
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jun 22 18:06:13 2009
@@ -2134,25 +2134,32 @@
         MemberType = MemberType.getQualifiedType(combinedQualifiers);
       }
 
+      MarkDeclarationReferenced(MemberLoc, FD);
       return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
                                             MemberLoc, MemberType));
     }
     
-    if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl))
+    if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
+      MarkDeclarationReferenced(MemberLoc, MemberDecl);
       return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
                                             Var, MemberLoc,
                                          Var->getType().getNonReferenceType()));
-    if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl))
+    }
+    if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
+      MarkDeclarationReferenced(MemberLoc, MemberDecl);
       return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
                                             MemberFn, MemberLoc,
                                             MemberFn->getType()));
+    }
     if (OverloadedFunctionDecl *Ovl
           = dyn_cast<OverloadedFunctionDecl>(MemberDecl))
       return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
                                             MemberLoc, Context.OverloadTy));
-    if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl))
+    if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
+      MarkDeclarationReferenced(MemberLoc, MemberDecl);
       return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
                                             Enum, MemberLoc, Enum->getType()));
+    }
     if (isa<TypeDecl>(MemberDecl))
       return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
         << DeclarationName(&Member) << int(OpKind == tok::arrow));
@@ -5475,6 +5482,9 @@
 void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
   assert(D && "No declaration?");
   
+  if (D->isUsed())
+    return;
+  
   // Mark a parameter declaration "used", regardless of whether we're in a
   // template or not.
   if (isa<ParmVarDecl>(D))
@@ -5512,16 +5522,22 @@
     // FIXME: more checking for other implicits go here.
     else
       Constructor->setUsed(true);
-    return;
   } 
   
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
-    // FIXME: implicit template instantiation
+    // Implicit instantiation of function templates
+    if (!Function->getBody(Context)) {
+      if (Function->getInstantiatedFromMemberFunction())
+        PendingImplicitInstantiations.push(std::make_pair(Function, Loc));
+
+      // FIXME: check for function template specializations.
+    }
+    
+    
     // FIXME: keep track of references to static functions
-    (void)Function;
     Function->setUsed(true);
     return;
-  } 
+  }
   
   if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
     (void)Var;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jun 22 18:06:13 2009
@@ -597,6 +597,8 @@
   if (Function->isInvalidDecl())
     return;
 
+  assert(!Function->getBody(Context) && "Already instantiated!");
+  
   // Find the function body that we'll be substituting.
   const FunctionDecl *PatternDecl 
     = Function->getInstantiatedFromMemberFunction();
@@ -776,3 +778,18 @@
 
   return D;
 }
+
+/// \brief Performs template instantiation for all implicit template 
+/// instantiations we have seen until this point.
+void Sema::PerformPendingImplicitInstantiations() {
+  while (!PendingImplicitInstantiations.empty()) {
+    PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
+    PendingImplicitInstantiations.pop();
+    
+    if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first))
+      if (!Function->getBody(Context))
+        InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function);
+    
+    // FIXME: instantiation static member variables
+  }
+}

Added: cfe/trunk/test/CodeGenCXX/implicit-instantiation-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/implicit-instantiation-1.cpp?rev=73915&view=auto

==============================================================================
--- cfe/trunk/test/CodeGenCXX/implicit-instantiation-1.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/implicit-instantiation-1.cpp Mon Jun 22 18:06:13 2009
@@ -0,0 +1,29 @@
+// RUN: clang-cc -emit-llvm %s -o %t &&
+
+template<typename T>
+struct X {
+  void f(T) { }
+  void f(char) { }
+  
+  void g(T) { }
+  
+  void h(T) { }
+};
+
+void foo(X<int> &xi, X<float> *xfp, int i, float f) {
+  // RUN: grep "linkonce_odr.*_ZN1XIiE1fEi" %t | count 1 &&
+  xi.f(i);
+  
+  // RUN: grep "linkonce_odr.*_ZN1XIiE1gEi" %t | count 1 &&
+  xi.g(f);
+  
+  // RUN: grep "linkonce_odr.*_ZN1XIfE1fEf" %t | count 1 &&
+  xfp->f(f);
+  
+  // RUN: grep "linkonce_odr.*_ZN1XIfE1hEf" %t | count 0 &&
+  
+  // RUN: true
+}
+
+
+

Modified: cfe/trunk/test/SemaTemplate/example-dynarray.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/example-dynarray.cpp?rev=73915&r1=73914&r2=73915&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/example-dynarray.cpp (original)
+++ cfe/trunk/test/SemaTemplate/example-dynarray.cpp Mon Jun 22 18:06:13 2009
@@ -89,6 +89,21 @@
   iterator end() { return Last; }
   const_iterator end() const { return Last; }
   
+  bool operator==(const dynarray &other) const {
+    if (size() != other.size())
+      return false;
+    
+    for (unsigned I = 0, N = size(); I != N; ++I)
+      if ((*this)[I] != other[I])
+        return false;
+    
+    return true;
+  }
+  
+  bool operator!=(const dynarray &other) const {
+    return !(*this == other);
+  }
+  
 public:
   T* Start, *Last, *End;
 };
@@ -100,11 +115,6 @@
   float x, y, z;
 };
 
-// FIXME: remove these when we have implicit instantiation for member
-// functions of class templates.
-template class dynarray<int>;
-template class dynarray<Point>;
-
 int main() {
   dynarray<int> di;
   di.push_back(0);
@@ -146,5 +156,13 @@
        I != IEnd; ++I)
     assert(*I == I - di4.begin());
 
+  assert(di4 == di);
+  di4[3] = 17;
+  assert(di4 != di);
+  
+  dynarray<Point> dp;
+  dp.push_back(Point());
+  assert(dp.size() == 1);
+  
   return 0;
 }





More information about the cfe-commits mailing list