From 636e61ea4dff36d9eb03b8e49a23b049b76a7d87 Mon Sep 17 00:00:00 2001 From: Razvan Nitu Date: Fri, 20 Jan 2023 16:11:37 +0800 Subject: [PATCH] Deprecate traits(isVirtualFunction) and traits(getVirtualFunctions) (#14802) --- changelog/dmd.get-is-virtual-function.dd | 11 +++++ compiler/src/dmd/traits.d | 11 +++++ compiler/test/compilable/ice13920.d | 5 -- .../deprecate_getVirtualFunctions.d | 20 ++++++++ compiler/test/fail_compilation/fail19076.d | 2 +- compiler/test/fail_compilation/test17096.d | 47 ++++++++++--------- compiler/test/runnable/e7804.d | 2 - compiler/test/runnable/traits.d | 38 --------------- druntime/src/core/internal/traits.d | 2 +- druntime/src/object.d | 4 +- 10 files changed, 70 insertions(+), 72 deletions(-) create mode 100644 changelog/dmd.get-is-virtual-function.dd create mode 100644 compiler/test/fail_compilation/deprecate_getVirtualFunctions.d diff --git a/changelog/dmd.get-is-virtual-function.dd b/changelog/dmd.get-is-virtual-function.dd new file mode 100644 index 0000000000..73ca37a77f --- /dev/null +++ b/changelog/dmd.get-is-virtual-function.dd @@ -0,0 +1,11 @@ +Deprecate `traits(isVirtualFunction)` and `traits(getVirtualFunctions)` + +Up until this release, D had both `traits(isVirtualFunction)` and `traits(isVirtualMethod)` +(and their coressponding `traits(get...)` counterpart). The differenrcte between the two is +that `isVirtualFunction` returns true for `final` methods that do not override anything. This +is in contradiction with the D spec which states that `final` functions that do not override +other functions cannot be virtual. `isVirtualMethod` correctly returns `false` in that case. + +Starting with this release, both `traits(isVirtualFunction)` and `traits(getVirtualFunctions)` +are deprecated. If the behavior of `traits(isVirtualFunction)` is desired, it can be achieved by +`traits(isVirtualMethod, f) || (traits(isFinalFunction, f) && !traits(isOverrideFunction, f))`. diff --git a/compiler/src/dmd/traits.d b/compiler/src/dmd/traits.d index a64b57b5a2..f991c0b567 100644 --- a/compiler/src/dmd/traits.d +++ b/compiler/src/dmd/traits.d @@ -634,6 +634,10 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } if (e.ident == Id.isVirtualFunction) { + // @@@DEPRECATED2.121@@@ + // Deprecated in 2.101 - Can be removed from 2.121 + e.deprecation("`traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead"); + if (dim != 1) return dimError(1); @@ -995,6 +999,13 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (errors < global.errors) e.error("`%s` cannot be resolved", eorig.toChars()); + if (e.ident == Id.getVirtualFunctions) + { + // @@@DEPRECATED2.121@@@ + // Deprecated in 2.101 - Can be removed from 2.121 + e.deprecation("`traits(getVirtualFunctions)` is deprecated. Use `traits(getVirtualMethods)` instead"); + } + /* Create tuple of functions of ex */ auto exps = new Expressions(); diff --git a/compiler/test/compilable/ice13920.d b/compiler/test/compilable/ice13920.d index 466b2e0449..a4540d1eac 100644 --- a/compiler/test/compilable/ice13920.d +++ b/compiler/test/compilable/ice13920.d @@ -14,11 +14,6 @@ class Foo { auto dg = &f; } - - foreach (f; __traits(getVirtualFunctions, typeof(this), "bar")) - { - auto dg = &f; - } } uint bar() { return 0; } diff --git a/compiler/test/fail_compilation/deprecate_getVirtualFunctions.d b/compiler/test/fail_compilation/deprecate_getVirtualFunctions.d new file mode 100644 index 0000000000..137482f98a --- /dev/null +++ b/compiler/test/fail_compilation/deprecate_getVirtualFunctions.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecate_getVirtualFunctions.d(18): Deprecation: `traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead +fail_compilation/deprecate_getVirtualFunctions.d(19): Deprecation: `traits(getVirtualFunctions)` is deprecated. Use `traits(getVirtualMethods)` instead +--- +*/ + +class A +{ + void fun() {} +} + +void main() +{ + auto a = __traits(isVirtualFunction, A.fun); + foreach(f; __traits(getVirtualFunctions, A, "fun")) {} +} diff --git a/compiler/test/fail_compilation/fail19076.d b/compiler/test/fail_compilation/fail19076.d index 9bfc0a564e..2441d6f3ca 100644 --- a/compiler/test/fail_compilation/fail19076.d +++ b/compiler/test/fail_compilation/fail19076.d @@ -8,4 +8,4 @@ fail_compilation/fail19076.d(11): Error: `(I).V` cannot be resolved interface P { } interface I : P { } -auto F = __traits(getVirtualFunctions, I, "V"); +auto F = __traits(getVirtualMethods, I, "V"); diff --git a/compiler/test/fail_compilation/test17096.d b/compiler/test/fail_compilation/test17096.d index e421419ae2..2c431a3849 100644 --- a/compiler/test/fail_compilation/test17096.d +++ b/compiler/test/fail_compilation/test17096.d @@ -1,28 +1,29 @@ /* TEST_OUTPUT: --- -fail_compilation/test17096.d(28): Error: expected 1 arguments for `isPOD` but had 2 -fail_compilation/test17096.d(29): Error: expected 1 arguments for `isNested` but had 2 -fail_compilation/test17096.d(30): Error: expected 1 arguments for `isVirtualFunction` but had 2 -fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualMethod` but had 2 -fail_compilation/test17096.d(32): Error: expected 1 arguments for `isAbstractFunction` but had 2 -fail_compilation/test17096.d(33): Error: expected 1 arguments for `isFinalFunction` but had 2 -fail_compilation/test17096.d(34): Error: expected 1 arguments for `isOverrideFunction` but had 2 -fail_compilation/test17096.d(35): Error: expected 1 arguments for `isStaticFunction` but had 2 -fail_compilation/test17096.d(36): Error: expected 1 arguments for `isRef` but had 2 -fail_compilation/test17096.d(37): Error: expected 1 arguments for `isOut` but had 2 -fail_compilation/test17096.d(38): Error: expected 1 arguments for `isLazy` but had 2 -fail_compilation/test17096.d(39): Error: expected 1 arguments for `identifier` but had 2 -fail_compilation/test17096.d(40): Error: expected 1 arguments for `getProtection` but had 2 -fail_compilation/test17096.d(41): Error: expected 1 arguments for `parent` but had 2 -fail_compilation/test17096.d(42): Error: expected 1 arguments for `classInstanceSize` but had 2 -fail_compilation/test17096.d(43): Error: expected 1 arguments for `allMembers` but had 2 -fail_compilation/test17096.d(44): Error: expected 1 arguments for `derivedMembers` but had 2 -fail_compilation/test17096.d(45): Error: expected 1 arguments for `getAliasThis` but had 2 -fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAttributes` but had 2 -fail_compilation/test17096.d(47): Error: expected 1 arguments for `getFunctionAttributes` but had 2 -fail_compilation/test17096.d(48): Error: expected 1 arguments for `getUnitTests` but had 2 -fail_compilation/test17096.d(49): Error: expected 1 arguments for `getVirtualIndex` but had 2 -fail_compilation/test17096.d(50): Error: a single type expected for trait pointerBitmap +fail_compilation/test17096.d(29): Error: expected 1 arguments for `isPOD` but had 2 +fail_compilation/test17096.d(30): Error: expected 1 arguments for `isNested` but had 2 +fail_compilation/test17096.d(31): Deprecation: `traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead +fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualFunction` but had 2 +fail_compilation/test17096.d(32): Error: expected 1 arguments for `isVirtualMethod` but had 2 +fail_compilation/test17096.d(33): Error: expected 1 arguments for `isAbstractFunction` but had 2 +fail_compilation/test17096.d(34): Error: expected 1 arguments for `isFinalFunction` but had 2 +fail_compilation/test17096.d(35): Error: expected 1 arguments for `isOverrideFunction` but had 2 +fail_compilation/test17096.d(36): Error: expected 1 arguments for `isStaticFunction` but had 2 +fail_compilation/test17096.d(37): Error: expected 1 arguments for `isRef` but had 2 +fail_compilation/test17096.d(38): Error: expected 1 arguments for `isOut` but had 2 +fail_compilation/test17096.d(39): Error: expected 1 arguments for `isLazy` but had 2 +fail_compilation/test17096.d(40): Error: expected 1 arguments for `identifier` but had 2 +fail_compilation/test17096.d(41): Error: expected 1 arguments for `getProtection` but had 2 +fail_compilation/test17096.d(42): Error: expected 1 arguments for `parent` but had 2 +fail_compilation/test17096.d(43): Error: expected 1 arguments for `classInstanceSize` but had 2 +fail_compilation/test17096.d(44): Error: expected 1 arguments for `allMembers` but had 2 +fail_compilation/test17096.d(45): Error: expected 1 arguments for `derivedMembers` but had 2 +fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAliasThis` but had 2 +fail_compilation/test17096.d(47): Error: expected 1 arguments for `getAttributes` but had 2 +fail_compilation/test17096.d(48): Error: expected 1 arguments for `getFunctionAttributes` but had 2 +fail_compilation/test17096.d(49): Error: expected 1 arguments for `getUnitTests` but had 2 +fail_compilation/test17096.d(50): Error: expected 1 arguments for `getVirtualIndex` but had 2 +fail_compilation/test17096.d(51): Error: a single type expected for trait pointerBitmap --- */ enum b03 = __traits(isPOD, 1, 2); diff --git a/compiler/test/runnable/e7804.d b/compiler/test/runnable/e7804.d index d32531055f..ff66310ff2 100644 --- a/compiler/test/runnable/e7804.d +++ b/compiler/test/runnable/e7804.d @@ -63,8 +63,6 @@ TmpPrm!(__traits(getMember, Foo, "MyInt")) tpt = TmpPrm!(__traits(getMember, Foo int virtual(int p){return p;} void test(this T)() { - alias vf = __traits(getVirtualFunctions, Class, "virtual"); - assert(vf.length == 2); alias vm = __traits(getVirtualMethods, Class, "virtual"); assert(vm.length == 1); assert(vm[0](42) == 42); diff --git a/compiler/test/runnable/traits.d b/compiler/test/runnable/traits.d index ddd505919d..5186987dea 100644 --- a/compiler/test/runnable/traits.d +++ b/compiler/test/runnable/traits.d @@ -312,14 +312,6 @@ void test9() /********************************************************/ -void test10() -{ - assert(__traits(isVirtualFunction, C.bar) == true); - assert(__traits(isVirtualFunction, S.bar) == false); -} - -/********************************************************/ - void test11() { assert(__traits(isAbstractFunction, C.bar) == false); @@ -403,24 +395,6 @@ class D15 int foo(int) { return 2; } } -void test15() -{ - D15 d = new D15(); - - assert(__traits(getVirtualFunctions, D15, "foo").length == 2); - assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[0])).toString() - == "void function()"); - assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[1])).toString() - == "int function(int)"); - - alias typeof(__traits(getVirtualFunctions, D15, "foo")) b; - assert(typeid(b[0]).toString() == "void function()"); - assert(typeid(b[1]).toString() == "int function(int)"); - - auto i = __traits(getVirtualFunctions, d, "foo")[1](1); - assert(i == 2); -} - /********************************************************/ struct S16 { } @@ -714,14 +688,6 @@ interface AA int YYY(); } -class CC : AA -{ - final int YYY() { return 4; } -} - -static assert(__traits(isVirtualMethod, CC.YYY)); -static assert(__traits(getVirtualMethods, CC, "YYY").length == 1); - class DD { final int YYY() { return 4; } @@ -790,8 +756,6 @@ void test7858() static assert(__traits(isFinalFunction, C.ffunc) == __traits(isFinalFunction, __traits(getOverloads, C, "ffunc")[0])); // NG - static assert(__traits(isVirtualFunction, C.vfunc) == - __traits(isVirtualFunction, __traits(getOverloads, C, "vfunc")[0])); // NG static assert(__traits(isVirtualMethod, C.vfunc) == __traits(isVirtualMethod, __traits(getOverloads, C, "vfunc")[0])); // NG static assert(__traits(isAbstractFunction, C.afunc) == @@ -1456,13 +1420,11 @@ int main() test7(); test8(); test9(); - test10(); test11(); test12(); test13(); test7123(); test14(); - test15(); test16(); test17(); test18(); diff --git a/druntime/src/core/internal/traits.d b/druntime/src/core/internal/traits.d index 0b4890cbfa..966839f176 100644 --- a/druntime/src/core/internal/traits.d +++ b/druntime/src/core/internal/traits.d @@ -654,7 +654,7 @@ if (func.length == 1 /*&& isCallable!func*/) int test(int); int test() @property; } - alias ov = __traits(getVirtualFunctions, Overloads, "test"); + alias ov = __traits(getVirtualMethods, Overloads, "test"); alias F_ov0 = FunctionTypeOf!(ov[0]); alias F_ov1 = FunctionTypeOf!(ov[1]); alias F_ov2 = FunctionTypeOf!(ov[2]); diff --git a/druntime/src/object.d b/druntime/src/object.d index 0385b51d60..d98e698aa6 100644 --- a/druntime/src/object.d +++ b/druntime/src/object.d @@ -1417,7 +1417,7 @@ class TypeInfo_Function : TypeInfo int func(int a, int b); } - alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func")); + alias functionTypes = typeof(__traits(getVirtualMethods, C, "func")); assert(typeid(functionTypes[0]).toString() == "void function()"); assert(typeid(functionTypes[1]).toString() == "void function(int)"); assert(typeid(functionTypes[2]).toString() == "int function(int, int)"); @@ -1431,7 +1431,7 @@ class TypeInfo_Function : TypeInfo void func(int a); } - alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func")); + alias functionTypes = typeof(__traits(getVirtualMethods, C, "func")); Object obj = typeid(functionTypes[0]); assert(obj.opEquals(typeid(functionTypes[0])));