Skip to content

Commit e9988c3

Browse files
[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: #127683.
1 parent 8a53324 commit e9988c3

File tree

4 files changed

+82
-2
lines changed

4 files changed

+82
-2
lines changed

clang/docs/ReleaseNotes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ Bug Fixes to C++ Support
340340
- Fixed an assertion failure affecting code that uses C++23 "deducing this". (#GH130272)
341341
- Clang now properly instantiates destructors for initialized members within non-delegating constructors. (#GH93251)
342342
- Correctly diagnoses if unresolved using declarations shadows template paramters (#GH129411)
343+
- Clang was previously coalescing volatile writes to members of volatile base class subobjects.
344+
The issue has been addressed by propagating qualifiers during derived-to-base conversions in the AST. (#GH127824)
343345

344346
Bug Fixes to AST Handling
345347
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -3113,8 +3113,15 @@ Sema::PerformObjectMemberConversion(Expr *From,
31133113
/*IgnoreAccess=*/true))
31143114
return ExprError();
31153115

3116-
return ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase,
3117-
VK, &BasePath);
3116+
// Propagate qualifiers to base subobjects as per:
3117+
// C++ [basic.type.qualifier]p1.2:
3118+
// A volatile object is [...] a subobject of a volatile object.
3119+
Qualifiers FromTypeQuals = FromType.getQualifiers();
3120+
FromTypeQuals.setAddressSpace(DestType.getAddressSpace());
3121+
DestType = Context.getQualifiedType(DestType, FromTypeQuals);
3122+
3123+
return ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase, VK,
3124+
&BasePath);
31183125
}
31193126

31203127
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,

clang/test/CodeGenCXX/derived-to-base.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,29 @@ namespace test3 {
4646
}
4747
}
4848

49+
// Ensure volatile is preserved during derived-to-base conversion.
50+
namespace PR127683 {
51+
52+
struct Base {
53+
int Val;
54+
};
55+
56+
struct Derived : Base { };
57+
58+
volatile Derived Obj;
59+
60+
// CHECK-LABEL: define void @_ZN8PR12768319test_volatile_storeEv()
61+
// CHECK: store volatile i32 0, ptr @_ZN8PR1276833ObjE, align 4
62+
void test_volatile_store() {
63+
Obj.Val = 0;
64+
}
65+
66+
// CHECK-LABEL: define void @_ZN8PR12768318test_volatile_loadEv()
67+
// CHECK: %0 = load volatile i32, ptr @_ZN8PR1276833ObjE, align 4
68+
void test_volatile_load() {
69+
[[maybe_unused]] int Val = Obj.Val;
70+
}
71+
72+
}
73+
4974
// CHECK: attributes [[NUW]] = { mustprogress noinline nounwind{{.*}} }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -ast-dump -verify %s | FileCheck %s
2+
3+
// Ensure qualifiers are preserved during derived-to-base conversion.
4+
namespace PR127683 {
5+
6+
struct Base {
7+
int Val;
8+
};
9+
10+
struct Derived : Base { };
11+
12+
// Value-initialize base class subobjects with type qualifiers.
13+
volatile Derived VObj;
14+
const Derived CObj{}; // expected-note{{variable 'CObj' declared const here}}
15+
const volatile Derived CVObj{}; // expected-note{{variable 'CVObj' declared const here}}
16+
__attribute__((address_space(1))) Derived AddrSpaceObj{};
17+
18+
void test_store() {
19+
// CHECK: `-ImplicitCastExpr {{.*}} 'volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
20+
VObj.Val = 0;
21+
22+
// CHECK: `-ImplicitCastExpr {{.*}} 'const PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
23+
CObj.Val = 1; // expected-error {{cannot assign to variable 'CObj' with const-qualified type 'const Derived'}}
24+
25+
// CHECK: `-ImplicitCastExpr {{.*}} 'const volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
26+
CVObj.Val = 1; // expected-error {{cannot assign to variable 'CVObj' with const-qualified type 'const volatile Derived'}}
27+
28+
// CHECK: `-ImplicitCastExpr {{.*}} '__attribute__((address_space(1))) PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
29+
AddrSpaceObj.Val = 1;
30+
}
31+
32+
void test_load() {
33+
// CHECK: `-ImplicitCastExpr {{.*}} <col:30> 'volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
34+
[[maybe_unused]] int Val = VObj.Val;
35+
36+
// CHECK: `-ImplicitCastExpr {{.*}} 'const PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
37+
Val = CObj.Val;
38+
39+
// CHECK: `-ImplicitCastExpr {{.*}} 'const volatile PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
40+
Val = CVObj.Val;
41+
42+
// CHECK: `-ImplicitCastExpr {{.*}} '__attribute__((address_space(1))) PR127683::Base' lvalue <UncheckedDerivedToBase (Base)>
43+
Val = AddrSpaceObj.Val;
44+
}
45+
46+
}

0 commit comments

Comments
 (0)