[cfe-commits] r72461 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Sema/SemaTemplateInstantiateExpr.cpp test/SemaTemplate/example-dynarray.cpp

Douglas Gregor dgregor at apple.com
Tue May 26 22:35:13 PDT 2009


Author: dgregor
Date: Wed May 27 00:35:12 2009
New Revision: 72461

URL: http://llvm.org/viewvc/llvm-project?rev=72461&view=rev
Log:
Initial stab at a generalized operation for determining the
instantiation of a declaration from the template version (or version
that lives in a template) and a given set of template arguments. This
needs much, much more testing, but it suffices for simple examples
like

  typedef T* iterator;
  iterator begin();



Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp
    cfe/trunk/test/SemaTemplate/example-dynarray.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed May 27 00:35:12 2009
@@ -2138,7 +2138,7 @@
     /// this template instantiation.
     Sema &SemaRef;
 
-    /// \brief A mapping from local variable declarations that occur
+    /// \brief A mapping from local declarations that occur
     /// within a template to their instantiations.
     ///
     /// This mapping is used during instantiation to keep track of,
@@ -2152,7 +2152,7 @@
     /// when we instantiate add<int>, we will introduce a mapping from
     /// the ParmVarDecl for 'x' that occurs in the template to the
     /// instantiated ParmVarDecl for 'x'.
-    llvm::DenseMap<const VarDecl *, VarDecl *> LocalDecls;
+    llvm::DenseMap<const Decl *, Decl *> LocalDecls;
 
     /// \brief The outer scope, in which contains local variable
     /// definitions from some other instantiation (that is not
@@ -2173,20 +2173,24 @@
       SemaRef.CurrentInstantiationScope = Outer;
     }
 
-    VarDecl *getInstantiationOf(const VarDecl *Var) {
-      VarDecl *Result = LocalDecls[Var];
-      assert(Result && "Variable was not instantiated in this scope!");
+    Decl *getInstantiationOf(const Decl *D) {
+      Decl *Result = LocalDecls[D];
+      assert(Result && "declaration was not instantiated in this scope!");
       return Result;
     }
 
+    VarDecl *getInstantiationOf(const VarDecl *Var) {
+      return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var)));
+    }
+
     ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) {
-      return cast<ParmVarDecl>(getInstantiationOf(cast<VarDecl>(Var)));
+      return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var)));
     }
 
-    void InstantiatedLocal(const VarDecl *Var, VarDecl *VarInst) {
-      VarDecl *&Stored = LocalDecls[Var];
-      assert(!Stored && "Already instantiated this local variable");
-      Stored = VarInst;
+    void InstantiatedLocal(const Decl *D, Decl *Inst) {
+      Decl *&Stored = LocalDecls[D];
+      assert(!Stored && "Already instantiated this local");
+      Stored = Inst;
     }
   };
 
@@ -2246,6 +2250,9 @@
                                      FunctionDecl *Function);
   void InstantiateVariableDefinition(VarDecl *Var);
 
+  NamedDecl *
+  InstantiateDeclRef(NamedDecl *D, const TemplateArgumentList &TemplateArgs);
+  
   // Simple function for cloning expressions.
   template<typename T> 
   OwningExprResult Clone(T *E) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed May 27 00:35:12 2009
@@ -406,9 +406,13 @@
 QualType 
 TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T,
                                                  unsigned Quals) const {
-  // FIXME: Implement this
-  assert(false && "Cannot instantiate TypedefType yet");
-  return QualType();
+  TypedefDecl *Typedef 
+    = cast_or_null<TypedefDecl>(SemaRef.InstantiateDeclRef(T->getDecl(), 
+                                                           TemplateArgs));
+  if (!Typedef)
+    return QualType();
+  
+  return SemaRef.Context.getTypeDeclType(Typedef);
 }
 
 QualType 
@@ -435,17 +439,25 @@
 QualType 
 TemplateTypeInstantiator::InstantiateRecordType(const RecordType *T,
                                                 unsigned Quals) const {
-  // FIXME: Implement this
-  assert(false && "Cannot instantiate RecordType yet");
-  return QualType();
+  RecordDecl *Record 
+    = cast_or_null<RecordDecl>(SemaRef.InstantiateDeclRef(T->getDecl(), 
+                                                          TemplateArgs));
+  if (!Record)
+    return QualType();
+  
+  return SemaRef.Context.getTypeDeclType(Record);
 }
 
 QualType 
 TemplateTypeInstantiator::InstantiateEnumType(const EnumType *T,
                                               unsigned Quals) const {
-  // FIXME: Implement this
-  assert(false && "Cannot instantiate EnumType yet");
-  return QualType();
+  EnumDecl *Enum 
+    = cast_or_null<EnumDecl>(SemaRef.InstantiateDeclRef(T->getDecl(), 
+                                                        TemplateArgs));
+  if (!Enum)
+    return QualType();
+  
+  return SemaRef.Context.getTypeDeclType(Enum);
 }
 
 QualType 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed May 27 00:35:12 2009
@@ -635,3 +635,125 @@
 void Sema::InstantiateVariableDefinition(VarDecl *Var) {
   // FIXME: Implement this!
 }
+
+static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
+  if (D->getKind() != Other->getKind())
+    return false;
+
+  if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other))
+    return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass())
+             == Ctx.getCanonicalDecl(D);
+
+  if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other))
+    return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction())
+             == Ctx.getCanonicalDecl(D);
+
+  // FIXME: Need something similar to the above for EnumDecls.
+
+  // FIXME: How can we find instantiations of anonymous unions?
+
+  return D->getDeclName() && isa<NamedDecl>(Other) &&
+    D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
+}
+
+template<typename ForwardIterator>
+static NamedDecl *findInstantiationOf(ASTContext &Ctx, 
+                                      NamedDecl *D,
+                                      ForwardIterator first,
+                                      ForwardIterator last) {
+  for (; first != last; ++first)
+    if (isInstantiationOf(Ctx, D, *first))
+      return cast<NamedDecl>(*first);
+
+  return 0;
+}
+
+/// \brief Find the instantiation of the given declaration with the
+/// given template arguments.
+///
+/// This routine is intended to be used when \p D is a declaration
+/// referenced from within a template, that needs to mapped into the
+/// corresponding declaration within an instantiation. For example,
+/// given:
+///
+/// \code
+/// template<typename T>
+/// struct X {
+///   enum Kind {
+///     KnownValue = sizeof(T)
+///   };
+///
+///   bool getKind() const { return KnownValue; }
+/// };
+///
+/// template struct X<int>;
+/// \endcode
+///
+/// In the instantiation of X<int>::getKind(), we need to map the
+/// EnumConstantDecl for KnownValue (which refers to
+/// X<T>::<Kind>::KnownValue) to its instantiation
+/// (X<int>::<Kind>::KnownValue). InstantiateDeclRef() performs this
+/// mapping, given the template arguments 'int'.
+NamedDecl *
+Sema::InstantiateDeclRef(NamedDecl *D, const TemplateArgumentList &TemplateArgs) {
+  DeclContext *ParentDC = D->getDeclContext();
+
+  if (!ParentDC->isFileContext()) {
+    NamedDecl *ParentDecl = cast<NamedDecl>(ParentDC);
+    ParentDecl = InstantiateDeclRef(ParentDecl, TemplateArgs);
+    if (!ParentDecl)
+      return 0;
+
+    ParentDC = cast<DeclContext>(ParentDecl);
+  }
+
+  if (ParentDC->isFunctionOrMethod()) {
+    // D is a local of some kind. Look into the map of local
+    // variables to their instantiations.
+    return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
+  }
+
+  if (ParentDC != D->getDeclContext()) {
+    // We performed some kind of instantiation in the parent context,
+    // so now we need to look into the instantiated parent context to
+    // find the instantiation of the declaration D.
+    NamedDecl *Result = 0;
+    if (D->getDeclName()) {
+      DeclContext::lookup_result Found
+        = ParentDC->lookup(Context, D->getDeclName());
+      Result = findInstantiationOf(Context, D, Found.first, Found.second);
+    } else {
+      // Since we don't have a name for the entity we're looking for,
+      // our only option is to walk through all of the declarations to
+      // find that name. This will occur in a few cases:
+      //
+      //   - anonymous struct/union within a template
+      //   - unnamed class/struct/union/enum within a template
+      //
+      // FIXME: Find a better way to find these instantiations!
+      Result = findInstantiationOf(Context, D, 
+                                   ParentDC->decls_begin(Context),
+                                   ParentDC->decls_end(Context));
+    }
+    assert(Result && "Unable to find instantiation of declaration!");
+    D = Result;
+  }
+
+  // D itself might be a class template that we need to instantiate
+  // with the given template arguments.
+  if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
+    if (ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate()) {
+      QualType InjectedClassName 
+        = ClassTemplate->getInjectedClassNameType(Context);
+      QualType InstantiatedType = InstantiateType(InjectedClassName,
+                                                  TemplateArgs,
+                                                  Record->getLocation(), 
+                                                  Record->getDeclName());
+      if (InstantiatedType.isNull())
+        return 0;
+      if (const RecordType *RT = InstantiatedType->getAsRecordType())
+        D = RT->getDecl();
+    }
+
+  return D;
+}

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp Wed May 27 00:35:12 2009
@@ -108,6 +108,7 @@
 
 Sema::OwningExprResult
 TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) {
+  // FIXME: Recast this in terms of Sema::InstantiateDeclRef.
   Decl *D = E->getDecl();
   ValueDecl *NewD = 0;
   if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/example-dynarray.cpp (original)
+++ cfe/trunk/test/SemaTemplate/example-dynarray.cpp Wed May 27 00:35:12 2009
@@ -77,16 +77,14 @@
     return Start[Idx];
   }
 
-  // FIXME: use these for begin/end when we can instantiate
-  // TypedefType nodes.
   typedef T* iterator;
   typedef const T* const_iterator;
 
-  T* begin() { return Start; }
-  const T* begin() const { return Start; }
+  iterator begin() { return Start; }
+  const_iterator begin() const { return Start; }
   
-  T* end() { return Last; }
-  const T* end() const { return Last; }
+  iterator end() { return Last; }
+  const_iterator end() const { return Last; }
   
 public:
   T* Start, *Last, *End;
@@ -115,6 +113,9 @@
   for (dynarray<int>::iterator I = di.begin(), IEnd = di.end(); I != IEnd; ++I)
     assert(*I == I - di.begin());
 
+  for (int I = 0, N = di.size(); I != N; ++I)
+    assert(di[I] == I);
+
   di.pop_back();
   assert(di.size() == 4);
   di.push_back(4);





More information about the cfe-commits mailing list