summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2009-10-18 09:09:24 +0000
committerJohn McCall <rjmccall@apple.com>2009-10-18 09:09:24 +0000
commitcebee16bc05ed6ca88041e916ef803b088f495f2 (patch)
treec0352965acb264ab0de2f219b33c20ab55dedaf2 /clang/lib
parent0b8db2dab78f101acea99bfe0702d4668a7273e2 (diff)
downloadbcm5719-llvm-cebee16bc05ed6ca88041e916ef803b088f495f2.tar.gz
bcm5719-llvm-cebee16bc05ed6ca88041e916ef803b088f495f2.zip
When performing template-substitution into a type, don't just replace the
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. llvm-svn: 84412
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp28
-rw-r--r--clang/lib/AST/Type.cpp5
-rw-r--r--clang/lib/Frontend/PCHReader.cpp13
-rw-r--r--clang/lib/Frontend/PCHWriter.cpp12
-rw-r--r--clang/lib/Sema/Sema.cpp128
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp6
-rw-r--r--clang/lib/Sema/TreeTransform.h7
7 files changed, 170 insertions, 29 deletions
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
OpenPOWER on IntegriCloud