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

Clarify that direct-initialized, copy-initialized from E #4582

Open
xmh0511 opened this issue Apr 9, 2021 · 12 comments
Open

Clarify that direct-initialized, copy-initialized from E #4582

xmh0511 opened this issue Apr 9, 2021 · 12 comments
Labels
big An issue causing a large set of changes, scattered across most of the text.

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Apr 9, 2021

Presumably, "direct-initialized from E" and "copy-initialized from E" should be distinguishable with direct-initialization and copy-initialization. The initialization might be considered as an expression, as per

If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition. Conversions applied to the result of an expression in order to satisfy the requirements of the language construct in which the expression appears are also considered to be part of the full-expression. For an initializer, performing the initialization of the entity (including evaluating default member initializers of an aggregate) is also considered part of the full-expression.

I mean that an initialization has been a recipe(comprises the function will be called, if any) whose evaluation will initialize the destination object. However, direct(copy)-initialized from E might be a bit different.

There are many such a usage in the standard, such as
expr.static.cast#4

Otherwise, the result object is direct-initialized from E

dcl.dcl#dcl.init.aggr-5

Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list

So, what's the appearance of form here for copy-initialize or direct-initialize respectively? In other words, if we say that an entity t is direct-initialized from an expression E, what's the form?

T t(E); // #1
T t{E}; //#2

Does it refer to #1 or #2? Similarly, when we say that an entity t is copy-initialized from an expression E, what's the form?

T t = E; //#3
T t = {E};  //#4

It does not specify in the standard.

@xmh0511 xmh0511 changed the title Clarify direct-initialize and copy-initialize Clarify that direct-initialized, copy-initialized from E Apr 9, 2021
@jwakely
Copy link
Member

jwakely commented Apr 9, 2021

Presumably, "direct-initialized from E" and "copy-initialized from E" should be distinguishable with direct-initialization and copy-initialization.

Why?

So, what's the appearance of form here for copy-initialize or direct-initialize respectively? In other words, if we say that an entity t is direct-initialized from an expression E, what's the form?

If we say it's direct-initialized, we mean it's initialized using direct-initialization. Similarly for copy-initialized. I don't understand why there would be any doubt about that.

Direct-initialized means #1, because #2 is direct-list-initialization. Copy-initialized means #3 because #4 is copy-list-initialization.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 9, 2021

Presumably, "direct-initialized from E" and "copy-initialized from E" should be distinguishable with direct-initialization and copy-initialization.

Why?

So, what's the appearance of form here for copy-initialize or direct-initialize respectively? In other words, if we say that an entity t is direct-initialized from an expression E, what's the form?

If we say it's direct-initialized, we mean it's initialized using direct-initialization. Similarly for copy-initialized. I don't understand why there would be any doubt about that.

Direct-initialized means #1, because #2 is direct-list-initialization. Copy-initialized means #3 because #4 is copy-list-initialization.

Such as

struct A{
 A(int);  //#1
};
A a = static_cast<A>(0);

According to expr.static.cast#4, that says the result object a will be direct-initialized from 0. However, the expression 0 is not an initializer here, the whole section [dcl.init.general] is described for initializer. How will the initialization do?

@jensmaurer
Copy link
Member

I think we say "X-list-initialized" everywhere we mean it. Anywhere we initialize from a single expression, it's understood to be non-list-initialization. In some case, it depends on the form of the initializer (possibly given elsewhere) what we do.
The library section has some uses of "direct-non-list-initialization from (some expression)", though; maybe that would clarify.

@jensmaurer jensmaurer added the decision-required A decision of the editorial group (or the Project Editor) is required. label Apr 9, 2021
@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 10, 2021

I think we say "X-list-initialized" everywhere we mean it. Anywhere we initialize from a single expression, it's understood to be non-list-initialization. In some case, it depends on the form of the initializer (possibly given elsewhere) what we do.
The library section has some uses of "direct-non-list-initialization from (some expression)", though; maybe that would clarify.

Actually, the issue is caused by https://stackoverflow.com/questions/67016640/why-cant-a-prvalue-of-array-type-be-converted-to-the-same-type-using-static-cas.

int main(){
  using T = int[2];
  T arr = T{1,2};
}

Major implements complain that the above code is ill-formed. However, as per [expr.type.conv#2]

  1. A simple-type-specifier or typename-specifier followed by a parenthesized optional expression-list or by a braced-init-list (the initializer)...
  2. If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the corresponding cast expression. Otherwise, if the type is cv void and the initializer is () or {} (after pack expansion, if any), the expression is a prvalue of type void that performs no initialization. Otherwise, the expression is a prvalue of the specified type whose result object is direct-initialized with the initializer. If the initializer is a parenthesized optional expression-list, the specified type shall not be an array type.

Here the wording is "direct-initialized", which is equivalent to that the direct-initialization of the result object from the initializer where the initializer is {1,2}. Isn't that direct-list-initialization? That is, [dcl.init.list#3.4] will determine how to initialize the result object. It appears to me that the code should be well-defined.


Moreover, the whole [dcl.init.general] is most using either initializer or initializer expression in these bullets. However, in the other sections, we convenience to use the wording Y is X-initialized from E. I want to say that such an E is not the grammar of initializer that appears in a declaration. When determining how to initialize the object, Is that initializer or initializer expression conflict with E?

So, my point is, could we say that "Y is X-initialized from E" will model a declaration
For copy-initialized from E, it will be

T Y = E;

For direct-initialized from E, it E is braced-init-list, it will be

T Y E;

otherwise, if E is an expression, the corresponding declaration will be

T Y(E);

Now, E becomes an initializer or initializer expression in concept, which will conform with the wording in [dcl.init.general]

@jensmaurer
Copy link
Member

To your first point, the "direct-initialized" in [expr.type.conv] is correct, because it applies to both parenthesized expression-lists and to braced-init-lists. From there, we go to do [dcl.init] p15, and p15.1 branches off to [dcl.init.list] right away. [dcl.init.list] p3.4, in turn, goes to [dcl.init.aggr] and everything should work fine.

To your second point, I think the wording is sufficiently clear in intent that "direct-initialized from expression E" means "direct-non-list-initialized with source E" in the parlance of [dcl.init] p15. I do sympathize with clearly saying "direct-non-list-initialized" (or copy-non-list-initialized") for these cases.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 10, 2021

To your first point, the "direct-initialized" in [expr.type.conv] is correct, because it applies to both parenthesized expression-lists and to braced-init-lists. From there, we go to do [dcl.init] p15, and p15.1 branches off to [dcl.init.list] right away. [dcl.init.list] p3.4, in turn, goes to [dcl.init.aggr] and everything should work fine.

So, for the first point, we all agree that GCC and Clang have the wrong interpretation for the case.


For the second point, the whole [dcl.init]p15 is based on a destination type and a source type to state the relevant initialization where the source type is derived from the initializer expression

The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression.

However, some initializations are not triggered by a declaration with an initializer. Such as, it says that "Y is X-initialized from E". Could we say that E is an initializer expression? In my point, E is not an initializer on the grammar at all. The key point is here. As aforementioned, p15 is with the help of using source type(the type of the initializer expression).

@jensmaurer
Copy link
Member

We agree that E is not an initializer per the grammar; but I think it's reasonable to consider it an "initializer expression".

Would you be happier if we said "... direct-initialized from the initializer expression E..." everywhere we used "from E" nowadays?

@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 10, 2021

Would you be happier if we said "... direct-initialized from the initializer expression E..." everywhere we used "from E" nowadays?

No, I wouldn't. That would be a bit duplicate. Since there's no normative definition for initializer expression where the wording initializer might easily be understood as the expression that appears in the initializer.

@jensmaurer
Copy link
Member

So, back to saying "direct-non-list-initialized" and "copy-non-list-initialized" where we talk about expressions (as opposed to braced-init-lists).

@xmh0511
Copy link
Contributor Author

xmh0511 commented Apr 10, 2021

So, back to saying "direct-non-list-initialized" and "copy-non-list-initialized" where we talk about expressions (as opposed to braced-init-lists).

I think we are not necessary to say "direct-non-list-initialized" and "copy-non-list-initialized", since the following rule

List-initialization is initialization of an object or reference from a braced-init-list.

That means, Only the E is a braced-init-list will it be called direct or copy list initialization. I think we should clarify the wording "initializer expression" whose meaning beyond the initializer(grammar). It also refers to E when we say "Y is X-initialized from E" where E is not an initializer on grammar. I think.

Similarly, in the aggregate initialization, in some section, it says

the element is copy-initialized from an empty initializer list

That means the corresponding initialization is specified by [dcl.init#general]#15.1, however, the paragraph says

If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized

It refers to the initializer which is on grammar. Instead, strictly speaks, "an empty initializer list" is not an initializer on grammar. So, I still think we should introduce a hypothetical declaration to eliminate these conflicts.

@tkoeppe tkoeppe added the big An issue causing a large set of changes, scattered across most of the text. label Apr 16, 2021
@jensmaurer
Copy link
Member

Editorial meeting 2021-04-16: We have an in-between situation here. [dcl.init] should either state the complete set of places where which initialization happens (and then we just say X is initialized by "grammar"), or any place should be specific and say "direct-non-list-initialization" and the lists of places in [dcl.init] should be removed.

Consensus: Remove all "where" info from dcl.init and make sure all users of dcl.init are clear what kind of initialization they want.
Define X-initialization from an expression to be identical to X-initialization by (E).

Have CWG review the change.

@xmh0511
Copy link
Contributor Author

xmh0511 commented May 24, 2022

@jensmaurer The addition to this issue.

  1. Clarify the initializer expression

Since [dcl.init.general] p16.3 says

The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression. If the initializer is not a single (possibly parenthesized) expression, the source type is not defined.

How about this?

 T t = E;

In this declaration, the initializer is = E(grammatically ,= initializer-clause), which is not an expression.

  1. [over.match.ctor], [over.match.copy], [over.match.conv], [over.match.ref], [over.match.list] are only suitable for the initialization occurred in initializing declaration, in other words, for the simple-declaration that has initializer.

Consider [over.match.ctor] p1

The argument list is the expression-list or assignment-expression of the initializer.

In this rule, the initializer refers to the grammatical initializer. For this rule, consider this example

struct T{
   T(int);
};
T x = static_cast<T>(0);

According to [expr.static.cast] p4

Otherwise, the result object is direct-initialized from E.

The intent is [dcl.init.general] p16.6.2 and [over.match.ctor] apply here. However, what is the initializer of this direct-initialization in the context where the result object is direct-initialized from E? Anyway, we do not have the initializer since we do not have a grammar component like initializing declaration that specifies its grammatical initializer. Furthermore

The call is used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization.

when [over.match.ctor] is checked for this direct-initialization, what is the initializer in this context? It is also not clearly specified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
big An issue causing a large set of changes, scattered across most of the text.
Projects
None yet
Development

No branches or pull requests

4 participants