mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 08:01:11 +03:00
Add __traits(initSymbol, <aggregate type>) (#3774)
A clean way of directly accessing struct and class init symbols. It yields a `const(void[])` slice; the length reflecting the struct/class instance size, and the pointer either pointing to the init symbol or being null for zero-initialized structs. Paves the way for resolving #3773 in druntime as well as accessing class init symbols without `TypeInfo_Class.initializer()` indirection, and so with -betterC as well.
This commit is contained in:
parent
383129c3b0
commit
c6096a7d27
9 changed files with 107 additions and 24 deletions
|
@ -1710,6 +1710,19 @@ version (IN_LLVM)
|
|||
* This is a shell around a back end symbol
|
||||
*/
|
||||
extern (C++) final class SymbolDeclaration : Declaration
|
||||
{
|
||||
version (IN_LLVM)
|
||||
{
|
||||
AggregateDeclaration dsym;
|
||||
|
||||
extern (D) this(const ref Loc loc, AggregateDeclaration dsym)
|
||||
{
|
||||
super(loc, dsym.ident);
|
||||
this.dsym = dsym;
|
||||
storage_class |= STC.const_;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StructDeclaration dsym;
|
||||
|
||||
|
@ -1719,6 +1732,7 @@ extern (C++) final class SymbolDeclaration : Declaration
|
|||
this.dsym = dsym;
|
||||
storage_class |= STC.const_;
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminate need for dynamic_cast
|
||||
override inout(SymbolDeclaration) isSymbolDeclaration() inout
|
||||
|
|
|
@ -273,7 +273,11 @@ public:
|
|||
class SymbolDeclaration : public Declaration
|
||||
{
|
||||
public:
|
||||
#if IN_LLVM
|
||||
AggregateDeclaration *dsym;
|
||||
#else
|
||||
StructDeclaration *dsym;
|
||||
#endif
|
||||
|
||||
// Eliminate need for dynamic_cast
|
||||
SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
|
||||
|
|
|
@ -2139,6 +2139,12 @@ public:
|
|||
}
|
||||
else if (SymbolDeclaration s = d.isSymbolDeclaration())
|
||||
{
|
||||
version (IN_LLVM)
|
||||
{
|
||||
// exclude void[]-typed `__traits(initSymbol)` (LDC extension)
|
||||
if (s.type.toBasetype().ty != Tstruct)
|
||||
return CTFEExp.cantexp;
|
||||
}
|
||||
// Struct static initializers, for example
|
||||
e = s.dsym.type.defaultInitLiteral(loc);
|
||||
if (e.op == TOK.error)
|
||||
|
|
1
dmd/id.d
1
dmd/id.d
|
@ -520,6 +520,7 @@ immutable Msgtable[] msgtable =
|
|||
// IN_LLVM: LDC-specific traits.
|
||||
{ "targetCPU" },
|
||||
{ "targetHasFeature" },
|
||||
{ "initSymbol" },
|
||||
|
||||
// IN_LLVM: LDC-specific attributes
|
||||
{ "ldc" },
|
||||
|
|
19
dmd/traits.d
19
dmd/traits.d
|
@ -1922,6 +1922,25 @@ else
|
|||
}
|
||||
version (IN_LLVM)
|
||||
{
|
||||
if (e.ident == Id.initSymbol)
|
||||
{
|
||||
if (dim != 1)
|
||||
return dimError(1);
|
||||
|
||||
auto o = (*e.args)[0];
|
||||
Type t = isType(o);
|
||||
AggregateDeclaration ad = t ? isAggregate(t) : null;
|
||||
if (!ad)
|
||||
{
|
||||
e.error("aggregate type expected as argument to __traits(initSymbol)");
|
||||
return ErrorExp.get();
|
||||
}
|
||||
|
||||
Declaration d = new SymbolDeclaration(ad.loc, ad);
|
||||
d.type = Type.tvoid.arrayOf().constOf();
|
||||
d.storage_class |= STC.rvalue;
|
||||
return new VarExp(ad.loc, d);
|
||||
}
|
||||
if (Expression ret = semanticTraitsHook(e, sc))
|
||||
{
|
||||
return ret;
|
||||
|
|
|
@ -1573,23 +1573,32 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) {
|
|||
}
|
||||
|
||||
if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) {
|
||||
// this seems to be the static initialiser for structs
|
||||
Type *sdecltype = sdecl->type->toBasetype();
|
||||
IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
|
||||
assert(sdecltype->ty == Tstruct);
|
||||
TypeStruct *ts = static_cast<TypeStruct *>(sdecltype);
|
||||
StructDeclaration *sd = ts->sym;
|
||||
assert(sd);
|
||||
DtoResolveStruct(sd);
|
||||
// this is the static initialiser (init symbol) for aggregates
|
||||
AggregateDeclaration *ad = sdecl->dsym;
|
||||
IF_LOG Logger::print("Sym: ad=%s\n", ad->toChars());
|
||||
DtoResolveDsymbol(ad);
|
||||
auto sd = ad->isStructDeclaration();
|
||||
|
||||
// LDC extension: void[]-typed `__traits(initSymbol)`, for classes too
|
||||
auto tb = sdecl->type->toBasetype();
|
||||
if (tb->ty != Tstruct) {
|
||||
assert(tb->ty == Tarray && tb->nextOf()->ty == Tvoid);
|
||||
const auto size = DtoConstSize_t(ad->structsize);
|
||||
llvm::Constant *ptr =
|
||||
sd && sd->zeroInit
|
||||
? getNullValue(getVoidPtrType())
|
||||
: DtoBitCast(getIrAggr(ad)->getInitSymbol(), getVoidPtrType());
|
||||
return new DSliceValue(type, size, ptr);
|
||||
}
|
||||
|
||||
assert(sd);
|
||||
if (sd->zeroInit) {
|
||||
error(loc, "no init symbol for zero-initialized struct");
|
||||
fatal();
|
||||
}
|
||||
|
||||
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
|
||||
initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
|
||||
return new DLValue(type, initsym);
|
||||
return new DLValue(type, DtoBitCast(initsym, DtoPtrToType(sd->type)));
|
||||
}
|
||||
|
||||
llvm_unreachable("Unimplemented VarExp type");
|
||||
|
|
|
@ -71,15 +71,17 @@ public:
|
|||
LOG_SCOPE;
|
||||
|
||||
if (SymbolDeclaration *sdecl = e->var->isSymbolDeclaration()) {
|
||||
// this seems to be the static initialiser for structs
|
||||
Type *sdecltype = sdecl->type->toBasetype();
|
||||
IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
|
||||
assert(sdecltype->ty == Tstruct);
|
||||
TypeStruct *ts = static_cast<TypeStruct *>(sdecltype);
|
||||
DtoResolveStruct(ts->sym);
|
||||
result = getIrAggr(ts->sym)->getDefaultInit();
|
||||
// This is the static initialiser (init symbol) for aggregates.
|
||||
// Exclude void[]-typed `__traits(initSymbol)` (LDC extension).
|
||||
if (sdecl->type->toBasetype()->ty == Tstruct) {
|
||||
const auto sd = sdecl->dsym->isStructDeclaration();
|
||||
assert(sd);
|
||||
IF_LOG Logger::print("Sym: sd=%s\n", sd->toChars());
|
||||
DtoResolveStruct(sd);
|
||||
result = getIrAggr(sd)->getDefaultInit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (TypeInfoDeclaration *ti = e->var->isTypeInfoDeclaration()) {
|
||||
result = DtoTypeInfoOf(e->loc, ti->tinfo, /*base=*/false);
|
||||
|
|
|
@ -2755,13 +2755,11 @@ bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) {
|
|||
// to initialize a `S[1]` lhs with a `S` rhs.
|
||||
if (auto ve = rhs->isVarExp()) {
|
||||
if (auto symdecl = ve->var->isSymbolDeclaration()) {
|
||||
Type *t = symdecl->type->toBasetype();
|
||||
if (auto ts = t->isTypeStruct()) {
|
||||
// this is the static initializer for a struct (init symbol)
|
||||
StructDeclaration *sd = ts->sym;
|
||||
// exclude void[]-typed `__traits(initSymbol)` (LDC extension)
|
||||
if (symdecl->type->toBasetype()->ty == Tstruct) {
|
||||
auto sd = symdecl->dsym->isStructDeclaration();
|
||||
assert(sd);
|
||||
DtoResolveStruct(sd);
|
||||
|
||||
if (sd->zeroInit) {
|
||||
Logger::println("success, zeroing out");
|
||||
DtoMemSetZero(DtoLVal(lhs));
|
||||
|
|
30
tests/semantic/traits_initSymbol.d
Normal file
30
tests/semantic/traits_initSymbol.d
Normal file
|
@ -0,0 +1,30 @@
|
|||
// RUN: %ldc -run %s
|
||||
|
||||
struct Zero { int x; }
|
||||
|
||||
struct NonZero { long x = 1; }
|
||||
|
||||
class C { short x = 123; }
|
||||
|
||||
void main()
|
||||
{
|
||||
auto zeroInit = __traits(initSymbol, Zero);
|
||||
static assert(is(typeof(zeroInit) == const(void[])));
|
||||
assert(zeroInit.ptr is null && zeroInit.length == Zero.sizeof);
|
||||
|
||||
auto nonZeroInit = __traits(initSymbol, NonZero);
|
||||
static assert(is(typeof(nonZeroInit) == const(void[])));
|
||||
assert(nonZeroInit.ptr !is null && nonZeroInit.length == NonZero.sizeof);
|
||||
assert(cast(const(long[])) nonZeroInit == [1L]);
|
||||
|
||||
auto cInit = __traits(initSymbol, C);
|
||||
static assert(is(typeof(cInit) == const(void[])));
|
||||
assert(cInit.ptr !is null && cInit.length == __traits(classInstanceSize, C));
|
||||
scope c = new C;
|
||||
import core.stdc.string;
|
||||
assert(memcmp(cast(void*) c, cInit.ptr, cInit.length) == 0);
|
||||
|
||||
static assert(!__traits(compiles, __traits(initSymbol, int)));
|
||||
static assert(!__traits(compiles, __traits(initSymbol, Zero[1])));
|
||||
static assert(!__traits(compiles, __traits(initSymbol, 123)));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue