On 7/2/25 7:58 PM, Patrick Palka wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk?
-- >8 --
Here the flag -fno-delete-null-pointer-checks causes the trivial address
comparison in
inline int a, b;
static_assert(&a != &b);
to be rejected as non-constant because with the flag we can't assume
such weak symbols are non-NULL, which causes symtab/fold-const.cc to
punt on such comparisons. Note this also affects -fsanitize=undefined
since it implies -fno-delete-null-pointer-checks.
Right, the underlying problem is that we use the one flag to mean two
things:
1) a static storage duration decl can live at address 0
2) do more careful checking for null pointers/lvalues (i.e. in
gimple_call_nonnull_result_p)
Both cases are related to checking for null, but they are different
situations and really shouldn't depend on the same flag.
Your patch seems wrong for #1 targets; on such a target 'a' might end up
allocated at address 0, so "&a != nullptr" is not decidable at compile time.
OTOH such targets are a small minority, and I suspect they already have
other C++ issues with e.g. a conversion to base not adjusting a null
pointer.
Jakub, what do you think? It's been 9 years since you proposed a better
fix in the PR, but that hasn't happened yet.
This issue seems conceptually the same as PR96862 which was about
-frounding-math breaking some constexpr floating point arithmetic,
and we fixed that PR by disabling -frounding-math during manifestly
constant evaluation. This patch proposes to do the same for
-fno-delete-null-pointer-checks, disabling it during maniestly constant
evaluation. I opted to disable it narrowly around the relevant
fold_binary call which seems to address all reported constexpr failures,
but we could consider it disabling it more broadly as well.
PR c++/71962
gcc/cp/ChangeLog:
* constexpr.cc (cxx_eval_binary_expression): Set
flag_delete_null_pointer_checks alongside folding_cxx_constexpr
during manifestly constant evaluation.
gcc/testsuite/ChangeLog:
* g++.dg/ext/constexpr-pr71962.C: New test.
* g++.dg/ubsan/pr71962.C: New test.
---
gcc/cp/constexpr.cc | 2 ++
gcc/testsuite/g++.dg/ext/constexpr-pr71962.C | 18 ++++++++++++++++++
gcc/testsuite/g++.dg/ubsan/pr71962.C | 5 +++++
3 files changed, 25 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/ext/constexpr-pr71962.C
create mode 100644 gcc/testsuite/g++.dg/ubsan/pr71962.C
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 704d936f2ec3..e8426b40c543 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -4068,6 +4068,8 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx,
tree t,
|| TREE_CODE (type) != REAL_TYPE))
{
auto ofcc = make_temp_override (folding_cxx_constexpr, true);
+ auto odnpc = make_temp_override (flag_delete_null_pointer_checks,
+ true);
r = fold_binary_initializer_loc (loc, code, type, lhs, rhs);
}
else
diff --git a/gcc/testsuite/g++.dg/ext/constexpr-pr71962.C
b/gcc/testsuite/g++.dg/ext/constexpr-pr71962.C
new file mode 100644
index 000000000000..57cb14ac804e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/constexpr-pr71962.C
@@ -0,0 +1,18 @@
+// PR c++/71962
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fno-delete-null-pointer-checks" }
+
+struct A { void f(); };
+static_assert(&A::f != nullptr, "");
+
+#if __cpp_inline_variables
+inline int a, b;
+static_assert(&a != &b, "");
+static_assert(&a != nullptr, "");
+#endif
+
+int main() {
+ static int x, y;
+ static_assert(&x != &y, "");
+ static_assert(&x != nullptr, "");
+}
diff --git a/gcc/testsuite/g++.dg/ubsan/pr71962.C
b/gcc/testsuite/g++.dg/ubsan/pr71962.C
new file mode 100644
index 000000000000..f17c825da449
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr71962.C
@@ -0,0 +1,5 @@
+// PR c++/71962
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fsanitize=undefined" }
+
+#include "../ext/constexpr-pr71962.C"