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

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2016-12-22
                 CC|                            |jakub at gcc dot gnu.org,
                   |                            |jason at gcc dot gnu.org
            Summary|Segmentation fault occurs   |[C++17] Segmentation fault
                   |when use variable           |occurs when use variable
                   |initialized using           |initialized using
                   |structured binding with     |structured binding with
                   |capture-by-ref lambda       |capture-by-ref lambda
     Ever confirmed|0                           |1

--- Comment #1 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
This is interesting.
In [dcl.decomp]/4, there doesn't seem to be enough restrictions:
"Otherwise, all of E’s non-static data members shall be public direct members
of E or of the same unambiguous
public base class of E, E shall not have an anonymous union member, and the
number of elements in the
identifier-list shall be equal to the number of non-static data members of E.
Designating the non-static data
members of E as m 0 , m 1 , m 2 , ... (in declaration order), each v i is the
name of an lvalue that refers to the
member m i of e and whose type is cv T i , where T i is the declared type of
that member; the referenced type is
cv T i ."
It doesn't even say that E must be a class type (but what else can have
non-static data members).
And a lambda-expression has a class type [expr.prim.lambda]/4
"The type of the lambda-expression (which is also the type of the closure
object) is a unique, unnamed
non-union class type — called the closure type — whose properties are described
below. This class type is not
an aggregate type (8.6.1). The closure type is declared in the smallest block
scope, class scope, or namespace
scope that contains the corresponding lambda-expression. [ Note: This
determines the set of namespaces
and classes associated with the closure type (3.4.2). The parameter types of a
lambda-declarator do not
affect these associated namespaces and classes. — end note ]"

so this effectively allows taking apart the implementation defined non-static
data members of the lambda type.  Shall that be allowed?  Does the standard say
anything about the members of the lambda class type (i.e. can we e.g. declare
all of them to be private and reject the testcase from this reason)? Other
implementation defined types that could have similar weird effects are e.g.
va_list.

#include <stdarg.h>
void foo (int x, ...) {
  va_list ap;
  va_start (ap, x);
  auto [b, c, d, e] { *ap };
  va_end (ap);
}

On x86_64-linux with -m32, both g++ and clang++ correctly reject this, because
type of *ap is char.  With -m64, g++ rejects this with:
pr78896-2.C: In function ‘void foo(int, ...)’:
pr78896-2.C:5:8: error: cannot decompose non-array non-class type
‘__va_list_tag’
   auto [b, c, d, e] { *ap };
        ^~~~~~~~~~~~
because we do not consider __va_list_tag a class type, just an implementation
created record type.  clang++ actually accepts this with -m64.

Reply via email to