Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-08-02 Thread Martin Sebor

On 08/02/2016 12:34 AM, Thomas Schwinge wrote:

Hi!

On Wed, 6 Jul 2016 16:20:44 -0600, Martin Sebor  wrote:

PR c++/60760 - arithmetic on null pointers should not be allowed in constant
   expressions
PR c++/71091 - constexpr reference bound to a null pointer dereference
accepted

[...]
* g++.dg/cpp0x/constexpr-cast.C: New test.


In x86_64 GNU/Linux testing, I see that one FAIL for the -m32 multilib:

 +FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 
10)
 +FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 
11)
 +PASS: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 
24)
 +FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11 (test for excess errors)
 +XFAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11 bug c++/49171 (test for 
errors, line 8)
 +FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 
10)
 +FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 
11)
 +PASS: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 
24)
 +FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14 (test for excess errors)
 +XFAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14 bug c++/49171 (test for 
errors, line 8)
 +UNSUPPORTED: g++.dg/cpp0x/constexpr-cast.C  -std=c++98

 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:10:22: error: 
'reinterpret_cast(1)' is not a constant-expression
 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:11:22: error: 
'reinterpret_cast(1u)' is not a constant-expression
 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:26:   in 
constexpr expansion of 'f()'
 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:27: error: 
value '4u' of type 'int*' is not a constant expression

For the -m64 multilib, it looks as follows (all PASSes):

 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:10:47: error: 
value '1u' of type 'void*' is not a constant expression
 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:11:22: error: 
'reinterpret_cast(1ul)' is not a constant-expression
 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:26:   in 
constexpr expansion of 'f()'
 [...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:27: error: 
value '4u' of type 'int*' is not a constant expression


Thanks for pointing it out and for all the detail! I managed to run
into at least two problems with this change: one in the test assuming
that (void*)1 will appear in GCC diagnostics as 1ul, and another in
GCC due to the inconsistent spelling of "constant expression."  Some
errors hyphenate the words, others don't, and depending on which one
triggers a test that assumes one or the other will fail. Let me submit
a patch for this and CC you on it.

Martin



For reference:


--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C
@@ -0,0 +1,24 @@
+// Test to verify that evaluating reinterpret_cast is diagnosed in
+// constant expressions.
+// { dg-do compile { target c++11 } }
+
+int i;
+
+// The following is accepted due to bug 49171.
+constexpr void *q = reinterpret_cast();// { dg-error "" "bug 
c++/49171" { xfail *-*-*-* } }
+
+constexpr void *r0 = reinterpret_cast(1);// { dg-error "not a constant 
expression" }
+constexpr void *r1 = reinterpret_cast(sizeof 'x');  // { dg-error 
".reinterpret_cast\\(1ul\\). is not a constant-expression" }
+
+template 
+constexpr bool f ()
+{
+#if __cplusplus > 201103L
+  T *p = reinterpret_cast(sizeof (T));
+  return p;
+#else
+  return *reinterpret_cast(sizeof (T));
+#endif
+}
+
+constexpr bool b = f();   // { dg-error "not a constant expression" }



Grüße
  Thomas





Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-08-02 Thread Thomas Schwinge
Hi!

On Wed, 6 Jul 2016 16:20:44 -0600, Martin Sebor  wrote:
> PR c++/60760 - arithmetic on null pointers should not be allowed in constant
>   expressions
> PR c++/71091 - constexpr reference bound to a null pointer dereference
>accepted
> 
> [...]
>   * g++.dg/cpp0x/constexpr-cast.C: New test.

In x86_64 GNU/Linux testing, I see that one FAIL for the -m32 multilib:

+FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 10)
+FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 11)
+PASS: g++.dg/cpp0x/constexpr-cast.C  -std=c++11  (test for errors, line 24)
+FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11 (test for excess errors)
+XFAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++11 bug c++/49171 (test for 
errors, line 8)
+FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 10)
+FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 11)
+PASS: g++.dg/cpp0x/constexpr-cast.C  -std=c++14  (test for errors, line 24)
+FAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14 (test for excess errors)
+XFAIL: g++.dg/cpp0x/constexpr-cast.C  -std=c++14 bug c++/49171 (test for 
errors, line 8)
+UNSUPPORTED: g++.dg/cpp0x/constexpr-cast.C  -std=c++98

[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:10:22: error: 
'reinterpret_cast(1)' is not a constant-expression
[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:11:22: error: 
'reinterpret_cast(1u)' is not a constant-expression
[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:26:   in 
constexpr expansion of 'f()'
[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:27: error: 
value '4u' of type 'int*' is not a constant expression

For the -m64 multilib, it looks as follows (all PASSes):

[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:10:47: error: 
value '1u' of type 'void*' is not a constant expression
[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:11:22: error: 
'reinterpret_cast(1ul)' is not a constant-expression
[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:26:   in 
constexpr expansion of 'f()'
[...]/source-gcc/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C:24:27: error: 
value '4u' of type 'int*' is not a constant expression

For reference:

> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-cast.C
> @@ -0,0 +1,24 @@
> +// Test to verify that evaluating reinterpret_cast is diagnosed in
> +// constant expressions.
> +// { dg-do compile { target c++11 } }
> +
> +int i;
> +
> +// The following is accepted due to bug 49171.
> +constexpr void *q = reinterpret_cast();// { dg-error "" "bug 
> c++/49171" { xfail *-*-*-* } }
> +
> +constexpr void *r0 = reinterpret_cast(1);// { dg-error "not a 
> constant expression" }
> +constexpr void *r1 = reinterpret_cast(sizeof 'x');  // { dg-error 
> ".reinterpret_cast\\(1ul\\). is not a constant-expression" }
> +
> +template 
> +constexpr bool f ()
> +{
> +#if __cplusplus > 201103L
> +  T *p = reinterpret_cast(sizeof (T));
> +  return p;
> +#else
> +  return *reinterpret_cast(sizeof (T));
> +#endif
> +}
> +
> +constexpr bool b = f();   // { dg-error "not a constant expression" }


Grüße
 Thomas


signature.asc
Description: PGP signature


Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-07-20 Thread Jason Merrill
On Wed, Jul 20, 2016 at 2:15 PM, Martin Sebor  wrote:
> On 07/20/2016 07:52 AM, Jason Merrill wrote:
>>
>> On Mon, Jul 18, 2016 at 6:15 PM, Martin Sebor  wrote:
>>>
>>> On 07/18/2016 11:51 AM, Jason Merrill wrote:


 On 07/06/2016 06:20 PM, Martin Sebor wrote:
>
>
> @@ -2911,6 +2923,14 @@ cxx_eval_indirect_ref (const constexpr_ctx
> *ctx, tree t,
> if (*non_constant_p)
>   return t;
>
> +  if (integer_zerop (op0))
> +{
> +  if (!ctx->quiet)
> +error ("dereferencing a null pointer");
> +  *non_constant_p = true;
> +  return t;
> +}


 I'm skeptical of checking this here, since *p is valid for null p; &*p
 is even a constant expression.  And removing this hunk doesn't seem to
 break any of your tests.

 OK with that hunk removed.
>>>
>>>
>>> With it removed the constexpr-nullptr-2.C test fails on line 64:
>>>
>>>constexpr const int *pi0 = >pa1->pa0->i;   // { dg-error "null
>>> pointer|not a constant" }
>>>
>>> Here, pa2 and pa1 are non-null but pa0 is null.
>>
>>
>> It doesn't fail for me; that line hits the error in
>> cxx_eval_component_reference.  I'm only talking about removing the
>> cxx_eval_indirect_ref hunk.
>
>
> Sorry, I may have been referring to an older patch.  With the latest
> patch, the assertion is on line 75.  It's also not failing, even
> though it should be.  The problem is that I had misunderstood how
> the vertical bar in DejaGnu directives works.  I thought it meant
> that both sides had to match a message on that line, when it means
> only one side has to.  I'll need to fix that (how does one match
> two messages on the same line?)
>
> But removing the hunk as you suggest does break the intent of the
> test.  With it there, we get a descriptive message for the invalid
> code below clearly explaining the problem:
>
> $ cat xyz.c && /build/gcc-60760/gcc/xgcc -B /build/gcc-60760/gcc -S -Wall
> -Wextra -Wpedantic -xc++ xyz.c
> struct S { const S *p; int i; };
>
> constexpr S s0 = { 0, 0 };
> constexpr S s1 = { , 1 };
>
> constexpr int i = s1.p->p->i;
> xyz.c:6:28: error: dereferencing a null pointer
>  constexpr int i = s1.p->p->i;
> ^
>
> With the hunk removed, all we get is the generic:
>
> xyz.c:6:28: error: ‘*(const S*)((const S*)s1.S::p)->S::p’ is not a constant
> expression
>  constexpr int i = s1.p->p->i;
> ^
>
> Re-reading your comment above now: "since *p is valid for null p;"
> I agree that &*p is valid when p is null.  Unless I missed a case
> it is accepted with or without the hunk.  Otherwise, *p is not valid,
> and it is also rejected with or without it.
>
> Is there something else you're worried about with the hunk that
> makes you want to trade it off for the less informative message?

OK, we can keep the hunk, but only when !lval, since that means we
access the value.

Jason


Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-07-20 Thread Martin Sebor

On 07/20/2016 07:52 AM, Jason Merrill wrote:

On Mon, Jul 18, 2016 at 6:15 PM, Martin Sebor  wrote:

On 07/18/2016 11:51 AM, Jason Merrill wrote:


On 07/06/2016 06:20 PM, Martin Sebor wrote:


@@ -2911,6 +2923,14 @@ cxx_eval_indirect_ref (const constexpr_ctx
*ctx, tree t,
if (*non_constant_p)
  return t;

+  if (integer_zerop (op0))
+{
+  if (!ctx->quiet)
+error ("dereferencing a null pointer");
+  *non_constant_p = true;
+  return t;
+}


I'm skeptical of checking this here, since *p is valid for null p; &*p
is even a constant expression.  And removing this hunk doesn't seem to
break any of your tests.

OK with that hunk removed.


With it removed the constexpr-nullptr-2.C test fails on line 64:

   constexpr const int *pi0 = >pa1->pa0->i;   // { dg-error "null
pointer|not a constant" }

Here, pa2 and pa1 are non-null but pa0 is null.


It doesn't fail for me; that line hits the error in
cxx_eval_component_reference.  I'm only talking about removing the
cxx_eval_indirect_ref hunk.


Sorry, I may have been referring to an older patch.  With the latest
patch, the assertion is on line 75.  It's also not failing, even
though it should be.  The problem is that I had misunderstood how
the vertical bar in DejaGnu directives works.  I thought it meant
that both sides had to match a message on that line, when it means
only one side has to.  I'll need to fix that (how does one match
two messages on the same line?)

But removing the hunk as you suggest does break the intent of the
test.  With it there, we get a descriptive message for the invalid
code below clearly explaining the problem:

$ cat xyz.c && /build/gcc-60760/gcc/xgcc -B /build/gcc-60760/gcc -S 
-Wall -Wextra -Wpedantic -xc++ xyz.c

struct S { const S *p; int i; };

constexpr S s0 = { 0, 0 };
constexpr S s1 = { , 1 };

constexpr int i = s1.p->p->i;
xyz.c:6:28: error: dereferencing a null pointer
 constexpr int i = s1.p->p->i;
^

With the hunk removed, all we get is the generic:

xyz.c:6:28: error: ‘*(const S*)((const S*)s1.S::p)->S::p’ is not a 
constant expression

 constexpr int i = s1.p->p->i;
^

Re-reading your comment above now: "since *p is valid for null p;"
I agree that &*p is valid when p is null.  Unless I missed a case
it is accepted with or without the hunk.  Otherwise, *p is not valid,
and it is also rejected with or without it.

Is there something else you're worried about with the hunk that
makes you want to trade it off for the less informative message?

Martin


Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-07-20 Thread Jason Merrill
On Mon, Jul 18, 2016 at 6:15 PM, Martin Sebor  wrote:
> On 07/18/2016 11:51 AM, Jason Merrill wrote:
>>
>> On 07/06/2016 06:20 PM, Martin Sebor wrote:
>>>
>>> @@ -2911,6 +2923,14 @@ cxx_eval_indirect_ref (const constexpr_ctx
>>> *ctx, tree t,
>>>if (*non_constant_p)
>>>  return t;
>>>
>>> +  if (integer_zerop (op0))
>>> +{
>>> +  if (!ctx->quiet)
>>> +error ("dereferencing a null pointer");
>>> +  *non_constant_p = true;
>>> +  return t;
>>> +}
>>
>> I'm skeptical of checking this here, since *p is valid for null p; &*p
>> is even a constant expression.  And removing this hunk doesn't seem to
>> break any of your tests.
>>
>> OK with that hunk removed.
>
> With it removed the constexpr-nullptr-2.C test fails on line 64:
>
>   constexpr const int *pi0 = >pa1->pa0->i;   // { dg-error "null
> pointer|not a constant" }
>
> Here, pa2 and pa1 are non-null but pa0 is null.

It doesn't fail for me; that line hits the error in
cxx_eval_component_reference.  I'm only talking about removing the
cxx_eval_indirect_ref hunk.

Jason


Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-07-18 Thread Martin Sebor

On 07/18/2016 11:51 AM, Jason Merrill wrote:

On 07/06/2016 06:20 PM, Martin Sebor wrote:

@@ -2911,6 +2923,14 @@ cxx_eval_indirect_ref (const constexpr_ctx
*ctx, tree t,



   if (*non_constant_p)



 return t;







+  if (integer_zerop (op0))



+{



+  if (!ctx->quiet)



+error ("dereferencing a null pointer");



+  *non_constant_p = true;



+  return t;



+}


I'm skeptical of checking this here, since *p is valid for null p; &*p
is even a constant expression.  And removing this hunk doesn't seem to
break any of your tests.

OK with that hunk removed.


With it removed the constexpr-nullptr-2.C test fails on line 64:

  constexpr const int *pi0 = >pa1->pa0->i;   // { dg-error "null 
pointer|not a constant" }


Here, pa2 and pa1 are non-null but pa0 is null.

Martin


Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-07-18 Thread Jason Merrill

On 07/06/2016 06:20 PM, Martin Sebor wrote:

@@ -2911,6 +2923,14 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,



   if (*non_constant_p)



return t;







+  if (integer_zerop (op0))



+   {



+ if (!ctx->quiet)



+   error ("dereferencing a null pointer");



+ *non_constant_p = true;



+ return t;



+   }


I'm skeptical of checking this here, since *p is valid for null p; &*p 
is even a constant expression.  And removing this hunk doesn't seem to 
break any of your tests.


OK with that hunk removed.

Jason



Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-07-14 Thread Martin Sebor

Ping.  Jason, do you have any further comments or concerns with
the updated patch?

https://gcc.gnu.org/ml/gcc-patches/2016-07/msg00280.html

Thanks
Martin

On 07/06/2016 04:20 PM, Martin Sebor wrote:

On 06/23/2016 03:36 PM, Jason Merrill wrote:

On 06/20/2016 10:17 PM, Martin Sebor wrote:

+  && tree_int_cst_equal (lhs, null_pointer_node)
+  && !tree_int_cst_equal (rhs, integer_zero_node))


Not integer_zerop?


+"invalid conversion involving a null pointer");

...

+"invalid conversion from %qT to %qT",


The conversion isn't invalid, it just isn't a constant expression.


(Sorry for the delay following up on this review.  I got busy
with something else.)

I've adjusted the text of the diagnostics, though the first one
is also issued for conversions that are invalid even outside
constexpr, such as those that cast away constness, or those that
cast to incomplete type.  Without -fpermissve those are already
diagnosed by this point but I'm not sure how much trouble to go
to here to avoid diagnosing them again, or at all with
-fpermissve.


For
the null pointer to pointer conversion, does this properly allow
conversion to void* or to base*?


It didn't handle either but does now.  Thank you for calling it
out.  Surprisingly, a regression run including libstdc++ didn't
catch it.  I've added tests to exercise it.




+if (integer_zerop (op))

...

+ else if (!integer_zerop (op))


The second test seems redundant.


I have removed it.

Martin




Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-07-06 Thread Martin Sebor

On 06/23/2016 03:36 PM, Jason Merrill wrote:

On 06/20/2016 10:17 PM, Martin Sebor wrote:

+  && tree_int_cst_equal (lhs, null_pointer_node)
+  && !tree_int_cst_equal (rhs, integer_zero_node))


Not integer_zerop?


+"invalid conversion involving a null pointer");

...

+"invalid conversion from %qT to %qT",


The conversion isn't invalid, it just isn't a constant expression.


(Sorry for the delay following up on this review.  I got busy
with something else.)

I've adjusted the text of the diagnostics, though the first one
is also issued for conversions that are invalid even outside
constexpr, such as those that cast away constness, or those that
cast to incomplete type.  Without -fpermissve those are already
diagnosed by this point but I'm not sure how much trouble to go
to here to avoid diagnosing them again, or at all with
-fpermissve.


For
the null pointer to pointer conversion, does this properly allow
conversion to void* or to base*?


It didn't handle either but does now.  Thank you for calling it
out.  Surprisingly, a regression run including libstdc++ didn't
catch it.  I've added tests to exercise it.




+if (integer_zerop (op))

...

+ else if (!integer_zerop (op))


The second test seems redundant.


I have removed it.

Martin
PR c++/60760 - arithmetic on null pointers should not be allowed in constant
  expressions
PR c++/71091 - constexpr reference bound to a null pointer dereference
   accepted

gcc/cp/ChangeLog:
2016-07-06  Martin Sebor  

PR c++/60760
PR c++/71091
* constexpr.c (cxx_eval_binary_expression): Reject invalid expressions
involving null pointers.
(cxx_eval_component_reference): Reject null pointer dereferences.
(cxx_eval_indirect_ref): Reject indirecting through null pointers.
(cxx_eval_constant_expression): Reject invalid expressions involving
null pointers.

gcc/testsuite/ChangeLog:
2016-07-06  Martin Sebor  

PR c++/60760
PR c++/71091
	* g++.dg/cpp0x/constexpr-cast.C: New test.
* g++.dg/cpp0x/constexpr-nullptr-2.C: New test.
* g++.dg/cpp1y/constexpr-sfinae.C: Correct.
* g++.dg/ubsan/pr63956.C: Correct.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index ba40435..83954d8 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1811,6 +1811,13 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
 		   || null_member_pointer_value_p (rhs)))
 	r = constant_boolean_node (!is_code_eq, type);
 }
+  if (code == POINTER_PLUS_EXPR && !*non_constant_p
+  && integer_zerop (lhs) && !integer_zerop (rhs))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", lhs);
+  return t;
+}
 
   if (r == NULL_TREE)
 r = fold_binary_loc (loc, code, type, lhs, rhs);
@@ -2151,6 +2158,11 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 	 lval,
 	 non_constant_p, overflow_p);
+  if (TREE_CODE (whole) == INDIRECT_REF
+  && integer_zerop (TREE_OPERAND (whole, 0))
+  && !ctx->quiet)
+error ("dereferencing a null pointer in %qE", orig_whole);
+
   if (TREE_CODE (whole) == PTRMEM_CST)
 whole = cplus_expand_constant (whole);
   if (whole == orig_whole)
@@ -2911,6 +2923,14 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
   if (*non_constant_p)
 	return t;
 
+  if (integer_zerop (op0))
+	{
+	  if (!ctx->quiet)
+	error ("dereferencing a null pointer");
+	  *non_constant_p = true;
+	  return t;
+	}
+
   r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), op0,
  _base);
   if (r == NULL_TREE)
@@ -3559,10 +3579,22 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  if (!flag_permissive || ctx->quiet)
 	*overflow_p = true;
 	}
+
+  if (TREE_CODE (t) == INTEGER_CST
+  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+  && !integer_zerop (t))
+{
+  if (!ctx->quiet)
+error ("value %qE of type %qT is not a constant expression",
+		   t, TREE_TYPE (t));
+	  *non_constant_p = true;
+}
+
   return t;
 }
 
-  switch (TREE_CODE (t))
+  tree_code tcode = TREE_CODE (t);
+  switch (tcode)
 {
 case RESULT_DECL:
   if (lval)
@@ -3973,7 +4005,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 case NOP_EXPR:
 case UNARY_PLUS_EXPR:
   {
-	enum tree_code tcode = TREE_CODE (t);
 	tree oldop = TREE_OPERAND (t, 0);
 
 	tree op = cxx_eval_constant_expression (ctx, oldop,
@@ -3999,15 +4030,48 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 		return t;
 	  }
 	  }
-	if (POINTER_TYPE_P (type)
-	&& TREE_CODE (op) == INTEGER_CST
-	&& !integer_zerop (op))
-	  {
-	if (!ctx->quiet)
-	  error_at (EXPR_LOC_OR_LOC (t, input_location),
-			

Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-06-23 Thread Jason Merrill

On 06/20/2016 10:17 PM, Martin Sebor wrote:

+  && tree_int_cst_equal (lhs, null_pointer_node)
+  && !tree_int_cst_equal (rhs, integer_zero_node))


Not integer_zerop?


+   "invalid conversion involving a null pointer");

...

+   "invalid conversion from %qT to %qT",


The conversion isn't invalid, it just isn't a constant expression.  For 
the null pointer to pointer conversion, does this properly allow 
conversion to void* or to base*?



+   if (integer_zerop (op))

...

+ else if (!integer_zerop (op))


The second test seems redundant.

Jason



Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-06-20 Thread Martin Sebor

+  if (TREE_CODE (whole) == INDIRECT_REF
+  && integer_zerop (TREE_OPERAND (whole, 0))
+  && !ctx->quiet)
+error ("dereferencing a null pointer in %qE", orig_whole);



+  if (TREE_CODE (t) == INTEGER_CST
+  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+  && !integer_zerop (t))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", t);
+}


These places should all set *non_constant_p, and the second should
return t after doing so.  OK with that change.


Some additional testing exposed a couple of bugs in the patch.
First, adding or subtracting a constant zero to or from a null
pointer is valid (it was rejected with the previous patch).
Second, the code in cxx_eval_constant_expression that tried
to detect invalid conversions didn't handle qualifiers
correctly in all cases, causing conversions that add constness
to be rejected.  Finally, while fixing these issues I decided
that dereferencing and indirecting through null pointers would
be more appropriately handled in the functions that deal with
those expressions rather than in cxx_eval_constant_expression.

Since the updates aren't completely trivial I post the new
version of the patch for another review before committing it.

Thanks
Martin

PR c++/60760 - arithmetic on null pointers should not be allowed in constant
  expressions
PR c++/71091 - constexpr reference bound to a null pointer dereference
   accepted

gcc/cp/ChangeLog:
2016-06-20  Martin Sebor  

	PR c++/60760
	PR c++/71091
	* constexpr.c (cxx_eval_binary_expression): Reject invalid expressions
	involving null pointers.
	(cxx_eval_component_reference): Reject null pointer dereferences.
	(cxx_eval_indirect_ref): Reject indirecting through null pointers.
	(cxx_eval_constant_expression): Reject invalid expressions involving
	null pointers.

gcc/testsuite/ChangeLog:
2016-06-20  Martin Sebor  

	PR c++/60760
	PR c++/71091
	* g++.dg/cpp0x/constexpr-nullptr-2.C: New test.
	* g++.dg/cpp1y/constexpr-sfinae.C: Correct.
	* g++.dg/ubsan/pr63956.C: Correct.

Index: gcc/cp/constexpr.c
===
--- gcc/cp/constexpr.c	(revision 237582)
+++ gcc/cp/constexpr.c	(working copy)
@@ -1811,6 +1811,14 @@ cxx_eval_binary_expression (const constexpr_ctx *c
 		   || null_member_pointer_value_p (rhs)))
 	r = constant_boolean_node (!is_code_eq, type);
 }
+  if (code == POINTER_PLUS_EXPR && !*non_constant_p
+  && tree_int_cst_equal (lhs, null_pointer_node)
+  && !tree_int_cst_equal (rhs, integer_zero_node))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", lhs);
+  return t;
+}
 
   if (r == NULL_TREE)
 r = fold_binary_loc (loc, code, type, lhs, rhs);
@@ -2151,6 +2159,11 @@ cxx_eval_component_reference (const constexpr_ctx
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 	 lval,
 	 non_constant_p, overflow_p);
+  if (TREE_CODE (whole) == INDIRECT_REF
+  && integer_zerop (TREE_OPERAND (whole, 0))
+  && !ctx->quiet)
+error ("dereferencing a null pointer in %qE", orig_whole);
+
   if (TREE_CODE (whole) == PTRMEM_CST)
 whole = cplus_expand_constant (whole);
   if (whole == orig_whole)
@@ -2911,6 +2924,14 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, t
   if (*non_constant_p)
 	return t;
 
+  if (integer_zerop (op0))
+	{
+	  if (!ctx->quiet)
+	error ("dereferencing a null pointer");
+	  *non_constant_p = true;
+	  return t;
+	}
+
   r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), op0,
  _base);
   if (r == NULL_TREE)
@@ -3559,10 +3580,20 @@ cxx_eval_constant_expression (const constexpr_ctx
 	  if (!flag_permissive || ctx->quiet)
 	*overflow_p = true;
 	}
+
+  if (TREE_CODE (t) == INTEGER_CST
+  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+  && !integer_zerop (t))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", t);
+}
+
   return t;
 }
 
-  switch (TREE_CODE (t))
+  tree_code tcode = TREE_CODE (t);
+  switch (tcode)
 {
 case RESULT_DECL:
   if (lval)
@@ -3973,7 +4004,6 @@ cxx_eval_constant_expression (const constexpr_ctx
 case NOP_EXPR:
 case UNARY_PLUS_EXPR:
   {
-	enum tree_code tcode = TREE_CODE (t);
 	tree oldop = TREE_OPERAND (t, 0);
 
 	tree op = cxx_eval_constant_expression (ctx, oldop,
@@ -3999,15 +4029,43 @@ cxx_eval_constant_expression (const constexpr_ctx
 		return t;
 	  }
 	  }
-	if (POINTER_TYPE_P (type)
-	&& TREE_CODE (op) == INTEGER_CST
-	&& !integer_zerop (op))
-	  {
-	if (!ctx->quiet)
-	  error_at (EXPR_LOC_OR_LOC (t, input_location),
-			"reinterpret_cast from integer to pointer");
-	*non_constant_p = true;
-	return t;
+	if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
+  {
+	if (integer_zerop (op))
+	  

Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-06-02 Thread Jason Merrill

On 06/01/2016 10:49 PM, Martin Sebor wrote:

On 06/01/2016 01:20 PM, Jason Merrill wrote:

On 06/01/2016 02:44 PM, Martin Sebor wrote:

The new code in cxx_eval_component_reference diagnoses the following
problem that's not detected otherwise:

  struct S { const S *s; };

  constexpr S s = { 0 };

  constexpr const void *p = >s;


Note that this falls under core issue 1530, which has not been
resolved.


I don't quite see the relevance of this issue.  It's concerned
with storage in which an object will exist at some point in
the future when its lifetime begins or where it existed in
the past before its lifetime ended.  There is no object or
storage at s.s above because s.s is null.


True.  Unfortunately there isn't any wording about what you can do with
the result of indirecting a null pointer or pointer to one-past-the-end
of an array.  There was some proposed for issue 232, but that hasn't
been a high priority.  What do you see in the standard currently that
makes it undefined?


In N4567, expr.ref, the E1->E2 expression which is equivalent
to (*E1).E2, the closest match is paragraph 4.2:

  If E2 is a non-static data member and the type of E1 is "cq1
  vq1 X", and the type of E2 is "cq2 vq2 T", the expression
  designates the named member of the object designated by the
  first expression.

There is no object, so 4.2 doesn't apply, and since there is
no other bullet that would apply, the behavior is undefined.


OK, I'll buy that.


+  if (code == POINTER_PLUS_EXPR && !*non_constant_p
+  && tree_int_cst_equal (lhs, null_pointer_node))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", lhs);
+  return t;
+}



+  if (TREE_CODE (whole) == INDIRECT_REF
+  && integer_zerop (TREE_OPERAND (whole, 0))
+  && !ctx->quiet)
+error ("dereferencing a null pointer in %qE", orig_whole);



+  if (TREE_CODE (t) == INTEGER_CST
+  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+  && !integer_zerop (t))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", t);
+}


These places should all set *non_constant_p, and the second should
return t after doing so.  OK with that change.


Thanks.  I've made the change, but I haven't managed to come up
with a test to exercise it.  IIUC, the purpose setting
non_constant_p while the quiet flag is set is to determine without
causing errors that expressions are not valid constant expressions
by passing them to __builtin_constant_p, correct?


No, __builtin_constant_p allows more things than C++ constant 
expressions.  The purpose of setting *non_constant_p is to cause 
maybe_constant_value to return its argument unchanged.


Jason



Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-06-01 Thread Martin Sebor

On 06/01/2016 01:20 PM, Jason Merrill wrote:

On 06/01/2016 02:44 PM, Martin Sebor wrote:

The new code in cxx_eval_component_reference diagnoses the following
problem that's not detected otherwise:

  struct S { const S *s; };

  constexpr S s = { 0 };

  constexpr const void *p = >s;


Note that this falls under core issue 1530, which has not been resolved.


I don't quite see the relevance of this issue.  It's concerned
with storage in which an object will exist at some point in
the future when its lifetime begins or where it existed in
the past before its lifetime ended.  There is no object or
storage at s.s above because s.s is null.


True.  Unfortunately there isn't any wording about what you can do with
the result of indirecting a null pointer or pointer to one-past-the-end
of an array.  There was some proposed for issue 232, but that hasn't
been a high priority.  What do you see in the standard currently that
makes it undefined?


In N4567, expr.ref, the E1->E2 expression which is equivalent
to (*E1).E2, the closest match is paragraph 4.2:

  If E2 is a non-static data member and the type of E1 is "cq1
  vq1 X", and the type of E2 is "cq2 vq2 T", the expression
  designates the named member of the object designated by the
  first expression.

There is no object, so 4.2 doesn't apply, and since there is
no other bullet that would apply, the behavior is undefined.


It might perhaps be okay to accept the expression above as
an extension with the rationale that the offset of the first
member is zero and so its address must be a null pointer, but
it surely wouldn't be okay in the modified test case below
where the second member's offset is non-zero and there may
not be a way to represent that offset as a pointer.


Why not?  It would be a pointer to address 4 or whatever.


Because the hardware may simply not have a representation for
4 (or any small integer) in a pointer type.  Possibly because
it uses that bit pattern for some special mapping and when
there is no mapping, using the invalid pointer value traps.
Whether or not this is the case is implementation-defined
(certainly in C for this reason, and I expect also in C++).

For core constant expressions, my impression is that they
are deliberately constrained to a fairly narrow guaranteed-
to-be-valid subset, which is why things like reinterpret_cast
are not allowed.  The expression we're discussing basically
boils down to a conversion of the offset 4 to a pointer,
which is equivalent to the forbidden reinterpret_cast.

I agree that the standard text isn't ironclad on this, but
I can't think of a useful purpose that allowing constexpr
expressions to form invalid addresses would serve even in
the (common) case where the hardware does allow it.

From a practical point of view, if GCC were to continue to
allow it, it would need to track those pointers and diagnose
them on their first use, because that is undefined in any
case.


+  if (code == POINTER_PLUS_EXPR && !*non_constant_p
+  && tree_int_cst_equal (lhs, null_pointer_node))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", lhs);
+  return t;
+}



+  if (TREE_CODE (whole) == INDIRECT_REF
+  && integer_zerop (TREE_OPERAND (whole, 0))
+  && !ctx->quiet)
+error ("dereferencing a null pointer in %qE", orig_whole);



+  if (TREE_CODE (t) == INTEGER_CST
+  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+  && !integer_zerop (t))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", t);
+}


These places should all set *non_constant_p, and the second should
return t after doing so.  OK with that change.


Thanks.  I've made the change, but I haven't managed to come up
with a test to exercise it.  IIUC, the purpose setting
non_constant_p while the quiet flag is set is to determine without
causing errors that expressions are not valid constant expressions
by passing them to __builtin_constant_p, correct?

If so, then there must be something wrong somewhere because the
test case below fails the static assertion (the first error is
expected with the patch):

$ cat null.c && /home/msebor/build/gcc-60760/gcc/xgcc -B 
/home/msebor/build/gcc-60760/gcc -S -Wall -Wextra -Wpedantic -xc++ null.c

constexpr int *p = 0;
constexpr int *q = p + 1;

static_assert (!__builtin_constant_p (p + 1), "<<<");

null.c:2:24: error: arithmetic involving a null pointer in ‘0u’
 constexpr int *q = p + 1;
^
null.c:4:1: error: static assertion failed: <<<
 static_assert (!__builtin_constant_p (p + 1), "<<<");
 ^

(I know of at least one bug here, c++/70552, but this one is new.)

Martin


Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-06-01 Thread Jason Merrill

On 06/01/2016 02:44 PM, Martin Sebor wrote:

The new code in cxx_eval_component_reference diagnoses the following
problem that's not detected otherwise:

  struct S { const S *s; };

  constexpr S s = { 0 };

  constexpr const void *p = >s;


Note that this falls under core issue 1530, which has not been resolved.


I don't quite see the relevance of this issue.  It's concerned
with storage in which an object will exist at some point in
the future when its lifetime begins or where it existed in
the past before its lifetime ended.  There is no object or
storage at s.s above because s.s is null.


True.  Unfortunately there isn't any wording about what you can do with 
the result of indirecting a null pointer or pointer to one-past-the-end 
of an array.  There was some proposed for issue 232, but that hasn't 
been a high priority.  What do you see in the standard currently that 
makes it undefined?



It might perhaps be okay to accept the expression above as
an extension with the rationale that the offset of the first
member is zero and so its address must be a null pointer, but
it surely wouldn't be okay in the modified test case below
where the second member's offset is non-zero and there may
not be a way to represent that offset as a pointer.


Why not?  It would be a pointer to address 4 or whatever.


Thanks for the hint.  I've made that change and also adjusted
the rest of the patch to avoid passing the nullptr_p around.
It was surprisingly simpler to do than I remembered from my
first attempt back in March.



+  if (code == POINTER_PLUS_EXPR && !*non_constant_p
+  && tree_int_cst_equal (lhs, null_pointer_node))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", lhs);
+  return t;
+}



+  if (TREE_CODE (whole) == INDIRECT_REF
+  && integer_zerop (TREE_OPERAND (whole, 0))
+  && !ctx->quiet)
+error ("dereferencing a null pointer in %qE", orig_whole);



+  if (TREE_CODE (t) == INTEGER_CST
+  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+  && !integer_zerop (t))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", t);
+}


These places should all set *non_constant_p, and the second should 
return t after doing so.  OK with that change.


Jason



Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-06-01 Thread Martin Sebor

The new code in cxx_eval_component_reference diagnoses the following
problem that's not detected otherwise:

  struct S { const S *s; };

  constexpr S s = { 0 };

  constexpr const void *p = >s;


Note that this falls under core issue 1530, which has not been resolved.


I don't quite see the relevance of this issue.  It's concerned
with storage in which an object will exist at some point in
the future when its lifetime begins or where it existed in
the past before its lifetime ended.  There is no object or
storage at s.s above because s.s is null.

It might perhaps be okay to accept the expression above as
an extension with the rationale that the offset of the first
member is zero and so its address must be a null pointer, but
it surely wouldn't be okay in the modified test case below
where the second member's offset is non-zero and there may
not be a way to represent that offset as a pointer. This
seems unquestionably undefined to me.  Did I miss something?

  struct S { const S *s; int i; };

  constexpr S s = { 0 };

  constexpr const void *p = >i;


  I believe that this is fine under the current wording; only "access"
to a non-static data member is undefined, and "access" is defined as
reading or writing.  There has been discussion in the context of UBsan
about making this undefined, but that hasn't been decided yet.  But I'm
OK with changing G++ to go in that direction.

cxx_eval_component_reference could check whether 'whole' is a null (or
other invalid) lvalue; for that testcase it's an INDIRECT_REF of 0.


Thanks for the hint.  I've made that change and also adjusted
the rest of the patch to avoid passing the nullptr_p around.
It was surprisingly simpler to do than I remembered from my
first attempt back in March.

Martin
PR c++/60760 - arithmetic on null pointers should not be allowed
   in constant expressions
PR c++/71091 - constexpr reference bound to a null pointer dereference
   accepted

gcc/testsuite/ChangeLog:
2016-05-12  Martin Sebor  

	PR c++/60760
	PR c++/71091
	* g++.dg/cpp0x/constexpr-nullptr-2.C: New test.
	* gcc/testsuite/g++.dg/ubsan/pr63956.C: Adjust.

gcc/cp/ChangeLog:
2016-05-12  Martin Sebor  

	PR c++/60760
	PR c++/71091
	* constexpr.c (cxx_eval_binary_expression): Reject invalid arithmetic
	involving null pointers.
	(cxx_eval_constant_expression): Same.
	(cxx_eval_component_reference): Reject null pointer dereferences.

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 482f8af..d1fe276 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1757,6 +1757,13 @@ cxx_eval_binary_expression (const constexpr_ctx *ctx, tree t,
 		   || null_member_pointer_value_p (rhs)))
 	r = constant_boolean_node (!is_code_eq, type);
 }
+  if (code == POINTER_PLUS_EXPR && !*non_constant_p
+  && tree_int_cst_equal (lhs, null_pointer_node))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", lhs);
+  return t;
+}
 
   if (r == NULL_TREE)
 r = fold_binary_loc (loc, code, type, lhs, rhs);
@@ -2097,6 +2104,11 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, tree t,
   tree whole = cxx_eval_constant_expression (ctx, orig_whole,
 	 lval,
 	 non_constant_p, overflow_p);
+  if (TREE_CODE (whole) == INDIRECT_REF
+  && integer_zerop (TREE_OPERAND (whole, 0))
+  && !ctx->quiet)
+error ("dereferencing a null pointer in %qE", orig_whole);
+
   if (TREE_CODE (whole) == PTRMEM_CST)
 whole = cplus_expand_constant (whole);
   if (whole == orig_whole)
@@ -3505,10 +3517,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 	  if (!flag_permissive || ctx->quiet)
 	*overflow_p = true;
 	}
+
+  if (TREE_CODE (t) == INTEGER_CST
+  && TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+  && !integer_zerop (t))
+{
+  if (!ctx->quiet)
+error ("arithmetic involving a null pointer in %qE", t);
+}
+
   return t;
 }
 
-  switch (TREE_CODE (t))
+  tree_code tcode = TREE_CODE (t);
+  switch (tcode)
 {
 case RESULT_DECL:
   if (lval)
@@ -3919,7 +3941,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 case NOP_EXPR:
 case UNARY_PLUS_EXPR:
   {
-	enum tree_code tcode = TREE_CODE (t);
 	tree oldop = TREE_OPERAND (t, 0);
 
 	tree op = cxx_eval_constant_expression (ctx, oldop,
@@ -3945,15 +3966,26 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 		return t;
 	  }
 	  }
-	if (POINTER_TYPE_P (type)
-	&& TREE_CODE (op) == INTEGER_CST
-	&& !integer_zerop (op))
-	  {
-	if (!ctx->quiet)
-	  error_at (EXPR_LOC_OR_LOC (t, input_location),
-			"reinterpret_cast from integer to pointer");
-	*non_constant_p = true;
-	return t;
+	if (POINTER_TYPE_P (type) && TREE_CODE (op) == INTEGER_CST)
+  {
+const char *msg = NULL;
+if (integer_zerop (op))
+  {
+if 

Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-06-01 Thread Jason Merrill

On 05/31/2016 06:03 PM, Martin Sebor wrote:

On 05/17/2016 01:44 PM, Jason Merrill wrote:

On 05/12/2016 06:34 PM, Martin Sebor wrote:

Attached is a resubmission of the patch for c++/60760 originally
submitted late in the 6.0 cycle along with a patch for c++/67376.
Since c++/60760 was not a regression, it was decided that it
would be safer to defer the fix until after the 6.1.0 release.

While retesting this patch I was happy to notice that it also
fixes another bug: c++/71091 - constexpr reference bound to a null
pointer dereference accepted.


I'm not sure why we need to track nullptr_p through everything.  Can't
we set *non_constant_p instead in the places where it's problematic, as
in cxx_eval_binary_expression?


That would have certainly been my preference over adding another
argument to a subset of the functions, making their declarations
inconsistent.  Unfortunately, I couldn't come up with a simpler
way to make it work.

FWIW, my first inclination was to make the nullptr_p flag part
of constexpr_ctx and move the other xxx_p arguments there, to
simplify the interface, until I noticed that all the functions
take a const constexpr_ctx*, preventing them to modify it.  It
seemed like too much of a change to fix a bug in stage 3, but
I'd be comfortable making it in stage 1 if you think it's
worthwhile (though my preference would be to do in a separate
commit, after fixing this bug).


I understand that the complication comes because of needing to allow

constexpr int *p = &*(int*)0;

but I don't see how cxx_eval_component_reference could come up with a
constant value for the referent of a null pointer, so we already reject

struct A { int i; };
constexpr A* p = nullptr;
constexpr int i = p->i;

In cxx_eval_indirect_ref, we could check !lval and reject the
constant-expression at that point.


The new code in cxx_eval_component_reference diagnoses the following
problem that's not detected otherwise:

  struct S { const S *s; };

  constexpr S s = { 0 };

  constexpr const void *p = >s;


Note that this falls under core issue 1530, which has not been resolved. 
 I believe that this is fine under the current wording; only "access" 
to a non-static data member is undefined, and "access" is defined as 
reading or writing.  There has been discussion in the context of UBsan 
about making this undefined, but that hasn't been decided yet.  But I'm 
OK with changing G++ to go in that direction.


cxx_eval_component_reference could check whether 'whole' is a null (or 
other invalid) lvalue; for that testcase it's an INDIRECT_REF of 0.


Jason



Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-05-31 Thread Martin Sebor

On 05/17/2016 01:44 PM, Jason Merrill wrote:

On 05/12/2016 06:34 PM, Martin Sebor wrote:

Attached is a resubmission of the patch for c++/60760 originally
submitted late in the 6.0 cycle along with a patch for c++/67376.
Since c++/60760 was not a regression, it was decided that it
would be safer to defer the fix until after the 6.1.0 release.

While retesting this patch I was happy to notice that it also
fixes another bug: c++/71091 - constexpr reference bound to a null
pointer dereference accepted.


I'm not sure why we need to track nullptr_p through everything.  Can't
we set *non_constant_p instead in the places where it's problematic, as
in cxx_eval_binary_expression?


That would have certainly been my preference over adding another
argument to a subset of the functions, making their declarations
inconsistent.  Unfortunately, I couldn't come up with a simpler
way to make it work.

FWIW, my first inclination was to make the nullptr_p flag part
of constexpr_ctx and move the other xxx_p arguments there, to
simplify the interface, until I noticed that all the functions
take a const constexpr_ctx*, preventing them to modify it.  It
seemed like too much of a change to fix a bug in stage 3, but
I'd be comfortable making it in stage 1 if you think it's
worthwhile (though my preference would be to do in a separate
commit, after fixing this bug).



I understand that the complication comes because of needing to allow

constexpr int *p = &*(int*)0;

but I don't see how cxx_eval_component_reference could come up with a
constant value for the referent of a null pointer, so we already reject

struct A { int i; };
constexpr A* p = nullptr;
constexpr int i = p->i;

In cxx_eval_indirect_ref, we could check !lval and reject the
constant-expression at that point.


The new code in cxx_eval_component_reference diagnoses the following
problem that's not detected otherwise:

  struct S { const S *s; };

  constexpr S s = { 0 };

  constexpr const void *p = >s;

Martin


Re: [PATCH] c++/60760 - arithmetic on null pointers should not be allowed in constant expressions

2016-05-17 Thread Jason Merrill

On 05/12/2016 06:34 PM, Martin Sebor wrote:

Attached is a resubmission of the patch for c++/60760 originally
submitted late in the 6.0 cycle along with a patch for c++/67376.
Since c++/60760 was not a regression, it was decided that it
would be safer to defer the fix until after the 6.1.0 release.

While retesting this patch I was happy to notice that it also
fixes another bug: c++/71091 - constexpr reference bound to a null
pointer dereference accepted.


I'm not sure why we need to track nullptr_p through everything.  Can't 
we set *non_constant_p instead in the places where it's problematic, as 
in cxx_eval_binary_expression?


I understand that the complication comes because of needing to allow

constexpr int *p = &*(int*)0;

but I don't see how cxx_eval_component_reference could come up with a 
constant value for the referent of a null pointer, so we already reject


struct A { int i; };
constexpr A* p = nullptr;
constexpr int i = p->i;

In cxx_eval_indirect_ref, we could check !lval and reject the 
constant-expression at that point.


Jason