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.

llvm-svn: 372359
This commit is contained in:
Richard Smith 2019-09-19 22:00:16 +00:00
parent 0c3d4cfbad
commit 40c3d6e335
4 changed files with 64 additions and 42 deletions

View File

@ -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);
}

View File

@ -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<ImplicitCastExpr>(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<ExprWithCleanups>(Converted)) {
Expr *Inner =
const_cast<Expr *>(IgnoreNarrowingConversion(Ctx, EWC->getSubExpr()));
return ExprWithCleanups::Create(Ctx, Inner, EWC->cleanupsHaveSideEffects(),
EWC->getObjects());
}
while (auto *ICE = dyn_cast<ImplicitCastExpr>(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;

View File

@ -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();
if (getCurFunction()->SwitchStack.empty())
return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false,
getLangOpts().CPlusPlus11);
auto CheckAndFinish = [&](Expr *E) {
if (CondType->isDependentType() || E->isTypeDependent())
return ExprResult(E);
Expr *CondExpr =
getCurFunction()->SwitchStack.back().getPointer()->getCond();
if (!CondExpr)
return ExprError();
QualType CondType = CondExpr->getType();
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);
}
auto CheckAndFinish = [&](Expr *E) {
if (CondType->isDependentType() || E->isTypeDependent())
return ExprResult(E);
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;
};
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 Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish);
if (Converted.get() == Val.get())
Converted = CheckAndFinish(Val.get());
if (Converted.isInvalid())
return ExprError();
Val = Converted;
}
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

View File

@ -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<PackExpansionExpr>(Arg);
if (PE)