From: Douglas Gregor Date: Mon, 28 Feb 2011 00:04:36 +0000 (+0000) Subject: When we encounter a dependent template name within a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa2187de137e5b809dcbbe14f3b61ae907a3d8aa;p=clang When we encounter a dependent template name within a nested-name-specifier, e.g., T::template apply:: represent the dependent template name specialization as a DependentTemplateSpecializationType, rather than a TemplateSpecializationType with a dependent TemplateName. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126593 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index b124bbe475..d215df92a0 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2659,25 +2659,41 @@ public: ParsedType ObjectType, bool EnteringContext); - /// \brief The parser has parsed a nested-name-specifier 'type::'. + /// \brief The parser has parsed a nested-name-specifier + /// 'template[opt] template-name < template-args >::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// - /// \param Type The type, which will be a template specialization - /// type, preceding the '::'. - /// - /// \param CCLoc The location of the '::'. + /// \param TemplateLoc The location of the 'template' keyword, if any. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). + /// + /// \param TemplateLoc the location of the 'template' keyword, if any. + /// \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 ('>'). + /// \param CCLoc The location of the '::'. + + /// \param EnteringContext Whether we're entering the context of the + /// nested-name-specifier. + /// /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, - ParsedType Type, + SourceLocation TemplateLoc, + CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, SourceLocation CCLoc, - CXXScopeSpec &SS); + bool EnteringContext); /// \brief Given a C++ nested-name-specifier, produce an annotation value /// that the parser can use later to reconstruct the given diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 9c2455034d..ef9e7b3133 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2377,7 +2377,8 @@ ASTContext::getDependentTemplateSpecializationType( const IdentifierInfo *Name, unsigned NumArgs, const TemplateArgument *Args) const { - assert(NNS->isDependent() && "nested-name-specifier must be dependent"); + assert((!NNS || NNS->isDependent()) && + "nested-name-specifier must be dependent"); llvm::FoldingSetNodeID ID; DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS, @@ -3014,10 +3015,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { = T->getAs()) { NestedNameSpecifier *Prefix = getCanonicalNestedNameSpecifier(DTST->getQualifier()); - TemplateName Name - = getDependentTemplateName(Prefix, DTST->getIdentifier()); - T = getTemplateSpecializationType(Name, - DTST->getArgs(), DTST->getNumArgs()); + + T = getDependentTemplateSpecializationType(DTST->getKeyword(), + Prefix, DTST->getIdentifier(), + DTST->getNumArgs(), + DTST->getArgs()); T = getCanonicalType(T); } diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 939ca7a924..8474ea3633 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -625,6 +625,17 @@ void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } + } else if (const DependentTemplateSpecializationType *DTST + = dyn_cast(QTy)) { + TemplateName Template + = getASTContext().getDependentTemplateName(DTST->getQualifier(), + DTST->getIdentifier()); + mangleTemplatePrefix(Template); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs()); } else { // We use the QualType mangle type variant here because it handles // substitutions. @@ -1596,7 +1607,7 @@ void CXXNameMangler::mangleType(const DependentNameType *T) { } void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { - // Dependently-scoped template types are always nested + // Dependently-scoped template types are nested if they have a prefix. Out << 'N'; // TODO: avoid making this TemplateName. diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index b03314e11d..d1136adbab 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1040,9 +1040,9 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType( QualType Canon) : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true, /*VariablyModified=*/false, - NNS->containsUnexpandedParameterPack()), + NNS && NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name), NumArgs(NumArgs) { - assert(NNS && NNS->isDependent() && + assert((!NNS || NNS->isDependent()) && "DependentTemplateSpecializatonType requires dependent qualifier"); for (unsigned I = 0; I != NumArgs; ++I) { if (Args[I].containsUnexpandedParameterPack()) diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index d8db711809..a059e0b75a 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -199,29 +199,32 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { - AnnotateTemplateIdTokenAsType(&SS); - - assert(Tok.is(tok::annot_typename) && - "AnnotateTemplateIdTokenAsType isn't working"); - Token TypeToken = Tok; + // Consume the template-id token. ConsumeToken(); + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); if (!HasScopeSpecifier) HasScopeSpecifier = true; - - if (ParsedType T = getTypeAnnotation(TypeToken)) { - if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), T, CCLoc, SS)) - SS.SetInvalid(SourceRange(SS.getBeginLoc(), CCLoc)); - - continue; - } else { - SourceLocation Start = SS.getBeginLoc().isValid()? SS.getBeginLoc() - : CCLoc; - SS.SetInvalid(SourceRange(Start, CCLoc)); - } + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), + /*FIXME:*/SourceLocation(), + SS, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + CCLoc, + EnteringContext)) + SS.SetInvalid(SourceRange(SS.getBeginLoc(), CCLoc)); + + TemplateId->Destroy(); continue; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 69d1853c0f..3ed070321d 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1062,6 +1062,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc); + TemplateId->Destroy(); } else { Diag(Tok, diag::err_expected_type_name_after_typename) << SS.getRange(); diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 7ad4b45945..8eb628f59b 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -641,20 +641,73 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, } bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, - ParsedType Type, + SourceLocation TemplateLoc, + CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc, SourceLocation CCLoc, - CXXScopeSpec &SS) { + bool EnteringContext) { if (SS.isInvalid()) return true; - TypeSourceInfo *TSInfo; - QualType T = GetTypeFromParser(Type, &TSInfo); + // Translate the parser's template argument list in our AST format. + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); + + if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){ + // Handle a dependent template specialization for which we cannot resolve + // the template name. + assert(DTN->getQualifier() + == static_cast(SS.getScopeRep())); + QualType T = Context.getDependentTemplateSpecializationType(ETK_None, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + + // Create source-location information for this type. + TypeLocBuilder Builder; + DependentTemplateSpecializationTypeLoc SpecTL + = Builder.push(T); + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + SpecTL.setKeywordLoc(SourceLocation()); + SpecTL.setNameLoc(TemplateNameLoc); + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + + SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T), + CCLoc); + return false; + } + + // We were able to resolve the template name to an actual template. + // Build an appropriate nested-name-specifier. + QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc, + TemplateArgs); if (T.isNull()) return true; - assert(TSInfo && "Not TypeSourceInfo in nested-name-specifier?"); - // FIXME: location of the 'template' keyword? - SS.Extend(Context, SourceLocation(), TSInfo->getTypeLoc(), CCLoc); + // FIXME: Template aliases will need to check the resulting type to make + // sure that it's either dependent or a tag type. + + // Provide source-location information for the template specialization + // type. + TypeLocBuilder Builder; + TemplateSpecializationTypeLoc SpecTL + = Builder.push(T); + + 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()); + + + SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T), + CCLoc); return false; } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 57a44ad9d9..fa4637a27e 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -754,6 +754,9 @@ public: getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); if (T.isNull()) return QualType(); + if (Keyword == ETK_None) + return T; + // NOTE: NNS is already recorded in template specialization type T. return SemaRef.Context.getElaboratedType(Keyword, /*NNS=*/0, T); }