https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/196548
We never did the load in the first place, causing us to only look at the `const char *p` parameter when evaluating the `__builtin_object_size` call. The current interpreter however _tries_ to do the load and only uses the subexpr pointer if the load fails. Add a `LoadPopL` op to do exactly that. >From b7c7f1870fe889bda7a1b3a22b0647e327545d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Fri, 8 May 2026 06:37:44 +0200 Subject: [PATCH] asdf --- clang/lib/AST/ByteCode/Compiler.cpp | 8 +++++-- clang/lib/AST/ByteCode/Interp.h | 22 ++++++++++++++++++ clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 +- clang/lib/AST/ByteCode/Opcodes.td | 1 + .../test/AST/ByteCode/builtin-object-size.cpp | 23 +++++++++++++++++-- 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 11c5478a5c748..1ed2a7066c37e 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -218,8 +218,12 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { case CK_LValueToRValue: { - if (ToLValue && E->getType()->isPointerType()) - return this->delegate(SubExpr); + if (ToLValue && E->getType()->isPointerType()) { + assert(!DiscardResult); + if (!this->visit(SubExpr)) + return false; + return this->emitLoadPopL(E); + } if (SubExpr->getType().isVolatileQualified()) return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, E); diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 4a550fdd63bfb..f0e0099d06a6f 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2132,6 +2132,28 @@ bool LoadPop(InterpState &S, CodePtr OpPC) { return true; } +/// Like LoadPop above, but if any of the checks fail, we simply +/// push the Pointer itself. +inline bool LoadPopL(InterpState &S, CodePtr OpPC) { + const Pointer &Ptr = S.Stk.pop<Pointer>(); + auto P = S.getEvalStatus().Diag; + S.getEvalStatus().Diag = nullptr; + bool Failed = false; + if (!CheckLoad(S, OpPC, Ptr)) + Failed = true; + if (!Ptr.isBlockPointer()) + Failed = true; + if (!Ptr.canDeref(PT_Ptr)) + Failed = true; + S.getEvalStatus().Diag = P; + + if (Failed) + S.Stk.push<Pointer>(Ptr); + else + S.Stk.push<Pointer>(Ptr.deref<Pointer>()); + return true; +} + template <PrimType Name, class T = typename PrimConv<Name>::T> bool Store(InterpState &S, CodePtr OpPC) { const T &Value = S.Stk.pop<T>(); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 77ea83605cc16..7964f02ecabbf 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -2438,7 +2438,7 @@ UnsignedOrNone evaluateBuiltinObjectSize(const ASTContext &ASTCtx, bool ReportMinimum = (Kind & 2u); if (!UseFieldDesc || DetermineForCompleteObject) { // Can't read beyond the pointer decl desc. - if (!ReportMinimum && DeclDesc->getType()->isPointerType()) + if (!ReportMinimum && DeclDesc->getDataType(ASTCtx)->isPointerType()) return std::nullopt; if (InvalidBase) diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 3fb25a5fa0884..a5c486460fdc0 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -515,6 +515,7 @@ class LoadOpcode : Opcode { def Load : LoadOpcode {} // [Pointer] -> [Value] def LoadPop : LoadOpcode {} +def LoadPopL : Opcode {} class StoreOpcode : Opcode { let Types = [AllTypeClass]; diff --git a/clang/test/AST/ByteCode/builtin-object-size.cpp b/clang/test/AST/ByteCode/builtin-object-size.cpp index e4433ea700ccb..ebd98284c9972 100644 --- a/clang/test/AST/ByteCode/builtin-object-size.cpp +++ b/clang/test/AST/ByteCode/builtin-object-size.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected %s // RUN: %clang_cc1 -verify=both,ref %s - -// ref-no-diagnostics +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected %s -std=c++2c -Winvalid-constexpr +// RUN: %clang_cc1 -verify=both,ref %s -std=c++2c -Winvalid-constexpr typedef __SIZE_TYPE__ size_t; @@ -50,8 +50,27 @@ namespace InvalidBase { constexpr size_t bos_name = __builtin_object_size(invalid_base().name, 1); // expected-error {{must be initialized by a constant expression}} \ // expected-note {{non-constexpr function 'invalid_base'}} +#if __cplusplus < 202002L struct T { ~T(); }; T invalid_base_2(); constexpr size_t bos_dtor = __builtin_object_size(&(T&)(T&&)invalid_base_2(), 0); // expected-error {{must be initialized by a constant expression}} \ // expected-note {{non-literal type 'T'}} +#endif +} + +constexpr int stringLength(const char *p) { // ref-error {{never produces a constant expression}} + return __builtin_dynamic_object_size(p, 0); // ref-note 2{{subexpression not valid in a constant expression}} +} +static_assert(stringLength("hello") == 6); // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} +#if __cplusplus >= 202002L + +constexpr int allocation(unsigned n) { + const char * ptr = new char[n]; + int res = stringLength(ptr); + delete[] ptr; + return res; } +static_assert(allocation(1) == 1); +static_assert(allocation(14) == 14); +#endif _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
