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

None

>From 89c6d3b954544483cc8907c337fa5034744dc416 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Sat, 3 Jan 2026 15:52:16 +0100
Subject: [PATCH] [clang][bytecode] Check inc/dec operations for constness

---
 clang/lib/AST/ByteCode/Interp.h      | 32 ++++++++++++++++
 clang/test/AST/ByteCode/literals.cpp | 57 +++++++++++++++++++++++++++-
 2 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 9accbbc1605a9..155d96fc1652b 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -777,6 +777,8 @@ bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr,
                                                       CanOverflow);
@@ -788,6 +790,8 @@ bool IncBitfield(InterpState &S, CodePtr OpPC, bool 
CanOverflow,
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, 
CanOverflow,
                                                       BitWidth);
@@ -801,6 +805,8 @@ bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) 
{
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, 
CanOverflow);
 }
@@ -811,6 +817,8 @@ bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool 
CanOverflow,
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
                                                      BitWidth);
@@ -821,6 +829,8 @@ bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) 
{
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, 
CanOverflow);
 }
@@ -831,6 +841,8 @@ bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool 
CanOverflow,
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,
                                                      BitWidth);
@@ -845,6 +857,8 @@ bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,
                                                       CanOverflow);
@@ -855,6 +869,8 @@ bool DecBitfield(InterpState &S, CodePtr OpPC, bool 
CanOverflow,
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, 
CanOverflow,
                                                       BitWidth);
@@ -868,6 +884,8 @@ bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) 
{
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, 
CanOverflow);
 }
@@ -878,6 +896,8 @@ bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool 
CanOverflow,
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
                                                      BitWidth);
@@ -888,6 +908,8 @@ bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) 
{
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, 
CanOverflow);
 }
 
@@ -897,6 +919,8 @@ bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool 
CanOverflow,
   const Pointer &Ptr = S.Stk.peek<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,
                                                      BitWidth);
 }
@@ -926,6 +950,8 @@ inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t 
FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
 }
@@ -934,6 +960,8 @@ inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t 
FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
 }
@@ -942,6 +970,8 @@ inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t 
FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
 }
@@ -950,6 +980,8 @@ inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t 
FPOI) {
   const Pointer &Ptr = S.Stk.pop<Pointer>();
   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
     return false;
+  if (!CheckConst(S, OpPC, Ptr))
+    return false;
 
   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
 }
diff --git a/clang/test/AST/ByteCode/literals.cpp 
b/clang/test/AST/ByteCode/literals.cpp
index c6d79f9c60058..d637eccc448c4 100644
--- a/clang/test/AST/ByteCode/literals.cpp
+++ b/clang/test/AST/ByteCode/literals.cpp
@@ -866,7 +866,62 @@ namespace IncDec {
                             // both-note {{function parameter 'a' with unknown 
value cannot be used in a constant expression}}
   }
 
-};
+  namespace Const {
+    constexpr int test1(const int a) {
+      ((int&)a)++; // both-note {{modification of object of const-qualified 
type 'const int'}}
+      return a;
+    }
+    static_assert(test1(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+
+    constexpr int test2(const int a) {
+      ++((int&)a); // both-note {{modification of object of const-qualified 
type 'const int'}}
+      return a;
+    }
+    static_assert(test2(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+    constexpr int test3(const int a) {
+      ((int&)a)--; // both-note {{modification of object of const-qualified 
type 'const int'}}
+      return a;
+    }
+    static_assert(test3(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+
+    constexpr int test4(const int a) {
+      --((int&)a); // both-note {{modification of object of const-qualified 
type 'const int'}}
+      return a;
+    }
+    static_assert(test4(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+
+    constexpr int test5(const int a) {
+      int b = ((int&)a)++; // both-note {{modification of object of 
const-qualified type 'const int'}}
+      return a;
+    }
+    static_assert(test5(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+
+    constexpr int test6(const int a) {
+      int b = ++((int&)a); // both-note {{modification of object of 
const-qualified type 'const int'}}
+      return a;
+    }
+    static_assert(test6(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+    constexpr int test7(const int a) {
+      int b = ((int&)a)--; // both-note {{modification of object of 
const-qualified type 'const int'}}
+      return a;
+    }
+    static_assert(test7(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+
+    constexpr int test8(const int a) {
+      int b = --((int&)a); // both-note {{modification of object of 
const-qualified type 'const int'}}
+      return a;
+    }
+    static_assert(test8(12) == 10); // both-error {{not an integral constant 
expression}} \
+                                    // both-note {{in call to}}
+  }
+}
 #endif
 
 namespace CompoundLiterals {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to