diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-10-16 23:00:46 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-10-16 23:00:46 +0000 |
commit | 9c04bce1f1b22feff652b40b0aab1d9ed278baf1 (patch) | |
tree | 823dea72315b07d4c27c6ede1631108c800e196a /clang/lib/Sema | |
parent | 82e3e373b3e0c4d8d47a60d3ee1f9b348d8cf413 (diff) | |
download | bcm5719-llvm-9c04bce1f1b22feff652b40b0aab1d9ed278baf1.tar.gz bcm5719-llvm-9c04bce1f1b22feff652b40b0aab1d9ed278baf1.zip |
Re-commit r217995 and follow-up patches (r217997, r218011, r218053). These were
reverted in r218058 because they triggered a rejects-valid bug in MSVC.
Original commit message from r217995:
Instantiate exception specifications when instantiating function types (other
than the type of a function declaration). We previously didn't instantiate
these at all! This also covers the pathological case where the only mention of
a parameter pack is within the exception specification; this gives us a second
way (other than alias templates) to reach the horrible state where a type
contains an unexpanded pack, but its canonical type does not.
llvm-svn: 219977
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 32 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 62 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 168 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 156 |
6 files changed, 255 insertions, 190 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ed15012a160..d1f337f5b99 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13168,13 +13168,12 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { return false; } -void -Sema::checkExceptionSpecification(ExceptionSpecificationType EST, - ArrayRef<ParsedType> DynamicExceptions, - ArrayRef<SourceRange> DynamicExceptionRanges, - Expr *NoexceptExpr, - SmallVectorImpl<QualType> &Exceptions, - FunctionProtoType::ExceptionSpecInfo &ESI) { +void Sema::checkExceptionSpecification( + bool IsTopLevel, ExceptionSpecificationType EST, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, Expr *NoexceptExpr, + SmallVectorImpl<QualType> &Exceptions, + FunctionProtoType::ExceptionSpecInfo &ESI) { Exceptions.clear(); ESI.Type = EST; if (EST == EST_Dynamic) { @@ -13183,13 +13182,15 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST, // FIXME: Preserve type source info. QualType ET = GetTypeFromParser(DynamicExceptions[ei]); - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - collectUnexpandedParameterPacks(ET, Unexpanded); - if (!Unexpanded.empty()) { - DiagnoseUnexpandedParameterPacks(DynamicExceptionRanges[ei].getBegin(), - UPPC_ExceptionType, - Unexpanded); - continue; + if (IsTopLevel) { + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(ET, Unexpanded); + if (!Unexpanded.empty()) { + DiagnoseUnexpandedParameterPacks( + DynamicExceptionRanges[ei].getBegin(), UPPC_ExceptionType, + Unexpanded); + continue; + } } // Check that the type is valid for an exception spec, and @@ -13208,7 +13209,8 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST, NoexceptExpr->getType()->getCanonicalTypeUnqualified() == Context.BoolTy) && "Parser should have made sure that the expression is boolean"); - if (NoexceptExpr && DiagnoseUnexpandedParameterPack(NoexceptExpr)) { + if (IsTopLevel && NoexceptExpr && + DiagnoseUnexpandedParameterPack(NoexceptExpr)) { ESI.Type = EST_BasicNoexcept; return; } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index e4963b13d64..4e4de5a3e7f 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -720,10 +720,11 @@ static bool CheckSpecForTypesEquivalent(Sema &S, /// assignment and override compatibility check. We do not check the parameters /// of parameter function pointers recursively, as no sane programmer would /// even be able to write such a function type. -bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, - const FunctionProtoType *Target, SourceLocation TargetLoc, - const FunctionProtoType *Source, SourceLocation SourceLoc) -{ +bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID, + const FunctionProtoType *Target, + SourceLocation TargetLoc, + const FunctionProtoType *Source, + SourceLocation SourceLoc) { if (CheckSpecForTypesEquivalent( *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(), Target->getReturnType(), TargetLoc, Source->getReturnType(), @@ -744,23 +745,30 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, return false; } -bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) -{ +bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { // First we check for applicability. // Target type must be a function, function pointer or function reference. const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); - if (!ToFunc) + if (!ToFunc || ToFunc->hasDependentExceptionSpec()) return false; // SourceType must be a function or function pointer. const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); - if (!FromFunc) + if (!FromFunc || FromFunc->hasDependentExceptionSpec()) return false; // Now we've got the correct types on both sides, check their compatibility. // This means that the source of the conversion can only throw a subset of // the exceptions of the target, and any exception specs on arguments or // return types must be equivalent. + // + // FIXME: If there is a nested dependent exception specification, we should + // not be checking it here. This is fine: + // template<typename T> void f() { + // void (*p)(void (*) throw(T)); + // void (*q)(void (*) throw(int)) = p; + // } + // ... because it might be instantiated with T=int. return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), PDiag(), ToFunc, From->getSourceRange().getBegin(), diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 9c1ffb0c654..a9aae009401 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -791,11 +791,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, @@ -1327,21 +1333,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 * @@ -1576,7 +1577,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, @@ -1599,9 +1601,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); } @@ -1611,6 +1621,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, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index ec8c08ddf53..cc2460c617a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3056,7 +3056,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, /// Introduce the instantiated function parameters into the local /// instantiation scope, and set the parameter names to those used /// in the template. -static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, +static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, const FunctionDecl *PatternDecl, LocalInstantiationScope &Scope, const MultiLevelTemplateArgumentList &TemplateArgs) { @@ -3067,15 +3067,22 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, // Simple case: not a parameter pack. assert(FParamIdx < Function->getNumParams()); ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); + FunctionParam->setDeclName(PatternParam->getDeclName()); // If the parameter's type is not dependent, update it to match the type // in the pattern. They can differ in top-level cv-qualifiers, and we want // the pattern's type here. If the type is dependent, they can't differ, - // per core issue 1668. + // per core issue 1668. Substitute into the type from the pattern, in case + // it's instantiation-dependent. // FIXME: Updating the type to work around this is at best fragile. - if (!PatternDecl->getType()->isDependentType()) - FunctionParam->setType(PatternParam->getType()); + if (!PatternDecl->getType()->isDependentType()) { + QualType T = S.SubstType(PatternParam->getType(), TemplateArgs, + FunctionParam->getLocation(), + FunctionParam->getDeclName()); + if (T.isNull()) + return true; + FunctionParam->setType(T); + } - FunctionParam->setDeclName(PatternParam->getDeclName()); Scope.InstantiatedLocal(PatternParam, FunctionParam); ++FParamIdx; continue; @@ -3087,136 +3094,27 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, = S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); assert(NumArgumentsInExpansion && "should only be called when all template arguments are known"); + QualType PatternType = + PatternParam->getType()->castAs<PackExpansionType>()->getPattern(); for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) { ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx); - if (!PatternDecl->getType()->isDependentType()) - FunctionParam->setType(PatternParam->getType()); - FunctionParam->setDeclName(PatternParam->getDeclName()); - Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); - ++FParamIdx; - } - } -} - -static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New, - const FunctionProtoType *Proto, - const MultiLevelTemplateArgumentList &TemplateArgs) { - assert(Proto->getExceptionSpecType() != EST_Uninstantiated); - - // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type - // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or - // declarator. - CXXRecordDecl *ThisContext = nullptr; - unsigned ThisTypeQuals = 0; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(New)) { - ThisContext = Method->getParent(); - ThisTypeQuals = Method->getTypeQualifiers(); - } - Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals, - SemaRef.getLangOpts().CPlusPlus11); - - // The function has an exception specification or a "noreturn" - // attribute. Substitute into each of the exception types. - SmallVector<QualType, 4> Exceptions; - for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { - // FIXME: Poor location information! - if (const PackExpansionType *PackExpansion - = Proto->getExceptionType(I)->getAs<PackExpansionType>()) { - // We have a pack expansion. Instantiate it. - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), - Unexpanded); - assert(!Unexpanded.empty() && - "Pack expansion without parameter packs?"); - - bool Expand = false; - bool RetainExpansion = false; - Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); - if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), - SourceRange(), - Unexpanded, - TemplateArgs, - Expand, - RetainExpansion, - NumExpansions)) - break; - - if (!Expand) { - // We can't expand this pack expansion into separate arguments yet; - // just substitute into the pattern and create a new pack expansion - // type. - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); + if (!PatternDecl->getType()->isDependentType()) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, Arg); + QualType T = S.SubstType(PatternType, TemplateArgs, + FunctionParam->getLocation(), + FunctionParam->getDeclName()); if (T.isNull()) - break; - - T = SemaRef.Context.getPackExpansionType(T, NumExpansions); - Exceptions.push_back(T); - continue; - } - - // Substitute into the pack expansion pattern for each template - bool Invalid = false; - for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); - - QualType T = SemaRef.SubstType(PackExpansion->getPattern(), - TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull()) { - Invalid = true; - break; - } - - Exceptions.push_back(T); + return true; + FunctionParam->setType(T); } - if (Invalid) - break; - - continue; - } - - QualType T - = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, - New->getLocation(), New->getDeclName()); - if (T.isNull() || - SemaRef.CheckSpecifiedExceptionType(T, New->getLocation())) - continue; - - Exceptions.push_back(T); - } - Expr *NoexceptExpr = nullptr; - if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { - EnterExpressionEvaluationContext Unevaluated(SemaRef, - Sema::ConstantEvaluated); - ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); - if (E.isUsable()) - E = SemaRef.CheckBooleanCondition(E.get(), E.get()->getLocStart()); - - if (E.isUsable()) { - NoexceptExpr = E.get(); - if (!NoexceptExpr->isTypeDependent() && - !NoexceptExpr->isValueDependent()) - NoexceptExpr - = SemaRef.VerifyIntegerConstantExpression(NoexceptExpr, - nullptr, diag::err_noexcept_needs_constant_expression, - /*AllowFold*/ false).get(); + Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam); + ++FParamIdx; } } - FunctionProtoType::ExceptionSpecInfo ESI; - ESI.Type = Proto->getExceptionSpecType(); - ESI.Exceptions = Exceptions; - ESI.NoexceptExpr = NoexceptExpr; - - SemaRef.UpdateExceptionSpec(New, ESI); + return false; } void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, @@ -3243,11 +3141,14 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); FunctionDecl *Template = Proto->getExceptionSpecTemplate(); - addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs); + if (addInstantiatedParametersToScope(*this, Decl, Template, Scope, + TemplateArgs)) { + UpdateExceptionSpec(Decl, EST_None); + return; + } - ::InstantiateExceptionSpec(*this, Decl, - Template->getType()->castAs<FunctionProtoType>(), - TemplateArgs); + SubstExceptionSpec(Decl, Template->getType()->castAs<FunctionProtoType>(), + TemplateArgs); } /// \brief Initializes the common fields of an instantiation function @@ -3316,7 +3217,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, New->setType(SemaRef.Context.getFunctionType( NewProto->getReturnType(), NewProto->getParamTypes(), EPI)); } else { - ::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs); + SemaRef.SubstExceptionSpec(New, Proto, TemplateArgs); } } @@ -3506,8 +3407,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); - addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, - TemplateArgs); + if (addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope, + TemplateArgs)) + return; // If this is a constructor, instantiate the member initializers. if (const CXXConstructorDecl *Ctor = diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3ce9489fdd2..f395e10caa0 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2989,7 +2989,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, NoexceptExpr = FTI.NoexceptExpr; } - S.checkExceptionSpecification(FTI.getExceptionSpecType(), + S.checkExceptionSpecification(D.isFunctionDeclarationContext(), + FTI.getExceptionSpecType(), DynamicExceptions, DynamicExceptionRanges, NoexceptExpr, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 28890f59ce2..75783f29e64 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -563,10 +563,17 @@ public: QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + template<typename Fn> QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals); + unsigned ThisTypeQuals, + Fn TransformExceptionSpec); + + bool TransformExceptionSpec(SourceLocation Loc, + FunctionProtoType::ExceptionSpecInfo &ESI, + SmallVectorImpl<QualType> &Exceptions, + bool &Changed); StmtResult TransformSEHHandler(Stmt *Handler); @@ -4550,15 +4557,19 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { - return getDerived().TransformFunctionProtoType(TLB, TL, nullptr, 0); -} - -template<typename Derived> -QualType -TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - CXXRecordDecl *ThisContext, - unsigned ThisTypeQuals) { + SmallVector<QualType, 4> ExceptionStorage; + return getDerived().TransformFunctionProtoType( + TLB, TL, nullptr, 0, + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return TransformExceptionSpec(TL.getBeginLoc(), ESI, ExceptionStorage, + Changed); + }); +} + +template<typename Derived> template<typename Fn> +QualType TreeTransform<Derived>::TransformFunctionProtoType( + TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals, Fn TransformExceptionSpec) { // Transform the parameters and return type. // // We are required to instantiate the params and return type in source order. @@ -4603,15 +4614,21 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, return QualType(); } - // FIXME: Need to transform the exception-specification too. + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + + bool EPIChanged = false; + if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged)) + return QualType(); + + // FIXME: Need to transform ConsumedParameters for variadic template + // expansion. QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() || T->getNumParams() != ParamTypes.size() || !std::equal(T->param_type_begin(), T->param_type_end(), - ParamTypes.begin())) { - Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, - T->getExtProtoInfo()); + ParamTypes.begin()) || EPIChanged) { + Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI); if (Result.isNull()) return QualType(); } @@ -4628,6 +4645,107 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, } template<typename Derived> +bool TreeTransform<Derived>::TransformExceptionSpec( + SourceLocation Loc, FunctionProtoType::ExceptionSpecInfo &ESI, + SmallVectorImpl<QualType> &Exceptions, bool &Changed) { + assert(ESI.Type != EST_Uninstantiated && ESI.Type != EST_Unevaluated); + + // Instantiate a dynamic noexcept expression, if any. + if (ESI.Type == EST_ComputedNoexcept) { + EnterExpressionEvaluationContext Unevaluated(getSema(), + Sema::ConstantEvaluated); + ExprResult NoexceptExpr = getDerived().TransformExpr(ESI.NoexceptExpr); + if (NoexceptExpr.isInvalid()) + return true; + + NoexceptExpr = getSema().CheckBooleanCondition( + NoexceptExpr.get(), NoexceptExpr.get()->getLocStart()); + if (NoexceptExpr.isInvalid()) + return true; + + if (!NoexceptExpr.get()->isValueDependent()) { + NoexceptExpr = getSema().VerifyIntegerConstantExpression( + NoexceptExpr.get(), nullptr, + diag::err_noexcept_needs_constant_expression, + /*AllowFold*/false); + if (NoexceptExpr.isInvalid()) + return true; + } + + if (ESI.NoexceptExpr != NoexceptExpr.get()) + Changed = true; + ESI.NoexceptExpr = NoexceptExpr.get(); + } + + if (ESI.Type != EST_Dynamic) + return false; + + // Instantiate a dynamic exception specification's type. + for (QualType T : ESI.Exceptions) { + if (const PackExpansionType *PackExpansion = + T->getAs<PackExpansionType>()) { + Changed = true; + + // We have a pack expansion. Instantiate it. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and + // should + // be expanded. + bool Expand = false; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); + // FIXME: Track the location of the ellipsis (and track source location + // information for the types in the exception specification in general). + if (getDerived().TryExpandParameterPacks( + Loc, SourceRange(), Unexpanded, Expand, + RetainExpansion, NumExpansions)) + return true; + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the pattern and create a new pack expansion + // type. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + QualType U = getDerived().TransformType(PackExpansion->getPattern()); + if (U.isNull()) + return true; + + U = SemaRef.Context.getPackExpansionType(U, NumExpansions); + Exceptions.push_back(U); + continue; + } + + // Substitute into the pack expansion pattern for each slice of the + // pack. + for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx); + + QualType U = getDerived().TransformType(PackExpansion->getPattern()); + if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) + return true; + + Exceptions.push_back(U); + } + } else { + QualType U = getDerived().TransformType(T); + if (U.isNull() || SemaRef.CheckSpecifiedExceptionType(U, Loc)) + return true; + if (T != U) + Changed = true; + + Exceptions.push_back(U); + } + } + + ESI.Exceptions = Exceptions; + return false; +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformFunctionNoProtoType( TypeLocBuilder &TLB, FunctionNoProtoTypeLoc TL) { @@ -9005,9 +9123,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // transformed parameters. TypeLocBuilder NewCallOpTLBuilder; - QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder, - OldCallOpFPTL, - nullptr, 0); + SmallVector<QualType, 4> ExceptionStorage; + QualType NewCallOpType = TransformFunctionProtoType( + NewCallOpTLBuilder, OldCallOpFPTL, nullptr, 0, + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } |