Author: Timm Baeder Date: 2026-02-09T13:37:14+01:00 New Revision: 4344268ad605a3b77d00a30fb9284f453b240ec0
URL: https://github.com/llvm/llvm-project/commit/4344268ad605a3b77d00a30fb9284f453b240ec0 DIFF: https://github.com/llvm/llvm-project/commit/4344268ad605a3b77d00a30fb9284f453b240ec0.diff LOG: [clang] Return std::optional from all Expr::tryEvaluate* API (#179230) tryEvaluateString was returning an std::optional, but the other try* API was not. Update tryEvaluateObjectSize and tryEvaluateStrLen to return an std::optional<uint64_t>. Added: Modified: clang/include/clang/AST/Expr.h clang/lib/AST/ByteCode/Context.cpp clang/lib/AST/ByteCode/Context.h clang/lib/AST/ExprConstant.cpp clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp clang/lib/CodeGen/CGBuiltin.cpp clang/lib/Sema/SemaChecking.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 697dc73c46c2d..873ddb38e832a 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -777,14 +777,14 @@ class Expr : public ValueStmt { /// /// \param Type - How to evaluate the size of the Expr, as defined by the /// "type" parameter of __builtin_object_size - bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, - unsigned Type) const; + std::optional<uint64_t> tryEvaluateObjectSize(const ASTContext &Ctx, + unsigned Type) const; /// If the current Expr is a pointer, this will try to statically /// determine the strlen of the string pointed to. /// Returns true if all of the above holds and we were able to figure out the /// strlen, false otherwise. - bool tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const; + std::optional<uint64_t> tryEvaluateStrLen(const ASTContext &Ctx) const; bool EvaluateCharRangeAsString(std::string &Result, const Expr *SizeExpression, diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 3dc36ce1a5204..b4b8939f3fe00 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -285,10 +285,11 @@ bool Context::evaluateString(State &Parent, const Expr *E, return true; } -bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) { +std::optional<uint64_t> Context::evaluateStrlen(State &Parent, const Expr *E) { assert(Stk.empty()); Compiler<EvalEmitter> C(*this, *P, Parent, Stk); + std::optional<uint64_t> Result; auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) { const Descriptor *FieldDesc = Ptr.getFieldDesc(); if (!FieldDesc->isPrimitiveArray()) @@ -312,7 +313,7 @@ bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) { auto Elem = Ptr.elem<T>(I); if (Elem.isZero()) return true; - ++Result; + ++(*Result); }); } // We didn't find a 0 byte. @@ -322,16 +323,18 @@ bool Context::evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result) { if (PtrRes.isInvalid()) { C.cleanup(); Stk.clear(); - return false; + return std::nullopt; } - return true; + return Result; } -bool Context::tryEvaluateObjectSize(State &Parent, const Expr *E, unsigned Kind, - uint64_t &Result) { +std::optional<uint64_t> +Context::tryEvaluateObjectSize(State &Parent, const Expr *E, unsigned Kind) { assert(Stk.empty()); Compiler<EvalEmitter> C(*this, *P, Parent, Stk); + std::optional<uint64_t> Result; + auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) { const Descriptor *DeclDesc = Ptr.getDeclDesc(); if (!DeclDesc) @@ -353,9 +356,9 @@ bool Context::tryEvaluateObjectSize(State &Parent, const Expr *E, unsigned Kind, if (PtrRes.isInvalid()) { C.cleanup(); Stk.clear(); - return false; + return std::nullopt; } - return true; + return Result; } const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); } diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h index 313c040f84743..53afafdb49c0d 100644 --- a/clang/lib/AST/ByteCode/Context.h +++ b/clang/lib/AST/ByteCode/Context.h @@ -73,7 +73,7 @@ class Context final { /// Evalute \param E and if it can be evaluated to a string literal, /// run strlen() on it. - bool evaluateStrlen(State &Parent, const Expr *E, uint64_t &Result); + std::optional<uint64_t> evaluateStrlen(State &Parent, const Expr *E); /// If \param E evaluates to a pointer the number of accessible bytes /// past the pointer is estimated in \param Result as if evaluated by @@ -85,8 +85,8 @@ class Context final { /// as the one referred to by E are considered, when Kind & 1 == 0 /// bytes belonging to the same storage (stack, heap allocation, /// global variable) are considered. - bool tryEvaluateObjectSize(State &Parent, const Expr *E, unsigned Kind, - uint64_t &Result); + std::optional<uint64_t> tryEvaluateObjectSize(State &Parent, const Expr *E, + unsigned Kind); /// Returns the AST context. ASTContext &getASTContext() const { return Ctx; } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index d4068368f5b9d..44629b8bae194 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1775,9 +1775,9 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, EvalInfo &Info); static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); -static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, - EvalInfo &Info, - std::string *StringResult = nullptr); +static std::optional<uint64_t> +EvaluateBuiltinStrLen(const Expr *E, EvalInfo &Info, + std::string *StringResult = nullptr); /// Evaluate an integer or fixed point expression into an APResult. static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result, @@ -15781,8 +15781,8 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc, /// /// If @p WasError is non-null, this will report whether the failure to evaluate /// is to be treated as an Error in IntExprEvaluator. -static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, - EvalInfo &Info, uint64_t &Size) { +static std::optional<uint64_t> +tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, EvalInfo &Info) { // Determine the denoted object. LValue LVal; { @@ -15797,31 +15797,27 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, // Expr::tryEvaluateObjectSize. APValue RVal; if (!EvaluateAsRValue(Info, E, RVal)) - return false; + return std::nullopt; LVal.setFrom(Info.Ctx, RVal); } else if (!EvaluatePointer(ignorePointerCastsAndParens(E), LVal, Info, /*InvalidBaseOK=*/true)) - return false; + return std::nullopt; } // If we point to before the start of the object, there are no accessible // bytes. - if (LVal.getLValueOffset().isNegative()) { - Size = 0; - return true; - } + if (LVal.getLValueOffset().isNegative()) + return 0; CharUnits EndOffset; if (!determineEndOffset(Info, E->getExprLoc(), Type, LVal, EndOffset)) - return false; + return std::nullopt; // If we've fallen outside of the end offset, just pretend there's nothing to // write to/read from. if (EndOffset <= LVal.getLValueOffset()) - Size = 0; - else - Size = (EndOffset - LVal.getLValueOffset()).getQuantity(); - return true; + return 0; + return (EndOffset - LVal.getLValueOffset()).getQuantity(); } bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { @@ -15952,9 +15948,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue(); assert(Type <= 3 && "unexpected type"); - uint64_t Size; - if (tryEvaluateBuiltinObjectSize(E->getArg(0), Type, Info, Size)) - return Success(Size, E); + if (std::optional<uint64_t> Size = + tryEvaluateBuiltinObjectSize(E->getArg(0), Type, Info)) + return Success(*Size, E); if (E->getArg(0)->HasSideEffects(Info.Ctx)) return Success((Type & 2) ? 0 : -1, E); @@ -16552,9 +16548,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_wcslen: { // As an extension, we support __builtin_strlen() as a constant expression, // and support folding strlen() to a constant. - uint64_t StrLen; - if (EvaluateBuiltinStrLen(E->getArg(0), StrLen, Info)) - return Success(StrLen, E); + if (std::optional<uint64_t> StrLen = + EvaluateBuiltinStrLen(E->getArg(0), Info)) + return Success(*StrLen, E); return false; } @@ -21661,29 +21657,28 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E, return Diags.empty(); } -bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, - unsigned Type) const { +std::optional<uint64_t> Expr::tryEvaluateObjectSize(const ASTContext &Ctx, + unsigned Type) const { if (!getType()->isPointerType()) - return false; + return std::nullopt; Expr::EvalStatus Status; EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold); - if (Info.EnableNewConstInterp) { - return Info.Ctx.getInterpContext().tryEvaluateObjectSize(Info, this, Type, - Result); - } - return tryEvaluateBuiltinObjectSize(this, Type, Info, Result); + if (Info.EnableNewConstInterp) + return Info.Ctx.getInterpContext().tryEvaluateObjectSize(Info, this, Type); + return tryEvaluateBuiltinObjectSize(this, Type, Info); } -static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, - EvalInfo &Info, std::string *StringResult) { +static std::optional<uint64_t> +EvaluateBuiltinStrLen(const Expr *E, EvalInfo &Info, + std::string *StringResult) { if (!E->getType()->hasPointerRepresentation() || !E->isPRValue()) - return false; + return std::nullopt; LValue String; if (!EvaluatePointer(E, String, Info)) - return false; + return std::nullopt; QualType CharTy = E->getType()->getPointeeType(); @@ -21702,10 +21697,9 @@ static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, if (Pos != StringRef::npos) Str = Str.substr(0, Pos); - Result = Str.size(); if (StringResult) *StringResult = Str; - return true; + return Str.size(); } // Fall through to slow path. @@ -21716,21 +21710,19 @@ static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, APValue Char; if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) || !Char.isInt()) - return false; - if (!Char.getInt()) { - Result = Strlen; - return true; - } else if (StringResult) + return std::nullopt; + if (!Char.getInt()) + return Strlen; + else if (StringResult) StringResult->push_back(Char.getInt().getExtValue()); if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1)) - return false; + return std::nullopt; } } std::optional<std::string> Expr::tryEvaluateString(ASTContext &Ctx) const { Expr::EvalStatus Status; EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold); - uint64_t Result; std::string StringResult; if (Info.EnableNewConstInterp) { @@ -21739,7 +21731,7 @@ std::optional<std::string> Expr::tryEvaluateString(ASTContext &Ctx) const { return StringResult; } - if (EvaluateBuiltinStrLen(this, Result, Info, &StringResult)) + if (EvaluateBuiltinStrLen(this, Info, &StringResult)) return StringResult; return std::nullopt; } @@ -21816,14 +21808,13 @@ bool Expr::EvaluateCharRangeAsString(APValue &Result, PtrExpression, Ctx, Status); } -bool Expr::tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const { +std::optional<uint64_t> Expr::tryEvaluateStrLen(const ASTContext &Ctx) const { Expr::EvalStatus Status; EvalInfo Info(Ctx, Status, EvaluationMode::ConstantFold); if (Info.EnableNewConstInterp) - return Info.Ctx.getInterpContext().evaluateStrlen(Info, this, Result); - - return EvaluateBuiltinStrLen(this, Result, Info); + return Info.Ctx.getInterpContext().evaluateStrlen(Info, this); + return EvaluateBuiltinStrLen(this, Info); } namespace { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index ca2b8a5b192a6..5e6c9e8e2490e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -2037,8 +2037,9 @@ mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type, mlir::Value CIRGenFunction::evaluateOrEmitBuiltinObjectSize( const Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE, bool isDynamic) { - uint64_t objectSize; - if (!e->tryEvaluateObjectSize(objectSize, getContext(), type)) - return emitBuiltinObjectSize(e, type, resType, emittedE, isDynamic); - return builder.getConstInt(getLoc(e->getSourceRange()), resType, objectSize); + if (std::optional<uint64_t> objectSize = + e->tryEvaluateObjectSize(getContext(), type)) + return builder.getConstInt(getLoc(e->getSourceRange()), resType, + *objectSize); + return emitBuiltinObjectSize(e, type, resType, emittedE, isDynamic); } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index cf686581240a5..3db880f63a4fe 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -926,10 +926,10 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type, llvm::IntegerType *ResType, llvm::Value *EmittedE, bool IsDynamic) { - uint64_t ObjectSize; - if (!E->tryEvaluateObjectSize(ObjectSize, getContext(), Type)) - return emitBuiltinObjectSize(E, Type, ResType, EmittedE, IsDynamic); - return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true); + if (std::optional<uint64_t> ObjectSize = + E->tryEvaluateObjectSize(getContext(), Type)) + return ConstantInt::get(ResType, *ObjectSize, /*isSigned=*/true); + return emitBuiltinObjectSize(E, Type, ResType, EmittedE, IsDynamic); } namespace { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index dd00f883ff9f6..e82c82d881a8a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1217,12 +1217,12 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, return std::nullopt; const Expr *ObjArg = TheCall->getArg(NewIndex); - uint64_t Result; - if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) - return std::nullopt; - - // Get the object size in the target's size_t width. - return llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); + if (std::optional<uint64_t> ObjSize = + ObjArg->tryEvaluateObjectSize(getASTContext(), BOSType)) { + // Get the object size in the target's size_t width. + return llvm::APSInt::getUnsigned(*ObjSize).extOrTrunc(SizeTypeWidth); + } + return std::nullopt; }; auto ComputeStrLenArgument = @@ -1233,11 +1233,13 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, unsigned NewIndex = *IndexOptional; const Expr *ObjArg = TheCall->getArg(NewIndex); - uint64_t Result; - if (!ObjArg->tryEvaluateStrLen(Result, getASTContext())) - return std::nullopt; - // Add 1 for null byte. - return llvm::APSInt::getUnsigned(Result + 1).extOrTrunc(SizeTypeWidth); + + if (std::optional<uint64_t> Result = + ObjArg->tryEvaluateStrLen(getASTContext())) { + // Add 1 for null byte. + return llvm::APSInt::getUnsigned(*Result + 1).extOrTrunc(SizeTypeWidth); + } + return std::nullopt; }; std::optional<llvm::APSInt> SourceSize; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
