diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 19 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 142 |
6 files changed, 180 insertions, 16 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 5572b7a3a09..4684a806f05 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -220,6 +220,25 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); } +VarDecl *ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) { + assert(Var->isStaticDataMember() && "Not a static data member"); + llvm::DenseMap<VarDecl *, VarDecl *>::iterator Pos + = InstantiatedFromStaticDataMember.find(Var); + if (Pos == InstantiatedFromStaticDataMember.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl) { + assert(Inst->isStaticDataMember() && "Not a static data member"); + assert(Tmpl->isStaticDataMember() && "Not a static data member"); + assert(!InstantiatedFromStaticDataMember[Inst] && + "Already noted what static data member was instantiated from"); + InstantiatedFromStaticDataMember[Inst] = Tmpl; +} + namespace { class BeforeInTranslationUnit : std::binary_function<SourceRange, SourceRange, bool> { diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index b4710c2c536..9701f6c90d4 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -341,6 +341,10 @@ SourceRange VarDecl::getSourceRange() const { return SourceRange(getLocation(), getLocation()); } +VarDecl *VarDecl::getInstantiatedFromStaticDataMember() { + return getASTContext().getInstantiatedFromStaticDataMember(this); +} + bool VarDecl::isTentativeDefinition(ASTContext &Context) const { if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus) return false; diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 3f14c49ed4b..164c65f02cd 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2732,7 +2732,10 @@ public: void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false); - void InstantiateVariableDefinition(VarDecl *Var); + void InstantiateStaticDataMemberDefinition( + SourceLocation PointOfInstantiation, + VarDecl *Var, + bool Recursive = false); NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 66e73f99e90..98d1f4c6af5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5780,10 +5780,17 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { } if (VarDecl *Var = dyn_cast<VarDecl>(D)) { - (void)Var; - // FIXME: implicit template instantiation + // Implicit instantiation of static data members of class templates. + // FIXME: distinguish between implicit instantiations (which we need to + // actually instantiate) and explicit specializations. + if (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember()) + PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc)); + // FIXME: keep track of references to static data? + D->setUsed(true); - } + return; +} } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index a75a8584d1f..cb43f1c6a0d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -189,8 +189,7 @@ void Sema::PrintInstantiationStack() { DiagID) << Context.getTypeDeclType(Record) << Active->InstantiationRange; - } else { - FunctionDecl *Function = cast<FunctionDecl>(D); + } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { unsigned DiagID; if (Function->getPrimaryTemplate()) DiagID = diag::note_function_template_spec_here; @@ -200,6 +199,11 @@ void Sema::PrintInstantiationStack() { DiagID) << Function << Active->InstantiationRange; + } else { + Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), + diag::note_template_static_data_member_def_here) + << cast<VarDecl>(D) + << Active->InstantiationRange; } break; } @@ -1059,9 +1063,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (!Function->getBody()) InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) { - const VarDecl *Def = 0; - if (!Var->getDefinition(Def)) - InstantiateVariableDefinition(Var); + if (Var->isStaticDataMember()) + InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) { assert(Record->getInstantiatedFromMemberClass() && diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 5718e9b69b0..a6513f16726 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -120,12 +120,24 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); Var->setDeclaredInCondition(D->isDeclaredInCondition()); + // If we are instantiating a static data member defined + // out-of-line, the instantiation will have the same lexical + // context (which will be a namespace scope) as the template. + if (D->isOutOfLine()) + Var->setLexicalDeclContext(D->getLexicalDeclContext()); + // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. bool Redeclaration = false; SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration); - Owner->addDecl(Var); - + + if (D->isOutOfLine()) { + D->getLexicalDeclContext()->addDecl(Var); + Owner->makeDeclVisibleInContext(Var); + } else { + Owner->addDecl(Var); + } + if (D->getInit()) { OwningExprResult Init = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs); @@ -138,6 +150,11 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // FIXME: Call ActOnUninitializedDecl? (Not always) } + // Link instantiations of static data members back to the template from + // which they were instantiated. + if (Var->isStaticDataMember()) + SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D); + return Var; } @@ -374,6 +391,12 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) { D->isInline()); Method->setInstantiationOfMemberFunction(D); + // If we are instantiating a member function defined + // out-of-line, the instantiation will have the same lexical + // context (which will be a namespace scope) as the template. + if (D->isOutOfLine()) + Method->setLexicalDeclContext(D->getLexicalDeclContext()); + // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Method); @@ -773,9 +796,103 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, /// \brief Instantiate the definition of the given variable from its /// template. /// -/// \param Var the already-instantiated declaration of a variable. -void Sema::InstantiateVariableDefinition(VarDecl *Var) { - // FIXME: Implement this! +/// \param PointOfInstantiation the point at which the instantiation was +/// required. Note that this is not precisely a "point of instantiation" +/// for the function, but it's close. +/// +/// \param Var the already-instantiated declaration of a static member +/// variable of a class template specialization. +/// +/// \param Recursive if true, recursively instantiates any functions that +/// are required by this instantiation. +void Sema::InstantiateStaticDataMemberDefinition( + SourceLocation PointOfInstantiation, + VarDecl *Var, + bool Recursive) { + if (Var->isInvalidDecl()) + return; + + // Find the out-of-line definition of this static data member. + // FIXME: Do we have to look for specializations separately? + VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); + bool FoundOutOfLineDef = false; + assert(Def && "This data member was not instantiated from a template?"); + assert(Def->isStaticDataMember() && "Not a static data member?"); + for (VarDecl::redecl_iterator RD = Def->redecls_begin(), + RDEnd = Def->redecls_end(); + RD != RDEnd; ++RD) { + if (RD->getLexicalDeclContext()->isFileContext()) { + Def = *RD; + FoundOutOfLineDef = true; + } + } + + if (!FoundOutOfLineDef) { + // We did not find an out-of-line definition of this static data member, + // so we won't perform any instantiation. Rather, we rely on the user to + // instantiate this definition (or provide a specialization for it) in + // another translation unit. + return; + } + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); + if (Inst) + return; + + // If we're performing recursive template instantiation, create our own + // queue of pending implicit instantiations that we will instantiate later, + // while we're still within our own instantiation context. + std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations; + if (Recursive) + PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + DeclContext *PreviousContext = CurContext; + CurContext = Var->getDeclContext(); + +#if 0 + // Instantiate the initializer of this static data member. + OwningExprResult Init + = InstantiateExpr(Def->getInit(), getTemplateInstantiationArgs(Var)); + if (Init.isInvalid()) { + // If instantiation of the initializer failed, mark the declaration invalid + // and don't instantiate anything else that was triggered by this + // instantiation. + Var->setInvalidDecl(); + + // Restore the set of pending implicit instantiations. + PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + + return; + } + + // Type-check the initializer. + if (Init.get()) + AddInitializerToDecl(DeclPtrTy::make(Var), move(Init), + Def->hasCXXDirectInitializer()); + else + ActOnUninitializedDecl(DeclPtrTy::make(Var), false); +#else + Var = cast_or_null<VarDecl>(InstantiateDecl(Def, Var->getDeclContext(), + getTemplateInstantiationArgs(Var))); +#endif + + CurContext = PreviousContext; + + if (Var) { + DeclGroupRef DG(Var); + Consumer.HandleTopLevelDecl(DG); + } + + if (Recursive) { + // Instantiate any pending implicit instantiations found during the + // instantiation of this template. + PerformPendingImplicitInstantiations(); + + // Restore the set of pending implicit instantiations. + PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations); + } } static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { @@ -794,6 +911,11 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { return Enum->getInstantiatedFromMemberEnum()->getCanonicalDecl() == D->getCanonicalDecl(); + if (VarDecl *Var = dyn_cast<VarDecl>(Other)) + if (Var->isStaticDataMember()) + return Var->getInstantiatedFromStaticDataMember()->getCanonicalDecl() + == D->getCanonicalDecl(); + // FIXME: How can we find instantiations of anonymous unions? return D->getDeclName() && isa<NamedDecl>(Other) && @@ -912,10 +1034,16 @@ void Sema::PerformPendingImplicitInstantiations() { PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front(); PendingImplicitInstantiations.pop_front(); - if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) + // Instantiate function definitions + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) { if (!Function->getBody()) InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true); + continue; + } - // FIXME: instantiate static member variables + // Instantiate static data member definitions. + VarDecl *Var = cast<VarDecl>(Inst.first); + assert(Var->isStaticDataMember() && "Not a static data member?"); + InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true); } } |