diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-03 23:51:38 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-03 23:51:38 +0000 |
commit | 6cc60c9164a96f1d73ccfd302303490e0d085b87 (patch) | |
tree | f2639ec1876eaba545ef3845d3572424ae9cc621 /lib/Sema | |
parent | db45e9b8b840d510c5c5bc1bf7476e70312c59dd (diff) |
CWG issue 727: Fix numerous bugs in support for class-scope explicit
specializations for variable templates.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359947 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 181 |
3 files changed, 108 insertions, 97 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 9564c8f0cb..2d9dbdd342 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -15721,7 +15721,12 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, "Invalid Expr argument to DoMarkVarDeclReferenced"); Var->setReferenced(); - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + if (Var->isInvalidDecl()) + return; + + auto *MSI = Var->getMemberSpecializationInfo(); + TemplateSpecializationKind TSK = MSI ? MSI->getTemplateSpecializationKind() + : Var->getTemplateSpecializationKind(); bool OdrUseContext = isOdrUseContext(SemaRef); bool UsableInConstantExpr = @@ -15754,11 +15759,15 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, (TSK == TSK_ExplicitInstantiationDeclaration && UsableInConstantExpr); if (TryInstantiating) { - SourceLocation PointOfInstantiation = Var->getPointOfInstantiation(); + SourceLocation PointOfInstantiation = + MSI ? MSI->getPointOfInstantiation() : Var->getPointOfInstantiation(); bool FirstInstantiation = PointOfInstantiation.isInvalid(); if (FirstInstantiation) { PointOfInstantiation = Loc; - Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); + if (MSI) + MSI->setPointOfInstantiation(PointOfInstantiation); + else + Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); } bool InstantiationDependent = false; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 939941a4c2..58ad439747 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3927,13 +3927,6 @@ DeclResult Sema::ActOnVarTemplateSpecialization( Specialization->setAccess(VarTemplate->getAccess()); } - // Link instantiations of static data members back to the template from - // which they were instantiated. - if (Specialization->isStaticDataMember()) - Specialization->setInstantiationOfStaticDataMember( - VarTemplate->getTemplatedDecl(), - Specialization->getSpecializationKind()); - return Specialization; } @@ -9198,7 +9191,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!PrevTemplate) { if (!Prev || !Prev->isStaticDataMember()) { - // We expect to see a data data member here. + // We expect to see a static data member here. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) << Name; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 90ae8989c1..653eb69326 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3132,13 +3132,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( "for a member class template"); // Lookup the already-instantiated declaration in the instantiation - // of the class template. FIXME: Diagnose or assert if this fails? - DeclContext::lookup_result Found - = Owner->lookup(ClassTemplate->getDeclName()); - if (Found.empty()) - return nullptr; - ClassTemplateDecl *InstClassTemplate - = dyn_cast<ClassTemplateDecl>(Found.front()); + // of the class template. + ClassTemplateDecl *InstClassTemplate = + cast_or_null<ClassTemplateDecl>(SemaRef.FindInstantiatedDecl( + D->getLocation(), ClassTemplate, TemplateArgs)); if (!InstClassTemplate) return nullptr; @@ -3247,6 +3244,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Instantiate the members of the class-scope explicit specialization eagerly. // We don't have support for lazy instantiation of an explicit specialization // yet, and MSVC eagerly instantiates in this case. + // FIXME: This is wrong in standard C++. if (D->isThisDeclarationADefinition() && SemaRef.InstantiateClass(D->getLocation(), InstD, D, TemplateArgs, TSK_ImplicitInstantiation, @@ -3264,6 +3262,12 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( assert(VarTemplate && "A template specialization without specialized template?"); + VarTemplateDecl *InstVarTemplate = + cast_or_null<VarTemplateDecl>(SemaRef.FindInstantiatedDecl( + D->getLocation(), VarTemplate, TemplateArgs)); + if (!InstVarTemplate) + return nullptr; + // Substitute the current template arguments. const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo(); VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc()); @@ -3275,28 +3279,33 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList( - VarTemplate, VarTemplate->getBeginLoc(), - const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false, - Converted)) + if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), + VarTemplateArgsInfo, false, Converted)) return nullptr; - // Find the variable template specialization declaration that - // corresponds to these arguments. + // Check whether we've already seen a declaration of this specialization. void *InsertPos = nullptr; - if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization( - Converted, InsertPos)) - // If we already have a variable template specialization, return it. - return VarSpec; + VarTemplateSpecializationDecl *PrevDecl = + InstVarTemplate->findSpecialization(Converted, InsertPos); + + // Check whether we've already seen a conflicting instantiation of this + // declaration (for instance, if there was a prior implicit instantiation). + bool Ignored; + if (PrevDecl && SemaRef.CheckSpecializationInstantiationRedecl( + D->getLocation(), D->getSpecializationKind(), PrevDecl, + PrevDecl->getSpecializationKind(), + PrevDecl->getPointOfInstantiation(), Ignored)) + return nullptr; - return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos, - VarTemplateArgsInfo, Converted); + return VisitVarTemplateSpecializationDecl( + InstVarTemplate, D, InsertPos, VarTemplateArgsInfo, Converted, PrevDecl); } Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos, const TemplateArgumentListInfo &TemplateArgsInfo, - ArrayRef<TemplateArgument> Converted) { + ArrayRef<TemplateArgument> Converted, + VarTemplateSpecializationDecl *PrevDecl) { // Do substitution on the type of the declaration TypeSourceInfo *DI = @@ -3323,8 +3332,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( if (SubstQualifier(D, Var)) return nullptr; - SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, - Owner, StartingScope); + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner, + StartingScope, false, PrevDecl); return Var; } @@ -4339,7 +4348,19 @@ void Sema::BuildVariableInstantiation( const MultiLevelTemplateArgumentList &TemplateArgs, LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, LocalInstantiationScope *StartingScope, - bool InstantiatingVarTemplate) { + bool InstantiatingVarTemplate, + VarTemplateSpecializationDecl *PrevDeclForVarTemplateSpecialization) { + // Instantiating a partial specialization to produce a partial + // specialization. + bool InstantiatingVarTemplatePartialSpec = + isa<VarTemplatePartialSpecializationDecl>(OldVar) && + isa<VarTemplatePartialSpecializationDecl>(NewVar); + // Instantiating from a variable template (or partial specialization) to + // produce a variable template specialization. + bool InstantiatingSpecFromTemplate = + isa<VarTemplateSpecializationDecl>(NewVar) && + (OldVar->getDescribedVarTemplate() || + isa<VarTemplatePartialSpecializationDecl>(OldVar)); // If we are instantiating a local extern declaration, the // instantiation belongs lexically to the containing function. @@ -4385,8 +4406,11 @@ void Sema::BuildVariableInstantiation( NewVar->getLocation(), OldVar->getPreviousDecl(), TemplateArgs)) Previous.addDecl(NewPrev); } else if (!isa<VarTemplateSpecializationDecl>(NewVar) && - OldVar->hasLinkage()) + OldVar->hasLinkage()) { LookupQualifiedName(Previous, NewVar->getDeclContext(), false); + } else if (PrevDeclForVarTemplateSpecialization) { + Previous.addDecl(PrevDeclForVarTemplateSpecialization); + } CheckVariableDeclaration(NewVar, Previous); if (!InstantiatingVarTemplate) { @@ -4402,23 +4426,44 @@ void Sema::BuildVariableInstantiation( // Link instantiations of static data members back to the template from // which they were instantiated. - if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate) + // + // Don't do this when instantiating a template (we link the template itself + // back in that case) nor when instantiating a static data member template + // (that's not a member specialization). + if (NewVar->isStaticDataMember() && !InstantiatingVarTemplate && + !InstantiatingSpecFromTemplate) NewVar->setInstantiationOfStaticDataMember(OldVar, TSK_ImplicitInstantiation); + // If the pattern is an (in-class) explicit specialization, then the result + // is also an explicit specialization. + if (VarTemplateSpecializationDecl *OldVTSD = + dyn_cast<VarTemplateSpecializationDecl>(OldVar)) { + if (OldVTSD->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<VarTemplatePartialSpecializationDecl>(OldVTSD)) + cast<VarTemplateSpecializationDecl>(NewVar)->setSpecializationKind( + TSK_ExplicitSpecialization); + } + // Forward the mangling number from the template to the instantiated decl. Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar)); Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar)); - // Delay instantiation of the initializer for variable templates or inline - // static data members until a definition of the variable is needed. We need - // it right away if the type contains 'auto'. - if ((!isa<VarTemplateSpecializationDecl>(NewVar) && - !InstantiatingVarTemplate && - !(OldVar->isInline() && OldVar->isThisDeclarationADefinition() && - !NewVar->isThisDeclarationADefinition())) || - NewVar->getType()->isUndeducedType()) + // Figure out whether to eagerly instantiate the initializer. + if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) { + // We're producing a template. Don't instantiate the initializer yet. + } else if (NewVar->getType()->isUndeducedType()) { + // We need the type to complete the declaration of the variable. InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + } else if (InstantiatingSpecFromTemplate || + (OldVar->isInline() && OldVar->isThisDeclarationADefinition() && + !NewVar->isThisDeclarationADefinition())) { + // Delay instantiation of the initializer for variable template + // specializations or inline static data members until a definition of the + // variable is needed. + } else { + InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + } // Diagnose unused local variables with dependent types, where the diagnostic // will have been deferred. @@ -4518,15 +4563,23 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (Var->isInvalidDecl()) return; - VarTemplateSpecializationDecl *VarSpec = - dyn_cast<VarTemplateSpecializationDecl>(Var); - VarDecl *PatternDecl = nullptr, *Def = nullptr; + // Never instantiate an explicitly-specialized entity. + TemplateSpecializationKind TSK = + Var->getTemplateSpecializationKindForInstantiation(); + if (TSK == TSK_ExplicitSpecialization) + return; + + // Find the pattern and the arguments to substitute into it. + VarDecl *PatternDecl = Var->getTemplateInstantiationPattern(); + assert(PatternDecl && "no pattern for templated variable"); MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Var); + VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(Var); if (VarSpec) { // If this is a variable template specialization, make sure that it is - // non-dependent, then find its instantiation pattern. + // non-dependent. bool InstantiationDependent = false; assert(!TemplateSpecializationType::anyDependentTemplateArguments( VarSpec->getTemplateArgsInfo(), InstantiationDependent) && @@ -4534,37 +4587,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, "not type-dependent"); (void)InstantiationDependent; - // 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 *>()) { - VarTemplatePartialSpecializationDecl *Tmpl = - PatternPtr.get<VarTemplatePartialSpecializationDecl *>(); - while (VarTemplatePartialSpecializationDecl *From = - Tmpl->getInstantiatedFromMember()) { - if (Tmpl->isMemberSpecialization()) - break; - - Tmpl = From; - } - PatternDecl = Tmpl; - } else { - VarTemplateDecl *Tmpl = PatternPtr.get<VarTemplateDecl *>(); - while (VarTemplateDecl *From = - Tmpl->getInstantiatedFromMemberTemplate()) { - if (Tmpl->isMemberSpecialization()) - break; - - Tmpl = From; - } - PatternDecl = Tmpl->getTemplatedDecl(); - } - // If this is a static data member template, there might be an // uninstantiated initializer on the declaration. If so, instantiate // it now. @@ -4608,20 +4630,12 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, Local.Exit(); GlobalInstantiations.perform(); } - - // 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->getDefinition(); + assert(Var->isStaticDataMember() && PatternDecl->isStaticDataMember() && + "not a static data member?"); } - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + VarDecl *Def = PatternDecl->getDefinition(getASTContext()); // 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 @@ -4643,7 +4657,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, } return; } - } // FIXME: We need to track the instantiation stack in order to know which @@ -4655,11 +4668,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, /*Complain*/DefinitionRequired)) return; - - // Never instantiate an explicit specialization. - if (TSK == TSK_ExplicitSpecialization) - return; - // C++11 [temp.explicit]p10: // Except for inline functions, const variables of literal types, variables // of reference types, [...] explicit instantiation declarations @@ -5495,7 +5503,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Check if the most recent declaration has changed the specialization kind // and removed the need for implicit instantiation. - switch (Var->getMostRecentDecl()->getTemplateSpecializationKind()) { + switch (Var->getMostRecentDecl() + ->getTemplateSpecializationKindForInstantiation()) { case TSK_Undeclared: llvm_unreachable("Cannot instantitiate an undeclared specialization."); case TSK_ExplicitInstantiationDeclaration: |