dmd/compiler/test/runnable/class_destructors.d
Nick Treleaven 7d6ac55712
Fix Issue 12118 - Modify immutable data using throw (#14706)
* Fix Issue 12118 - Modify immutable data using throw

* Change immutable test to const

* Deprecate throwing any qualified type

* Allow throw shared as std.concurrency does that

* Use static this instead of static const for test

* Only allow single shared qualifier or none

* Add changelog

* Disallow throwing shared objects too

* Update changelog/dmd.throw-qualifier.dd

Co-authored-by: Razvan Nitu <razvan.nitu1305@gmail.com>

---------

Co-authored-by: Razvan Nitu <razvan.nitu1305@gmail.com>
2023-03-13 17:42:18 +02:00

194 lines
2.5 KiB
D

/**
https://issues.dlang.org/show_bug.cgi?id=21799
PERMUTE_ARGS:
**/
int main()
{
testDeleteD();
testDeleteDScope();
testDeleteWithoutD();
testDeleteCpp();
testDeleteCppScope();
testDeleteWithoutCpp();
testThrowingDtor();
return 0;
}
enum forceCtfe = main();
/*************************************************/
class ParentD
{
char[]* ptr;
~this()
{
*ptr ~= 'A';
}
}
class ChildD : ParentD
{
~this()
{
*ptr ~= 'B';
}
}
void testDeleteD()
{
char[] res;
ChildD cd = new ChildD();
cd.ptr = &res;
if (!__ctfe)
{
destroy(cd);
assert(res == "BA", cast(string) res);
}
}
void testDeleteDScope()
{
char[] res;
{
scope cd = new ChildD();
cd.ptr = &res;
}
assert(res == "BA", cast(string) res);
}
/*************************************************/
class ChildWithoutDtorD : ChildD {}
void testDeleteWithoutD()
{
char[] res;
ChildWithoutDtorD cd = new ChildWithoutDtorD();
cd.ptr = &res;
if (!__ctfe)
{
destroy(cd);
assert(res == "BA", cast(string) res);
}
}
/*************************************************/
extern (C++) class ParentCpp
{
char[]* ptr;
~this()
{
*ptr ~= 'C';
}
}
extern (C++) class ChildCpp : ParentCpp
{
~this()
{
*ptr ~= 'D';
}
}
void testDeleteCpp()
{
// Internal assertion failure
version (Windows)
return;
// Segfault at runtime
if (!__ctfe)
return;
char[] res;
ChildCpp cc = new ChildCpp();
cc.ptr = &res;
if (!__ctfe)
{
destroy(cc);
assert(res == "DC", cast(string) res);
}
}
void testDeleteCppScope()
{
// Unsupported pointer cast
version (Windows) if (__ctfe)
return;
char[] res;
{
scope cc = new ChildCpp();
cc.ptr = &res;
}
assert(res == "DC", cast(string) res);
}
/*************************************************/
class ChildWithoutDtorCpp : ChildCpp {}
void testDeleteWithoutCpp()
{
// delete segfaults at runtime
if (!__ctfe)
return;
char[] res;
ChildWithoutDtorCpp cd = new ChildWithoutDtorCpp();
cd.ptr = &res;
if (!__ctfe)
{
destroy(cd);
assert(res == "DC", cast(string) res);
}
}
/*************************************************/
class ThrowingChildD : ChildD
{
static Exception ex;
static this()
{
ex = new Exception("STOP");
}
~this()
{
throw ex;
}
}
void testThrowingDtor()
{
// Finalization error at runtime
if (!__ctfe)
return;
char[] res;
ThrowingChildD tcd = new ThrowingChildD();
tcd.ptr = &res;
if (!__ctfe)
{
try
{
destroy(tcd);
assert(false, "No exception thrown!");
}
catch (Exception e)
{
assert(e is ThrowingChildD.ex);
}
assert(res == "", cast(string) res);
}
}