]> granicus.if.org Git - clang/commitdiff
When performing template-substitution into a type, don't just replace the
authorJohn McCall <rjmccall@apple.com>
Sun, 18 Oct 2009 09:09:24 +0000 (09:09 +0000)
committerJohn McCall <rjmccall@apple.com>
Sun, 18 Oct 2009 09:09:24 +0000 (09:09 +0000)
TemplateTypeParmType with the substituted type directly;  instead, replace it
with a SubstTemplateTypeParmType which will note that the type was originally
written as a template type parameter.  This makes it reasonable to preserve
source information even through template substitution.

Also define the new SubstTemplateTypeParmType class, obviously.

For consistency with current behavior, we stringize these types as if they
were the underlying type.  I'm not sure this is the right thing to do.
At any rate, I paled at adding yet another clause to the don't-desugar 'if'
statement, so I extracted a function to do it.  The new function also does
The Right Thing more often, I think:  e.g. if we have a chain of typedefs
leading to a vector type, we will now desugar all but the last one.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84412 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
include/clang/AST/TypeLoc.h
include/clang/AST/TypeNodes.def
include/clang/Frontend/PCHBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHWriter.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/TreeTransform.h

index c4e81b41bc3246b14cbba78784803013675934dc..493d8acf3b880922b050a49bf1b56043dea6d0b1 100644 (file)
@@ -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);
index 8d2c63aa7552c1dc68391683ed2c442145420525..6b0eb97ca414d69aba77b3e3d8cb0701ed4a26a6 100644 (file)
@@ -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.
 ///
index fb202a5a50a10637a6cb90b8b8b5d48adab5e217..05eed0a18707109d06dcb8e1dd1f5356a5aa256e 100644 (file)
@@ -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> {
index b565e2e3d779b468269b46f84b44ef4f1c928868..2615f14e8d04e04e48941f2e85fc98da24477a73 100644 (file)
@@ -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)
index 93eac86ee226116b827d8def6d979625f07df608..e4161fcae68298c4c1c4cc9b87b931f7b8fc2e82 100644 (file)
@@ -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
index 1b77bbe1dbd8cc1f9c71d91e56781b25e8dfb2b5..c7e5752ec3c03ac67efb408df6b7aad0f1334e22 100644 (file)
@@ -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.
index bb9f57b6d1c1064b12586daad30db529eebe1af9..0922538f5e1bd73dde33b2efa836295548deffca 100644 (file)
@@ -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,
index 98f3f0b39590e23ff2eb5237eab42efb23a303eb..bd5bbbe1e87a4aba5d75eb77c70c61f46eef56b4 100644 (file)
@@ -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++]));
index a15576a82f0cea2551d4dd7d8c14eae96299284d..602f9c9efba35e785bb70e335fc6a900755a4181 100644 (file)
@@ -209,6 +209,14 @@ void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
   Code = pch::TYPE_ELABORATED;
 }
 
+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) {
@@ -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);
index 9061576f81360a2d76038a8956094351bebedfec..5d5a57632fb1b5fc9dc6018bf4d01e3a953c3017 100644 (file)
 #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 += "')";
index 51971d4b1aca441d2bbfe62d8b6527041cdbdcb6..7f8960a2bf48d0b01359452a6619a5c0023c1a6a 100644 (file)
@@ -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.,
index a3c9fa5628af09e2744de62911d702b44d81d0c6..00af8c1ca0e50bbcb0987602abf77a96b9364d82 100644 (file)
@@ -2328,6 +2328,13 @@ QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
   return QualType(T, 0);
 }
 
+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) {