[PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
Richard Biener
richard.guenther@gmail.com
Mon May 17 07:56:07 GMT 2021
On Fri, May 14, 2021 at 2:23 AM Martin Sebor via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On 5/13/21 1:26 PM, Jason Merrill via Gcc-patches wrote:
> > Ping.
> >
> > On 5/1/21 12:29 PM, Jason Merrill wrote:
> >> Like my recent patch to add ovl_range and lkp_range in the C++ front end,
> >> this patch adds the tsi_range adaptor for using C++11 range-based
> >> 'for' with
> >> a STATEMENT_LIST, e.g.
> >>
> >> for (tree stmt : tsi_range (stmt_list)) { ... }
> >>
> >> This also involves adding some operators to tree_stmt_iterator that are
> >> needed for range-for iterators, and should also be useful in code that
> >> uses
> >> the iterators directly.
> >>
> >> The patch updates the suitable loops in the C++ front end, but does not
> >> touch any loops elsewhere in the compiler.
>
> I like the modernization of the loops.
The only worry I have (and why I stopped looking at range-for) is that
this adds another style of looping over stmts without opening the
possibility to remove another or even unify all of them. That's because
range-for isn't powerful enough w/o jumping through hoops and/or
we cannot use what appearantly ranges<> was intended for (fix
this limitation).
That said, if some C++ literate could see if for example
what gimple-iterator.h provides can be completely modernized
then that would be great of course.
There's stuff like reverse iteration, iteration skipping debug stmts,
compares of iterators like gsi_one_before_end_p, etc.
Given my failed tries (but I'm a C++ illiterate) my TODO list now
only contains turning the iterators into STL style ones, thus
gsi_stmt (it) -> *it, gsi_next (&it) -> ++it, etc. - but even
it != end_p looks a bit awkward there.
Richard.
> I can't find anything terribly wrong with the iterator but let me
> at least pick on some nits ;)
>
> >>
> >> gcc/ChangeLog:
> >>
> >> * tree-iterator.h (struct tree_stmt_iterator): Add operator++,
> >> operator--, operator*, operator==, and operator!=.
> >> (class tsi_range): New.
> >>
> >> gcc/cp/ChangeLog:
> >>
> >> * constexpr.c (build_data_member_initialization): Use tsi_range.
> >> (build_constexpr_constructor_member_initializers): Likewise.
> >> (constexpr_fn_retval, cxx_eval_statement_list): Likewise.
> >> (potential_constant_expression_1): Likewise.
> >> * coroutines.cc (await_statement_expander): Likewise.
> >> (await_statement_walker): Likewise.
> >> * module.cc (trees_out::core_vals): Likewise.
> >> * pt.c (tsubst_expr): Likewise.
> >> * semantics.c (set_cleanup_locs): Likewise.
> >> ---
> >> gcc/tree-iterator.h | 28 +++++++++++++++++++++++-----
> >> gcc/cp/constexpr.c | 42 ++++++++++++++----------------------------
> >> gcc/cp/coroutines.cc | 10 ++++------
> >> gcc/cp/module.cc | 5 ++---
> >> gcc/cp/pt.c | 5 ++---
> >> gcc/cp/semantics.c | 5 ++---
> >> 6 files changed, 47 insertions(+), 48 deletions(-)
> >>
> >> diff --git a/gcc/tree-iterator.h b/gcc/tree-iterator.h
> >> index 076fff8644c..f57456bb473 100644
> >> --- a/gcc/tree-iterator.h
> >> +++ b/gcc/tree-iterator.h
> >> @@ -1,4 +1,4 @@
> >> -/* Iterator routines for manipulating GENERIC tree statement list.
> >> +/* Iterator routines for manipulating GENERIC tree statement list.
> >> -*- C++ -*-
> >> Copyright (C) 2003-2021 Free Software Foundation, Inc.
> >> Contributed by Andrew MacLeod <amacleod@redhat.com>
> >> @@ -32,6 +32,13 @@ along with GCC; see the file COPYING3. If not see
> >> struct tree_stmt_iterator {
> >> struct tree_statement_list_node *ptr;
> >> tree container;
>
> I assume the absence of ctors is intentional. If so, I suggest
> to add a comment explaing why. Otherwise, I would provide one
> (or as many as needed).
>
> >> +
> >> + bool operator== (tree_stmt_iterator b) const
> >> + { return b.ptr == ptr && b.container == container; }
> >> + bool operator!= (tree_stmt_iterator b) const { return !(*this == b); }
> >> + tree_stmt_iterator &operator++ () { ptr = ptr->next; return *this; }
> >> + tree_stmt_iterator &operator-- () { ptr = ptr->prev; return *this; }
>
> I would suggest to add postincrement and postdecrement.
>
> >> + tree &operator* () { return ptr->stmt; }
>
> Given the pervasive lack of const-safety in GCC and the by-value
> semantics of the iterator this probably isn't worth it but maybe
> add a const overload. operator-> would probably never be used.
>
> >> };
> >> static inline tree_stmt_iterator
> >> @@ -71,27 +78,38 @@ tsi_one_before_end_p (tree_stmt_iterator i)
> >> static inline void
> >> tsi_next (tree_stmt_iterator *i)
> >> {
> >> - i->ptr = i->ptr->next;
> >> + ++(*i);
> >> }
> >> static inline void
> >> tsi_prev (tree_stmt_iterator *i)
> >> {
> >> - i->ptr = i->ptr->prev;
> >> + --(*i);
> >> }
> >> static inline tree *
> >> tsi_stmt_ptr (tree_stmt_iterator i)
> >> {
> >> - return &i.ptr->stmt;
> >> + return &(*i);
> >> }
> >> static inline tree
> >> tsi_stmt (tree_stmt_iterator i)
> >> {
> >> - return i.ptr->stmt;
> >> + return *i;
> >> }
> >> +/* Make tree_stmt_iterator work as a C++ range, e.g.
> >> + for (tree stmt : tsi_range (stmt_list)) { ... } */
> >> +class tsi_range
> >> +{
> >> + tree t;
> >> + public:
> >> + tsi_range (tree t): t(t) { }
> >> + tree_stmt_iterator begin() { return tsi_start (t); }
> >> + tree_stmt_iterator end() { return { nullptr, t }; }
>
> Those member functions could be made const.
>
> Martin
>
> >> +};
> >> +
> >> enum tsi_iterator_update
> >> {
> >> TSI_NEW_STMT, /* Only valid when single statement is added,
> >> move
> >> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> >> index 9481a5bfd3c..260b0122f59 100644
> >> --- a/gcc/cp/constexpr.c
> >> +++ b/gcc/cp/constexpr.c
> >> @@ -330,12 +330,9 @@ build_data_member_initialization (tree t,
> >> vec<constructor_elt, va_gc> **vec)
> >> return false;
> >> if (TREE_CODE (t) == STATEMENT_LIST)
> >> {
> >> - tree_stmt_iterator i;
> >> - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
> >> - {
> >> - if (! build_data_member_initialization (tsi_stmt (i), vec))
> >> - return false;
> >> - }
> >> + for (tree stmt : tsi_range (t))
> >> + if (! build_data_member_initialization (stmt, vec))
> >> + return false;
> >> return true;
> >> }
> >> if (TREE_CODE (t) == CLEANUP_STMT)
> >> @@ -577,10 +574,9 @@ build_constexpr_constructor_member_initializers
> >> (tree type, tree body)
> >> break;
> >> case STATEMENT_LIST:
> >> - for (tree_stmt_iterator i = tsi_start (body);
> >> - !tsi_end_p (i); tsi_next (&i))
> >> + for (tree stmt : tsi_range (body))
> >> {
> >> - body = tsi_stmt (i);
> >> + body = stmt;
> >> if (TREE_CODE (body) == BIND_EXPR)
> >> break;
> >> }
> >> @@ -617,10 +613,9 @@ build_constexpr_constructor_member_initializers
> >> (tree type, tree body)
> >> }
> >> else if (TREE_CODE (body) == STATEMENT_LIST)
> >> {
> >> - tree_stmt_iterator i;
> >> - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
> >> + for (tree stmt : tsi_range (body))
> >> {
> >> - ok = build_data_member_initialization (tsi_stmt (i), &vec);
> >> + ok = build_data_member_initialization (stmt, &vec);
> >> if (!ok)
> >> break;
> >> }
> >> @@ -675,11 +670,10 @@ constexpr_fn_retval (tree body)
> >> {
> >> case STATEMENT_LIST:
> >> {
> >> - tree_stmt_iterator i;
> >> tree expr = NULL_TREE;
> >> - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i))
> >> + for (tree stmt : tsi_range (body))
> >> {
> >> - tree s = constexpr_fn_retval (tsi_stmt (i));
> >> + tree s = constexpr_fn_retval (stmt);
> >> if (s == error_mark_node)
> >> return error_mark_node;
> >> else if (s == NULL_TREE)
> >> @@ -5772,7 +5766,6 @@ cxx_eval_statement_list (const constexpr_ctx
> >> *ctx, tree t,
> >> bool *non_constant_p, bool *overflow_p,
> >> tree *jump_target)
> >> {
> >> - tree_stmt_iterator i;
> >> tree local_target;
> >> /* In a statement-expression we want to return the last value.
> >> For empty statement expression return void_node. */
> >> @@ -5782,9 +5775,8 @@ cxx_eval_statement_list (const constexpr_ctx
> >> *ctx, tree t,
> >> local_target = NULL_TREE;
> >> jump_target = &local_target;
> >> }
> >> - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
> >> + for (tree stmt : tsi_range (t))
> >> {
> >> - tree stmt = tsi_stmt (i);
> >> /* We've found a continue, so skip everything until we reach
> >> the label its jumping to. */
> >> if (continues (jump_target))
> >> @@ -8283,16 +8275,10 @@ potential_constant_expression_1 (tree t, bool
> >> want_rval, bool strict, bool now,
> >> }
> >> case STATEMENT_LIST:
> >> - {
> >> - tree_stmt_iterator i;
> >> - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
> >> - {
> >> - if (!RECUR (tsi_stmt (i), any))
> >> - return false;
> >> - }
> >> - return true;
> >> - }
> >> - break;
> >> + for (tree stmt : tsi_range (t))
> >> + if (!RECUR (stmt, any))
> >> + return false;
> >> + return true;
> >> case MODIFY_EXPR:
> >> if (cxx_dialect < cxx14)
> >> diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
> >> index dbd703a67cc..9b498f9d0b4 100644
> >> --- a/gcc/cp/coroutines.cc
> >> +++ b/gcc/cp/coroutines.cc
> >> @@ -1771,10 +1771,9 @@ await_statement_expander (tree *stmt, int
> >> *do_subtree, void *d)
> >> return NULL_TREE; /* Just process the sub-trees. */
> >> else if (TREE_CODE (*stmt) == STATEMENT_LIST)
> >> {
> >> - tree_stmt_iterator i;
> >> - for (i = tsi_start (*stmt); !tsi_end_p (i); tsi_next (&i))
> >> + for (tree &s : tsi_range (*stmt))
> >> {
> >> - res = cp_walk_tree (tsi_stmt_ptr (i), await_statement_expander,
> >> + res = cp_walk_tree (&s, await_statement_expander,
> >> d, NULL);
> >> if (res)
> >> return res;
> >> @@ -3523,10 +3522,9 @@ await_statement_walker (tree *stmt, int
> >> *do_subtree, void *d)
> >> }
> >> else if (TREE_CODE (*stmt) == STATEMENT_LIST)
> >> {
> >> - tree_stmt_iterator i;
> >> - for (i = tsi_start (*stmt); !tsi_end_p (i); tsi_next (&i))
> >> + for (tree &s : tsi_range (*stmt))
> >> {
> >> - res = cp_walk_tree (tsi_stmt_ptr (i), await_statement_walker,
> >> + res = cp_walk_tree (&s, await_statement_walker,
> >> d, NULL);
> >> if (res)
> >> return res;
> >> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> >> index 02c19f55548..f0fb0144706 100644
> >> --- a/gcc/cp/module.cc
> >> +++ b/gcc/cp/module.cc
> >> @@ -6094,9 +6094,8 @@ trees_out::core_vals (tree t)
> >> break;
> >> case STATEMENT_LIST:
> >> - for (tree_stmt_iterator iter = tsi_start (t);
> >> - !tsi_end_p (iter); tsi_next (&iter))
> >> - if (tree stmt = tsi_stmt (iter))
> >> + for (tree stmt : tsi_range (t))
> >> + if (stmt)
> >> WT (stmt);
> >> WT (NULL_TREE);
> >> break;
> >> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> >> index 116bdd2e42a..ad140cfd586 100644
> >> --- a/gcc/cp/pt.c
> >> +++ b/gcc/cp/pt.c
> >> @@ -18234,9 +18234,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t
> >> complain, tree in_decl,
> >> {
> >> case STATEMENT_LIST:
> >> {
> >> - tree_stmt_iterator i;
> >> - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
> >> - RECUR (tsi_stmt (i));
> >> + for (tree stmt : tsi_range (t))
> >> + RECUR (stmt);
> >> break;
> >> }
> >> diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
> >> index 6224f49f189..2912efad9be 100644
> >> --- a/gcc/cp/semantics.c
> >> +++ b/gcc/cp/semantics.c
> >> @@ -613,9 +613,8 @@ set_cleanup_locs (tree stmts, location_t loc)
> >> set_cleanup_locs (CLEANUP_BODY (stmts), loc);
> >> }
> >> else if (TREE_CODE (stmts) == STATEMENT_LIST)
> >> - for (tree_stmt_iterator i = tsi_start (stmts);
> >> - !tsi_end_p (i); tsi_next (&i))
> >> - set_cleanup_locs (tsi_stmt (i), loc);
> >> + for (tree stmt : tsi_range (stmts))
> >> + set_cleanup_locs (stmt, loc);
> >> }
> >> /* Finish a scope. */
> >>
> >> base-commit: 3c65858787dc52b65b26fa7018587c01510f442c
> >> prerequisite-patch-id: 7ce9dff1f7d449f4a13fb882bf7b1a962a56de95
> >>
> >
>
More information about the Gcc-patches
mailing list