diff --git a/compiler/include/dmd/init.h b/compiler/include/dmd/init.h index 142af9c73619..be80077e6bb8 100644 --- a/compiler/include/dmd/init.h +++ b/compiler/include/dmd/init.h @@ -84,9 +84,10 @@ class ArrayInitializer final : public Initializer public: Expressions index; // indices Initializers value; // of Initializer *'s - unsigned dim; // length of array being initialized Type *type; // type that array will be used to initialize - d_bool isCarray; // C array semantics + unsigned dim; // length of array being initialized + d_bool isCarray; // C array semantics + d_bool defaultInitialze; // ends with `,...]` meaning "default initialize the rest" bool isAssociativeArray() const; diff --git a/compiler/src/dmd/astbase.d b/compiler/src/dmd/astbase.d index 77f7e5b1d8e9..0df594afcdca 100644 --- a/compiler/src/dmd/astbase.d +++ b/compiler/src/dmd/astbase.d @@ -6526,8 +6526,10 @@ struct ASTBase { Expressions index; Initializers value; - uint dim; Type type; + uint dim; + bool isCarray; + bool defaultInitialize; extern (D) this(Loc loc) { diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index 8ce816a68199..13342237123e 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -4129,9 +4129,10 @@ class ArrayInitializer final : public Initializer public: Array index; Array value; - uint32_t dim; Type* type; + uint32_t dim; bool isCarray; + bool defaultInitialize; bool isAssociativeArray() const; void accept(Visitor* v) override; }; diff --git a/compiler/src/dmd/hdrgen.d b/compiler/src/dmd/hdrgen.d index 6ba5ee210387..d9e1c4b6fa7a 100644 --- a/compiler/src/dmd/hdrgen.d +++ b/compiler/src/dmd/hdrgen.d @@ -4265,6 +4265,8 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, ref HdrGenS if (auto iz = ai.value[i]) initializerToBuffer(iz, buf, hgs); } + if (ai.defaultInitialize) + buf.put(", ..."); buf.put(']'); } diff --git a/compiler/src/dmd/init.d b/compiler/src/dmd/init.d index 9a118bb3d658..a466021058da 100644 --- a/compiler/src/dmd/init.d +++ b/compiler/src/dmd/init.d @@ -175,9 +175,10 @@ extern (C++) final class ArrayInitializer : Initializer { Expressions index; // indices Initializers value; // of Initializer *'s - uint dim; // length of array being initialized Type type; // type that array will be used to initialize + uint dim; // length of array being initialized bool isCarray; // C array semantics + bool defaultInitialize; // ends with `,...]` meaning "default initialize the rest" extern (D) this(Loc loc) { diff --git a/compiler/src/dmd/initsem.d b/compiler/src/dmd/initsem.d index b3cf9933a9df..579049d374ac 100644 --- a/compiler/src/dmd/initsem.d +++ b/compiler/src/dmd/initsem.d @@ -251,11 +251,13 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn } i.type = t; length = 0; + bool hasIndices = false; for (size_t j = 0; j < i.index.length; j++) // don't replace with foreach; j is modified { Expression idx = i.index[j]; if (idx) { + hasIndices = true; sc = sc.startCTFE(); idx = idx.expressionSemantic(sc); sc = sc.endCTFE(); @@ -320,6 +322,18 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn else { ulong edim = tsa.dim.toInteger(); + if (i.defaultInitialize && hasIndices) + { + error(i.loc, "cannot use both indices and `...` in static array initializer"); + return err(); + } + if (i.dim < edim && !i.defaultInitialize && !i.isCarray && !hasIndices && + sc.hasEdition(Edition.v2024)) + { + deprecation(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); + deprecationSupplemental(i.loc, "use `, ...]` if intentional"); + //return err(); + } if (i.dim > edim) { error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); @@ -327,6 +341,11 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn } } } + else if (i.defaultInitialize) + { + error(i.loc, "can only use `...` in static array initializer"); + return err(); + } if (errors) return err(); diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 81dac5c5d8ae..d5f709e1dbc1 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -7012,6 +7012,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer */ private AST.Initializer parseInitializer() { + //printf("parseInitializer()\n"); const loc = token.loc; switch (token.value) @@ -7086,6 +7087,16 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer commaExpected = true; continue; + case TOK.dotDotDot: + if (commaExpected) + { + error("comma expected before `...]`"); + } + ia.defaultInitialize = true; + nextToken(); + check(TOK.rightBracket); + break; + case TOK.leftCurly: case TOK.leftBracket: if (commaExpected) diff --git a/compiler/test/compilable/extra-files/vcg-ast.d.cg b/compiler/test/compilable/extra-files/vcg-ast.d.cg index dafad19e7b43..f1c97ae61511 100644 --- a/compiler/test/compilable/extra-files/vcg-ast.d.cg +++ b/compiler/test/compilable/extra-files/vcg-ast.d.cg @@ -108,6 +108,7 @@ template imported() alias myImport = vcg_ast_import; enum bool compiles = true; enum bool isexp = true; +int[3] arr = [1, ...]; R!int { struct _R @@ -257,4 +258,4 @@ RTInfo!(_R) { enum immutable(void)* RTInfo = null; -} +} \ No newline at end of file diff --git a/compiler/test/compilable/vcg-ast.d b/compiler/test/compilable/vcg-ast.d index 6a9055574008..1851b4b97fc4 100644 --- a/compiler/test/compilable/vcg-ast.d +++ b/compiler/test/compilable/vcg-ast.d @@ -88,3 +88,5 @@ enum isexp = is(typeof({ int[] arr; arr ~= 1; })); + +int[3] arr = [1, ...]; diff --git a/compiler/test/fail_compilation/array1.d b/compiler/test/fail_compilation/array1.d new file mode 100644 index 000000000000..92d5a1b0fad8 --- /dev/null +++ b/compiler/test/fail_compilation/array1.d @@ -0,0 +1,30 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/array1.d(22): Deprecation: array initializer has 3 elements, but array length is 4 +fail_compilation/array1.d(22): use `, ...]` if intentional +fail_compilation/array1.d(25): Error: can only use `...` in static array initializer +fail_compilation/array1.d(26): Error: cannot use both indices and `...` in static array initializer +fail_compilation/array1.d(29): Deprecation: array initializer has 1 elements, but array length is 4 +fail_compilation/array1.d(29): use `, ...]` if intentional +--- +*/ + +module m 2024; + +extern (C) immutable int[4] a = [1,2,3,...]; +static assert(a[3] == 0); + +immutable int[4] b = [1,2,3,...]; +static assert(b[3] == 0); + +int[4] c = [1,2,3]; +int[4] d = [1:1]; // OK + +int[] e = [1,...]; +int[4] f = [2:1,...]; + +// nested initializer +int[4][] s1 = [[1]]; +int[4][] s2 = [[1,...]]; // OK diff --git a/compiler/test/runnable/b20890.d b/compiler/test/runnable/b20890.d index 9b208da3f772..033f700e6959 100644 --- a/compiler/test/runnable/b20890.d +++ b/compiler/test/runnable/b20890.d @@ -30,11 +30,12 @@ void format8(string spec, S8[1] s) assert (spec == "lengthy"); assert (s[0].m == 42); } -struct S42 { ubyte[42] m = [42]; } +struct S42 { ubyte[42] m = [42, ...]; } void format42(string spec, S42[1] s) { assert (spec == "lengthy"); assert (s[0].m[0] == 42); + assert (s[0].m[1] == 0); } void main() diff --git a/druntime/src/core/sys/windows/winsock2.d b/druntime/src/core/sys/windows/winsock2.d index c2cc1864e1d8..09092d1a6d91 100644 --- a/druntime/src/core/sys/windows/winsock2.d +++ b/druntime/src/core/sys/windows/winsock2.d @@ -637,7 +637,7 @@ union in6_addr } -enum in6_addr IN6ADDR_ANY = { s6_addr8: [0] }; +enum in6_addr IN6ADDR_ANY = { s6_addr8: 0 }; enum in6_addr IN6ADDR_LOOPBACK = { s6_addr8: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] }; //alias IN6ADDR_ANY_INIT = IN6ADDR_ANY; //alias IN6ADDR_LOOPBACK_INIT = IN6ADDR_LOOPBACK; diff --git a/druntime/src/core/sys/windows/winver.d b/druntime/src/core/sys/windows/winver.d index 5ef0864c4405..e1b1618d3a32 100644 --- a/druntime/src/core/sys/windows/winver.d +++ b/druntime/src/core/sys/windows/winver.d @@ -256,7 +256,7 @@ VERSIONHELPERAPI IsWindows10OrGreater() VERSIONHELPERAPI IsWindowsServer() { - OSVERSIONINFOEXW osvi = { OSVERSIONINFOEXW.sizeof, 0, 0, 0, 0, [0], 0, 0, 0, VER_NT_WORKSTATION }; + OSVERSIONINFOEXW osvi = { OSVERSIONINFOEXW.sizeof, 0, 0, 0, 0, 0, 0, 0, 0, VER_NT_WORKSTATION }; const DWORDLONG dwlConditionMask = VerSetConditionMask( 0, VER_PRODUCT_TYPE, VER_EQUAL ); return !VerifyVersionInfoW(&osvi, VER_PRODUCT_TYPE, dwlConditionMask); diff --git a/spec/arrays.dd b/spec/arrays.dd index 8dc3a27e1a41..34b168e6acf2 100644 --- a/spec/arrays.dd +++ b/spec/arrays.dd @@ -1140,11 +1140,11 @@ $(H3 $(LNAME2 array-initializers, Array Initializers)) $(GRAMMAR $(GNAME ArrayInitializer): - $(D [) $(I ArrayElementInitializers)$(OPT) $(D ]) + `[` *ArrayElementInitializers* `,`$(OPT) `]` + `[` *ArrayElementInitializers* `, ... ]` $(GNAME ArrayElementInitializers): $(I ArrayElementInitializer) - $(I ArrayElementInitializer) $(D ,) $(I ArrayElementInitializer) $(D ,) $(GSELF ArrayElementInitializers) $(GNAME ArrayElementInitializer): @@ -1153,7 +1153,12 @@ $(GNAME ArrayElementInitializer): ) $(P An *ArrayInitializer* is a list of element initializers enclosed in `[ ]`. - Each element initializer can be optionally preceded by an index expression and a `:`. + The $(GRAMMAR_INLINE *ArrayElementInitializers* `, ...`) form + $(RELATIVE_LINK2 static-init-static, can only be used) when the declaration + is a static array.) + + $(P Each element initializer can be optionally preceded by an index + expression and a `:`. If an index is not supplied, it is set to the previous index plus 1, or 0 if it is the first value. Any missing elements will be initialized to the default value @@ -1207,6 +1212,26 @@ assert(value == [5, 6, 2]); $(H3 $(LNAME2 static-init-static, Static Initialization of Statically Allocated Arrays)) + $(P When a static array type is expected, an *ArrayInitializer* must either:) + + - Match the expected number of elements in the type + - Have at least one element index provided + - Use the trailing `...` syntax + + $(P The `...` syntax is used to specify 0 or more missing elements. Any + missing elements will be initialized to the default value of the element type:) + +$(SPEC_RUNNABLE_EXAMPLE_RUN +--------- +int[4] a = [1, 2, 3, 4]; // OK + +//int[4] b = [1, 2]; // Error, missing elements +int[4] b = [1, 2, ...]; // OK + +void main() => assert(b == [1, 2, 0, 0]); +--------- +) + $(P All elements of a static array can be initialized to a specific value which implicitly converts to the array element type:)