Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-10-10 Thread Jakub Jelinek
On Mon, Oct 08, 2018 at 03:36:18PM +0200, Andreas Schwab wrote:
> This still doesn't fix the tests.

Sure, one needs to add the constexpr virtual calls for ia64 as I said in the
mail.

Jakub


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-10-08 Thread Andreas Schwab
On Sep 20 2018, Jakub Jelinek  wrote:

> --- gcc/cp/class.c.jj 2018-09-20 09:56:59.229751895 +0200
> +++ gcc/cp/class.c2018-09-20 10:12:17.447370890 +0200
> @@ -9266,7 +9266,6 @@ build_vtbl_initializer (tree binfo,
>tree vcall_index;
>tree fn, fn_original;
>tree init = NULL_TREE;
> -  tree idx = size_int (jx++);
>  
>fn = BV_FN (v);
>fn_original = fn;
> @@ -9370,7 +9369,7 @@ build_vtbl_initializer (tree binfo,
> int i;
> if (init == size_zero_node)
>   for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> -   CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> +   CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
> else
>   for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> {
> @@ -9378,11 +9377,11 @@ build_vtbl_initializer (tree binfo,
>fn, build_int_cst (NULL_TREE, i));
>   TREE_CONSTANT (fdesc) = 1;
>  
> - CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
> + CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), fdesc);
> }
>   }
>else
> - CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> + CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
>  }
>  }

This still doesn't fix the tests.

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-27 Thread Jakub Jelinek
On Thu, Sep 27, 2018 at 07:08:41PM -0400, Marek Polacek wrote:
> > This patch is OK.  And your suggestion for cxx_eval_call_expression
> > sounds right, too.  Marek, will you follow up on that?
> 
> Ok, I will (provided I can get a box that has TARGET_VTABLE_USES_DESCRIPTORS, 
> I
> think ppc64 BE should be enough).

AFAIK only ia64 defines this macro to non-zero, so you need to cross-compile.
Given that this is constexpr stuff, all you are looking for is compile time
anyway ;)

Jakub


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-27 Thread Jason Merrill
On Thu, Sep 27, 2018, 7:08 PM Marek Polacek  wrote:

> On Thu, Sep 27, 2018 at 01:15:46AM -0400, Jason Merrill wrote:
> > On Thu, Sep 20, 2018 at 5:20 AM, Jakub Jelinek  wrote:
> > > On Thu, Sep 20, 2018 at 09:12:53AM +0200, Andreas Schwab wrote:
> > >> On Sep 19 2018, Jason Merrill  wrote:
> > >>
> > >> > Andreas, do the new testcases pass?  That would surprise me, but OK
> if so.
> > >>
> > >> No, they don't.
> > >>
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:26:
> error: non-constant condition for static assertion
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:23:
> error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr'
> function
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:26:
> error: non-constant condition for static assertion
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:23:
> error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr'
> function
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:27:
> error: non-constant condition for static assertion
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:24:
> error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr'
> function
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:26:
> error: non-constant condition for static assertion
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:23:
> error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr'
> function
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:26:
> error: non-constant condition for static assertion
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:23:
> error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr'
> function
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:27:
> error: non-constant condition for static assertion
> > >>
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:24:
> error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr'
> function
> > >> compiler exited with status 1
> > >> FAIL: g++.dg/cpp2a/constexpr-virtual2.C   (test for excess errors)
> > >
> > > I think the primary problem here is:
> > >   /* When using function descriptors, the address of the
> > >  vtable entry is treated as a function pointer.  */
> > >   if (TARGET_VTABLE_USES_DESCRIPTORS)
> > > e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
> > >  cp_build_addr_expr (e2, complain));
> > > in typeck.c, on non-descriptor targets we have an INDIRECT_REF where we
> > > read the vtable function pointer.  On ia64, the above optimizes the
> > > INDIRECT_REF away, so what the cxx_eval_call_expression actually gets
> > > after constexpr evaluating the CALL_FN is not ADDR_EXPR of a function,
> > > but the address of the function descriptor (e.g. &_ZTV2X2 + 16 ).
> > >
> > > So, perhaps in cxx_eval_call_expression we need:
> > >if (TREE_CODE (fun) == ADDR_EXPR)
> > > fun = TREE_OPERAND (fun, 0);
> > > +  else if (TARGET_VTABLE_USES_DESCRIPTORS
> > > +  && TREE_CODE (fun) == POINTER_PLUS_EXPR
> > > +  && ...)
> > > where we verify that p+ first argument is ADDR_EXPR of a virtual table,
> > > second arg is INTEGER_CST and just walk the DECL_INITIAL of that,
> finding
> > > the FDESC_EXPR at the right offset (therefore, I believe you need
> following
> > > rather than the patch you've posted, so that you can actually find it)
> and
> > > finally pick the function from the FDESC_EXPR entry.
> > > Makes me wonder what happens with indirect calls in constexpr
> evaluation,
> > > e.g. if I do:
> > > constexpr int bar () { return 42; }
> > > constexpr int foo () { int (*fn) () = bar; return fn (); }
> > > static_assert (foo () == 42);
> > > but apparently this works.
> > >
> > > --- gcc/cp/class.c.jj   2018-09-20 09:56:59.229751895 +0200
> > > +++ gcc/cp/class.c  2018-09-20 10:12:17.447370890 +0200
> > > @@ -9266,7 +9266,6 @@ build_vtbl_initializer (tree binfo,
> > >tree vcall_index;
> > >tree fn, fn_original;
> > >tree init = NULL_TREE;
> > > -  tree idx = size_int (jx++);
> > >
> > >fn = BV_FN (v);
> > >fn_original = fn;
> > > @@ -9370,7 +9369,7 @@ build_vtbl_initializer (tree binfo,
> > >   int i;
> > >   if (init == size_zero_node)
> > > for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> > > - CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> > > + CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
> > >   else
> > > for (i = 0; i < 

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-27 Thread Marek Polacek
On Thu, Sep 27, 2018 at 01:15:46AM -0400, Jason Merrill wrote:
> On Thu, Sep 20, 2018 at 5:20 AM, Jakub Jelinek  wrote:
> > On Thu, Sep 20, 2018 at 09:12:53AM +0200, Andreas Schwab wrote:
> >> On Sep 19 2018, Jason Merrill  wrote:
> >>
> >> > Andreas, do the new testcases pass?  That would surprise me, but OK if 
> >> > so.
> >>
> >> No, they don't.
> >>
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:26:
> >>  error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:23:
> >>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 
> >> 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:26:
> >>  error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:23:
> >>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 
> >> 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:27:
> >>  error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:24:
> >>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 
> >> 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:26:
> >>  error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:23:
> >>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 
> >> 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:26:
> >>  error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:23:
> >>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 
> >> 'constexpr' function
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:27:
> >>  error: non-constant condition for static assertion
> >> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:24:
> >>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 
> >> 'constexpr' function
> >> compiler exited with status 1
> >> FAIL: g++.dg/cpp2a/constexpr-virtual2.C   (test for excess errors)
> >
> > I think the primary problem here is:
> >   /* When using function descriptors, the address of the
> >  vtable entry is treated as a function pointer.  */
> >   if (TARGET_VTABLE_USES_DESCRIPTORS)
> > e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
> >  cp_build_addr_expr (e2, complain));
> > in typeck.c, on non-descriptor targets we have an INDIRECT_REF where we
> > read the vtable function pointer.  On ia64, the above optimizes the
> > INDIRECT_REF away, so what the cxx_eval_call_expression actually gets
> > after constexpr evaluating the CALL_FN is not ADDR_EXPR of a function,
> > but the address of the function descriptor (e.g. &_ZTV2X2 + 16 ).
> >
> > So, perhaps in cxx_eval_call_expression we need:
> >if (TREE_CODE (fun) == ADDR_EXPR)
> > fun = TREE_OPERAND (fun, 0);
> > +  else if (TARGET_VTABLE_USES_DESCRIPTORS
> > +  && TREE_CODE (fun) == POINTER_PLUS_EXPR
> > +  && ...)
> > where we verify that p+ first argument is ADDR_EXPR of a virtual table,
> > second arg is INTEGER_CST and just walk the DECL_INITIAL of that, finding
> > the FDESC_EXPR at the right offset (therefore, I believe you need following
> > rather than the patch you've posted, so that you can actually find it) and
> > finally pick the function from the FDESC_EXPR entry.
> > Makes me wonder what happens with indirect calls in constexpr evaluation,
> > e.g. if I do:
> > constexpr int bar () { return 42; }
> > constexpr int foo () { int (*fn) () = bar; return fn (); }
> > static_assert (foo () == 42);
> > but apparently this works.
> >
> > --- gcc/cp/class.c.jj   2018-09-20 09:56:59.229751895 +0200
> > +++ gcc/cp/class.c  2018-09-20 10:12:17.447370890 +0200
> > @@ -9266,7 +9266,6 @@ build_vtbl_initializer (tree binfo,
> >tree vcall_index;
> >tree fn, fn_original;
> >tree init = NULL_TREE;
> > -  tree idx = size_int (jx++);
> >
> >fn = BV_FN (v);
> >fn_original = fn;
> > @@ -9370,7 +9369,7 @@ build_vtbl_initializer (tree binfo,
> >   int i;
> >   if (init == size_zero_node)
> > for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> > - CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> > + CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
> >   else
> > for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> >   {
> > @@ -9378,11 +9377,11 @@ build_vtbl_initializer (tree binfo,
> >  fn, 

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-26 Thread Jason Merrill
On Thu, Sep 20, 2018 at 5:20 AM, Jakub Jelinek  wrote:
> On Thu, Sep 20, 2018 at 09:12:53AM +0200, Andreas Schwab wrote:
>> On Sep 19 2018, Jason Merrill  wrote:
>>
>> > Andreas, do the new testcases pass?  That would surprise me, but OK if so.
>>
>> No, they don't.
>>
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:26:
>>  error: non-constant condition for static assertion
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:23:
>>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
>> function
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:26:
>>  error: non-constant condition for static assertion
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:23:
>>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
>> function
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:27:
>>  error: non-constant condition for static assertion
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:24:
>>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
>> function
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:26:
>>  error: non-constant condition for static assertion
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:23:
>>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
>> function
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:26:
>>  error: non-constant condition for static assertion
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:23:
>>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
>> function
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:27:
>>  error: non-constant condition for static assertion
>> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:24:
>>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
>> function
>> compiler exited with status 1
>> FAIL: g++.dg/cpp2a/constexpr-virtual2.C   (test for excess errors)
>
> I think the primary problem here is:
>   /* When using function descriptors, the address of the
>  vtable entry is treated as a function pointer.  */
>   if (TARGET_VTABLE_USES_DESCRIPTORS)
> e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
>  cp_build_addr_expr (e2, complain));
> in typeck.c, on non-descriptor targets we have an INDIRECT_REF where we
> read the vtable function pointer.  On ia64, the above optimizes the
> INDIRECT_REF away, so what the cxx_eval_call_expression actually gets
> after constexpr evaluating the CALL_FN is not ADDR_EXPR of a function,
> but the address of the function descriptor (e.g. &_ZTV2X2 + 16 ).
>
> So, perhaps in cxx_eval_call_expression we need:
>if (TREE_CODE (fun) == ADDR_EXPR)
> fun = TREE_OPERAND (fun, 0);
> +  else if (TARGET_VTABLE_USES_DESCRIPTORS
> +  && TREE_CODE (fun) == POINTER_PLUS_EXPR
> +  && ...)
> where we verify that p+ first argument is ADDR_EXPR of a virtual table,
> second arg is INTEGER_CST and just walk the DECL_INITIAL of that, finding
> the FDESC_EXPR at the right offset (therefore, I believe you need following
> rather than the patch you've posted, so that you can actually find it) and
> finally pick the function from the FDESC_EXPR entry.
> Makes me wonder what happens with indirect calls in constexpr evaluation,
> e.g. if I do:
> constexpr int bar () { return 42; }
> constexpr int foo () { int (*fn) () = bar; return fn (); }
> static_assert (foo () == 42);
> but apparently this works.
>
> --- gcc/cp/class.c.jj   2018-09-20 09:56:59.229751895 +0200
> +++ gcc/cp/class.c  2018-09-20 10:12:17.447370890 +0200
> @@ -9266,7 +9266,6 @@ build_vtbl_initializer (tree binfo,
>tree vcall_index;
>tree fn, fn_original;
>tree init = NULL_TREE;
> -  tree idx = size_int (jx++);
>
>fn = BV_FN (v);
>fn_original = fn;
> @@ -9370,7 +9369,7 @@ build_vtbl_initializer (tree binfo,
>   int i;
>   if (init == size_zero_node)
> for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> - CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> + CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
>   else
> for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
>   {
> @@ -9378,11 +9377,11 @@ build_vtbl_initializer (tree binfo,
>  fn, build_int_cst (NULL_TREE, i));
> TREE_CONSTANT (fdesc) = 1;
>
> -   CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
> +   CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), fdesc);
>   }
> }
>else

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-20 Thread Jakub Jelinek
On Thu, Sep 20, 2018 at 09:12:53AM +0200, Andreas Schwab wrote:
> On Sep 19 2018, Jason Merrill  wrote:
> 
> > Andreas, do the new testcases pass?  That would surprise me, but OK if so.
> 
> No, they don't.
> 
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:26:
>  error: non-constant condition for static assertion
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:23:
>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
> function
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:26:
>  error: non-constant condition for static assertion
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:23:
>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
> function
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:27:
>  error: non-constant condition for static assertion
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:24:
>  error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
> function
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:26:
>  error: non-constant condition for static assertion
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:23:
>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
> function
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:26:
>  error: non-constant condition for static assertion
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:23:
>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
> function
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:27:
>  error: non-constant condition for static assertion
> /usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:24:
>  error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
> function
> compiler exited with status 1
> FAIL: g++.dg/cpp2a/constexpr-virtual2.C   (test for excess errors)

I think the primary problem here is:
  /* When using function descriptors, the address of the
 vtable entry is treated as a function pointer.  */
  if (TARGET_VTABLE_USES_DESCRIPTORS)
e2 = build1 (NOP_EXPR, TREE_TYPE (e2),
 cp_build_addr_expr (e2, complain));
in typeck.c, on non-descriptor targets we have an INDIRECT_REF where we
read the vtable function pointer.  On ia64, the above optimizes the
INDIRECT_REF away, so what the cxx_eval_call_expression actually gets
after constexpr evaluating the CALL_FN is not ADDR_EXPR of a function,
but the address of the function descriptor (e.g. &_ZTV2X2 + 16 ).

So, perhaps in cxx_eval_call_expression we need:
   if (TREE_CODE (fun) == ADDR_EXPR)
fun = TREE_OPERAND (fun, 0);
+  else if (TARGET_VTABLE_USES_DESCRIPTORS
+  && TREE_CODE (fun) == POINTER_PLUS_EXPR
+  && ...)
where we verify that p+ first argument is ADDR_EXPR of a virtual table,
second arg is INTEGER_CST and just walk the DECL_INITIAL of that, finding
the FDESC_EXPR at the right offset (therefore, I believe you need following
rather than the patch you've posted, so that you can actually find it) and
finally pick the function from the FDESC_EXPR entry.
Makes me wonder what happens with indirect calls in constexpr evaluation,
e.g. if I do:
constexpr int bar () { return 42; }
constexpr int foo () { int (*fn) () = bar; return fn (); }
static_assert (foo () == 42);
but apparently this works.

--- gcc/cp/class.c.jj   2018-09-20 09:56:59.229751895 +0200
+++ gcc/cp/class.c  2018-09-20 10:12:17.447370890 +0200
@@ -9266,7 +9266,6 @@ build_vtbl_initializer (tree binfo,
   tree vcall_index;
   tree fn, fn_original;
   tree init = NULL_TREE;
-  tree idx = size_int (jx++);
 
   fn = BV_FN (v);
   fn_original = fn;
@@ -9370,7 +9369,7 @@ build_vtbl_initializer (tree binfo,
  int i;
  if (init == size_zero_node)
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
- CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
+ CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
  else
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
  {
@@ -9378,11 +9377,11 @@ build_vtbl_initializer (tree binfo,
 fn, build_int_cst (NULL_TREE, i));
TREE_CONSTANT (fdesc) = 1;
 
-   CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
+   CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), fdesc);
  }
}
   else
-   CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
+   CONSTRUCTOR_APPEND_ELT (*inits, size_int (jx++), init);
 }
 }
 


Jakub


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-20 Thread Andreas Schwab
On Sep 19 2018, Jason Merrill  wrote:

> Andreas, do the new testcases pass?  That would surprise me, but OK if so.

No, they don't.

/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:26:
 error: non-constant condition for static assertion
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:29:23:
 error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
function
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:26:
 error: non-constant condition for static assertion
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:33:23:
 error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
function
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:27:
 error: non-constant condition for static assertion
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:37:24:
 error: expression '((& X2::_ZTV2X2) + 16)' does not designate a 'constexpr' 
function
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:26:
 error: non-constant condition for static assertion
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:41:23:
 error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
function
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:26:
 error: non-constant condition for static assertion
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:45:23:
 error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
function
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:27:
 error: non-constant condition for static assertion
/usr/local/gcc/gcc-20180920/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual2.C:49:24:
 error: expression '((& X4::_ZTV2X4) + 16)' does not designate a 'constexpr' 
function
compiler exited with status 1
FAIL: g++.dg/cpp2a/constexpr-virtual2.C   (test for excess errors)

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-19 Thread Jason Merrill
On Wed, Sep 19, 2018 at 11:10 AM, Marek Polacek  wrote:
> On Wed, Sep 19, 2018 at 05:07:34PM +0200, Andreas Schwab wrote:
>> On Sep 19 2018, Marek Polacek  wrote:
>>
>> > 2018-09-19  Marek Polacek  
>> >
>> > * class.c (build_vtbl_initializer): Don't mess with *inits for
>> > TARGET_VTABLE_USES_DESCRIPTORS.
>> >
>> > diff --git gcc/cp/class.c gcc/cp/class.c
>> > index 9ca46441871..0239f6ae045 100644
>> > --- gcc/cp/class.c
>> > +++ gcc/cp/class.c
>> > @@ -9370,7 +9370,7 @@ build_vtbl_initializer (tree binfo,
>> >   int i;
>> >   if (init == size_zero_node)
>> > for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
>> > - CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
>> > + CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
>> >   else
>> > for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
>> >   {
>> > @@ -9378,7 +9378,7 @@ build_vtbl_initializer (tree binfo,
>> >  fn, build_int_cst (NULL_TREE, i));
>> > TREE_CONSTANT (fdesc) = 1;
>> >
>> > -   CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
>> > +   CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
>> >   }
>> > }
>> >else
>>
>> Thanks, that works.
>
> Great.  Jason, can I commit it then?

Andreas, do the new testcases pass?  That would surprise me, but OK if so.

Jason


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-19 Thread Marek Polacek
On Wed, Sep 19, 2018 at 05:07:34PM +0200, Andreas Schwab wrote:
> On Sep 19 2018, Marek Polacek  wrote:
> 
> > 2018-09-19  Marek Polacek  
> >
> > * class.c (build_vtbl_initializer): Don't mess with *inits for
> > TARGET_VTABLE_USES_DESCRIPTORS.
> >
> > diff --git gcc/cp/class.c gcc/cp/class.c
> > index 9ca46441871..0239f6ae045 100644
> > --- gcc/cp/class.c
> > +++ gcc/cp/class.c
> > @@ -9370,7 +9370,7 @@ build_vtbl_initializer (tree binfo,
> >   int i;
> >   if (init == size_zero_node)
> > for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> > - CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> > + CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
> >   else
> > for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> >   {
> > @@ -9378,7 +9378,7 @@ build_vtbl_initializer (tree binfo,
> >  fn, build_int_cst (NULL_TREE, i));
> > TREE_CONSTANT (fdesc) = 1;
> >  
> > -   CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
> > +   CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
> >   }
> > }
> >else
> 
> Thanks, that works.

Great.  Jason, can I commit it then?

Marek


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-19 Thread Andreas Schwab
On Sep 19 2018, Marek Polacek  wrote:

> 2018-09-19  Marek Polacek  
>
>   * class.c (build_vtbl_initializer): Don't mess with *inits for
>   TARGET_VTABLE_USES_DESCRIPTORS.
>
> diff --git gcc/cp/class.c gcc/cp/class.c
> index 9ca46441871..0239f6ae045 100644
> --- gcc/cp/class.c
> +++ gcc/cp/class.c
> @@ -9370,7 +9370,7 @@ build_vtbl_initializer (tree binfo,
> int i;
> if (init == size_zero_node)
>   for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> -   CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
> +   CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
> else
>   for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
> {
> @@ -9378,7 +9378,7 @@ build_vtbl_initializer (tree binfo,
>fn, build_int_cst (NULL_TREE, i));
>   TREE_CONSTANT (fdesc) = 1;
>  
> - CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
> + CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
> }
>   }
>else

Thanks, that works.

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-19 Thread Marek Polacek
On Wed, Sep 19, 2018 at 03:25:02PM +0200, Andreas Schwab wrote:
> I'm getting this ICE on ia64:
> 
> libtool: compile:  /usr/local/gcc/gcc-20180919/Build/./gcc/xgcc 
> -shared-libgcc -B/usr/local/gcc/gcc-20180919/Build/./gcc -nostdinc++ 
> -L/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/src 
> -L/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/src/.libs 
> -L/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/libsupc++/.libs
>  -B/usr/ia64-suse-linux/bin/ -B/usr/ia64-suse-linux/lib/ -isystem 
> /usr/ia64-suse-linux/include -isystem /usr/ia64-suse-linux/sys-include 
> -fno-checking -I/usr/local/gcc/gcc-20180919/libstdc++-v3/../libgcc 
> -I/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/include/ia64-suse-linux
>  -I/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/include 
> -I/usr/local/gcc/gcc-20180919/libstdc++-v3/libsupc++ -D_GLIBCXX_SHARED 
> -fno-implicit-templates -Wall -Wextra -Wwrite-strings -Wcast-qual -Wabi=2 
> -fdiagnostics-show-location=once -ffunction-sections -fdata-sections 
> -frandom-seed=bad_typeid.lo -O2 -g -D_GNU_SOURCE -c 
> ../../../../libstdc++-v3/libsupc++/bad_typeid.cc  -fPIC -DPIC 
> -D_GLIBCXX_SHARED -o bad_typeid.o
> ../../../../libstdc++-v3/libsupc++/bad_typeid.cc:36:1: internal compiler 
> error: in output_constructor_regular_field, at varasm.c:5165
> 36 | } // namespace std
>| ^
> 0x4176abaf output_constructor_regular_field
> ../../gcc/varasm.c:5165
> 0x4176d09f output_constructor
> ../../gcc/varasm.c:5475
> 0x4176940f output_constant
> ../../gcc/varasm.c:4967
> 0x4175414f assemble_variable_contents
> ../../gcc/varasm.c:2143
> 0x4175586f assemble_variable(tree_node*, int, int, int)
> ../../gcc/varasm.c:2319
> 0x417a564f varpool_node::assemble_decl()
> ../../gcc/varpool.c:586
> 0x417a74cf symbol_table::output_variables()
> ../../gcc/varpool.c:752
> 0x407b806f symbol_table::compile()
> ../../gcc/cgraphunit.c:2611
> 0x407bd8ef symbol_table::compile()
> ../../gcc/cgraphunit.c:2791
> 0x407bd8ef symbol_table::finalize_compilation_unit()
> ../../gcc/cgraphunit.c:2788
> 
> (gdb) up
> #1  0x4176abb0 in output_constructor_regular_field (
> local=0x600ee920) at ../../gcc/varasm.c:5165
> 5165gcc_assert (fieldpos == local->total_bytes);
> (gdb) p fieldpos
> $1 = 16
> (gdb) p local->total_bytes
> $2 = 24

That muset be because ia64 uses TARGET_VTABLE_USES_DESCRIPTORS.
Does this help?

2018-09-19  Marek Polacek  

* class.c (build_vtbl_initializer): Don't mess with *inits for
TARGET_VTABLE_USES_DESCRIPTORS.

diff --git gcc/cp/class.c gcc/cp/class.c
index 9ca46441871..0239f6ae045 100644
--- gcc/cp/class.c
+++ gcc/cp/class.c
@@ -9370,7 +9370,7 @@ build_vtbl_initializer (tree binfo,
  int i;
  if (init == size_zero_node)
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
- CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
+ CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
  else
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
  {
@@ -9378,7 +9378,7 @@ build_vtbl_initializer (tree binfo,
 fn, build_int_cst (NULL_TREE, i));
TREE_CONSTANT (fdesc) = 1;
 
-   CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
+   CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
  }
}
   else


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-19 Thread Andreas Schwab
I'm getting this ICE on ia64:

libtool: compile:  /usr/local/gcc/gcc-20180919/Build/./gcc/xgcc -shared-libgcc 
-B/usr/local/gcc/gcc-20180919/Build/./gcc -nostdinc++ 
-L/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/src 
-L/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/src/.libs 
-L/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/libsupc++/.libs
 -B/usr/ia64-suse-linux/bin/ -B/usr/ia64-suse-linux/lib/ -isystem 
/usr/ia64-suse-linux/include -isystem /usr/ia64-suse-linux/sys-include 
-fno-checking -I/usr/local/gcc/gcc-20180919/libstdc++-v3/../libgcc 
-I/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/include/ia64-suse-linux
 -I/usr/local/gcc/gcc-20180919/Build/ia64-suse-linux/libstdc++-v3/include 
-I/usr/local/gcc/gcc-20180919/libstdc++-v3/libsupc++ -D_GLIBCXX_SHARED 
-fno-implicit-templates -Wall -Wextra -Wwrite-strings -Wcast-qual -Wabi=2 
-fdiagnostics-show-location=once -ffunction-sections -fdata-sections 
-frandom-seed=bad_typeid.lo -O2 -g -D_GNU_SOURCE -c 
../../../../libstdc++-v3/libsupc++/bad_typeid.cc  -fPIC -DPIC -D_GLIBCXX_SHARED 
-o bad_typeid.o
../../../../libstdc++-v3/libsupc++/bad_typeid.cc:36:1: internal compiler error: 
in output_constructor_regular_field, at varasm.c:5165
36 | } // namespace std
   | ^
0x4176abaf output_constructor_regular_field
../../gcc/varasm.c:5165
0x4176d09f output_constructor
../../gcc/varasm.c:5475
0x4176940f output_constant
../../gcc/varasm.c:4967
0x4175414f assemble_variable_contents
../../gcc/varasm.c:2143
0x4175586f assemble_variable(tree_node*, int, int, int)
../../gcc/varasm.c:2319
0x417a564f varpool_node::assemble_decl()
../../gcc/varpool.c:586
0x417a74cf symbol_table::output_variables()
../../gcc/varpool.c:752
0x407b806f symbol_table::compile()
../../gcc/cgraphunit.c:2611
0x407bd8ef symbol_table::compile()
../../gcc/cgraphunit.c:2791
0x407bd8ef symbol_table::finalize_compilation_unit()
../../gcc/cgraphunit.c:2788

(gdb) up
#1  0x4176abb0 in output_constructor_regular_field (
local=0x600ee920) at ../../gcc/varasm.c:5165
5165gcc_assert (fieldpos == local->total_bytes);
(gdb) p fieldpos
$1 = 16
(gdb) p local->total_bytes
$2 = 24

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-18 Thread Marek Polacek
On Tue, Sep 18, 2018 at 02:29:16PM -0400, Jason Merrill wrote:
> > --- gcc/cp/class.c
> > +++ gcc/cp/class.c
> > @@ -9266,6 +9266,7 @@ build_vtbl_initializer (tree binfo,
> >tree vcall_index;
> >tree fn, fn_original;
> >tree init = NULL_TREE;
> > +  tree idx = build_int_cst (size_type_node, jx++);
> 
> Let's use size_int here, like in process_init_constructor_array.

Done.
 
> OK with that change.

Thanks for quick reviews!  Next one: explicit(bool).

Applying to trunk.

2018-09-18  Marek Polacek  

P1064R0 - Allowing Virtual Function Calls in Constant Expressions
* call.c (build_over_call): No longer check if we're outside a template
function.
* class.c (build_vtbl_initializer): Build vtable's constructor with
indexes.
* constexpr.c (cxx_eval_constant_expression): Don't ignore _vptr's
initializer.  Handle OBJ_TYPE_REF.
(potential_constant_expression_1): Handle OBJ_TYPE_REF.
* decl.c (maybe_commonize_var): Bail out for any DECL_ARTIFICIAL.
(initialize_artificial_var): Mark the variable as constexpr.
(grokdeclarator): Change error to pedwarn.  Only warn when
pedantic and not C++2a.

* gimple-fold.c (gimple_get_virt_method_for_vtable): Adjust assert.

* g++.dg/cpp0x/constexpr-virtual5.C: Adjust dg-error.
* g++.dg/cpp2a/constexpr-virtual1.C: New test.
* g++.dg/cpp2a/constexpr-virtual2.C: New test.
* g++.dg/cpp2a/constexpr-virtual3.C: New test.
* g++.dg/cpp2a/constexpr-virtual4.C: New test.
* g++.dg/cpp2a/constexpr-virtual5.C: New test.
* g++.dg/cpp2a/constexpr-virtual6.C: New test.
* g++.dg/cpp2a/constexpr-virtual7.C: New test.
* g++.dg/cpp2a/constexpr-virtual8.C: New test.
* g++.dg/cpp2a/constexpr-virtual9.C: New test.
* g++.dg/diagnostic/virtual-constexpr.C: Skip for C++2a.  Use
-pedantic-errors.  Adjust dg-error.

diff --git gcc/cp/call.c gcc/cp/call.c
index 69503ca7920..ddf0ed044a0 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -8399,10 +8399,7 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
   && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL)
 maybe_warn_class_memaccess (input_location, fn, args);
 
-  if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
-  /* Don't mess with virtual lookup in instantiate_non_dependent_expr;
-virtual functions can't be constexpr.  */
-  && !in_template_function ())
+  if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
 {
   tree t;
   tree binfo = lookup_base (TREE_TYPE (TREE_TYPE (argarray[0])),
diff --git gcc/cp/class.c gcc/cp/class.c
index e950a7423f7..9ca46441871 100644
--- gcc/cp/class.c
+++ gcc/cp/class.c
@@ -9266,6 +9266,7 @@ build_vtbl_initializer (tree binfo,
   tree vcall_index;
   tree fn, fn_original;
   tree init = NULL_TREE;
+  tree idx = size_int (jx++);
 
   fn = BV_FN (v);
   fn_original = fn;
@@ -9369,7 +9370,7 @@ build_vtbl_initializer (tree binfo,
  int i;
  if (init == size_zero_node)
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
- CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
+ CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
  else
for (i = 0; i < TARGET_VTABLE_USES_DESCRIPTORS; ++i)
  {
@@ -9377,11 +9378,11 @@ build_vtbl_initializer (tree binfo,
 fn, build_int_cst (NULL_TREE, i));
TREE_CONSTANT (fdesc) = 1;
 
-   CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, fdesc);
+   CONSTRUCTOR_APPEND_ELT (*inits, idx, fdesc);
  }
}
   else
-   CONSTRUCTOR_APPEND_ELT (*inits, NULL_TREE, init);
+   CONSTRUCTOR_APPEND_ELT (*inits, idx, init);
 }
 }
 
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 88c73787961..aa33319875f 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -4209,7 +4209,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
 CONST_DECL for aggregate constants.  */
   if (lval)
return t;
+  /* is_really_empty_class doesn't take into account _vptr, so initializing
+otherwise empty class with { } would overwrite the initializer that
+initialize_vtable created for us.  */
   if (COMPLETE_TYPE_P (TREE_TYPE (t))
+ && !TYPE_POLYMORPHIC_P (TREE_TYPE (t))
  && is_really_empty_class (TREE_TYPE (t)))
{
  /* If the class is empty, we aren't actually loading anything.  */
@@ -4778,7 +4782,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
 case MODOP_EXPR:
   /* GCC internal stuff.  */
 case VA_ARG_EXPR:
-case OBJ_TYPE_REF:
 case NON_DEPENDENT_EXPR:
 case BASELINK:
 case OFFSET_REF:
@@ -4788,6 +4791,34 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
   

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-18 Thread Jason Merrill
On Tue, Sep 18, 2018 at 11:25 AM, Marek Polacek  wrote:
> On Mon, Sep 17, 2018 at 11:28:06PM -0400, Jason Merrill wrote:
>> On Mon, Sep 17, 2018 at 5:39 PM, Marek Polacek  wrote:
>> > On Fri, Sep 14, 2018 at 04:45:22PM -0400, Marek Polacek wrote:
>> >> On Fri, Sep 14, 2018 at 04:30:46PM -0400, Jason Merrill wrote:
>> >> > On Fri, Sep 14, 2018 at 1:19 PM, Marek Polacek  
>> >> > wrote:
>> >> > > This patch implements another bit of C++20, virtual calls in constant
>> >> > > expression:
>> >> > > 
>> >> > > The basic idea is that since in a constant expression we know the 
>> >> > > dynamic
>> >> > > type (to detect invalid code etc.), the restriction that prohibits 
>> >> > > virtual
>> >> > > calls is unnecessary.
>> >> > >
>> >> > > Handling virtual function calls turned out to be fairly easy (as 
>> >> > > anticipated);
>> >> > > I simply let the constexpr machinery figure out the dynamic type and 
>> >> > > then
>> >> > > OBJ_TYPE_REF_TOKEN gives us the index into the virtual function 
>> >> > > table.  That
>> >> > > way we get the function decl we're interested in, and 
>> >> > > cxx_eval_call_expression
>> >> > > takes it from there.
>> >> > >
>> >> > > But handling pointer-to-virtual-member-functions doesn't work like 
>> >> > > that.
>> >> > > get_member_function_from_ptrfunc creates a COND_EXPR which looks like
>> >> > > if (pf.__pfn & 1) // is it a virtual function?
>> >> > >   // yes, find the pointer in the vtable
>> >> > > else
>> >> > >   // no, just return the pointer
>> >> > > so ideally we want to evaluate the then-branch.  Eventually it'll 
>> >> > > evaluate it
>> >> > > to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd 
>> >> > > end up
>> >> > > with "not a constant expression" error.
>> >> >
>> >> > Then let's mark the vtable as constexpr, there's no reason for it not 
>> >> > to be.
>> >
>> > Done.  But then I had to add indexes to the vtable's ctor (because 
>> > find_array_ctor_elt
>> > expects it), which broke an assert in gimple_get_virt_method_for_vtable.  
>> > But I
>> > don't need the array_ref hack anymore!
>>
>> > Also, I had to set DECL_DECLARED_CONSTEXPR_P after maybe_commonize_var,
>> > otherwise we run into the sorry in that function with -fno-weak...
>>
>> Hmm, we shouldn't give that sorry for DECL_ARTIFICIAL variables.
>>
>> Looking more closely, it seems that the call to maybe_commonize_var
>> from initialize_artificial_var did nothing before this change, since
>> the vtable is DECL_ARTIFICIAL, so it didn't pass the condition at the
>> top.  I suppose we should extend the !DECL_ARTIFICIAL check in
>> maybe_commonize_var to the inline variable case as well.
>
> Done.  And then I could move setting DECL_DECLARED_CONSTEXPR_P to
> initialize_artificial_var, which is where I think it belongs.
>
>> >> Ok, unfortunately it wasn't as easy as merely marking it 
>> >> DECL_DECLARED_CONSTEXPR_P
>> >> in initialize_artificial_var because then I saw "used in its own 
>> >> initializer"
>> >> error.  Which I don't know why, but now that I know you agree with this 
>> >> direction
>> >> I can dig deeper.
>> >>
>> >> > > Since the vtable initializer is
>> >> > > a compile-time constant, I thought we could make it work by a hack as 
>> >> > > the one
>> >> > > in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression 
>> >> > > do its
>> >> > > job and everything is hunky-dory.
>> >> > >
>> >> > > Except when it isn't: I noticed that the presence of _vptr doesn't 
>> >> > > make the
>> >> > > class non-empty, and when cxx_eval_constant_expression saw a decl 
>> >> > > with an empty
>> >> > > class type, it just evaluated it to { }.  But such a class still had 
>> >> > > gotten an
>> >> > > initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  
>> >> > > So
>> >> > > replacing it with { } will lose the proper initializer whereupon we 
>> >> > > fail.
>> >> > > The check I've added to cxx_eval_constant_expression won't win any 
>> >> > > beauty
>> >> > > contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.
>> >> >
>> >> > Perhaps we should check !TYPE_POLYMORPHIC_P as well as
>> >> > is_really_empty_class.  Perhaps there should be a predicate for that,
>> >> > say, is_really_nearly_empty_class...
>> >
>> > For now I've only added the !TYPE_POLYMORPHIC_P check, which works just 
>> > fine.
>> >
>> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>> >
>> > 2018-09-17  Marek Polacek  
>> >
>> > P1064R0 - Allowing Virtual Function Calls in Constant Expressions
>> > * call.c (build_over_call): Add FIXME.
>> > * class.c (initialize_vtable): Mark the vtable as constexpr.
>> > (build_vtbl_initializer): Build vtable's constructor with indexes.
>> > * constexpr.c (cxx_eval_constant_expression): Don't ignore _vptr's
>> > initializer.  Handle OBJ_TYPE_REF.
>> > (potential_constant_expression_1): Handle 

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v4)

2018-09-18 Thread Marek Polacek
On Mon, Sep 17, 2018 at 11:28:06PM -0400, Jason Merrill wrote:
> On Mon, Sep 17, 2018 at 5:39 PM, Marek Polacek  wrote:
> > On Fri, Sep 14, 2018 at 04:45:22PM -0400, Marek Polacek wrote:
> >> On Fri, Sep 14, 2018 at 04:30:46PM -0400, Jason Merrill wrote:
> >> > On Fri, Sep 14, 2018 at 1:19 PM, Marek Polacek  
> >> > wrote:
> >> > > This patch implements another bit of C++20, virtual calls in constant
> >> > > expression:
> >> > > 
> >> > > The basic idea is that since in a constant expression we know the 
> >> > > dynamic
> >> > > type (to detect invalid code etc.), the restriction that prohibits 
> >> > > virtual
> >> > > calls is unnecessary.
> >> > >
> >> > > Handling virtual function calls turned out to be fairly easy (as 
> >> > > anticipated);
> >> > > I simply let the constexpr machinery figure out the dynamic type and 
> >> > > then
> >> > > OBJ_TYPE_REF_TOKEN gives us the index into the virtual function table. 
> >> > >  That
> >> > > way we get the function decl we're interested in, and 
> >> > > cxx_eval_call_expression
> >> > > takes it from there.
> >> > >
> >> > > But handling pointer-to-virtual-member-functions doesn't work like 
> >> > > that.
> >> > > get_member_function_from_ptrfunc creates a COND_EXPR which looks like
> >> > > if (pf.__pfn & 1) // is it a virtual function?
> >> > >   // yes, find the pointer in the vtable
> >> > > else
> >> > >   // no, just return the pointer
> >> > > so ideally we want to evaluate the then-branch.  Eventually it'll 
> >> > > evaluate it
> >> > > to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd 
> >> > > end up
> >> > > with "not a constant expression" error.
> >> >
> >> > Then let's mark the vtable as constexpr, there's no reason for it not to 
> >> > be.
> >
> > Done.  But then I had to add indexes to the vtable's ctor (because 
> > find_array_ctor_elt
> > expects it), which broke an assert in gimple_get_virt_method_for_vtable.  
> > But I
> > don't need the array_ref hack anymore!
> 
> > Also, I had to set DECL_DECLARED_CONSTEXPR_P after maybe_commonize_var,
> > otherwise we run into the sorry in that function with -fno-weak...
> 
> Hmm, we shouldn't give that sorry for DECL_ARTIFICIAL variables.
> 
> Looking more closely, it seems that the call to maybe_commonize_var
> from initialize_artificial_var did nothing before this change, since
> the vtable is DECL_ARTIFICIAL, so it didn't pass the condition at the
> top.  I suppose we should extend the !DECL_ARTIFICIAL check in
> maybe_commonize_var to the inline variable case as well.

Done.  And then I could move setting DECL_DECLARED_CONSTEXPR_P to
initialize_artificial_var, which is where I think it belongs.

> >> Ok, unfortunately it wasn't as easy as merely marking it 
> >> DECL_DECLARED_CONSTEXPR_P
> >> in initialize_artificial_var because then I saw "used in its own 
> >> initializer"
> >> error.  Which I don't know why, but now that I know you agree with this 
> >> direction
> >> I can dig deeper.
> >>
> >> > > Since the vtable initializer is
> >> > > a compile-time constant, I thought we could make it work by a hack as 
> >> > > the one
> >> > > in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression 
> >> > > do its
> >> > > job and everything is hunky-dory.
> >> > >
> >> > > Except when it isn't: I noticed that the presence of _vptr doesn't 
> >> > > make the
> >> > > class non-empty, and when cxx_eval_constant_expression saw a decl with 
> >> > > an empty
> >> > > class type, it just evaluated it to { }.  But such a class still had 
> >> > > gotten an
> >> > > initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  
> >> > > So
> >> > > replacing it with { } will lose the proper initializer whereupon we 
> >> > > fail.
> >> > > The check I've added to cxx_eval_constant_expression won't win any 
> >> > > beauty
> >> > > contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.
> >> >
> >> > Perhaps we should check !TYPE_POLYMORPHIC_P as well as
> >> > is_really_empty_class.  Perhaps there should be a predicate for that,
> >> > say, is_really_nearly_empty_class...
> >
> > For now I've only added the !TYPE_POLYMORPHIC_P check, which works just 
> > fine.
> >
> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> >
> > 2018-09-17  Marek Polacek  
> >
> > P1064R0 - Allowing Virtual Function Calls in Constant Expressions
> > * call.c (build_over_call): Add FIXME.
> > * class.c (initialize_vtable): Mark the vtable as constexpr.
> > (build_vtbl_initializer): Build vtable's constructor with indexes.
> > * constexpr.c (cxx_eval_constant_expression): Don't ignore _vptr's
> > initializer.  Handle OBJ_TYPE_REF.
> > (potential_constant_expression_1): Handle OBJ_TYPE_REF.
> > * decl.c (grokdeclarator): Change error to pedwarn.  Only warn when
> > pedantic and not C++2a.
> >
> > * gimple-fold.c 

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions

2018-09-17 Thread Jason Merrill
On Mon, Sep 17, 2018 at 5:39 PM, Marek Polacek  wrote:
> On Fri, Sep 14, 2018 at 04:45:22PM -0400, Marek Polacek wrote:
>> On Fri, Sep 14, 2018 at 04:30:46PM -0400, Jason Merrill wrote:
>> > On Fri, Sep 14, 2018 at 1:19 PM, Marek Polacek  wrote:
>> > > This patch implements another bit of C++20, virtual calls in constant
>> > > expression:
>> > > 
>> > > The basic idea is that since in a constant expression we know the dynamic
>> > > type (to detect invalid code etc.), the restriction that prohibits 
>> > > virtual
>> > > calls is unnecessary.
>> > >
>> > > Handling virtual function calls turned out to be fairly easy (as 
>> > > anticipated);
>> > > I simply let the constexpr machinery figure out the dynamic type and then
>> > > OBJ_TYPE_REF_TOKEN gives us the index into the virtual function table.  
>> > > That
>> > > way we get the function decl we're interested in, and 
>> > > cxx_eval_call_expression
>> > > takes it from there.
>> > >
>> > > But handling pointer-to-virtual-member-functions doesn't work like that.
>> > > get_member_function_from_ptrfunc creates a COND_EXPR which looks like
>> > > if (pf.__pfn & 1) // is it a virtual function?
>> > >   // yes, find the pointer in the vtable
>> > > else
>> > >   // no, just return the pointer
>> > > so ideally we want to evaluate the then-branch.  Eventually it'll 
>> > > evaluate it
>> > > to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd end 
>> > > up
>> > > with "not a constant expression" error.
>> >
>> > Then let's mark the vtable as constexpr, there's no reason for it not to 
>> > be.
>
> Done.  But then I had to add indexes to the vtable's ctor (because 
> find_array_ctor_elt
> expects it), which broke an assert in gimple_get_virt_method_for_vtable.  But 
> I
> don't need the array_ref hack anymore!

> Also, I had to set DECL_DECLARED_CONSTEXPR_P after maybe_commonize_var,
> otherwise we run into the sorry in that function with -fno-weak...

Hmm, we shouldn't give that sorry for DECL_ARTIFICIAL variables.

Looking more closely, it seems that the call to maybe_commonize_var
from initialize_artificial_var did nothing before this change, since
the vtable is DECL_ARTIFICIAL, so it didn't pass the condition at the
top.  I suppose we should extend the !DECL_ARTIFICIAL check in
maybe_commonize_var to the inline variable case as well.

>> Ok, unfortunately it wasn't as easy as merely marking it 
>> DECL_DECLARED_CONSTEXPR_P
>> in initialize_artificial_var because then I saw "used in its own initializer"
>> error.  Which I don't know why, but now that I know you agree with this 
>> direction
>> I can dig deeper.
>>
>> > > Since the vtable initializer is
>> > > a compile-time constant, I thought we could make it work by a hack as 
>> > > the one
>> > > in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression do 
>> > > its
>> > > job and everything is hunky-dory.
>> > >
>> > > Except when it isn't: I noticed that the presence of _vptr doesn't make 
>> > > the
>> > > class non-empty, and when cxx_eval_constant_expression saw a decl with 
>> > > an empty
>> > > class type, it just evaluated it to { }.  But such a class still had 
>> > > gotten an
>> > > initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  So
>> > > replacing it with { } will lose the proper initializer whereupon we fail.
>> > > The check I've added to cxx_eval_constant_expression won't win any beauty
>> > > contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.
>> >
>> > Perhaps we should check !TYPE_POLYMORPHIC_P as well as
>> > is_really_empty_class.  Perhaps there should be a predicate for that,
>> > say, is_really_nearly_empty_class...
>
> For now I've only added the !TYPE_POLYMORPHIC_P check, which works just fine.
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
>
> 2018-09-17  Marek Polacek  
>
> P1064R0 - Allowing Virtual Function Calls in Constant Expressions
> * call.c (build_over_call): Add FIXME.
> * class.c (initialize_vtable): Mark the vtable as constexpr.
> (build_vtbl_initializer): Build vtable's constructor with indexes.
> * constexpr.c (cxx_eval_constant_expression): Don't ignore _vptr's
> initializer.  Handle OBJ_TYPE_REF.
> (potential_constant_expression_1): Handle OBJ_TYPE_REF.
> * decl.c (grokdeclarator): Change error to pedwarn.  Only warn when
> pedantic and not C++2a.
>
> * gimple-fold.c (gimple_get_virt_method_for_vtable): Remove assert.
>
> * g++.dg/cpp0x/constexpr-virtual5.C: Adjust dg-error.
> * g++.dg/cpp2a/constexpr-virtual1.C: New test.
> * g++.dg/cpp2a/constexpr-virtual2.C: New test.
> * g++.dg/cpp2a/constexpr-virtual3.C: New test.
> * g++.dg/cpp2a/constexpr-virtual4.C: New test.
> * g++.dg/cpp2a/constexpr-virtual5.C: New test.
> * g++.dg/cpp2a/constexpr-virtual6.C: New test.
> * 

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions

2018-09-17 Thread Marek Polacek
On Fri, Sep 14, 2018 at 04:45:22PM -0400, Marek Polacek wrote:
> On Fri, Sep 14, 2018 at 04:30:46PM -0400, Jason Merrill wrote:
> > On Fri, Sep 14, 2018 at 1:19 PM, Marek Polacek  wrote:
> > > This patch implements another bit of C++20, virtual calls in constant
> > > expression:
> > > 
> > > The basic idea is that since in a constant expression we know the dynamic
> > > type (to detect invalid code etc.), the restriction that prohibits virtual
> > > calls is unnecessary.
> > >
> > > Handling virtual function calls turned out to be fairly easy (as 
> > > anticipated);
> > > I simply let the constexpr machinery figure out the dynamic type and then
> > > OBJ_TYPE_REF_TOKEN gives us the index into the virtual function table.  
> > > That
> > > way we get the function decl we're interested in, and 
> > > cxx_eval_call_expression
> > > takes it from there.
> > >
> > > But handling pointer-to-virtual-member-functions doesn't work like that.
> > > get_member_function_from_ptrfunc creates a COND_EXPR which looks like
> > > if (pf.__pfn & 1) // is it a virtual function?
> > >   // yes, find the pointer in the vtable
> > > else
> > >   // no, just return the pointer
> > > so ideally we want to evaluate the then-branch.  Eventually it'll 
> > > evaluate it
> > > to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd end 
> > > up
> > > with "not a constant expression" error.
> > 
> > Then let's mark the vtable as constexpr, there's no reason for it not to be.

Done.  But then I had to add indexes to the vtable's ctor (because 
find_array_ctor_elt
expects it), which broke an assert in gimple_get_virt_method_for_vtable.  But I
don't need the array_ref hack anymore!

Also, I had to set DECL_DECLARED_CONSTEXPR_P after maybe_commonize_var,
otherwise we run into the sorry in that function with -fno-weak...

> Ok, unfortunately it wasn't as easy as merely marking it 
> DECL_DECLARED_CONSTEXPR_P
> in initialize_artificial_var because then I saw "used in its own initializer"
> error.  Which I don't know why, but now that I know you agree with this 
> direction
> I can dig deeper.
>  
> > > Since the vtable initializer is
> > > a compile-time constant, I thought we could make it work by a hack as the 
> > > one
> > > in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression do 
> > > its
> > > job and everything is hunky-dory.
> > >
> > > Except when it isn't: I noticed that the presence of _vptr doesn't make 
> > > the
> > > class non-empty, and when cxx_eval_constant_expression saw a decl with an 
> > > empty
> > > class type, it just evaluated it to { }.  But such a class still had 
> > > gotten an
> > > initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  So
> > > replacing it with { } will lose the proper initializer whereupon we fail.
> > > The check I've added to cxx_eval_constant_expression won't win any beauty
> > > contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.
> > 
> > Perhaps we should check !TYPE_POLYMORPHIC_P as well as
> > is_really_empty_class.  Perhaps there should be a predicate for that,
> > say, is_really_nearly_empty_class...

For now I've only added the !TYPE_POLYMORPHIC_P check, which works just fine.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-09-17  Marek Polacek  

P1064R0 - Allowing Virtual Function Calls in Constant Expressions
* call.c (build_over_call): Add FIXME.
* class.c (initialize_vtable): Mark the vtable as constexpr.
(build_vtbl_initializer): Build vtable's constructor with indexes.
* constexpr.c (cxx_eval_constant_expression): Don't ignore _vptr's
initializer.  Handle OBJ_TYPE_REF.
(potential_constant_expression_1): Handle OBJ_TYPE_REF.
* decl.c (grokdeclarator): Change error to pedwarn.  Only warn when
pedantic and not C++2a.

* gimple-fold.c (gimple_get_virt_method_for_vtable): Remove assert.

* g++.dg/cpp0x/constexpr-virtual5.C: Adjust dg-error.
* g++.dg/cpp2a/constexpr-virtual1.C: New test.
* g++.dg/cpp2a/constexpr-virtual2.C: New test.
* g++.dg/cpp2a/constexpr-virtual3.C: New test.
* g++.dg/cpp2a/constexpr-virtual4.C: New test.
* g++.dg/cpp2a/constexpr-virtual5.C: New test.
* g++.dg/cpp2a/constexpr-virtual6.C: New test.
* g++.dg/cpp2a/constexpr-virtual7.C: New test.
* g++.dg/cpp2a/constexpr-virtual8.C: New test.
* g++.dg/cpp2a/constexpr-virtual9.C: New test.
* g++.dg/diagnostic/virtual-constexpr.C: Skip for C++2a.  Use
-pedantic-errors.  Adjust dg-error.

diff --git gcc/cp/call.c gcc/cp/call.c
index 69503ca7920..6c70874af40 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -8401,7 +8401,8 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
 
   if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
   /* Don't mess with virtual 

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions

2018-09-14 Thread Marek Polacek
On Fri, Sep 14, 2018 at 04:30:46PM -0400, Jason Merrill wrote:
> On Fri, Sep 14, 2018 at 1:19 PM, Marek Polacek  wrote:
> > This patch implements another bit of C++20, virtual calls in constant
> > expression:
> > 
> > The basic idea is that since in a constant expression we know the dynamic
> > type (to detect invalid code etc.), the restriction that prohibits virtual
> > calls is unnecessary.
> >
> > Handling virtual function calls turned out to be fairly easy (as 
> > anticipated);
> > I simply let the constexpr machinery figure out the dynamic type and then
> > OBJ_TYPE_REF_TOKEN gives us the index into the virtual function table.  That
> > way we get the function decl we're interested in, and 
> > cxx_eval_call_expression
> > takes it from there.
> >
> > But handling pointer-to-virtual-member-functions doesn't work like that.
> > get_member_function_from_ptrfunc creates a COND_EXPR which looks like
> > if (pf.__pfn & 1) // is it a virtual function?
> >   // yes, find the pointer in the vtable
> > else
> >   // no, just return the pointer
> > so ideally we want to evaluate the then-branch.  Eventually it'll evaluate 
> > it
> > to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd end up
> > with "not a constant expression" error.
> 
> Then let's mark the vtable as constexpr, there's no reason for it not to be.

Ok, unfortunately it wasn't as easy as merely marking it 
DECL_DECLARED_CONSTEXPR_P
in initialize_artificial_var because then I saw "used in its own initializer"
error.  Which I don't know why, but now that I know you agree with this 
direction
I can dig deeper.
 
> > Since the vtable initializer is
> > a compile-time constant, I thought we could make it work by a hack as the 
> > one
> > in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression do its
> > job and everything is hunky-dory.
> >
> > Except when it isn't: I noticed that the presence of _vptr doesn't make the
> > class non-empty, and when cxx_eval_constant_expression saw a decl with an 
> > empty
> > class type, it just evaluated it to { }.  But such a class still had gotten 
> > an
> > initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  So
> > replacing it with { } will lose the proper initializer whereupon we fail.
> > The check I've added to cxx_eval_constant_expression won't win any beauty
> > contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.
> 
> Perhaps we should check !TYPE_POLYMORPHIC_P as well as
> is_really_empty_class.  Perhaps there should be a predicate for that,
> say, is_really_nearly_empty_class...

Ack.  Thanks,

Marek


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions

2018-09-14 Thread Jason Merrill
On Fri, Sep 14, 2018 at 1:19 PM, Marek Polacek  wrote:
> This patch implements another bit of C++20, virtual calls in constant
> expression:
> 
> The basic idea is that since in a constant expression we know the dynamic
> type (to detect invalid code etc.), the restriction that prohibits virtual
> calls is unnecessary.
>
> Handling virtual function calls turned out to be fairly easy (as anticipated);
> I simply let the constexpr machinery figure out the dynamic type and then
> OBJ_TYPE_REF_TOKEN gives us the index into the virtual function table.  That
> way we get the function decl we're interested in, and cxx_eval_call_expression
> takes it from there.
>
> But handling pointer-to-virtual-member-functions doesn't work like that.
> get_member_function_from_ptrfunc creates a COND_EXPR which looks like
> if (pf.__pfn & 1) // is it a virtual function?
>   // yes, find the pointer in the vtable
> else
>   // no, just return the pointer
> so ideally we want to evaluate the then-branch.  Eventually it'll evaluate it
> to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd end up
> with "not a constant expression" error.

Then let's mark the vtable as constexpr, there's no reason for it not to be.

> Since the vtable initializer is
> a compile-time constant, I thought we could make it work by a hack as the one
> in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression do its
> job and everything is hunky-dory.
>
> Except when it isn't: I noticed that the presence of _vptr doesn't make the
> class non-empty, and when cxx_eval_constant_expression saw a decl with an 
> empty
> class type, it just evaluated it to { }.  But such a class still had gotten an
> initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  So
> replacing it with { } will lose the proper initializer whereupon we fail.
> The check I've added to cxx_eval_constant_expression won't win any beauty
> contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.

Perhaps we should check !TYPE_POLYMORPHIC_P as well as
is_really_empty_class.  Perhaps there should be a predicate for that,
say, is_really_nearly_empty_class...

Jason


Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions (v2)

2018-09-14 Thread Marek Polacek
On Fri, Sep 14, 2018 at 07:36:47PM +0200, Jakub Jelinek wrote:
> On Fri, Sep 14, 2018 at 01:19:50PM -0400, Marek Polacek wrote:
> > +   /* We expect something in the form of  get x. */
> > +   if (TREE_CODE (obj) != ADDR_EXPR)
> > + return t;
> 
> Shouldn't it then be a gcc_assert instead, or code like:
>   if (TREE_CODE (obj) != ADDR_EXPR)
> {
>   if (!ctx->quiet)
> error (...);
>   *non_constant_p = true;
> }
> to make it clear that we haven't handled it and don't consider it a constant
> expression?

Not an assert, but setting *non_constant_p is probably sensible.  Thus:

v2: Set *non_constant_p if OBJ_TYPE_REF is not in expected format.

Bootstrapped/regtested on x86_64-linux.

2018-09-14  Marek Polacek  

P1064R0 - Allowing Virtual Function Calls in Constant Expressions
* call.c (build_over_call): Add FIXME.
* constexpr.c (cxx_eval_array_reference): Handle referencing the vtable.
(cxx_eval_constant_expression): Don't ignore _vptr's initializer.
(potential_constant_expression_1): Handle OBJ_TYPE_REF.
* decl.c (grokdeclarator): Change error to pedwarn.  Only warn when
pedantic and not C++2a.

* g++.dg/cpp0x/constexpr-virtual5.C: Adjust dg-error.
* g++.dg/cpp2a/constexpr-virtual1.C: New test.
* g++.dg/cpp2a/constexpr-virtual2.C: New test.
* g++.dg/cpp2a/constexpr-virtual3.C: New test.
* g++.dg/cpp2a/constexpr-virtual4.C: New test.
* g++.dg/cpp2a/constexpr-virtual5.C: New test.
* g++.dg/cpp2a/constexpr-virtual6.C: New test.
* g++.dg/cpp2a/constexpr-virtual7.C: New test.
* g++.dg/cpp2a/constexpr-virtual8.C: New test.
* g++.dg/cpp2a/constexpr-virtual9.C: New test.
* g++.dg/diagnostic/virtual-constexpr.C: Skip for C++2a.  Use
-pedantic-errors.  Adjust dg-error.

diff --git gcc/cp/call.c gcc/cp/call.c
index 69503ca7920..6c70874af40 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -8401,7 +8401,8 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
 
   if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
   /* Don't mess with virtual lookup in instantiate_non_dependent_expr;
-virtual functions can't be constexpr.  */
+virtual functions can't be constexpr.  FIXME Actually, no longer
+true in C++2a.  */
   && !in_template_function ())
 {
   tree t;
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 88c73787961..eb6b8fa1842 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -2414,16 +2414,27 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, 
tree t,
  bool *non_constant_p, bool *overflow_p)
 {
   tree oldary = TREE_OPERAND (t, 0);
+  tree oldidx = TREE_OPERAND (t, 1);
+
+  /* The virtual table isn't constexpr, but has static storage duration and its
+ initializer is a compile-time constant, so we handle referencing an 
element
+ in the table specially.  */
+  if (TREE_TYPE (t) == vtable_entry_type)
+{
+  VERIFY_CONSTANT (oldidx);
+  tree ctor = DECL_INITIAL (oldary);
+  return CONSTRUCTOR_ELT (ctor, tree_to_uhwi (oldidx))->value;
+}
+
   tree ary = cxx_eval_constant_expression (ctx, oldary,
   lval,
   non_constant_p, overflow_p);
-  tree index, oldidx;
+  tree index;
   HOST_WIDE_INT i = 0;
   tree elem_type = NULL_TREE;
   unsigned len = 0, elem_nchars = 1;
   if (*non_constant_p)
 return t;
-  oldidx = TREE_OPERAND (t, 1);
   index = cxx_eval_constant_expression (ctx, oldidx,
false,
non_constant_p, overflow_p);
@@ -4209,7 +4220,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
 CONST_DECL for aggregate constants.  */
   if (lval)
return t;
+  /* is_really_empty_class doesn't take into account _vptr, so initializing
+otherwise empty class with { } would overwrite the initializer that
+initialize_vtable created for us.  */
   if (COMPLETE_TYPE_P (TREE_TYPE (t))
+ && !(DECL_INITIAL (t)
+  && TREE_CODE (DECL_INITIAL (t)) == CONSTRUCTOR
+  /* But if DECL_INITIAL was { }, do mark it as constant.  */
+  && CONSTRUCTOR_NELTS (DECL_INITIAL (t)) > 0)
  && is_really_empty_class (TREE_TYPE (t)))
{
  /* If the class is empty, we aren't actually loading anything.  */
@@ -4778,7 +4796,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
 case MODOP_EXPR:
   /* GCC internal stuff.  */
 case VA_ARG_EXPR:
-case OBJ_TYPE_REF:
 case NON_DEPENDENT_EXPR:
 case BASELINK:
 case OFFSET_REF:
@@ -4788,6 +4805,34 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
   *non_constant_p = true;
   break;
 
+case OBJ_TYPE_REF:
+  {
+   

Re: C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions

2018-09-14 Thread Jakub Jelinek
On Fri, Sep 14, 2018 at 01:19:50PM -0400, Marek Polacek wrote:
> + /* We expect something in the form of  get x. */
> + if (TREE_CODE (obj) != ADDR_EXPR)
> +   return t;

Shouldn't it then be a gcc_assert instead, or code like:
if (TREE_CODE (obj) != ADDR_EXPR)
  {
if (!ctx->quiet)
  error (...);
*non_constant_p = true;
  }
to make it clear that we haven't handled it and don't consider it a constant
expression?

Jakub


C++ PATCH to implement P1064R0, Virtual Function Calls in Constant Expressions

2018-09-14 Thread Marek Polacek
This patch implements another bit of C++20, virtual calls in constant
expression:

The basic idea is that since in a constant expression we know the dynamic
type (to detect invalid code etc.), the restriction that prohibits virtual
calls is unnecessary.

Handling virtual function calls turned out to be fairly easy (as anticipated);
I simply let the constexpr machinery figure out the dynamic type and then
OBJ_TYPE_REF_TOKEN gives us the index into the virtual function table.  That
way we get the function decl we're interested in, and cxx_eval_call_expression
takes it from there.

But handling pointer-to-virtual-member-functions doesn't work like that.
get_member_function_from_ptrfunc creates a COND_EXPR which looks like
if (pf.__pfn & 1) // is it a virtual function?
  // yes, find the pointer in the vtable
else
  // no, just return the pointer
so ideally we want to evaluate the then-branch.  Eventually it'll evaluate it
to something like _ZTV2X2[2], but the vtable isn't constexpr so we'd end up
with "not a constant expression" error.  Since the vtable initializer is
a compile-time constant, I thought we could make it work by a hack as the one
in cxx_eval_array_reference.  We'll then let cxx_eval_call_expression do its
job and everything is hunky-dory.

Except when it isn't: I noticed that the presence of _vptr doesn't make the
class non-empty, and when cxx_eval_constant_expression saw a decl with an empty
class type, it just evaluated it to { }.  But such a class still had gotten an
initializer that looks like {.D.2082 = {._vptr.X2 = &_ZTV2X2 + 16}}.  So
replacing it with { } will lose the proper initializer whereupon we fail.
The check I've added to cxx_eval_constant_expression won't win any beauty
contests but unfortunately EMPTY_CONSTRUCTOR_P doesn't work there.

I've made no attempt to handle virtual bases.  The proposal doesn't mention
them at all, and I thought this would be enough for starters.

Bootstrapped/regtested on x86_64-linux.

2018-09-14  Marek Polacek  

P1064R0 - Allowing Virtual Function Calls in Constant Expressions
* call.c (build_over_call): Add FIXME.
* constexpr.c (cxx_eval_array_reference): Handle referencing the vtable.
(cxx_eval_constant_expression): Don't ignore _vptr's initializer.
(potential_constant_expression_1): Handle OBJ_TYPE_REF.
* decl.c (grokdeclarator): Change error to pedwarn.  Only warn when
pedantic and not C++2a.

* g++.dg/cpp0x/constexpr-virtual5.C: Adjust dg-error.
* g++.dg/cpp2a/constexpr-virtual1.C: New test.
* g++.dg/cpp2a/constexpr-virtual2.C: New test.
* g++.dg/cpp2a/constexpr-virtual3.C: New test.
* g++.dg/cpp2a/constexpr-virtual4.C: New test.
* g++.dg/cpp2a/constexpr-virtual5.C: New test.
* g++.dg/cpp2a/constexpr-virtual6.C: New test.
* g++.dg/cpp2a/constexpr-virtual7.C: New test.
* g++.dg/cpp2a/constexpr-virtual8.C: New test.
* g++.dg/cpp2a/constexpr-virtual9.C: New test.
* g++.dg/diagnostic/virtual-constexpr.C: Skip for C++2a.  Use
-pedantic-errors.  Adjust dg-error.

diff --git gcc/cp/call.c gcc/cp/call.c
index 69503ca7920..6c70874af40 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -8401,7 +8401,8 @@ build_over_call (struct z_candidate *cand, int flags, 
tsubst_flags_t complain)
 
   if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0
   /* Don't mess with virtual lookup in instantiate_non_dependent_expr;
-virtual functions can't be constexpr.  */
+virtual functions can't be constexpr.  FIXME Actually, no longer
+true in C++2a.  */
   && !in_template_function ())
 {
   tree t;
diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 88c73787961..8ebd86b611c 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -2414,16 +2414,27 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, 
tree t,
  bool *non_constant_p, bool *overflow_p)
 {
   tree oldary = TREE_OPERAND (t, 0);
+  tree oldidx = TREE_OPERAND (t, 1);
+
+  /* The virtual table isn't constexpr, but has static storage duration and its
+ initializer is a compile-time constant, so we handle referencing an 
element
+ in the table specially.  */
+  if (TREE_TYPE (t) == vtable_entry_type)
+{
+  VERIFY_CONSTANT (oldidx);
+  tree ctor = DECL_INITIAL (oldary);
+  return CONSTRUCTOR_ELT (ctor, tree_to_uhwi (oldidx))->value;
+}
+
   tree ary = cxx_eval_constant_expression (ctx, oldary,
   lval,
   non_constant_p, overflow_p);
-  tree index, oldidx;
+  tree index;
   HOST_WIDE_INT i = 0;
   tree elem_type = NULL_TREE;
   unsigned len = 0, elem_nchars = 1;
   if (*non_constant_p)
 return t;
-  oldidx = TREE_OPERAND (t, 1);
   index = cxx_eval_constant_expression (ctx, oldidx,