Re: [PATCH v6] c++: Move consteval folding to cp_fold_r

2023-09-16 Thread Jason Merrill via Gcc-patches

On 9/15/23 16:32, Marek Polacek wrote:

On Fri, Sep 15, 2023 at 02:08:46PM -0400, Jason Merrill wrote:

On 9/13/23 20:02, Marek Polacek wrote:

On Wed, Sep 13, 2023 at 05:57:47PM -0400, Jason Merrill wrote:

On 9/13/23 16:56, Marek Polacek wrote:

On Tue, Sep 12, 2023 at 05:26:25PM -0400, Jason Merrill wrote:

On 9/8/23 14:24, Marek Polacek wrote:

+  switch (TREE_CODE (stmt))
+{
+/* Unfortunately we must handle code like
+false ? bar () : 42
+   where we have to check bar too.  */
+case COND_EXPR:
+  if (cp_fold_immediate_r (&TREE_OPERAND (stmt, 1), walk_subtrees, data))
+   return error_mark_node;
+  if (TREE_OPERAND (stmt, 2)
+ && cp_fold_immediate_r (&TREE_OPERAND (stmt, 2), walk_subtrees, data))
+   return error_mark_node;


Is this necessary?  Doesn't walk_tree already walk into the arms of
COND_EXPR?


Unfortunately yes.  The cp_fold call in cp_fold_r could fold the ?: into
a constant before we see it here.  I've added a comment saying just that.


Ah.  But in that case I guess we need to walk into the arms, not just check
the top-level expression in them.

Arg, of course.  I was fooled into thinking that it would recurse, but
you're right.  Fixed by using cp_walk_tree as I intended.  Tested in
consteval34.C.


But maybe cp_fold_r should do that before the cp_fold, instead of this
function?


I...am not sure how that would be better than what I did.


Callers of cp_fold_immediate don't need this because cp_fold_r isn't
involved, so it isn't folding anything.


This is true.
  

cp_fold_r can walk the arms with cp_fold_r and then clear *walk_subtrees to
avoid walking the arms again normally.


I didn't think we wanted to do everything cp_fold_r does even in dead
branches, but ok.


Ah, that's a good point.  With the recursive walk in 
cp_fold_immediate_r, I suppose we could suppress it when called from 
cp_fold_immediate with a new fold_flag?  That would still allow for 
cp_walk_tree_without_duplicates.


Incidentally, I notice you check for null op2 of COND_EXPR, should 
probably also check op1.


Jason



[PATCH v6] c++: Move consteval folding to cp_fold_r

2023-09-15 Thread Marek Polacek via Gcc-patches
On Fri, Sep 15, 2023 at 02:08:46PM -0400, Jason Merrill wrote:
> On 9/13/23 20:02, Marek Polacek wrote:
> > On Wed, Sep 13, 2023 at 05:57:47PM -0400, Jason Merrill wrote:
> > > On 9/13/23 16:56, Marek Polacek wrote:
> > > > On Tue, Sep 12, 2023 at 05:26:25PM -0400, Jason Merrill wrote:
> > > > > On 9/8/23 14:24, Marek Polacek wrote:
> > > > > > +  switch (TREE_CODE (stmt))
> > > > > > +{
> > > > > > +/* Unfortunately we must handle code like
> > > > > > +false ? bar () : 42
> > > > > > +   where we have to check bar too.  */
> > > > > > +case COND_EXPR:
> > > > > > +  if (cp_fold_immediate_r (&TREE_OPERAND (stmt, 1), 
> > > > > > walk_subtrees, data))
> > > > > > +   return error_mark_node;
> > > > > > +  if (TREE_OPERAND (stmt, 2)
> > > > > > + && cp_fold_immediate_r (&TREE_OPERAND (stmt, 2), 
> > > > > > walk_subtrees, data))
> > > > > > +   return error_mark_node;
> > > > > 
> > > > > Is this necessary?  Doesn't walk_tree already walk into the arms of
> > > > > COND_EXPR?
> > > > 
> > > > Unfortunately yes.  The cp_fold call in cp_fold_r could fold the ?: into
> > > > a constant before we see it here.  I've added a comment saying just 
> > > > that.
> > > 
> > > Ah.  But in that case I guess we need to walk into the arms, not just 
> > > check
> > > the top-level expression in them.
> > Arg, of course.  I was fooled into thinking that it would recurse, but
> > you're right.  Fixed by using cp_walk_tree as I intended.  Tested in
> > consteval34.C.
> > 
> > > But maybe cp_fold_r should do that before the cp_fold, instead of this
> > > function?
> > 
> > I...am not sure how that would be better than what I did.
> 
> Callers of cp_fold_immediate don't need this because cp_fold_r isn't
> involved, so it isn't folding anything.

This is true.
 
> cp_fold_r can walk the arms with cp_fold_r and then clear *walk_subtrees to
> avoid walking the arms again normally.

I didn't think we wanted to do everything cp_fold_r does even in dead
branches, but ok.

I figured that we need to recurse on the conditional of the COND_EXPR too.
It can be, for example:

  &((const struct S *) VIEW_CONVERT_EXPR(q))->b != 0B

which is supposed to be evaluated into:

  &((const struct S *) &s)->b != 0B

otherwise we'd get ICEs like "error: constant not recomputed when 'ADDR_EXPR'
changed".

> cp_fold_r uses data->pset to avoid walking the same tree twice;
> cp_fold_immediate_r currently doesn't do anything to avoid that.  If
> cp_fold_immediate_r doesn't itself call cp_walk_tree, cp_fold_immediate can
> use cp_walk_tree_without_duplicates.

Adjusted.
 
> > > > > > +  break;
> > > > > > +
> > > > > > case PTRMEM_CST:
> > > > > >   if (TREE_CODE (PTRMEM_CST_MEMBER (stmt)) == FUNCTION_DECL
> > > > > >   && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER 
> > > > > > (stmt)))
> > > > > > {
> > > > > > - if (!data->pset.add (stmt))
> > > > > > + if (!data->pset.add (stmt) && (complain & tf_error))
> > > > > > error_at (PTRMEM_CST_LOCATION (stmt),
> > > > > >   "taking address of an immediate function 
> > > > > > %qD",
> > > > > >   PTRMEM_CST_MEMBER (stmt));
> > > > > >   stmt = *stmt_p = build_zero_cst (TREE_TYPE (stmt));
> > > > > 
> > > > > It looks like this will overwrite *stmt_p even if we didn't give an 
> > > > > error.
> > > > 
> > > > I suppose that could result in missing errors, adjusted.  And there's no
> > > > point in setting stmt.
> > > > > > - break;
> > > > > > + return error_mark_node;
> > > > > > }
> > > > > >   break;
> > > > > > +/* Expand immediate invocations.  */
> > > > > > +case CALL_EXPR:
> > > > > > +case AGGR_INIT_EXPR:
> > > > > > +  if (tree fn = cp_get_callee (stmt))
> > > > > > +   if (TREE_CODE (fn) != ADDR_EXPR || ADDR_EXPR_DENOTES_CALL_P 
> > > > > > (fn))
> > > > > > + if (tree fndecl = cp_get_fndecl_from_callee (fn, 
> > > > > > /*fold*/false))
> > > > > > +   if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
> > > > > > + {
> > > > > > +   *stmt_p = stmt = cxx_constant_value (stmt, complain);
> > > > > 
> > > > > Likewise.
> > > > 
> > > > I think we have to keep setting *stmt_p to actually evaluate consteval
> > > > functions.
> > > 
> > > But only when it succeeds; we don't want to set it to error_mark_node if 
> > > we
> > > aren't complaining.
> > 
> > Hmm, probably not.  Fixed, thanks.
> > 
> > +   if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
> > + {
> > +   stmt = cxx_constant_value (stmt, complain);
> > +   if (stmt == error_mark_node && (complain & tf_error))
> > + return error_mark_node;
> > +   *stmt_p = stmt;
> > + }
> 
> This seems backwards; like with the ADDR_EXPR/PTRMEM_CST cases, I think we
> want to return error_mark_node regardless of complain, but only set *stmt_p
> when complaining.

Ug.  I really hope it's alright thi