* [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
@ 2021-05-01 16:29 Jason Merrill
2021-05-13 19:26 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-05-01 16:29 UTC (permalink / raw)
To: gcc-patches
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.
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;
+
+ 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; }
+ tree &operator* () { return ptr->stmt; }
};
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 }; }
+};
+
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
--
2.27.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
2021-05-01 16:29 [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator Jason Merrill
@ 2021-05-13 19:26 ` Jason Merrill
2021-05-13 23:21 ` Martin Sebor
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-05-13 19:26 UTC (permalink / raw)
To: gcc-patches
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.
>
> 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;
> +
> + 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; }
> + tree &operator* () { return ptr->stmt; }
> };
>
> 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 }; }
> +};
> +
> 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
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
2021-05-13 19:26 ` Jason Merrill
@ 2021-05-13 23:21 ` Martin Sebor
2021-05-14 1:50 ` Jason Merrill
2021-05-17 7:56 ` Richard Biener
0 siblings, 2 replies; 8+ messages in thread
From: Martin Sebor @ 2021-05-13 23:21 UTC (permalink / raw)
To: Jason Merrill, gcc-patches
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.
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
>>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
2021-05-13 23:21 ` Martin Sebor
@ 2021-05-14 1:50 ` Jason Merrill
2021-05-17 7:56 ` Richard Biener
1 sibling, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2021-05-14 1:50 UTC (permalink / raw)
To: Martin Sebor, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 12418 bytes --]
On 5/13/21 7:21 PM, Martin Sebor 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.
>
> 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.
Sure:
>>> +};
>>> +
>>> 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
>>>
>>
>
[-- Attachment #2: 0001-fixup-tree-iterator-C-11-range-for-and-tree_stmt_ite.patch --]
[-- Type: text/x-patch, Size: 1744 bytes --]
From 964005e6f08c3eff8b5cd8dfb4e4def5dfc28709 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Thu, 13 May 2021 21:21:23 -0400
Subject: [PATCH] fixup! tree-iterator: C++11 range-for and tree_stmt_iterator
To: gcc-patches@gcc.gnu.org
---
gcc/tree-iterator.h | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/gcc/tree-iterator.h b/gcc/tree-iterator.h
index f57456bb473..a72d0d37f1c 100644
--- a/gcc/tree-iterator.h
+++ b/gcc/tree-iterator.h
@@ -33,12 +33,20 @@ struct tree_stmt_iterator {
struct tree_statement_list_node *ptr;
tree container;
+ /* No need for user-defined constructors, the implicit definitions (or
+ aggregate initialization) are fine. */
+
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; }
+ tree_stmt_iterator operator++ (int)
+ { tree_stmt_iterator x = *this; ++*this; return x; }
+ tree_stmt_iterator operator-- (int)
+ { tree_stmt_iterator x = *this; --*this; return x; }
tree &operator* () { return ptr->stmt; }
+ tree operator* () const { return ptr->stmt; }
};
static inline tree_stmt_iterator
@@ -106,8 +114,8 @@ 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 }; }
+ tree_stmt_iterator begin() const { return tsi_start (t); }
+ tree_stmt_iterator end() const { return { nullptr, t }; }
};
enum tsi_iterator_update
--
2.27.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
2021-05-13 23:21 ` Martin Sebor
2021-05-14 1:50 ` Jason Merrill
@ 2021-05-17 7:56 ` Richard Biener
2021-05-17 17:58 ` Jason Merrill
1 sibling, 1 reply; 8+ messages in thread
From: Richard Biener @ 2021-05-17 7:56 UTC (permalink / raw)
To: Martin Sebor; +Cc: Jason Merrill, GCC Patches
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
> >>
> >
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
2021-05-17 7:56 ` Richard Biener
@ 2021-05-17 17:58 ` Jason Merrill
2021-05-26 13:56 ` Jason Merrill
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-05-17 17:58 UTC (permalink / raw)
To: Richard Biener, Martin Sebor; +Cc: GCC Patches
On 5/17/21 3:56 AM, Richard Biener wrote:
> 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).
The range-for enabled by my patch simplifies the common case of simple
iteration over elements; that seems worth doing to me even if it doesn't
replace all loops. Just as FOR_EACH_VEC_ELT isn't suitable for all
loops over a vector.
> 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
This is typically done with the reverse_iterator<> adaptor, which we
could get from <iterator> or duplicate. I didn't see enough reverse
iterations to make it seem worth the bother.
> iteration skipping debug stmts,
There you can move the condition into the loop:
if (gimple_code (stmt) == GIMPLE_DEBUG)
continue;
> compares of iterators like gsi_one_before_end_p, etc.
Certainly anything where you want to mess with the iterators directly
doesn't really translate to range-for.
> 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.
Well, it < end_val is pretty typical for loops involving integer
iterators. But you don't have to use that style if you'd rather not.
You could continue to use gsi_end_p, or just *it, since we know that *it
is NULL at the end of the sequence.
>> 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
>>>>
>>>
>>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
2021-05-17 17:58 ` Jason Merrill
@ 2021-05-26 13:56 ` Jason Merrill
2021-05-28 6:53 ` Richard Biener
0 siblings, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2021-05-26 13:56 UTC (permalink / raw)
To: Richard Biener, Martin Sebor; +Cc: GCC Patches
Ping.
On 5/17/21 1:58 PM, Jason Merrill wrote:
> On 5/17/21 3:56 AM, Richard Biener wrote:
>> 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).
>
> The range-for enabled by my patch simplifies the common case of simple
> iteration over elements; that seems worth doing to me even if it doesn't
> replace all loops. Just as FOR_EACH_VEC_ELT isn't suitable for all
> loops over a vector.
>
>> 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
>
> This is typically done with the reverse_iterator<> adaptor, which we
> could get from <iterator> or duplicate. I didn't see enough reverse
> iterations to make it seem worth the bother.
>
>> iteration skipping debug stmts,
>
> There you can move the condition into the loop:
>
> if (gimple_code (stmt) == GIMPLE_DEBUG)
> continue;
>
>> compares of iterators like gsi_one_before_end_p, etc.
>
> Certainly anything where you want to mess with the iterators directly
> doesn't really translate to range-for.
>
>> 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.
>
> Well, it < end_val is pretty typical for loops involving integer
> iterators. But you don't have to use that style if you'd rather not.
> You could continue to use gsi_end_p, or just *it, since we know that *it
> is NULL at the end of the sequence.
>
>>> 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
>>>>>
>>>>
>>>
>>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator
2021-05-26 13:56 ` Jason Merrill
@ 2021-05-28 6:53 ` Richard Biener
0 siblings, 0 replies; 8+ messages in thread
From: Richard Biener @ 2021-05-28 6:53 UTC (permalink / raw)
To: Jason Merrill; +Cc: Martin Sebor, GCC Patches
On Wed, May 26, 2021 at 3:56 PM Jason Merrill <jason@redhat.com> wrote:
>
> Ping.
The non-C++ parts are OK.
Richard.
> On 5/17/21 1:58 PM, Jason Merrill wrote:
> > On 5/17/21 3:56 AM, Richard Biener wrote:
> >> 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).
> >
> > The range-for enabled by my patch simplifies the common case of simple
> > iteration over elements; that seems worth doing to me even if it doesn't
> > replace all loops. Just as FOR_EACH_VEC_ELT isn't suitable for all
> > loops over a vector.
> >
> >> 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
> >
> > This is typically done with the reverse_iterator<> adaptor, which we
> > could get from <iterator> or duplicate. I didn't see enough reverse
> > iterations to make it seem worth the bother.
> >
> >> iteration skipping debug stmts,
> >
> > There you can move the condition into the loop:
> >
> > if (gimple_code (stmt) == GIMPLE_DEBUG)
> > continue;
> >
> >> compares of iterators like gsi_one_before_end_p, etc.
> >
> > Certainly anything where you want to mess with the iterators directly
> > doesn't really translate to range-for.
> >
> >> 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.
> >
> > Well, it < end_val is pretty typical for loops involving integer
> > iterators. But you don't have to use that style if you'd rather not.
> > You could continue to use gsi_end_p, or just *it, since we know that *it
> > is NULL at the end of the sequence.
> >
> >>> 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
> >>>>>
> >>>>
> >>>
> >>
> >
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-05-28 6:54 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-01 16:29 [PATCH RFA] tree-iterator: C++11 range-for and tree_stmt_iterator Jason Merrill
2021-05-13 19:26 ` Jason Merrill
2021-05-13 23:21 ` Martin Sebor
2021-05-14 1:50 ` Jason Merrill
2021-05-17 7:56 ` Richard Biener
2021-05-17 17:58 ` Jason Merrill
2021-05-26 13:56 ` Jason Merrill
2021-05-28 6:53 ` Richard Biener
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).