[clang] [clang] Placement new error when modifying consts (PR #132460)
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 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 +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()); // 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 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 -constexpr T modify_const_variable_tmpl() { - T a = 10; - n
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
https://github.com/mariusdr edited https://github.com/llvm/llvm-project/pull/133574 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Placement new error when modifying consts (PR #132460)
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 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 +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()); // 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); +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Placement new error when modifying consts (PR #132460)
mariusdr wrote: > Thanks. Will you need me to merge that for you? Yes, please https://github.com/llvm/llvm-project/pull/132460 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
https://github.com/mariusdr edited https://github.com/llvm/llvm-project/pull/133574 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
https://github.com/mariusdr edited https://github.com/llvm/llvm-project/pull/133574 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
https://github.com/mariusdr updated https://github.com/llvm/llvm-project/pull/133574 >From dd54aa59eabe9c3b7b110f46d82ff5c4d0b88c57 Mon Sep 17 00:00:00 2001 From: marius doerner Date: Sat, 29 Mar 2025 09:21:20 +0100 Subject: [PATCH 1/2] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` After builtin macro expansion in `Preprocessor::ExpandBuiltinMacro` the result token may have the `Token::NeedsCleaning` flag set which causes an assertion failure later on when the lexer retrives the spelling of the token in `getSpellingSlow` in Lexer.cpp. --- clang/lib/Lex/PPMacroExpansion.cpp | 2 +- clang/test/Preprocessor/embed___has_embed.c | 19 clang/test/Preprocessor/has_attribute.c | 20 + clang/test/Preprocessor/has_attribute.cpp | 20 + clang/test/Preprocessor/has_c_attribute.c | 20 + clang/test/Preprocessor/has_include.c | 49 + 6 files changed, 129 insertions(+), 1 deletion(-) diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 8e35d56d3f1a6..107d5c31e039d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1646,7 +1646,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Set up the return result. Tok.setIdentifierInfo(nullptr); - Tok.clearFlag(Token::NeedsCleaning); bool IsAtStartOfLine = Tok.isAtStartOfLine(); bool HasLeadingSpace = Tok.hasLeadingSpace(); @@ -2089,6 +2088,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation()); Tok.setFlagValue(Token::StartOfLine, IsAtStartOfLine); Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace); + Tok.clearFlag(Token::NeedsCleaning); } void Preprocessor::markMacroAsUsed(MacroInfo *MI) { diff --git a/clang/test/Preprocessor/embed___has_embed.c b/clang/test/Preprocessor/embed___has_embed.c index 43a3068b5f53a..2705b5ef6fd5b 100644 --- a/clang/test/Preprocessor/embed___has_embed.c +++ b/clang/test/Preprocessor/embed___has_embed.c @@ -58,3 +58,22 @@ unsigned char buffer[] = { #else #error 17 #endif + +#if __has_embed(__FILE__\ +) +#else +#error 18 +#endif + +#define F __FI\ +LE__ +#if __has_embed(F) +#else +#error 19 +#endif + +#if __has_embed(F\ +) +#else +#error 20 +#endif diff --git a/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c index 0ba664a53e649..6f6f519bd299d 100644 --- a/clang/test/Preprocessor/has_attribute.c +++ b/clang/test/Preprocessor/has_attribute.c @@ -68,3 +68,23 @@ int has_no_volatile_attribute(); int has_fallthrough; #endif // CHECK: int has_fallthrough; + +#if __has_attribute(F\ +) +int has_fallthrough_2; +#endif +// CHECK: int has_fallthrough_2; + +#define F_2 fall\ +through + +#if __has_attribute(F_2) +int has_fallthrough_3; +#endif +// CHECK: int has_fallthrough_3; + +#if __has_attribute(F_2\ +) +int has_fallthrough_4; +#endif +// CHECK: int has_fallthrough_4; diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index 00ec57615c84b..72af6de27e8bb 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -116,6 +116,26 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_cpp_attribute(CF\ +) +int has_clang_falthrough_5; +#endif +// CHECK: int has_clang_falthrough_5; + +#define CF_2 clang::\ +fallthrough + +#if __has_cpp_attribute(CF_2) +int has_clang_falthrough_6; +#endif +// CHECK: int has_clang_falthrough_6; + +#if __has_cpp_attribute(CF_2\ +) +int has_clang_falthrough_7; +#endif +// CHECK: int has_clang_falthrough_7; } // Test for Microsoft __declspec attributes diff --git a/clang/test/Preprocessor/has_c_attribute.c b/clang/test/Preprocessor/has_c_attribute.c index 3332571d758c8..d8be13f5898a9 100644 --- a/clang/test/Preprocessor/has_c_attribute.c +++ b/clang/test/Preprocessor/has_c_attribute.c @@ -84,3 +84,23 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_c_attribute(CL\ +) +int has_clang_likely_5; +#endif +// CHECK: int has_clang_likely_5; + +#define CL_2 clang::\ +likely + +#if __has_c_attribute(CL_2) +int has_clang_likely_6; +#endif +// CHECK: int has_clang_likely_6; + +#if __has_c_attribute(CL_2\ +) +int has_clang_likely_7; +#endif +// CHECK: int has_clang_likely_7; diff --git a/clang/test/Preprocessor/has_include.c b/clang/test/Preprocessor/has_include.c index c95025d83860a..ff199bf23063f 100644 --- a/clang/test/Preprocessor/has_include.c +++ b/clang/test/Preprocessor/has_include.c @@ -197,3 +197,52 @@ __has_include #ifdef FOO #elif __has_include() #endif + +#if __has_include(\ +) +#else + #error "__has_include failed (10)." +#endif + +#define MACRO6 +#if __has_include(MACRO6\ +) +#else + #error "__has_include failed (11)." +#endif + +#if __has_include_next(/*expected-warning {{#include_next in primary source file}}*/\ +) +#else + #error "__has_
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
@@ -1646,7 +1646,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Set up the return result. Tok.setIdentifierInfo(nullptr); - Tok.clearFlag(Token::NeedsCleaning); mariusdr wrote: True, my bad. If the flag is removed we can get asserts on __DATE__ and __TIME__ expansion. I've put it back and added some test cases to account for this (also for some similar macros like __LINE__, __FILE__ which do not early return but are easily tested in the same way). https://github.com/llvm/llvm-project/pull/133574 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
https://github.com/mariusdr updated https://github.com/llvm/llvm-project/pull/133574 >From bcf038103c717edfdcf633ac8f3f6f1f306d927a Mon Sep 17 00:00:00 2001 From: marius doerner Date: Sat, 29 Mar 2025 09:21:20 +0100 Subject: [PATCH 1/3] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` After builtin macro expansion in `Preprocessor::ExpandBuiltinMacro` the result token may have the `Token::NeedsCleaning` flag set which causes an assertion failure later on when the lexer retrives the spelling of the token in `getSpellingSlow` in Lexer.cpp. --- clang/lib/Lex/PPMacroExpansion.cpp | 2 +- clang/test/Preprocessor/embed___has_embed.c | 19 clang/test/Preprocessor/has_attribute.c | 20 + clang/test/Preprocessor/has_attribute.cpp | 20 + clang/test/Preprocessor/has_c_attribute.c | 20 + clang/test/Preprocessor/has_include.c | 49 + 6 files changed, 129 insertions(+), 1 deletion(-) diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 8e35d56d3f1a6..107d5c31e039d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1646,7 +1646,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Set up the return result. Tok.setIdentifierInfo(nullptr); - Tok.clearFlag(Token::NeedsCleaning); bool IsAtStartOfLine = Tok.isAtStartOfLine(); bool HasLeadingSpace = Tok.hasLeadingSpace(); @@ -2089,6 +2088,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation()); Tok.setFlagValue(Token::StartOfLine, IsAtStartOfLine); Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace); + Tok.clearFlag(Token::NeedsCleaning); } void Preprocessor::markMacroAsUsed(MacroInfo *MI) { diff --git a/clang/test/Preprocessor/embed___has_embed.c b/clang/test/Preprocessor/embed___has_embed.c index 43a3068b5f53a..2705b5ef6fd5b 100644 --- a/clang/test/Preprocessor/embed___has_embed.c +++ b/clang/test/Preprocessor/embed___has_embed.c @@ -58,3 +58,22 @@ unsigned char buffer[] = { #else #error 17 #endif + +#if __has_embed(__FILE__\ +) +#else +#error 18 +#endif + +#define F __FI\ +LE__ +#if __has_embed(F) +#else +#error 19 +#endif + +#if __has_embed(F\ +) +#else +#error 20 +#endif diff --git a/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c index 0ba664a53e649..6f6f519bd299d 100644 --- a/clang/test/Preprocessor/has_attribute.c +++ b/clang/test/Preprocessor/has_attribute.c @@ -68,3 +68,23 @@ int has_no_volatile_attribute(); int has_fallthrough; #endif // CHECK: int has_fallthrough; + +#if __has_attribute(F\ +) +int has_fallthrough_2; +#endif +// CHECK: int has_fallthrough_2; + +#define F_2 fall\ +through + +#if __has_attribute(F_2) +int has_fallthrough_3; +#endif +// CHECK: int has_fallthrough_3; + +#if __has_attribute(F_2\ +) +int has_fallthrough_4; +#endif +// CHECK: int has_fallthrough_4; diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index 00ec57615c84b..72af6de27e8bb 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -116,6 +116,26 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_cpp_attribute(CF\ +) +int has_clang_falthrough_5; +#endif +// CHECK: int has_clang_falthrough_5; + +#define CF_2 clang::\ +fallthrough + +#if __has_cpp_attribute(CF_2) +int has_clang_falthrough_6; +#endif +// CHECK: int has_clang_falthrough_6; + +#if __has_cpp_attribute(CF_2\ +) +int has_clang_falthrough_7; +#endif +// CHECK: int has_clang_falthrough_7; } // Test for Microsoft __declspec attributes diff --git a/clang/test/Preprocessor/has_c_attribute.c b/clang/test/Preprocessor/has_c_attribute.c index 3332571d758c8..d8be13f5898a9 100644 --- a/clang/test/Preprocessor/has_c_attribute.c +++ b/clang/test/Preprocessor/has_c_attribute.c @@ -84,3 +84,23 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_c_attribute(CL\ +) +int has_clang_likely_5; +#endif +// CHECK: int has_clang_likely_5; + +#define CL_2 clang::\ +likely + +#if __has_c_attribute(CL_2) +int has_clang_likely_6; +#endif +// CHECK: int has_clang_likely_6; + +#if __has_c_attribute(CL_2\ +) +int has_clang_likely_7; +#endif +// CHECK: int has_clang_likely_7; diff --git a/clang/test/Preprocessor/has_include.c b/clang/test/Preprocessor/has_include.c index c95025d83860a..ff199bf23063f 100644 --- a/clang/test/Preprocessor/has_include.c +++ b/clang/test/Preprocessor/has_include.c @@ -197,3 +197,52 @@ __has_include #ifdef FOO #elif __has_include() #endif + +#if __has_include(\ +) +#else + #error "__has_include failed (10)." +#endif + +#define MACRO6 +#if __has_include(MACRO6\ +) +#else + #error "__has_include failed (11)." +#endif + +#if __has_include_next(/*expected-warning {{#include_next in primary source file}}*/\ +) +#else + #error "__has_
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
mariusdr wrote: > LGTM - sorry for the delayed response. > > Will you need me to merge that for you (once the merge conflict is resolved)? Yes, thanks! https://github.com/llvm/llvm-project/pull/133574 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Placement new error when modifying consts (PR #132460)
mariusdr wrote: Added release notes under "Bug Fixes to C++ Support". Thanks for the review. https://github.com/llvm/llvm-project/pull/132460 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Placement new error when modifying consts (PR #132460)
mariusdr wrote: > The tests should go into a file not under `ByteCode/` since they aren't > specific to the bytecode interpreter. There should be existing placement new > tests in `SemaCXX/`. Thanks for the hint, moved them to clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp https://github.com/llvm/llvm-project/pull/132460 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Placement new error when modifying consts (PR #132460)
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 Date: Fri, 21 Mar 2025 20:19:57 +0100 Subject: [PATCH 1/2] [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 +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()); // 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 b596108cb5f66f81bdc1a0809f91cfa9b4dad0a6 Mon Sep 17 00:00:00 2001 From: marius doerner Date: Sun, 23 Mar 2025 09:21:34 +0100 Subject: [PATCH 2/2] 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 -constexpr T modify_const_variable_tmpl() { - T a = 10; - n
[clang] [clang] Placement new error when modifying consts (PR #132460)
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 Date: Fri, 21 Mar 2025 20:19:57 +0100 Subject: [PATCH 1/2] [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 +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()); // 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 Date: Sun, 23 Mar 2025 09:21:34 +0100 Subject: [PATCH 2/2] 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 -constexpr T modify_const_variable_tmpl() { - T a = 10; - n
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
https://github.com/mariusdr updated https://github.com/llvm/llvm-project/pull/133574 >From dd54aa59eabe9c3b7b110f46d82ff5c4d0b88c57 Mon Sep 17 00:00:00 2001 From: marius doerner Date: Sat, 29 Mar 2025 09:21:20 +0100 Subject: [PATCH] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` After builtin macro expansion in `Preprocessor::ExpandBuiltinMacro` the result token may have the `Token::NeedsCleaning` flag set which causes an assertion failure later on when the lexer retrives the spelling of the token in `getSpellingSlow` in Lexer.cpp. --- clang/lib/Lex/PPMacroExpansion.cpp | 2 +- clang/test/Preprocessor/embed___has_embed.c | 19 clang/test/Preprocessor/has_attribute.c | 20 + clang/test/Preprocessor/has_attribute.cpp | 20 + clang/test/Preprocessor/has_c_attribute.c | 20 + clang/test/Preprocessor/has_include.c | 49 + 6 files changed, 129 insertions(+), 1 deletion(-) diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 8e35d56d3f1a6..107d5c31e039d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1646,7 +1646,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Set up the return result. Tok.setIdentifierInfo(nullptr); - Tok.clearFlag(Token::NeedsCleaning); bool IsAtStartOfLine = Tok.isAtStartOfLine(); bool HasLeadingSpace = Tok.hasLeadingSpace(); @@ -2089,6 +2088,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation()); Tok.setFlagValue(Token::StartOfLine, IsAtStartOfLine); Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace); + Tok.clearFlag(Token::NeedsCleaning); } void Preprocessor::markMacroAsUsed(MacroInfo *MI) { diff --git a/clang/test/Preprocessor/embed___has_embed.c b/clang/test/Preprocessor/embed___has_embed.c index 43a3068b5f53a..2705b5ef6fd5b 100644 --- a/clang/test/Preprocessor/embed___has_embed.c +++ b/clang/test/Preprocessor/embed___has_embed.c @@ -58,3 +58,22 @@ unsigned char buffer[] = { #else #error 17 #endif + +#if __has_embed(__FILE__\ +) +#else +#error 18 +#endif + +#define F __FI\ +LE__ +#if __has_embed(F) +#else +#error 19 +#endif + +#if __has_embed(F\ +) +#else +#error 20 +#endif diff --git a/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c index 0ba664a53e649..6f6f519bd299d 100644 --- a/clang/test/Preprocessor/has_attribute.c +++ b/clang/test/Preprocessor/has_attribute.c @@ -68,3 +68,23 @@ int has_no_volatile_attribute(); int has_fallthrough; #endif // CHECK: int has_fallthrough; + +#if __has_attribute(F\ +) +int has_fallthrough_2; +#endif +// CHECK: int has_fallthrough_2; + +#define F_2 fall\ +through + +#if __has_attribute(F_2) +int has_fallthrough_3; +#endif +// CHECK: int has_fallthrough_3; + +#if __has_attribute(F_2\ +) +int has_fallthrough_4; +#endif +// CHECK: int has_fallthrough_4; diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index 00ec57615c84b..72af6de27e8bb 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -116,6 +116,26 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_cpp_attribute(CF\ +) +int has_clang_falthrough_5; +#endif +// CHECK: int has_clang_falthrough_5; + +#define CF_2 clang::\ +fallthrough + +#if __has_cpp_attribute(CF_2) +int has_clang_falthrough_6; +#endif +// CHECK: int has_clang_falthrough_6; + +#if __has_cpp_attribute(CF_2\ +) +int has_clang_falthrough_7; +#endif +// CHECK: int has_clang_falthrough_7; } // Test for Microsoft __declspec attributes diff --git a/clang/test/Preprocessor/has_c_attribute.c b/clang/test/Preprocessor/has_c_attribute.c index 3332571d758c8..d8be13f5898a9 100644 --- a/clang/test/Preprocessor/has_c_attribute.c +++ b/clang/test/Preprocessor/has_c_attribute.c @@ -84,3 +84,23 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_c_attribute(CL\ +) +int has_clang_likely_5; +#endif +// CHECK: int has_clang_likely_5; + +#define CL_2 clang::\ +likely + +#if __has_c_attribute(CL_2) +int has_clang_likely_6; +#endif +// CHECK: int has_clang_likely_6; + +#if __has_c_attribute(CL_2\ +) +int has_clang_likely_7; +#endif +// CHECK: int has_clang_likely_7; diff --git a/clang/test/Preprocessor/has_include.c b/clang/test/Preprocessor/has_include.c index c95025d83860a..ff199bf23063f 100644 --- a/clang/test/Preprocessor/has_include.c +++ b/clang/test/Preprocessor/has_include.c @@ -197,3 +197,52 @@ __has_include #ifdef FOO #elif __has_include() #endif + +#if __has_include(\ +) +#else + #error "__has_include failed (10)." +#endif + +#define MACRO6 +#if __has_include(MACRO6\ +) +#else + #error "__has_include failed (11)." +#endif + +#if __has_include_next(/*expected-warning {{#include_next in primary source file}}*/\ +) +#else + #error "__has_inclu
[clang] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` (PR #133574)
https://github.com/mariusdr created https://github.com/llvm/llvm-project/pull/133574 After builtin macro expansion in `Preprocessor::ExpandBuiltinMacro` the result token may have the `Token::NeedsCleaning` flag set which causes an assertion failure later on when the lexer retrieves the spelling of the token in `getSpellingSlow`. This commit moves the `Tok.clearFlag(Token::NeedsCleaning)` call to the end of `ExpandBuiltinMacro`. Closes #128384 >From ae2279bb0fa44ff290a3305b90598caf60284066 Mon Sep 17 00:00:00 2001 From: marius doerner Date: Sat, 29 Mar 2025 09:21:20 +0100 Subject: [PATCH] [clang] Clear `NeedsCleaning` flag after `ExpandBuiltinMacro` After builtin macro expansion in `Preprocessor::ExpandBuiltinMacro` the result token may have the `Token::NeedsCleaning` flag set which causes an assertion failure later on when the lexer retrives the spelling of the token in `getSpellingSlow` in Lexer.cpp. --- clang/lib/Lex/PPMacroExpansion.cpp | 2 +- clang/test/Preprocessor/embed___has_embed.c | 19 clang/test/Preprocessor/has_attribute.c | 20 + clang/test/Preprocessor/has_attribute.cpp | 20 + clang/test/Preprocessor/has_c_attribute.c | 20 + clang/test/Preprocessor/has_include.c | 49 + 6 files changed, 129 insertions(+), 1 deletion(-) diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 8e35d56d3f1a6..107d5c31e039d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1646,7 +1646,6 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Set up the return result. Tok.setIdentifierInfo(nullptr); - Tok.clearFlag(Token::NeedsCleaning); bool IsAtStartOfLine = Tok.isAtStartOfLine(); bool HasLeadingSpace = Tok.hasLeadingSpace(); @@ -2089,6 +2088,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation()); Tok.setFlagValue(Token::StartOfLine, IsAtStartOfLine); Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace); + Tok.clearFlag(Token::NeedsCleaning); } void Preprocessor::markMacroAsUsed(MacroInfo *MI) { diff --git a/clang/test/Preprocessor/embed___has_embed.c b/clang/test/Preprocessor/embed___has_embed.c index 43a3068b5f53a..2705b5ef6fd5b 100644 --- a/clang/test/Preprocessor/embed___has_embed.c +++ b/clang/test/Preprocessor/embed___has_embed.c @@ -58,3 +58,22 @@ unsigned char buffer[] = { #else #error 17 #endif + +#if __has_embed(__FILE__\ +) +#else +#error 18 +#endif + +#define F __FI\ +LE__ +#if __has_embed(F) +#else +#error 19 +#endif + +#if __has_embed(F\ +) +#else +#error 20 +#endif diff --git a/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c index 0ba664a53e649..6f6f519bd299d 100644 --- a/clang/test/Preprocessor/has_attribute.c +++ b/clang/test/Preprocessor/has_attribute.c @@ -68,3 +68,23 @@ int has_no_volatile_attribute(); int has_fallthrough; #endif // CHECK: int has_fallthrough; + +#if __has_attribute(F\ +) +int has_fallthrough_2; +#endif +// CHECK: int has_fallthrough_2; + +#define F_2 fall\ +through + +#if __has_attribute(F_2) +int has_fallthrough_3; +#endif +// CHECK: int has_fallthrough_3; + +#if __has_attribute(F_2\ +) +int has_fallthrough_4; +#endif +// CHECK: int has_fallthrough_4; diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp index 00ec57615c84b..72af6de27e8bb 100644 --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -116,6 +116,26 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_cpp_attribute(CF\ +) +int has_clang_falthrough_5; +#endif +// CHECK: int has_clang_falthrough_5; + +#define CF_2 clang::\ +fallthrough + +#if __has_cpp_attribute(CF_2) +int has_clang_falthrough_6; +#endif +// CHECK: int has_clang_falthrough_6; + +#if __has_cpp_attribute(CF_2\ +) +int has_clang_falthrough_7; +#endif +// CHECK: int has_clang_falthrough_7; } // Test for Microsoft __declspec attributes diff --git a/clang/test/Preprocessor/has_c_attribute.c b/clang/test/Preprocessor/has_c_attribute.c index 3332571d758c8..d8be13f5898a9 100644 --- a/clang/test/Preprocessor/has_c_attribute.c +++ b/clang/test/Preprocessor/has_c_attribute.c @@ -84,3 +84,23 @@ int funclike_1; int funclike_2; #endif // CHECK: int funclike_2; + +#if __has_c_attribute(CL\ +) +int has_clang_likely_5; +#endif +// CHECK: int has_clang_likely_5; + +#define CL_2 clang::\ +likely + +#if __has_c_attribute(CL_2) +int has_clang_likely_6; +#endif +// CHECK: int has_clang_likely_6; + +#if __has_c_attribute(CL_2\ +) +int has_clang_likely_7; +#endif +// CHECK: int has_clang_likely_7; diff --git a/clang/test/Preprocessor/has_include.c b/clang/test/Preprocessor/has_include.c index c95025d83860a..ff199bf23063f 100644 --- a/clang/test/Preprocessor/has_include.c +++ b/clang/test/Preprocessor/has_include.c @@ -197,3 +19