diff options
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 406 |
1 files changed, 306 insertions, 100 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7a452af77839..6a213953ec9a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -227,6 +227,86 @@ static void instantiateDependentCUDALaunchBoundsAttr( Attr.getSpellingListIndex()); } +static void +instantiateDependentModeAttr(Sema &S, + const MultiLevelTemplateArgumentList &TemplateArgs, + const ModeAttr &Attr, Decl *New) { + S.AddModeAttr(Attr.getRange(), New, Attr.getMode(), + Attr.getSpellingListIndex(), /*InInstantiation=*/true); +} + +/// Instantiation of 'declare simd' attribute and its arguments. +static void instantiateOMPDeclareSimdDeclAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const OMPDeclareSimdDeclAttr &Attr, Decl *New) { + // Allow 'this' in clauses with varlists. + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New)) + New = FTD->getTemplatedDecl(); + auto *FD = cast<FunctionDecl>(New); + auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext()); + SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps; + SmallVector<unsigned, 4> LinModifiers; + + auto &&Subst = [&](Expr *E) -> ExprResult { + if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + Sema::ContextRAII SavedContext(S, FD); + LocalInstantiationScope Local(S); + if (FD->getNumParams() > PVD->getFunctionScopeIndex()) + Local.InstantiatedLocal( + PVD, FD->getParamDecl(PVD->getFunctionScopeIndex())); + return S.SubstExpr(E, TemplateArgs); + } + Sema::CXXThisScopeRAII ThisScope(S, ThisContext, /*TypeQuals=*/0, + FD->isCXXInstanceMember()); + return S.SubstExpr(E, TemplateArgs); + }; + + ExprResult Simdlen; + if (auto *E = Attr.getSimdlen()) + Simdlen = Subst(E); + + if (Attr.uniforms_size() > 0) { + for(auto *E : Attr.uniforms()) { + ExprResult Inst = Subst(E); + if (Inst.isInvalid()) + continue; + Uniforms.push_back(Inst.get()); + } + } + + auto AI = Attr.alignments_begin(); + for (auto *E : Attr.aligneds()) { + ExprResult Inst = Subst(E); + if (Inst.isInvalid()) + continue; + Aligneds.push_back(Inst.get()); + Inst = ExprEmpty(); + if (*AI) + Inst = S.SubstExpr(*AI, TemplateArgs); + Alignments.push_back(Inst.get()); + ++AI; + } + + auto SI = Attr.steps_begin(); + for (auto *E : Attr.linears()) { + ExprResult Inst = Subst(E); + if (Inst.isInvalid()) + continue; + Linears.push_back(Inst.get()); + Inst = ExprEmpty(); + if (*SI) + Inst = S.SubstExpr(*SI, TemplateArgs); + Steps.push_back(Inst.get()); + ++SI; + } + LinModifiers.append(Attr.modifiers_begin(), Attr.modifiers_end()); + (void)S.ActOnOpenMPDeclareSimdDirective( + S.ConvertDeclToDeclGroup(New), Attr.getBranchState(), Simdlen.get(), + Uniforms, Aligneds, Alignments, Linears, LinModifiers, Steps, + Attr.getRange()); +} + void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -265,6 +345,16 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (const ModeAttr *Mode = dyn_cast<ModeAttr>(TmplAttr)) { + instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New); + continue; + } + + if (const auto *OMPAttr = dyn_cast<OMPDeclareSimdDeclAttr>(TmplAttr)) { + instantiateOMPDeclareSimdDeclAttr(*this, TemplateArgs, *OMPAttr, New); + continue; + } + // Existing DLL attribute on the instantiation takes precedence. if (TmplAttr->getKind() == attr::DLLExport || TmplAttr->getKind() == attr::DLLImport) { @@ -273,6 +363,20 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } } + if (auto ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) { + AddParameterABIAttr(ABIAttr->getRange(), New, ABIAttr->getABI(), + ABIAttr->getSpellingListIndex()); + continue; + } + + if (isa<NSConsumedAttr>(TmplAttr) || isa<CFConsumedAttr>(TmplAttr)) { + AddNSConsumedAttr(TmplAttr->getRange(), New, + TmplAttr->getSpellingListIndex(), + isa<NSConsumedAttr>(TmplAttr), + /*template instantiation*/ true); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the @@ -321,6 +425,16 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { } Decl * +TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) { + llvm_unreachable("pragma comment cannot be instantiated"); +} + +Decl *TemplateDeclInstantiator::VisitPragmaDetectMismatchDecl( + PragmaDetectMismatchDecl *D) { + llvm_unreachable("pragma comment cannot be instantiated"); +} + +Decl * TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) { llvm_unreachable("extern \"C\" context cannot be instantiated"); } @@ -491,13 +605,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate) { - // If this is the variable for an anonymous struct or union, - // instantiate the anonymous struct/union type first. - if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) - if (RecordTy->getDecl()->isAnonymousStructOrUnion()) - if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) - return nullptr; - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, @@ -696,7 +803,7 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { QualType T = cast<FieldDecl>(NamedChain[i-1])->getType(); IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create( SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T, - NamedChain, D->getChainingSize()); + {NamedChain, D->getChainingSize()}); for (const auto *Attr : D->attrs()) IndirectField->addAttr(Attr->clone(SemaRef.Context)); @@ -911,9 +1018,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition( } } - // FIXME: Fixup LBraceLoc - SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), - Enum->getRBraceLoc(), Enum, + SemaRef.ActOnEnumBody(Enum->getLocation(), Enum->getBraceRange(), Enum, Enumerators, nullptr, nullptr); } @@ -1499,8 +1604,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.begin(), - Innermost.size()), + Innermost), /*InsertPos=*/nullptr); } else if (isFriend) { // Note, we need this connection even if the friend doesn't have a body. @@ -1736,36 +1840,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->isExplicit(), Constructor->isInlineSpecified(), false, Constructor->isConstexpr()); - - // Claim that the instantiation of a constructor or constructor template - // inherits the same constructor that the template does. - if (CXXConstructorDecl *Inh = const_cast<CXXConstructorDecl *>( - Constructor->getInheritedConstructor())) { - // If we're instantiating a specialization of a function template, our - // "inherited constructor" will actually itself be a function template. - // Instantiate a declaration of it, too. - if (FunctionTemplate) { - assert(!TemplateParams && Inh->getDescribedFunctionTemplate() && - !Inh->getParent()->isDependentContext() && - "inheriting constructor template in dependent context?"); - Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(), - Inh); - if (Inst.isInvalid()) - return nullptr; - Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext()); - LocalInstantiationScope LocalScope(SemaRef); - - // Use the same template arguments that we deduced for the inheriting - // constructor. There's no way they could be deduced differently. - MultiLevelTemplateArgumentList InheritedArgs; - InheritedArgs.addOuterTemplateArguments(TemplateArgs.getInnermost()); - Inh = cast_or_null<CXXConstructorDecl>( - SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs)); - if (!Inh) - return nullptr; - } - cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh); - } } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1821,8 +1895,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.begin(), - Innermost.size()), + Innermost), /*InsertPos=*/nullptr); } else if (!isFriend) { // Record that this is an instantiation of a member function. @@ -2080,16 +2153,11 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *Param; if (IsExpandedParameterPack) - Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, - D->getInnerLocStart(), - D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), - D->getIdentifier(), T, - DI, - ExpandedParameterPackTypes.data(), - ExpandedParameterPackTypes.size(), - ExpandedParameterPackTypesAsWritten.data()); + Param = NonTypeTemplateParmDecl::Create( + SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), + D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(), + D->getIdentifier(), T, DI, ExpandedParameterPackTypes, + ExpandedParameterPackTypesAsWritten); else Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), @@ -2104,6 +2172,8 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( Param->setInvalidDecl(); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { + EnterExpressionEvaluationContext ConstantEvaluated(SemaRef, + Sema::ConstantEvaluated); ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs); if (!Value.isInvalid()) Param->setDefaultArgument(Value.get()); @@ -2289,9 +2359,14 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { if (!QualifierLoc) return nullptr; - // The name info is non-dependent, so no transformation - // is required. + // For an inheriting constructor declaration, the name of the using + // declaration is the name of a constructor in this class, not in the + // base class. DeclarationNameInfo NameInfo = D->getNameInfo(); + if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) + if (auto *RD = dyn_cast<CXXRecordDecl>(SemaRef.CurContext)) + NameInfo.setName(SemaRef.Context.DeclarationNames.getCXXConstructorName( + SemaRef.Context.getCanonicalType(SemaRef.Context.getRecordType(RD)))); // We only need to do redeclaration lookups if we're in a class // scope (in fact, it's not really even possible in non-class @@ -2334,18 +2409,23 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { if (NewUD->isInvalidDecl()) return NewUD; - if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) { + if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) SemaRef.CheckInheritingConstructorUsingDecl(NewUD); - return NewUD; - } bool isFunctionScope = Owner->isFunctionOrMethod(); // Process the shadow decls. for (auto *Shadow : D->shadows()) { + // FIXME: UsingShadowDecl doesn't preserve its immediate target, so + // reconstruct it in the case where it matters. + NamedDecl *OldTarget = Shadow->getTargetDecl(); + if (auto *CUSD = dyn_cast<ConstructorUsingShadowDecl>(Shadow)) + if (auto *BaseShadow = CUSD->getNominatedBaseClassShadowDecl()) + OldTarget = BaseShadow; + NamedDecl *InstTarget = cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl( - Shadow->getLocation(), Shadow->getTargetDecl(), TemplateArgs)); + Shadow->getLocation(), OldTarget, TemplateArgs)); if (!InstTarget) return nullptr; @@ -2376,6 +2456,12 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { return nullptr; } +Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl( + ConstructorUsingShadowDecl *D) { + // Ignore these; we handle them in bulk when processing the UsingDecl. + return nullptr; +} + Decl * TemplateDeclInstantiator ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { NestedNameSpecifierLoc QualifierLoc @@ -2477,6 +2563,86 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( return TD; } +Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( + OMPDeclareReductionDecl *D) { + // Instantiate type and check if it is allowed. + QualType SubstReductionType = SemaRef.ActOnOpenMPDeclareReductionType( + D->getLocation(), + ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs, + D->getLocation(), DeclarationName()))); + if (SubstReductionType.isNull()) + return nullptr; + bool IsCorrect = !SubstReductionType.isNull(); + // Create instantiated copy. + std::pair<QualType, SourceLocation> ReductionTypes[] = { + std::make_pair(SubstReductionType, D->getLocation())}; + auto *PrevDeclInScope = D->getPrevDeclInScope(); + if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) { + PrevDeclInScope = cast<OMPDeclareReductionDecl>( + SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope) + ->get<Decl *>()); + } + auto DRD = SemaRef.ActOnOpenMPDeclareReductionDirectiveStart( + /*S=*/nullptr, Owner, D->getDeclName(), ReductionTypes, D->getAccess(), + PrevDeclInScope); + auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl()); + if (isDeclWithinFunction(NewDRD)) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD); + Expr *SubstCombiner = nullptr; + Expr *SubstInitializer = nullptr; + // Combiners instantiation sequence. + if (D->getCombiner()) { + SemaRef.ActOnOpenMPDeclareReductionCombinerStart( + /*S=*/nullptr, NewDRD); + const char *Names[] = {"omp_in", "omp_out"}; + for (auto &Name : Names) { + DeclarationName DN(&SemaRef.Context.Idents.get(Name)); + auto OldLookup = D->lookup(DN); + auto Lookup = NewDRD->lookup(DN); + if (!OldLookup.empty() && !Lookup.empty()) { + assert(Lookup.size() == 1 && OldLookup.size() == 1); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldLookup.front(), + Lookup.front()); + } + } + SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get(); + SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner); + // Initializers instantiation sequence. + if (D->getInitializer()) { + SemaRef.ActOnOpenMPDeclareReductionInitializerStart( + /*S=*/nullptr, NewDRD); + const char *Names[] = {"omp_orig", "omp_priv"}; + for (auto &Name : Names) { + DeclarationName DN(&SemaRef.Context.Idents.get(Name)); + auto OldLookup = D->lookup(DN); + auto Lookup = NewDRD->lookup(DN); + if (!OldLookup.empty() && !Lookup.empty()) { + assert(Lookup.size() == 1 && OldLookup.size() == 1); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + OldLookup.front(), Lookup.front()); + } + } + SubstInitializer = + SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get(); + SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD, + SubstInitializer); + } + IsCorrect = IsCorrect && SubstCombiner && + (!D->getInitializer() || SubstInitializer); + } else + IsCorrect = false; + + (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD, + IsCorrect); + + return NewDRD; +} + +Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl( + OMPCapturedExprDecl * /*D*/) { + llvm_unreachable("Should not be met in templates"); +} + Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { return VisitFunctionDecl(D, nullptr); } @@ -2580,8 +2746,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( D->getLocStart(), D->getLocation(), InstClassTemplate, - Converted.data(), - Converted.size(), + Converted, PrevDecl); // Add this partial specialization to the set of class template partial @@ -2596,7 +2761,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Build the canonical type that describes the converted template // arguments of the class template explicit specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(InstClassTemplate), Converted.data(), Converted.size(), + TemplateName(InstClassTemplate), Converted, SemaRef.Context.getRecordType(InstD)); // Build the fully-sugared type for this class template @@ -2673,13 +2838,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( const TemplateArgumentListInfo &TemplateArgsInfo, ArrayRef<TemplateArgument> Converted) { - // If this is the variable for an anonymous struct or union, - // instantiate the anonymous struct/union type first. - if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) - if (RecordTy->getDecl()->isAnonymousStructOrUnion()) - if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) - return nullptr; - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, @@ -2696,8 +2854,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Build the instantiated declaration VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(), - Converted.size()); + VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted); Var->setTemplateArgsInfo(TemplateArgsInfo); if (InsertPos) VarTemplate->AddSpecialization(Var, InsertPos); @@ -2830,8 +2987,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // arguments of the class template partial specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), - Converted.data(), - Converted.size()); + Converted); // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization @@ -2880,8 +3036,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( PartialSpec->getLocation(), InstParams, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, InstTemplateArgs, CanonType, nullptr); @@ -2953,7 +3108,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // Build the canonical type that describes the converted template // arguments of the variable template partial specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(VarTemplate), Converted.data(), Converted.size()); + TemplateName(VarTemplate), Converted); // Build the fully-sugared type for this variable template // specialization as the user wrote in the specialization @@ -3009,8 +3164,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( VarTemplatePartialSpecializationDecl::Create( SemaRef.Context, Owner, PartialSpec->getInnerLocStart(), PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(), - DI, PartialSpec->getStorageClass(), Converted.data(), - Converted.size(), InstTemplateArgs); + DI, PartialSpec->getStorageClass(), Converted, InstTemplateArgs); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) @@ -3118,9 +3272,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, // In this case, we'll just go instantiate the ParmVarDecls that we // synthesized in the method declaration. SmallVector<QualType, 4> ParamTypes; - if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), - D->getNumParams(), TemplateArgs, ParamTypes, - &Params)) + Sema::ExtParameterInfoBuilder ExtParamInfos; + if (SemaRef.SubstParmTypes(D->getLocation(), D->parameters(), nullptr, + TemplateArgs, ParamTypes, &Params, + ExtParamInfos)) return nullptr; } @@ -3347,7 +3502,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive, - bool DefinitionRequired) { + bool DefinitionRequired, + bool AtEndOfTU) { if (Function->isInvalidDecl() || Function->isDefined()) return; @@ -3401,6 +3557,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Pattern = PatternDecl->getBody(PatternDecl); } + // FIXME: Check that the definition is visible before trying to instantiate + // it. This requires us to track the instantiation stack in order to know + // which definitions should be visible. + if (!Pattern && !PatternDecl->isDefaulted()) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) @@ -3421,6 +3581,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, assert(!Recursive); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); + } else if (Function->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) { + if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { + Diag(PointOfInstantiation, diag::warn_func_template_missing) + << Function; + Diag(PatternDecl->getLocation(), diag::note_forward_template_decl); + if (getLangOpts().CPlusPlus11) + Diag(PointOfInstantiation, diag::note_inst_declaration_hint) + << Function; + } } return; @@ -3451,6 +3621,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst.isInvalid()) return; + PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), + "instantiating function definition"); // Copy the inner loc start from the pattern. Function->setInnerLocStart(PatternDecl->getInnerLocStart()); @@ -3681,11 +3853,12 @@ void Sema::BuildVariableInstantiation( Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar)); Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar)); - // Delay instantiation of the initializer for variable templates until a - // definition of the variable is needed. We need it right away if the type - // contains 'auto'. + // 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) || + !InstantiatingVarTemplate && + !(OldVar->isInline() && OldVar->isThisDeclarationADefinition())) || NewVar->getType()->isUndeducedType()) InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); @@ -3701,6 +3874,13 @@ void Sema::BuildVariableInstantiation( void Sema::InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs) { + // We propagate the 'inline' flag with the initializer, because it + // would otherwise imply that the variable is a definition for a + // non-static data member. + if (OldVar->isInlineSpecified()) + Var->setInlineSpecified(); + else if (OldVar->isInline()) + Var->setImplicitlyInline(); if (Var->getAnyInitializer()) // We already have an initializer in the class. @@ -3713,9 +3893,14 @@ void Sema::InstantiateVariableInitializer( PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar); // Instantiate the initializer. - ExprResult Init = - SubstInitializer(OldVar->getInit(), TemplateArgs, - OldVar->getInitStyle() == VarDecl::CallInit); + ExprResult Init; + + { + ContextRAII SwitchContext(*this, Var->getDeclContext()); + Init = SubstInitializer(OldVar->getInit(), TemplateArgs, + OldVar->getInitStyle() == VarDecl::CallInit); + } + if (!Init.isInvalid()) { bool TypeMayContainAuto = true; Expr *InitExpr = Init.get(); @@ -3768,7 +3953,7 @@ void Sema::InstantiateStaticDataMemberDefinition( void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive, - bool DefinitionRequired) { + bool DefinitionRequired, bool AtEndOfTU) { if (Var->isInvalidDecl()) return; @@ -3830,6 +4015,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid()) return; + PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + "instantiating variable initializer"); // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate @@ -3876,9 +4063,13 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, assert(PatternDecl && "data member was not instantiated from a template?"); assert(PatternDecl->isStaticDataMember() && "not a static data member?"); - Def = PatternDecl->getOutOfLineDefinition(); + Def = PatternDecl->getDefinition(); } + // FIXME: Check that the definition is visible before trying to instantiate + // it. This requires us to track the instantiation stack in order to know + // which definitions should be visible. + // 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 @@ -3900,6 +4091,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, == TSK_ExplicitInstantiationDefinition) { PendingInstantiations.push_back( std::make_pair(Var, PointOfInstantiation)); + } else if (Var->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) { + // Warn about missing definition at the end of translation unit. + if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { + Diag(PointOfInstantiation, diag::warn_var_template_missing) + << Var; + Diag(PatternDecl->getLocation(), diag::note_forward_template_decl); + if (getLangOpts().CPlusPlus11) + Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var; + } } return; @@ -3943,6 +4144,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid()) return; + PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + "instantiating variable definition"); // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, @@ -3958,11 +4161,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, LocalInstantiationScope Local(*this); VarDecl *OldVar = Var; - if (!VarSpec) + if (Def->isStaticDataMember() && !Def->isOutOfLine()) { + // We're instantiating an inline static data member whose definition was + // provided inside the class. + // FIXME: Update record? + InstantiateVariableInitializer(Var, Def, TemplateArgs); + } else if (!VarSpec) { Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), TemplateArgs)); - else if (Var->isStaticDataMember() && - Var->getLexicalDeclContext()->isRecord()) { + } 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. @@ -4664,12 +4872,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Instantiate function definitions if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) { - PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), - "instantiating function definition"); bool DefinitionRequired = Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, - DefinitionRequired); + DefinitionRequired, true); continue; } @@ -4710,7 +4916,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Instantiate static data member definitions or variable template // specializations. InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true, - DefinitionRequired); + DefinitionRequired, true); } } |