mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
Deprecate alias this for classes v2 (#14812)
This commit is contained in:
parent
1d19f710b2
commit
af7817b4ae
20 changed files with 89 additions and 324 deletions
8
changelog/dmd.deprecate-alias-this-for-classes.dd
Normal file
8
changelog/dmd.deprecate-alias-this-for-classes.dd
Normal 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 ~ "; }");
|
||||
```
|
|
@ -317,6 +317,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
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);
|
||||
Dsymbol s = ad.search(dsym.loc, dsym.ident);
|
||||
if (!s)
|
||||
|
|
|
@ -291,7 +291,21 @@ public:
|
|||
|
||||
/// Informations about the current context in the AST
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
struct S {}
|
||||
|
||||
class C {
|
||||
S s;
|
||||
alias s this;
|
||||
}
|
||||
|
||||
void main() {
|
||||
auto c = new C;
|
||||
auto p = cast(void*) c;
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
}
|
|
@ -1,7 +1,16 @@
|
|||
/*
|
||||
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
|
||||
runnable/aliasthis.d(2100): Deprecation: alias this for classes/interfaces is deprecated
|
||||
[] = int
|
||||
[] = string
|
||||
[0] = int
|
||||
|
@ -10,6 +19,7 @@ false
|
|||
[] = int
|
||||
[1] = string
|
||||
[0] = int
|
||||
runnable/aliasthis.d(741): Deprecation: alias this for classes/interfaces is deprecated
|
||||
---
|
||||
|
||||
RUN_OUTPUT:
|
||||
|
|
|
@ -4,6 +4,7 @@ TEST_OUTPUT:
|
|||
true
|
||||
g
|
||||
&Test109S(&Test109S(<recursion>))
|
||||
runnable/interpret.d(3742): Deprecation: alias this for classes/interfaces is deprecated
|
||||
tfoo
|
||||
tfoo
|
||||
Crash!
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
static T Field;
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
// 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
|
||||
{
|
||||
int a;
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
// 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 Outer {
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
// 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
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
// 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;
|
||||
|
||||
extern(C) void rt_finalize(void *ptr, bool det=true);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
REQUIRED_ARGS: -preview=rvaluerefparam
|
||||
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
|
||||
- true true true true true true true
|
||||
Xa true true true true true true true
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
module traits_getPointerBitmap;
|
||||
|
||||
import core.stdc.stdio;
|
||||
|
@ -76,19 +75,6 @@ template pOff(T)
|
|||
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)
|
||||
|
@ -118,21 +104,6 @@ void testType(T)(size_t[] expected)
|
|||
// prepend string
|
||||
sexp[0] = (expected[0] << tOff!(S!(T, string))) | (1 << pOff!(S!(T, string))) | 2; // arr ptr
|
||||
_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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
//
|
||||
/* TEST_OUTPUT:
|
||||
---
|
||||
runnable/xtest46.d(165): Deprecation: alias this for classes/interfaces is deprecated
|
||||
Boo!double
|
||||
Boo!int
|
||||
true
|
||||
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)
|
||||
long
|
||||
C10390(C10390(C10390(<recursion>)))
|
||||
|
@ -19,6 +22,7 @@ string[]
|
|||
double[]
|
||||
double[]
|
||||
{}
|
||||
runnable/xtest46.d(4670): Deprecation: alias this for classes/interfaces is deprecated
|
||||
tuple("m")
|
||||
true
|
||||
TFunction1: extern (C) void function()
|
||||
|
|
|
@ -3,11 +3,14 @@ REQUIRED_ARGS: -lowmem -Jrunnable -preview=rvaluerefparam
|
|||
EXTRA_FILES: xtest46.d
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
runnable/xtest46_gc.d-mixin-33(197): Deprecation: alias this for classes/interfaces is deprecated
|
||||
Boo!double
|
||||
Boo!int
|
||||
true
|
||||
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)
|
||||
long
|
||||
C10390(C10390(<recursion>))
|
||||
|
@ -20,6 +23,7 @@ string[]
|
|||
double[]
|
||||
double[]
|
||||
{}
|
||||
runnable/xtest46_gc.d-mixin-33(4702): Deprecation: alias this for classes/interfaces is deprecated
|
||||
tuple("m")
|
||||
true
|
||||
TFunction1: extern (C) void function()
|
||||
|
|
|
@ -2927,25 +2927,6 @@ void clear(Value, Key)(Value[Key]* 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
|
||||
* efficient.
|
||||
|
@ -4278,44 +4259,6 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == interface))
|
|||
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
|
||||
{
|
||||
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
|
||||
void destroy(bool initialize = true, T)(ref T obj)
|
||||
if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue