From: John McCall Date: Tue, 27 Apr 2010 00:57:59 +0000 (+0000) Subject: Make the InjectedClassNameType the canonical type of the current instantiation X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=31f17ecbef57b5679c017c375db330546b7b5145;p=clang 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 A { ... }; or template class B { ... }; make 'A' and 'B' 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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102407 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 71e6b6d96a..b4aa03daaa 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -600,11 +600,13 @@ public: 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, diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index da501e95b1..2bb971d814 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -1122,6 +1122,15 @@ public: "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(getTypeForDecl()) + ->getInjectedSpecializationType(); + } // FIXME: Add Profile support! diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index f42d799325..5f5377414d 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2434,8 +2434,11 @@ public: 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 ContextAndCurrentInstantiation; /// \brief The name of the template being specialized. TemplateName Template; @@ -2446,6 +2449,7 @@ class TemplateSpecializationType TemplateSpecializationType(ASTContext &Context, TemplateName T, + bool IsCurrentInstantiation, const TemplateArgument *Args, unsigned NumArgs, QualType Canon); @@ -2477,6 +2481,12 @@ public: 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 @@ public: /// \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 @@ public: 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 A { ... }; + /// this is A, whereas in + /// template class A > { ... }; + /// this is A >. + /// + /// 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(TST)); assert(!TST.hasQualifiers()); - assert(TST->getCanonicalTypeInternal() == Canon); + assert(TST->isDependentType()); } public: - QualType getUnderlyingType() const { return UnderlyingType; } - const TemplateSpecializationType *getUnderlyingTST() const { - return cast(UnderlyingType.getTypePtr()); + QualType getInjectedSpecializationType() const { return InjectedType; } + const TemplateSpecializationType *getInjectedTST() const { + return cast(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; diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 7e8b73c7a5..c665073025 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -91,7 +91,7 @@ DEPENDENT_TYPE(TemplateTypeParm, Type) 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 @@ LAST_TYPE(ObjCObjectPointer) #ifdef LEAF_TYPE LEAF_TYPE(Enum) LEAF_TYPE(Builtin) +LEAF_TYPE(Record) +LEAF_TYPE(InjectedClassName) LEAF_TYPE(ObjCInterface) LEAF_TYPE(TemplateTypeParm) #undef LEAF_TYPE diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 94d6891453..165105be89 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -653,10 +653,6 @@ ASTContext::getTypeInfo(const Type *T) { case Type::QualifiedName: return getTypeInfo(cast(T)->getNamedType().getTypePtr()); - case Type::InjectedClassName: - return getTypeInfo(cast(T) - ->getUnderlyingType().getTypePtr()); - case Type::TemplateSpecialization: assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); @@ -1741,8 +1737,8 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, Decl->TypeForDecl = PrevDecl->TypeForDecl; assert(isa(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 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, - QualType Canon) { + QualType Canon, + bool IsCurrentInstantiation) { unsigned NumArgs = Args.size(); llvm::SmallVector ArgVec; @@ -1881,17 +1878,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, 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 CanonArgs; @@ -1902,7 +1905,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, // 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 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, 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 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, 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); diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 866b7f799f..e4cd2a9c10 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -57,12 +57,6 @@ static bool ShouldAKA(ASTContext &Context, QualType QT, continue; } - // ...or an injected class name... - if (isa(Ty)) { - QT = cast(Ty)->desugar(); - continue; - } - // ...or a substituted template type parameter. if (isa(Ty)) { QT = cast(Ty)->desugar(); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 2b09575f34..ae09d7978e 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -612,8 +612,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const InjectedClassNameType *Inj1 = cast(T1); const InjectedClassNameType *Inj2 = cast(T2); if (!IsStructurallyEquivalent(Context, - Inj1->getUnderlyingType(), - Inj2->getUnderlyingType())) + Inj1->getInjectedSpecializationType(), + Inj2->getInjectedSpecializationType())) return false; break; } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index eef067b0d8..e6e9ee6cc0 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -659,15 +659,6 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { 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(ClassTy)) - ClassTy = cast(ClassTy)->getUnderlyingType(); - ClassTy = C.getQualifiedType(ClassTy, Qualifiers::fromCVRMask(getTypeQualifiers())); return C.getPointerType(ClassTy); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index b449398624..e3d30a0b27 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -186,7 +186,7 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { 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; } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d21890daf7..52ee60b984 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1004,12 +1004,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { 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 @@ TemplateSpecializationType::getArg(unsigned Idx) const { 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); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 340e373af1..7953b86716 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -546,7 +546,7 @@ void TypePrinter::PrintTemplateSpecialization( void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T, std::string &S) { - PrintTemplateSpecialization(T->getUnderlyingTST(), S); + PrintTemplateSpecialization(T->getInjectedTST(), S); } void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index d11ea1b70f..4991c0ff02 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1246,7 +1246,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast(Ty), Unit); - case Type::InjectedClassName: case Type::TemplateSpecialization: case Type::Elaborated: case Type::QualifiedName: diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 9dc3e2cf87..cb32570bd4 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -1191,6 +1191,13 @@ void CXXNameMangler::mangleType(const BlockPointerType *T) { 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!"); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 633532fdab..e56dd31322 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -63,6 +63,7 @@ namespace { #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::VisitQualifiedNameType(const QualifiedNameType *T) { 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; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3ea9bd0afa..212a36f3cc 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3047,6 +3047,7 @@ public: QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, DeclarationName Name); + void RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 89f8aec6e0..10adc6762f 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -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(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(Ty)) + return cast(cast(Ty)->getDecl()); + else if (isa(Ty)) + return cast(Ty)->getDecl(); + else + return 0; } /// \brief Compute the DeclContext that is associated with the given type. @@ -92,7 +48,7 @@ DeclContext *Sema::computeDeclContext(QualType T) { if (const TagType *Tag = T->getAs()) 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 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { 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 @@ bool Sema::ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS) { return true; EnterDeclaratorContext(S, DC); + + // Rebuild the nested name specifier for the new scope. + if (DC->isDependentContext()) + RebuildNestedNameSpecifierInCurrentInstantiation(SS); + return false; } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 958ed4498e..731836b0b1 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1344,27 +1344,25 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // Check the template parameter list against its corresponding template-id. if (DependentTemplateId) { - TemplateDecl *Template - = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl(); - - if (ClassTemplateDecl *ClassTemplate - = dyn_cast(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); + TemplateParameterList *ExpectedTemplateParams = 0; + + // Are there cases in (e.g.) friends where this won't match? + if (const InjectedClassNameType *Injected + = TemplateId->getAs()) { + CXXRecordDecl *Record = Injected->getDecl(); + if (ClassTemplatePartialSpecializationDecl *Partial = + dyn_cast(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 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, "Converted template argument list is too short!"); QualType CanonType; + bool IsCurrentInstantiation = false; if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( @@ -1451,6 +1450,45 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // 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(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(Ctx); + if (!Record) continue; + + // Look for one of the two cases with InjectedClassNameTypes + // and check whether it's the same template. + if (!isa(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(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(Template)) { // Find the class template specialization declaration that @@ -1484,7 +1522,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // 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 @@ QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, return Rebuilder.TransformType(T); } +void Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { + if (SS.isInvalid()) return; + + NestedNameSpecifier *NNS = static_cast(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 diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index d61a767dc5..7154d62d6c 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -638,7 +638,8 @@ DeduceTemplateArguments(Sema &S, case Type::InjectedClassName: { // Treat a template's injected-class-name as if the template // specialization type had been used. - Param = cast(Param)->getUnderlyingType(); + Param = cast(Param) + ->getInjectedSpecializationType(); assert(isa(Param) && "injected class name is not a template specialization type"); // fall through @@ -2340,13 +2341,16 @@ Sema::getMoreSpecializedPartialSpecialization( // are more constrained. We know that every template parameter is deduc llvm::SmallVector 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 @@ Sema::getMoreSpecializedPartialSpecialization( 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 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, break; } + case Type::InjectedClassName: + T = cast(T)->getInjectedSpecializationType(); + // fall through + case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec = cast(T); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index d14ea1a9ff..4575d47329 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2500,7 +2500,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, T = Context.getTypeDeclType(Record); assert(isa(T) && "type of partial specialization is not an InjectedClassNameType"); - T = cast(T)->getUnderlyingType(); + T = cast(T)->getInjectedSpecializationType(); } if (!T.isNull()) { diff --git a/test/SemaTemplate/instantiate-member-expr.cpp b/test/SemaTemplate/instantiate-member-expr.cpp index f3a60679d1..fe5588d57c 100644 --- a/test/SemaTemplate/instantiate-member-expr.cpp +++ b/test/SemaTemplate/instantiate-member-expr.cpp @@ -43,7 +43,7 @@ namespace test1 { int a; template struct B : A { void f() { - a = 0; // expected-error {{type 'test1::O' is not a direct or virtual base of ''B''}} + a = 0; // expected-error {{type 'test1::O' is not a direct or virtual base of ''test1::O::B''}} } }; };