[Bug c++/89767] [8/9 Regression] ICE with tuple and optimization

jakub at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Tue Mar 19 14:22:00 GMT 2019


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89767

--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Ah, so the reason why __t PARM_DECL is not normally removed is that we reuse
IDENTIFIER_MARKED for something different, in particular:
  /* If TREE_TYPE isn't set, we're still in the introducer, so check
     for duplicates.  */
  if (!LAMBDA_EXPR_CLOSURE (lambda))
    {
      if (IDENTIFIER_MARKED (name))
        {
          pedwarn (input_location, 0,
                   "already captured %qD in lambda expression", id);
          return NULL_TREE;
        }
      IDENTIFIER_MARKED (name) = true;
    }
and we only clear it much later in register_capture_members:
  IDENTIFIER_MARKED (DECL_NAME (field)) = false;
But, while we are parsing the lambda, we perform those push_to_top_level and
pop_from_top_level and those do use IDENTIFIER_MARKED to determine if the
identifier binding actually should be saved/restored or not.
This particular testcase I guess could be fixed by replacing:
  /* Add __ to the beginning of the field name so that user code
     won't find the field with name lookup.  We can't just leave the name
     unset because template instantiation uses the name to find
     instantiated fields.  */
  buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3);
  buf[1] = buf[0] = '_';
  memcpy (buf + 2, IDENTIFIER_POINTER (id),
          IDENTIFIER_LENGTH (id) + 1);
with using say ".." as prefix instead of "__", so that it is use inaccessible.
But what about following testcase?

void bar (int);
void foo () { int x = 0; auto z = [x, y = [x] { bar (x); }] { y (); bar (x); };
z (); }

clang++ -std=c++17 accepts that, g++ rejects with:
pr89767-4.C: In function ‘void foo()’:
pr89767-4.C:2:44: warning: already captured ‘x’ in lambda expression
    2 | void foo () { int x = 0; auto z = [x, y = [x] { bar (x); }] { y (); bar
(x); }; z (); }
      |                                            ^
pr89767-4.C: In lambda function:
pr89767-4.C:2:54: error: ‘x’ is not captured
    2 | void foo () { int x = 0; auto z = [x, y = [x] { bar (x); }] { y (); bar
(x); }; z (); }
      |                                                      ^
pr89767-4.C:2:45: note: the lambda has no capture-default
    2 | void foo () { int x = 0; auto z = [x, y = [x] { bar (x); }] { y (); bar
(x); }; z (); }
      |                                             ^
pr89767-4.C:2:19: note: ‘int x’ declared here
    2 | void foo () { int x = 0; auto z = [x, y = [x] { bar (x); }] { y (); bar
(x); }; z (); }
      |                   ^

Seems the use of IDENTIFIER_MARKED for this purpose has been added in r175211,
i.e. PR43831 fix.  So, if we want to keep using that and not something
different, we'd need to do those ..s or something similar and save/restore it
when starting to parse a new lambda.


More information about the Gcc-bugs mailing list