Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add __traits(initSymbol, <aggregate type>) #3774

Merged
merged 2 commits into from
Jun 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions dmd/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,11 @@ class VarDeclaration : public Declaration
class SymbolDeclaration : public Declaration
{
public:
#if IN_LLVM
AggregateDeclaration *dsym;
#else
StructDeclaration *dsym;
#endif

// Eliminate need for dynamic_cast
SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
Expand Down
6 changes: 6 additions & 0 deletions dmd/dinterpret.d
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,8 @@ immutable Msgtable[] msgtable =
// IN_LLVM: LDC-specific traits.
{ "targetCPU" },
{ "targetHasFeature" },

{ "initSymbol" },

// IN_LLVM: LDC-specific attributes
{ "ldc" },
{ "attributes" },
Expand Down
19 changes: 19 additions & 0 deletions dmd/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 19 additions & 10 deletions gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
18 changes: 10 additions & 8 deletions gen/toconstelem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,16 @@ class ToConstElemVisitor : public Visitor {
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();
return;
// 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()) {
Expand Down
8 changes: 3 additions & 5 deletions gen/toir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
30 changes: 30 additions & 0 deletions tests/semantic/traits_initSymbol.d
Original file line number Diff line number Diff line change
@@ -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)));
}