mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-09-06 22:11:37 +00:00
D front-end changes: - Import dmd v2.112.0. - Bitfields feature is now enabled by default. - The compiler now accepts `-std=d2024' and `-std=d202y'. - An error is now issued for dangling `else' statements. - `finally' statements are no longer rewritten to a sequence if no `Exception' was thrown. - Some forms of `printf' calls are now treated as `@safe'. - Implicit integer conversions in `int op= float` assignments has been deprecated. D runtime changes: - Import druntime v2.112.0. - Added `filterCaughtThrowable' in `core.thread.ThreadBase'. Phobos changes: - Import phobos v2.112.0. gcc/d/ChangeLog: * dmd/VERSION: Bump version to v2.112.0. * dmd/MERGE: Merge upstream dmd 24a41073c2. * d-attribs.cc (build_attributes): Update for new front-end interface. * d-builtins.cc (build_frontend_type): Likewise. (matches_builtin_type): Likewise. (d_init_versions): Predefine D_Profile when compiling with profile enabled. * d-codegen.cc (get_array_length): Update for new front-end interface. (lower_struct_comparison): Likewise. (build_array_from_val): Likewise. (get_function_type): Likewise. (get_frameinfo): Likewise. * d-compiler.cc (Compiler::paintAsType): Likewise. * d-convert.cc (convert_expr): Likewise. (convert_for_rvalue): Likewise. (convert_for_assignment): Likewise. (d_array_convert): Likewise. * d-diagnostic.cc (verrorReport): Rename to ... (vreportDiagnostic): ... this. (verrorReportSupplemental): Rename to ... (vsupplementalDiagnostic): ... this. * d-lang.cc (d_handle_option): Handle -std=d2024 and -std=d202y. (d_parse_file): Update for new front-end interface. * d-target.cc (Target::fieldalign): Likewise. (Target::isVectorTypeSupported): Likewise. (Target::isVectorOpSupported): Likewise. * decl.cc (get_symbol_decl): Likewise. (DeclVisitor::visit): Likewise. (DeclVisitor::visit (FuncDeclaration *)): Do NRVO on `__result' decl. * expr.cc (needs_postblit): Remove. (needs_dtor): Remove. (lvalue_p): Remove. (ExprVisitor::visit): Update for new front-end interface. (ExprVisitor::visit (AssignExp *)): Update for front-end lowering expression using templates. * imports.cc (ImportVisitor::visit): Update for new front-end interface. * intrinsics.def (INTRINSIC_VA_ARG): Update signature. (INTRINSIC_C_VA_ARG): Update signature. (INTRINSIC_VASTART): Update signature. * lang.opt: Add -std=d2024 and -std=d202y. * toir.cc (IRVisitor::visit): Update for new front-end interface. * typeinfo.cc (TypeInfoVisitor::visit): Likewise. (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Ensure semantic is ran on all TypeInfo members. (base_vtable_offset): Update for new front-end interface. * types.cc (TypeVisitor::visit): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 24a41073c2. * libdruntime/__importc_builtins.di: Reimplement. * src/MERGE: Merge upstream phobos 808314eb2. * testsuite/libphobos.aa/test_aa.d: Adjust test. * testsuite/libphobos.gc/forkgc2.d: Removed. * testsuite/libphobos.thread/filterthrownglobal.d: New test. * testsuite/libphobos.thread/filterthrownmethod.d: New test. gcc/testsuite/ChangeLog: * gdc.dg/pr90601.d: Adjust test. * lib/gdc-utils.exp: Handle new compiler options.
311 lines
7.7 KiB
D
311 lines
7.7 KiB
D
module core.internal.cast_;
|
|
|
|
// Needed because ClassInfo.opEquals(Object) does a dynamic cast,
|
|
// but we are trying to implement dynamic cast.
|
|
bool areClassInfosEqual(scope const ClassInfo a, scope const ClassInfo b) pure nothrow @safe @nogc
|
|
{
|
|
// same class if signatures match, works with potential duplicates across binaries
|
|
if (a is b)
|
|
return true;
|
|
|
|
// new fast way
|
|
if (a.m_flags & TypeInfo_Class.ClassFlags.hasNameSig)
|
|
return a.nameSig[0] == b.nameSig[0]
|
|
&& a.nameSig[1] == b.nameSig[1]
|
|
&& a.nameSig[2] == b.nameSig[2]
|
|
&& a.nameSig[3] == b.nameSig[3];
|
|
|
|
// old slow way for temporary binary compatibility
|
|
return a.name == b.name;
|
|
}
|
|
|
|
|
|
/*****
|
|
* Dynamic cast from a class object `o` to class or interface `To`, where `To` is a subtype of `o`.
|
|
* Params:
|
|
* o = instance of class
|
|
* To = class or interface that is a subtype of `o`
|
|
* Returns:
|
|
* null if `o` is null or `To` is not a subclass type of `o`. Otherwise, return `o`.
|
|
*/
|
|
private void* _d_dynamic_cast(To)(const return scope Object o) @trusted
|
|
{
|
|
void* res = null;
|
|
size_t offset = 0;
|
|
|
|
if (o && _d_isbaseof2!To(typeid(o), offset))
|
|
{
|
|
res = cast(void*) o + offset;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Dynamic cast `o` to final class `To` only one level down
|
|
* Params:
|
|
* o = object that is instance of a class
|
|
* To = final class that is a subclass type of `o`
|
|
* Returns:
|
|
* o if it succeeds, null if it fails
|
|
*/
|
|
private void* _d_paint_cast(To)(const return scope Object o)
|
|
{
|
|
/* If o is really an instance of c, just do a paint
|
|
*/
|
|
auto p = o && cast(void*)(areClassInfosEqual(typeid(o), typeid(To).info)) ? o : null;
|
|
debug assert(cast(void*)p is cast(void*)_d_dynamic_cast!To(o));
|
|
return cast(void*)p;
|
|
}
|
|
|
|
private void* _d_class_cast_impl(const return scope Object o, const ClassInfo c) pure nothrow @safe @nogc
|
|
{
|
|
if (!o)
|
|
return null;
|
|
|
|
ClassInfo oc = typeid(o);
|
|
int delta = oc.depth;
|
|
|
|
if (delta && c.depth)
|
|
{
|
|
delta -= c.depth;
|
|
if (delta < 0)
|
|
return null;
|
|
|
|
while (delta--)
|
|
oc = oc.base;
|
|
if (areClassInfosEqual(oc, c))
|
|
return cast(void*)o;
|
|
return null;
|
|
}
|
|
|
|
// no depth data - support the old way
|
|
do
|
|
{
|
|
if (areClassInfosEqual(oc, c))
|
|
return cast(void*)o;
|
|
oc = oc.base;
|
|
} while (oc);
|
|
return null;
|
|
}
|
|
|
|
/*****
|
|
* Dynamic cast from a class object o to class type `To`, where `To` is a subclass type of `o`.
|
|
* Params:
|
|
* o = instance of class
|
|
* To = a subclass type of o
|
|
* Returns:
|
|
* null if `o` is null or `To` is not a subclass type of `o`. Otherwise, return `o`.
|
|
*/
|
|
private void* _d_class_cast(To)(const return scope Object o)
|
|
{
|
|
return _d_class_cast_impl(o, typeid(To));
|
|
}
|
|
|
|
/*************************************
|
|
* Attempts to cast interface Object o to class type `To`.
|
|
* Returns o if successful, null if not.
|
|
*/
|
|
private void* _d_interface_cast(To)(void* p) @trusted
|
|
{
|
|
if (!p)
|
|
return null;
|
|
|
|
Interface* pi = **cast(Interface***) p;
|
|
|
|
Object o2 = cast(Object)(p - pi.offset);
|
|
void* res = null;
|
|
size_t offset = 0;
|
|
if (o2 && _d_isbaseof2!To(typeid(o2), offset))
|
|
{
|
|
res = cast(void*) o2 + offset;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Hook that detects the type of cast performed and calls the appropriate function.
|
|
* Params:
|
|
* o = object that is being casted
|
|
* To = type to which the object is being casted
|
|
* Returns:
|
|
* null if the cast fails, otherwise returns the object casted to the type `To`.
|
|
*/
|
|
void* _d_cast(To, From)(From o) @trusted
|
|
{
|
|
static if (is(From == To))
|
|
{
|
|
return *cast(void**) &o;
|
|
}
|
|
else static if (is(From == class) && is(To == interface))
|
|
{
|
|
return _d_dynamic_cast!To(o);
|
|
}
|
|
else static if (is(From == class) && is(To == class))
|
|
{
|
|
|
|
/* Check for:
|
|
* class A { }
|
|
* final class B : A { }
|
|
* ... cast(B) A ...
|
|
*/
|
|
/* Multiple inheritance is not allowed, so we can safely assume
|
|
* that the second super can only be an interface.
|
|
*/
|
|
static if (is(From FromSupers == super) && is(To ToSupers == super) &&
|
|
__traits(isFinalClass, To) && is(ToSupers[0] == From) &&
|
|
ToSupers.length == 1 && FromSupers.length <= 1)
|
|
{
|
|
return _d_paint_cast!To(o);
|
|
}
|
|
else static if (is (To : From))
|
|
{
|
|
return _d_class_cast!To(o);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
else static if (is(From == interface))
|
|
{
|
|
return _d_interface_cast!To(cast(void*)o);
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private bool _d_isbaseof2(To)(scope ClassInfo oc, scope ref size_t offset)
|
|
{
|
|
auto c = typeid(To).info;
|
|
|
|
if (areClassInfosEqual(oc, c))
|
|
return true;
|
|
|
|
do
|
|
{
|
|
if (oc.base && areClassInfosEqual(oc.base, c))
|
|
return true;
|
|
|
|
// Bugzilla 2013: Use depth-first search to calculate offset
|
|
// from the derived (oc) to the base (c).
|
|
foreach (iface; oc.interfaces)
|
|
{
|
|
if (areClassInfosEqual(iface.classinfo, c) || _d_isbaseof2!To(iface.classinfo, offset))
|
|
{
|
|
offset += iface.offset;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
oc = oc.base;
|
|
} while (oc);
|
|
|
|
return false;
|
|
}
|
|
|
|
@safe pure unittest
|
|
{
|
|
interface I {}
|
|
|
|
class A {}
|
|
class B : A {}
|
|
class C : B, I{}
|
|
|
|
A ac = new C();
|
|
assert(_d_cast!I(ac) !is null); // A(c) to I
|
|
assert(_d_dynamic_cast!I(ac) !is null);
|
|
|
|
A ab = new B();
|
|
assert(_d_cast!I(ab) is null); // A(b) to I
|
|
assert(_d_dynamic_cast!I(ab) is null);
|
|
}
|
|
|
|
@safe pure unittest
|
|
{
|
|
class A {}
|
|
class B : A {}
|
|
class C : B {}
|
|
final class D : C {}
|
|
|
|
C cd = new D();
|
|
assert(_d_cast!D(cd) !is null); // C(d) to D
|
|
assert(_d_paint_cast!D(cd) !is null);
|
|
|
|
class G {}
|
|
final class J {}
|
|
A a = new A();
|
|
assert(_d_cast!G(a) is null); // A(a) to G
|
|
assert(_d_paint_cast!G(a) is null);
|
|
|
|
assert(_d_cast!J(a) is null); // A(a) to J
|
|
assert(_d_paint_cast!J(a) is null);
|
|
}
|
|
|
|
@safe pure unittest
|
|
{
|
|
class A {}
|
|
class B : A {}
|
|
class C : B {}
|
|
class D {}
|
|
|
|
A ac = new C();
|
|
assert(_d_cast!C(ac) !is null); // A(c) to C
|
|
assert(_d_class_cast!C(ac) !is null);
|
|
|
|
assert(_d_cast!B(ac) !is null); // A(c) to B
|
|
assert(_d_class_cast!B(ac) !is null);
|
|
|
|
A ab = new B();
|
|
assert(_d_cast!C(ab) is null); // A(b) to C
|
|
assert(_d_class_cast!C(ab) is null);
|
|
|
|
A a = new A();
|
|
assert(_d_cast!D(a) is null); // A(a) to D
|
|
assert(_d_class_cast!D(a) is null);
|
|
}
|
|
|
|
@safe pure unittest
|
|
{
|
|
interface I1 {}
|
|
interface I2 {}
|
|
interface I3 {}
|
|
class A {}
|
|
class B : A, I1, I2 {}
|
|
class C : B, I3 {}
|
|
|
|
I1 bi = new B();
|
|
assert(_d_cast!I2(bi) !is null); // I1(b) to I2
|
|
assert(_d_interface_cast!I2(cast(void*)bi) !is null);
|
|
|
|
assert(_d_cast!A(bi) !is null); // I1(b) to A
|
|
assert(_d_interface_cast!A(cast(void*)bi) !is null);
|
|
|
|
assert(_d_cast!B(bi) !is null); // I1(b) to B
|
|
assert(_d_interface_cast!B(cast(void*)bi) !is null);
|
|
|
|
assert(_d_cast!I3(bi) is null); // I1(b) to I3
|
|
assert(_d_interface_cast!I3(cast(void*)bi) is null);
|
|
|
|
assert(_d_cast!C(bi) is null); // I1(b) to C
|
|
assert(_d_interface_cast!C(cast(void*)bi) is null);
|
|
|
|
assert(_d_cast!I1(bi) !is null); // I1(b) to I1
|
|
assert(_d_interface_cast!I1(cast(void*)bi) !is null);
|
|
|
|
I3 ci = new C();
|
|
assert(_d_cast!I1(ci) !is null); // I3(c) to I1
|
|
assert(_d_interface_cast!I1(cast(void*)ci) !is null);
|
|
}
|
|
|
|
// https://github.com/dlang/dmd/issues/21646
|
|
@system pure unittest {
|
|
static class C {
|
|
@disable void opCast(T)();
|
|
}
|
|
|
|
const(C) const_c = new C();
|
|
C mutable_c = cast() const_c;
|
|
}
|