[cfe-commits] r102407 - in /cfe/trunk: include/clang/AST/ lib/AST/ lib/CodeGen/ lib/Frontend/ lib/Sema/ test/SemaTemplate/

John McCall rjmccall at apple.com
Mon Apr 26 17:57:59 PDT 2010


Author: rjmccall
Date: Mon Apr 26 19:57:59 2010
New Revision: 102407

URL: http://llvm.org/viewvc/llvm-project?rev=102407&view=rev
Log:
Make the InjectedClassNameType the canonical type of the current instantiation
of a class template or class template partial specialization.  That is to
say, in
  template <class T> class A { ... };
or
  template <class T> class B<const T*> { ... };
make 'A<T>' and 'B<const T*>' sugar for the corresponding InjectedClassNameType
when written inside the appropriate context.  This allows us to track the
current instantiation appropriately even inside AST routines.  It also allows
us to compute a DeclContext for a type much more efficiently, at some extra
cost every time we write a template specialization (which can be optimized,
but I've left it simple in this patch).


Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/AST/TypeNodes.def
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/ASTDiagnostic.cpp
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypePrinter.cpp
    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
    cfe/trunk/lib/CodeGen/Mangle.cpp
    cfe/trunk/lib/Frontend/PCHWriter.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/instantiate-member-expr.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Mon Apr 26 19:57:59 2010
@@ -600,11 +600,13 @@
   QualType getTemplateSpecializationType(TemplateName T,
                                          const TemplateArgument *Args,
                                          unsigned NumArgs,
-                                         QualType Canon = QualType());
+                                         QualType Canon = QualType(),
+                                         bool IsCurrentInstantiation = false);
 
   QualType getTemplateSpecializationType(TemplateName T,
                                          const TemplateArgumentListInfo &Args,
-                                         QualType Canon = QualType());
+                                         QualType Canon = QualType(),
+                                         bool IsCurrentInstantiation = false);
 
   TypeSourceInfo *
   getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc,

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Mon Apr 26 19:57:59 2010
@@ -1122,6 +1122,15 @@
            "Only member templates can be member template specializations");
     return First->InstantiatedFromMember.setInt(true);
   }
+
+  /// Retrieves the injected specialization type for this partial
+  /// specialization.  This is not the same as the type-decl-type for
+  /// this partial specialization, which is an InjectedClassNameType.
+  QualType getInjectedSpecializationType() const {
+    assert(getTypeForDecl() && "partial specialization has no type set!");
+    return cast<InjectedClassNameType>(getTypeForDecl())
+             ->getInjectedSpecializationType();
+  }
     
   // FIXME: Add Profile support!
 

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Apr 26 19:57:59 2010
@@ -2434,8 +2434,11 @@
 class TemplateSpecializationType
   : public Type, public llvm::FoldingSetNode {
 
-  // FIXME: Currently needed for profiling expressions; can we avoid this?
-  ASTContext &Context;
+  // The ASTContext is currently needed in order to profile expressions.
+  // FIXME: avoid this.
+  //
+  // The bool is whether this is a current instantiation.
+  llvm::PointerIntPair<ASTContext*, 1, bool> ContextAndCurrentInstantiation;
 
     /// \brief The name of the template being specialized.
   TemplateName Template;
@@ -2446,6 +2449,7 @@
 
   TemplateSpecializationType(ASTContext &Context,
                              TemplateName T,
+                             bool IsCurrentInstantiation,
                              const TemplateArgument *Args,
                              unsigned NumArgs, QualType Canon);
 
@@ -2477,6 +2481,12 @@
   static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &,
                                                const PrintingPolicy &Policy);
 
+  /// True if this template specialization type matches a current
+  /// instantiation in the context in which it is found.
+  bool isCurrentInstantiation() const {
+    return ContextAndCurrentInstantiation.getInt();
+  }
+
   typedef const TemplateArgument * iterator;
 
   iterator begin() const { return getArgs(); }
@@ -2497,15 +2507,20 @@
   /// \precondition @c isArgType(Arg)
   const TemplateArgument &getArg(unsigned Idx) const;
 
-  bool isSugared() const { return !isDependentType(); }
+  bool isSugared() const {
+    return !isDependentType() || isCurrentInstantiation();
+  }
   QualType desugar() const { return getCanonicalTypeInternal(); }
 
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, Template, getArgs(), NumArgs, Context);
+    Profile(ID, Template, isCurrentInstantiation(), getArgs(), NumArgs,
+            *ContextAndCurrentInstantiation.getPointer());
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
-                      const TemplateArgument *Args, unsigned NumArgs,
+                      bool IsCurrentInstantiation,
+                      const TemplateArgument *Args,
+                      unsigned NumArgs,
                       ASTContext &Context);
 
   static bool classof(const Type *T) {
@@ -2514,40 +2529,56 @@
   static bool classof(const TemplateSpecializationType *T) { return true; }
 };
 
-/// \brief The injected class name of a C++ class template.  Used to
-/// record that a type was spelled with a bare identifier rather than
-/// as a template-id; the equivalent for non-templated classes is just
-/// RecordType.
+/// \brief The injected class name of a C++ class template or class
+/// template partial specialization.  Used to record that a type was
+/// spelled with a bare identifier rather than as a template-id; the
+/// equivalent for non-templated classes is just RecordType.
 ///
-/// For consistency, template instantiation turns these into RecordTypes.
+/// Injected class name types are always dependent.  Template
+/// instantiation turns these into RecordTypes.
 ///
-/// The desugared form is always a unqualified TemplateSpecializationType.
-/// The canonical form is always either a TemplateSpecializationType
-/// (when dependent) or a RecordType (otherwise).
+/// Injected class name types are always canonical.  This works
+/// because it is impossible to compare an injected class name type
+/// with the corresponding non-injected template type, for the same
+/// reason that it is impossible to directly compare template
+/// parameters from different dependent contexts: injected class name
+/// types can only occur within the scope of a particular templated
+/// declaration, and within that scope every template specialization
+/// will canonicalize to the injected class name (when appropriate
+/// according to the rules of the language).
 class InjectedClassNameType : public Type {
   CXXRecordDecl *Decl;
 
-  QualType UnderlyingType;
+  /// The template specialization which this type represents.
+  /// For example, in
+  ///   template <class T> class A { ... };
+  /// this is A<T>, whereas in
+  ///   template <class X, class Y> class A<B<X,Y> > { ... };
+  /// this is A<B<X,Y> >.
+  ///
+  /// It is always unqualified, always a template specialization type,
+  /// and always dependent.
+  QualType InjectedType;
 
   friend class ASTContext; // ASTContext creates these.
-  InjectedClassNameType(CXXRecordDecl *D, QualType TST, QualType Canon)
-    : Type(InjectedClassName, Canon, Canon->isDependentType()),
-      Decl(D), UnderlyingType(TST) {
+  InjectedClassNameType(CXXRecordDecl *D, QualType TST)
+    : Type(InjectedClassName, QualType(), true),
+      Decl(D), InjectedType(TST) {
     assert(isa<TemplateSpecializationType>(TST));
     assert(!TST.hasQualifiers());
-    assert(TST->getCanonicalTypeInternal() == Canon);
+    assert(TST->isDependentType());
   }
 
 public:
-  QualType getUnderlyingType() const { return UnderlyingType; }
-  const TemplateSpecializationType *getUnderlyingTST() const {
-    return cast<TemplateSpecializationType>(UnderlyingType.getTypePtr());
+  QualType getInjectedSpecializationType() const { return InjectedType; }
+  const TemplateSpecializationType *getInjectedTST() const {
+    return cast<TemplateSpecializationType>(InjectedType.getTypePtr());
   }
 
   CXXRecordDecl *getDecl() const { return Decl; }
 
-  bool isSugared() const { return true; }
-  QualType desugar() const { return UnderlyingType; }
+  bool isSugared() const { return false; }
+  QualType desugar() const { return QualType(this, 0); }
 
   static bool classof(const Type *T) {
     return T->getTypeClass() == InjectedClassName;

Modified: cfe/trunk/include/clang/AST/TypeNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeNodes.def?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TypeNodes.def (original)
+++ cfe/trunk/include/clang/AST/TypeNodes.def Mon Apr 26 19:57:59 2010
@@ -91,7 +91,7 @@
 NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
 NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
 NON_CANONICAL_TYPE(QualifiedName, Type)
-NON_CANONICAL_TYPE(InjectedClassName, Type)
+DEPENDENT_TYPE(InjectedClassName, Type)
 DEPENDENT_TYPE(DependentName, Type)
 TYPE(ObjCInterface, Type)
 TYPE(ObjCObjectPointer, Type)
@@ -105,6 +105,8 @@
 #ifdef LEAF_TYPE
 LEAF_TYPE(Enum)
 LEAF_TYPE(Builtin)
+LEAF_TYPE(Record)
+LEAF_TYPE(InjectedClassName)
 LEAF_TYPE(ObjCInterface)
 LEAF_TYPE(TemplateTypeParm)
 #undef LEAF_TYPE

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Apr 26 19:57:59 2010
@@ -653,10 +653,6 @@
   case Type::QualifiedName:
     return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr());
 
- case Type::InjectedClassName:
-   return getTypeInfo(cast<InjectedClassNameType>(T)
-                        ->getUnderlyingType().getTypePtr());
-
   case Type::TemplateSpecialization:
     assert(getCanonicalType(T) != T &&
            "Cannot request the size of a dependent type");
@@ -1741,8 +1737,8 @@
     Decl->TypeForDecl = PrevDecl->TypeForDecl;
     assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
   } else {
-    Decl->TypeForDecl = new (*this, TypeAlignment)
-      InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal());
+    Decl->TypeForDecl =
+      new (*this, TypeAlignment) InjectedClassNameType(Decl, TST);
     Types.push_back(Decl->TypeForDecl);
   }
   return QualType(Decl->TypeForDecl, 0);
@@ -1873,7 +1869,8 @@
 QualType
 ASTContext::getTemplateSpecializationType(TemplateName Template,
                                           const TemplateArgumentListInfo &Args,
-                                          QualType Canon) {
+                                          QualType Canon,
+                                          bool IsCurrentInstantiation) {
   unsigned NumArgs = Args.size();
 
   llvm::SmallVector<TemplateArgument, 4> ArgVec;
@@ -1881,17 +1878,23 @@
   for (unsigned i = 0; i != NumArgs; ++i)
     ArgVec.push_back(Args[i].getArgument());
 
-  return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Canon);
+  return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs,
+                                       Canon, IsCurrentInstantiation);
 }
 
 QualType
 ASTContext::getTemplateSpecializationType(TemplateName Template,
                                           const TemplateArgument *Args,
                                           unsigned NumArgs,
-                                          QualType Canon) {
+                                          QualType Canon,
+                                          bool IsCurrentInstantiation) {
   if (!Canon.isNull())
     Canon = getCanonicalType(Canon);
   else {
+    assert(!IsCurrentInstantiation &&
+           "current-instantiation specializations should always "
+           "have a canonical type");
+
     // Build the canonical template specialization type.
     TemplateName CanonTemplate = getCanonicalTemplateName(Template);
     llvm::SmallVector<TemplateArgument, 4> CanonArgs;
@@ -1902,7 +1905,7 @@
     // Determine whether this canonical template specialization type already
     // exists.
     llvm::FoldingSetNodeID ID;
-    TemplateSpecializationType::Profile(ID, CanonTemplate,
+    TemplateSpecializationType::Profile(ID, CanonTemplate, false,
                                         CanonArgs.data(), NumArgs, *this);
 
     void *InsertPos = 0;
@@ -1914,7 +1917,7 @@
       void *Mem = Allocate((sizeof(TemplateSpecializationType) +
                             sizeof(TemplateArgument) * NumArgs),
                            TypeAlignment);
-      Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate,
+      Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate, false,
                                                   CanonArgs.data(), NumArgs,
                                                   Canon);
       Types.push_back(Spec);
@@ -1934,7 +1937,9 @@
                         sizeof(TemplateArgument) * NumArgs),
                        TypeAlignment);
   TemplateSpecializationType *Spec
-    = new (Mem) TemplateSpecializationType(*this, Template, Args, NumArgs,
+    = new (Mem) TemplateSpecializationType(*this, Template,
+                                           IsCurrentInstantiation,
+                                           Args, NumArgs,
                                            Canon);
 
   Types.push_back(Spec);

Modified: cfe/trunk/lib/AST/ASTDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDiagnostic.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDiagnostic.cpp (original)
+++ cfe/trunk/lib/AST/ASTDiagnostic.cpp Mon Apr 26 19:57:59 2010
@@ -57,12 +57,6 @@
       continue;
     }
 
-    // ...or an injected class name...
-    if (isa<InjectedClassNameType>(Ty)) {
-      QT = cast<InjectedClassNameType>(Ty)->desugar();
-      continue;
-    }
-    
     // ...or a substituted template type parameter.
     if (isa<SubstTemplateTypeParmType>(Ty)) {
       QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Apr 26 19:57:59 2010
@@ -612,8 +612,8 @@
     const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1);
     const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2);
     if (!IsStructurallyEquivalent(Context,
-                                  Inj1->getUnderlyingType(),
-                                  Inj2->getUnderlyingType()))
+                                  Inj1->getInjectedSpecializationType(),
+                                  Inj2->getInjectedSpecializationType()))
       return false;
     break;
   }

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Apr 26 19:57:59 2010
@@ -659,15 +659,6 @@
   assert(isInstance() && "No 'this' for static methods!");
 
   QualType ClassTy = C.getTypeDeclType(getParent());
-
-  // Aesthetically we prefer not to synthesize a type as the
-  // InjectedClassNameType of a template pattern: injected class names
-  // are printed without template arguments, which might
-  // surprise/confuse/distract our poor users if they didn't
-  // explicitly write one.
-  if (isa<InjectedClassNameType>(ClassTy))
-    ClassTy = cast<InjectedClassNameType>(ClassTy)->getUnderlyingType();
-
   ClassTy = C.getQualifiedType(ClassTy,
                                Qualifiers::fromCVRMask(getTypeQualifiers()));
   return C.getPointerType(ClassTy);

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Mon Apr 26 19:57:59 2010
@@ -186,7 +186,7 @@
   for (partial_spec_iterator P = getPartialSpecializations().begin(),
                           PEnd = getPartialSpecializations().end();
        P != PEnd; ++P) {
-    if (Context.hasSameType(Context.getTypeDeclType(&*P), T))
+    if (Context.hasSameType(P->getInjectedSpecializationType(), T))
       return &*P;
   }
 

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Apr 26 19:57:59 2010
@@ -1004,12 +1004,13 @@
 
 TemplateSpecializationType::
 TemplateSpecializationType(ASTContext &Context, TemplateName T,
+                           bool IsCurrentInstantiation,
                            const TemplateArgument *Args,
                            unsigned NumArgs, QualType Canon)
   : Type(TemplateSpecialization,
          Canon.isNull()? QualType(this, 0) : Canon,
          T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
-    Context(Context),
+    ContextAndCurrentInstantiation(&Context, IsCurrentInstantiation),
     Template(T), NumArgs(NumArgs) {
   assert((!Canon.isNull() ||
           T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
@@ -1044,9 +1045,11 @@
 void
 TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
                                     TemplateName T,
+                                    bool IsCurrentInstantiation,
                                     const TemplateArgument *Args,
                                     unsigned NumArgs,
                                     ASTContext &Context) {
+  ID.AddBoolean(IsCurrentInstantiation);
   T.Profile(ID);
   for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
     Args[Idx].Profile(ID, Context);

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Mon Apr 26 19:57:59 2010
@@ -546,7 +546,7 @@
 
 void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T,
                                          std::string &S) {
-  PrintTemplateSpecialization(T->getUnderlyingTST(), S);
+  PrintTemplateSpecialization(T->getInjectedTST(), S);
 }
 
 void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, 

Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon Apr 26 19:57:59 2010
@@ -1246,7 +1246,6 @@
   case Type::MemberPointer:
     return CreateType(cast<MemberPointerType>(Ty), Unit);
 
-  case Type::InjectedClassName:
   case Type::TemplateSpecialization:
   case Type::Elaborated:
   case Type::QualifiedName:

Modified: cfe/trunk/lib/CodeGen/Mangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/Mangle.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/Mangle.cpp (original)
+++ cfe/trunk/lib/CodeGen/Mangle.cpp Mon Apr 26 19:57:59 2010
@@ -1191,6 +1191,13 @@
   mangleType(T->getPointeeType());
 }
 
+void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
+  // Mangle injected class name types as if the user had written the
+  // specialization out fully.  It may not actually be possible to see
+  // this mangling, though.
+  mangleType(T->getInjectedSpecializationType());
+}
+
 void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
   TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
   assert(TD && "FIXME: Support dependent template names!");

Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriter.cpp Mon Apr 26 19:57:59 2010
@@ -63,6 +63,7 @@
 #define ABSTRACT_TYPE(Class, Base)
 #define DEPENDENT_TYPE(Class, Base)
 #include "clang/AST/TypeNodes.def"
+    void VisitInjectedClassNameType(const InjectedClassNameType *T);
   };
 }
 
@@ -240,7 +241,7 @@
 
 void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
   Writer.AddDeclRef(T->getDecl(), Record);
-  Writer.AddTypeRef(T->getUnderlyingType(), Record);
+  Writer.AddTypeRef(T->getInjectedSpecializationType(), Record);
   Code = pch::TYPE_INJECTED_CLASS_NAME;
 }
 

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Apr 26 19:57:59 2010
@@ -3047,6 +3047,7 @@
 
   QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
                                              DeclarationName Name);
+  void RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS);
 
   std::string
   getTemplateArgumentBindingsText(const TemplateParameterList *Params,

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Mon Apr 26 19:57:59 2010
@@ -24,61 +24,17 @@
 using namespace clang;
 
 /// \brief Find the current instantiation that associated with the given type.
-static CXXRecordDecl *
-getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, 
-                          QualType T) {
+static CXXRecordDecl *getCurrentInstantiationOf(QualType T) {
   if (T.isNull())
     return 0;
-  
-  T = Context.getCanonicalType(T).getUnqualifiedType();
-  
-  for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
-    // If we've hit a namespace or the global scope, then the
-    // nested-name-specifier can't refer to the current instantiation.
-    if (Ctx->isFileContext())
-      return 0;
-    
-    // Skip non-class contexts.
-    CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
-    if (!Record)
-      continue;
-    
-    // If this record type is not dependent,
-    if (!Record->isDependentType())
-      return 0;
-    
-    // C++ [temp.dep.type]p1:
-    //
-    //   In the definition of a class template, a nested class of a
-    //   class template, a member of a class template, or a member of a
-    //   nested class of a class template, a name refers to the current
-    //   instantiation if it is
-    //     -- the injected-class-name (9) of the class template or
-    //        nested class,
-    //     -- in the definition of a primary class template, the name
-    //        of the class template followed by the template argument
-    //        list of the primary template (as described below)
-    //        enclosed in <>,
-    //     -- in the definition of a nested class of a class template,
-    //        the name of the nested class referenced as a member of
-    //        the current instantiation, or
-    //     -- in the definition of a partial specialization, the name
-    //        of the class template followed by the template argument
-    //        list of the partial specialization enclosed in <>. If
-    //        the nth template parameter is a parameter pack, the nth
-    //        template argument is a pack expansion (14.6.3) whose
-    //        pattern is the name of the parameter pack.
-    //        (FIXME: parameter packs)
-    //
-    // All of these options come down to having the
-    // nested-name-specifier type that is equivalent to the
-    // injected-class-name of one of the types that is currently in
-    // our context.
-    if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
-      return Record;
-  }  
-  
-  return 0;
+
+  const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
+  if (isa<RecordType>(Ty))
+    return cast<CXXRecordDecl>(cast<RecordType>(Ty)->getDecl());
+  else if (isa<InjectedClassNameType>(Ty))
+    return cast<InjectedClassNameType>(Ty)->getDecl();
+  else
+    return 0;
 }
 
 /// \brief Compute the DeclContext that is associated with the given type.
@@ -92,7 +48,7 @@
   if (const TagType *Tag = T->getAs<TagType>())
     return Tag->getDecl();
 
-  return ::getCurrentInstantiationOf(Context, CurContext, T);
+  return ::getCurrentInstantiationOf(T);
 }
 
 /// \brief Compute the DeclContext that is associated with the given
@@ -218,7 +174,7 @@
     return 0;
 
   QualType T = QualType(NNS->getAsType(), 0);
-  return ::getCurrentInstantiationOf(Context, CurContext, T);
+  return ::getCurrentInstantiationOf(T);
 }
 
 /// \brief Require that the context specified by SS be complete.
@@ -704,6 +660,11 @@
     return true;
     
   EnterDeclaratorContext(S, DC);
+
+  // Rebuild the nested name specifier for the new scope.
+  if (DC->isDependentContext())
+    RebuildNestedNameSpecifierInCurrentInstantiation(SS);
+
   return false;
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Apr 26 19:57:59 2010
@@ -1344,27 +1344,25 @@
 
     // Check the template parameter list against its corresponding template-id.
     if (DependentTemplateId) {
-      TemplateDecl *Template
-        = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
+      TemplateParameterList *ExpectedTemplateParams = 0;
 
-      if (ClassTemplateDecl *ClassTemplate
-            = dyn_cast<ClassTemplateDecl>(Template)) {
-        TemplateParameterList *ExpectedTemplateParams = 0;
-        // Is this template-id naming the primary template?
-        if (Context.hasSameType(TemplateId,
-                 ClassTemplate->getInjectedClassNameSpecialization(Context)))
-          ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
-        // ... or a partial specialization?
-        else if (ClassTemplatePartialSpecializationDecl *PartialSpec
-                   = ClassTemplate->findPartialSpecialization(TemplateId))
-          ExpectedTemplateParams = PartialSpec->getTemplateParameters();
-
-        if (ExpectedTemplateParams)
-          TemplateParameterListsAreEqual(ParamLists[Idx],
-                                         ExpectedTemplateParams,
-                                         true, TPL_TemplateMatch);
+      // Are there cases in (e.g.) friends where this won't match?
+      if (const InjectedClassNameType *Injected
+            = TemplateId->getAs<InjectedClassNameType>()) {
+        CXXRecordDecl *Record = Injected->getDecl();
+        if (ClassTemplatePartialSpecializationDecl *Partial =
+              dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
+          ExpectedTemplateParams = Partial->getTemplateParameters();
+        else
+          ExpectedTemplateParams = Record->getDescribedClassTemplate()
+            ->getTemplateParameters();
       }
 
+      if (ExpectedTemplateParams)
+        TemplateParameterListsAreEqual(ParamLists[Idx],
+                                       ExpectedTemplateParams,
+                                       true, TPL_TemplateMatch);
+
       CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember);
     } else if (ParamLists[Idx]->size() > 0)
       Diag(ParamLists[Idx]->getTemplateLoc(),
@@ -1430,6 +1428,7 @@
          "Converted template argument list is too short!");
 
   QualType CanonType;
+  bool IsCurrentInstantiation = false;
 
   if (Name.isDependent() ||
       TemplateSpecializationType::anyDependentTemplateArguments(
@@ -1451,6 +1450,45 @@
     // In the future, we need to teach getTemplateSpecializationType to only
     // build the canonical type and return that to us.
     CanonType = Context.getCanonicalType(CanonType);
+
+    // This might work out to be a current instantiation, in which
+    // case the canonical type needs to be the InjectedClassNameType.
+    //
+    // TODO: in theory this could be a simple hashtable lookup; most
+    // changes to CurContext don't change the set of current
+    // instantiations.
+    if (isa<ClassTemplateDecl>(Template)) {
+      for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
+        // If we get out to a namespace, we're done.
+        if (Ctx->isFileContext()) break;
+
+        // If this isn't a record, keep looking.
+        CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
+        if (!Record) continue;
+
+        // Look for one of the two cases with InjectedClassNameTypes
+        // and check whether it's the same template.
+        if (!isa<ClassTemplatePartialSpecializationDecl>(Record) &&
+            !Record->getDescribedClassTemplate())
+          continue;
+          
+        // Fetch the injected class name type and check whether its
+        // injected type is equal to the type we just built.
+        QualType ICNT = Context.getTypeDeclType(Record);
+        QualType Injected = cast<InjectedClassNameType>(ICNT)
+          ->getInjectedSpecializationType();
+
+        if (CanonType != Injected->getCanonicalTypeInternal())
+          continue;
+
+        // If so, the canonical type of this TST is the injected
+        // class name type of the record we just found.
+        assert(ICNT.isCanonical());
+        CanonType = ICNT;
+        IsCurrentInstantiation = true;
+        break;
+      }
+    }
   } else if (ClassTemplateDecl *ClassTemplate
                = dyn_cast<ClassTemplateDecl>(Template)) {
     // Find the class template specialization declaration that
@@ -1484,7 +1522,8 @@
   // Build the fully-sugared type for this class template
   // specialization, which refers back to the class template
   // specialization we created or found.
-  return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType);
+  return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType,
+                                               IsCurrentInstantiation);
 }
 
 Action::TypeResult
@@ -5389,6 +5428,17 @@
   return Rebuilder.TransformType(T);
 }
 
+void Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) {
+  if (SS.isInvalid()) return;
+
+  NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+  CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(),
+                                          DeclarationName());
+  NestedNameSpecifier *Rebuilt = 
+    Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange());
+  if (Rebuilt) SS.setScopeRep(Rebuilt);
+}
+
 /// \brief Produces a formatted string that describes the binding of
 /// template parameters to template arguments.
 std::string

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Apr 26 19:57:59 2010
@@ -638,7 +638,8 @@
     case Type::InjectedClassName: {
       // Treat a template's injected-class-name as if the template
       // specialization type had been used.
-      Param = cast<InjectedClassNameType>(Param)->getUnderlyingType();
+      Param = cast<InjectedClassNameType>(Param)
+        ->getInjectedSpecializationType();
       assert(isa<TemplateSpecializationType>(Param) &&
              "injected class name is not a template specialization type");
       // fall through
@@ -2340,13 +2341,16 @@
   // are more constrained. We know that every template parameter is deduc
   llvm::SmallVector<DeducedTemplateArgument, 4> Deduced;
   Sema::TemplateDeductionInfo Info(Context, Loc);
+
+  QualType PT1 = PS1->getInjectedSpecializationType();
+  QualType PT2 = PS2->getInjectedSpecializationType();
   
   // Determine whether PS1 is at least as specialized as PS2
   Deduced.resize(PS2->getTemplateParameters()->size());
   bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
                                                   PS2->getTemplateParameters(),
-                                                  Context.getTypeDeclType(PS2),
-                                                  Context.getTypeDeclType(PS1),
+                                                               PT2,
+                                                               PT1,
                                                                Info,
                                                                Deduced,
                                                                0);
@@ -2356,8 +2360,8 @@
   Deduced.resize(PS1->getTemplateParameters()->size());
   bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(*this,
                                                   PS1->getTemplateParameters(),
-                                                  Context.getTypeDeclType(PS1),
-                                                  Context.getTypeDeclType(PS2),
+                                                               PT1,
+                                                               PT2,
                                                                Info,
                                                                Deduced,
                                                                0);
@@ -2537,6 +2541,10 @@
     break;
   }
 
+  case Type::InjectedClassName:
+    T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
+    // fall through
+
   case Type::TemplateSpecialization: {
     const TemplateSpecializationType *Spec
       = cast<TemplateSpecializationType>(T);

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Apr 26 19:57:59 2010
@@ -2500,7 +2500,7 @@
       T = Context.getTypeDeclType(Record);
       assert(isa<InjectedClassNameType>(T) &&
              "type of partial specialization is not an InjectedClassNameType");
-      T = cast<InjectedClassNameType>(T)->getUnderlyingType();
+      T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType();
     }  
     
     if (!T.isNull()) {

Modified: cfe/trunk/test/SemaTemplate/instantiate-member-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-member-expr.cpp?rev=102407&r1=102406&r2=102407&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-member-expr.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-member-expr.cpp Mon Apr 26 19:57:59 2010
@@ -43,7 +43,7 @@
     int a;
     template<typename T> struct B : A<T> {
       void f() {
-        a = 0; // expected-error {{type 'test1::O' is not a direct or virtual base of ''B<int>''}}
+        a = 0; // expected-error {{type 'test1::O' is not a direct or virtual base of ''test1::O::B<int>''}}
       }
     };
   };





More information about the cfe-commits mailing list