diff options
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 248 |
1 files changed, 190 insertions, 58 deletions
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 14c6405..6ac7175 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -448,6 +448,10 @@ void Sema::PrintInstantiationStack() { diag::note_template_enum_def_here) << ED << Active->InstantiationRange; + } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + Diags.Report(Active->PointOfInstantiation, + diag::note_template_nsdmi_here) + << FD << Active->InstantiationRange; } else { Diags.Report(Active->PointOfInstantiation, diag::note_template_type_alias_instantiation_here) @@ -767,6 +771,8 @@ namespace { QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = nullptr); + const LoopHintAttr *TransformLoopHintAttr(const LoopHintAttr *LH); + ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); @@ -789,11 +795,17 @@ namespace { ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); QualType TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL); + FunctionProtoTypeLoc TL) { + // Call the base version; it will forward to our overridden version below. + return inherited::TransformFunctionProtoType(TLB, TL); + } + + template<typename Fn> QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals); + unsigned ThisTypeQuals, + Fn TransformExceptionSpec); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, @@ -1023,7 +1035,7 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, - SourceLocation NameLoc, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope) { if (TemplateTemplateParmDecl *TTP @@ -1127,6 +1139,24 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg); } +const LoopHintAttr * +TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { + Expr *TransformedExpr = getDerived().TransformExpr(LH->getValue()).get(); + + if (TransformedExpr == LH->getValue()) + return LH; + + // Generate error if there is a problem with the value. + if (getSema().CheckLoopHintExpr(TransformedExpr, LH->getLocation())) + return LH; + + // Create new LoopHintValueAttr with integral expression in place of the + // non-type template parameter. + return LoopHintAttr::CreateImplicit( + getSema().Context, LH->getSemanticSpelling(), LH->getOption(), + LH->getState(), TransformedExpr, LH->getRange()); +} + ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( NonTypeTemplateParmDecl *parm, SourceLocation loc, @@ -1255,8 +1285,8 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E, Decl *TransformedDecl; if (DeclArgumentPack *Pack = Found->dyn_cast<DeclArgumentPack *>()) { - // If this is a reference to a function parameter pack which we can substitute - // but can't yet expand, build a FunctionParmPackExpr for it. + // If this is a reference to a function parameter pack which we can + // substitute but can't yet expand, build a FunctionParmPackExpr for it. if (getSema().ArgumentPackSubstitutionIndex == -1) { QualType T = TransformType(E->getType()); if (T.isNull()) @@ -1307,21 +1337,16 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( E->getParam()); } -QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL) { - // We need a local instantiation scope for this function prototype. - LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformFunctionProtoType(TLB, TL); -} - +template<typename Fn> QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals) { + unsigned ThisTypeQuals, + Fn TransformExceptionSpec) { // We need a local instantiation scope for this function prototype. LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformFunctionProtoType(TLB, TL, ThisContext, - ThisTypeQuals); + return inherited::TransformFunctionProtoType( + TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec); } ParmVarDecl * @@ -1556,7 +1581,8 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { /// A form of SubstType intended specifically for instantiating the /// type of a FunctionDecl. Its purpose is solely to force the -/// instantiation of default-argument expressions. +/// instantiation of default-argument expressions and to avoid +/// instantiating an exception-specification. TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &Args, SourceLocation Loc, @@ -1579,9 +1605,17 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, QualType Result; - if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) { - Result = Instantiator.TransformFunctionProtoType(TLB, Proto, ThisContext, - ThisTypeQuals); + if (FunctionProtoTypeLoc Proto = + TL.IgnoreParens().getAs<FunctionProtoTypeLoc>()) { + // Instantiate the type, other than its exception specification. The + // exception specification is instantiated in InitFunctionInstantiation + // once we've built the FunctionDecl. + // FIXME: Set the exception specification to EST_Uninstantiated here, + // instead of rebuilding the function type again later. + Result = Instantiator.TransformFunctionProtoType( + TLB, Proto, ThisContext, ThisTypeQuals, + [](FunctionProtoType::ExceptionSpecInfo &ESI, + bool &Changed) { return false; }); } else { Result = Instantiator.TransformType(TLB, TL); } @@ -1591,6 +1625,26 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, return TLB.getTypeSourceInfo(Context, Result); } +void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, + const MultiLevelTemplateArgumentList &Args) { + FunctionProtoType::ExceptionSpecInfo ESI = + Proto->getExtProtoInfo().ExceptionSpec; + assert(ESI.Type != EST_Uninstantiated); + + TemplateInstantiator Instantiator(*this, Args, New->getLocation(), + New->getDeclName()); + + SmallVector<QualType, 4> ExceptionStorage; + bool Changed = false; + if (Instantiator.TransformExceptionSpec( + New->getTypeSourceInfo()->getTypeLoc().getLocEnd(), ESI, + ExceptionStorage, Changed)) + // On error, recover by dropping the exception specification. + ESI.Type = EST_None; + + UpdateExceptionSpec(New, ESI); +} + ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, @@ -1947,8 +2001,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); SmallVector<Decl*, 4> Fields; - SmallVector<std::pair<FieldDecl*, FieldDecl*>, 4> - FieldsWithMemberInitializers; // Delay instantiation of late parsed attributes. LateInstantiatedAttrVec LateAttrs; Instantiator.enableLateAttributeInstantiation(&LateAttrs); @@ -1975,10 +2027,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (NewMember) { if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) { Fields.push_back(Field); - FieldDecl *OldField = cast<FieldDecl>(Member); - if (OldField->getInClassInitializer()) - FieldsWithMemberInitializers.push_back(std::make_pair(OldField, - Field)); } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(NewMember)) { // C++11 [temp.inst]p1: The implicit instantiation of a class template // specialization causes the implicit instantiation of the definitions @@ -2015,31 +2063,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, SourceLocation(), SourceLocation(), nullptr); CheckCompletedCXXClass(Instantiation); - // Attach any in-class member initializers now the class is complete. - // FIXME: We are supposed to defer instantiating these until they are needed. - if (!FieldsWithMemberInitializers.empty()) { - // C++11 [expr.prim.general]p4: - // Otherwise, if a member-declarator declares a non-static data member - // (9.2) of a class X, the expression this is a prvalue of type "pointer - // to X" within the optional brace-or-equal-initializer. It shall not - // appear elsewhere in the member-declarator. - CXXThisScopeRAII ThisScope(*this, Instantiation, (unsigned)0); - - for (unsigned I = 0, N = FieldsWithMemberInitializers.size(); I != N; ++I) { - FieldDecl *OldField = FieldsWithMemberInitializers[I].first; - FieldDecl *NewField = FieldsWithMemberInitializers[I].second; - Expr *OldInit = OldField->getInClassInitializer(); - - ActOnStartCXXInClassMemberInitializer(); - ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, - /*CXXDirectInit=*/false); - Expr *Init = NewInit.get(); - assert((!Init || !isa<ParenListExpr>(Init)) && - "call-style init in class"); - ActOnFinishCXXInClassMemberInitializer(NewField, - Init ? Init->getLocStart() : SourceLocation(), Init); - } - } // Instantiate late parsed attributes, and attach them to their decls. // See Sema::InstantiateAttrs for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(), @@ -2180,6 +2203,80 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, return Instantiation->isInvalidDecl(); } + +/// \brief Instantiate the definition of a field from the given pattern. +/// +/// \param PointOfInstantiation The point of instantiation within the +/// source code. +/// \param Instantiation is the declaration whose definition is being +/// instantiated. This will be a class of a class temploid +/// specialization, or a local enumeration within a function temploid +/// specialization. +/// \param Pattern The templated declaration from which the instantiation +/// occurs. +/// \param TemplateArgs The template arguments to be substituted into +/// the pattern. +/// +/// \return \c true if an error occurred, \c false otherwise. +bool Sema::InstantiateInClassInitializer( + SourceLocation PointOfInstantiation, FieldDecl *Instantiation, + FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) { + // If there is no initializer, we don't need to do anything. + if (!Pattern->hasInClassInitializer()) + return false; + + assert(Instantiation->getInClassInitStyle() == + Pattern->getInClassInitStyle() && + "pattern and instantiation disagree about init style"); + + // Error out if we haven't parsed the initializer of the pattern yet because + // we are waiting for the closing brace of the outer class. + Expr *OldInit = Pattern->getInClassInitializer(); + if (!OldInit) { + RecordDecl *PatternRD = Pattern->getParent(); + RecordDecl *OutermostClass = PatternRD->getOuterLexicalRecordContext(); + if (OutermostClass == PatternRD) { + Diag(Pattern->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) + << PatternRD << Pattern; + } else { + Diag(Pattern->getLocEnd(), + diag::err_in_class_initializer_not_yet_parsed_outer_class) + << PatternRD << OutermostClass << Pattern; + } + Instantiation->setInvalidDecl(); + return true; + } + + InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); + if (Inst.isInvalid()) + return true; + + // Enter the scope of this instantiation. We don't use PushDeclContext because + // we don't have a scope. + ContextRAII SavedContext(*this, Instantiation->getParent()); + EnterExpressionEvaluationContext EvalContext(*this, + Sema::PotentiallyEvaluated); + + LocalInstantiationScope Scope(*this); + + // Instantiate the initializer. + ActOnStartCXXInClassMemberInitializer(); + CXXThisScopeRAII ThisScope(*this, Instantiation->getParent(), /*TypeQuals=*/0); + + ExprResult NewInit = SubstInitializer(OldInit, TemplateArgs, + /*CXXDirectInit=*/false); + Expr *Init = NewInit.get(); + assert((!Init || !isa<ParenListExpr>(Init)) && "call-style init in class"); + ActOnFinishCXXInClassMemberInitializer( + Instantiation, Init ? Init->getLocStart() : SourceLocation(), Init); + + // Exit the scope of this instantiation. + SavedContext.pop(); + + // Return true if the in-class initializer is still missing. + return !Instantiation->getInClassInitializer(); +} + namespace { /// \brief A partial specialization whose template arguments have matched /// a given template-id. @@ -2458,7 +2555,10 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, // Always skip the injected-class-name, along with any // redeclarations of nested classes, since both would cause us // to try to instantiate the members of a class twice. - if (Record->isInjectedClassName() || Record->getPreviousDecl()) + // Skip closure types; they'll get instantiated when we instantiate + // the corresponding lambda-expression. + if (Record->isInjectedClassName() || Record->getPreviousDecl() || + Record->isLambda()) continue; MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo(); @@ -2541,6 +2641,19 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, MSInfo->setTemplateSpecializationKind(TSK); MSInfo->setPointOfInstantiation(PointOfInstantiation); } + } else if (auto *Field = dyn_cast<FieldDecl>(D)) { + // No need to instantiate in-class initializers during explicit + // instantiation. + if (Field->hasInClassInitializer() && TSK == TSK_ImplicitInstantiation) { + CXXRecordDecl *ClassPattern = + Instantiation->getTemplateInstantiationPattern(); + DeclContext::lookup_result Lookup = + ClassPattern->lookup(Field->getDeclName()); + assert(Lookup.size() == 1); + FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]); + InstantiateInClassInitializer(PointOfInstantiation, Field, Pattern, + TemplateArgs); + } } } } @@ -2649,8 +2762,7 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, return Instantiator.TransformTemplateArguments(Args, NumArgs, Result); } - -static const Decl* getCanonicalParmVarDecl(const Decl *D) { +static const Decl *getCanonicalParmVarDecl(const Decl *D) { // When storing ParmVarDecls in the local instantiation scope, we always // want to use the ParmVarDecl from the canonical function declaration, // since the map is then valid for any redeclaration or definition of that @@ -2658,7 +2770,10 @@ static const Decl* getCanonicalParmVarDecl(const Decl *D) { if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(D)) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { unsigned i = PV->getFunctionScopeIndex(); - return FD->getCanonicalDecl()->getParamDecl(i); + // This parameter might be from a freestanding function type within the + // function and isn't necessarily referring to one of FD's parameters. + if (FD->getParamDecl(i) == PV) + return FD->getCanonicalDecl()->getParamDecl(i); } } return D; @@ -2707,12 +2822,22 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; - if (Stored.isNull()) + if (Stored.isNull()) { +#ifndef NDEBUG + // It should not be present in any surrounding scope either. + LocalInstantiationScope *Current = this; + while (Current->CombineWithOuterScope && Current->Outer) { + Current = Current->Outer; + assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() && + "Instantiated local in inner and outer scopes"); + } +#endif Stored = Inst; - else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) + } else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) { Pack->push_back(Inst); - else + } else { assert(Stored.get<Decl *>() == Inst && "Already instantiated this local"); + } } void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, @@ -2723,9 +2848,16 @@ void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, } void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { +#ifndef NDEBUG + // This should be the first time we've been told about this decl. + for (LocalInstantiationScope *Current = this; + Current && Current->CombineWithOuterScope; Current = Current->Outer) + assert(Current->LocalDecls.find(D) == Current->LocalDecls.end() && + "Creating local pack after instantiation of local"); +#endif + D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; - assert(Stored.isNull() && "Already instantiated this local"); DeclArgumentPack *Pack = new DeclArgumentPack; Stored = Pack; ArgumentPacks.push_back(Pack); |