Deprecate alias this for classes v2 (#14812)

This commit is contained in:
Razvan Nitu 2023-02-15 19:28:28 +08:00 committed by GitHub
parent 1d19f710b2
commit af7817b4ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 89 additions and 324 deletions

View file

@ -0,0 +1,8 @@
Alias this for classes is deprecated
Using `alias this` for classes has not been clearly specified and the lookup rules in such circumstances are not defined. As a consequence, various failures or crashes may appear when `alias this` is used in conjunction with classes. Starting with this release, `alias this` for classes is being deprecated. As an alternative, getter/setter methods may be used to replace the `alias this`. This can be generically handled by:
```d
static foreach(member, __traits(allMembers, LeClass))
mixin("ref auto " ~ member() { return $field_name." ~ member ~ "; }");
```

View file

@ -317,6 +317,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
return; return;
} }
// @@@DEPRECATED_2.121@@@
// Deprecated in 2.101 - Can be removed in 2.121
if (ad.isClassDeclaration() || ad.isInterfaceDeclaration())
deprecation(dsym.loc, "alias this for classes/interfaces is deprecated");
assert(ad.members); assert(ad.members);
Dsymbol s = ad.search(dsym.loc, dsym.ident); Dsymbol s = ad.search(dsym.loc, dsym.ident);
if (!s) if (!s)

View file

@ -291,7 +291,21 @@ public:
/// Informations about the current context in the AST /// Informations about the current context in the AST
Context context; Context context;
alias context this;
// Generates getter-setter methods to replace the use of alias this
// This should be replaced by a `static foreach` once the gdc tester
// gets upgraded to version 10 (to support `static foreach`).
private extern(D) static string generateMembers()
{
string result = "";
foreach(member; __traits(allMembers, Context))
{
result ~= "ref auto " ~ member ~ "() { return context." ~ member ~ "; }\n";
}
return result;
}
mixin(generateMembers());
this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) scope this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) scope
{ {

View file

@ -1,16 +0,0 @@
// https://issues.dlang.org/show_bug.cgi?id=21073
class C
{
auto internal() const
{
return 5;
}
alias internal this;
}
void main() pure
{
const c = new C;
auto r = cast(C)c;
}

View file

@ -1,116 +0,0 @@
// https://issues.dlang.org/show_bug.cgi?id=21543
class B
{
Nullable!B data;
alias data this;
}
void test1()
{
B b;
Nullable!B n;
}
struct Nullable(T)
{
T payload;
void opAssign()(T)
{
move(payload);
}
inout(T) get_() inout
{
return payload;
}
alias get_ this;
}
// another version with chain of 3 alias this
struct C
{
Nullable2 data;
alias data this;
}
void test2()
{
C c;
Nullable2 n2 = &c;
Nullable3 n3 = &c;
// these are to check a sane -vcg-ast output
fn1(c);
fn1(n2);
fn1(n3);
fn2(c);
fn2(n2);
fn2(n3);
fn3(c);
fn3(n2);
fn3(n3);
}
void fn1(C x) {}
void fn2(Nullable2 x) {}
void fn3(Nullable3 x) {}
struct Nullable2
{
Nullable3 payload;
this(C* c)
{
payload = Nullable3(c);
}
void opAssign()(Nullable3)
{
move(payload);
}
inout(Nullable3) get_() inout
{
return payload;
}
alias get_ this;
}
struct Nullable3
{
C* payload;
this(C* c)
{
payload = c;
}
void opAssign()(C)
{
move(payload);
}
inout(C) get_() inout
{
return *payload;
}
alias get_ this;
}
T move(T)(ref T source)
{
return source;
}
T move(T)(T source)
{
return source;
}

View file

@ -1,41 +0,0 @@
// https://issues.dlang.org/show_bug.cgi?id=5973
class A { int a = 1; }
class B { int b = 2; }
class C : A
{
B obj;
alias obj this;
this(){ obj = new B(); }
}
class X : C {}
class D
{
int i;
}
class E
{
D x;
alias x this;
}
class F : E
{
void test()
{
i = 5;
}
}
void main()
{
auto c = new C();
assert(c.a == 1); // lookup C -> A, OK
assert(c.b == 2); // lookup C => B, OK
auto x = new X();
assert(x.a == 1); // lookup X -> C -> A, OK
assert(x.b == 2); // lookup X -> C => B, NG (Line 17)
}

View file

@ -1,11 +0,0 @@
struct S {}
class C {
S s;
alias s this;
}
void main() {
auto c = new C;
auto p = cast(void*) c;
}

View file

@ -1,16 +0,0 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail5851.d(11): Error: alias this is not reachable as `Foo` already converts to `object.Object`
---
*/
class Foo
{
Object o;
alias o this;
}
void main()
{
}

View file

@ -1,7 +1,16 @@
/* /*
TEST_OUTPUT: TEST_OUTPUT:
--- ---
runnable/aliasthis.d(103): Deprecation: alias this for classes/interfaces is deprecated
runnable/aliasthis.d(291): Deprecation: alias this for classes/interfaces is deprecated
runnable/aliasthis.d(292): Deprecation: alias this for classes/interfaces is deprecated
runnable/aliasthis.d(294): Deprecation: alias this for classes/interfaces is deprecated
runnable/aliasthis.d(465): Deprecation: alias this for classes/interfaces is deprecated
runnable/aliasthis.d(466): Deprecation: alias this for classes/interfaces is deprecated
runnable/aliasthis.d(477): Deprecation: alias this for classes/interfaces is deprecated
runnable/aliasthis.d(1013): Deprecation: alias this for classes/interfaces is deprecated
false false
runnable/aliasthis.d(2100): Deprecation: alias this for classes/interfaces is deprecated
[] = int [] = int
[] = string [] = string
[0] = int [0] = int
@ -10,6 +19,7 @@ false
[] = int [] = int
[1] = string [1] = string
[0] = int [0] = int
runnable/aliasthis.d(741): Deprecation: alias this for classes/interfaces is deprecated
--- ---
RUN_OUTPUT: RUN_OUTPUT:

View file

@ -4,6 +4,7 @@ TEST_OUTPUT:
true true
g g
&Test109S(&Test109S(<recursion>)) &Test109S(&Test109S(<recursion>))
runnable/interpret.d(3742): Deprecation: alias this for classes/interfaces is deprecated
tfoo tfoo
tfoo tfoo
Crash! Crash!

View file

@ -1,3 +1,13 @@
/*
TEST_OUTPUT:
---
runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated
runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated
runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated
runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated
---
*/
struct StructField(T) struct StructField(T)
{ {
static T Field; static T Field;

View file

@ -1,4 +1,12 @@
// https://issues.dlang.org/show_bug.cgi?id=19782 // https://issues.dlang.org/show_bug.cgi?id=19782
/*
TEST_OUTPUT:
---
runnable/test19782.d(17): Deprecation: alias this for classes/interfaces is deprecated
---
*/
class Inner class Inner
{ {
int a; int a;

View file

@ -1,5 +1,12 @@
// https://issues.dlang.org/show_bug.cgi?id=21039 // https://issues.dlang.org/show_bug.cgi?id=21039
/*
TEST_OUTPUT:
---
runnable/test21039.d(14): Deprecation: alias this for classes/interfaces is deprecated
---
*/
class Inner {} class Inner {}
class Outer { class Outer {

View file

@ -1,5 +1,12 @@
// https://issues.dlang.org/show_bug.cgi?id=23234 // https://issues.dlang.org/show_bug.cgi?id=23234
/*
TEST_OUTPUT:
---
runnable/test23234.d(17): Deprecation: alias this for classes/interfaces is deprecated
---
*/
class Bar class Bar
{ {
} }

View file

@ -1,5 +1,13 @@
// https://issues.dlang.org/show_bug.cgi?id=11294 // https://issues.dlang.org/show_bug.cgi?id=11294
/*
TEST_OUTPUT:
---
runnable/testaliascast.d(29): Deprecation: alias this for classes/interfaces is deprecated
runnable/testaliascast.d(58): Deprecation: alias this for classes/interfaces is deprecated
---
*/
string result; string result;
extern(C) void rt_finalize(void *ptr, bool det=true); extern(C) void rt_finalize(void *ptr, bool det=true);

View file

@ -2,6 +2,8 @@
REQUIRED_ARGS: -preview=rvaluerefparam REQUIRED_ARGS: -preview=rvaluerefparam
TEST_OUTPUT: TEST_OUTPUT:
--- ---
runnable/testassign.d(802): Deprecation: alias this for classes/interfaces is deprecated
runnable/testassign.d(808): Deprecation: alias this for classes/interfaces is deprecated
\ S1 S2a S2b S3a S3b S4a S4b \ S1 S2a S2b S3a S3b S4a S4b
- true true true true true true true - true true true true true true true
Xa true true true true true true true Xa true true true true true true true

View file

@ -1,4 +1,3 @@
module traits_getPointerBitmap; module traits_getPointerBitmap;
import core.stdc.stdio; import core.stdc.stdio;
@ -76,19 +75,6 @@ template pOff(T)
enum pOff = T.p.offsetof / bytesPerPtr; enum pOff = T.p.offsetof / bytesPerPtr;
} }
class C(T, aliasTo = void)
{
static if(!is(aliasTo == void))
{
aliasTo a;
alias a this;
}
size_t x;
T t = void;
void* p;
}
/////////////////////////////////////// ///////////////////////////////////////
void _testType(T)(size_t[] expected) void _testType(T)(size_t[] expected)
@ -118,21 +104,6 @@ void testType(T)(size_t[] expected)
// prepend string // prepend string
sexp[0] = (expected[0] << tOff!(S!(T, string))) | (1 << pOff!(S!(T, string))) | 2; // arr ptr sexp[0] = (expected[0] << tOff!(S!(T, string))) | (1 << pOff!(S!(T, string))) | 2; // arr ptr
_testType!(S!(T, string))(sexp); _testType!(S!(T, string))(sexp);
// generate bit pattern for C!T
C!T ct = null;
size_t mutexBit = (RTInfoMark__Monitor ? 2 : 0);
size_t ctpOff = ct.p.offsetof / bytesPerPtr;
size_t cttOff = ct.t.offsetof / bytesPerPtr;
sexp[0] = (expected[0] << cttOff) | (1 << ctpOff) | mutexBit;
_testType!(C!(T))(sexp);
C!(T, string) cts = null;
size_t ctspOff = cts.p.offsetof / bytesPerPtr;
size_t ctstOff = cts.t.offsetof / bytesPerPtr;
// generate bit pattern for C!T
sexp[0] = (expected[0] << ctstOff) | (1 << ctspOff) | mutexBit | 0b1000; // arr ptr
_testType!(C!(T, string))(sexp);
} }
/////////////////////////////////////// ///////////////////////////////////////

View file

@ -2,11 +2,14 @@
// //
/* TEST_OUTPUT: /* TEST_OUTPUT:
--- ---
runnable/xtest46.d(165): Deprecation: alias this for classes/interfaces is deprecated
Boo!double Boo!double
Boo!int Boo!int
true true
int int
!! immutable(int)[] !! immutable(int)[]
runnable/xtest46.d(2932): Deprecation: alias this for classes/interfaces is deprecated
runnable/xtest46.d(2964): Deprecation: alias this for classes/interfaces is deprecated
int(int i, long j = 7L) int(int i, long j = 7L)
long long
C10390(C10390(C10390(<recursion>))) C10390(C10390(C10390(<recursion>)))
@ -19,6 +22,7 @@ string[]
double[] double[]
double[] double[]
{} {}
runnable/xtest46.d(4670): Deprecation: alias this for classes/interfaces is deprecated
tuple("m") tuple("m")
true true
TFunction1: extern (C) void function() TFunction1: extern (C) void function()

View file

@ -3,11 +3,14 @@ REQUIRED_ARGS: -lowmem -Jrunnable -preview=rvaluerefparam
EXTRA_FILES: xtest46.d EXTRA_FILES: xtest46.d
TEST_OUTPUT: TEST_OUTPUT:
--- ---
runnable/xtest46_gc.d-mixin-33(197): Deprecation: alias this for classes/interfaces is deprecated
Boo!double Boo!double
Boo!int Boo!int
true true
int int
!! immutable(int)[] !! immutable(int)[]
runnable/xtest46_gc.d-mixin-33(2964): Deprecation: alias this for classes/interfaces is deprecated
runnable/xtest46_gc.d-mixin-33(2996): Deprecation: alias this for classes/interfaces is deprecated
int(int i, long j = 7L) int(int i, long j = 7L)
long long
C10390(C10390(<recursion>)) C10390(C10390(<recursion>))
@ -20,6 +23,7 @@ string[]
double[] double[]
double[] double[]
{} {}
runnable/xtest46_gc.d-mixin-33(4702): Deprecation: alias this for classes/interfaces is deprecated
tuple("m") tuple("m")
true true
TFunction1: extern (C) void function() TFunction1: extern (C) void function()

View file

@ -2927,25 +2927,6 @@ void clear(Value, Key)(Value[Key]* aa)
assert("k1" !in aa); assert("k1" !in aa);
} }
// Issue 20559
@system unittest
{
static class Foo
{
int[string] aa;
alias aa this;
}
auto v = new Foo();
v["Hello World"] = 42;
v.clear;
assert("Hello World" !in v);
// Test for T*
static assert(!__traits(compiles, (&v).clear));
static assert( __traits(compiles, (*(&v)).clear));
}
/*********************************** /***********************************
* Reorganizes the associative array in place so that lookups are more * Reorganizes the associative array in place so that lookups are more
* efficient. * efficient.
@ -4278,44 +4259,6 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == interface))
destroy!true(new C()); destroy!true(new C());
} }
@system unittest
{
// class with an `alias this`
class A
{
static int dtorCount;
~this()
{
dtorCount++;
}
}
class B
{
A a;
alias a this;
this()
{
a = new A;
}
static int dtorCount;
~this()
{
dtorCount++;
}
}
auto b = new B;
assert(A.dtorCount == 0);
assert(B.dtorCount == 0);
destroy(b);
assert(A.dtorCount == 0);
assert(B.dtorCount == 1);
auto a = new A;
destroy(a);
assert(A.dtorCount == 1);
}
@system unittest @system unittest
{ {
interface I { } interface I { }
@ -4529,43 +4472,6 @@ if (__traits(isStaticArray, T))
} }
} }
// https://issues.dlang.org/show_bug.cgi?id=19218
@system unittest
{
static struct S
{
static dtorCount = 0;
~this() { ++dtorCount; }
}
static interface I
{
ref S[3] getArray();
alias getArray this;
}
static class C : I
{
static dtorCount = 0;
~this() { ++dtorCount; }
S[3] a;
alias a this;
ref S[3] getArray() { return a; }
}
C c = new C();
destroy(c);
assert(S.dtorCount == 3);
assert(C.dtorCount == 1);
I i = new C();
destroy(i);
assert(S.dtorCount == 6);
assert(C.dtorCount == 2);
}
/// ditto /// ditto
void destroy(bool initialize = true, T)(ref T obj) void destroy(bool initialize = true, T)(ref T obj)
if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T)) if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T))