Fix #20763 - Inconsistent handling of type + value in typeof expressions (#20798)

* Fix #20763 - Inconsistent handling of type + value in typeof expressions

* Add supplemental error

---------

Co-authored-by: Dennis Korpel <dennis@sarc.nl>
This commit is contained in:
Dennis 2025-01-29 11:26:01 +01:00 committed by GitHub
parent 3b863b9c28
commit 28bc5c6e74
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 60 additions and 8 deletions

View file

@ -14769,11 +14769,16 @@ private bool checkArithmetic(Expression e, EXP op)
return true; return true;
} }
// FIXME: Existing code relies on adding / subtracting types in typeof() expressions: if ((op == EXP.add || op == EXP.min) && e.isTypeExp())
// alias I = ulong; alias U = typeof(I + 1u); {
// https://github.com/dlang/dmd/issues/20763 // @@@DEPRECATED_2.121@@@
if (op == EXP.add || op == EXP.min) // Deprecated in 2.111
// In 2.121, remove this branch to let `checkValue` raise the error
deprecation(e.loc, "type `%s` has no value", e.toChars);
if (!e.type.isOpaqueType)
deprecationSupplemental(e.loc, "perhaps use `%s.init`", e.toChars);
return false; return false;
}
return e.checkValue(); return e.checkValue();
} }
@ -14844,6 +14849,8 @@ bool checkValue(Expression e)
if (auto te = e.isTypeExp()) if (auto te = e.isTypeExp())
{ {
error(e.loc, "type `%s` has no value", e.toChars()); error(e.loc, "type `%s` has no value", e.toChars());
if (!e.type.isOpaqueType)
errorSupplemental(e.loc, "perhaps use `%s.init`", e.toChars());
return true; return true;
} }

View file

@ -7609,6 +7609,18 @@ bool checkRetType(TypeFunction tf, const ref Loc loc)
return false; return false;
} }
/// Returns: whether `t` is a struct/class/enum without a body
bool isOpaqueType(Type t)
{
if (auto te = t.isTypeEnum())
return te.sym.members is null;
if (auto ts = t.isTypeStruct())
return ts.sym.members is null;
if (auto tc = t.isTypeClass())
return tc.sym.members is null;
return false;
}
/******************************* Private *****************************************/ /******************************* Private *****************************************/

View file

@ -1,9 +1,10 @@
/* /*
TEST_OUTPUT: TEST_OUTPUT:
--- ---
fail_compilation/b17285.d(14): Error: type `ONE` has no value fail_compilation/b17285.d(15): Error: type `ONE` has no value
fail_compilation/b17285.d(14): Error: type `TWO` has no value fail_compilation/b17285.d(15): perhaps use `ONE.init`
fail_compilation/b17285.d(14): Error: cannot implicitly convert expression `ONE` of type `b17285.ONE` to `int` fail_compilation/b17285.d(15): Error: type `TWO` has no value
fail_compilation/b17285.d(15): Error: cannot implicitly convert expression `ONE` of type `b17285.ONE` to `int`
--- ---
*/ */

View file

@ -2,7 +2,8 @@
/* /*
TEST_OUTPUT: TEST_OUTPUT:
---- ----
fail_compilation/ice9545.d(13): Error: type `int` has no value fail_compilation/ice9545.d(14): Error: type `int` has no value
fail_compilation/ice9545.d(14): perhaps use `int.init`
---- ----
*/ */

View file

@ -0,0 +1,31 @@
/*
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
fail_compilation/test20763.d(25): Deprecation: type `ulong` has no value
fail_compilation/test20763.d(25): perhaps use `ulong.init`
fail_compilation/test20763.d(26): Deprecation: type `ulong` has no value
fail_compilation/test20763.d(26): perhaps use `ulong.init`
fail_compilation/test20763.d(27): Error: type `ulong` has no value
fail_compilation/test20763.d(27): perhaps use `ulong.init`
fail_compilation/test20763.d(28): Error: type `ulong` has no value
fail_compilation/test20763.d(28): perhaps use `ulong.init`
fail_compilation/test20763.d(29): Error: type `ulong` has no value
fail_compilation/test20763.d(29): perhaps use `ulong.init`
fail_compilation/test20763.d(30): Error: type `ulong` has no value
fail_compilation/test20763.d(30): perhaps use `ulong.init`
---
*/
// https://github.com/dlang/dmd/issues/20763
void test()
{
alias I = ulong;
alias U0 = typeof(I + 1u);
alias U1 = typeof(1 - I);
alias U2 = typeof(+I);
alias U3 = typeof(I * 1);
alias U4 = typeof(I << 1);
alias U5 = typeof(I | 1);
}