diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-31 00:43:58 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-31 00:43:58 +0000 |
commit | c45c232440dfafedca1a3773b904fb42609b1b19 (patch) | |
tree | 8fc8ee76514079ac19b30b1200dddedd6f74dece /lib | |
parent | af3e72285238369c2ea4ebd40a1c9a87bd3eabb7 (diff) |
Parsing and AST representation for dependent template names that occur
within nested-name-specifiers, e.g., for the "apply" in
typename MetaFun::template apply<T1, T2>::type
At present, we can't instantiate these nested-name-specifiers, so our
testing is sketchy.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68081 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 2 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 36 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 12 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 7 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 134 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 2 |
11 files changed, 169 insertions, 44 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index b62438cd61..18a3a4221a 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1373,8 +1373,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) { - // FIXME: If Template is dependent, canonicalize it! - if (!Canon.isNull()) Canon = getCanonicalType(Canon); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 6922dcc6c0..a4117b2bdf 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -94,8 +94,12 @@ QualType Type::getDesugaredType() const { if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this)) return TOT->getUnderlyingType().getDesugaredType(); if (const TemplateSpecializationType *Spec - = dyn_cast<TemplateSpecializationType>(this)) - return Spec->getCanonicalTypeInternal().getDesugaredType(); + = dyn_cast<TemplateSpecializationType>(this)) { + QualType Canon = Spec->getCanonicalTypeInternal(); + if (Canon->getAsTemplateSpecializationType()) + return QualType(this, 0); + return Canon->getDesugaredType(); + } if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this)) return QualName->getNamedType().getDesugaredType(); diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index e99e96a7dc..fcbf4eea94 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -134,7 +134,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, } TemplateNameKind -MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S, +MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S, TemplateTy &TemplateDecl, const CXXScopeSpec *SS) { return TNK_Non_template; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f80afe3f4b..11658d4c50 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -513,7 +513,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, Token Next = NextToken(); if (Next.is(tok::annot_template_id) && static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()) - ->Kind == TNK_Class_template) { + ->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A<int> CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS); @@ -640,7 +640,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (TemplateId->Kind != TNK_Class_template) { + if (TemplateId->Kind != TNK_Type_template) { // This template-id does not refer to a type name, so we're // done with the type-specifiers. goto DoneWithDeclSpec; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index fdfc7315a8..663fea5096 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -307,7 +307,7 @@ Parser::TypeTy *Parser::ParseClassName(SourceLocation &EndLocation, if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (TemplateId->Kind == TNK_Class_template) { + if (TemplateId->Kind == TNK_Type_template) { if (AnnotateTemplateIdTokenAsType(SS)) return 0; @@ -419,7 +419,7 @@ void Parser::ParseClassSpecifier(DeclSpec &DS, TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); NameLoc = ConsumeToken(); - if (TemplateId->Kind != TNK_Class_template) { + if (TemplateId->Kind != TNK_Type_template) { // The template-name in the simple-template-id refers to // something other than a class template. Give an appropriate // error message and skip to the ';'. diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 4d419bbd87..2c6963a05f 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -92,9 +92,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { Tok.is(tok::kw_template)) { // Parse the optional 'template' keyword, then make sure we have // 'identifier <' after it. - SourceLocation TemplateKWLoc; if (Tok.is(tok::kw_template)) { - TemplateKWLoc = ConsumeToken(); + SourceLocation TemplateKWLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok.getLocation(), @@ -110,20 +109,20 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { << SourceRange(TemplateKWLoc, Tok.getLocation()); break; } - } - else { - // FIXME: If the nested-name-specifier thus far is dependent, - // we need to break out of here, because this '<' is taken as - // an operator and not as part of a simple-template-id. + + TemplateTy Template + = Actions.ActOnDependentTemplateName(TemplateKWLoc, + *Tok.getIdentifierInfo(), + Tok.getLocation(), + SS); + AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, + &SS, TemplateKWLoc, false); + continue; } TemplateTy Template; - TemplateNameKind TNK = TNK_Non_template; - // FIXME: If the nested-name-specifier thus far is dependent, - // set TNK = TNK_Dependent_template_name and skip the - // "isTemplateName" check. - TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), - CurScope, Template, &SS); + TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), + CurScope, Template, &SS); if (TNK) { // We have found a template name, so annotate this this token // with a template-id annotation. We do not permit the @@ -131,7 +130,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id // token. - AnnotateTemplateIdToken(Template, TNK, &SS, TemplateKWLoc, false); + AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false); continue; } } @@ -142,12 +141,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { // simple-template-id '::' // // So we need to check whether the simple-template-id is of the - // right kind (it should name a type), and then convert it into - // a type within the nested-name-specifier. + // right kind (it should name a type or be dependent), and then + // convert it into a type within the nested-name-specifier. TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (TemplateId->Kind == TNK_Class_template) { + if (TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) { if (AnnotateTemplateIdTokenAsType(&SS)) SS.clear(); @@ -172,7 +172,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { SS.setEndLoc(CCLoc); continue; } else - assert(false && "FIXME: Only class template names supported here"); + assert(false && "FIXME: Only type template names supported here"); } // We don't have any tokens that form the beginning of a diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 8eda694864..45d148e38b 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -531,8 +531,7 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, return; // Build the annotation token. - // FIXME: Not just for class templates! - if (TNK == TNK_Class_template && AllowTypeAnnotation) { + if (TNK == TNK_Type_template && AllowTypeAnnotation) { Action::TypeResult Type = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, @@ -550,8 +549,8 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, else Tok.setLocation(TemplateNameLoc); } else { - // This is a function template. We'll be building a template-id - // annotation token. + // Build a template-id annotation token that can be processed + // later. Tok.setKind(tok::annot_template_id); TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Allocate(TemplateArgs.size()); @@ -595,8 +594,9 @@ bool Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - assert(TemplateId->Kind == TNK_Class_template && - "Only works for class templates"); + assert((TemplateId->Kind == TNK_Type_template || + TemplateId->Kind == TNK_Dependent_template_name) && + "Only works for type and dependent templates"); ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateId->getTemplateArgs(), diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index a101aaa732..56e217a329 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -901,7 +901,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); - if (TemplateId->Kind == TNK_Class_template) { + if (TemplateId->Kind == TNK_Type_template) { // A template-id that refers to a type was parsed into a // template-id annotation in a context where we weren't allowed // to produce a type annotation token. Update the template-id diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c46b044c29..634c90a36e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1690,7 +1690,7 @@ public: //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // - virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S, + virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, TemplateTy &Template, const CXXScopeSpec *SS = 0); bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); @@ -1756,6 +1756,11 @@ public: SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc); + virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, + const IdentifierInfo &Name, + SourceLocation NameLoc, + const CXXScopeSpec &SS); + bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, ClassTemplateSpecializationDecl *PrevDecl, SourceLocation TemplateNameLoc, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 56a016d270..591f323347 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -26,7 +26,7 @@ using namespace clang; /// declaration if II names a template. An optional CXXScope can be /// passed to indicate the C++ scope in which the identifier will be /// found. -TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S, +TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S, TemplateTy &TemplateResult, const CXXScopeSpec *SS) { NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName); @@ -38,10 +38,9 @@ TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S, if ((Template = dyn_cast<TemplateDecl>(IIDecl))) { if (isa<FunctionTemplateDecl>(IIDecl)) TNK = TNK_Function_template; - else if (isa<ClassTemplateDecl>(IIDecl)) - TNK = TNK_Class_template; - else if (isa<TemplateTemplateParmDecl>(IIDecl)) - TNK = TNK_Template_template_parm; + else if (isa<ClassTemplateDecl>(IIDecl) || + isa<TemplateTemplateParmDecl>(IIDecl)) + TNK = TNK_Type_template; else assert(false && "Unknown template declaration kind"); } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) { @@ -59,11 +58,11 @@ TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S, if (Record->isInjectedClassName()) { Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record)); if ((Template = Record->getDescribedClassTemplate())) - TNK = TNK_Class_template; + TNK = TNK_Type_template; else if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { Template = Spec->getSpecializedTemplate(); - TNK = TNK_Class_template; + TNK = TNK_Type_template; } } } @@ -716,6 +715,56 @@ translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, } } +/// \brief Build a canonical version of a template argument list. +/// +/// This function builds a canonical version of the given template +/// argument list, where each of the template arguments has been +/// converted into its canonical form. This routine is typically used +/// to canonicalize a template argument list when the template name +/// itself is dependent. When the template name refers to an actual +/// template declaration, Sema::CheckTemplateArgumentList should be +/// used to check and canonicalize the template arguments. +/// +/// \param TemplateArgs The incoming template arguments. +/// +/// \param NumTemplateArgs The number of template arguments in \p +/// TemplateArgs. +/// +/// \param Canonical A vector to be filled with the canonical versions +/// of the template arguments. +/// +/// \param Context The ASTContext in which the template arguments live. +static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + llvm::SmallVectorImpl<TemplateArgument> &Canonical, + ASTContext &Context) { + Canonical.reserve(NumTemplateArgs); + for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) { + switch (TemplateArgs[Idx].getKind()) { + case TemplateArgument::Expression: + // FIXME: Build canonical expression (!) + Canonical.push_back(TemplateArgs[Idx]); + break; + + case TemplateArgument::Declaration: + Canonical.push_back(TemplateArgument(SourceLocation(), + TemplateArgs[Idx].getAsDecl())); + break; + + case TemplateArgument::Integral: + Canonical.push_back(TemplateArgument(SourceLocation(), + *TemplateArgs[Idx].getAsIntegral(), + TemplateArgs[Idx].getIntegralType())); + + case TemplateArgument::Type: { + QualType CanonType + = Context.getCanonicalType(TemplateArgs[Idx].getAsType()); + Canonical.push_back(TemplateArgument(SourceLocation(), CanonType)); + } + } + } +} + QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -723,7 +772,25 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, unsigned NumTemplateArgs, SourceLocation RAngleLoc) { TemplateDecl *Template = Name.getAsTemplateDecl(); - assert(Template && "Cannot handle dependent template-names yet"); + if (!Template) { + // The template name does not resolve to a template, so we just + // build a dependent template-id type. + + // Canonicalize the template arguments to build the canonical + // template-id type. + llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs; + CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs, + CanonicalTemplateArgs, Context); + + // FIXME: Get the canonical template-name + QualType CanonType + = Context.getTemplateSpecializationType(Name, &CanonicalTemplateArgs[0], + CanonicalTemplateArgs.size()); + + // Build the dependent template-id type. + return Context.getTemplateSpecializationType(Name, TemplateArgs, + NumTemplateArgs, CanonType); + } // Check that the template argument list is well-formed for this // template. @@ -808,6 +875,57 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, return Result.getAsOpaquePtr(); } +/// \brief Form a dependent template name. +/// +/// This action forms a dependent template name given the template +/// name and its (presumably dependent) scope specifier. For +/// example, given "MetaFun::template apply", the scope specifier \p +/// SS will be "MetaFun::", \p TemplateKWLoc contains the location +/// of the "template" keyword, and "apply" is the \p Name. +Sema::TemplateTy +Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, + const IdentifierInfo &Name, + SourceLocation NameLoc, + const CXXScopeSpec &SS) { + if (!SS.isSet() || SS.isInvalid()) + return TemplateTy(); + + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + + // FIXME: member of the current instantiation + + if (!Qualifier->isDependent()) { + // C++0x [temp.names]p5: + // If a name prefixed by the keyword template is not the name of + // a template, the program is ill-formed. [Note: the keyword + // template may not be applied to non-template members of class + // templates. -end note ] [ Note: as is the case with the + // typename prefix, the template prefix is allowed in cases + // where it is not strictly necessary; i.e., when the + // nested-name-specifier or the expression on the left of the -> + // or . is not dependent on a template-parameter, or the use + // does not appear in the scope of a template. -end note] + // + // Note: C++03 was more strict here, because it banned the use of + // the "template" keyword prior to a template-name that was not a + // dependent name. C++ DR468 relaxed this requirement (the + // "template" keyword is now permitted). We follow the C++0x + // rules, even in C++03 mode, retroactively applying the DR. + TemplateTy Template; + TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS); + if (TNK == TNK_Non_template) { + Diag(NameLoc, diag::err_template_kw_refers_to_non_template) + << &Name; + return TemplateTy(); + } + + return Template; + } + + return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 08f96012dd..2eb874597e 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -475,7 +475,7 @@ InstantiateTemplateSpecializationType( // FIXME: Need to instantiate into the template name. return SemaRef.CheckTemplateIdType(T->getTemplateName(), Loc, - SourceLocation(), + SourceLocation(), &InstantiatedTemplateArgs[0], InstantiatedTemplateArgs.size(), SourceLocation()); |