[clang] [clang] Placement new error when modifying consts (PR #132460)
marius doerner via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 21 12:51:58 PDT 2025
https://github.com/mariusdr created https://github.com/llvm/llvm-project/pull/132460
Closes #131432
Raise an error when placement new is used to modify a const-qualified variable in a constexpr function.
Note that diag::note_constexpr_modify_const_type is used since the it is also raised when the sample program is compiled with '-fexperimental-new-constant-interpreter'.
>From d4af25b14fb21f50c3771cce4595ca5c1bb920a7 Mon Sep 17 00:00:00 2001
From: marius doerner <mariusdr at users.noreply.github.com>
Date: Fri, 21 Mar 2025 20:19:57 +0100
Subject: [PATCH] [clang] Placement new error when modifying consts
Raise an error when placement new is used to modify a const-qualified
variable in a constexpr function.
---
clang/lib/AST/ExprConstant.cpp | 9 ++++++
clang/test/AST/ByteCode/placement-new.cpp | 39 +++++++++++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 92a28897cf3ee..b4fc3d4471064 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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;
diff --git a/clang/test/AST/ByteCode/placement-new.cpp b/clang/test/AST/ByteCode/placement-new.cpp
index c353162a7aab0..9b12c9f2b1714 100644
--- a/clang/test/AST/ByteCode/placement-new.cpp
+++ b/clang/test/AST/ByteCode/placement-new.cpp
@@ -376,3 +376,42 @@ constexpr int N = [] // expected-error {{must be initialized by a constant expre
return s.a[0];
}();
#endif
+
+constexpr int modify_const_variable() {
+ const int a = 10;
+ new ((int *)&a) int(12); // both-note {{modification of object of const-qualified type 'const int' is not allowed in a constant expression}}
+ return a;
+}
+static_assert(modify_const_variable()); // both-error {{not an integral constant expression}} \
+ // both-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); // both-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()); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+template<typename T>
+constexpr T modify_const_variable_tmpl() {
+ T a = 10;
+ new ((int *)&a) int(12); // both-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>()); // both-error {{not an integral constant expression}} \
+ // both-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);
+}
More information about the cfe-commits
mailing list