Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make
in
a first-class storage class, not a const [scope]
alias
For a long time, the 'in' storage class was only a second class citizen, merely an alias for 'const', which is a type constructor. While it was also documented for a long time as being 'scope', this was removed when 'scope' actually started to have an effect (when DIP1000 started to be implemented). Currently, a switch (-preview=in) allows to get back this 'scope'. However, the 'in' storage class does not really exists, it gets lowered to 'const [scope]' at an early stage by the compiler, which means that we expose what is essentially an implementation detail to the user. This led to a variety of problems for both developers and users. The most obvious one was that functions involving `in` would show up simply as `const` (or `const scope`), both in generated header and error messagges, hindering the ability to do header generation with `-preview=in` as the same value for this switch was needed for both producer and consumer. Another issue was that the result of `__traits(getParameterStorageClass)` was inaccurate, giving either an empty tuple or `scope`. For compiler developers, the `in` storage class simply couldn't be relied on, as it was replaced by `const [scope]` rather early in the semantic phase (in TypeFunction's semantic), which lead to some dead code (e.g. in dmangle). After this change, the class will show up properly in error message, and in `getParameterStorageClass`, which can be a surprising change for users. However, it is not expected that code can break as a result, unless they break as a result of using the `-preview=in` switch.
- Loading branch information
Showing
10 changed files
with
140 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
PERMUTE_ARGS: -preview=in | ||
TEST_OUTPUT: | ||
--- | ||
fail_compilation/diagin.d(18): Error: function `diagin.foo(in string)` is not callable using argument types `()` | ||
fail_compilation/diagin.d(18): missing argument for parameter #1: `in string` | ||
fail_compilation/diagin.d(19): Error: function `diagin.foo1(in ref string)` is not callable using argument types `()` | ||
fail_compilation/diagin.d(19): missing argument for parameter #1: `in ref string` | ||
fail_compilation/diagin.d(20): Error: template `diagin.foo2` cannot deduce function from argument types `!()(int)`, candidates are: | ||
fail_compilation/diagin.d(27): `foo2(T)(in T v, string)` | ||
fail_compilation/diagin.d(22): Error: template `diagin.foo3` cannot deduce function from argument types `!()(bool[])`, candidates are: | ||
fail_compilation/diagin.d(28): `foo3(T)(in ref T v, string)` | ||
--- | ||
*/ | ||
|
||
void main () | ||
{ | ||
foo(); | ||
foo1(); | ||
foo2(42); | ||
bool[] lvalue; | ||
foo3(lvalue); | ||
} | ||
|
||
void foo(in string) {} | ||
void foo1(in ref string) {} | ||
void foo2(T)(in T v, string) {} | ||
void foo3(T)(ref in T v, string) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
REQUIRED_ARGS: -preview=in -preview=dip1000 | ||
TEST_OUTPUT: | ||
--- | ||
fail_compilation/previewin.d(3): Error: function `previewin.func1(void function(ulong[8]) dg)` is not callable using argument types `(void function(in ulong[8]))` | ||
fail_compilation/previewin.d(3): cannot pass argument `& func_byRef` of type `void function(in ulong[8])` to parameter `void function(ulong[8]) dg` | ||
fail_compilation/previewin.d(4): Error: function `previewin.func2(void function(ref ulong[8]) dg)` is not callable using argument types `(void function(in ulong[8]))` | ||
fail_compilation/previewin.d(4): cannot pass argument `& func_byRef` of type `void function(in ulong[8])` to parameter `void function(ref ulong[8]) dg` | ||
fail_compilation/previewin.d(5): Error: function `previewin.func3(void function(ref const(ulong[8])) dg)` is not callable using argument types `(void function(in ulong[8]))` | ||
fail_compilation/previewin.d(5): cannot pass argument `& func_byRef` of type `void function(in ulong[8])` to parameter `void function(ref const(ulong[8])) dg` | ||
fail_compilation/previewin.d(7): Error: function `previewin.func4(void function(ref ulong) dg)` is not callable using argument types `(void function(in ulong))` | ||
fail_compilation/previewin.d(7): cannot pass argument `& func_byValue` of type `void function(in ulong)` to parameter `void function(ref ulong) dg` | ||
fail_compilation/previewin.d(41): Error: scope variable `arg` assigned to non-scope `myGlobal` | ||
fail_compilation/previewin.d(42): Error: scope variable `arg` assigned to non-scope `myGlobal` | ||
fail_compilation/previewin.d(43): Error: scope variable `arg` may not be returned | ||
fail_compilation/previewin.d(44): Error: scope variable `arg` assigned to `escape` with longer lifetime | ||
fail_compilation/previewin.d(48): Error: returning `arg` escapes a reference to parameter `arg`, perhaps annotate with `return` | ||
--- | ||
*/ | ||
|
||
#line 1 | ||
void main () | ||
{ | ||
func1(&func_byRef); // No | ||
func2(&func_byRef); // No | ||
func3(&func_byRef); // Yes | ||
|
||
func4(&func_byValue); // No | ||
func5(&func_byValue); // Yes | ||
|
||
func6(&func_byValue2); // Yes | ||
func7(&func_byValue3); // Yes | ||
|
||
tryEscape("Hello World"); // Yes by `tryEscape` is NG | ||
} | ||
|
||
// Takes by `scope ref const` | ||
void func_byRef(in ulong[8]) {} | ||
// Takes by `scope const` | ||
void func_byValue(in size_t) {} | ||
|
||
// Error: `ulong[8]` is passed by `ref` | ||
void func1(void function(scope ulong[8]) dg) {} | ||
// Error: Missing `scope` on a `ref` | ||
void func2(void function(ref ulong[8]) dg) {} | ||
// Works: `scope ref` | ||
void func3(void function(scope const ref ulong[8]) dg) {} | ||
|
||
// Error: `size_t` is passed by value | ||
void func4(void function(ref size_t) dg) {} | ||
// Works: By value `scope const` | ||
void func5(void function(scope const size_t) dg) {} | ||
|
||
// This works for arrays: | ||
void func_byValue2(in char[]) {} | ||
void func6(void function(char[]) dg) {} | ||
void func_byValue3(scope const(char)[]) {} | ||
void func7(void function(in char[]) dg) {} | ||
|
||
// Make sure things cannot be escaped (`scope` is applied) | ||
const(char)[] myGlobal; | ||
void tryEscape(in char[] arg) @safe { myGlobal = arg; } | ||
void tryEscape2(scope const char[] arg) @safe { myGlobal = arg; } | ||
const(char)[] tryEscape3(in char[] arg) @safe { return arg; } | ||
void tryEscape4(in char[] arg, ref const(char)[] escape) @safe { escape = arg; } | ||
// Okay: value type | ||
ulong[8] tryEscape5(in ulong[8] arg) @safe { return arg; } | ||
// NG: Ref | ||
ref const(ulong[8]) tryEscape6(in ulong[8] arg) @safe { return arg; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters