Skip to content

[0005] Adding spec language for strict initializer lists #522

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions proposals/0005-strict-initializer-lists.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,86 @@ Fix-It will be backwards compatible to prior HLSL versions.
New code that takes advantage of C & C++'s zero-initialization behavior, will
not be backwards compatible to older HLSL versions.

## Detailed Design

HLSL 202y shall adopt specification language aligned with the [ISO C++
specification (ISO/IEC
14882:2011)](https://timsong-cpp.github.io/cppwp/n3337/dcl.init).

The language in the next subsection will replace the **Decl.Init.Agg** section
of the HLSL specification.

### Specification Language

An _aggregate_ is a vector, matrix, array, or class which contains
* no user-declared or inherited constructors
* no non-public non-static data members, and
* no non-public base classes

The subobjects of an aggregate have a defined _subobject order_. For vectors and
arrays the order is increasing subscript order. For matrices it is increasing
subscript order with the subscript nesting such that in the notation
`Mat[M][N]`, the ordering is `Mat[0][0]...Mat[0][N]... Mat[M][0]...Mat[M][N]`.
For classes the order is recursively the order of the base class, followed by
member subobjects in declaration order. Anonymous bitfields are not included in
the subobject ordering.

When initialized by an initializer list the elements of the initializer list are
initializers for the members of the aggregate in subobject order. Each member is
copy-initialized from the corresponding initializer-clause. If the
initializer-clause is an expression which requires a narrowing conversion to
convert to the subobject type, the program is ill-formed.

An aggregate that is a class can also be initialized by a single expression not
enclosed in braces.

An array of unknown size may be initialized by a brace enclosed
initializer-list. For arrays of unknown size the initializer list shall contain
`n` initializers where `n > 0` and will produce an array containing `n`
elements.

If an initializer-list contains more initializer-clauses than the number of
subbjects being initialized, the program is ill-formed.

If an initializer-list contains fewer initializer-clauses than the number of
subobjects being initialized, each member not explicitly initialized shall be
initialized as if by an empty initializer list.

If an aggregate class contains a subobject member that has no members in its
subobject order, the initializer-clause for the empty subobject shall not be
omitted from an initializer list for the containing class unless the
initializer-caluses for all following members of the class are also omitted.

An initializer-list that is part of a braced-init-list may elide braces for
initializing subobjects. If braces are elided, a number of initializer-clauses
equal to the subobject's number of elements initializes the subobject. If braces
are present, it forms a braced-init-list which initializes the subobject
following the rules of this section.

A multi-dimensional array may be initialized using a single braced-initializer
list or with nested initializer lists. When initializing with a single
braced-initializer the order of initialization matches the memory layout.

```hlsl
int x[2][2] = {1, 2, 3, 4}; // [0][0] = 1, [0][1] = 2,
// [1][0] = 3,[1][1] = 4
int y[3][2] = {{1,2}, {3}, {4}}; // [0][0] = 1, [0][1] = 2,
// [1][0] = 3, [1][1] = 0,
// [2][0] = 4, [2][1] = 0
```

Element initialization behaves as if an assignment-expression is evaluated
from the initializer-clause to the initialized member. All implicit conversions
are applied as appropriate to convert the initializer to the member type. If the
assignment-expression is ill-formed and the element is a subobject, brace
elision is assumed and an assignment-expression is evaluated as if initializing
the first element of the subobject. If both assignment-expressions are
ill-formed the program is ill-formed.

When a union is initialized with an initializer-list, the initializer-list will
contain only one initializer-clause which will initialize the first non-static
data member of the union.

## Unanswered Questions

### Should we support initialization constructors (i.e. `uint4 i4{}`)?
Expand Down