From 54dabfca850ca9e60e9ffb60003529f868d4d127 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 14 May 2009 23:26:13 +0000 Subject: [PATCH] Introduce basic support for instantiating the definitions of member functions of class templates. Only compound statements and expression statements are currently implemented. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71814 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 13 ++-- lib/Sema/SemaTemplate.cpp | 12 +--- lib/Sema/SemaTemplateInstantiate.cpp | 20 ++++++ lib/Sema/SemaTemplateInstantiateDecl.cpp | 21 +++++- lib/Sema/SemaTemplateInstantiateExpr.cpp | 70 ++++++++++++++++++++ test/SemaTemplate/instantiate-expr-2.cpp | 4 +- test/SemaTemplate/instantiate-function-1.cpp | 14 ++++ 7 files changed, 137 insertions(+), 17 deletions(-) create mode 100644 test/SemaTemplate/instantiate-function-1.cpp diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index d4c03a12a8..43d3816275 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1970,6 +1970,8 @@ public: // C++ Template Instantiation // + const TemplateArgumentList &getTemplateInstantiationArgs(NamedDecl *D); + /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { /// \brief The kind of template instantiation we are performing @@ -2117,7 +2119,7 @@ public: /// when we instantiate add, we will introduce a mapping from /// the ParmVarDecl for 'x' that occurs in the template to the /// instantiated ParmVarDecl for 'x'. - llvm::DenseMap LocalDecls; + llvm::DenseMap LocalDecls; /// \brief The outer scope, in which contains local variable /// definitions from some other instantiation (that is not @@ -2138,17 +2140,17 @@ public: SemaRef.CurrentInstantiationScope = Outer; } - VarDecl *getInstantiationOf(VarDecl *Var) { + VarDecl *getInstantiationOf(const VarDecl *Var) { VarDecl *Result = LocalDecls[Var]; assert(Result && "Variable was not instantiated in this scope!"); return Result; } - ParmVarDecl *getInstantiationOf(ParmVarDecl *Var) { + ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) { return cast(getInstantiationOf(cast(Var))); } - void InstantiatedLocal(VarDecl *Var, VarDecl *VarInst) { + void InstantiatedLocal(const VarDecl *Var, VarDecl *VarInst) { VarDecl *&Stored = LocalDecls[Var]; assert(!Stored && "Already instantiated this local variable"); Stored = VarInst; @@ -2165,6 +2167,9 @@ public: OwningExprResult InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs); + OwningStmtResult InstantiateStmt(Stmt *S, + const TemplateArgumentList &TemplateArgs); + Decl *InstantiateDecl(Decl *D, DeclContext *Owner, const TemplateArgumentList &TemplateArgs); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1453dcfe5e..6f65288164 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2391,27 +2391,19 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, } } - // Find the enclosing template, because we need its template - // arguments to instantiate this class. - DeclContext *EnclosingTemplateCtx = Record->getDeclContext(); - while (!isa(EnclosingTemplateCtx)) - EnclosingTemplateCtx = EnclosingTemplateCtx->getParent(); - ClassTemplateSpecializationDecl *EnclosingTemplate - = cast(EnclosingTemplateCtx); - if (!Record->getDefinition(Context)) { // If the class has a definition, instantiate it (and all of its // members, recursively). Pattern = cast_or_null(Pattern->getDefinition(Context)); if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, - EnclosingTemplate->getTemplateArgs(), + getTemplateInstantiationArgs(Record), /*ExplicitInstantiation=*/true)) return true; } else { // Instantiate all of the members of class. InstantiatingTemplate Inst(*this, TemplateLoc, Record); InstantiateClassMembers(TemplateLoc, Record, - EnclosingTemplate->getTemplateArgs()); + getTemplateInstantiationArgs(Record)); } // FIXME: We don't have any representation for explicit diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 5c6ed758d9..9503ad9180 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -24,6 +24,26 @@ using namespace clang; // Template Instantiation Support //===----------------------------------------------------------------------===/ +/// \brief Retrieve the template argument list that should be used to +/// instantiate the given declaration. +const TemplateArgumentList & +Sema::getTemplateInstantiationArgs(NamedDecl *D) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(D)) + return Spec->getTemplateArgs(); + + DeclContext *EnclosingTemplateCtx = D->getDeclContext(); + while (!isa(EnclosingTemplateCtx)) { + assert(!EnclosingTemplateCtx->isFileContext() && + "Tried to get the instantiation arguments of a non-template"); + EnclosingTemplateCtx = EnclosingTemplateCtx->getParent(); + } + + ClassTemplateSpecializationDecl *EnclosingTemplate + = cast(EnclosingTemplateCtx); + return EnclosingTemplate->getTemplateArgs(); +} + Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, CXXRecordDecl *Entity, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 02df5931a5..eb006dc3f3 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -572,6 +572,9 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, void Sema::InstantiateFunctionDefinition(FunctionDecl *Function) { // FIXME: make this work for function template specializations, too. + if (Function->isInvalidDecl()) + return; + // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getInstantiatedFromMemberFunction(); @@ -582,7 +585,23 @@ void Sema::InstantiateFunctionDefinition(FunctionDecl *Function) { if (!Pattern) return; - // FIXME: instantiate the pattern + // Introduce a new scope where local variable instantiations will be + // recorded. + LocalInstantiationScope Scope(*this); + + // Introduce the instantiated function parameters into the local + // instantiation scope. + for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) + Scope.InstantiatedLocal(PatternDecl->getParamDecl(I), + Function->getParamDecl(I)); + + // Instantiate the function body. + OwningStmtResult Body + = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function)); + if (Body.isInvalid()) + Function->setInvalidDecl(true); + else + Function->setBody(Body.takeAs()); } /// \brief Instantiate the definition of the given variable from its diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index d7b0854997..6dde788f2e 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -423,3 +423,73 @@ Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) { TemplateExprInstantiator Instantiator(*this, TemplateArgs); return Instantiator.Visit(E); } + +namespace { + class VISIBILITY_HIDDEN TemplateStmtInstantiator + : public StmtVisitor { + Sema &SemaRef; + const TemplateArgumentList &TemplateArgs; + + public: + typedef Sema::OwningExprResult OwningExprResult; + typedef Sema::OwningStmtResult OwningStmtResult; + + TemplateStmtInstantiator(Sema &SemaRef, + const TemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { } + + // FIXME: Once we get closer to completion, replace these + // manually-written declarations with automatically-generated ones + // from clang/AST/StmtNodes.def. + OwningStmtResult VisitCompoundStmt(CompoundStmt *S); + OwningStmtResult VisitExpr(Expr *E); + + // Base case. I'm supposed to ignore this. + OwningStmtResult VisitStmt(Stmt *S) { + S->dump(); + assert(false && "Cannot instantiate this kind of statement"); + return SemaRef.StmtError(); + } + }; +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitCompoundStmt(CompoundStmt *S) { + // FIXME: We need an *easy* RAII way to delete these statements if + // something goes wrong. + llvm::SmallVector Statements; + + for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end(); + B != BEnd; ++B) { + OwningStmtResult Result = Visit(*B); + if (Result.isInvalid()) { + // FIXME: This should be handled by an RAII destructor. + for (unsigned I = 0, N = Statements.size(); I != N; ++I) + Statements[I]->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + Statements.push_back(Result.takeAs()); + } + + return SemaRef.Owned( + new (SemaRef.Context) CompoundStmt(SemaRef.Context, + &Statements[0], + Statements.size(), + S->getLBracLoc(), + S->getRBracLoc())); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitExpr(Expr *E) { + Sema::OwningExprResult Result = SemaRef.InstantiateExpr(E, TemplateArgs); + if (Result.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.Owned(Result.takeAs()); +} + +Sema::OwningStmtResult +Sema::InstantiateStmt(Stmt *S, const TemplateArgumentList &TemplateArgs) { + TemplateStmtInstantiator Instantiator(*this, TemplateArgs); + return Instantiator.Visit(S); +} diff --git a/test/SemaTemplate/instantiate-expr-2.cpp b/test/SemaTemplate/instantiate-expr-2.cpp index 1832fd4ab7..80f403ed56 100644 --- a/test/SemaTemplate/instantiate-expr-2.cpp +++ b/test/SemaTemplate/instantiate-expr-2.cpp @@ -116,7 +116,7 @@ namespace N7 { //Cond C; // Errors //int V(C.foo()); // Errors - //typedef Cond::Type Type; // Errors + CRASHES! + //typedef Cond::Type Type; // Errors typedef Cond::Type Type; } @@ -128,5 +128,5 @@ struct X0 { }; void test_X0(X0 x, IntegralConstant ic) { - x.f(5, ic); + x.f(5,ic); } diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp new file mode 100644 index 0000000000..61b361f894 --- /dev/null +++ b/test/SemaTemplate/instantiate-function-1.cpp @@ -0,0 +1,14 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template +struct X0 { + void f(T x, U y) { + x + y; // expected-error{{invalid operands}} + } +}; + +struct X1 { }; + +template struct X0; +template struct X0; +template struct X0; // expected-note{{instantiation of}} -- 2.40.0