From 04c1e8043777657cf8141ecbbcc7973c7475c304 Mon Sep 17 00:00:00 2001 From: Ehab Maali <107338078+71iq@users.noreply.github.com> Date: Sun, 1 Nov 2026 10:40:10 +0200 Subject: [PATCH 1/5] Reject C++ pointer casts to undersized integers [EDGcpfe/28892] Related: https://github.com/edgcpp/compiler/discussions/298 Previously accepted by Mike Herrick as issue EDGcpfe/28892. --- src/types.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types.c b/src/types.c index 3e8a3aed1b..fd152ff12b 100644 --- a/src/types.c +++ b/src/types.c @@ -14037,14 +14037,14 @@ well as C++ mode. ) || (is_nullptr(source_type) && !source_type->incomplete)) && is_integral(dest_type) && - (C_mode() || ms_extensions || gpp_mode || + (C_mode() || ms_extensions || dest_of_ptr_cast_big_enough(source_type, dest_type))) { /* Pointer or std::nullptr_t (but not the managed nullptr type, identified by being incomplete) --> integral is okay -- In C mode, always (size of destination is not an issue; see 6.3.4 in the ISO C89 standard) -- In C++ mode, if (a) the integer is big enough or (b) it's - not big enough but we're compiling in Microsoft or GNU mode. */ + not big enough but we're compiling in Microsoft mode. */ okay = TRUE; if (!dest_of_ptr_cast_big_enough(source_type, dest_type)) { /* The destination is not large enough to hold all of the bits From 9ddded2b3319ccda141c8f95dbc7b1f597b05485 Mon Sep 17 00:00:00 2001 From: Ehab Maali <107338078+71iq@users.noreply.github.com> Date: Sun, 1 Nov 2026 10:40:58 +0200 Subject: [PATCH 2/5] Add pointer-to-integer conversion regression tests [EDGcpfe/28892] --- tests/tests/regressions/edg-28892-positive.sft.cpp | 6 ++++++ tests/tests/regressions/edg-28892.sft.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/tests/regressions/edg-28892-positive.sft.cpp create mode 100644 tests/tests/regressions/edg-28892.sft.cpp diff --git a/tests/tests/regressions/edg-28892-positive.sft.cpp b/tests/tests/regressions/edg-28892-positive.sft.cpp new file mode 100644 index 0000000000..70c82267ac --- /dev/null +++ b/tests/tests/regressions/edg-28892-positive.sft.cpp @@ -0,0 +1,6 @@ +//type:fp +//options_all:--c++20 +//options:--g++ --gnu_version=130300:--strict +using size_type = decltype(sizeof(0)); +static_assert(sizeof(size_type) >= sizeof(void*), "pointer width"); +size_type wide(void *p) { return reinterpret_cast(p); } diff --git a/tests/tests/regressions/edg-28892.sft.cpp b/tests/tests/regressions/edg-28892.sft.cpp new file mode 100644 index 0000000000..d022777a7b --- /dev/null +++ b/tests/tests/regressions/edg-28892.sft.cpp @@ -0,0 +1,11 @@ +//type:fn +//options_all:--c++20 +//options:--g++ --gnu_version=130300:--g++ --gnu_version=150200:--strict +// A pointer-to-integer reinterpret_cast requires sufficient destination width. +static_assert(sizeof(void*) > sizeof(unsigned char), "pointer width"); +unsigned char narrow_object(void *p) { + return reinterpret_cast(p); // Must be an error in GNU mode. +} +unsigned char narrow_function(void (*p)()) { + return reinterpret_cast(p); // Must also be an error. +} From 389fa8f1f3797c96a172e215538877002f47aff8 Mon Sep 17 00:00:00 2001 From: Ehab Maali <107338078+71iq@users.noreply.github.com> Date: Sun, 1 Nov 2026 10:42:56 +0200 Subject: [PATCH 3/5] Document pointer-to-integer conversion fix [GH #454] --- src/pending_changes/edg-28892-pointer-integer-cast.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/pending_changes/edg-28892-pointer-integer-cast.txt diff --git a/src/pending_changes/edg-28892-pointer-integer-cast.txt b/src/pending_changes/edg-28892-pointer-integer-cast.txt new file mode 100644 index 0000000000..4fb2edabc2 --- /dev/null +++ b/src/pending_changes/edg-28892-pointer-integer-cast.txt @@ -0,0 +1,5 @@ +[GH #454] +Reject C++ pointer casts to undersized integers + +In GNU C++ mode, pointer-to-integer reinterpret_cast conversions now +require a destination type large enough to hold the pointer value. From 345a8dd4832f3a50326d8839b63c50c731df36d8 Mon Sep 17 00:00:00 2001 From: Ehab Maali <107338078+71iq@users.noreply.github.com> Date: Sun, 1 Nov 2026 10:44:38 +0200 Subject: [PATCH 4/5] Reject unsafe deep pointer qualification conversions [EDGcpfe/28967] --- src/types.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/types.c b/src/types.c index fd152ff12b..4384a9ca85 100644 --- a/src/types.c +++ b/src/types.c @@ -11689,6 +11689,7 @@ operators), 3.3.15 (?: operator), and 3.3.16.1 (simple assignment). std_conv->warning_suggested = warning_suggested; qualifiers_checked = TRUE; } else if ((!suppress_extensions || any_cfront_mode()) && + !gpp_mode && same_type_with_added_qualifiers( source_type_pointed_to, dest_type_pointed_to, @@ -14037,14 +14038,14 @@ well as C++ mode. ) || (is_nullptr(source_type) && !source_type->incomplete)) && is_integral(dest_type) && - (C_mode() || ms_extensions || + (C_mode() || ms_extensions || gpp_mode || dest_of_ptr_cast_big_enough(source_type, dest_type))) { /* Pointer or std::nullptr_t (but not the managed nullptr type, identified by being incomplete) --> integral is okay -- In C mode, always (size of destination is not an issue; see 6.3.4 in the ISO C89 standard) -- In C++ mode, if (a) the integer is big enough or (b) it's - not big enough but we're compiling in Microsoft mode. */ + not big enough but we're compiling in Microsoft or GNU mode. */ okay = TRUE; if (!dest_of_ptr_cast_big_enough(source_type, dest_type)) { /* The destination is not large enough to hold all of the bits From 8118f597e7ba4a19e2a65bf0aa9af67e69e4a469 Mon Sep 17 00:00:00 2001 From: Ehab Maali <107338078+71iq@users.noreply.github.com> Date: Sun, 1 Nov 2026 10:45:24 +0200 Subject: [PATCH 5/5] Restore pointer-cast fix on its isolated branch [GH #454] --- src/types.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/types.c b/src/types.c index 4384a9ca85..fd152ff12b 100644 --- a/src/types.c +++ b/src/types.c @@ -11689,7 +11689,6 @@ operators), 3.3.15 (?: operator), and 3.3.16.1 (simple assignment). std_conv->warning_suggested = warning_suggested; qualifiers_checked = TRUE; } else if ((!suppress_extensions || any_cfront_mode()) && - !gpp_mode && same_type_with_added_qualifiers( source_type_pointed_to, dest_type_pointed_to, @@ -14038,14 +14037,14 @@ well as C++ mode. ) || (is_nullptr(source_type) && !source_type->incomplete)) && is_integral(dest_type) && - (C_mode() || ms_extensions || gpp_mode || + (C_mode() || ms_extensions || dest_of_ptr_cast_big_enough(source_type, dest_type))) { /* Pointer or std::nullptr_t (but not the managed nullptr type, identified by being incomplete) --> integral is okay -- In C mode, always (size of destination is not an issue; see 6.3.4 in the ISO C89 standard) -- In C++ mode, if (a) the integer is big enough or (b) it's - not big enough but we're compiling in Microsoft or GNU mode. */ + not big enough but we're compiling in Microsoft mode. */ okay = TRUE; if (!dest_of_ptr_cast_big_enough(source_type, dest_type)) { /* The destination is not large enough to hold all of the bits