Eliminate a silly little Parse/Sema dance when parsing typename

specifiers such as

  typename T::template apply<U>

Previously, we would turn T::template apply<U> into a
TemplateSpecializationType. Then, we'd reprocess that
TemplateSpecializationType and turn it into either a
TemplateSpecializationType wrapped in an ElaboratedType (when we could
resolve "apply" to a template declaration) or a
DependentTemplateSpecializationType. We now produce the same ASTs but
without generating the intermediate TemplateSpecializationType.

The end goal here is to avoid generating TemplateSpecializationTypes
with dependent template-names, ever. We're not there yet.

llvm-svn: 126589
This commit is contained in:
Douglas Gregor 2011-02-27 22:46:49 +00:00
parent 99847d2bf1
commit b09518c551
3 changed files with 83 additions and 60 deletions

View File

@ -3384,11 +3384,20 @@ public:
/// \param TypenameLoc the location of the 'typename' keyword
/// \param SS the nested-name-specifier following the typename (e.g., 'T::').
/// \param TemplateLoc the location of the 'template' keyword, if any.
/// \param Ty the type that the typename specifier refers to.
/// \param TemplateName The template name.
/// \param TemplateNameLoc The location of the template name.
/// \param LAngleLoc The location of the opening angle bracket ('<').
/// \param TemplateArgs The template arguments.
/// \param RAngleLoc The location of the closing angle bracket ('>').
TypeResult
ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
const CXXScopeSpec &SS, SourceLocation TemplateLoc,
ParsedType Ty);
const CXXScopeSpec &SS,
SourceLocation TemplateLoc,
TemplateTy Template,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation RAngleLoc);
QualType CheckTypenameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,

View File

@ -1051,15 +1051,17 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) {
return true;
}
AnnotateTemplateIdTokenAsType(0);
assert(Tok.is(tok::annot_typename) &&
"AnnotateTemplateIdTokenAsType isn't working properly");
if (Tok.getAnnotationValue())
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
SourceLocation(),
getTypeAnnotation(Tok));
else
Ty = true;
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
/*FIXME:*/SourceLocation(),
TemplateId->Template,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc);
} else {
Diag(Tok, diag::err_expected_type_name_after_typename)
<< SS.getRange();

View File

@ -5923,75 +5923,87 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
}
TypeResult
Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
const CXXScopeSpec &SS, SourceLocation TemplateLoc,
ParsedType Ty) {
Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
const CXXScopeSpec &SS,
SourceLocation TemplateLoc,
TemplateTy TemplateIn,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation RAngleLoc) {
if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() &&
!getLangOptions().CPlusPlus0x)
Diag(TypenameLoc, diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
TypeSourceInfo *InnerTSI = 0;
QualType T = GetTypeFromParser(Ty, &InnerTSI);
assert(isa<TemplateSpecializationType>(T) &&
"Expected a template specialization type");
<< FixItHint::CreateRemoval(TypenameLoc);
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
TemplateName Template = TemplateIn.get();
if (computeDeclContext(SS, false)) {
// If we can compute a declaration context, then the "typename"
// keyword was superfluous. Just build an ElaboratedType to keep
// track of the nested-name-specifier.
// Push the inner type, preserving its source locations if possible.
QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs);
if (T.isNull())
return true;
// Provide source-location information for the template specialization
// type.
TypeLocBuilder Builder;
if (InnerTSI)
Builder.pushFullCopy(InnerTSI->getTypeLoc());
else
Builder.push<TemplateSpecializationTypeLoc>(T).initialize(Context,
TemplateLoc);
TemplateSpecializationTypeLoc SpecTL
= Builder.push<TemplateSpecializationTypeLoc>(T);
// FIXME: No place to set the location of the 'template' keyword!
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
SpecTL.setTemplateNameLoc(TemplateNameLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
// FIXME: This is a hack. We really want to push the nested-name-specifier
// into TemplateSpecializationType.
/* Note: NNS already embedded in template specialization type T. */
T = Context.getElaboratedType(ETK_Typename, /*NNS=*/0, T);
ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T);
TL.setKeywordLoc(TypenameLoc);
TL.setQualifierRange(SS.getRange());
TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T);
return CreateParsedType(T, TSI);
}
// TODO: it's really silly that we make a template specialization
// type earlier only to drop it again here.
const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
DependentTemplateName *DTN =
TST->getTemplateName().getAsDependentTemplateName();
// Construct a dependent template specialization type.
DependentTemplateName *DTN = Template.getAsDependentTemplateName();
assert(DTN && "dependent template has non-dependent name?");
assert(DTN->getQualifier()
== static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
T = Context.getDependentTemplateSpecializationType(ETK_Typename,
DTN->getQualifier(),
DTN->getIdentifier(),
TST->getNumArgs(),
TST->getArgs());
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
DependentTemplateSpecializationTypeLoc TL =
cast<DependentTemplateSpecializationTypeLoc>(TSI->getTypeLoc());
if (InnerTSI) {
TemplateSpecializationTypeLoc TSTL =
cast<TemplateSpecializationTypeLoc>(InnerTSI->getTypeLoc());
TL.setLAngleLoc(TSTL.getLAngleLoc());
TL.setRAngleLoc(TSTL.getRAngleLoc());
for (unsigned I = 0, E = TST->getNumArgs(); I != E; ++I)
TL.setArgLocInfo(I, TSTL.getArgLocInfo(I));
} else {
// FIXME: Poor source-location information here.
TL.initializeLocal(Context, TemplateLoc);
}
TL.setKeywordLoc(TypenameLoc);
TL.setQualifierRange(SS.getRange());
return CreateParsedType(T, TSI);
QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename,
DTN->getQualifier(),
DTN->getIdentifier(),
TemplateArgs);
// Create source-location information for this type.
TypeLocBuilder Builder;
DependentTemplateSpecializationTypeLoc SpecTL
= Builder.push<DependentTemplateSpecializationTypeLoc>(T);
SpecTL.setLAngleLoc(LAngleLoc);
SpecTL.setRAngleLoc(RAngleLoc);
SpecTL.setKeywordLoc(TypenameLoc);
SpecTL.setNameLoc(TemplateNameLoc);
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
// FIXME: Nested-name-specifier source locations.
SpecTL.setQualifierRange(SS.getRange());
return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
/// \brief Build the type that describes a C++ typename specifier,
/// e.g., "typename T::type".
QualType