Author: Timm Baeder Date: 2026-05-11T09:18:11+02:00 New Revision: 47495f4934094fab8f991303ec5d94d76b9254fb
URL: https://github.com/llvm/llvm-project/commit/47495f4934094fab8f991303ec5d94d76b9254fb DIFF: https://github.com/llvm/llvm-project/commit/47495f4934094fab8f991303ec5d94d76b9254fb.diff LOG: [clang][bytecode] Visit `tryEvaluateObjectSize` expr as lvalue (#196010) Just like we do with the first parameter of a regular `__builtin_object_size` call. This still doesn't fix the bigger bos test cases since e.g. ```c++ int NoViableOverloadObjectSize3(void *const p PS(3)) __attribute__((overloadable)) { return __builtin_object_size(p, 3); } void test4(struct Foo *t) { gi = NoViableOverloadObjectSize3(&t[1].t[1]); } ``` is still broken because we don't have special handling for the `&t[1].t[1]` handling here and we can't usually access a one-past-end pointer. Added: Modified: clang/lib/AST/ByteCode/ByteCodeEmitter.h clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Compiler.h clang/lib/AST/ByteCode/Context.cpp clang/lib/AST/ByteCode/EvalEmitter.cpp clang/lib/AST/ByteCode/EvalEmitter.h clang/test/AST/ByteCode/builtin-object-size-codegen.c Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h index 102ce939c6717..e3aa3c940de47 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h @@ -46,6 +46,7 @@ class ByteCodeEmitter { /// Methods implemented by the compiler. virtual bool visitFunc(const FunctionDecl *E) = 0; virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0; + virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) = 0; virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init, bool ConstantContext) = 0; virtual bool visit(const Expr *E) = 0; diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 9a8842bf258f6..faad6e0b4a230 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -5155,6 +5155,15 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) { return maybeDestroyLocals() && false; } +template <class Emitter> +bool Compiler<Emitter>::visitLValueExpr(const Expr *E, + bool DestroyToplevelScope) { + OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false, + /*NewInitializing=*/false, /*ToLValue=*/true); + + return this->visitExpr(E, DestroyToplevelScope); +} + template <class Emitter> VarCreationState Compiler<Emitter>::visitDecl(const VarDecl *VD) { diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index de6ea524897a0..ff5d0c05fe14b 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -253,6 +253,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, protected: bool visitStmt(const Stmt *S); bool visitExpr(const Expr *E, bool DestroyToplevelScope) override; + bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) override; bool visitFunc(const FunctionDecl *F) override; bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init, diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 3a8a50f2aeb53..35959715946c3 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -345,7 +345,7 @@ Context::tryEvaluateObjectSize(State &Parent, const Expr *E, unsigned Kind) { std::optional<uint64_t> Result; - auto PtrRes = C.interpretAsPointer(E, [&](const Pointer &Ptr) { + auto PtrRes = C.interpretAsLValuePointer(E, [&](const Pointer &Ptr) { const Descriptor *DeclDesc = Ptr.getDeclDesc(); if (!DeclDesc) return false; diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 319ef7edd57b9..d3acaa406af51 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -75,14 +75,13 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, const Expr *Init, EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E, PtrCallback PtrCB) { - S.setEvalLocation(E->getExprLoc()); this->ConvertResultToRValue = false; this->CheckFullyInitialized = false; this->PtrCB = PtrCB; EvalResult.setSource(E); - if (!this->visitExpr(E, /*DestroyToplevelScope=*/true)) { + if (!this->visitExpr(E, true)) { // EvalResult may already have a result set, but something failed // after that (e.g. evaluating destructors). EvalResult.setInvalid(); @@ -91,6 +90,20 @@ EvaluationResult EvalEmitter::interpretAsPointer(const Expr *E, return std::move(this->EvalResult); } +EvaluationResult EvalEmitter::interpretAsLValuePointer(const Expr *E, + PtrCallback PtrCB) { + S.setEvalLocation(E->getExprLoc()); + this->ConvertResultToRValue = false; + this->CheckFullyInitialized = false; + this->PtrCB = PtrCB; + EvalResult.setSource(E); + + if (!this->visitLValueExpr(E, true)) + EvalResult.setInvalid(); + + return std::move(this->EvalResult); +} + bool EvalEmitter::interpretCall(const FunctionDecl *FD, const Expr *E) { // Add parameters to the parameter map. The values in the ParamOffset don't // matter in this case as reading from them can't ever work. diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h index 8f6da7aef422a..ce5825eef3607 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.h +++ b/clang/lib/AST/ByteCode/EvalEmitter.h @@ -42,6 +42,7 @@ class EvalEmitter : public SourceMapper { bool CheckFullyInitialized); /// Interpret the given Expr to a Pointer. EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB); + EvaluationResult interpretAsLValuePointer(const Expr *E, PtrCallback PtrCB); /// Interpret the given expression as if it was in the body of the given /// function, i.e. the parameters of the function are available for use. bool interpretCall(const FunctionDecl *FD, const Expr *E); @@ -61,6 +62,7 @@ class EvalEmitter : public SourceMapper { /// Methods implemented by the compiler. virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope) = 0; + virtual bool visitLValueExpr(const Expr *E, bool DestroyToplevelScope) = 0; virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init, bool ConstantContext) = 0; virtual bool visitFunc(const FunctionDecl *F) = 0; diff --git a/clang/test/AST/ByteCode/builtin-object-size-codegen.c b/clang/test/AST/ByteCode/builtin-object-size-codegen.c index 6aa0485bd65ad..1b2561a89ebba 100644 --- a/clang/test/AST/ByteCode/builtin-object-size-codegen.c +++ b/clang/test/AST/ByteCode/builtin-object-size-codegen.c @@ -35,6 +35,12 @@ // gi = ObjectSize2(&t[1].t[1]); } +void foo2(struct Foo *t) { + // CHECK: call i32 @ObjectSize3(ptr noundef %{{.*}}, i64 noundef 36) + ObjectSize3(&t->t[1]); +} + + /// Used to crash due to the void-typed ArraySubscriptExpr. void foo(void *p) { int i = __builtin_object_size(&p[2], 3); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
