mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 16:11:08 +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
|
* This is a shell around a back end symbol
|
||||||
*/
|
*/
|
||||||
extern (C++) final class SymbolDeclaration : Declaration
|
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;
|
StructDeclaration dsym;
|
||||||
|
|
||||||
|
@ -1719,6 +1732,7 @@ extern (C++) final class SymbolDeclaration : Declaration
|
||||||
this.dsym = dsym;
|
this.dsym = dsym;
|
||||||
storage_class |= STC.const_;
|
storage_class |= STC.const_;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Eliminate need for dynamic_cast
|
// Eliminate need for dynamic_cast
|
||||||
override inout(SymbolDeclaration) isSymbolDeclaration() inout
|
override inout(SymbolDeclaration) isSymbolDeclaration() inout
|
||||||
|
|
|
@ -273,7 +273,11 @@ public:
|
||||||
class SymbolDeclaration : public Declaration
|
class SymbolDeclaration : public Declaration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
#if IN_LLVM
|
||||||
|
AggregateDeclaration *dsym;
|
||||||
|
#else
|
||||||
StructDeclaration *dsym;
|
StructDeclaration *dsym;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Eliminate need for dynamic_cast
|
// Eliminate need for dynamic_cast
|
||||||
SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
|
SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
|
||||||
|
|
|
@ -2139,6 +2139,12 @@ public:
|
||||||
}
|
}
|
||||||
else if (SymbolDeclaration s = d.isSymbolDeclaration())
|
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
|
// Struct static initializers, for example
|
||||||
e = s.dsym.type.defaultInitLiteral(loc);
|
e = s.dsym.type.defaultInitLiteral(loc);
|
||||||
if (e.op == TOK.error)
|
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.
|
// IN_LLVM: LDC-specific traits.
|
||||||
{ "targetCPU" },
|
{ "targetCPU" },
|
||||||
{ "targetHasFeature" },
|
{ "targetHasFeature" },
|
||||||
|
{ "initSymbol" },
|
||||||
|
|
||||||
// IN_LLVM: LDC-specific attributes
|
// IN_LLVM: LDC-specific attributes
|
||||||
{ "ldc" },
|
{ "ldc" },
|
||||||
|
|
19
dmd/traits.d
19
dmd/traits.d
|
@ -1922,6 +1922,25 @@ else
|
||||||
}
|
}
|
||||||
version (IN_LLVM)
|
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))
|
if (Expression ret = semanticTraitsHook(e, sc))
|
||||||
{
|
{
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -1573,23 +1573,32 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) {
|
if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) {
|
||||||
// this seems to be the static initialiser for structs
|
// this is the static initialiser (init symbol) for aggregates
|
||||||
Type *sdecltype = sdecl->type->toBasetype();
|
AggregateDeclaration *ad = sdecl->dsym;
|
||||||
IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
|
IF_LOG Logger::print("Sym: ad=%s\n", ad->toChars());
|
||||||
assert(sdecltype->ty == Tstruct);
|
DtoResolveDsymbol(ad);
|
||||||
TypeStruct *ts = static_cast<TypeStruct *>(sdecltype);
|
auto sd = ad->isStructDeclaration();
|
||||||
StructDeclaration *sd = ts->sym;
|
|
||||||
assert(sd);
|
|
||||||
DtoResolveStruct(sd);
|
|
||||||
|
|
||||||
|
// 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) {
|
if (sd->zeroInit) {
|
||||||
error(loc, "no init symbol for zero-initialized struct");
|
error(loc, "no init symbol for zero-initialized struct");
|
||||||
fatal();
|
fatal();
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
|
LLValue *initsym = getIrAggr(sd)->getInitSymbol();
|
||||||
initsym = DtoBitCast(initsym, DtoType(ts->pointerTo()));
|
return new DLValue(type, DtoBitCast(initsym, DtoPtrToType(sd->type)));
|
||||||
return new DLValue(type, initsym);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm_unreachable("Unimplemented VarExp type");
|
llvm_unreachable("Unimplemented VarExp type");
|
||||||
|
|
|
@ -71,15 +71,17 @@ public:
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
if (SymbolDeclaration *sdecl = e->var->isSymbolDeclaration()) {
|
if (SymbolDeclaration *sdecl = e->var->isSymbolDeclaration()) {
|
||||||
// this seems to be the static initialiser for structs
|
// This is the static initialiser (init symbol) for aggregates.
|
||||||
Type *sdecltype = sdecl->type->toBasetype();
|
// Exclude void[]-typed `__traits(initSymbol)` (LDC extension).
|
||||||
IF_LOG Logger::print("Sym: type=%s\n", sdecltype->toChars());
|
if (sdecl->type->toBasetype()->ty == Tstruct) {
|
||||||
assert(sdecltype->ty == Tstruct);
|
const auto sd = sdecl->dsym->isStructDeclaration();
|
||||||
TypeStruct *ts = static_cast<TypeStruct *>(sdecltype);
|
assert(sd);
|
||||||
DtoResolveStruct(ts->sym);
|
IF_LOG Logger::print("Sym: sd=%s\n", sd->toChars());
|
||||||
result = getIrAggr(ts->sym)->getDefaultInit();
|
DtoResolveStruct(sd);
|
||||||
|
result = getIrAggr(sd)->getDefaultInit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (TypeInfoDeclaration *ti = e->var->isTypeInfoDeclaration()) {
|
if (TypeInfoDeclaration *ti = e->var->isTypeInfoDeclaration()) {
|
||||||
result = DtoTypeInfoOf(e->loc, ti->tinfo, /*base=*/false);
|
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.
|
// to initialize a `S[1]` lhs with a `S` rhs.
|
||||||
if (auto ve = rhs->isVarExp()) {
|
if (auto ve = rhs->isVarExp()) {
|
||||||
if (auto symdecl = ve->var->isSymbolDeclaration()) {
|
if (auto symdecl = ve->var->isSymbolDeclaration()) {
|
||||||
Type *t = symdecl->type->toBasetype();
|
// exclude void[]-typed `__traits(initSymbol)` (LDC extension)
|
||||||
if (auto ts = t->isTypeStruct()) {
|
if (symdecl->type->toBasetype()->ty == Tstruct) {
|
||||||
// this is the static initializer for a struct (init symbol)
|
auto sd = symdecl->dsym->isStructDeclaration();
|
||||||
StructDeclaration *sd = ts->sym;
|
|
||||||
assert(sd);
|
assert(sd);
|
||||||
DtoResolveStruct(sd);
|
DtoResolveStruct(sd);
|
||||||
|
|
||||||
if (sd->zeroInit) {
|
if (sd->zeroInit) {
|
||||||
Logger::println("success, zeroing out");
|
Logger::println("success, zeroing out");
|
||||||
DtoMemSetZero(DtoLVal(lhs));
|
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