From 090253155017b7eec031bbd7bf07824a448e1d7a Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sat, 29 Aug 2009 05:16:22 +0000 Subject: [PATCH] Instantiate member and base initializers. Patch by Anders Johnsen! (tweaked slightly by me) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80422 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 4 + lib/Sema/SemaTemplateInstantiateDecl.cpp | 78 ++++++++++++++++++- .../instantiate-member-initializers.cpp | 20 +++++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 test/SemaTemplate/instantiate-member-initializers.cpp diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1a062b79e8..accbcd1479 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2960,6 +2960,10 @@ public: VarDecl *Var, bool Recursive = false); + void InstantiateMemInitializers(CXXConstructorDecl *New, + const CXXConstructorDecl *Tmpl, + const MultiLevelTemplateArgumentList &TemplateArgs); + NamedDecl *FindInstantiatedDecl(NamedDecl *D); DeclContext *FindInstantiatedContext(DeclContext *DC); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e2ebd09954..ba5c786366 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -992,9 +992,18 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, DeclContext *PreviousContext = CurContext; CurContext = Function; + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Function); + + // If this is a constructor, instantiate the member initializers. + if (const CXXConstructorDecl *Ctor = + dyn_cast(PatternDecl)) { + InstantiateMemInitializers(cast(Function), Ctor, + TemplateArgs); + } + // Instantiate the function body. - OwningStmtResult Body - = SubstStmt(Pattern, getTemplateInstantiationArgs(Function)); + OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs); ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), /*IsInstantiation=*/true); @@ -1092,6 +1101,71 @@ void Sema::InstantiateStaticDataMemberDefinition( } } +void +Sema::InstantiateMemInitializers(CXXConstructorDecl *New, + const CXXConstructorDecl *Tmpl, + const MultiLevelTemplateArgumentList &TemplateArgs) { + + llvm::SmallVector NewInits; + + // Instantiate all the initializers. + for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(), + InitsEnd = Tmpl->init_end(); Inits != InitsEnd; ++Inits) { + CXXBaseOrMemberInitializer *Init = *Inits; + + ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this); + + // Instantiate all the arguments. + for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end(); + Args != ArgsEnd; ++Args) { + OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs); + + if (NewArg.isInvalid()) + New->setInvalidDecl(); + else + NewArgs.push_back(NewArg.takeAs()); + } + + MemInitResult NewInit; + + if (Init->isBaseInitializer()) { + // FIXME: Type needs to be instantiated. + QualType BaseType = + Context.getCanonicalType(QualType(Init->getBaseClass(), 0)); + + NewInit = BuildBaseInitializer(BaseType, + (Expr **)NewArgs.data(), + NewArgs.size(), + Init->getSourceLocation(), + Init->getRParenLoc(), + New->getParent()); + } else if (Init->isMemberInitializer()) { + FieldDecl *Member = + cast(FindInstantiatedDecl(Init->getMember())); + + NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), + NewArgs.size(), + Init->getSourceLocation(), + Init->getRParenLoc()); + } + + if (NewInit.isInvalid()) + New->setInvalidDecl(); + else { + // FIXME: It would be nice if ASTOwningVector had a release function. + NewArgs.take(); + + NewInits.push_back((MemInitTy *)NewInit.get()); + } + } + + // Assign all the initializers to the new constructor. + ActOnMemInitializers(DeclPtrTy::make(New), + /*FIXME: ColonLoc */ + SourceLocation(), + NewInits.data(), NewInits.size()); +} + static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) return false; diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp new file mode 100644 index 0000000000..66f4d37d01 --- /dev/null +++ b/test/SemaTemplate/instantiate-member-initializers.cpp @@ -0,0 +1,20 @@ +// RUN: clang-cc -fsyntax-only -Wall -verify %s + +template struct A { + A() : a(1) { } // expected-error{{incompatible type passing 'int', expected 'void *'}} + + T a; +}; + +A a0; +A a1; // expected-note{{in instantiation of member function 'A::A' requested here}} + +template struct B { + // FIXME: This should warn about initialization order + B() : b(1), a(2) { } + + int a; + int b; +}; + +B b0; -- 2.40.0