[clang] e9988c3 - [clang][Sema] Propagate qualifiers during derived-to-base conversion
Antonio Frighetto via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 19 01:09:38 PDT 2025
Author: Antonio Frighetto
Date: 2025-03-19T09:04:29+01:00
New Revision: e9988c36ed788b2d1ce00b028bed51169bd8b02c
URL: https://github.com/llvm/llvm-project/commit/e9988c36ed788b2d1ce00b028bed51169bd8b02c
DIFF: https://github.com/llvm/llvm-project/commit/e9988c36ed788b2d1ce00b028bed51169bd8b02c.diff
LOG: [clang][Sema] Propagate qualifiers during derived-to-base conversion
When accessing a field member through a derived-to-base conversion,
ensure qualifiers are propagated to the base class subobject.
Fixes: https://github.com/llvm/llvm-project/issues/127683.
Added:
clang/test/SemaCXX/derived-to-base-propagate-qualifiers.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaExpr.cpp
clang/test/CodeGenCXX/derived-to-base.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ce4336acb806a..1c0504d831e3f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -340,6 +340,8 @@ Bug Fixes to C++ Support
- Fixed an assertion failure affecting code that uses C++23 "deducing this". (#GH130272)
- Clang now properly instantiates destructors for initialized members within non-delegating constructors. (#GH93251)
- Correctly diagnoses if unresolved using declarations shadows template paramters (#GH129411)
+- Clang was previously coalescing volatile writes to members of volatile base class subobjects.
+ The issue has been addressed by propagating qualifiers during derived-to-base conversions in the AST. (#GH127824)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3ff372bdc9d0c..a03acb5fbd273 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3113,8 +3113,15 @@ Sema::PerformObjectMemberConversion(Expr *From,
/*IgnoreAccess=*/true))
return ExprError();
- return ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase,
- VK, &BasePath);
+ // Propagate qualifiers to base subobjects as per:
+ // C++ [basic.type.qualifier]p1.2:
+ // A volatile object is [...] a subobject of a volatile object.
+ Qualifiers FromTypeQuals = FromType.getQualifiers();
+ FromTypeQuals.setAddressSpace(DestType.getAddressSpace());
+ DestType = Context.getQualifiedType(DestType, FromTypeQuals);
+
+ return ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase, VK,
+ &BasePath);
}
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
diff --git a/clang/test/CodeGenCXX/derived-to-base.cpp b/clang/test/CodeGenCXX/derived-to-base.cpp
index c8dbd5bf5cb05..c09a12b728bbb 100644
--- a/clang/test/CodeGenCXX/derived-to-base.cpp
+++ b/clang/test/CodeGenCXX/derived-to-base.cpp
@@ -46,4 +46,29 @@ namespace test3 {
}
}
+// Ensure volatile is preserved during derived-to-base conversion.
+namespace PR127683 {
+
+struct Base {
+ int Val;
+};
+
+struct Derived : Base { };
+
+volatile Derived Obj;
+
+// CHECK-LABEL: define void @_ZN8PR12768319test_volatile_storeEv()
+// CHECK: store volatile i32 0, ptr @_ZN8PR1276833ObjE, align 4
+void test_volatile_store() {
+ Obj.Val = 0;
+}
+
+// CHECK-LABEL: define void @_ZN8PR12768318test_volatile_loadEv()
+// CHECK: %0 = load volatile i32, ptr @_ZN8PR1276833ObjE, align 4
+void test_volatile_load() {
+ [[maybe_unused]] int Val = Obj.Val;
+}
+
+}
+
// CHECK: attributes [[NUW]] = { mustprogress noinline nounwind{{.*}} }
diff --git a/clang/test/SemaCXX/derived-to-base-propagate-qualifiers.cpp b/clang/test/SemaCXX/derived-to-base-propagate-qualifiers.cpp
new file mode 100644
index 0000000000000..8a3b944ab1cb6
--- /dev/null
+++ b/clang/test/SemaCXX/derived-to-base-propagate-qualifiers.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -ast-dump -verify %s | FileCheck %s
+
+// Ensure qualifiers are preserved during derived-to-base conversion.
+namespace PR127683 {
+
+struct Base {
+ int Val;
+};
+
+struct Derived : Base { };
+
+// Value-initialize base class subobjects with type qualifiers.
+volatile Derived VObj;
+const Derived CObj{}; // expected-note{{variable 'CObj' declared const here}}
+const volatile Derived CVObj{}; // expected-note{{variable 'CVObj' declared const here}}
+__attribute__((address_space(1))) Derived AddrSpaceObj{};
+
+void test_store() {
+ // CHECK: `-ImplicitCastExpr {{.*}} 'volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ VObj.Val = 0;
+
+ // CHECK: `-ImplicitCastExpr {{.*}} 'const PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ CObj.Val = 1; // expected-error {{cannot assign to variable 'CObj' with const-qualified type 'const Derived'}}
+
+ // CHECK: `-ImplicitCastExpr {{.*}} 'const volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ CVObj.Val = 1; // expected-error {{cannot assign to variable 'CVObj' with const-qualified type 'const volatile Derived'}}
+
+ // CHECK: `-ImplicitCastExpr {{.*}} '__attribute__((address_space(1))) PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ AddrSpaceObj.Val = 1;
+}
+
+void test_load() {
+ // CHECK: `-ImplicitCastExpr {{.*}} <col:30> 'volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ [[maybe_unused]] int Val = VObj.Val;
+
+ // CHECK: `-ImplicitCastExpr {{.*}} 'const PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ Val = CObj.Val;
+
+ // CHECK: `-ImplicitCastExpr {{.*}} 'const volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ Val = CVObj.Val;
+
+ // CHECK: `-ImplicitCastExpr {{.*}} '__attribute__((address_space(1))) PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
+ Val = AddrSpaceObj.Val;
+}
+
+}
More information about the cfe-commits
mailing list