]> granicus.if.org Git - clang/commitdiff
Implement implicit instantiation of the member functions of a class template
authorDouglas Gregor <dgregor@apple.com>
Mon, 22 Jun 2009 23:06:13 +0000 (23:06 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 22 Jun 2009 23:06:13 +0000 (23:06 +0000)
specialization. At present, all implicit instantiations occur at the
end of the translation unit.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73915 91177308-0d34-0410-b5e6-96231b3b80d8

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 [new file with mode: 0644]
test/SemaTemplate/example-dynarray.cpp

index 69152523a112ec08fc54573619724d9b28418764..426f56f4380e5da5eb91cfd51fad39700d8f898f 100644 (file)
@@ -273,7 +273,7 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) {
 /// [C++]   template-declaration
 /// [C++]   namespace-definition
 /// [C++]   using-directive
-/// [C++]   using-declaration [TODO]
+/// [C++]   using-declaration
 /// [C++0x] static_assert-declaration
 ///         others... [FIXME]
 ///
index 2fa09b9046461086d81d129a0abb6422d62865bd..c37f66dae907178c122190772250011c82f262dc 100644 (file)
@@ -235,6 +235,18 @@ void Sema::DeleteStmt(StmtTy *S) {
 /// 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;
 
index 28f81e614a33c159a965df7510c92d0105ce732e..e5502a5937800e4cfa06f0a46c4f941c88570a64 100644 (file)
@@ -31,6 +31,7 @@
 #include "llvm/ADT/OwningPtr.h"
 #include <list>
 #include <string>
+#include <queue>
 #include <vector>
 
 namespace llvm {
@@ -2504,6 +2505,22 @@ public:
   /// 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 @@ public:
   void InstantiateVariableDefinition(VarDecl *Var);
 
   NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D);
-  
+    
   // Simple function for cloning expressions.
   template<typename T> 
   OwningExprResult Clone(T *E) {
index 04c569a528a4f898df2d91e072cd8e46be2a8839..e8265d9ad9e91e09a2c96f67b99e69666ce67049 100644 (file)
@@ -1921,6 +1921,7 @@ void Sema::InitializeVarWithConstructor(VarDecl *VD,
                                         Expr **Exprs, unsigned NumExprs) {
   Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor, 
                                         false, Exprs, NumExprs);
+  MarkDeclarationReferenced(VD->getLocation(), Constructor);
   VD->setInit(Context, Temp);
 }
 
index c005f103a30db5193b31e7717c0560ee82b2a74e..81765a57d60cf1411aed4fa2279e99049bcdc75a 100644 (file)
@@ -2134,25 +2134,32 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
         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 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
 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 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
     // 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;
index 461302f81d58003b9010b79b25dd4bcf4a1d1efc..ece71bc0d3269625f5629a4a2f1d32224275f529 100644 (file)
@@ -597,6 +597,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
   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 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
 
   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
+  }
+}
diff --git a/test/CodeGenCXX/implicit-instantiation-1.cpp b/test/CodeGenCXX/implicit-instantiation-1.cpp
new file mode 100644 (file)
index 0000000..f6c6114
--- /dev/null
@@ -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
+}
+
+
+
index cca3709bebbf9836c785be8e9b0803d90242a520..680ee04ba18e17b872b5e7eac9bf308570b9612c 100644 (file)
@@ -89,6 +89,21 @@ public:
   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 @@ struct Point {
   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 @@ int main() {
        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;
 }