diff options
-rw-r--r-- | clang/include/clang/AST/ASTContext.h | 4 | ||||
-rw-r--r-- | clang/include/clang/AST/Type.h | 53 | ||||
-rw-r--r-- | clang/include/clang/AST/TypeLoc.h | 15 | ||||
-rw-r--r-- | clang/include/clang/AST/TypeNodes.def | 1 | ||||
-rw-r--r-- | clang/include/clang/Frontend/PCHBitCodes.h | 4 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 28 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Frontend/PCHReader.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Frontend/PCHWriter.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 128 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 7 |
12 files changed, 241 insertions, 35 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index c4e81b41bc3..493d8acf3b8 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -81,6 +81,7 @@ class ASTContext { llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes; llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes; llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; + llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes; llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes; llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes; llvm::FoldingSet<TypenameType> TypenameTypes; @@ -469,6 +470,9 @@ public: /// specified typename decl. QualType getTypedefType(TypedefDecl *Decl); + QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, + QualType Replacement); + QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, IdentifierInfo *Name = 0); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 8d2c63aa755..6b0eb97ca41 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2142,6 +2142,59 @@ public: static bool classof(const TemplateTypeParmType *T) { return true; } }; +/// \brief Represents the result of substituting a type for a template +/// type parameter. +/// +/// Within an instantiated template, all template type parameters have +/// been replaced with these. They are used solely to record that a +/// type was originally written as a template type parameter; +/// therefore they are never canonical. +class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { + // The original type parameter. + const TemplateTypeParmType *Replaced; + + SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) + : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType()), + Replaced(Param) { } + + friend class ASTContext; + +public: + IdentifierInfo *getName() const { return Replaced->getName(); } + + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + /// Gets the type that was substituted for the template + /// parameter. + QualType getReplacementType() const { + return getCanonicalTypeInternal(); + } + + virtual void getAsStringInternal(std::string &InnerString, + const PrintingPolicy &Policy) const; + + bool isSugared() const { return true; } + QualType desugar() const { return getReplacementType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacedParameter(), getReplacementType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + QualType Replacement) { + ID.AddPointer(Replaced); + ID.AddPointer(Replacement.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParm; + } + static bool classof(const SubstTemplateTypeParmType *T) { return true; } +}; + /// \brief Represents the type of a template specialization as written /// in the source code. /// diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index fb202a5a50a..05eed0a1870 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -364,6 +364,16 @@ class BuiltinTypeLoc : public TypeSpecTypeLoc<BuiltinTypeLoc, BuiltinType> { }; +/// \brief Wrapper for template type parameters. +class TemplateTypeParmTypeLoc : public TypeSpecTypeLoc<TemplateTypeParmTypeLoc, + TemplateTypeParmType> { +}; + +/// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmTypeLoc : + public TypeSpecTypeLoc<SubstTemplateTypeParmTypeLoc, + SubstTemplateTypeParmType> { +}; /// \brief Wrapper for source info for ObjC interfaces. class ObjCInterfaceTypeLoc : public TypeSpecTypeLoc<ObjCInterfaceTypeLoc, @@ -714,7 +724,6 @@ class VariableArrayTypeLoc : VariableArrayType> { }; - // None of these types have proper implementations yet. class VectorTypeLoc : public TypeSpecTypeLoc<VectorTypeLoc, VectorType> { @@ -766,10 +775,6 @@ class ElaboratedTypeLoc : public TypeSpecTypeLoc<ElaboratedTypeLoc, ElaboratedType> { }; -class TemplateTypeParmTypeLoc : public TypeSpecTypeLoc<TemplateTypeParmTypeLoc, - TemplateTypeParmType> { -}; - class TemplateSpecializationTypeLoc : public TypeSpecTypeLoc<TemplateSpecializationTypeLoc, TemplateSpecializationType> { diff --git a/clang/include/clang/AST/TypeNodes.def b/clang/include/clang/AST/TypeNodes.def index b565e2e3d77..2615f14e8d0 100644 --- a/clang/include/clang/AST/TypeNodes.def +++ b/clang/include/clang/AST/TypeNodes.def @@ -80,6 +80,7 @@ TYPE(Record, TagType) TYPE(Enum, TagType) NON_CANONICAL_TYPE(Elaborated, Type) DEPENDENT_TYPE(TemplateTypeParm, Type) +NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) TYPE(TemplateSpecialization, Type) NON_CANONICAL_TYPE(QualifiedName, Type) DEPENDENT_TYPE(Typename, Type) diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h index 93eac86ee22..e4161fcae68 100644 --- a/clang/include/clang/Frontend/PCHBitCodes.h +++ b/clang/include/clang/Frontend/PCHBitCodes.h @@ -402,7 +402,9 @@ namespace clang { /// \brief a DecltypeType record. TYPE_DECLTYPE = 24, /// \brief An ElaboratedType record. - TYPE_ELABORATED = 25 + TYPE_ELABORATED = 25, + /// \brief A SubstTemplateTypeParmType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM = 26 }; /// \brief The type IDs for special types constructed by semantic diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 1b77bbe1dbd..c7e5752ec3c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -747,6 +747,11 @@ ASTContext::getTypeInfo(const Type *T) { break; } + case Type::SubstTemplateTypeParm: { + return getTypeInfo(cast<SubstTemplateTypeParmType>(T)-> + getReplacementType().getTypePtr()); + } + case Type::Elaborated: { return getTypeInfo(cast<ElaboratedType>(T)->getUnderlyingType().getTypePtr()); } @@ -1694,6 +1699,29 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) { return QualType(Decl->TypeForDecl, 0); } +/// \brief Retrieve a substitution-result type. +QualType +ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, + QualType Replacement) { + assert(Replacement->isCanonical() + && "replacement types must always be canonical"); + + llvm::FoldingSetNodeID ID; + SubstTemplateTypeParmType::Profile(ID, Parm, Replacement); + void *InsertPos = 0; + SubstTemplateTypeParmType *SubstParm + = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (!SubstParm) { + SubstParm = new (*this, TypeAlignment) + SubstTemplateTypeParmType(Parm, Replacement); + Types.push_back(SubstParm); + SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + } + + return QualType(SubstParm, 0); +} + /// \brief Retrieve the template type parameter type for a template /// parameter or parameter pack with the given depth, index, and (optionally) /// name. diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index bb9f57b6d1c..0922538f5e1 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -628,6 +628,7 @@ bool Type::isSpecifierType() const { case TypeOfExpr: case TypeOf: case TemplateTypeParm: + case SubstTemplateTypeParm: case TemplateSpecialization: case QualifiedName: case Typename: @@ -1267,6 +1268,10 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const P InnerString = Name->getName() + InnerString; } +void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + getReplacementType().getAsStringInternal(InnerString, Policy); +} + std::string TemplateSpecializationType::PrintTemplateArgumentList( const TemplateArgument *Args, diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 98f3f0b3959..bd5bbbe1e87 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -1968,6 +1968,15 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { Protos.push_back(cast<ObjCProtocolDecl>(GetDecl(Record[Idx++]))); return Context->getObjCProtocolListType(OIT, Protos.data(), NumProtos); } + + case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: { + unsigned Idx = 0; + QualType Parm = GetType(Record[Idx++]); + QualType Replacement = GetType(Record[Idx++]); + return + Context->getSubstTemplateTypeParmType(cast<TemplateTypeParmType>(Parm), + Replacement); + } } // Suppress a GCC warning return QualType(); @@ -2094,6 +2103,10 @@ void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); } +void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); +} void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index a15576a82f0..602f9c9efba 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -210,6 +210,14 @@ void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { } void +PCHTypeWriter::VisitSubstTemplateTypeParmType( + const SubstTemplateTypeParmType *T) { + Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); + Writer.AddTypeRef(T->getReplacementType(), Record); + Code = pch::TYPE_SUBST_TEMPLATE_TYPE_PARM; +} + +void PCHTypeWriter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { // FIXME: Serialize this type (C++ only) @@ -363,6 +371,10 @@ void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } +void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( + SubstTemplateTypeParmTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} void TypeLocWriter::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 9061576f813..5d5a57632fb 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -23,6 +23,101 @@ #include "clang/Basic/TargetInfo.h" using namespace clang; +/// Determines whether we should have an a.k.a. clause when +/// pretty-printing a type. There are two main criteria: +/// +/// 1) Some types provide very minimal sugar that doesn't impede the +/// user's understanding --- for example, elaborated type +/// specifiers. If this is all the sugar we see, we don't want an +/// a.k.a. clause. +/// 2) Some types are technically sugared but are much more familiar +/// when seen in their sugared form --- for example, va_list, +/// vector types, and the magic Objective C types. We don't +/// want to desugar these, even if we do produce an a.k.a. clause. +static bool ShouldAKA(ASTContext &Context, QualType QT, + QualType& DesugaredQT) { + + bool AKA = false; + QualifierCollector Qc; + + while (true) { + const Type *Ty = Qc.strip(QT); + + // Don't aka just because we saw an elaborated type... + if (isa<ElaboratedType>(Ty)) { + QT = cast<ElaboratedType>(Ty)->desugar(); + continue; + } + + // ...or a qualified name type... + if (isa<QualifiedNameType>(Ty)) { + QT = cast<QualifiedNameType>(Ty)->desugar(); + continue; + } + + // ...or a substituted template type parameter. + if (isa<SubstTemplateTypeParmType>(Ty)) { + QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); + continue; + } + + // Don't desugar template specializations. + if (isa<TemplateSpecializationType>(Ty)) + break; + + // Don't desugar magic Objective-C types. + if (QualType(Ty,0) == Context.getObjCIdType() || + QualType(Ty,0) == Context.getObjCClassType() || + QualType(Ty,0) == Context.getObjCSelType() || + QualType(Ty,0) == Context.getObjCProtoType()) + break; + + // Don't desugar va_list. + if (QualType(Ty,0) == Context.getBuiltinVaListType()) + break; + + // Otherwise, do a single-step desugar. + QualType Underlying; + bool IsSugar = false; + switch (Ty->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ + case Type::Class: { \ + const Class##Type *CTy = cast<Class##Type>(Ty); \ + if (CTy->isSugared()) { \ + IsSugar = true; \ + Underlying = CTy->desugar(); \ + } \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + + // If it wasn't sugared, we're done. + if (!IsSugar) + break; + + // If the desugared type is a vector type, we don't want to expand + // it, it will turn into an attribute mess. People want their "vec4". + if (isa<VectorType>(Underlying)) + break; + + // Otherwise, we're tearing through something opaque; note that + // we'll eventually need an a.k.a. clause and keep going. + AKA = true; + QT = Underlying; + continue; + } + + // If we ever tore through opaque sugar + if (AKA) { + DesugaredQT = Qc.apply(QT); + return true; + } + + return false; +} + /// \brief Convert the given type to a string suitable for printing as part of /// a diagnostic. /// @@ -33,34 +128,11 @@ static std::string ConvertTypeToDiagnosticString(ASTContext &Context, // FIXME: Playing with std::string is really slow. std::string S = Ty.getAsString(Context.PrintingPolicy); - // If this is a sugared type (like a typedef, typeof, etc), then unwrap one - // level of the sugar so that the type is more obvious to the user. - QualType DesugaredTy = Ty.getDesugaredType(); - - if (Ty != DesugaredTy && - // If the desugared type is a vector type, we don't want to expand it, - // it will turn into an attribute mess. People want their "vec4". - !isa<VectorType>(DesugaredTy) && - - // Don't aka just because we saw an elaborated type... - (!isa<ElaboratedType>(Ty) || - cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) && - - // ...or a qualified name type... - (!isa<QualifiedNameType>(Ty) || - cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) && - - // ...or a non-dependent template specialization. - (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) && - - // Don't desugar magic Objective-C types. - Ty.getUnqualifiedType() != Context.getObjCIdType() && - Ty.getUnqualifiedType() != Context.getObjCClassType() && - Ty.getUnqualifiedType() != Context.getObjCSelType() && - Ty.getUnqualifiedType() != Context.getObjCProtoType() && - - // Not va_list. - Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { + // Consider producing an a.k.a. clause if removing all the direct + // sugar gives us something "significantly different". + + QualType DesugaredTy; + if (ShouldAKA(Context, Ty, DesugaredTy)) { S = "'"+S+"' (aka '"; S += DesugaredTy.getAsString(Context.PrintingPolicy); S += "')"; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 51971d4b1ac..7f8960a2bf4 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -613,7 +613,11 @@ TemplateInstantiator::TransformTemplateTypeParmType( == TemplateArgument::Type && "Template argument kind mismatch"); - return TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + QualType Replacement + = TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + + // TODO: only do this uniquing once, at the start of instantiation. + return getSema().Context.getSubstTemplateTypeParmType(T, Replacement); } // The template type parameter comes from an inner template (e.g., diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index a3c9fa5628a..00af8c1ca0e 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2329,6 +2329,13 @@ QualType TreeTransform<Derived>::TransformTemplateTypeParmType( } template<typename Derived> +QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( + const SubstTemplateTypeParmType *T) { + // Nothing to do + return QualType(T, 0); +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( const TemplateSpecializationType *T) { TemplateName Template |