Skip to content

[clang] Placement new error when modifying consts #132460

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ Bug Fixes to C++ Support
The issue has been addressed by propagating qualifiers during derived-to-base conversions in the AST. (#GH127824)
- Clang now emits the ``-Wunused-variable`` warning when some structured bindings are unused
and the ``[[maybe_unused]]`` attribute is not applied. (#GH125810)
- Clang now issues an error when placement new is used to modify a const-qualified variable
in a ``constexpr`` function. (#GH131432)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10415,7 +10415,16 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {

typedef bool result_type;
bool failed() { return false; }
bool checkConst(QualType QT) {
if (QT.isConstQualified()) {
Info.FFDiag(E, diag::note_constexpr_modify_const_type) << QT;
return false;
}
return true;
}
bool found(APValue &Subobj, QualType SubobjType) {
if (!checkConst(SubobjType))
return false;
// FIXME: Reject the cases where [basic.life]p8 would not permit the
// old name of the object to be used to name the new object.
unsigned SubobjectSize = 1;
Expand Down
39 changes: 39 additions & 0 deletions clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,42 @@ constexpr bool bleh() {
}
static_assert(bleh()); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to 'bleh()'}}

constexpr int modify_const_variable() {
const int a = 10;
new ((int *)&a) int(12); // expected-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}
return a;
}
static_assert(modify_const_variable()); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}

typedef const int T0;
typedef T0 T1;
constexpr T1 modify_const_variable_td() {
T1 a = 10;
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}}
return a;
}
static_assert(modify_const_variable_td()); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}

template<typename T>
constexpr T modify_const_variable_tmpl() {
T a = 10;
new ((int *)&a) int(12); // expected-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}
return a;
}
static_assert(modify_const_variable_tmpl<const int>()); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to}}

namespace ModifyMutableMember {
struct S {
mutable int a {10};
};
constexpr int modify_mutable_member() {
const S s;
new ((int *)&s.a) int(12);
return s.a;
}
static_assert(modify_mutable_member() == 12);
}