Author: Timm Baeder
Date: 2026-06-26T08:01:45+02:00
New Revision: eac90446207dedf6bd243c9033fb3f1c7dec8dee

URL: 
https://github.com/llvm/llvm-project/commit/eac90446207dedf6bd243c9033fb3f1c7dec8dee
DIFF: 
https://github.com/llvm/llvm-project/commit/eac90446207dedf6bd243c9033fb3f1c7dec8dee.diff

LOG: [clang][bytecode] Don't check instance pointers for mutability (#205820)

The instance pointer being mutable is perfectly fine, we just can't read
anything from it.

This regresses a test case in `cxx11.cpp` where we now diagnose an extra
frame for `U(g1.u)`, but this seems correct since the read is happening
in the copy constructor of `U`.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/Interp.cpp
    clang/test/AST/ByteCode/cxx11.cpp
    clang/test/AST/ByteCode/mutable.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 71021815baeef..2f09c19178f09 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -660,16 +660,7 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView 
Ptr, AccessKinds AK) {
 
   if (S.checkingConstantDestruction()) {
     // Never allowed when checking for constant destruction.
-    // Find the reason this pointer is mutable.
-    PtrView MutablePtr = Ptr;
-    while (!MutablePtr.isRoot() && MutablePtr.getBase().isMutable())
-      MutablePtr = MutablePtr.getBase();
-
-    const FieldDecl *Field = MutablePtr.getField();
-    S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_mutable, 
1)
-        << AK << Field;
-    S.Note(Field->getLocation(), diag::note_declared_at);
-    return false;
+    // Diagnose below.
   } else if (S.getLangOpts().CPlusPlus14 &&
              S.lifetimeStartedInEvaluation(Ptr.block())) {
     // In C++14 onwards, it is permitted to read a mutable member whose
@@ -677,8 +668,13 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView 
Ptr, AccessKinds AK) {
     return true;
   }
 
+  // Find the reason this pointer is mutable.
+  PtrView MutablePtr = Ptr;
+  while (!MutablePtr.isRoot() && MutablePtr.getBase().isMutable())
+    MutablePtr = MutablePtr.getBase();
+
   const SourceInfo &Loc = S.Current->getSource(OpPC);
-  const FieldDecl *Field = Ptr.getField();
+  const FieldDecl *Field = MutablePtr.getField();
   S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK << Field;
   S.Note(Field->getLocation(), diag::note_declared_at);
   return false;
@@ -1025,8 +1021,6 @@ static bool CheckInvoke(InterpState &S, CodePtr OpPC, 
const Pointer &Ptr,
       return false;
     if (!(IsCtor || IsDtor) && !CheckLifetime(S, OpPC, Ptr, AK_MemberCall))
       return false;
-    if (!IsDtor && !CheckMutable(S, OpPC, Ptr))
-      return false;
   }
   return true;
 }

diff  --git a/clang/test/AST/ByteCode/cxx11.cpp 
b/clang/test/AST/ByteCode/cxx11.cpp
index ffe2f3c67c511..3553ab3ba68ad 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -343,6 +343,7 @@ namespace ReadMutableInCopyCtor {
   constexpr G g1 = {};
   constexpr G g2 = g1; // both-error {{must be initialized by a constant 
expression}} \
                        // both-note {{read of mutable member 'u'}} \
+                       // expected-note {{in call to 'U(g1.u)'}} \
                        // both-note {{in call to 'G(g1)'}}
 }
 

diff  --git a/clang/test/AST/ByteCode/mutable.cpp 
b/clang/test/AST/ByteCode/mutable.cpp
index 16c8ce9125d5e..5dbaa66ab4c86 100644
--- a/clang/test/AST/ByteCode/mutable.cpp
+++ b/clang/test/AST/ByteCode/mutable.cpp
@@ -73,4 +73,27 @@ constexpr D d2 = d1; // both-error {{must be initialized by 
a constant expressio
                      // both-note {{read of mutable member 'y}} \
                      // both-note {{in call to}}
 
+namespace MutablenessFromBasePtr {
+  struct Foo  {
+    constexpr int five() const { return 5; }
+    int k = 12;
+  };
+  struct M {
+    mutable Foo F; // both-note {{declared here}}
+  };
+  constexpr M m{};
+  static_assert(m.F.k == 12, ""); // both-error {{not an integral constant 
expression}} \
+                                  // both-note {{read of mutable member 'F' is 
not allowed in a constant expression}}
+}
 
+namespace MemberCall {
+  struct Foo  {
+    constexpr int five() const { return 5; }
+  };
+  struct M {
+    mutable Foo F;
+    constexpr int zomg() const { return F.five(); }
+  };
+  constexpr M m{};
+  static_assert(m.zomg() == 5, "");
+}


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

Reply via email to