Skip to content

[basic.def.odr] explicitly captured variable is not odr-usable in lambda contract predicate #14

Description

@abhinavagarwal07

Subclause: [basic.def.odr]

Issue description

Bullet 4 of the odr-usability rule in [basic.def.odr] paragraph 10 requires the lambda's block scope to be an intervening scope. But a function contract predicate sits in the lambda-declarator, outside the block scope — so this [expr.prim.lambda] example is ill-formed despite its // OK:

void test() {
  int i = 1;
  auto f3 = [i] pre(i > 0) {};   // OK, i is captured explicitly.
}

Only bullet 4 can apply to the intervening lambda scope. i is captured, so the first conjunct holds; the second wants the block scope {} to intervene, but pre(i > 0) precedes {}. So i is not odr-usable.

P2900R14 added a contract-assertion scope to the benign-scope list in p10 but missed bullet 4, which still only knows the block scope. So it rejects this explicit-capture lambda contract predicate just as bullet 4 (CWG 2380) deliberately rejects [=](int k = n) {}.

Proposed resolution

Let bullet 4's second conjunct also accept a contract-assertion scope of the lambda-expression:

 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
+the block scope of the lambda-expression,
+or a contract-assertion scope [basic.scope.contract] introduced by a function
+contract assertion [dcl.contract.func] of the call operator or operator template
+of that lambda-expression,
 is also an intervening scope.

[=](int k = n) {} stays ill-formed, so CWG 2380 is unaffected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions