summaryrefslogtreecommitdiff
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp90
1 files changed, 49 insertions, 41 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index ab964e592de8..fa4e10e84de0 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5761,8 +5761,12 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(),
FS->getCond(), Continue))
return ESR_Failed;
- if (!Continue)
+
+ if (!Continue) {
+ if (!IterScope.destroy())
+ return ESR_Failed;
break;
+ }
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody());
if (ESR != ESR_Continue) {
@@ -6549,8 +6553,8 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
}
static bool EvaluateCallArg(const ParmVarDecl *PVD, const Expr *Arg,
- CallRef Call, EvalInfo &Info,
- bool NonNull = false) {
+ CallRef Call, EvalInfo &Info, bool NonNull = false,
+ APValue **EvaluatedArg = nullptr) {
LValue LV;
// Create the parameter slot and register its destruction. For a vararg
// argument, create a temporary.
@@ -6570,13 +6574,17 @@ static bool EvaluateCallArg(const ParmVarDecl *PVD, const Expr *Arg,
return false;
}
+ if (EvaluatedArg)
+ *EvaluatedArg = &V;
+
return true;
}
/// Evaluate the arguments to a function call.
static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call,
EvalInfo &Info, const FunctionDecl *Callee,
- bool RightToLeft = false) {
+ bool RightToLeft = false,
+ LValue *ObjectArg = nullptr) {
bool Success = true;
llvm::SmallBitVector ForbiddenNullArgs;
if (Callee->hasAttr<NonNullAttr>()) {
@@ -6599,13 +6607,16 @@ static bool EvaluateArgs(ArrayRef<const Expr *> Args, CallRef Call,
const ParmVarDecl *PVD =
Idx < Callee->getNumParams() ? Callee->getParamDecl(Idx) : nullptr;
bool NonNull = !ForbiddenNullArgs.empty() && ForbiddenNullArgs[Idx];
- if (!EvaluateCallArg(PVD, Args[Idx], Call, Info, NonNull)) {
+ APValue *That = nullptr;
+ if (!EvaluateCallArg(PVD, Args[Idx], Call, Info, NonNull, &That)) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.noteFailure())
return false;
Success = false;
}
+ if (PVD && PVD->isExplicitObjectParameter() && That && That->isLValue())
+ ObjectArg->setFrom(Info.Ctx, *That);
}
return Success;
}
@@ -6633,14 +6644,15 @@ static bool handleTrivialCopy(EvalInfo &Info, const ParmVarDecl *Param,
/// Evaluate a function call.
static bool HandleFunctionCall(SourceLocation CallLoc,
- const FunctionDecl *Callee, const LValue *This,
- const Expr *E, ArrayRef<const Expr *> Args,
- CallRef Call, const Stmt *Body, EvalInfo &Info,
+ const FunctionDecl *Callee,
+ const LValue *ObjectArg, const Expr *E,
+ ArrayRef<const Expr *> Args, CallRef Call,
+ const Stmt *Body, EvalInfo &Info,
APValue &Result, const LValue *ResultSlot) {
if (!Info.CheckCallLimit(CallLoc))
return false;
- CallStackFrame Frame(Info, E->getSourceRange(), Callee, This, E, Call);
+ CallStackFrame Frame(Info, E->getSourceRange(), Callee, ObjectArg, E, Call);
// For a trivial copy or move assignment, perform an APValue copy. This is
// essential for unions, where the operations performed by the assignment
@@ -6653,16 +6665,20 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
(MD->getParent()->isUnion() ||
(MD->isTrivial() &&
isReadByLvalueToRvalueConversion(MD->getParent())))) {
- assert(This &&
+ unsigned ExplicitOffset = MD->isExplicitObjectMemberFunction() ? 1 : 0;
+ assert(ObjectArg &&
(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
APValue RHSValue;
if (!handleTrivialCopy(Info, MD->getParamDecl(0), Args[0], RHSValue,
MD->getParent()->isUnion()))
return false;
- if (!handleAssignment(Info, Args[0], *This, MD->getThisType(),
+
+ LValue Obj;
+ if (!handleAssignment(Info, Args[ExplicitOffset], *ObjectArg,
+ MD->getFunctionObjectParameterReferenceType(),
RHSValue))
return false;
- This->moveInto(Result);
+ ObjectArg->moveInto(Result);
return true;
} else if (MD && isLambdaCallOperator(MD)) {
// We're in a lambda; determine the lambda capture field maps unless we're
@@ -8289,7 +8305,7 @@ public:
QualType CalleeType = Callee->getType();
const FunctionDecl *FD = nullptr;
- LValue *This = nullptr, ThisVal;
+ LValue *This = nullptr, ObjectArg;
auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
@@ -8300,28 +8316,28 @@ public:
const CXXMethodDecl *Member = nullptr;
if (const MemberExpr *ME = dyn_cast<MemberExpr>(Callee)) {
// Explicit bound member calls, such as x.f() or p->g();
- if (!EvaluateObjectArgument(Info, ME->getBase(), ThisVal))
+ if (!EvaluateObjectArgument(Info, ME->getBase(), ObjectArg))
return false;
Member = dyn_cast<CXXMethodDecl>(ME->getMemberDecl());
if (!Member)
return Error(Callee);
- This = &ThisVal;
+ This = &ObjectArg;
HasQualifier = ME->hasQualifier();
} else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
// Indirect bound member calls ('.*' or '->*').
const ValueDecl *D =
- HandleMemberPointerAccess(Info, BE, ThisVal, false);
+ HandleMemberPointerAccess(Info, BE, ObjectArg, false);
if (!D)
return false;
Member = dyn_cast<CXXMethodDecl>(D);
if (!Member)
return Error(Callee);
- This = &ThisVal;
+ This = &ObjectArg;
} else if (const auto *PDE = dyn_cast<CXXPseudoDestructorExpr>(Callee)) {
if (!Info.getLangOpts().CPlusPlus20)
Info.CCEDiag(PDE, diag::note_constexpr_pseudo_destructor);
- return EvaluateObjectArgument(Info, PDE->getBase(), ThisVal) &&
- HandleDestruction(Info, PDE, ThisVal, PDE->getDestroyedType());
+ return EvaluateObjectArgument(Info, PDE->getBase(), ObjectArg) &&
+ HandleDestruction(Info, PDE, ObjectArg, PDE->getDestroyedType());
} else
return Error(Callee);
FD = Member;
@@ -8358,7 +8374,7 @@ public:
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
HasThis = MD->isImplicitObjectMemberFunction();
if (!EvaluateArgs(HasThis ? Args.slice(1) : Args, Call, Info, FD,
- /*RightToLeft=*/true))
+ /*RightToLeft=*/true, &ObjectArg))
return false;
}
@@ -8373,20 +8389,20 @@ public:
if (Args.empty())
return Error(E);
- if (!EvaluateObjectArgument(Info, Args[0], ThisVal))
+ if (!EvaluateObjectArgument(Info, Args[0], ObjectArg))
return false;
// If we are calling a static operator, the 'this' argument needs to be
// ignored after being evaluated.
if (MD->isInstance())
- This = &ThisVal;
+ This = &ObjectArg;
// If this is syntactically a simple assignment using a trivial
// assignment operator, start the lifetimes of union members as needed,
// per C++20 [class.union]5.
if (Info.getLangOpts().CPlusPlus20 && OCE &&
OCE->getOperator() == OO_Equal && MD->isTrivial() &&
- !MaybeHandleUnionActiveMemberChange(Info, Args[0], ThisVal))
+ !MaybeHandleUnionActiveMemberChange(Info, Args[0], ObjectArg))
return false;
Args = Args.slice(1);
@@ -8441,7 +8457,8 @@ public:
// Evaluate the arguments now if we've not already done so.
if (!Call) {
Call = Info.CurrentCall->createCall(FD);
- if (!EvaluateArgs(Args, Call, Info, FD))
+ if (!EvaluateArgs(Args, Call, Info, FD, /*RightToLeft*/ false,
+ &ObjectArg))
return false;
}
@@ -8475,6 +8492,11 @@ public:
Stmt *Body = FD->getBody(Definition);
SourceLocation Loc = E->getExprLoc();
+ // Treat the object argument as `this` when evaluating defaulted
+ // special menmber functions
+ if (FD->hasCXXExplicitFunctionObjectParameter())
+ This = &ObjectArg;
+
if (!CheckConstexprFunction(Info, Loc, FD, Definition, Body) ||
!HandleFunctionCall(Loc, Definition, This, E, Args, Call, Body, Info,
Result, ResultSlot))
@@ -15223,21 +15245,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType);
}
- if (Info.Ctx.getLangOpts().CPlusPlus && Info.InConstantContext &&
- Info.EvalMode == EvalInfo::EM_ConstantExpression &&
- DestType->isEnumeralType()) {
-
- bool ConstexprVar = true;
-
- // We know if we are here that we are in a context that we might require
- // a constant expression or a context that requires a constant
- // value. But if we are initializing a value we don't know if it is a
- // constexpr variable or not. We can check the EvaluatingDecl to determine
- // if it constexpr or not. If not then we don't want to emit a diagnostic.
- if (const auto *VD = dyn_cast_or_null<VarDecl>(
- Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()))
- ConstexprVar = VD->isConstexpr();
-
+ if (Info.Ctx.getLangOpts().CPlusPlus && DestType->isEnumeralType()) {
const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType());
const EnumDecl *ED = ET->getDecl();
// Check that the value is within the range of the enumeration values.
@@ -15257,13 +15265,13 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
ED->getValueRange(Max, Min);
--Max;
- if (ED->getNumNegativeBits() && ConstexprVar &&
+ if (ED->getNumNegativeBits() &&
(Max.slt(Result.getInt().getSExtValue()) ||
Min.sgt(Result.getInt().getSExtValue())))
Info.CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range)
<< llvm::toString(Result.getInt(), 10) << Min.getSExtValue()
<< Max.getSExtValue() << ED;
- else if (!ED->getNumNegativeBits() && ConstexprVar &&
+ else if (!ED->getNumNegativeBits() &&
Max.ult(Result.getInt().getZExtValue()))
Info.CCEDiag(E, diag::note_constexpr_unscoped_enum_out_of_range)
<< llvm::toString(Result.getInt(), 10) << Min.getZExtValue()