Skip to content

CWG2883 [basic.def.odr] Using captures in lambda bodies always disallowed because odr-usable definition does not account for lambda scopes #523

Description

@hubert-reinterpretcast

Full name of submitter (unless configured in github; will be published with the issue): Hubert Tong

Reference (section label): basic.def.odr

Link to reflector thread (if any): N/A

Issue description:
https://eel.is/c++draft/basic.def.odr#10 defines odr-usable and has a rule:

If a local entity is odr-used in a scope in which it is not odr-usable, the program is ill-formed.

One of the requirements for a local entity to be odr-usable, is that there are no intervening scopes other than block scopes and function parameter scopes.

Consider:

void f() {
  int x;
  [&] { return x; };
}

There is a lambda scope (https://eel.is/c++draft/basic.scope.lambda) between the block scope of the compound-statement and the definition of x. It follows that the above code is ill-formed (according to the wording).

Consider also:

struct A {
  A() = default;
  A(const A &) = delete;
  constexpr operator int() { return 42; }
};
void f() {
  constexpr A a;
  [=]<typename T, int = a> {};
}

The only reason from the wording for why a is not odr-usable from the default argument (and thus not captured, see https://eel.is/c++draft/expr.prim.lambda.capture#7) is because there is a lambda scope. There is implementation divergence: https://godbolt.org/z/d41381qxM. Behaviours observed include accepting the code, rejecting the code because of the deleted copy constructor, and rejecting the code because a is named from the default template argument.

Suggested resolution:
Replace the bullets under https://eel.is/c++draft/basic.def.odr#10.2 with:

  • the intervening scope is a block scope,
  • the intervening scope is the function parameter scope of a lambda-expression, or
  • the intervening scope is the lambda scope of a lambda-expression that has a simple-capture naming the entity or has a capture-default, and the block scope of the lambda-expression is also an intervening scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions