Keep track of when DependentNameTypes have no associated keyword

(e.g., no typename, enum, class, etc.), e.g., because the context is
one that is known to refer to a type. Patch from Enea Zaffanella!

llvm-svn: 102243
This commit is contained in:
Douglas Gregor 2010-04-24 15:35:55 +00:00
parent fb278831aa
commit bbdf20acd0
6 changed files with 15 additions and 13 deletions

View File

@ -3017,7 +3017,8 @@ public:
ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
SourceLocation TemplateLoc, TypeTy *Ty); SourceLocation TemplateLoc, TypeTy *Ty);
QualType CheckTypenameType(NestedNameSpecifier *NNS, QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo &II, const IdentifierInfo &II,
SourceRange Range); SourceRange Range);

View File

@ -89,9 +89,8 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
// We know from the grammar that this name refers to a type, so build a // We know from the grammar that this name refers to a type, so build a
// DependentNameType node to describe the type. // DependentNameType node to describe the type.
// FIXME: Record somewhere that this DependentNameType node has no "typename" return CheckTypenameType(ETK_None,
// keyword associated with it. (NestedNameSpecifier *)SS->getScopeRep(),
return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
II, SS->getRange()).getAsOpaquePtr(); II, SS->getRange()).getAsOpaquePtr();
} }

View File

@ -1088,7 +1088,8 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!NotUnknownSpecialization) { if (!NotUnknownSpecialization) {
// When the scope specifier can refer to a member of an unknown // When the scope specifier can refer to a member of an unknown
// specialization, we take it as a type name. // specialization, we take it as a type name.
BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(), BaseType = CheckTypenameType(ETK_None,
(NestedNameSpecifier *)SS.getScopeRep(),
*MemberOrBase, SS.getRange()); *MemberOrBase, SS.getRange());
if (BaseType.isNull()) if (BaseType.isNull())
return true; return true;

View File

@ -261,7 +261,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
Range = SourceRange(NameLoc); Range = SourceRange(NameLoc);
} }
return CheckTypenameType(NNS, II, Range).getAsOpaquePtr(); return CheckTypenameType(ETK_None, NNS, II, Range).getAsOpaquePtr();
} }
if (ObjectTypePtr) if (ObjectTypePtr)

View File

@ -5128,7 +5128,8 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
if (!NNS) if (!NNS)
return true; return true;
QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc)); QualType T = CheckTypenameType(ETK_Typename, NNS, II,
SourceRange(TypenameLoc, IdLoc));
if (T.isNull()) if (T.isNull())
return true; return true;
return T.getAsOpaquePtr(); return T.getAsOpaquePtr();
@ -5160,7 +5161,8 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
/// \brief Build the type that describes a C++ typename specifier, /// \brief Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type". /// e.g., "typename T::type".
QualType QualType
Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS, const IdentifierInfo &II,
SourceRange Range) { SourceRange Range) {
CXXRecordDecl *CurrentInstantiation = 0; CXXRecordDecl *CurrentInstantiation = 0;
if (NNS->isDependent()) { if (NNS->isDependent()) {
@ -5169,7 +5171,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
// If the nested-name-specifier does not refer to the current // If the nested-name-specifier does not refer to the current
// instantiation, then build a typename type. // instantiation, then build a typename type.
if (!CurrentInstantiation) if (!CurrentInstantiation)
return Context.getDependentNameType(ETK_Typename, NNS, &II); return Context.getDependentNameType(Keyword, NNS, &II);
// The nested-name-specifier refers to the current instantiation, so the // The nested-name-specifier refers to the current instantiation, so the
// "typename" keyword itself is superfluous. In C++03, the program is // "typename" keyword itself is superfluous. In C++03, the program is
@ -5205,7 +5207,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::NotFoundInCurrentInstantiation:
// Okay, it's a member of an unknown instantiation. // Okay, it's a member of an unknown instantiation.
return Context.getDependentNameType(ETK_Typename, NNS, &II); return Context.getDependentNameType(Keyword, NNS, &II);
case LookupResult::Found: case LookupResult::Found:
if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {

View File

@ -574,10 +574,9 @@ public:
TagDecl::TagKind Kind = TagDecl::TK_enum; TagDecl::TagKind Kind = TagDecl::TK_enum;
switch (Keyword) { switch (Keyword) {
case ETK_None: case ETK_None:
// FIXME: Note the lack of the "typename" specifier! // Fall through.
// Fall through
case ETK_Typename: case ETK_Typename:
return SemaRef.CheckTypenameType(NNS, *Id, SR); return SemaRef.CheckTypenameType(Keyword, NNS, *Id, SR);
case ETK_Class: Kind = TagDecl::TK_class; break; case ETK_Class: Kind = TagDecl::TK_class; break;
case ETK_Struct: Kind = TagDecl::TK_struct; break; case ETK_Struct: Kind = TagDecl::TK_struct; break;