On 5/4/23 09:59, Richard Biener wrote:

I've previously sent
https://gcc.gnu.org/pipermail/gcc-patches/2022-December/608077.html
adding ADDR_EXPR_NONZERO and there were comments from Jason
where I just realized I ignored ARRAY_REF for the following.
Anyway, here's a more aggressive variant not going for an extra
flag set by the frontend but instead have the middle-end treat
all &*.component as non-NULL (all handled_component_p).

This passes bootstrap for all languages, testing there isn't
complete but it already shows for example
gcc.c-torture/execute/pr44555.c explicitely testing that
we keep &p->z NULL when p is NULL and z is at offset zero.

There's also execute FAILs for gfortran.dg/class_optional_2.f90
and some optimization dump scan fails I did not yet investigate.

Nevertheless I'd like to hear opinions on whether a middle-end
implementation without frontend help is the way to go and
what the reasonable restrictions should be there?  Is
gcc.c-torture/execute/pr44555.c sanctioned by the C standard?
If so I think we have a lost cause without some help from
the frontend?

The relevant C++ rule is https://eel.is/c++draft/expr.ref#8

The corresponding C clause doesn't have as explicit a rule that I can see, I don't know what the sense of the C committee is about this. The special allowance for the common initial sequence suggests such that it is an exception to such a rule, but I'm not sure where that rule is, exactly.

I imagine that not all languages are as strict about this, so an unconditional rule like this may not be what we want.

And as I think I commented before, this kind of assumption based on undefined behavior ought to have a -fsanitize=undefined check.

Thanks,
Richard.


--

The following avoids a bogus -Wstringop-overflow diagnostic by
properly recognizing that &d->m_mutex cannot be nullptr
even if m_mutex is at offset zero.  The C++ frontend already diagnoses
a &d->m_mutex != nullptr comparison and the following transfers
this knowledge to the middle-end in the most general way.

To avoid the bogus diagnostic this avoids separating the nullptr
path via jump-threading by eliminating the nullptr check.

        PR tree-optimization/104475
        * fold-const.cc (tree_single_nonzero_warnv_p): An ADDR_EXPR
        of a component reference can never be null.

        * g++.dg/opt/pr104475.C: New testcase.
---
  gcc/fold-const.cc                   | 11 ++++++++++-
  gcc/testsuite/g++.dg/opt/pr104475.C | 12 ++++++++++++
  2 files changed, 22 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/opt/pr104475.C

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index db54bfc5662..c5c923e059d 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -15368,7 +15368,16 @@ tree_single_nonzero_warnv_p (tree t, bool 
*strict_overflow_p)
        tree base = TREE_OPERAND (t, 0);
if (!DECL_P (base))
-         base = get_base_address (base);
+         {
+           gcc_checking_assert (TREE_CODE (base) != WITH_SIZE_EXPR);
+           /* Any component reference, even if at offset zero, requires
+              a non-null base.  */
+           if (handled_component_p (base)
+               && !targetm.addr_space.zero_address_valid
+                     (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (t)))))
+             return true;
+           base = get_base_address (base);
+         }
if (base && TREE_CODE (base) == TARGET_EXPR)
          base = TARGET_EXPR_SLOT (base);
diff --git a/gcc/testsuite/g++.dg/opt/pr104475.C 
b/gcc/testsuite/g++.dg/opt/pr104475.C
new file mode 100644
index 00000000000..013c70302c6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr104475.C
@@ -0,0 +1,12 @@
+// { dg-do compile }
+// { dg-require-effective-target c++11 }
+// { dg-options "-O -Waddress -fdump-tree-original" }
+
+struct X { int i; };
+
+bool foo (struct X *p)
+{
+  return &p->i != nullptr; /* { dg-warning "never be NULL" } */
+}
+
+/* { dg-final { scan-tree-dump "return <retval> = 1;" "original" } } */

Reply via email to