Red
Red

Reputation: 1

Discarded-value expression and odr-used in C++20

Consider the following example:


    #include <iostream>
    using namespace std;
    
    int main() {
         int n=1;
        []()
            {
                n;// (1): error
             }();
    }

According to c++20 :

A variable x whose name appears as a potentially-evaluated expression E is odr-used by E unless
...
— x is a variable of non-reference type, and E is an element of the set of potential results of a discarded-value expression (7.2) to which the lvalue-to-rvalue conversion is not applied.

And also in c++20 :

A local entity (6.1) is odr-usable in a declarative region (6.4.1) if:

(9.1) — either the local entity is not *this, or 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, and

(9.2) — for each intervening declarative region (6.4.1) between the point at which the entity is introduced and the region (where *this is considered to be introduced within the innermost enclosing class or non-lambda function definition scope), either:

(9.2.1) — the intervening declarative region is a block scope, or

(9.2.2) — the intervening declarative region is the function parameter 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 declarative region.

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

(1) is a discarded-value expression so "n" is not odr-used and can therefore be used in a lambda without capture (according to the above rules ). So why is (1) error?

Upvotes: 0

Views: 158

Answers (1)

duck
duck

Reputation: 2448

Your analysis is correct: n is not odr-used by its appearance in the lambda body, so it does not have to be captured, which makes this program well-formed. Curiously, none of the major implementations seem to get this right.

The change that made this case valid was introduced by the resolution of CWG2083, prior to which [basic.def.odr]/3 used to read:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion to x yields a constant expression 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 is applied to e, or e is a discarded-value expression.

The relevant part of the change is that the "not odr-used if discarded" property now applies to all non-reference variables, rather than only to (a subset of) those usable in constant expressions.

Upvotes: 0

Related Questions