cplusplus / draft

C++ standards drafts
http://www.open-std.org/jtc1/sc22/wg21/
5.69k stars 748 forks source link

[dcl.array] p.7 may be outdated #4387

Open RazvanAM opened 3 years ago

RazvanAM commented 3 years ago

Paragraph 7 of [dcl.array] (https://eel.is/c++draft/dcl.array#7) states:

In addition to declarations in which an incomplete object type is allowed, an array bound may be omitted in some cases in the declaration of a function parameter ([dcl.fct]). An array bound may also be omitted when an object (but not a non-static data member) of array type is initialized and the declarator is followed by an initializer ([dcl.init], [class.mem], [expr.type.conv], [expr.new]). In these cases, the array bound is calculated from the number of initial elements (say, N) supplied ([dcl.init.aggr]), and the type of the array is “array of N U”.

The wording "an array bound may be omitted in some cases in the declaration of a function parameter", among other changes, was added by the resolution to CWG619.

Actually, the highlighted part ("in some cases") is the only difference between the proposed resolution in February of 2010 and the proposed resolution in March of 2010.

I believe that the only cases in which it was not allowed (at that time) to omit array bounds in the declaration of a function parameter were specified by [dcl.fct] p.8, which stated (in N3035, published in 2010):

If the type of a parameter includes a type of the form “pointer to array of unknown bound of T” or “reference to array of unknown bound of T,” the program is ill-formed. Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays of pointers to functions. Types shall not be defined in return or parameter types. The type of a parameter or the return type for a function definition shall not be an incomplete class type (possibly cv-qualified) unless the function definition is nested within the member-specification for that class (including definitions in nested classes defined within the class).

However, the highlighted part of [dcl.fct] p.8 (forbidding pointers or references to arrays of unknown bound in the type of a parameter) was removed by the resolution to CWG393.

I do not know any cases in which, by the current specification, one cannot use arrays of unknown bound in the type of a function parameter. Are there any such cases that I am overlooking?

jensmaurer commented 3 years ago

I do not know any cases in which, by the current specification, one cannot use arrays of unknown bound in the type of a function parameter. Are there any such cases that I am overlooking?

What about

template<int> struct C { };
using T = long;
void f(C<sizeof(T[])> x);
RazvanAM commented 3 years ago

What about

template<int> struct C { };
using T = long;
void f(C<sizeof(T[])> x);

You are right, all 'contexts' that require a complete type (in this case the operand of sizeof) must have this requirement satisfied even if they appear in the declaration of a function parameter.

Maybe a better wording for [dcl.array]/7 should be something similar to:

An array bound may be omitted in declarations in which an incomplete object type is allowed. In addition to this, the type of a function parameter can be array of unknown bound of T. [...]

This is because I believe that being in a parameter declaration allows omitting only the array bound of the "top-level declarator" of the parameter (but there is no mention of "top-level declarator" in the standard, nor is the wording completely correct, as it would also allow cases such as void f(int a[ sizeof(int[]) ])). But I may be mistaken again.

jensmaurer commented 3 years ago

I'm wondering how much of what we say here is redundant with other places in the standard.

RazvanAM commented 3 years ago

After a quick search I did not find anything that allows omitting the array bound in function parameters except for this paragraph. But the first part (arrays of unknown bound are allowed in declarations in which an incomplete object is allowed) can be entailed from the rest of the standard.

RazvanAM commented 3 years ago

I'm wondering how much of what we say here is redundant with other places in the standard.

I apologize, I think I may have misunderstood you at first. Did you mean that removing "in some cases" from [dcl.array]/7 may be enough, because all other contexts that require an array bound even in the declaration of a function parameter are specified explicitly in the standard?

jensmaurer commented 3 years ago

No. I was wondering: What if we removed all this talk about where an array of unknown bounds is permitted in dcl.array p7, and just relied on the fact it's an incomplete type (plus it's effectively complete when we see an initializer). Function parameters may have incomplete type in non-defining function declarations, and the "array of unknown bound" decays to "pointer to X" anyway. Also, [dcl.fct.def.general] p2 prohibits only incomplete class types in function definitions; incomplete array types seem to be fine.

RazvanAM commented 3 years ago

I agree that there is nothing forbidding incomplete types (in general) to be the type of a parameter in a function declaration, except for, as you said, [dcl.fct.def.general]/2, which explicitly prohibits only incomplete class types from being the return type or the type of a parameter in a function definition (implying that other incomplete types, if not explicitly specified otherwise, are allowed), and [basic.def.odr]/12.9, a bullet in a note referring to [dcl.fct.def.general]/2, I believe.

So you are suggesting that [dcl.array]/7 should be changed to:

In addition to declarations in which an incomplete object type is allowed, an array bound may be omitted in some cases in the declaration of a function parameter ([dcl.fct]). An array bound may also be omitted when an object (but not a non-static data member) of array type is initialized and the declarator is followed by an initializer ([dcl.init], [class.mem], [expr.type.conv], [expr.new]). In these cases, the array bound is calculated from the number of initial elements (say, N) supplied ([dcl.init.aggr]), and the type of the array is “array of N U”.

Maybe a note should then be added to either [dcl.array]/7, [dcl.fct.def.general]/2 or [dcl.fct]/5 (or somewhere else, I do not know which place is better suited for this) to specify that a parameter in a function definition is allowed to have the type "array of unknown bound of T".

jensmaurer commented 3 years ago

Yes.