diff options
Diffstat (limited to 'lib/Sema/TreeTransform.h')
-rw-r--r-- | lib/Sema/TreeTransform.h | 662 |
1 files changed, 528 insertions, 134 deletions
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 312811d2c008..36abbb624af7 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H -#define LLVM_CLANG_SEMA_TREETRANSFORM_H +#ifndef LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H +#define LLVM_CLANG_LIB_SEMA_TREETRANSFORM_H #include "TypeLocBuilder.h" #include "clang/AST/Decl.h" @@ -327,6 +327,27 @@ public: /// \returns the transformed OpenMP clause. OMPClause *TransformOMPClause(OMPClause *S); + /// \brief Transform the given attribute. + /// + /// By default, this routine transforms a statement by delegating to the + /// appropriate TransformXXXAttr function to transform a specific kind + /// of attribute. Subclasses may override this function to transform + /// attributed statements using some other mechanism. + /// + /// \returns the transformed attribute + const Attr *TransformAttr(const Attr *S); + +/// \brief Transform the specified attribute. +/// +/// Subclasses should override the transformation of attributes with a pragma +/// spelling to transform expressions stored within the attribute. +/// +/// \returns the transformed attribute. +#define ATTR(X) +#define PRAGMA_SPELLING_ATTR(X) \ + const X##Attr *Transform##X##Attr(const X##Attr *R) { return R; } +#include "clang/Basic/AttrList.inc" + /// \brief Transform the given expression. /// /// By default, this routine transforms an expression by delegating to the @@ -542,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); @@ -560,10 +588,9 @@ public: TemplateName Template, CXXScopeSpec &SS); - QualType - TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL, - NestedNameSpecifierLoc QualifierLoc); + QualType TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, + NestedNameSpecifierLoc QualifierLoc); /// \brief Transforms the parameters of a function type into the /// given vectors. @@ -1665,10 +1692,8 @@ public: } StmtResult RebuildSEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, - Stmt *TryBlock, Stmt *Handler, int HandlerIndex, - int HandlerParentIndex) { - return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler, - HandlerIndex, HandlerParentIndex); + Stmt *TryBlock, Stmt *Handler) { + return getSema().ActOnSEHTryBlock(IsCXXTry, TryLoc, TryBlock, Handler); } StmtResult RebuildSEHExceptStmt(SourceLocation Loc, Expr *FilterExpr, @@ -1680,6 +1705,15 @@ public: return getSema().ActOnSEHFinallyBlock(Loc, Block); } + /// \brief Build a new predefined expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildPredefinedExpr(SourceLocation Loc, + PredefinedExpr::IdentType IT) { + return getSema().BuildPredefinedExpr(Loc, IT); + } + /// \brief Build a new expression that references a declaration. /// /// By default, performs semantic analysis to build the new expression. @@ -2757,6 +2791,27 @@ public: return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); } + /// \brief Build a new C++1z fold-expression. + /// + /// By default, performs semantic analysis in order to build a new fold + /// expression. + ExprResult RebuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, + BinaryOperatorKind Operator, + SourceLocation EllipsisLoc, Expr *RHS, + SourceLocation RParenLoc) { + return getSema().BuildCXXFoldExpr(LParenLoc, LHS, Operator, EllipsisLoc, + RHS, RParenLoc); + } + + /// \brief Build an empty C++1z fold-expression with the given operator. + /// + /// By default, produces the fallback value for the fold-expression, or + /// produce an error if there is no fallback value. + ExprResult RebuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, + BinaryOperatorKind Operator) { + return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); + } + /// \brief Build a new atomic operation expression. /// /// By default, performs semantic analysis to build the new expression. @@ -3103,6 +3158,14 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc()); break; + case NestedNameSpecifier::Super: { + CXXRecordDecl *RD = + cast_or_null<CXXRecordDecl>(getDerived().TransformDecl( + SourceLocation(), QNNS->getAsRecordDecl())); + SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc()); + break; + } + case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, @@ -4515,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; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + return getDerived().TransformFunctionProtoType( + TLB, TL, nullptr, 0, + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->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. @@ -4568,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(); } @@ -4593,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) { @@ -5147,8 +5322,8 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, if (const TemplateSpecializationType *TST = NamedT->getAs<TemplateSpecializationType>()) { TemplateName Template = TST->getTemplateName(); - if (TypeAliasTemplateDecl *TAT = - dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + if (TypeAliasTemplateDecl *TAT = dyn_cast_or_null<TypeAliasTemplateDecl>( + Template.getAsTemplateDecl())) { SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), diag::err_tag_reference_non_tag) << 4; SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); @@ -5529,19 +5704,43 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { SubStmt.get()); } -template<typename Derived> -StmtResult -TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { +template <typename Derived> +const Attr *TreeTransform<Derived>::TransformAttr(const Attr *R) { + if (!R) + return R; + + switch (R->getKind()) { +// Transform attributes with a pragma spelling by calling TransformXXXAttr. +#define ATTR(X) +#define PRAGMA_SPELLING_ATTR(X) \ + case attr::X: \ + return getDerived().Transform##X##Attr(cast<X##Attr>(R)); +#include "clang/Basic/AttrList.inc" + default: + return R; + } +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { + bool AttrsChanged = false; + SmallVector<const Attr *, 1> Attrs; + + // Visit attributes and keep track if any are transformed. + for (const auto *I : S->getAttrs()) { + const Attr *R = getDerived().TransformAttr(I); + AttrsChanged |= (I != R); + Attrs.push_back(R); + } + StmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt()); if (SubStmt.isInvalid()) return StmtError(); - // TODO: transform attributes - if (SubStmt.get() == S->getSubStmt() /* && attrs are the same */) + if (SubStmt.get() == S->getSubStmt() && !AttrsChanged) return S; - return getDerived().RebuildAttributedStmt(S->getAttrLoc(), - S->getAttrs(), + return getDerived().RebuildAttributedStmt(S->getAttrLoc(), Attrs, SubStmt.get()); } @@ -5824,7 +6023,8 @@ TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) { template<typename Derived> StmtResult TreeTransform<Derived>::TransformReturnStmt(ReturnStmt *S) { - ExprResult Result = getDerived().TransformExpr(S->getRetValue()); + ExprResult Result = getDerived().TransformInitializer(S->getRetValue(), + /*NotCopyInit*/false); if (Result.isInvalid()) return StmtError(); @@ -6380,9 +6580,8 @@ StmtResult TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) { Handler.get() == S->getHandler()) return S; - return getDerived().RebuildSEHTryStmt( - S->getIsCXXTry(), S->getTryLoc(), TryBlock.get(), Handler.get(), - S->getHandlerIndex(), S->getHandlerParentIndex()); + return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(), S->getTryLoc(), + TryBlock.get(), Handler.get()); } template <typename Derived> @@ -6504,6 +6703,17 @@ TreeTransform<Derived>::TransformOMPForDirective(OMPForDirective *D) { template <typename Derived> StmtResult +TreeTransform<Derived>::TransformOMPForSimdDirective(OMPForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_for_simd, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPSectionsDirective(OMPSectionsDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_sections, DirName, nullptr, @@ -6568,6 +6778,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelForDirective( } template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPParallelForSimdDirective( + OMPParallelForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_for_simd, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> StmtResult TreeTransform<Derived>::TransformOMPParallelSectionsDirective( OMPParallelSectionsDirective *D) { DeclarationNameInfo DirName; @@ -6633,6 +6854,50 @@ TreeTransform<Derived>::TransformOMPFlushDirective(OMPFlushDirective *D) { return Res; } +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPOrderedDirective(OMPOrderedDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_ordered, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPAtomicDirective(OMPAtomicDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_atomic, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPTargetDirective(OMPTargetDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPTeamsDirective(OMPTeamsDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_teams, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// @@ -6740,6 +7005,39 @@ TreeTransform<Derived>::TransformOMPMergeableClause(OMPMergeableClause *C) { } template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPReadClause(OMPReadClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPWriteClause(OMPWriteClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPUpdateClause(OMPUpdateClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPCaptureClause(OMPCaptureClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPSeqCstClause(OMPSeqCstClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) { llvm::SmallVector<Expr *, 16> Vars; @@ -6912,7 +7210,11 @@ OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { - return E; + if (!E->isTypeDependent()) + return E; + + return getDerived().RebuildPredefinedExpr(E->getLocation(), + E->getIdentType()); } template<typename Derived> @@ -7161,6 +7463,12 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformTypoExpr(TypoExpr *E) { + return E; +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) { // Rebuild the syntactic form. The original syntactic form has // opaque-value expressions in it, so strip those away and rebuild @@ -7873,15 +8181,11 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { Type == E->getTypeInfoAsWritten() && SubExpr.get() == E->getSubExpr()) return E; - return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), - E->getStmtClass(), - E->getAngleBrackets().getBegin(), - Type, - E->getAngleBrackets().getEnd(), - // FIXME. this should be '(' location - E->getAngleBrackets().getEnd(), - SubExpr.get(), - E->getRParenLoc()); + return getDerived().RebuildCXXNamedCastExpr( + E->getOperatorLoc(), E->getStmtClass(), E->getAngleBrackets().getBegin(), + Type, E->getAngleBrackets().getEnd(), + // FIXME. this should be '(' location + E->getAngleBrackets().getEnd(), SubExpr.get(), E->getRParenLoc()); } template<typename Derived> @@ -8786,113 +9090,68 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( template<typename Derived> ExprResult TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { - - // Transform any init-capture expressions before entering the scope of the + // Transform any init-capture expressions before entering the scope of the // lambda body, because they are not semantically within that scope. SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes; InitCaptureExprsAndTypes.resize(E->explicit_capture_end() - E->explicit_capture_begin()); - for (LambdaExpr::capture_iterator C = E->capture_begin(), - CEnd = E->capture_end(); - C != CEnd; ++C) { + CEnd = E->capture_end(); + C != CEnd; ++C) { if (!C->isInitCapture()) continue; - EnterExpressionEvaluationContext EEEC(getSema(), - Sema::PotentiallyEvaluated); + EnterExpressionEvaluationContext EEEC(getSema(), + Sema::PotentiallyEvaluated); ExprResult NewExprInitResult = getDerived().TransformInitializer( C->getCapturedVar()->getInit(), C->getCapturedVar()->getInitStyle() == VarDecl::CallInit); - + if (NewExprInitResult.isInvalid()) return ExprError(); Expr *NewExprInit = NewExprInitResult.get(); - + VarDecl *OldVD = C->getCapturedVar(); - QualType NewInitCaptureType = - getSema().performLambdaInitCaptureInitialization(C->getLocation(), - OldVD->getType()->isReferenceType(), OldVD->getIdentifier(), + QualType NewInitCaptureType = + getSema().performLambdaInitCaptureInitialization(C->getLocation(), + OldVD->getType()->isReferenceType(), OldVD->getIdentifier(), NewExprInit); NewExprInitResult = NewExprInit; InitCaptureExprsAndTypes[C - E->capture_begin()] = std::make_pair(NewExprInitResult, NewInitCaptureType); - } LambdaScopeInfo *LSI = getSema().PushLambdaScope(); + Sema::FunctionScopeRAII FuncScopeCleanup(getSema()); + // Transform the template parameters, and add them to the current // instantiation scope. The null case is handled correctly. LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); - // Check to see if the TypeSourceInfo of the call operator needs to - // be transformed, and if so do the transformation in the - // CurrentInstantiationScope. - - TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); - FunctionProtoTypeLoc OldCallOpFPTL = - OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); + // Transform the type of the original lambda's call operator. + // The transformation MUST be done in the CurrentInstantiationScope since + // it introduces a mapping of the original to the newly created + // transformed parameters. TypeSourceInfo *NewCallOpTSI = nullptr; - - const bool CallOpWasAlreadyTransformed = - getDerived().AlreadyTransformed(OldCallOpTSI->getType()); - - // Use the Old Call Operator's TypeSourceInfo if it is already transformed. - if (CallOpWasAlreadyTransformed) - NewCallOpTSI = OldCallOpTSI; - else { - // Transform the TypeSourceInfo of the Original Lambda's Call Operator. - // The transformation MUST be done in the CurrentInstantiationScope since - // it introduces a mapping of the original to the newly created - // transformed parameters. + { + TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); + FunctionProtoTypeLoc OldCallOpFPTL = + OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); TypeLocBuilder NewCallOpTLBuilder; - QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder, - OldCallOpFPTL, - nullptr, 0); + SmallVector<QualType, 4> ExceptionStorage; + TreeTransform *This = this; // Work around gcc.gnu.org/PR56135. + QualType NewCallOpType = TransformFunctionProtoType( + NewCallOpTLBuilder, OldCallOpFPTL, nullptr, 0, + [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) { + return This->TransformExceptionSpec(OldCallOpFPTL.getBeginLoc(), ESI, + ExceptionStorage, Changed); + }); + if (NewCallOpType.isNull()) + return ExprError(); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } - // Extract the ParmVarDecls from the NewCallOpTSI and add them to - // the vector below - this will be used to synthesize the - // NewCallOperator. Additionally, add the parameters of the untransformed - // lambda call operator to the CurrentInstantiationScope. - SmallVector<ParmVarDecl *, 4> Params; - { - FunctionProtoTypeLoc NewCallOpFPTL = - NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>(); - ParmVarDecl **NewParamDeclArray = NewCallOpFPTL.getParmArray(); - const unsigned NewNumArgs = NewCallOpFPTL.getNumParams(); - - for (unsigned I = 0; I < NewNumArgs; ++I) { - // If this call operator's type does not require transformation, - // the parameters do not get added to the current instantiation scope, - // - so ADD them! This allows the following to compile when the enclosing - // template is specialized and the entire lambda expression has to be - // transformed. - // template<class T> void foo(T t) { - // auto L = [](auto a) { - // auto M = [](char b) { <-- note: non-generic lambda - // auto N = [](auto c) { - // int x = sizeof(a); - // x = sizeof(b); <-- specifically this line - // x = sizeof(c); - // }; - // }; - // }; - // } - // foo('a') - if (CallOpWasAlreadyTransformed) - getDerived().transformedLocalDecl(NewParamDeclArray[I], - NewParamDeclArray[I]); - // Add to Params array, so these parameters can be used to create - // the newly transformed call operator. - Params.push_back(NewParamDeclArray[I]); - } - } - - if (!NewCallOpTSI) - return ExprError(); // Create the local class that will describe the lambda. CXXRecordDecl *Class @@ -8900,19 +9159,21 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { NewCallOpTSI, /*KnownDependent=*/false, E->getCaptureDefault()); - getDerived().transformedLocalDecl(E->getLambdaClass(), Class); // Build the call operator. - CXXMethodDecl *NewCallOperator - = getSema().startLambdaDefinition(Class, E->getIntroducerRange(), - NewCallOpTSI, - E->getCallOperator()->getLocEnd(), - Params); + CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( + Class, E->getIntroducerRange(), NewCallOpTSI, + E->getCallOperator()->getLocEnd(), + NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams()); LSI->CallOperator = NewCallOperator; getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); + // TransformLambdaScope will manage the function scope, so we can disable the + // cleanup. + FuncScopeCleanup.disable(); + return getDerived().TransformLambdaScope(E, NewCallOperator, InitCaptureExprsAndTypes); } @@ -8954,6 +9215,10 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit()); continue; } + // Captured expression will be recaptured during captured variables + // rebuilding. + if (C->capturesVLAType()) + continue; // Rebuild init-captures, including the implied field declaration. if (C->isInitCapture()) { @@ -9033,7 +9298,7 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E, VarDecl *CapturedVar = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(), C->getCapturedVar())); - if (!CapturedVar) { + if (!CapturedVar || CapturedVar->isInvalidDecl()) { Invalid = true; continue; } @@ -9398,6 +9663,128 @@ TreeTransform<Derived>::TransformMaterializeTemporaryExpr( template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { + Expr *Pattern = E->getPattern(); + + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions; + if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(), + Pattern->getSourceRange(), + Unexpanded, + Expand, RetainExpansion, + NumExpansions)) + return true; + + if (!Expand) { + // Do not expand any packs here, just transform and rebuild a fold + // expression. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + + ExprResult LHS = + E->getLHS() ? getDerived().TransformExpr(E->getLHS()) : ExprResult(); + if (LHS.isInvalid()) + return true; + + ExprResult RHS = + E->getRHS() ? getDerived().TransformExpr(E->getRHS()) : ExprResult(); + if (RHS.isInvalid()) + return true; + + if (!getDerived().AlwaysRebuild() && + LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) + return E; + + return getDerived().RebuildCXXFoldExpr( + E->getLocStart(), LHS.get(), E->getOperator(), E->getEllipsisLoc(), + RHS.get(), E->getLocEnd()); + } + + // The transform has determined that we should perform an elementwise + // expansion of the pattern. Do so. + ExprResult Result = getDerived().TransformExpr(E->getInit()); + if (Result.isInvalid()) + return true; + bool LeftFold = E->isLeftFold(); + + // If we're retaining an expansion for a right fold, it is the innermost + // component and takes the init (if any). + if (!LeftFold && RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + Result = getDerived().RebuildCXXFoldExpr( + E->getLocStart(), Out.get(), E->getOperator(), E->getEllipsisLoc(), + Result.get(), E->getLocEnd()); + if (Result.isInvalid()) + return true; + } + + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex( + getSema(), LeftFold ? I : *NumExpansions - I - 1); + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + if (Out.get()->containsUnexpandedParameterPack()) { + // We still have a pack; retain a pack expansion for this slice. + Result = getDerived().RebuildCXXFoldExpr( + E->getLocStart(), + LeftFold ? Result.get() : Out.get(), + E->getOperator(), E->getEllipsisLoc(), + LeftFold ? Out.get() : Result.get(), + E->getLocEnd()); + } else if (Result.isUsable()) { + // We've got down to a single element; build a binary operator. + Result = getDerived().RebuildBinaryOperator( + E->getEllipsisLoc(), E->getOperator(), + LeftFold ? Result.get() : Out.get(), + LeftFold ? Out.get() : Result.get()); + } else + Result = Out; + + if (Result.isInvalid()) + return true; + } + + // If we're retaining an expansion for a left fold, it is the outermost + // component and takes the complete expansion so far as its init (if any). + if (LeftFold && RetainExpansion) { + ForgetPartiallySubstitutedPackRAII Forget(getDerived()); + + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + Result = getDerived().RebuildCXXFoldExpr( + E->getLocStart(), Result.get(), + E->getOperator(), E->getEllipsisLoc(), + Out.get(), E->getLocEnd()); + if (Result.isInvalid()) + return true; + } + + // If we had no init and an empty pack, and we're not retaining an expansion, + // then produce a fallback value or error. + if (Result.isUnset()) + return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(), + E->getOperator()); + + return Result; +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXStdInitializerListExpr( CXXStdInitializerListExpr *E) { return getDerived().TransformExpr(E->getSubExpr()); @@ -10292,7 +10679,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, SourceLocation RBrace; if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee)) { - DeclarationNameLoc &NameLoc = DRE->getNameInfo().getInfo(); + DeclarationNameLoc NameLoc = DRE->getNameInfo().getInfo(); LBrace = SourceLocation::getFromRawEncoding( NameLoc.CXXOperatorName.BeginOpNameLoc); RBrace = SourceLocation::getFromRawEncoding( @@ -10348,9 +10735,16 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, // The scope type is now known to be a valid nested name specifier // component. Tack it on to the end of the nested name specifier. - if (ScopeType) - SS.Extend(SemaRef.Context, SourceLocation(), - ScopeType->getTypeLoc(), CCLoc); + if (ScopeType) { + if (!ScopeType->getType()->getAs<TagType>()) { + getSema().Diag(ScopeType->getTypeLoc().getBeginLoc(), + diag::err_expected_class_or_namespace) + << ScopeType->getType() << getSema().getLangOpts().CPlusPlus; + return ExprError(); + } + SS.Extend(SemaRef.Context, SourceLocation(), ScopeType->getTypeLoc(), + CCLoc); + } SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. return getSema().BuildMemberReferenceExpr(Base, BaseType, @@ -10397,4 +10791,4 @@ TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) { } // end namespace clang -#endif // LLVM_CLANG_SEMA_TREETRANSFORM_H +#endif |