Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[clang][bytecode] Fix const-in-mutable fields#149286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
tbaederr merged 2 commits intollvm:mainfromtbaederr:const-in-mutable
Jul 18, 2025

Conversation

tbaederr
Copy link
Contributor

For mutable and const fields, we have two bits in InlineDescriptor, which both get inherited down the hierarchy. When a field is both const and mutable, we CAN read from it if it is a mutable-in-const field, but wecan't read from it if it is a const-in-mutable field. We need another bit to distinguish the two cases.

@llvmbotllvmbot added clangClang issues not falling into any other category clang:frontendLanguage frontend issues, e.g. anything involving "Sema" clang:bytecodeIssues for the clang bytecode constexpr interpreter labelsJul 17, 2025
@llvmbot
Copy link
Member

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

For mutable and const fields, we have two bits in InlineDescriptor, which both get inherited down the hierarchy. When a field is both const and mutable, we CAN read from it if it is a mutable-in-const field, but wecan't read from it if it is a const-in-mutable field. We need another bit to distinguish the two cases.


Full diff:https://github.com/llvm/llvm-project/pull/149286.diff

5 Files Affected:

  • (modified) clang/lib/AST/ByteCode/Descriptor.cpp (+3-1)
  • (modified) clang/lib/AST/ByteCode/Descriptor.h (+4)
  • (modified) clang/lib/AST/ByteCode/Interp.cpp (+1-1)
  • (modified) clang/lib/AST/ByteCode/Pointer.h (+5)
  • (modified) clang/test/AST/ByteCode/mutable.cpp (+48-8)
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cppindex c89eca9bef440..2d5334dbb46b6 100644--- a/clang/lib/AST/ByteCode/Descriptor.cpp+++ b/clang/lib/AST/ByteCode/Descriptor.cpp@@ -160,8 +160,10 @@ static void initField(Block *B, std::byte *Ptr, bool IsConst, bool IsMutable,   Desc->IsActive = IsActive && !IsUnionField;   Desc->InUnion = InUnion;   Desc->IsConst = IsConst || D->IsConst;-  Desc->IsFieldMutable = IsMutable || D->IsMutable;+  Desc->IsFieldMutable = (IsMutable || D->IsMutable);   Desc->IsVolatile = IsVolatile || D->IsVolatile;+  // True if this field is const AND the parent is mutable.+  Desc->IsConstInMutable = Desc->IsConst && IsMutable;    if (auto Fn = D->CtorFn)     Fn(B, Ptr + FieldOffset, Desc->IsConst, Desc->IsFieldMutable,diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.hindex 4591eabb69bb4..0227e4c0c7e38 100644--- a/clang/lib/AST/ByteCode/Descriptor.h+++ b/clang/lib/AST/ByteCode/Descriptor.h@@ -101,6 +101,10 @@ struct InlineDescriptor {   /// Flag indicating if the field is mutable (if in a record).   LLVM_PREFERRED_TYPE(bool)   unsigned IsFieldMutable : 1;+  /// Flag indicating if this field is a const field nested in+  /// a mutable parent field.+  LLVM_PREFERRED_TYPE(bool)+  unsigned IsConstInMutable : 1;   /// Flag indicating if the field is an element of a composite array.   LLVM_PREFERRED_TYPE(bool)   unsigned IsArrayElement : 1;diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cppindex edb1866b5265c..709b3bb64d280 100644--- a/clang/lib/AST/ByteCode/Interp.cpp+++ b/clang/lib/AST/ByteCode/Interp.cpp@@ -566,7 +566,7 @@ bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,  bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {   assert(Ptr.isLive() && "Pointer is not live");-  if (!Ptr.isConst() || Ptr.isMutable())+  if (!Ptr.isConst() || !Ptr.isConstInMutable())     return true;    if (!Ptr.isBlockPointer())diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.hindex e6a64e6658f06..da74013cf83a6 100644--- a/clang/lib/AST/ByteCode/Pointer.h+++ b/clang/lib/AST/ByteCode/Pointer.h@@ -576,6 +576,11 @@ class Pointer {       return true;     return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;   }+  bool isConstInMutable() const {+    if (!isBlockPointer())+      return false;+    return isRoot() ? false : getInlineDesc()->IsConstInMutable;+  }    /// Checks if an object or a subfield is volatile.   bool isVolatile() const {diff --git a/clang/test/AST/ByteCode/mutable.cpp b/clang/test/AST/ByteCode/mutable.cppindex aebbea920578c..35c5a0389921e 100644--- a/clang/test/AST/ByteCode/mutable.cpp+++ b/clang/test/AST/ByteCode/mutable.cpp@@ -1,11 +1,7 @@-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++11 -verify=expected,expected11,both,both11 %s-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++14 -verify=expected,expected14,both %s-// RUN: %clang_cc1 -std=c++11 -verify=ref,ref11,both,both11 %s-// RUN: %clang_cc1 -std=c++14 -verify=ref,ref14,both %s----+// RUN: %clang_cc1 -std=c++11 -verify=expected,expected11,both,both11 %s -fexperimental-new-constant-interpreter+// RUN: %clang_cc1 -std=c++14 -verify=expected,expected14,both        %s -fexperimental-new-constant-interpreter+// RUN: %clang_cc1 -std=c++11 -verify=ref,ref11,both,both11           %s+// RUN: %clang_cc1 -std=c++14 -verify=ref,ref14,both                  %s  namespace Simple {   struct S {@@ -26,3 +22,47 @@ namespace Simple {   static_assert(s2.a2 == 12, ""); // both11-error {{not an integral constant expression}} \                                   // both11-note {{initializer of 's2' is not a constant expression}} }+#if __cplusplus >= 201402L+namespace ConstInMutable {+  class B {+    public:++    const int f;+    constexpr B() : f(12) {}+  };+  class A {+    public:+    mutable B b;+    constexpr A() = default;+  };+  constexpr int constInMutable() {+    A a;++    int *m = (int*)&a.b.f;+    *m = 12; // both-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}+    return 1;+  }+  static_assert(constInMutable() == 1, ""); // both-error {{not an integral constant expression}} \+                                            // both-note {{in call to}}+}++namespace MutableInConst {+  class C {+  public:+    mutable int c;+    constexpr C() : c(50) {}+  };+  class D {+  public:+    C c;+    constexpr D() {}+  };+  constexpr int mutableInConst() {+    const D d{};+    int *m = (int*)&d.c.c;+    *m = 12;+    return 1;+  }+  static_assert(mutableInConst() == 1, "");+}+#endif

For mutable and const fields, we have two bits in InlineDescriptor,which both get inherited down the hierarchy. When a field is both constand mutable, we CAN read from it if it is a mutable-in-const field, butwe _can't_ read from it if it is a const-in-mutable field. We needanother bit to distinguish the two cases.
@tbaederrtbaederr merged commitb7660a5 intollvm:mainJul 18, 2025
9 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Labels
clang:bytecodeIssues for the clang bytecode constexpr interpreterclang:frontendLanguage frontend issues, e.g. anything involving "Sema"clangClang issues not falling into any other category
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants
@tbaederr@llvmbot

[8]ページ先頭

©2009-2025 Movatter.jp