Skip to content

Commit

Permalink
Deprecate typesafe variadic class arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
dkorpel committed Jan 16, 2025
1 parent 3daeb3a commit f622eb9
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 50 deletions.
40 changes: 40 additions & 0 deletions changelog/dmd.deprecation-typesafe-variadic-class.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Typesafe variadic class parameters have been deprecated

This obscure feature allowed a limited form of implicit construction:

---
void check(bool x, Exception e...)
{
if (!x)
throw e;
}

void main(string[] args)
{
check(args.length > 1, "missing argument");
}
---

However, few uses of this feature have been found, and one project was actually mistakenly using it instead of the more common Typesafe variadic array parameter.
Considering D doesn't support implicit construction and already has a confusing amount of different variadic parameter forms, it was decided to remove this feature.

As a corrective action, either call the constructor in the callee:

---
void check(string msg)
{
if (!x)
throw new Exception(msg);
}
---

Or let the caller construct the class instance:

---
void check(bool x, Exception e);

void main(string[] args)
{
check(args.length > 1, new Exception("missing argument"));
}
---
18 changes: 13 additions & 5 deletions compiler/src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -2493,10 +2493,18 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
errors = true;
}

const bool isTypesafeVariadic = i + 1 == dim &&
tf.parameterList.varargs == VarArg.typesafe &&
(t.isTypeDArray() || t.isTypeClass());
if (isTypesafeVariadic)
const bool isTypesafeVariadic = i + 1 == dim && tf.parameterList.varargs == VarArg.typesafe;
const bool isStackAllocatedVariadic = isTypesafeVariadic && (t.isTypeDArray() || t.isTypeClass());

if (isTypesafeVariadic && t.isTypeClass())
{
// @@@DEPRECATED_2.121@@@
// Deprecated in 2.111, make it an error in 2.121
.deprecation(loc, "typesafe variadic parameters with a `class` type (`%s %s...`) are deprecated",

Check warning on line 2503 in compiler/src/dmd/typesem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/typesem.d#L2503

Added line #L2503 was not covered by tests
t.isTypeClass().sym.ident.toChars(), fparam.toChars());
}

if (isStackAllocatedVariadic)
{
/* typesafe variadic arguments are constructed on the stack, so must be `scope`
*/
Expand All @@ -2518,7 +2526,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
}

if (isTypesafeVariadic)
if (isStackAllocatedVariadic)
{
/* This is because they can be constructed on the stack
* https://dlang.org/spec/function.html#typesafe_variadic_functions
Expand Down
11 changes: 0 additions & 11 deletions compiler/test/fail_compilation/test22023.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* TEST_OUTPUT:
---
fail_compilation/test22023.d(102): Error: typesafe variadic function parameter `a` of type `int[]` cannot be marked `return`
fail_compilation/test22023.d(107): Error: typesafe variadic function parameter `c` of type `test22023.C` cannot be marked `return`
---
*/

Expand All @@ -14,13 +13,3 @@ ref int f(return int[] a ...)
{
return a[2];
}

ref int g(return C c ...)
{
return c.x;
}

class C
{
int x;
}
1 change: 1 addition & 0 deletions compiler/test/fail_compilation/test22818.d
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* REQUIRED_ARGS: -preview=dip1000
* TEST_OUTPUT:
---
fail_compilation/test22818.d(102): Deprecation: typesafe variadic parameters with a `class` type (`C c...`) are deprecated
fail_compilation/test22818.d(104): Error: scope parameter `c` may not be returned
---
*/
Expand Down
34 changes: 0 additions & 34 deletions compiler/test/runnable/testv.d
Original file line number Diff line number Diff line change
Expand Up @@ -83,39 +83,6 @@ void test3()
printf("%d\n", i);
}

/*********************************************************/

class Foo4
{
int a;
float f;
double d;

this(int a, float f, double d)
{
this.a = a;
this.f = f;
this.d = d;
}
}

int sum4(Foo4 f ...)
{
return cast(int)(f.a + f.f + f.d);
}

void test4()
{
int i;
Foo4 foo = new Foo4(1, 2f, 3.0);

i = sum4(foo);
assert(i == 1+2+3);
i = sum4(4, 5f, 6.0);
assert(i == 4+5+6);

printf("%d\n", i);
}

/*********************************************************/

Expand All @@ -139,7 +106,6 @@ int main()
test1();
test2();
test3();
test4();
test5();

printf("Success\n");
Expand Down

0 comments on commit f622eb9

Please sign in to comment.