Message ID | 20161122204526.GG3541@tucnak.redhat.com |
---|---|
State | New |
Headers | show |
On Tue, Nov 22, 2016 at 3:45 PM, Jakub Jelinek <jakub@redhat.com> wrote: > As mentioned in the PR, another option I see is special case > REFERENCE_REF_P INDIRECT_REFs and MEM_REFs into which they are gimplified > in cp_genericize_r by not changing is_invisiref_parm decls if they are > already wrapped in those. That sounds more robust. Jason
On Wed, Nov 23, 2016 at 09:11:02AM -0500, Jason Merrill wrote: > On Tue, Nov 22, 2016 at 3:45 PM, Jakub Jelinek <jakub@redhat.com> wrote: > > As mentioned in the PR, another option I see is special case > > REFERENCE_REF_P INDIRECT_REFs and MEM_REFs into which they are gimplified > > in cp_genericize_r by not changing is_invisiref_parm decls if they are > > already wrapped in those. > > That sounds more robust. Actually, now that I think about it, it sounds less robust. E.g. if the invisiref parm is initially used as operand of ADDR_EXPR, then during the first cp_genericize_tree it will be turned into ADDR_EXPR <INDIRECT_REF <decl>>, but gimplification will turn that just into decl, and if we genericize that again, we turn it into INDIRECT_REF <decl> because we won't see INDIRECT_REF/MEM_REF wrapping it. Is there any easy way to construct a testcase where VEC_INIT_EXPR initializer will be an arbitrary expression where such &parm could appear if parm is passed by invisible reference? Also, gimplification already performs tons of other folding (through fold_stmt), making it less likely to recognize those. Jakub
On Wed, Nov 23, 2016 at 9:31 AM, Jakub Jelinek <jakub@redhat.com> wrote: > On Wed, Nov 23, 2016 at 09:11:02AM -0500, Jason Merrill wrote: >> On Tue, Nov 22, 2016 at 3:45 PM, Jakub Jelinek <jakub@redhat.com> wrote: >> > As mentioned in the PR, another option I see is special case >> > REFERENCE_REF_P INDIRECT_REFs and MEM_REFs into which they are gimplified >> > in cp_genericize_r by not changing is_invisiref_parm decls if they are >> > already wrapped in those. >> >> That sounds more robust. > > Actually, now that I think about it, it sounds less robust. > E.g. if the invisiref parm is initially used as operand of ADDR_EXPR, > then during the first cp_genericize_tree it will be turned into > ADDR_EXPR <INDIRECT_REF <decl>>, but gimplification will turn that just > into decl, and if we genericize that again, we turn it into INDIRECT_REF <decl> > because we won't see INDIRECT_REF/MEM_REF wrapping it. True. Then your patch is OK. > Is there any easy way to construct a testcase where VEC_INIT_EXPR > initializer will be an arbitrary expression where such &parm could appear > if parm is passed by invisible reference? I can't think of anything offhand. Jason
--- gcc/cp/cp-gimplify.c.jj 2016-11-15 16:18:49.000000000 +0100 +++ gcc/cp/cp-gimplify.c 2016-11-22 19:12:07.606813783 +0100 @@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. static tree cp_genericize_r (tree *, int *, void *); static tree cp_fold_r (tree *, int *, void *); -static void cp_genericize_tree (tree*); +static void cp_genericize_tree (tree*, bool); static tree cp_fold (tree); /* Local declarations. */ @@ -623,7 +623,7 @@ cp_gimplify_expr (tree *expr_p, gimple_s tf_warning_or_error); hash_set<tree> pset; cp_walk_tree (expr_p, cp_fold_r, &pset, NULL); - cp_genericize_tree (expr_p); + cp_genericize_tree (expr_p, false); ret = GS_OK; input_location = loc; } @@ -995,6 +995,7 @@ struct cp_genericize_data struct cp_genericize_omp_taskreg *omp_ctx; tree try_block; bool no_sanitize_p; + bool handle_invisiref_parm_p; }; /* Perform any pre-gimplification folding of C++ front end trees to @@ -1111,7 +1112,7 @@ cp_genericize_r (tree *stmt_p, int *walk } /* Otherwise, do dereference invisible reference parms. */ - if (is_invisiref_parm (stmt)) + if (wtd->handle_invisiref_parm_p && is_invisiref_parm (stmt)) { *stmt_p = convert_from_reference (stmt); *walk_subtrees = 0; @@ -1511,7 +1512,7 @@ cp_genericize_r (tree *stmt_p, int *walk /* Lower C++ front end trees to GENERIC in T_P. */ static void -cp_genericize_tree (tree* t_p) +cp_genericize_tree (tree* t_p, bool handle_invisiref_parm_p) { struct cp_genericize_data wtd; @@ -1520,6 +1521,7 @@ cp_genericize_tree (tree* t_p) wtd.omp_ctx = NULL; wtd.try_block = NULL_TREE; wtd.no_sanitize_p = false; + wtd.handle_invisiref_parm_p = handle_invisiref_parm_p; cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL); delete wtd.p_set; wtd.bind_expr_stack.release (); @@ -1639,12 +1641,12 @@ cp_genericize (tree fndecl) /* Expand all the array notations here. */ if (flag_cilkplus && contains_array_notation_expr (DECL_SAVED_TREE (fndecl))) - DECL_SAVED_TREE (fndecl) = - expand_array_notation_exprs (DECL_SAVED_TREE (fndecl)); + DECL_SAVED_TREE (fndecl) + = expand_array_notation_exprs (DECL_SAVED_TREE (fndecl)); /* We do want to see every occurrence of the parms, so we can't just use walk_tree's hash functionality. */ - cp_genericize_tree (&DECL_SAVED_TREE (fndecl)); + cp_genericize_tree (&DECL_SAVED_TREE (fndecl), true); if (flag_sanitize & SANITIZE_RETURN && do_ubsan_in_current_function ()) --- gcc/testsuite/g++.dg/cpp1y/pr77739.C.jj 2016-11-22 19:15:02.182659407 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr77739.C 2016-11-22 19:13:37.000000000 +0100 @@ -0,0 +1,15 @@ +// PR c++/77739 +// { dg-do compile { target c++14 } } + +struct A { + A(); + A(const A &); +}; +struct B { + B(); + template <typename... Args> auto g(Args &&... p1) { + return [=] { f(p1...); }; + } + void f(A, const char *); +}; +B::B() { g(A(), ""); }