diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-11-12 02:00:47 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-11-12 02:00:47 +0000 |
commit | 7c4e87a58b75f91f69e505c44303982313cabbd9 (patch) | |
tree | c802eac706edbbef00879e10e84ed4c47cb1aad9 /lib/Sema/TreeTransform.h | |
parent | b6ff5628bec83cb58cdb9724584eeaf0a51fe81b (diff) |
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.
This is a re-commit of r219977:
r219977 was reverted in r220038 because it hit a wrong-code bug in GCC 4.7.2.
(That's gcc.gnu.org/PR56135, and affects any implicit lambda-capture of
'this' within a template.)
r219977 was a re-commit of r217995, r218011, and r218053:
r217995 was reverted in r218058 because it hit a rejects-valid bug in MSVC.
(Incorrect overload resolution in the presence of using-declarations.)
It was re-committed in r219977 with a workaround for the MSVC rejects-valid.
r218011 was a workaround for an MSVC parser bug. (Incorrect desugaring of
unbraced range-based for loop).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221750 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/TreeTransform.h')
-rw-r--r-- | lib/Sema/TreeTransform.h | 157 |
1 files changed, 140 insertions, 17 deletions
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 9ddb6d842f..ecbc0118bb 100644 --- a/lib/Sema/TreeTransform.h +++ b/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); @@ -4571,15 +4578,20 @@ 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, + // The explicit 'this' capture is a workaround for gcc.gnu.org/PR56135. + [&, this](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. @@ -4624,15 +4636,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(); } @@ -4649,6 +4667,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) { @@ -9032,9 +9151,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, + [&, this](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } |