https://github.com/mariusdr updated https://github.com/llvm/llvm-project/pull/132460
>From d4af25b14fb21f50c3771cce4595ca5c1bb920a7 Mon Sep 17 00:00:00 2001 From: marius doerner <mariu...@users.noreply.github.com> Date: Fri, 21 Mar 2025 20:19:57 +0100 Subject: [PATCH 1/3] [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); +} >From 197063860b652ba93ee3baab8b6213bb5dc809de Mon Sep 17 00:00:00 2001 From: marius doerner <mariu...@users.noreply.github.com> Date: Sun, 23 Mar 2025 09:21:34 +0100 Subject: [PATCH 2/3] Move tests from Ast/Bytecode to SemaCxx --- clang/test/AST/ByteCode/placement-new.cpp | 39 ------------------- .../SemaCXX/cxx2c-constexpr-placement-new.cpp | 39 +++++++++++++++++++ 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/clang/test/AST/ByteCode/placement-new.cpp b/clang/test/AST/ByteCode/placement-new.cpp index 9b12c9f2b1714..c353162a7aab0 100644 --- a/clang/test/AST/ByteCode/placement-new.cpp +++ b/clang/test/AST/ByteCode/placement-new.cpp @@ -376,42 +376,3 @@ 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); -} diff --git a/clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp b/clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp index a29fb981cedbf..6f6f9b04aa392 100644 --- a/clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp +++ b/clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp @@ -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); +} >From ad8592bc81f07b93e70e6abd5db2755c84000732 Mon Sep 17 00:00:00 2001 From: marius doerner <mariu...@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:44:00 +0100 Subject: [PATCH 3/3] Add release notes. --- clang/docs/ReleaseNotes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 88862f7661191..62f3302b5e51b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 ^^^^^^^^^^^^^^^^^^^^^^^^^ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits