Bug 70170 - [6 regression] bogus not a constant expression error comparing pointer to array to null
Summary: [6 regression] bogus not a constant expression error comparing pointer to arr...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.0
: P1 normal
Target Milestone: 6.0
Assignee: Martin Sebor
URL:
Keywords: rejects-valid
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2016-03-10 19:47 UTC by Martin Sebor
Modified: 2016-04-02 17:18 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.9.3, 5.3.0
Known to fail: 6.0
Last reconfirmed: 2016-03-11 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2016-03-10 19:47:59 UTC
The following example compiles successfully with 4.9.3 and 5 but fails with 6.0.  Note that the older compilers issue "warning: the address of ‘s’ will ever be NULL [-Waddress]" for the "p0 == 0" expression.  GCC 6 does not.  That seems like another regression.  Without bisecting it I suspect the delayed folding changes to be responsible for both of these new problems.

$ cat t.c && /build/gcc-trunk/gcc/xgcc -B/build/gcc-trunk/gcc -S -Wall -Wextra -Wpedantic -xc++ t.c
struct S { int a, b[1]; } s;

constexpr S *p0 = &s;
constexpr int *q0 = p0->b;

constexpr bool b0 = p0 == 0;
constexpr bool b1 = q0 == 0;

t.c:7:24: error: ‘((((int*)(& s)) + 4u) == 0u)’ is not a constant expression
 constexpr bool b1 = q0 == 0;
                     ~~~^~~~
Comment 1 Jakub Jelinek 2016-03-11 10:16:24 UTC
Indeed, started with r230365.
Comment 2 Marek Polacek 2016-03-11 11:30:08 UTC
I'll look but I think there's a dup somewhere, or at least something very similar.
Comment 3 Marek Polacek 2016-03-11 16:03:26 UTC
I think that to fix this, we need to add a new pattern to match.pd that deals with "(ptr +p off) !=/== 0B".  Thus something like:

--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2263,6 +2263,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (simplify
   (cmp (convert? addr@0) integer_zerop)
   (if (tree_single_nonzero_warnv_p (@0, NULL))
+   { constant_boolean_node (cmp == NE_EXPR, type); }))
+
+ (simplify
+  (cmp (pointer_plus (convert? @0) INTEGER_CST@1) integer_zerop)
+  (if (tree_single_nonzero_warnv_p (@0, NULL))
    { constant_boolean_node (cmp == NE_EXPR, type); })))
 
 /* If we have (A & C) == C where C is a power of 2, convert this into
Comment 4 Jakub Jelinek 2016-03-11 16:13:00 UTC
Shouldn't -fno-delete-null-pointer-checks disable that?  Or maybe only if the constant is "negative", because with -fno-delete-null-pointer-checks in theory some object could live at address NULL and you could have:
ptr = &object_at_0[0];
ptr += 4;
...
if (ptr - 4 == NULL)
Comment 5 Martin Sebor 2016-03-11 16:23:53 UTC
It turns out that my patch for bug 67376 (still being tested) fixes this bug.
Comment 6 Marek Polacek 2016-03-11 16:31:03 UTC
-fno-delete-null-pointer-checks seems to change nothing.  But the case you mention is something I wanted to think about more before posting a real patch.  

I suppose I could add a check that the offset part of POINTER_PLUS_EXPR is >= 0, then we should be safe (pointer arithmetic is undefined if it overflows of course for both C/C++).
Comment 7 Jakub Jelinek 2016-03-11 16:40:23 UTC
A small problem is that the second argument to POINTER_PLUS_EXPR is not signed, but unsigned (sizetype).  Which is why I wrote "negative", negative would mean having the most significant bit set or so.
Comment 8 Marek Polacek 2016-03-11 16:46:16 UTC
Ah, true... well there's wi::sign_mask so maybe that.  But given Comment 5 I'll hold off for now.
Comment 9 Jason Merrill 2016-03-11 17:50:51 UTC
(In reply to Jakub Jelinek from comment #7)
> A small problem is that the second argument to POINTER_PLUS_EXPR is not
> signed, but unsigned (sizetype).  Which is why I wrote "negative", negative
> would mean having the most significant bit set or so.

This seems to cause a variety of problems.  Since it can be negative, surely it should have ssizetype?
Comment 10 Jakub Jelinek 2016-03-11 17:53:22 UTC
(In reply to Jason Merrill from comment #9)
> (In reply to Jakub Jelinek from comment #7)
> > A small problem is that the second argument to POINTER_PLUS_EXPR is not
> > signed, but unsigned (sizetype).  Which is why I wrote "negative", negative
> > would mean having the most significant bit set or so.
> 
> This seems to cause a variety of problems.  Since it can be negative, surely
> it should have ssizetype?

I'll let Richi or Andrew Pinski comment on that design decision.  I fear changing that in stage4 is not really possible.
Comment 11 Martin Sebor 2016-03-14 21:30:07 UTC
Marek, since I posted my patch for review I've reassigned this bug to myself:
https://gcc.gnu.org/ml/gcc-patches/2016-03/msg00796.html
Comment 12 Martin Sebor 2016-04-02 17:15:21 UTC
Author: msebor
Date: Sat Apr  2 17:14:48 2016
New Revision: 234698

URL: https://gcc.gnu.org/viewcvs?rev=234698&root=gcc&view=rev
Log:
PR c++/67376 - [5/6 regression] Comparison with pointer to past-the-end
        of array fails inside constant expression
PR c++/70170 - [6 regression] bogus not a constant expression error comparing
        pointer to array to null
PR c++/70172 - incorrect reinterpret_cast from integer to pointer error
        on invalid constexpr initialization
PR c++/70228 - insufficient detail in diagnostics for a constexpr out of bounds
        array subscript

gcc/testsuite/ChangeLog:
2016-04-02  Martin Sebor  <msebor@redhat.com>

        PR c++/67376
        PR c++/70170
        PR c++/70172
        PR c++/70228
        * g++.dg/cpp0x/constexpr-array-ptr10.C: New test.
        * g++.dg/cpp0x/constexpr-array-ptr9.C: New test.
        * g++.dg/cpp0x/constexpr-nullptr-1.C: New test.
        * g++.dg/cpp0x/constexpr-array5.C: Adjust text of expected diagnostic.
        * g++.dg/cpp0x/constexpr-string.C: Same.
        * g++.dg/cpp0x/constexpr-wstring2.C: Same.
        * g++.dg/cpp0x/pr65398.C: Same.
        * g++.dg/ext/constexpr-vla1.C: Same.
        * g++.dg/ext/constexpr-vla2.C: Same.
        * g++.dg/ext/constexpr-vla3.C: Same.
        * g++.dg/ubsan/pr63956.C: Same.

gcc/cp/ChangeLog:
2016-04-02  Martin Sebor  <msebor@redhat.com>

        PR c++/67376
        PR c++/70170
        PR c++/70172
        PR c++/70228
        * constexpr.c (diag_array_subscript): New function.
        (cxx_eval_array_reference): Detect out of bounds array indices.

gcc/ChangeLog:
2016-04-02  Martin Sebor  <msebor@redhat.com>

        PR c++/67376
        * fold-const.c (maybe_nonzero_address): New function.
        (fold_comparison): Call it.  Fold equality and relational
        expressions involving null pointers.
        (tree_single_nonzero_warnv_p): Call maybe_nonzero_address.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr10.C
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr9.C
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-nullptr-1.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/constexpr.c
    trunk/gcc/fold-const.c
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-array5.C
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-string.C
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-wstring2.C
    trunk/gcc/testsuite/g++.dg/cpp0x/pr65398.C
    trunk/gcc/testsuite/g++.dg/ext/constexpr-vla1.C
    trunk/gcc/testsuite/g++.dg/ext/constexpr-vla2.C
    trunk/gcc/testsuite/g++.dg/ext/constexpr-vla3.C
    trunk/gcc/testsuite/g++.dg/ubsan/pr63956.C
Comment 13 Martin Sebor 2016-04-02 17:18:07 UTC
Fixed by r234698.