diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 394bb2d9f42..3b9743e2927 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -14769,11 +14769,16 @@ private bool checkArithmetic(Expression e, EXP op) return true; } - // FIXME: Existing code relies on adding / subtracting types in typeof() expressions: - // alias I = ulong; alias U = typeof(I + 1u); - // https://github.com/dlang/dmd/issues/20763 - if (op == EXP.add || op == EXP.min) + if ((op == EXP.add || op == EXP.min) && e.isTypeExp()) + { + // @@@DEPRECATED_2.121@@@ + // 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 e.checkValue(); } @@ -14844,6 +14849,8 @@ bool checkValue(Expression e) if (auto te = e.isTypeExp()) { 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; } diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index 073f0906494..6d21d67befc 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -7609,6 +7609,18 @@ bool checkRetType(TypeFunction tf, const ref Loc loc) 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 *****************************************/ diff --git a/compiler/test/fail_compilation/b17285.d b/compiler/test/fail_compilation/b17285.d index 7b79cf0666f..9bf5d96cb24 100644 --- a/compiler/test/fail_compilation/b17285.d +++ b/compiler/test/fail_compilation/b17285.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/b17285.d(14): Error: type `ONE` has no value -fail_compilation/b17285.d(14): Error: type `TWO` has no value -fail_compilation/b17285.d(14): Error: cannot implicitly convert expression `ONE` of type `b17285.ONE` to `int` +fail_compilation/b17285.d(15): Error: type `ONE` has no value +fail_compilation/b17285.d(15): perhaps use `ONE.init` +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` --- */ diff --git a/compiler/test/fail_compilation/ice9545.d b/compiler/test/fail_compilation/ice9545.d index 7360bc534f2..b10e63987cf 100644 --- a/compiler/test/fail_compilation/ice9545.d +++ b/compiler/test/fail_compilation/ice9545.d @@ -2,7 +2,8 @@ /* 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` ---- */ diff --git a/compiler/test/fail_compilation/test20763.d b/compiler/test/fail_compilation/test20763.d new file mode 100644 index 00000000000..786f8d895ab --- /dev/null +++ b/compiler/test/fail_compilation/test20763.d @@ -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); +}