Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[basic.link] p19 Two confusing comments in the formal example #4925

Open
xmh0511 opened this issue Sep 22, 2021 · 6 comments
Open

[basic.link] p19 Two confusing comments in the formal example #4925

xmh0511 opened this issue Sep 22, 2021 · 6 comments

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Sep 22, 2021

export module A;
static void f() {}
// ...
struct S { void (&ref)(); } s{f};               // OK, value is TU-local
constexpr extern struct W { S &s; } wrap{s};    // OK, value is not TU-local
//...

static auto x = []{f();};           // OK
auto x2 = x;                        // error: the closure type is TU-local
int y = ([]{f();}(),0);             // error: the closure type is not TU-local

Per [basic.link#16.2]

A value or object is TU-local if either

  • it is, or is a pointer to, a TU-local function or the object associated with a TU-local variable, or
  • it is an object of class or array type and any of its subobjects or any of the objects or functions to which its non-static data members of reference type refer is TU-local and is usable in constant expressions.

s is not usable in constant expressions and it satisfies no bullet in the [basic.link] p15, hence s is a non-TU-local entity, what does the value mean? Why do we say the value of s is TU-local?

wrap is defined as a constexpr variable but is not initialized to a TU-local value, hence it is not an exposure as per [basic.link] p15, as well as it is a non-TU-local object. What does the value mean? Why do we say the value of wrap is not TU-local?

For int y = ([]{f();}(),0); , why do we say the declaration is an error? According to [basic.link#14.2], the declaration of y is not an exposure even though it is a non-TU-local entity, It didn't violate [basic.link#17].


Consider [basic.link] p14

A declaration is an exposure if it either names a TU-local entity (defined below), ignoring

  • [...]

or defines a constexpr variable initialized to a TU-local value (defined below).

According to [basic.pre] p3 and [basic.link] p16, value and object are different entities, does it mean a variable defined as constexpr that is initialized with a TU-local object is not an exposure?

@xmh0511 xmh0511 changed the title [basic.link] p19 Two confusing comments [basic.link] p19 Two confusing comments in the formal example Sep 22, 2021
@xmh0511
Copy link
Contributor Author

xmh0511 commented Sep 24, 2021

For int y = ([]{f();}(),0);. Presumably, the closure type is non-TU-local and it names the TU-local entity f, hence it is exposure. However, there is no normative explicitly says the closure type introduced by the lambda-expression names the entity f according to [basic.link] p13. The comment may expose the intent but it cannot be interpreted by normative rule. The divergence between Clang and GCC proofs the vague, see https://godbolt.org/z/xd8x1cbhK

@jensmaurer
Copy link
Member

@opensdh , any opinion here?

@opensdh
Copy link
Contributor

opensdh commented Nov 15, 2021

f is what is "usable in constant expressions", although that could do with some rephrasing since it's not the [expr.const]/4 definition that pertains there. The object (for) s is therefore TU-local, but the variable is not. Since s is not usable in constant expressions, the object (for) w is not TU-local, as required by the constexpr extern status of the variable w.

It is the declaration of the closure type of y's lambda that is the exposure: it isn't TU-local, because y isn't, and it mentions f.

[basic.pre]/3 is wrong: values and objects aren't entities. [basic.link]/14 (after the bullets) doesn't really mean to distinguish "value" and "object"; we just use the term "initialize x to a value y" to mean "initialize the object associated with x to have the state y", where "state" refers to the value of a scalar or the collection of values for an object. (We should clean up "value"/"object" while (or shortly after) we're cleaning up "object"/"variable".)

@xmh0511
Copy link
Contributor Author

xmh0511 commented Nov 16, 2021

@opensdh Based on your interpretation, the second bullet of [basic.link#16.2] can be phrased to that

A value or object is TU-local if either

  • it is, or is a pointer to, a TU-local function or the object associated with a TU-local variable, or
  • it is an object of class or array type, and
  • any of its subobjects ,or
  • any of the objects or functions to which its non-static data members of reference type refer

is TU-local and is usable in constant expressions.

Such a rearranged structure seems to be clearer.


For the case int y = ([]{f();}(),0);, I still cannot understand the corresponding comment. Since y is an non-TU-local entity, the closure type of the lambda expression []{f();} within this definition is also non-TU-local as per

a type, function, variable, or template that

  • has a name with internal linkage, or
  • does not have a name with linkage and is declared, or introduced by a lambda-expression, within the definition of a TU-local entity,

However, the declaration of y is not an exposure according to any bullet of [basic.link] p14; it do not violate [basic.link] p17. So, I don't understand what's the reason when we say the declaration is an error. You seem to say that the declaration of the closure type is exposure, I wonder which bullet in [basic.link] p13 and p14 does say that(i.e, the declaration of the closure type names the entity f)?

@opensdh
Copy link
Contributor

opensdh commented Nov 16, 2021

If we're going to change /16.2, we should actually fix the "usable in constant expressions" bit to not pertain to functions.

How does the closure type (or its operator(), if you imagine it might be defined outside the class) not name f? No one said the declaration of y itself was an exposure of anything.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Nov 16, 2021

@opensdh

How does the closure type (or its operator(), if you imagine it might be defined outside the class) not name f?

This is the question itself. In [expr.prim.lambda.closure] p3

The closure type for a lambda-expression has a public inline function call operator (for a non-generic lambda) or function call operator template (for a generic lambda)

It is the complete story about the operator() of the closure type, the rule didn't guarantee that the call operator is defined in the class or outside the class, and [basic.link] p13 do not clearly specify whether the closure type names the entity f(if there were, please point it out), hence we cannot determine whether the closure type is exposure since it depends on whether the declaration names TU-local entity.

Consider the declaration of closure type as the following

struct UniqueClosure{  // declaration of the closure type
   auto operator()();
};
auto UniqueClosure::operator()(){
    f();
}

A declaration D names an entity E if

  • D contains a lambda-expression whose closure type is E,
  • E is not a function or function template and D contains an id-expression, type-specifier, nested-name-specifier, template-name, or concept-name denoting E, or
  • E is a function or function template and D contains an expression that names E ([basic.def.odr]) or an id-expression that refers to a set of overloads that contains E.

None of these bullets prove that the declaration of UniqueClosure names the entity f.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants