diff options
28 files changed, 337 insertions, 129 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 0838a3d0eb..fab63f556b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -586,6 +586,8 @@ public: /// specified typename decl. QualType getTypedefType(const TypedefDecl *Decl); + QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST); + QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, QualType Replacement); @@ -602,6 +604,11 @@ public: const TemplateArgumentListInfo &Args, QualType Canon = QualType()); + TypeSourceInfo * + getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, + const TemplateArgumentListInfo &Args, + QualType Canon = QualType()); + QualType getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType); QualType getTypenameType(NestedNameSpecifier *NNS, diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 91aeff3439..bd9f01b0b5 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1429,7 +1429,6 @@ class TypeDecl : public NamedDecl { friend class DeclContext; friend class TagDecl; friend class TemplateTypeParmDecl; - friend class ClassTemplateSpecializationDecl; friend class TagType; protected: diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index ced174716c..560ce46ede 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -771,6 +771,10 @@ class ClassTemplateSpecializationDecl llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *> SpecializedTemplate; + /// \brief The type-as-written of an explicit template specialization. + /// Does not apply to implicit specializations. + TypeSourceInfo *TypeAsWritten; + /// \brief The template arguments used to describe this specialization. TemplateArgumentList TemplateArgs; @@ -883,8 +887,14 @@ public: /// \brief Sets the type of this specialization as it was written by /// the user. This will be a class template specialization type. - void setTypeAsWritten(QualType T) { - TypeForDecl = T.getTypePtr(); + void setTypeAsWritten(TypeSourceInfo *T) { + TypeAsWritten = T; + } + + /// \brief Gets the type of this specialization as it was written by + /// the user, if it was so written. + TypeSourceInfo *getTypeAsWritten() const { + return TypeAsWritten; } void Profile(llvm::FoldingSetNodeID &ID) const { @@ -921,6 +931,7 @@ class ClassTemplatePartialSpecializationDecl TemplateParameterList* TemplateParams; /// \brief The source info for the template arguments as written. + /// FIXME: redundant with TypeAsWritten? TemplateArgumentLoc *ArgsAsWritten; unsigned NumArgsAsWritten; @@ -954,6 +965,7 @@ public: ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, const TemplateArgumentListInfo &ArgInfos, + QualType CanonInjectedType, ClassTemplatePartialSpecializationDecl *PrevDecl); /// Get the list of template parameters @@ -1139,8 +1151,8 @@ public: /// the type \p T, or NULL if no such partial specialization exists. ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T); - /// \brief Retrieve the type of the injected-class-name for this - /// class template. + /// \brief Retrieve the template specialization type of the + /// injected-class-name for this class template. /// /// The injected-class-name for a class template \c X is \c /// X<template-args>, where \c template-args is formed from the @@ -1153,7 +1165,7 @@ public: /// typedef array this_type; // "array" is equivalent to "array<T, N>" /// }; /// \endcode - QualType getInjectedClassNameType(ASTContext &Context); + QualType getInjectedClassNameSpecialization(ASTContext &Context); /// \brief Retrieve the member class template that this class template was /// derived from. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index bd8a6bc846..111be55621 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2440,6 +2440,47 @@ 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. +/// +/// For consistency, 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). +class InjectedClassNameType : public Type { + CXXRecordDecl *Decl; + + QualType UnderlyingType; + + friend class ASTContext; // ASTContext creates these. + InjectedClassNameType(CXXRecordDecl *D, QualType TST, QualType Canon) + : Type(InjectedClassName, Canon, Canon->isDependentType()), + Decl(D), UnderlyingType(TST) { + assert(isa<TemplateSpecializationType>(TST)); + assert(!TST.hasQualifiers()); + assert(TST->getCanonicalTypeInternal() == Canon); + } + +public: + QualType getUnderlyingType() const { return UnderlyingType; } + const TemplateSpecializationType *getUnderlyingTST() const { + return cast<TemplateSpecializationType>(UnderlyingType.getTypePtr()); + } + + CXXRecordDecl *getDecl() const { return Decl; } + + bool isSugared() const { return true; } + QualType desugar() const { return UnderlyingType; } + + static bool classof(const Type *T) { + return T->getTypeClass() == InjectedClassName; + } + static bool classof(const InjectedClassNameType *T) { return true; } +}; + /// \brief Represents a type that was referred to via a qualified /// name, e.g., N::M::type. /// diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 6fb51edb76..27659bd02f 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -488,6 +488,14 @@ public: } }; +/// \brief Wrapper for source info for injected class names of class +/// templates. +class InjectedClassNameTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + InjectedClassNameTypeLoc, + InjectedClassNameType> { +}; + /// \brief Wrapper for source info for unresolved typename using decls. class UnresolvedUsingTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 8187caddc6..e75202e50a 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -91,6 +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(Typename, Type) TYPE(ObjCInterface, Type) TYPE(ObjCObjectPointer, Type) diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index d4014b3075..e234e9838a 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -408,7 +408,9 @@ namespace clang { /// \brief A SubstTemplateTypeParmType record. TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, /// \brief An UnresolvedUsingType record. - TYPE_UNRESOLVED_USING = 26 + TYPE_UNRESOLVED_USING = 26, + /// \brief An InjectedClassNameType record. + TYPE_INJECTED_CLASS_NAME = 27 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e2c80a6da5..f134bfdf1f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -888,6 +888,10 @@ ASTContext::getTypeInfo(const Type *T) { 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"); @@ -1918,6 +1922,39 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, return QualType(FTP, 0); } +#ifndef NDEBUG +static bool NeedsInjectedClassNameType(const RecordDecl *D) { + if (!isa<CXXRecordDecl>(D)) return false; + const CXXRecordDecl *RD = cast<CXXRecordDecl>(D); + if (isa<ClassTemplatePartialSpecializationDecl>(RD)) + return true; + if (RD->getDescribedClassTemplate() && + !isa<ClassTemplateSpecializationDecl>(RD)) + return true; + return false; +} +#endif + +/// getInjectedClassNameType - Return the unique reference to the +/// injected class name type for the specified templated declaration. +QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, + QualType TST) { + assert(NeedsInjectedClassNameType(Decl)); + if (Decl->TypeForDecl) { + assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); + } else if (CXXRecordDecl *PrevDecl + = cast_or_null<CXXRecordDecl>(Decl->getPreviousDeclaration())) { + assert(PrevDecl->TypeForDecl && "previous declaration has no type"); + Decl->TypeForDecl = PrevDecl->TypeForDecl; + assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); + } else { + Decl->TypeForDecl = new (*this, TypeAlignment) + InjectedClassNameType(Decl, TST, TST->getCanonicalTypeInternal()); + Types.push_back(Decl->TypeForDecl); + } + return QualType(Decl->TypeForDecl, 0); +} + /// getTypeDeclType - Return the unique reference to the type for the /// specified type declaration. QualType ASTContext::getTypeDeclType(const TypeDecl *Decl, @@ -1936,8 +1973,10 @@ QualType ASTContext::getTypeDeclType(const TypeDecl *Decl, if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; - else + else { + assert(!NeedsInjectedClassNameType(Record)); Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Record); + } } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { if (PrevDecl) Decl->TypeForDecl = PrevDecl->TypeForDecl; @@ -2022,6 +2061,24 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, return QualType(TypeParm, 0); } +TypeSourceInfo * +ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo &Args, + QualType CanonType) { + QualType TST = getTemplateSpecializationType(Name, Args, CanonType); + + TypeSourceInfo *DI = CreateTypeSourceInfo(TST); + TemplateSpecializationTypeLoc TL + = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc()); + TL.setTemplateNameLoc(NameLoc); + TL.setLAngleLoc(Args.getLAngleLoc()); + TL.setRAngleLoc(Args.getRAngleLoc()); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, Args[i].getLocInfo()); + return DI; +} + QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 7402b7dda4..866b7f799f 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -56,6 +56,12 @@ static bool ShouldAKA(ASTContext &Context, QualType QT, QT = cast<QualifiedNameType>(Ty)->desugar(); 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)) { diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index bf1551a099..d9c0d7b6be 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -610,6 +610,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } + case Type::InjectedClassName: { + const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1); + const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2); + if (!IsStructurallyEquivalent(Context, + Inj1->getUnderlyingType(), + Inj2->getUnderlyingType())) + return false; + break; + } + case Type::Typename: { const TypenameType *Typename1 = cast<TypenameType>(T1); const TypenameType *Typename2 = cast<TypenameType>(T2); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 9db6ae1329..a9495343e8 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -574,11 +574,22 @@ DeclContext *DeclContext::getPrimaryContext() { if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) { // If this is a tag type that has a definition or is currently // being defined, that definition is our primary context. - if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAs<TagType>()) - if (TagT->isBeingDefined() || - (TagT->getDecl() && TagT->getDecl()->isDefinition())) - return TagT->getDecl(); - return this; + TagDecl *Tag = cast<TagDecl>(this); + assert(isa<TagType>(Tag->TypeForDecl) || + isa<InjectedClassNameType>(Tag->TypeForDecl)); + + if (TagDecl *Def = Tag->getDefinition()) + return Def; + + if (!isa<InjectedClassNameType>(Tag->TypeForDecl)) { + const TagType *TagTy = cast<TagType>(Tag->TypeForDecl); + if (TagTy->isBeingDefined()) + // FIXME: is it necessarily being defined in the decl + // that owns the type? + return TagTy->getDecl(); + } + + return Tag; } assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast && diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 9b693af5bc..7f4ad34fb7 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -636,11 +636,16 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const { assert(isInstance() && "No 'this' for static methods!"); - QualType ClassTy; - if (ClassTemplateDecl *TD = getParent()->getDescribedClassTemplate()) - ClassTy = TD->getInjectedClassNameType(C); - else - ClassTy = C.getTagDeclType(getParent()); + 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); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index d80db45f45..b449398624 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -193,7 +193,8 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { return 0; } -QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { +QualType +ClassTemplateDecl::getInjectedClassNameSpecialization(ASTContext &Context) { if (!CommonPtr->InjectedClassNameType.isNull()) return CommonPtr->InjectedClassNameType; @@ -393,6 +394,7 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, SpecializedTemplate->getIdentifier(), PrevDecl), SpecializedTemplate(SpecializedTemplate), + TypeAsWritten(0), TemplateArgs(Context, Builder, /*TakeArgs=*/true), SpecializationKind(TSK_Undeclared) { } @@ -453,6 +455,7 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, ClassTemplateDecl *SpecializedTemplate, TemplateArgumentListBuilder &Builder, const TemplateArgumentListInfo &ArgInfos, + QualType CanonInjectedType, ClassTemplatePartialSpecializationDecl *PrevDecl) { unsigned N = ArgInfos.size(); TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; @@ -467,7 +470,8 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L, ClonedArgs, N, PrevDecl); Result->setSpecializationKind(TSK_ExplicitSpecialization); - Context.getTypeDeclType(Result, PrevDecl); + + Context.getInjectedClassNameType(Result, CanonInjectedType); return Result; } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 5b621cf728..6e88ca32ca 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -30,7 +30,7 @@ namespace { explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } void Print(QualType T, std::string &S); - void PrintTag(const TagType *T, std::string &S); + void PrintTag(TagDecl *T, std::string &S); #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) \ void Print##CLASS(const CLASS##Type *T, std::string &S); @@ -330,19 +330,21 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, Print(T->getResultType(), S); } -void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T, - std::string &S) { - IdentifierInfo *II = T->getDecl()->getIdentifier(); +static void PrintTypeSpec(const NamedDecl *D, std::string &S) { + IdentifierInfo *II = D->getIdentifier(); if (S.empty()) S = II->getName().str(); else S = II->getName().str() + ' ' + S; } +void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T, + std::string &S) { + PrintTypeSpec(T->getDecl(), S); +} + void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) { - if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. - S = ' ' + S; - S = T->getDecl()->getIdentifier()->getName().str() + S; + PrintTypeSpec(T->getDecl(), S); } void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) { @@ -371,18 +373,18 @@ void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) { S = "decltype(" + s.str() + ")" + S; } -void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) { +void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { if (Policy.SuppressTag) return; if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; - const char *Kind = Policy.SuppressTagKind? 0 : T->getDecl()->getKindName(); + const char *Kind = Policy.SuppressTagKind? 0 : D->getKindName(); const char *ID; - if (const IdentifierInfo *II = T->getDecl()->getIdentifier()) + if (const IdentifierInfo *II = D->getIdentifier()) ID = II->getNameStart(); - else if (TypedefDecl *Typedef = T->getDecl()->getTypedefForAnonDecl()) { + else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) { Kind = 0; assert(Typedef->getIdentifier() && "Typedef without identifier?"); ID = Typedef->getIdentifier()->getNameStart(); @@ -392,13 +394,22 @@ void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) { // If this is a class template specialization, print the template // arguments. if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) { - const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + const TemplateArgument *Args; + unsigned NumArgs; + if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { + const TemplateSpecializationType *TST = + cast<TemplateSpecializationType>(TAW->getType()); + Args = TST->getArgs(); + NumArgs = TST->getNumArgs(); + } else { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + Args = TemplateArgs.getFlatArgumentList(); + NumArgs = TemplateArgs.flat_size(); + } std::string TemplateArgsStr - = TemplateSpecializationType::PrintTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size(), - Policy); + = TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, + Policy); InnerString = TemplateArgsStr + InnerString; } @@ -406,7 +417,7 @@ void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) { // Compute the full nested-name-specifier for this type. In C, // this will always be empty. std::string ContextStr; - for (DeclContext *DC = T->getDecl()->getDeclContext(); + for (DeclContext *DC = D->getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { std::string MyPart; if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { @@ -441,11 +452,11 @@ void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) { } void TypePrinter::PrintRecord(const RecordType *T, std::string &S) { - PrintTag(T, S); + PrintTag(T->getDecl(), S); } void TypePrinter::PrintEnum(const EnumType *T, std::string &S) { - PrintTag(T, S); + PrintTag(T->getDecl(), S); } void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) { @@ -494,6 +505,12 @@ void TypePrinter::PrintTemplateSpecialization( S = SpecString + ' ' + S; } +void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T, + std::string &S) { + // TODO: this should probably be printed with template arguments + PrintTag(T->getDecl(), S); +} + void TypePrinter::PrintQualifiedName(const QualifiedNameType *T, std::string &S) { std::string MyString; diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 705d7f3c52..c3302e661d 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1246,6 +1246,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, case Type::MemberPointer: return CreateType(cast<MemberPointerType>(Ty), Unit); + case Type::InjectedClassName: case Type::TemplateSpecialization: case Type::Elaborated: case Type::QualifiedName: diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 9a5cae6e81..267f4c1585 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2018,6 +2018,12 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), Replacement); } + + case pch::TYPE_INJECTED_CLASS_NAME: { + CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0])); + QualType TST = GetType(Record[1]); // probably derivable + return Context->getInjectedClassNameType(D, TST); + } } // Suppress a GCC warning return QualType(); @@ -2172,6 +2178,9 @@ void TypeLocReader::VisitTemplateSpecializationTypeLoc( void TypeLocReader::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } +void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} void TypeLocReader::VisitTypenameTypeLoc(TypenameTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 93af754683..eed3cc1a5b 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -235,6 +235,12 @@ void PCHTypeWriter::VisitQualifiedNameType(const QualifiedNameType *T) { assert(false && "Cannot serialize qualified name types"); } +void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { + Writer.AddDeclRef(T->getDecl(), Record); + Writer.AddTypeRef(T->getUnderlyingType(), Record); + Code = pch::TYPE_INJECTED_CLASS_NAME; +} + void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { Writer.AddDeclRef(T->getDecl(), Record); Record.push_back(T->getNumProtocols()); @@ -394,6 +400,9 @@ void TypeLocWriter::VisitTemplateSpecializationTypeLoc( void TypeLocWriter::VisitQualifiedNameTypeLoc(QualifiedNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } +void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} void TypeLocWriter::VisitTypenameTypeLoc(TypenameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 971b78c489..95b79abd8f 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -76,14 +76,6 @@ getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext, // our context. if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T) return Record; - - if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { - QualType InjectedClassName - = Template->getInjectedClassNameType(Context); - if (T == Context.getCanonicalType(InjectedClassName)) - return Template->getTemplatedDecl(); - } - // FIXME: check for class template partial specializations } return 0; @@ -130,8 +122,11 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, return Record; if (EnteringContext) { - if (const TemplateSpecializationType *SpecType - = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) { + const Type *NNSType = NNS->getAsType(); + if (!NNSType) { + // do nothing, fall out + } else if (const TemplateSpecializationType *SpecType + = NNSType->getAs<TemplateSpecializationType>()) { // We are entering the context of the nested name specifier, so try to // match the nested name specifier to either a primary class template // or a class template partial specialization. @@ -144,7 +139,8 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, // If the type of the nested name specifier is the same as the // injected class name of the named class template, we're entering // into that class template definition. - QualType Injected = ClassTemplate->getInjectedClassNameType(Context); + QualType Injected + = ClassTemplate->getInjectedClassNameSpecialization(Context); if (Context.hasSameType(Injected, ContextType)) return ClassTemplate->getTemplatedDecl(); @@ -156,8 +152,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, = ClassTemplate->findPartialSpecialization(ContextType)) return PartialSpec; } - } else if (const RecordType *RecordT - = dyn_cast_or_null<RecordType>(NNS->getAsType())) { + } else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) { // The nested name specifier refers to a member of a class template. return RecordT->getDecl(); } @@ -248,7 +243,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. const TagType *TagT = Context.getTypeDeclType(Tag)->getAs<TagType>(); - if (TagT->isBeingDefined()) + if (TagT && TagT->isBeingDefined()) return false; // The type must be complete. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 82dcd60aa0..94fcfc6c29 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -188,18 +188,6 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { DiagnoseUseOfDecl(IIDecl, NameLoc); - // C++ [temp.local]p2: - // Within the scope of a class template specialization or - // partial specialization, when the injected-class-name is - // not followed by a <, it is equivalent to the - // injected-class-name followed by the template-argument s - // of the class template specialization or partial - // specialization enclosed in <>. - if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) - if (RD->isInjectedClassName()) - if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate()) - T = Template->getInjectedClassNameType(Context); - if (T.isNull()) T = Context.getTypeDeclType(TD); @@ -1773,12 +1761,7 @@ DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { return DeclarationName(); // Determine the type of the class being constructed. - QualType CurClassType; - if (ClassTemplateDecl *ClassTemplate - = CurClass->getDescribedClassTemplate()) - CurClassType = ClassTemplate->getInjectedClassNameType(Context); - else - CurClassType = Context.getTypeDeclType(CurClass); + QualType CurClassType = Context.getTypeDeclType(CurClass); // FIXME: Check two things: that the template-id names the same type as // CurClassType, and that the template-id does not occur when the name diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 79cab15e69..e694cb470c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -665,22 +665,29 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, (CXXBaseSpecifier**)(Bases), NumBases); } +static CXXRecordDecl *GetClassForType(QualType T) { + if (const RecordType *RT = T->getAs<RecordType>()) + return cast<CXXRecordDecl>(RT->getDecl()); + else if (const InjectedClassNameType *ICT = T->getAs<InjectedClassNameType>()) + return ICT->getDecl(); + else + return 0; +} + /// \brief Determine whether the type \p Derived is a C++ class that is /// derived from the type \p Base. bool Sema::IsDerivedFrom(QualType Derived, QualType Base) { if (!getLangOptions().CPlusPlus) return false; - - const RecordType *DerivedRT = Derived->getAs<RecordType>(); - if (!DerivedRT) + + CXXRecordDecl *DerivedRD = GetClassForType(Derived); + if (!DerivedRD) return false; - const RecordType *BaseRT = Base->getAs<RecordType>(); - if (!BaseRT) + CXXRecordDecl *BaseRD = GetClassForType(Base); + if (!BaseRD) return false; - CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl()); - CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl()); // FIXME: instantiate DerivedRD if necessary. We need a PoI for this. return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD); } @@ -691,16 +698,14 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { if (!getLangOptions().CPlusPlus) return false; - const RecordType *DerivedRT = Derived->getAs<RecordType>(); - if (!DerivedRT) + CXXRecordDecl *DerivedRD = GetClassForType(Derived); + if (!DerivedRD) return false; - const RecordType *BaseRT = Base->getAs<RecordType>(); - if (!BaseRT) + CXXRecordDecl *BaseRD = GetClassForType(Base); + if (!BaseRD) return false; - CXXRecordDecl *DerivedRD = cast<CXXRecordDecl>(DerivedRT->getDecl()); - CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(BaseRT->getDecl()); return DerivedRD->isDerivedFrom(BaseRD, Paths); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 309da292e1..b9c8afa195 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -172,14 +172,6 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { QualType T = Context.getTypeDeclType(Type); - // If we found the injected-class-name of a class template, retrieve the - // type of that template. - // FIXME: We really shouldn't need to do this. - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Type)) - if (Record->isInjectedClassName()) - if (Record->getDescribedClassTemplate()) - T = Record->getDescribedClassTemplate() - ->getInjectedClassNameType(Context); if (SearchType.isNull() || SearchType->isDependentType() || Context.hasSameUnqualifiedType(T, SearchType)) { @@ -200,16 +192,8 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, if (SS.isSet()) { if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { // Figure out the type of the context, if it has one. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) - MemberOfType = Context.getTypeDeclType(Spec); - else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) { - if (Record->getDescribedClassTemplate()) - MemberOfType = Record->getDescribedClassTemplate() - ->getInjectedClassNameType(Context); - else - MemberOfType = Context.getTypeDeclType(Record); - } + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) + MemberOfType = Context.getTypeDeclType(Record); } } if (MemberOfType.isNull()) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 445b68b167..7c4cab1183 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -871,10 +871,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, NewClass->setDescribedClassTemplate(NewTemplate); // Build the type for the class template declaration now. - QualType T = - Context.getTypeDeclType(NewClass, - PrevClassTemplate? - PrevClassTemplate->getTemplatedDecl() : 0); + QualType T = NewTemplate->getInjectedClassNameSpecialization(Context); + T = Context.getInjectedClassNameType(NewClass, T); assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; @@ -1306,7 +1304,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, TemplateParameterList *ExpectedTemplateParams = 0; // Is this template-id naming the primary template? if (Context.hasSameType(TemplateId, - ClassTemplate->getInjectedClassNameType(Context))) + ClassTemplate->getInjectedClassNameSpecialization(Context))) ExpectedTemplateParams = ClassTemplate->getTemplateParameters(); // ... or a partial specialization? else if (ClassTemplatePartialSpecializationDecl *PartialSpec @@ -1431,6 +1429,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, } CanonType = Context.getTypeDeclType(Decl); + assert(isa<RecordType>(CanonType) && + "type of non-dependent specialization is not a RecordType"); } // Build the fully-sugared type for this class template @@ -3488,6 +3488,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate, Converted, TemplateArgs, + CanonType, PrevPartial); if (PrevPartial) { @@ -3609,8 +3610,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // actually wrote the specialization, rather than formatting the // name based on the "canonical" representation used to store the // template arguments in the specialization. - QualType WrittenTy - = Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); + TypeSourceInfo *WrittenTy + = Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc, + TemplateArgs, CanonType); if (TUK != TUK_Friend) Specialization->setTypeAsWritten(WrittenTy); TemplateArgsIn.release(); @@ -3632,7 +3634,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TUK == TUK_Friend) { FriendDecl *Friend = FriendDecl::Create(Context, CurContext, TemplateNameLoc, - WrittenTy.getTypePtr(), + WrittenTy->getType().getTypePtr(), /*FIXME:*/KWLoc); Friend->setAccess(AS_public); CurContext->addDecl(Friend); @@ -4344,8 +4346,9 @@ Sema::ActOnExplicitInstantiation(Scope *S, // the explicit instantiation, rather than formatting the name based // on the "canonical" representation used to store the template // arguments in the specialization. - QualType WrittenTy - = Context.getTemplateSpecializationType(Name, TemplateArgs, + TypeSourceInfo *WrittenTy + = Context.getTemplateSpecializationTypeInfo(Name, TemplateNameLoc, + TemplateArgs, Context.getTypeDeclType(Specialization)); Specialization->setTypeAsWritten(WrittenTy); TemplateArgsIn.release(); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 7f16400aea..326519d3a3 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -625,6 +625,15 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_Success; } + case Type::InjectedClassName: { + // Treat a template's injected-class-name as if the template + // specialization type had been used. + Param = cast<InjectedClassNameType>(Param)->getUnderlyingType(); + assert(isa<TemplateSpecializationType>(Param) && + "injected class name is not a template specialization type"); + // fall through + } + // template-name<T> (where template-name refers to a class template) // template-name<i> // TT<T> diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3a6b4cb3cc..cf8d38c095 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -621,7 +621,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { Inst->setInstantiatedFromMemberTemplate(D); // Trigger creation of the type for the instantiation. - SemaRef.Context.getTypeDeclType(RecordInst); + SemaRef.Context.getInjectedClassNameType(RecordInst, + Inst->getInjectedClassNameSpecialization(SemaRef.Context)); // Finish handling of friends. if (Inst->getFriendObjectKind()) { @@ -1462,8 +1463,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // actually wrote the specialization, rather than formatting the // name based on the "canonical" representation used to store the // template arguments in the specialization. - QualType WrittenTy - = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), + TypeSourceInfo *WrittenTy + = SemaRef.Context.getTemplateSpecializationTypeInfo( + TemplateName(ClassTemplate), + PartialSpec->getLocation(), InstTemplateArgs, CanonType); @@ -1499,6 +1502,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( ClassTemplate, Converted, InstTemplateArgs, + CanonType, 0); InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); @@ -2236,12 +2240,18 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate(); if (ClassTemplate) { - T = ClassTemplate->getInjectedClassNameType(Context); + T = ClassTemplate->getInjectedClassNameSpecialization(Context); } else if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) { - T = Context.getTypeDeclType(Record); ClassTemplate = PartialSpec->getSpecializedTemplate(); - } + + // If we call SubstType with an InjectedClassNameType here we + // can end up in an infinite loop. + T = Context.getTypeDeclType(Record); + assert(isa<InjectedClassNameType>(T) && + "type of partial specialization is not an InjectedClassNameType"); + T = cast<InjectedClassNameType>(T)->getUnderlyingType(); + } if (!T.isNull()) { // Substitute into the injected-class-name to get the type @@ -2308,16 +2318,16 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // so now we need to look into the instantiated parent context to // find the instantiation of the declaration D. - // If our context is a class template specialization, we may need - // to instantiate it before performing lookup into that context. - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(ParentDC)) { + // If our context used to be dependent, we may need to instantiate + // it before performing lookup into that context. + if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) { if (!Spec->isDependentContext()) { QualType T = Context.getTypeDeclType(Spec); - if (const TagType *Tag = T->getAs<TagType>()) - if (!Tag->isBeingDefined() && - RequireCompleteType(Loc, T, diag::err_incomplete_type)) - return 0; + const RecordType *Tag = T->getAs<RecordType>(); + assert(Tag && "type of non-dependent record is not a RecordType"); + if (!Tag->isBeingDefined() && + RequireCompleteType(Loc, T, diag::err_incomplete_type)) + return 0; } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 24ea62cde1..17f94193fe 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -2823,6 +2823,20 @@ QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, return Result; } +template<typename Derived> +QualType TreeTransform<Derived>::TransformInjectedClassNameType( + TypeLocBuilder &TLB, + InjectedClassNameTypeLoc TL, + QualType ObjectType) { + Decl *D = getDerived().TransformDecl(TL.getNameLoc(), + TL.getTypePtr()->getDecl()); + if (!D) return QualType(); + + QualType T = SemaRef.Context.getTypeDeclType(cast<TypeDecl>(D)); + TLB.pushTypeSpec(T).setNameLoc(TL.getNameLoc()); + return T; +} + template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateTypeParmType( diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp index 392888e71b..dd3df63912 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp @@ -52,7 +52,7 @@ void e3(union B<A>::Member); void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}} template <class T> struct C { - void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B<int>'}} + void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'struct B<int>'}} }; C<float> f1; diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp index 482eae14ba..586be189b0 100644 --- a/test/SemaTemplate/injected-class-name.cpp +++ b/test/SemaTemplate/injected-class-name.cpp @@ -42,3 +42,9 @@ struct X1 { void f0(const X1<T, N>&); // expected-error{{redecl}} }; +namespace pr6326 { + template <class T> class A { + friend class A; + }; + template class A<int>; +} diff --git a/test/SemaTemplate/instantiation-default-1.cpp b/test/SemaTemplate/instantiation-default-1.cpp index 6f5a660d99..391589e250 100644 --- a/test/SemaTemplate/instantiation-default-1.cpp +++ b/test/SemaTemplate/instantiation-default-1.cpp @@ -36,7 +36,7 @@ typedef int& int_ref_t; Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}} -template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<int const>'}} +template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'struct Def1<int const>'}} template<typename T, typename T2 = T&> struct Def3; |