diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-31 17:21:17 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-31 17:21:17 +0000 |
commit | 550d9b28fd586db541eb6dd36f3c10d114e483d8 (patch) | |
tree | b01023c9c5330b297f5388de6ac1a22dadc028b1 | |
parent | df7c3b955e31a6951822f2adf36e98543ef14c7e (diff) |
Implement "incremental" template instantiation for non-type template
parameters and template type parameters, which occurs when
substituting into the declarations of member templates inside class
templates. This eliminates errors about our inability to "reduce
non-type template parameter depth", fixing PR5311.
Also fixes a bug when instantiating a template type parameter
declaration in a member template, where we weren't properly reducing
the template parameter's depth.
LLVM's StringSwitch header now parses.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85669 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/Sema.h | 15 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 99 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 34 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-non-type-template-parameter.cpp | 14 | ||||
-rw-r--r-- | test/SemaTemplate/member-template-access-expr.cpp | 18 |
5 files changed, 122 insertions, 58 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 5197516e46..3281fc450c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3117,7 +3117,7 @@ public: llvm::DenseMap<const Decl *, Decl *> LocalDecls; /// \brief The outer scope, in which contains local variable - /// definitions from some other instantiation (that is not + /// definitions from some other instantiation (that may not be /// relevant to this particular scope). LocalInstantiationScope *Outer; @@ -3126,9 +3126,13 @@ public: LocalInstantiationScope &operator=(const LocalInstantiationScope &); public: - LocalInstantiationScope(Sema &SemaRef) + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) { - SemaRef.CurrentInstantiationScope = this; + if (!CombineWithOuterScope) + SemaRef.CurrentInstantiationScope = this; + else + assert(SemaRef.CurrentInstantiationScope && + "No outer instantiation scope?"); } ~LocalInstantiationScope() { @@ -3149,6 +3153,11 @@ public: return cast<ParmVarDecl>(getInstantiationOf(cast<Decl>(Var))); } + NonTypeTemplateParmDecl *getInstantiationOf( + const NonTypeTemplateParmDecl *Var) { + return cast<NonTypeTemplateParmDecl>(getInstantiationOf(cast<Decl>(Var))); + } + void InstantiatedLocal(const Decl *D, Decl *Inst) { Decl *&Stored = LocalDecls[D]; assert(!Stored && "Already instantiated this local"); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 8fab8f62e4..e79511f923 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -562,58 +562,59 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { // FIXME: Clean this up a bit NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { - if (NTTP->getDepth() >= TemplateArgs.getNumLevels()) { - assert(false && "Cannot reduce non-type template parameter depth yet"); - return getSema().ExprError(); - } - - // If the corresponding template argument is NULL or non-existent, it's - // because we are performing instantiation from explicitly-specified - // template arguments in a function template, but there were some - // arguments left unspecified. - if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), - NTTP->getPosition())) - return SemaRef.Owned(E->Retain()); - - const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), - NTTP->getPosition()); - - // The template argument itself might be an expression, in which - // case we just return that expression. - if (Arg.getKind() == TemplateArgument::Expression) - return SemaRef.Owned(Arg.getAsExpr()->Retain()); - - if (Arg.getKind() == TemplateArgument::Declaration) { - ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); - - VD = cast_or_null<ValueDecl>( - getSema().FindInstantiatedDecl(VD, TemplateArgs)); - if (!VD) - return SemaRef.ExprError(); - - return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), - /*FIXME:*/false, /*FIXME:*/false); - } + if (NTTP->getDepth() < TemplateArgs.getNumLevels()) { + + // If the corresponding template argument is NULL or non-existent, it's + // because we are performing instantiation from explicitly-specified + // template arguments in a function template, but there were some + // arguments left unspecified. + if (!TemplateArgs.hasTemplateArgument(NTTP->getDepth(), + NTTP->getPosition())) + return SemaRef.Owned(E->Retain()); + + const TemplateArgument &Arg = TemplateArgs(NTTP->getDepth(), + NTTP->getPosition()); + + // The template argument itself might be an expression, in which + // case we just return that expression. + if (Arg.getKind() == TemplateArgument::Expression) + return SemaRef.Owned(Arg.getAsExpr()->Retain()); + + if (Arg.getKind() == TemplateArgument::Declaration) { + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); + + VD = cast_or_null<ValueDecl>( + getSema().FindInstantiatedDecl(VD, TemplateArgs)); + if (!VD) + return SemaRef.ExprError(); + + return SemaRef.BuildDeclRefExpr(VD, VD->getType(), E->getLocation(), + /*FIXME:*/false, /*FIXME:*/false); + } - assert(Arg.getKind() == TemplateArgument::Integral); - QualType T = Arg.getIntegralType(); - if (T->isCharType() || T->isWideCharType()) - return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( - Arg.getAsIntegral()->getZExtValue(), - T->isWideCharType(), - T, - E->getSourceRange().getBegin())); - if (T->isBooleanType()) - return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( - Arg.getAsIntegral()->getBoolValue(), - T, - E->getSourceRange().getBegin())); - - assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); - return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( - *Arg.getAsIntegral(), + assert(Arg.getKind() == TemplateArgument::Integral); + QualType T = Arg.getIntegralType(); + if (T->isCharType() || T->isWideCharType()) + return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral( + Arg.getAsIntegral()->getZExtValue(), + T->isWideCharType(), T, E->getSourceRange().getBegin())); + if (T->isBooleanType()) + return SemaRef.Owned(new (SemaRef.Context) CXXBoolLiteralExpr( + Arg.getAsIntegral()->getBoolValue(), + T, + E->getSourceRange().getBegin())); + + assert(Arg.getAsIntegral()->getBitWidth() == SemaRef.Context.getIntWidth(T)); + return SemaRef.Owned(new (SemaRef.Context) IntegerLiteral( + *Arg.getAsIntegral(), + T, + E->getSourceRange().getBegin())); + } + + // We have a non-type template parameter that isn't fully substituted; + // FindInstantiatedDecl will find it in the local instantiation scope. } NamedDecl *InstD = SemaRef.FindInstantiatedDecl(D, TemplateArgs); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index f8f2217464..27275230f7 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -409,6 +409,9 @@ namespace { } Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + // Create a local instantiation scope for this class template, which + // will contain the instantiations of the template parameters. + Sema::LocalInstantiationScope Scope(SemaRef); TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) @@ -491,8 +494,12 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - // FIXME: Dig out the out-of-line definition of this function template? - + // Create a local instantiation scope for this function template, which + // will contain the instantiations of the template parameters and then get + // merged with the local instantiation scope for the function template + // itself. + Sema::LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) @@ -582,7 +589,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef); + Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -711,7 +718,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, return Info->Function; } - Sema::LocalInstantiationScope Scope(SemaRef); + Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0); llvm::SmallVector<ParmVarDecl *, 4> Params; QualType T = SubstFunctionType(D, Params); @@ -886,7 +893,7 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), - TTPT->getDepth(), TTPT->getIndex(), + TTPT->getDepth() - 1, TTPT->getIndex(), TTPT->getName(), D->wasDeclaredWithTypename(), D->isParameterPack()); @@ -904,6 +911,10 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( D->defaultArgumentWasInherited() /* preserve? */); } + // Introduce this template parameter's instantiation into the instantiation + // scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst); + return Inst; } @@ -940,6 +951,10 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( Param->setInvalidDecl(); Param->setDefaultArgument(D->getDefaultArgument()); + + // Introduce this template parameter's instantiation into the instantiation + // scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param); return Param; } @@ -1024,6 +1039,11 @@ bool TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, ClassTemplatePartialSpecializationDecl *PartialSpec) { + // Create a local instantiation scope for this class template partial + // specialization, which will contain the instantiations of the template + // parameters. + Sema::LocalInstantiationScope Scope(SemaRef); + // Substitute into the template parameters of the class template partial // specialization. TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); @@ -1773,7 +1793,9 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D, } DeclContext *ParentDC = D->getDeclContext(); - if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) { + if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || + isa<TemplateTypeParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || + ParentDC->isFunctionOrMethod()) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D)); diff --git a/test/SemaTemplate/instantiate-non-type-template-parameter.cpp b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp new file mode 100644 index 0000000000..32acbd0d8b --- /dev/null +++ b/test/SemaTemplate/instantiate-non-type-template-parameter.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// PR5311 +template<typename T> +class StringSwitch { +public: + template<unsigned N> + void Case(const char (&S)[N], const int & Value) { + } +}; + +int main(int argc, char *argv[]) { + (void)StringSwitch<int>(); +} diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp index feef7926fb..0238cd53c5 100644 --- a/test/SemaTemplate/member-template-access-expr.cpp +++ b/test/SemaTemplate/member-template-access-expr.cpp @@ -75,3 +75,21 @@ void test_X1(X1 x1) { float* (*fp7)(int) = X1::f2<>; float* (*fp8)(float) = X1::f2<float>; } + +template<int A> struct X2 { + int m; +}; + +template<typename T> +struct X3 : T { }; + +template<typename T> +struct X4 { + template<typename U> + void f(X2<sizeof(X3<U>().U::m)>); +}; + +void f(X4<X3<int> > x4i) { + X2<sizeof(int)> x2; + x4i.f<X2<sizeof(int)> >(x2); +} |