diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-08-06 06:41:21 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-08-06 06:41:21 +0000 |
commit | d1067e5a0a6e2aee7260c392452df9553034c92b (patch) | |
tree | cffb06e1a3c70a8e4b2c588da0f7bfa86847e90e | |
parent | 38b02b912e1a55c912f603c4369431264d36a381 (diff) |
Implement transformation of template names within the generic tree
transform, then use the result for template instantiation. The generic
transformation fixes a few issues:
- It copes better with template template parameters and member
templates (when they're implemented).
- The logic used to replace template template parameters with their
arguments is now centralized in TransformDecl, so that it will apply
for other declaration-instantiation steps.
- The error-recovery strategy is normalized now, so that any error
results in a NULL TemplateName.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78292 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 85 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 166 | ||||
-rw-r--r-- | test/SemaTemplate/metafun-apply.cpp | 3 |
3 files changed, 182 insertions, 72 deletions
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 5f378993a2..8f877a8b56 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -324,9 +324,6 @@ namespace { /// this declaration. Decl *TransformDecl(Decl *D); - /// \brief Transform the given template name by instantiating it. - TemplateName TransformTemplateName(TemplateName Template); - /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(const TemplateTypeParmType *T); @@ -338,15 +335,22 @@ Sema::OwningExprResult TemplateInstantiator::TransformExpr(Expr *E) { } Decl *TemplateInstantiator::TransformDecl(Decl *D) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>(D)) { + // FIXME: Depth reduction + assert(TTP->getDepth() == 0 && + "Cannot reduce depth of a template template parameter"); + assert(TemplateArgs[TTP->getPosition()].getAsDecl() && + "Wrong kind of template template argument"); + TemplateDecl *Template + = dyn_cast<TemplateDecl>(TemplateArgs[TTP->getPosition()].getAsDecl()); + assert(Template && "Expected a template"); + return Template; + } + return SemaRef.InstantiateCurrentDeclRef(cast_or_null<NamedDecl>(D)); } -TemplateName -TemplateInstantiator::TransformTemplateName(TemplateName Template) { - return getSema().InstantiateTemplateName(Template, /*FIXME*/Loc, - TemplateArgs); -} - QualType TemplateInstantiator::TransformTemplateTypeParmType( const TemplateTypeParmType *T) { @@ -720,66 +724,9 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, TemplateName Sema::InstantiateTemplateName(TemplateName Name, SourceLocation Loc, const TemplateArgumentList &TemplateArgs) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null<TemplateTemplateParmDecl>( - Name.getAsTemplateDecl())) { - assert(TTP->getDepth() == 0 && - "Cannot reduce depth of a template template parameter"); - assert(TemplateArgs[TTP->getPosition()].getAsDecl() && - "Wrong kind of template template argument"); - ClassTemplateDecl *ClassTemplate - = dyn_cast<ClassTemplateDecl>( - TemplateArgs[TTP->getPosition()].getAsDecl()); - assert(ClassTemplate && "Expected a class template"); - if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { - NestedNameSpecifier *NNS - = InstantiateNestedNameSpecifier(QTN->getQualifier(), - /*FIXME=*/SourceRange(Loc), - TemplateArgs); - if (NNS) - return Context.getQualifiedTemplateName(NNS, - QTN->hasTemplateKeyword(), - ClassTemplate); - } - - return TemplateName(ClassTemplate); - } else if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { - NestedNameSpecifier *NNS - = InstantiateNestedNameSpecifier(DTN->getQualifier(), - /*FIXME=*/SourceRange(Loc), - TemplateArgs); - - if (!NNS) // FIXME: Not the best recovery strategy. - return Name; - - if (NNS->isDependent()) - return Context.getDependentTemplateName(NNS, DTN->getName()); - - // Somewhat redundant with ActOnDependentTemplateName. - CXXScopeSpec SS; - SS.setRange(SourceRange(Loc)); - SS.setScopeRep(NNS); - TemplateTy Template; - TemplateNameKind TNK = isTemplateName(*DTN->getName(), 0, Template, &SS); - if (TNK == TNK_Non_template) { - Diag(Loc, diag::err_template_kw_refers_to_non_template) - << DTN->getName(); - return Name; - } else if (TNK == TNK_Function_template) { - Diag(Loc, diag::err_template_kw_refers_to_non_template) - << DTN->getName(); - return Name; - } - - return Template.getAsVal<TemplateName>(); - } - - - - // FIXME: Even if we're referring to a Decl that isn't a template template - // parameter, we may need to instantiate the outer contexts of that - // Decl. However, this won't be needed until we implement member templates. - return Name; + TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, + DeclarationName()); + return Instantiator.TransformTemplateName(Name); } TemplateArgument Sema::Instantiate(TemplateArgument Arg, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 70ad317924..24deb4bbd5 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -171,8 +171,10 @@ public: /// \brief Transform the given template name. /// - /// FIXME: At the moment, subclasses must override this. - TemplateName TransformTemplateName(TemplateName Template); + /// By default, transforms the template name by transforming the declarations + /// and nested-name-specifiers that occur within the template name. + /// Subclasses may override this function to provide alternate behavior. + TemplateName TransformTemplateName(TemplateName Name); /// \brief Transform the given template argument. /// @@ -433,6 +435,36 @@ public: SourceRange Range, bool TemplateKW, QualType T); + + /// \brief Build a new template name given a nested name specifier, a flag + /// indicating whether the "template" keyword was provided, and the template + /// that the template name refers to. + /// + /// By default, builds the new template name directly. Subclasses may override + /// this routine to provide different behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + TemplateDecl *Template); + + /// \brief Build a new template name given a nested name specifier, a flag + /// indicating whether the "template" keyword was provided, and a set of + /// overloaded function templates. + /// + /// By default, builds the new template name directly. Subclasses may override + /// this routine to provide different behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + OverloadedFunctionDecl *Ovl); + + /// \brief Build a new template name given a nested name specifier and the + /// name that is referred to as a template. + /// + /// By default, performs semantic analysis to determine whether the name can + /// be resolved to a specific template, then builds the appropriate kind of + /// template name. Subclasses may override this routine to provide different + /// behavior. + TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo &II); }; template<typename Derived> @@ -477,6 +509,9 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0)); + if (T.isNull()) + return 0; + if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() && T == QualType(NNS->getAsType(), 0)) @@ -493,6 +528,88 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, } template<typename Derived> +TemplateName +TreeTransform<Derived>::TransformTemplateName(TemplateName Name) { + if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), + /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + if (!NNS) + return TemplateName(); + + if (TemplateDecl *Template = QTN->getTemplateDecl()) { + TemplateDecl *TransTemplate + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template)); + if (!TransTemplate) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + NNS == QTN->getQualifier() && + TransTemplate == Template) + return Name; + + return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(), + TransTemplate); + } + + OverloadedFunctionDecl *Ovl = QTN->getOverloadedFunctionDecl(); + assert(Ovl && "Not a template name or an overload set?"); + OverloadedFunctionDecl *TransOvl + = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl)); + if (!TransOvl) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + NNS == QTN->getQualifier() && + TransOvl == Ovl) + return Name; + + return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(), + TransOvl); + } + + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + NestedNameSpecifier *NNS + = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(), + /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + if (!NNS) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + NNS == DTN->getQualifier()) + return Name; + + return getDerived().RebuildTemplateName(NNS, *DTN->getName()); + } + + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + TemplateDecl *TransTemplate + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Template)); + if (!TransTemplate) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + TransTemplate == Template) + return Name; + + return TemplateName(TransTemplate); + } + + OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl(); + assert(Ovl && "Not a template name or an overload set?"); + OverloadedFunctionDecl *TransOvl + = cast_or_null<OverloadedFunctionDecl>(getDerived().TransformDecl(Ovl)); + if (!TransOvl) + return TemplateName(); + + if (!getDerived().AlwaysRebuild() && + TransOvl == Ovl) + return Name; + + return TemplateName(TransOvl); +} + +template<typename Derived> TemplateArgument TreeTransform<Derived>::TransformTemplateArgument(const TemplateArgument &Arg) { switch (Arg.getKind()) { @@ -1343,6 +1460,51 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, return 0; } +template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + TemplateDecl *Template) { + return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, + Template); +} + +template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + bool TemplateKW, + OverloadedFunctionDecl *Ovl) { + return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, Ovl); +} + +template<typename Derived> +TemplateName +TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo &II) { + if (Qualifier->isDependent()) + return SemaRef.Context.getDependentTemplateName(Qualifier, &II); + + // Somewhat redundant with ActOnDependentTemplateName. + CXXScopeSpec SS; + SS.setRange(SourceRange(getDerived().getBaseLocation())); + SS.setScopeRep(Qualifier); + Sema::TemplateTy Template; + TemplateNameKind TNK = SemaRef.isTemplateName(II, 0, Template, &SS); + if (TNK == TNK_Non_template) { + SemaRef.Diag(getDerived().getBaseLocation(), + diag::err_template_kw_refers_to_non_template) + << &II; + return TemplateName(); + } else if (TNK == TNK_Function_template) { + SemaRef.Diag(getDerived().getBaseLocation(), + diag::err_template_kw_refers_to_non_template) + << &II; + return TemplateName(); + } + + return Template.getAsVal<TemplateName>(); +} + } // end namespace clang #endif // LLVM_CLANG_SEMA_TREETRANSFORM_H diff --git a/test/SemaTemplate/metafun-apply.cpp b/test/SemaTemplate/metafun-apply.cpp index 9261ed6a6c..471b2ad3fa 100644 --- a/test/SemaTemplate/metafun-apply.cpp +++ b/test/SemaTemplate/metafun-apply.cpp @@ -35,7 +35,8 @@ void test() { apply1<add_reference, void>::type t; // expected-note{{in instantiation of template class 'struct apply1<struct add_reference, void>' requested here}} \ // FIXME: expected-error{{unexpected type name 'type': expected expression}} - apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}} + apply1<bogus, int>::type t2; // expected-note{{in instantiation of template class 'struct apply1<struct bogus, int>' requested here}} \ + // FIXME: expected-error{{unexpected type name 'type': expected expression}} } |