[clang] [clang][bytecode] Call CheckLocalLoad in GetLocal (PR #152090)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 4 23:00:35 PDT 2025


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/152090

I forgot to call this here as well. It was only used in the EvalEmitter implementation of the function. Also fix a problem where we didn't diagnose out-of-lifetime reads here.

>From 1203ec58f331b7a0753be6bbaa4a506d1344d7b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Tue, 5 Aug 2025 07:09:45 +0200
Subject: [PATCH] [clang][bytecode] Call CheckLocalLoad in GetLocal

I forgot to call this here as well. It was only used in the EvalEmitter
implementation of the function. Also fix a problem where we didn't
diagnose out-of-lifetime reads here.
---
 clang/lib/AST/ByteCode/Interp.cpp |  2 ++
 clang/lib/AST/ByteCode/Interp.h   |  2 +-
 clang/test/AST/ByteCode/cxx2a.cpp | 38 +++++++++++++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index f2366f674f45b..eb4e4800d44ae 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -752,6 +752,8 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
 
 // Similarly, for local loads.
 bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+  if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
+    return false;
   if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
     return false;
   if (!CheckVolatile(S, OpPC, Ptr, AK_Read))
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 61e776965a006..8a28106c0583a 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -1352,7 +1352,7 @@ inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
   const Pointer &Ptr = S.Current->getLocalPointer(I);
-  if (!CheckLoad(S, OpPC, Ptr))
+  if (!CheckLocalLoad(S, OpPC, Ptr))
     return false;
   S.Stk.push<T>(Ptr.deref<T>());
   return true;
diff --git a/clang/test/AST/ByteCode/cxx2a.cpp b/clang/test/AST/ByteCode/cxx2a.cpp
index d9541aca225b9..ac2f9883d49b6 100644
--- a/clang/test/AST/ByteCode/cxx2a.cpp
+++ b/clang/test/AST/ByteCode/cxx2a.cpp
@@ -1,6 +1,25 @@
 // RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=ref,both %s
 // RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=expected,both %s -fexperimental-new-constant-interpreter
 
+
+namespace std {
+  struct type_info;
+  struct destroying_delete_t {
+    explicit destroying_delete_t() = default;
+  } inline constexpr destroying_delete{};
+  struct nothrow_t {
+    explicit nothrow_t() = default;
+  } inline constexpr nothrow{};
+  using size_t = decltype(sizeof(0));
+  enum class align_val_t : size_t {};
+};
+
+constexpr void *operator new(std::size_t, void *p) { return p; }
+namespace std {
+  template<typename T> constexpr T *construct(T *p) { return new (p) T; }
+  template<typename T> constexpr void destroy(T *p) { p->~T(); }
+}
+
 template <unsigned N>
 struct S {
   S() requires (N==1) = default;
@@ -187,3 +206,22 @@ namespace PureVirtual {
   struct PureVirtualCall : Abstract { void f(); }; // both-note {{in call to 'Abstract}}
   constexpr PureVirtualCall pure_virtual_call; // both-error {{constant expression}} both-note {{in call to 'PureVirtualCall}}
 }
+
+namespace Dtor {
+  constexpr bool pseudo(bool read, bool recreate) {
+    using T = bool;
+    bool b = false; // both-note {{lifetime has already ended}}
+    // This evaluates the store to 'b'...
+    (b = true).~T();
+    // ... and ends the lifetime of the object.
+    return (read
+            ? b // both-note {{read of object outside its lifetime}}
+            : true) +
+           (recreate
+            ? (std::construct(&b), true)
+            : true);
+  }
+  static_assert(pseudo(false, false)); // both-error {{constant expression}} both-note {{in call}}
+  static_assert(pseudo(true, false)); // both-error {{constant expression}} both-note {{in call}}
+  static_assert(pseudo(false, true));
+}



More information about the cfe-commits mailing list