From 9e4451359e49b07daff391ed20fbf47b63df9bf2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 19 Sep 2019 22:00:16 +0000 Subject: [PATCH] Model converted constant expressions as full-expressions. This is groundwork for C++20's P0784R7, where non-trivial destructors can be constexpr, so we need ExprWithCleanups markers in constant expressions. No functionality change intended. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@372359 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Parse/ParseDecl.cpp | 4 ++- lib/Sema/SemaOverload.cpp | 28 ++++++++++++--- lib/Sema/SemaStmt.cpp | 71 +++++++++++++++++++-------------------- lib/Sema/SemaTemplate.cpp | 7 ++-- 4 files changed, 66 insertions(+), 44 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 14cbd0cd54..942c520a0b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -4678,8 +4678,10 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { ExprResult AssignedVal; EnumAvailabilityDiags.emplace_back(*this); + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); if (TryConsumeToken(tok::equal, EqualLoc)) { - AssignedVal = ParseConstantExpression(); + AssignedVal = ParseConstantExpressionInExprEvalContext(); if (AssignedVal.isInvalid()) SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6887cdd7ee..b8e1d2c035 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -257,8 +257,18 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { /// Skip any implicit casts which could be either part of a narrowing conversion /// or after one in an implicit conversion. -static const Expr *IgnoreNarrowingConversion(const Expr *Converted) { - while (const ImplicitCastExpr *ICE = dyn_cast(Converted)) { +static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx, + const Expr *Converted) { + // We can have cleanups wrapping the converted expression; these need to be + // preserved so that destructors run if necessary. + if (auto *EWC = dyn_cast(Converted)) { + Expr *Inner = + const_cast(IgnoreNarrowingConversion(Ctx, EWC->getSubExpr())); + return ExprWithCleanups::Create(Ctx, Inner, EWC->cleanupsHaveSideEffects(), + EWC->getObjects()); + } + + while (auto *ICE = dyn_cast(Converted)) { switch (ICE->getCastKind()) { case CK_NoOp: case CK_IntegralCast: @@ -332,7 +342,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (IgnoreFloatToIntegralConversion) return NK_Not_Narrowing; llvm::APSInt IntConstantValue; - const Expr *Initializer = IgnoreNarrowingConversion(Converted); + const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); assert(Initializer && "Unknown conversion expression"); // If it's value-dependent, we can't tell whether it's narrowing. @@ -370,7 +380,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (FromType->isRealFloatingType() && ToType->isRealFloatingType() && Ctx.getFloatingTypeOrder(FromType, ToType) == 1) { // FromType is larger than ToType. - const Expr *Initializer = IgnoreNarrowingConversion(Converted); + const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); // If it's value-dependent, we can't tell whether it's narrowing. if (Initializer->isValueDependent()) @@ -416,7 +426,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( (FromSigned && !ToSigned)) { // Not all values of FromType can be represented in ToType. llvm::APSInt InitializerValue; - const Expr *Initializer = IgnoreNarrowingConversion(Converted); + const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted); // If it's value-dependent, we can't tell whether it's narrowing. if (Initializer->isValueDependent()) @@ -5465,6 +5475,14 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, if (Result.isInvalid()) return Result; + // C++2a [intro.execution]p5: + // A full-expression is [...] a constant-expression [...] + Result = + S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(), + /*DiscardedValue=*/false, /*IsConstexpr=*/true); + if (Result.isInvalid()) + return Result; + // Check for a narrowing implicit conversion. APValue PreNarrowingValue; QualType PreNarrowingType; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index b963288dab..fdc85f24ec 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -430,45 +430,44 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) { // If we're not inside a switch, let the 'case' statement handling diagnose // this. Just clean up after the expression as best we can. - if (!getCurFunction()->SwitchStack.empty()) { - Expr *CondExpr = - getCurFunction()->SwitchStack.back().getPointer()->getCond(); - if (!CondExpr) - return ExprError(); - QualType CondType = CondExpr->getType(); - - auto CheckAndFinish = [&](Expr *E) { - if (CondType->isDependentType() || E->isTypeDependent()) - return ExprResult(E); - - if (getLangOpts().CPlusPlus11) { - // C++11 [stmt.switch]p2: the constant-expression shall be a converted - // constant expression of the promoted type of the switch condition. - llvm::APSInt TempVal; - return CheckConvertedConstantExpression(E, CondType, TempVal, - CCEK_CaseValue); - } + if (getCurFunction()->SwitchStack.empty()) + return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false, + getLangOpts().CPlusPlus11); - ExprResult ER = E; - if (!E->isValueDependent()) - ER = VerifyIntegerConstantExpression(E); - if (!ER.isInvalid()) - ER = DefaultLvalueConversion(ER.get()); - if (!ER.isInvalid()) - ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast); - return ER; - }; + Expr *CondExpr = + getCurFunction()->SwitchStack.back().getPointer()->getCond(); + if (!CondExpr) + return ExprError(); + QualType CondType = CondExpr->getType(); - ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish); - if (Converted.get() == Val.get()) - Converted = CheckAndFinish(Val.get()); - if (Converted.isInvalid()) - return ExprError(); - Val = Converted; - } + auto CheckAndFinish = [&](Expr *E) { + if (CondType->isDependentType() || E->isTypeDependent()) + return ExprResult(E); + + if (getLangOpts().CPlusPlus11) { + // C++11 [stmt.switch]p2: the constant-expression shall be a converted + // constant expression of the promoted type of the switch condition. + llvm::APSInt TempVal; + return CheckConvertedConstantExpression(E, CondType, TempVal, + CCEK_CaseValue); + } + + ExprResult ER = E; + if (!E->isValueDependent()) + ER = VerifyIntegerConstantExpression(E); + if (!ER.isInvalid()) + ER = DefaultLvalueConversion(ER.get()); + if (!ER.isInvalid()) + ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast); + if (!ER.isInvalid()) + ER = ActOnFinishFullExpr(ER.get(), ER.get()->getExprLoc(), false); + return ER; + }; - return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false, - getLangOpts().CPlusPlus11); + ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish); + if (Converted.get() == Val.get()) + Converted = CheckAndFinish(Val.get()); + return Converted; } StmtResult diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 91466fa904..5633582d67 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -6431,8 +6431,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } // If either the parameter has a dependent type or the argument is - // type-dependent, there's nothing we can check now. - if (ParamType->isDependentType() || Arg->isTypeDependent()) { + // type-dependent, there's nothing we can check now. The argument only + // contains an unexpanded pack during partial ordering, and there's + // nothing more we can check in that case. + if (ParamType->isDependentType() || Arg->isTypeDependent() || + Arg->containsUnexpandedParameterPack()) { // Force the argument to the type of the parameter to maintain invariants. auto *PE = dyn_cast(Arg); if (PE) -- 2.40.0