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.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73915 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 6915252..426f56f 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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]
 ///
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 2fa09b9..c37f66d 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -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;
 
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 28f81e6..e5502a5 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -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) {
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 04c569a..e8265d9 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -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);
 }
 
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c005f10..81765a5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 461302f..ece71bc 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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
+  }
+}
diff --git a/test/CodeGenCXX/implicit-instantiation-1.cpp b/test/CodeGenCXX/implicit-instantiation-1.cpp
new file mode 100644
index 0000000..f6c6114
--- /dev/null
+++ b/test/CodeGenCXX/implicit-instantiation-1.cpp
@@ -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
+}
+
+
+
diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp
index cca3709..680ee04 100644
--- a/test/SemaTemplate/example-dynarray.cpp
+++ b/test/SemaTemplate/example-dynarray.cpp
@@ -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;
 }