Skip to content

Commit 4067581

Browse files
authored
[clang] Placement new error when modifying consts (#132460)
Raise an error when placement new is used to modify a const-qualified variable in a constexpr function. Fixes #131432
1 parent 57f2e76 commit 4067581

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,8 @@ Bug Fixes to C++ Support
362362
- Fixed a Clang regression in C++20 mode where unresolved dependent call expressions were created inside non-dependent contexts (#GH122892)
363363
- Clang now emits the ``-Wunused-variable`` warning when some structured bindings are unused
364364
and the ``[[maybe_unused]]`` attribute is not applied. (#GH125810)
365+
- Clang now issues an error when placement new is used to modify a const-qualified variable
366+
in a ``constexpr`` function. (#GH131432)
365367

366368
Bug Fixes to AST Handling
367369
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/AST/ExprConstant.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10420,7 +10420,16 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
1042010420

1042110421
typedef bool result_type;
1042210422
bool failed() { return false; }
10423+
bool checkConst(QualType QT) {
10424+
if (QT.isConstQualified()) {
10425+
Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT;
10426+
return false;
10427+
}
10428+
return true;
10429+
}
1042310430
bool found(APValue &Subobj, QualType SubobjType) {
10431+
if (!checkConst(SubobjType))
10432+
return false;
1042410433
// FIXME: Reject the cases where [basic.life]p8 would not permit the
1042510434
// old name of the object to be used to name the new object.
1042610435
unsigned SubobjectSize = 1;

clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,42 @@ constexpr bool bleh() {
114114
}
115115
static_assert(bleh()); // expected-error {{not an integral constant expression}} \
116116
// expected-note {{in call to 'bleh()'}}
117+
118+
constexpr int modify_const_variable() {
119+
const int a = 10;
120+
new ((int *)&a) int(12); // expected-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}
121+
return a;
122+
}
123+
static_assert(modify_const_variable()); // expected-error {{not an integral constant expression}} \
124+
// expected-note {{in call to}}
125+
126+
typedef const int T0;
127+
typedef T0 T1;
128+
constexpr T1 modify_const_variable_td() {
129+
T1 a = 10;
130+
new ((int *)&a) int(12); // expected-note {{modification of object of const-qualified type 'T1' (aka 'const int') is not allowed in a constant expression}}
131+
return a;
132+
}
133+
static_assert(modify_const_variable_td()); // expected-error {{not an integral constant expression}} \
134+
// expected-note {{in call to}}
135+
136+
template<typename T>
137+
constexpr T modify_const_variable_tmpl() {
138+
T a = 10;
139+
new ((int *)&a) int(12); // expected-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}
140+
return a;
141+
}
142+
static_assert(modify_const_variable_tmpl<const int>()); // expected-error {{not an integral constant expression}} \
143+
// expected-note {{in call to}}
144+
145+
namespace ModifyMutableMember {
146+
struct S {
147+
mutable int a {10};
148+
};
149+
constexpr int modify_mutable_member() {
150+
const S s;
151+
new ((int *)&s.a) int(12);
152+
return s.a;
153+
}
154+
static_assert(modify_mutable_member() == 12);
155+
}

0 commit comments

Comments
 (0)