https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/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`.

>From 64b49b225f33298caa1dbb9070c3713da8077f87 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]>
Date: Thu, 25 Jun 2026 13:59:40 +0200
Subject: [PATCH] asdf

---
 clang/lib/AST/ByteCode/Interp.cpp   | 20 +++++++-------------
 clang/test/AST/ByteCode/cxx11.cpp   |  1 +
 clang/test/AST/ByteCode/mutable.cpp | 23 +++++++++++++++++++++++
 3 files changed, 31 insertions(+), 13 deletions(-)

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