On Tue, Jul 3, 2018 at 9:49 AM Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > While working on OpenMP range-for support, I ran into the weird thing that > the C++ FE accepts > for (auto &i : a) > if (i != *__for_begin || &i == __for_end || &__for_range[0] != &a[0]) > __builtin_abort (); > outside of templates, but doesn't inside of templates. > I think we shouldn't let people do this at any time, it will just lead to > non-portable code, and when it works only outside of templates, it isn't a > well defined extension. > > Now, we could just use create_tmp_var_name ("__for_range") instead of > get_identifier ("__for_range") etc. and the symbols would be non-accessible > to users (usually; if assembler doesn't support dots nor dollars in labels, > it is still a symbol with just alphanumeric chars in it, but there is a hard > to predict number suffix at least), or just NULL DECL_NAME. > But my understanding is that the intent was that in the debugger one could > use __for_range, __for_begin and __for_end to make it easier to debug > range fors. In that case, the following patch solves it by using a name > not accessible for the user when parsing the body (with space in it) and > correcting the names when the var gets out of scope. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Can we make them DECL_ARTIFICIAL and/or make name-lookup never lookup DECL_ARTIFICIAL vars instead? Richard. > 2018-07-02 Jakub Jelinek <ja...@redhat.com> > > PR c++/85515 > * parser.c (build_range_temp): Use "__for range" instead of > "__for_range". > (cp_convert_range_for): Use "__for begin" and "__for end" instead of > "__for_begin" and "__for_end". > * semantics.c (finish_for_stmt): Rename "__for {range,begin,end}" > local symbols to "__for_{range,begin,end}". > > * g++.dg/pr85515-2.C: Add expected dg-error. > * g++.dg/cpp0x/range-for36.C: New test. > > --- gcc/cp/parser.c.jj 2018-07-02 23:04:00.869370436 +0200 > +++ gcc/cp/parser.c 2018-07-02 23:08:44.572618486 +0200 > @@ -11953,7 +11953,7 @@ build_range_temp (tree range_expr) > > /* Create the __range variable. */ > range_temp = build_decl (input_location, VAR_DECL, > - get_identifier ("__for_range"), range_type); > + get_identifier ("__for range"), range_type); > TREE_USED (range_temp) = 1; > DECL_ARTIFICIAL (range_temp) = 1; > > @@ -12061,7 +12061,7 @@ cp_convert_range_for (tree statement, tr > > /* The new for initialization statement. */ > begin = build_decl (input_location, VAR_DECL, > - get_identifier ("__for_begin"), iter_type); > + get_identifier ("__for begin"), iter_type); > TREE_USED (begin) = 1; > DECL_ARTIFICIAL (begin) = 1; > pushdecl (begin); > @@ -12072,7 +12072,7 @@ cp_convert_range_for (tree statement, tr > if (cxx_dialect >= cxx17) > iter_type = cv_unqualified (TREE_TYPE (end_expr)); > end = build_decl (input_location, VAR_DECL, > - get_identifier ("__for_end"), iter_type); > + get_identifier ("__for end"), iter_type); > TREE_USED (end) = 1; > DECL_ARTIFICIAL (end) = 1; > pushdecl (end); > --- gcc/cp/semantics.c.jj 2018-06-25 14:51:23.096989196 +0200 > +++ gcc/cp/semantics.c 2018-07-02 23:23:40.784400542 +0200 > @@ -1060,7 +1060,31 @@ finish_for_stmt (tree for_stmt) > : &FOR_SCOPE (for_stmt)); > tree scope = *scope_ptr; > *scope_ptr = NULL; > + > + /* During parsing of the body, range for uses "__for {range,begin,end}" > + decl names to make those unaccessible by code in the body. > + Change it to ones with underscore instead of space, so that it can > + be inspected in the debugger. */ > + tree range_for_decl[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; > + for (int i = 0; i < 3; i++) > + { > + tree id > + = get_identifier ("__for range\0__for begin\0__for end" + 12 * i); > + if (IDENTIFIER_BINDING (id) > + && IDENTIFIER_BINDING (id)->scope == current_binding_level) > + { > + range_for_decl[i] = IDENTIFIER_BINDING (id)->value; > + gcc_assert (VAR_P (range_for_decl[i]) > + && DECL_ARTIFICIAL (range_for_decl[i])); > + } > + } > + > add_stmt (do_poplevel (scope)); > + > + for (int i = 0; i < 3; i++) > + if (range_for_decl[i]) > + DECL_NAME (range_for_decl[i]) > + = get_identifier ("__for_range\0__for_begin\0__for_end" + 12 * i); > } > > /* Begin a range-for-statement. Returns a new RANGE_FOR_STMT. > --- gcc/testsuite/g++.dg/pr85515-2.C.jj 2018-04-27 22:28:02.889462532 +0200 > +++ gcc/testsuite/g++.dg/pr85515-2.C 2018-07-02 23:33:50.638930364 +0200 > @@ -15,8 +15,7 @@ int test_2 () > int sum = 0; > for (const auto v: arr) { > sum += v; > - // TODO: should we issue an error for the following assignment? > - __for_begin = __for_end; > + __for_begin = __for_end; // { dg-error "was not declared in this > scope" } > } > return sum; > } > --- gcc/testsuite/g++.dg/cpp0x/range-for36.C.jj 2018-07-02 23:35:12.796000382 > +0200 > +++ gcc/testsuite/g++.dg/cpp0x/range-for36.C 2018-07-02 23:35:04.018992900 > +0200 > @@ -0,0 +1,32 @@ > +// PR c++/85515 > +// { dg-do compile { target c++11 } } > + > +int a[10]; > + > +void > +foo () > +{ > + for (auto &i : a) > + if (i != *__for_begin // { dg-error "was not declared in > this scope" } > + || &i == __for_end // { dg-error "was not declared in > this scope" } > + || &__for_range[0] != &a[0]) // { dg-error "was not declared in > this scope" } > + __builtin_abort (); > +} > + > +template <int N> > +void > +bar () > +{ > + for (auto &i : a) > + if (i != *__for_begin // { dg-error "was not declared in > this scope" } > + || &i == __for_end // { dg-error "was not declared in > this scope" } > + || &__for_range[0] != &a[0]) // { dg-error "was not declared in > this scope" } > + __builtin_abort (); > +} > + > +void > +baz () > +{ > + foo (); > + bar <0> (); > +} > > Jakub