diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-09-27 20:14:12 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-09-27 20:14:12 +0000 |
commit | 8809a0c95e7aa9e858f455bbb9a3f5a3c4ae96d3 (patch) | |
tree | 0902cddbb5d01a0a7cde1d63bbc6827b7a67ab6d /clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | |
parent | 23e43cdda610f04bfaec7d43958a1b1a8904113f (diff) | |
download | bcm5719-llvm-8809a0c95e7aa9e858f455bbb9a3f5a3c4ae96d3.tar.gz bcm5719-llvm-8809a0c95e7aa9e858f455bbb9a3f5a3c4ae96d3.zip |
Variable templates: handle instantiation of static data member templates
appropriately, especially when they appear within class templates.
llvm-svn: 191548
Diffstat (limited to 'clang/lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 260 |
1 files changed, 162 insertions, 98 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9779aa64ae5..8f4c009073a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -318,7 +318,6 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { return Inst; } -// FIXME: Revise for static member templates. Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false); } @@ -2338,7 +2337,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos, const TemplateArgumentListInfo &TemplateArgsInfo, - SmallVectorImpl<TemplateArgument> &Converted) { + llvm::ArrayRef<TemplateArgument> Converted) { // If this is the variable for an anonymous struct or union, // instantiate the anonymous struct/union type first. @@ -2366,7 +2365,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(), Converted.size()); Var->setTemplateArgsInfo(TemplateArgsInfo); - VarTemplate->AddSpecialization(Var, InsertPos); + if (InsertPos) + VarTemplate->AddSpecialization(Var, InsertPos); // Substitute the nested name specifier, if any. if (SubstQualifier(D, Var)) @@ -2691,12 +2691,8 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // specializations. The instantiation of the initializer is not necessary. VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); - // Set the initializer, to use as pattern for initialization. - if (VarDecl *Def = PartialSpec->getDefinition(SemaRef.getASTContext())) - PartialSpec = cast<VarTemplatePartialSpecializationDecl>(Def); SemaRef.BuildVariableInstantiation(InstPartialSpec, PartialSpec, TemplateArgs, LateAttrs, Owner, StartingScope); - InstPartialSpec->setInit(PartialSpec->getInit()); return InstPartialSpec; } @@ -3309,8 +3305,15 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( MultiLevelTemplateArgumentList TemplateArgLists; TemplateArgLists.addOuterTemplateArguments(&TemplateArgList); + // Instantiate the first declaration of the variable template: for a partial + // specialization of a static data member template, the first declaration may + // or may not be the declaration in the class; if it's in the class, we want + // to instantiate a member in the class (a declaration), and if it's outside, + // we want to instantiate a definition. + FromVar = FromVar->getFirstDeclaration(); + TemplateDeclInstantiator Instantiator( - *this, VarTemplate->getDeclContext(), + *this, FromVar->getDeclContext(), MultiLevelTemplateArgumentList(TemplateArgList)); // TODO: Set LateAttrs and StartingScope ... @@ -3327,10 +3330,8 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( const MultiLevelTemplateArgumentList &TemplateArgs) { // Do substitution on the type of the declaration - MultiLevelTemplateArgumentList Innermost; - Innermost.addOuterTemplateArguments(TemplateArgs.getInnermost()); TypeSourceInfo *DI = - SubstType(PatternDecl->getTypeSourceInfo(), Innermost, + SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs, PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName()); if (!DI) return 0; @@ -3429,14 +3430,9 @@ void Sema::BuildVariableInstantiation( NewVar->setInstantiationOfStaticDataMember(OldVar, TSK_ImplicitInstantiation); - if (isa<VarTemplateSpecializationDecl>(NewVar)) { - // Do not instantiate the variable just yet. - } else if (InstantiatingVarTemplate) { - assert(!NewVar->getInit() && - "A variable should not have an initializer if it is templated" - " and we are instantiating its template"); - NewVar->setInit(OldVar->getInit()); - } else + // Delay instantiation of the initializer for variable templates until a + // definition of the variable is needed. + if (!isa<VarTemplateSpecializationDecl>(NewVar) && !InstantiatingVarTemplate) InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); // Diagnose unused local variables with dependent types, where the diagnostic @@ -3513,19 +3509,18 @@ void Sema::InstantiateStaticDataMemberDefinition( void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive, bool DefinitionRequired) { - if (Var->isInvalidDecl()) return; VarTemplateSpecializationDecl *VarSpec = dyn_cast<VarTemplateSpecializationDecl>(Var); - assert((VarSpec || Var->isStaticDataMember()) && - "Not a static data member, nor a variable template specialization?"); - VarDecl *PatternDecl = 0; + VarDecl *PatternDecl = 0, *Def = 0; + MultiLevelTemplateArgumentList TemplateArgs = + getTemplateInstantiationArgs(Var); - // If this is a variable template specialization, make sure that it is - // non-dependent, then find its instantiation pattern. if (VarSpec) { + // If this is a variable template specialization, make sure that it is + // non-dependent, then find its instantiation pattern. bool InstantiationDependent = false; assert(!TemplateSpecializationType::anyDependentTemplateArguments( VarSpec->getTemplateArgsInfo(), InstantiationDependent) && @@ -3533,59 +3528,123 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, "not type-dependent"); (void)InstantiationDependent; - // Find the variable initialization that we'll be substituting. + // Find the variable initialization that we'll be substituting. If the + // pattern was instantiated from a member template, look back further to + // find the real pattern. assert(VarSpec->getSpecializedTemplate() && "Specialization without specialized template?"); llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> PatternPtr = VarSpec->getSpecializedTemplateOrPartial(); if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) { - PatternDecl = cast<VarDecl>( - PatternPtr.get<VarTemplatePartialSpecializationDecl *>()); + VarTemplatePartialSpecializationDecl *Tmpl = + PatternPtr.get<VarTemplatePartialSpecializationDecl *>(); + while (VarTemplatePartialSpecializationDecl *From = + Tmpl->getInstantiatedFromMember()) { + if (Tmpl->isMemberSpecialization()) + break; - // Find actual definition - if (VarDecl *Def = PatternDecl->getDefinition(getASTContext())) - PatternDecl = Def; + Tmpl = From; + } + PatternDecl = Tmpl; } else { - VarTemplateDecl *PatternTemplate = PatternPtr.get<VarTemplateDecl *>(); + VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>(); + while (VarTemplateDecl *From = + Tmpl->getInstantiatedFromMemberTemplate()) { + if (Tmpl->isMemberSpecialization()) + break; + + Tmpl = From; + } + PatternDecl = Tmpl->getTemplatedDecl(); + } - // Find actual definition - if (VarTemplateDecl *Def = PatternTemplate->getDefinition()) - PatternTemplate = Def; + // If this is a static data member template, there might be an + // uninstantiated initializer on the declaration. If so, instantiate + // it now. + if (PatternDecl->isStaticDataMember() && + (PatternDecl = PatternDecl->getFirstDeclaration())->hasInit() && + !Var->hasInit()) { + // FIXME: Factor out the duplicated instantiation context setup/tear down + // code here. + 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. + SmallVector<VTableUse, 16> SavedVTableUses; + std::deque<PendingImplicitInstantiation> SavedPendingInstantiations; + if (Recursive) { + VTableUses.swap(SavedVTableUses); + PendingInstantiations.swap(SavedPendingInstantiations); + } + + LocalInstantiationScope Local(*this); + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + ContextRAII PreviousContext(*this, Var->getDeclContext()); + InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs); + PreviousContext.pop(); + + // FIXME: Need to inform the ASTConsumer that we instantiated the + // initializer? + + // This variable may have local implicit instantiations that need to be + // instantiated within this scope. + PerformPendingInstantiations(/*LocalOnly=*/true); - PatternDecl = PatternTemplate->getTemplatedDecl(); + Local.Exit(); + + if (Recursive) { + // Define any newly required vtables. + DefineUsedVTables(); + + // Instantiate any pending implicit instantiations found during the + // instantiation of this template. + PerformPendingInstantiations(); + + // Restore the set of pending vtables. + assert(VTableUses.empty() && + "VTableUses should be empty before it is discarded."); + VTableUses.swap(SavedVTableUses); + + // Restore the set of pending implicit instantiations. + assert(PendingInstantiations.empty() && + "PendingInstantiations should be empty before it is discarded."); + PendingInstantiations.swap(SavedPendingInstantiations); + } } - assert(PatternDecl && "instantiating a non-template"); - } - // If this is a static data member, find its out-of-line definition. - VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); - if (Var->isStaticDataMember()) { - assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); - Def = Def->getOutOfLineDefinition(); + // Find actual definition + Def = PatternDecl->getDefinition(getASTContext()); + } else { + // If this is a static data member, find its out-of-line definition. + assert(Var->isStaticDataMember() && "not a static data member?"); + PatternDecl = Var->getInstantiatedFromStaticDataMember(); + + assert(PatternDecl && "data member was not instantiated from a template?"); + assert(PatternDecl->isStaticDataMember() && "not a static data member?"); + Def = PatternDecl->getOutOfLineDefinition(); } - // If the instantiation pattern does not have an initializer, or if an - // out-of-line definition is not found, 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. - if ((VarSpec && !PatternDecl->getInit()) || - (!VarSpec && Var->isStaticDataMember() && !Def)) { + // If we don't have a definition of the variable template, 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. + if (!Def) { if (DefinitionRequired) { - if (!Var->isStaticDataMember()) { + if (VarSpec) Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_var_template) - << PatternDecl; - Diag(PatternDecl->getLocation(), - diag::note_explicit_instantiation_here); - } else { - Def = Var->getInstantiatedFromStaticDataMember(); + diag::err_explicit_instantiation_undefined_var_template) << Var; + else Diag(PointOfInstantiation, diag::err_explicit_instantiation_undefined_member) - << 3 << Var->getDeclName() << Var->getDeclContext(); - Diag(Def->getLocation(), diag::note_explicit_instantiation_here); - } + << 2 << Var->getDeclName() << Var->getDeclContext(); + Diag(PatternDecl->getLocation(), + diag::note_explicit_instantiation_here); if (VarSpec) Var->setInvalidDecl(); } else if (Var->getTemplateSpecializationKind() @@ -3603,11 +3662,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (TSK == TSK_ExplicitSpecialization) return; - // C++0x [temp.explicit]p9: - // Except for inline functions, other explicit instantiation declarations - // have the effect of suppressing the implicit instantiation of the entity - // to which they refer. - // // C++11 [temp.explicit]p10: // Except for inline functions, [...] explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity @@ -3624,24 +3678,17 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, : Consumer(Consumer), Var(Var) { } ~PassToConsumerRAII() { - if (Var->isStaticDataMember()) - Consumer.HandleCXXStaticMemberVarInstantiation(Var); - else { - DeclGroupRef DG(Var); - Consumer.HandleTopLevelDecl(DG); - } + Consumer.HandleCXXStaticMemberVarInstantiation(Var); } } PassToConsumerRAII(Consumer, Var); - if (!VarSpec) { - // If we already have a definition, we're done. - if (VarDecl *Def = Var->getDefinition()) { - // We may be explicitly instantiating something we've already implicitly - // instantiated. - Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(), - PointOfInstantiation); - return; - } + // If we already have a definition, we're done. + if (VarDecl *Def = Var->getDefinition()) { + // We may be explicitly instantiating something we've already implicitly + // instantiated. + Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(), + PointOfInstantiation); + return; } InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); @@ -3666,29 +3713,46 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *OldVar = Var; if (!VarSpec) Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), - getTemplateInstantiationArgs(Var))); - else - // Construct a VarTemplateSpecializationDecl to avoid name clashing with - // the primary template. (Note that unlike function declarations, variable - // declarations cannot be overloaded.) - // In fact, there is no need to construct a new declaration from scratch. - // Thus, simply complete its definition with an appropriately substituted - // type and initializer. - Var = CompleteVarTemplateSpecializationDecl( - VarSpec, PatternDecl, getTemplateInstantiationArgs(Var)); + TemplateArgs)); + else if (Var->isStaticDataMember() && + Var->getLexicalDeclContext()->isRecord()) { + // We need to instantiate the definition of a static data member template, + // and all we have is the in-class declaration of it. Instantiate a separate + // declaration of the definition. + TemplateDeclInstantiator Instantiator(*this, Var->getDeclContext(), + TemplateArgs); + Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl( + VarSpec->getSpecializedTemplate(), Def, 0, + VarSpec->getTemplateArgsInfo(), VarSpec->getTemplateArgs().asArray())); + if (Var) { + llvm::PointerUnion<VarTemplateDecl *, + VarTemplatePartialSpecializationDecl *> PatternPtr = + VarSpec->getSpecializedTemplateOrPartial(); + if (VarTemplatePartialSpecializationDecl *Partial = + PatternPtr.dyn_cast<VarTemplatePartialSpecializationDecl *>()) + cast<VarTemplateSpecializationDecl>(Var)->setInstantiationOf( + Partial, &VarSpec->getTemplateInstantiationArgs()); + + // Merge the definition with the declaration. + LookupResult R(*this, Var->getDeclName(), Var->getLocation(), + LookupOrdinaryName, ForRedeclaration); + R.addDecl(OldVar); + MergeVarDecl(Var, R); + + // Attach the initializer. + InstantiateVariableInitializer(Var, Def, TemplateArgs); + } + } else + // Complete the existing variable's definition with an appropriately + // substituted type and initializer. + Var = CompleteVarTemplateSpecializationDecl(VarSpec, Def, TemplateArgs); PreviousContext.pop(); if (Var) { - MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); - if (!VarSpec) - assert(MSInfo && "Missing member specialization information?"); - PassToConsumerRAII.Var = Var; - if (MSInfo) - Var->setTemplateSpecializationKind( - MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation()); + Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind(), + OldVar->getPointOfInstantiation()); } // This variable may have local implicit instantiations that need to be |