<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>P0588R1: Simplifying implicit lambda capture</title>

<style type="text/css">
ins, ins > * { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
del, del > * { text-decoration:line-through; background-color:#FFA0A0 }

.new { /*color: blue*/ }

blockquote {
  color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em;
}
blockquote.stdins {
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3;
  padding-left: 0.5em; padding-right: 0.5em;
}
blockquote.stddel {
  text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5em; padding-right: 0.5em;
}
</style>

</head>

<body>
Richard Smith<br>
2017-11-07

<h1>P0588R1: Simplifying implicit lambda capture</h1>

<b>Also:</b><br>
<a href="http://wg21.link/cwg1632">Core Issue 1632</a>: Lambda capture in member initializers<br>
<a href="http://wg21.link/cwg1913">Core Issue 1913</a>: <tt>decltype((x))</tt> in <i>lambda-expression</i>s<br>
(Core issue?): effect of structured bindings on lambda capture unspecified<br>

<p>
Change in 6 basic paragraph 3:
</p>

<blockquote>
An <i>entity</i> is a value, object, reference, <ins>structured binding</ins>,
function, enumerator, type, class member, bit-field,
template, template specialization, namespace, or parameter pack.
</blockquote>

<p>
Add a new paragraph after 6 basic paragraph 6 ("A <i>variable</i> is &hellip;"):
</p>

<blockquote class="stdins">
A <i>local entity</i> is a variable
with automatic storage duration ([basic.stc.auto]),
a structured binding ([dcl.struct.bind]) whose corresponding variable is such an entity,
or the <tt>*this</tt> object ([expr.prim.this]).
</blockquote>

<p>
Change in 6.2 basic.def.odr paragraph 3, splitting into paragraphs as indicated:
</p>

<blockquote>
A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the
lvalue-to-rvalue conversion (7.1) to x yields a constant expression (8.20) that does not invoke any non-trivial
functions and, if x is an object, ex is an element of the set of potential results of an expression e, where
either the lvalue-to-rvalue conversion (7.1) is applied to e, or e is a discarded-value expression (Clause 8).

<p>
<ins>
A structured binding is odr-used if it appears as a potentially-evaluated
expression.
</ins>

<p>
<tt><ins>*</ins>this</tt> is odr-used if <del>it</del> <ins><tt>this</tt></ins>
appears as a potentially-evaluated expression (including as the result of the
implicit transformation in the body of a non-static member function (12.2.2)).

<p>
A virtual member function is odr-used if it is not pure.
A function whose name appears as a potentially-evaluated expression
is odr-used if it is the unique lookup result or the selected member
of a set of overloaded functions &hellip;

<p>
An allocation or deallocation function for a class is odr-used by a <i>new-expression</i> &hellip;

<p>
An assignment operator function in a class is odr-used by an implicitly-defined copy assignment or move-assignment function for another class as specified in 15.8.
A constructor for a class is odr-used as specified in 11.6.
A destructor for a class is odr-used if it is potentially invoked (15.4).
</blockquote>

<em>Drafting note: we may wish to further constrain what qualifies as an odr-use
of a structured binding when we start to allow structured binding declarations
to be declared <tt>constexpr</tt>.</em>

<p>
Add a new paragraph before 6.2 basic.def.odr paragraph 4 ("Every program shall contain exactly one definition"):
</p>

<blockquote class="stdins">
A local entity ([basic]) is <i>odr-usable</i>
in a declarative region ([basic.scope.declarative]) if:
<ul>
<li>
the local entity is either not <tt>*this</tt>, or
<span class="new">
an enclosing class or non-lambda function parameter scope exists
and, if the innermost such scope is a function parameter scope,
it corresponds to a non-static member function,
</span>
and
<li>
for each intervening declarative region ([basic.scope.declarative])
between the point at which the entity is introduced
(where <tt>*this</tt> is considered to be introduced within the
innermost enclosing class or
<span class="new">
non-lambda
</span>
function definition scope)
and the region, either:
<ul>
<li>
the declarative region is a block scope, or
<li>
the declarative region is the function parameter scope of a
<i>lambda-expression</i> that
has a <i>simple-capture</i> naming the entity
or
has a <i>capture-default</i>.
</ul>
</ul>
If a local entity is odr-used in a declarative region in which it is not
odr-usable, the program is ill-formed.
[&nbsp;<i>Example</i>:
<pre>void f(int n) {
  [] { n = 1; };         // error, n is not odr-usable due to intervening lambda-expression
  struct A {
    void f() { n = 2; }  // error, n is not odr-usable due to intervening function definition scope
  };
  void g(int = n);       // error, n is not odr-usable due to intervening function prototype scope
  [&amp;] { [n]{ n = 3; } }; // ok
}</pre> ]
</blockquote>

<p>
Add a new paragraph after 6.3.1 basic.scope.declarative paragraph 4 ("Given a set of declarations in a single declarative region"):
</p>

<blockquote class="stdins">
For a given declarative region <i>R</i> and a point <i>P</i> outside <i>R</i>,
the set of <i>intervening</i> declarative regions between <i>P</i> and <i>R</i>
comprises all declarative regions
that are or enclose <i>R</i> and do not enclose <i>P</i>.
</blockquote>

<p>
Move 6.3.3 basic.scope.block paragraph 2 to a new subclause
6.3.4 basic.scope.param ("Function parameter scope"), with the following changes:
</p>

<blockquote>
<ins>
A function parameter (including one appearing in a <i>lambda-declarator</i>) or
function-local predefined variable ([dcl.fct.def]) has
<i>function parameter scope</i>.
</ins>
The potential scope of a <del>function</del> parameter <del>name</del>
<del>(including one appearing in a lambda-declarator)</del> or
of a function-local predefined variable
<del>in a function definition (11.4)</del>
begins at its point of declaration.
<ins>
If the nearest enclosing function declarator is not the declarator of
a function definition, the potential scope ends at the
end of that function declarator. Otherwise, if
</ins>
<del>If</del>
the function has a function-try-block
the potential scope <del>of a parameter or of a function-local predefined variable</del>
ends at the end of the last associated handler
<del>, otherwise</del>
<ins>. Otherwise the potential scope</ins>
<del>it</del> ends at the end of the outermost block of the function definition.
A parameter name shall not be redeclared
in the outermost block of the function definition
nor in the outermost block of any handler associated
with a function-try-block.
</blockquote>

<p>
Delete 6.3.4 basic.scope.proto ("Function prototype scope").
</p>

<p>
Change in 8.1.4.1 expr.prim.id.unqual paragraph 1, inserting a paragraph break as shown:
</p>

<blockquote>
[&hellip;]
<del>The type of the expression is the type of the <i>identifier</i>.</del>

<p>
The result is the entity denoted by the identifier.
<ins>
If the entity is a local entity and
naming it from outside of an unevaluated operand within the declarative
region where the <i>unqualified-id</i> appears would result in some
intervening <i>lambda-expression</i> capturing it by copy,
the type of the expression is
the type of a class member access expression ([expr.ref])
naming the non-static data member
that would be declared for such a capture in the closure object of the
innermost such intervening <i>lambda-expression</i>.
[&nbsp;<i>Note</i>: If that <i>lambda-expression</i> is not declared
<tt>mutable</tt>, the type of such an identifier
will typically be <tt>const</tt> qualified. ]
Otherwise, the type of the expression is the type of the result.
[&nbsp;<i>Note</i>: The type will be adjusted as described in Clause [expr] if
it is <i>cv</i>-qualified or is a reference type. ]</ins>
The expression is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise; it is a bit-field if the identifier designates a bit-field.

<p>
<ins>[&nbsp;<i>Example</i>:</ins>
<pre><ins>void f() {
  float x, &r = x;
  [=] {
    decltype(x) y1; // y1 has type float
    decltype((x)) y2 = y1; // y2 has type float const& because this lambda is not mutable and x is an lvalue
    decltype(r) r1 = y1; // r1 has type float&
    decltype((r)) r2 = y2; // r2 has type float const&
  };
}
</ins>
</pre>
<ins>]</ins>
</blockquote>

<em>Drafting note: the above example is moved from 8.1.5.2 expr.prim.lambda.capture paragraph 14 with minor changes.</em>

<p>
Change in 8.1.5.2 expr.prim.lambda.capture paragraph 3:
</p>

<blockquote>
<span class="new">
A <i>lambda-expression</i>
<del>
whose smallest enclosing scope is
a block scope (6.3.3)</del>
is a <i>local lambda expression</i>
<ins>if its innermost enclosing scope is a block scope ([basic.scope.block]),
or if it appears within a default member initializer and its innermost
enclosing scope is the corresponding class scope ([basic.scope.class])</ins>;
</span>
any other <i>lambda-expression</i>
shall not have a <i>capture-default</i>
or <i>simple-capture</i> in its <i>lambda-introducer</i>.
<del>The <i>reaching scope</i> of a local lambda expression
is the set of enclosing scopes
up to and including the innermost enclosing function and its parameters.
[&nbsp;<i>Note</i>: This reaching scope includes any intervening
<i>lambda-expressions</i>. ]
</del>
</blockquote>

<p>
Change in 8.1.5.2 expr.prim.lambda.capture paragraph 4:
</p>

<blockquote>
The identifier in a <i>simple-capture</i> is looked up
using the usual rules for unqualified name lookup (6.4.1);
each such lookup shall find <del>an</del> <ins>a local</ins> entity.
<ins>The <i>simple-capture</i>s <tt>this</tt> and <tt>* this</tt> denote the
local entity <tt>*this</tt>.</ins>
An entity that is designated by a <i>simple-capture</i> is said to be
<i>explicitly captured</i><del>, and shall be *this
(when the simple-capture is “this” or “* this”) or a variable with automatic
storage duration declared in the reaching scope of the local lambda expression</del>.
</blockquote>

<p>
Change in 8.1.5.2 expr.prim.lambda.capture paragraph 7:
</p>

<blockquote>
<ins>
For the purposes of lambda capture, an expression potentially references
local entities as follows:
<ul>
<li>An <i>id-expression</i> that names a local entity potentially references that entity;
an <i>id-expression</i> that names one or more non-static class members
<span class="new">
and does not form a pointer to member ([expr.unary.op])
</span>
potentially references <tt>*this</tt>.
[&nbsp;<i>Note</i>: This occurs even if overload resolution selects a
static member function for the <i>id-expression</i>. ]
<li>A <tt>this</tt> expression potentially references <tt>*this</tt>.
<li>A <i>lambda-expression</i> potentially references the local entities named by its
<i>simple-capture</i>s.
</ul>
<!--
A local entity is <i>capturable</i> in a declarative region if
it is odr-usable ([basic.def.odr]) and there is at least one
intervening function parameter scope corresponding to a <i>lambda-expression</i>
between the 
-->
If an expression potentially references a local entity
within a declarative region in which it is odr-usable, and
the expression would be potentially evaluated
if the effect of any enclosing <tt>typeid</tt> expressions
([expr.typeid]) were ignored,
the entity is said to be <i>implicitly captured</i>
by each intervening</ins>
<del>A</del> <i>lambda-expression</i>
with an associated <i>capture-default</i>
that does not explicitly capture <ins>it.</ins>
<del>*this or a variable with automatic storage duration
(this excludes any id-expression that has been found to refer to an
init-capture’s associated non-static data member),
is said to <i>implicitly capture</i>
the entity (i.e., *this or a variable)
if the
<i>compound-statement</i>:
<ul>
<li>odr-uses (6.2) the entity (in the case of a variable),
<li>odr-uses (6.2) this (in the case of the object designated by *this), or
<li>names the entity in a potentially-evaluated expression (6.2) where the enclosing full-expression depends
on a generic lambda parameter declared within the reaching scope of the lambda-expression.
</ul>
</del>
[&nbsp;<i>Example</i>:
<pre>
void f(int, const int (&)[2] = {})<ins>;</ins> <del>{ }</del>   // #1
void f(const int&, const int (&)[1])<ins>;</ins> <del>{ }</del> // #2
void test() {
  const int x = 17;
  auto g = [](auto a) {
    f(x); // OK: calls #1, does not capture x
  };

<ins>
  auto g1 = [=](auto a) {
    f(x); // OK: calls #1, captures x
  };
</ins>

  auto g2 = [=](auto a) {
    int selector[sizeof(a) == 1 ? 1 : 2]{};
    f(x, selector); // OK: <del>is a dependent expression, so</del> captures x<ins>, might call #1 or #2</ins>
  };

<ins>
  auto g3 = [=](auto a) {
    typeid(a + x);  // captures x regardless of whether a + x is an unevaluated operand
  };
</ins>
}
</pre>
<ins>
Within <tt>g1</tt>, an implementation might optimize away the capture of
<tt>x</tt> as it is not odr-used.
</ins>
]
<ins>
[&nbsp;<i>Note</i>:
The set of captured entities is determined syntactically, and entities might be
implicitly captured even if the expression denoting a local entity is within a
discarded statement ([stmt.if]).
[&nbsp;<i>Example</i>:
<pre>
template&lt;bool B&gt;
void f(int n) {
  [=](auto a) {
    if constexpr (B &amp;&amp; sizeof(a) > 4) {
      (void)n;
    }
  }(0); // captures n regardless of the value of B and sizeof(int)
}
</pre>
] ]
</ins>
<del>
All such implicitly captured entities shall be declared
within the reaching scope of the lambda expression.
[&nbsp;<i>Note</i>:
The implicit capture of an entity by a nested lambda-expression
can cause its implicit capture by the containing lambda-expression (see below). Implicit odr-uses of this can result in implicit capture. ]
</del>
</blockquote>

<p>
Change in 8.1.5.2 expr.prim.lambda.capture paragraph 8:
</p>

<blockquote>
An entity is captured if it is captured explicitly or implicitly.
An entity captured by a lambda-expression is odr-used (6.2)
in the scope containing the lambda-expression.
<del>
If *this is captured by a local lambda
expression, its nearest enclosing function
shall be a non-static member function.
If a lambda-expression or an
instantiation of the function call operator template
of a generic lambda odr-uses (6.2) this or a variable with
automatic storage duration from its reaching scope,
that entity shall be captured by the lambda-expression.
</del>
If a <i>lambda-expression</i> <ins>explicitly</ins> captures an entity
<del>and</del>
that <del>entity</del> is not <ins>odr-usable</ins>
<del>defined or captured in the immediately
enclosing lambda expression or function</del>
<ins>or captures a structured binding (explicitly or implicitly)</ins>,
the program is ill-formed.
[&nbsp;<i>Example</i>:
<pre>
&hellip;
auto m4 = [&,j] {    // error: j <ins>not odr-usable due to intervening lambda</ins> <del>not captured by</del> m3
  int x = n;         // error: n <ins>is odr-used but not odr-usable due to intervening lambda</ins> <del>implicitly captured by m4 but not captured by</del> m3
  x += m;            // OK: &hellip;
  x += i;            // error: i is <del>outside of the reaching scope</del> <ins>odr-used but not odr-usable due to intervening function and class scopes</ins>
&hellip;
]
</blockquote>

<em>Drafting note: the wording for structured bindings here is a placeholder,
to be replaced by whatever behavior we actually want for lambda capture of
structured bindings.</em>

<p>
Change in 8.1.5.2 expr.prim.lambda.capture paragraph 11:
</p>

<blockquote>
Every id-expression within the compound-statement of a lambda-expression
that is an odr-use (6.2) of an entity captured by copy
is transformed into an access to the
corresponding unnamed data member of the closure type.
[ Note: An id-expression that is not an odr-use refers to the original entity,
never to a member of the closure type.
<del>Furthermore</del> <ins>However</ins>, such an id-expression
<del>does not</del> <ins>can still</ins> cause the implicit capture
of the entity. ]

If <tt>*this</tt> is captured by copy, each <ins>expression that</ins> odr-use<ins>s</ins> <del>of</del> <tt><ins>*</ins>this</tt> is transformed <del>into a pointer to</del><ins>to instead refer to</ins> the corresponding unnamed data member of the closure type<del>, cast (8.4) to the type of this</del>. <del>[Note: The cast ensures that the transformed expression is a prvalue. — end note ]</del>

[&hellip;]
</blockquote>

<p>
Delete 8.1.5.2 expr.prim.lambda.capture paragraph 14:
</p>

<blockquote class="stddel">
Every occurrence of <tt>decltype((x))</tt> where <tt>x</tt> is a possibly parenthesized <i>id-expression</i> that names an entity of automatic storage duration is treated as if <tt>x</tt> were transformed into an access to a correspnding data member of the closure type that would have been declared if <tt>x</tt> were an odr-use of the denoted entity.
[&nbsp;<i>Example</i>: &hellip; ]
</blockquote>

<p>
Change in 11.3.5 dcl.fct paragraph 14:
</p>

<blockquote>
[&hellip;] ([basic.scope.<del>proto</del><ins>param</ins>]) [&hellip;]
</blockquote>

<p>
Change in 11.3.6 dcl.fct.default paragraph 7:
</p>

<blockquote>
<ins>[&nbsp;<i>Note</i>:</ins>
A local variable <del>shall not appear as a potentially-evaluated expression</del>
<ins>cannot be odr-used ([basic.def.odr])</ins> in a default argument.
<ins>]</ins>
[&hellip;]
</blockquote>

<p>
Change in 12.4 class.local paragraph 1:
</p>

<blockquote>
<ins>[&nbsp;<i>Note</i>: A declaration</ins>
<del>Declarations</del> in a local class <del>shall</del> <ins>can</ins>not
odr-use (6.2) <del>a variable with automatic storage duration</del> <ins>a local entity</ins>
from an enclosing scope.
<ins>]</ins>
[&nbsp;<i>Example</i>:
<pre>
&hellip;
<ins>int arr[1, 2];
auto [y, z] = arr;</ins>

struct local {
  int g() { return x; }    // error: odr-use of <del>automatic</del> <ins>non-odr-usable</ins> variable x
  &hellip;
  int* n() { return &N; }  // error: odr-use of <del>automatic</del> <ins>non-odr-usable</ins> variable N
<ins>  int p() { return y; }    // error: odr-use of non-odr-usable structured binding y</ins>
};
&hellip;
</pre>
]
</blockquote>

<p>
Change in 17.8.1 temp.inst paragraph 9:
</p>

<blockquote>
An implementation shall not implicitly instantiate a function template, a
variable template, a member template, a non-virtual member function, a member
class, a static data member of a class template, or a substatement of a
constexpr if statement (9.4.1), unless such instantiation is required.
<ins>[&nbsp;<i>Note</i>:
The instantiation of a generic lambda does not require instantiation of
substatements of a constexpr if statement within its <i>compound-statement</i>
unless the call operator template is instantiated.
]</ins>
[&hellip;]
</blockquote>

<p>
Add entry to Annex C:
</p>

<blockquote class="stdins">
[expr.prim.lambda.capture]<br>
<b>Change:</b> Implicit lambda capture may capture additional entities.<br>
<b>Rationale:</b> Rule simplification, necessary to resolve interactions with constexpr if.</br>
<b>Effect on original feature:</b> Lambdas with a <i>capture-default</i> may capture
local entities that were not captured in C++ 2017 if those entities are only
referenced in contexts that do not result in an odr-use.
</blockquote>

</body></html>
