aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-03-31 20:19:30 +0000
committerDouglas Gregor <dgregor@apple.com>2010-03-31 20:19:30 +0000
commit4a2023f5014e82389d5980d307b89c545dbbac81 (patch)
treef5d79eebce14b9afda74569cc0d97a6360c17b58
parent0798df70753a5feee0e79f2b51f3d4f50127325d (diff)
Extend DependentNameType with a keyword enum that specifies whether
this was parsed as a typename-specifier, elaborated-type-specifier (including the kind), or just a dependent qualified type name. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100039 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h14
-rw-r--r--include/clang/AST/Type.h64
-rw-r--r--lib/AST/ASTContext.cpp38
-rw-r--r--lib/AST/TypePrinter.cpp10
-rw-r--r--lib/CodeGen/Mangle.cpp5
-rw-r--r--lib/Sema/SemaDecl.cpp4
-rw-r--r--lib/Sema/SemaTemplate.cpp15
-rw-r--r--lib/Sema/SemaType.cpp3
-rw-r--r--lib/Sema/TreeTransform.h20
9 files changed, 115 insertions, 58 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 0bf9642863..c41857ec02 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -630,12 +630,14 @@ public:
QualType getQualifiedNameType(NestedNameSpecifier *NNS,
QualType NamedType);
- QualType getDependentNameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- QualType Canon = QualType());
- QualType getDependentNameType(NestedNameSpecifier *NNS,
- const TemplateSpecializationType *TemplateId,
- QualType Canon = QualType());
+ QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon = QualType());
+ QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon = QualType());
QualType getElaboratedType(QualType UnderlyingType,
ElaboratedType::TagKind Tag);
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 53346569d3..578382a130 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -2550,6 +2550,24 @@ public:
static bool classof(const InjectedClassNameType *T) { return true; }
};
+/// \brief The elaboration keyword that precedes a qualified type name or
+/// introduces an elaborated-type-specifier.
+enum ElaboratedTypeKeyword {
+ /// \brief No keyword precedes the qualified type name.
+ ETK_None,
+ /// \brief The "typename" keyword precedes the qualified type name, e.g.,
+ /// \c typename T::type.
+ ETK_Typename,
+ /// \brief The "class" keyword introduces the elaborated-type-specifier.
+ ETK_Class,
+ /// \brief The "struct" keyword introduces the elaborated-type-specifier.
+ ETK_Struct,
+ /// \brief The "union" keyword introduces the elaborated-type-specifier.
+ ETK_Union,
+ /// \brief The "enum" keyword introduces the elaborated-type-specifier.
+ ETK_Enum
+};
+
/// \brief Represents a type that was referred to via a qualified
/// name, e.g., N::M::type.
///
@@ -2600,19 +2618,19 @@ public:
static bool classof(const QualifiedNameType *T) { return true; }
};
-/// \brief Represents a 'typename' specifier that names a type within
-/// a dependent type, e.g., "typename T::type".
+/// \brief Represents a qualified type name for which the type name is
+/// dependent.
///
-/// DependentNameType has a very similar structure to QualifiedNameType,
-/// which also involves a nested-name-specifier following by a type,
-/// and (FIXME!) both can even be prefixed by the 'typename'
-/// keyword. However, the two types serve very different roles:
-/// QualifiedNameType is a non-semantic type that serves only as sugar
-/// to show how a particular type was written in the source
-/// code. DependentNameType, on the other hand, only occurs when the
-/// nested-name-specifier is dependent, such that we cannot resolve
-/// the actual type until after instantiation.
+/// DependentNameType represents a class of dependent types that involve a
+/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent)
+/// name of a type. The DependentNameType may start with a "typename" (for a
+/// typename-specifier), "class", "struct", "union", or "enum" (for a
+/// dependent elaborated-type-specifier), or nothing (in contexts where we
+/// know that we must be referring to a type, e.g., in a base class specifier).
class DependentNameType : public Type, public llvm::FoldingSetNode {
+ /// \brief The keyword used to elaborate this type.
+ ElaboratedTypeKeyword Keyword;
+
/// \brief The nested name specifier containing the qualifier.
NestedNameSpecifier *NNS;
@@ -2622,16 +2640,18 @@ class DependentNameType : public Type, public llvm::FoldingSetNode {
/// \brief The type that this typename specifier refers to.
NameType Name;
- DependentNameType(NestedNameSpecifier *NNS, const IdentifierInfo *Name,
- QualType CanonType)
- : Type(DependentName, CanonType, true), NNS(NNS), Name(Name) {
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name, QualType CanonType)
+ : Type(DependentName, CanonType, true),
+ Keyword(Keyword), NNS(NNS), Name(Name) {
assert(NNS->isDependent() &&
"DependentNameType requires a dependent nested-name-specifier");
}
- DependentNameType(NestedNameSpecifier *NNS, const TemplateSpecializationType *Ty,
- QualType CanonType)
- : Type(DependentName, CanonType, true), NNS(NNS), Name(Ty) {
+ DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *Ty, QualType CanonType)
+ : Type(DependentName, CanonType, true),
+ Keyword(Keyword), NNS(NNS), Name(Ty) {
assert(NNS->isDependent() &&
"DependentNameType requires a dependent nested-name-specifier");
}
@@ -2639,6 +2659,9 @@ class DependentNameType : public Type, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these
public:
+ /// \brief Retrieve the keyword used to elaborate this type.
+ ElaboratedTypeKeyword getKeyword() const { return Keyword; }
+
/// \brief Retrieve the qualification on this type.
NestedNameSpecifier *getQualifier() const { return NNS; }
@@ -2662,11 +2685,12 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, NNS, Name);
+ Profile(ID, Keyword, NNS, Name);
}
- static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
- NameType Name) {
+ static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, NameType Name) {
+ ID.AddInteger(Keyword);
ID.AddPointer(NNS);
ID.AddPointer(Name.getOpaqueValue());
}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 7fce55b9df..31c4370ad3 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1962,19 +1962,24 @@ ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS,
return QualType(T, 0);
}
-QualType ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- QualType Canon) {
+QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name,
+ QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
- if (CanonNNS != NNS)
- Canon = getDependentNameType(CanonNNS, Name);
+ ElaboratedTypeKeyword CanonKeyword = Keyword;
+ if (Keyword == ETK_None)
+ CanonKeyword = ETK_Typename;
+
+ if (CanonNNS != NNS || CanonKeyword != Keyword)
+ Canon = getDependentNameType(CanonKeyword, CanonNNS, Name);
}
llvm::FoldingSetNodeID ID;
- DependentNameType::Profile(ID, NNS, Name);
+ DependentNameType::Profile(ID, Keyword, NNS, Name);
void *InsertPos = 0;
DependentNameType *T
@@ -1982,20 +1987,21 @@ QualType ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
if (T)
return QualType(T, 0);
- T = new (*this) DependentNameType(NNS, Name, Canon);
+ T = new (*this) DependentNameType(Keyword, NNS, Name, Canon);
Types.push_back(T);
DependentNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
}
QualType
-ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
- const TemplateSpecializationType *TemplateId,
- QualType Canon) {
+ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const TemplateSpecializationType *TemplateId,
+ QualType Canon) {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
llvm::FoldingSetNodeID ID;
- DependentNameType::Profile(ID, NNS, TemplateId);
+ DependentNameType::Profile(ID, Keyword, NNS, TemplateId);
void *InsertPos = 0;
DependentNameType *T
@@ -2006,12 +2012,16 @@ ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
if (Canon.isNull()) {
NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
- if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
+ ElaboratedTypeKeyword CanonKeyword = Keyword;
+ if (Keyword == ETK_None)
+ CanonKeyword = ETK_Typename;
+ if (CanonNNS != NNS || CanonKeyword != Keyword ||
+ CanonType != QualType(TemplateId, 0)) {
const TemplateSpecializationType *CanonTemplateId
= CanonType->getAs<TemplateSpecializationType>();
assert(CanonTemplateId &&
"Canonical type must also be a template specialization type");
- Canon = getDependentNameType(CanonNNS, CanonTemplateId);
+ Canon = getDependentNameType(CanonKeyword, CanonNNS, CanonTemplateId);
}
DependentNameType *CheckT
@@ -2019,7 +2029,7 @@ ASTContext::getDependentNameType(NestedNameSpecifier *NNS,
assert(!CheckT && "Typename canonical type is broken"); (void)CheckT;
}
- T = new (*this) DependentNameType(NNS, TemplateId, Canon);
+ T = new (*this) DependentNameType(Keyword, NNS, TemplateId, Canon);
Types.push_back(T);
DependentNameTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index da0ac3f5ae..4cf0922ee3 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -572,7 +572,15 @@ void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S)
{
llvm::raw_string_ostream OS(MyString);
- OS << "typename ";
+ switch (T->getKeyword()) {
+ case ETK_None: break;
+ case ETK_Typename: OS << "typename "; break;
+ case ETK_Class: OS << "class "; break;
+ case ETK_Struct: OS << "struct "; break;
+ case ETK_Union: OS << "union "; break;
+ case ETK_Enum: OS << "enum "; break;
+ }
+
T->getQualifier()->print(OS, Policy);
if (const IdentifierInfo *Ident = T->getIdentifier())
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index af5e5d3c78..077db7c268 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -1456,8 +1456,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
// It isn't clear that we ever actually want to have such a
// nested-name-specifier; why not just represent it as a typename type?
if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) {
- QTy = getASTContext().getDependentNameType(NNS->getPrefix(),
- NNS->getAsIdentifier())
+ QTy = getASTContext().getDependentNameType(ETK_Typename,
+ NNS->getPrefix(),
+ NNS->getAsIdentifier())
.getTypePtr();
}
assert(QTy && "Qualifier was not type!");
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 4898387357..eef73d8d7f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -198,7 +198,9 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
} else if (UnresolvedUsingTypenameDecl *UUDecl =
dyn_cast<UnresolvedUsingTypenameDecl>(IIDecl)) {
// FIXME: preserve source structure information.
- T = Context.getDependentNameType(UUDecl->getTargetNestedNameSpecifier(), &II);
+ T = Context.getDependentNameType(ETK_None,
+ UUDecl->getTargetNestedNameSpecifier(),
+ &II);
} else {
// If it's not plausibly a type, suppress diagnostics.
Result.suppressDiagnostics();
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5933659f6d..e3533905fd 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4958,7 +4958,8 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
}
- return Context.getDependentNameType(NNS, TemplateId).getAsOpaquePtr();
+ return Context.getDependentNameType(ETK_Typename, NNS, TemplateId)
+ .getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,
@@ -4973,7 +4974,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
// If the nested-name-specifier does not refer to the current
// instantiation, then build a typename type.
if (!CurrentInstantiation)
- return Context.getDependentNameType(NNS, &II);
+ return Context.getDependentNameType(ETK_Typename, NNS, &II);
// The nested-name-specifier refers to the current instantiation, so the
// "typename" keyword itself is superfluous. In C++03, the program is
@@ -5009,7 +5010,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation.
- return Context.getDependentNameType(NNS, &II);
+ return Context.getDependentNameType(ETK_Typename, NNS, &II);
case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
@@ -5135,10 +5136,12 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
Result = QualType(T, 0);
else
- Result = getDerived().RebuildDependentNameType(NNS, NewTemplateId);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ NNS, NewTemplateId);
} else
- Result = getDerived().RebuildDependentNameType(NNS, T->getIdentifier(),
- SourceRange(TL.getNameLoc()));
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(),
+ NNS, T->getIdentifier(),
+ SourceRange(TL.getNameLoc()));
if (Result.isNull())
return QualType();
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 24197adb11..8278691a4a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1261,7 +1261,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
NestedNameSpecifier *NNSPrefix = NNS->getPrefix();
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
- ClsType = Context.getDependentNameType(NNSPrefix, NNS->getAsIdentifier());
+ ClsType = Context.getDependentNameType(ETK_None, NNSPrefix,
+ NNS->getAsIdentifier());
break;
case NestedNameSpecifier::Namespace:
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 361ab2e78c..a2ace07576 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -540,15 +540,17 @@ public:
/// By default, builds a new DependentNameType type from the nested-name-specifier
/// and the given type. Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildDependentNameType(NestedNameSpecifier *NNS, QualType T) {
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS, QualType T) {
if (NNS->isDependent()) {
CXXScopeSpec SS;
SS.setScopeRep(NNS);
if (!SemaRef.computeDeclContext(SS))
- return SemaRef.Context.getDependentNameType(NNS,
+ return SemaRef.Context.getDependentNameType(Keyword, NNS,
cast<TemplateSpecializationType>(T));
}
+ // FIXME: Handle elaborated-type-specifiers separately.
return SemaRef.Context.getQualifiedNameType(NNS, T);
}
@@ -557,9 +559,11 @@ public:
/// By default, performs semantic analysis when building the typename type
/// (or qualified name type). Subclasses may override this routine to provide
/// different behavior.
- QualType RebuildDependentNameType(NestedNameSpecifier *NNS,
- const IdentifierInfo *Id,
- SourceRange SR) {
+ QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ const IdentifierInfo *Id,
+ SourceRange SR) {
+ // FIXME: Handle elaborated-type-specifiers separately.
return SemaRef.CheckTypenameType(NNS, *Id, SR);
}
@@ -3023,9 +3027,11 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB,
NewTemplateId == QualType(TemplateId, 0))
return QualType(T, 0);
- Result = getDerived().RebuildDependentNameType(NNS, NewTemplateId);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ NewTemplateId);
} else {
- Result = getDerived().RebuildDependentNameType(NNS, T->getIdentifier(), SR);
+ Result = getDerived().RebuildDependentNameType(T->getKeyword(), NNS,
+ T->getIdentifier(), SR);
}
if (Result.isNull())
return QualType();