diff options
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 90 |
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() |
