Skip to content
Closed
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
23 changes: 23 additions & 0 deletions changelog.dd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ $(COMMENT Pending changelog for 2.072. This will get copied to dlang.org and
)

$(BUGSTITLE Language Changes,
$(LI $(RELATIVE_LINK2 align_by_ctfe, Align attribute can be used with CTFEable expression.))
)

$(BUGSTITLE Compiler Changes,
Expand All @@ -13,6 +14,28 @@ $(BUGSTITLE Compiler Changes,
)

$(BUGSTITLE Language Changes,
$(LI $(LNAME2 align_by_ctfe, Align attribute can be used with CTFEable expression.)

$(P Example:)

---
version (D_LP64)
enum n = 8;
else
enum n = 4;
align (n) struct Data
{
align (n == 8 ? 2 : 1):
ubyte[3] buffer;
int flags;
}

version (D_LP64)
static assert(Data.flags.offsetof == 4);
else
static assert(Data.flags.offsetof == 3);
---
)
)

$(BUGSTITLE Compiler Changes,
Expand Down
2 changes: 1 addition & 1 deletion src/aggregate.d
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public:
sc2.inunion = 1;
sc2.protection = Prot(PROTpublic);
sc2.explicitProtection = 0;
sc2.structalign = STRUCTALIGN_DEFAULT;
sc2.aligndecl = null;
sc2.userAttribDecl = null;
return sc2;
}
Expand Down
122 changes: 104 additions & 18 deletions src/attrib.d
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,25 @@ public:
* If the returned scope != sc, the caller should pop
* the scope after it used.
*/
static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage, Prot protection, int explicitProtection, structalign_t structalign, PINLINE inlining)
static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
Prot protection, int explicitProtection, AlignDeclaration aligndecl,
PINLINE inlining)
{
Scope* sc2 = sc;
if (stc != sc.stc || linkage != sc.linkage || !protection.isSubsetOf(sc.protection) || explicitProtection != sc.explicitProtection || structalign != sc.structalign || inlining != sc.inlining)
if (stc != sc.stc ||
linkage != sc.linkage ||
!protection.isSubsetOf(sc.protection) ||
explicitProtection != sc.explicitProtection ||
aligndecl !is sc.aligndecl ||
inlining != sc.inlining)
{
// create new one for changes
sc2 = sc.copy();
sc2.stc = stc;
sc2.linkage = linkage;
sc2.protection = protection;
sc2.explicitProtection = explicitProtection;
sc2.structalign = structalign;
sc2.aligndecl = aligndecl;
sc2.inlining = inlining;
}
return sc2;
Expand Down Expand Up @@ -352,7 +359,9 @@ public:
scstc &= ~(STCsafe | STCtrusted | STCsystem);
scstc |= stc;
//printf("scstc = x%llx\n", scstc);
return createNewScope(sc, scstc, sc.linkage, sc.protection, sc.explicitProtection, sc.structalign, sc.inlining);
return createNewScope(sc, scstc, sc.linkage,
sc.protection, sc.explicitProtection, sc.aligndecl,
sc.inlining);
}

override final bool oneMember(Dsymbol* ps, Identifier ident)
Expand Down Expand Up @@ -499,7 +508,9 @@ public:

override Scope* newScope(Scope* sc)
{
return createNewScope(sc, sc.stc, this.linkage, sc.protection, sc.explicitProtection, sc.structalign, sc.inlining);
return createNewScope(sc, sc.stc, this.linkage,
sc.protection, sc.explicitProtection, sc.aligndecl,
sc.inlining);
}

override const(char)* toChars() const
Expand Down Expand Up @@ -563,7 +574,9 @@ public:
{
if (pkg_identifiers)
semantic(sc);
return createNewScope(sc, sc.stc, sc.linkage, this.protection, 1, sc.structalign, sc.inlining);
return createNewScope(sc, sc.stc, sc.linkage,
this.protection, 1, sc.aligndecl,
sc.inlining);
}

override void addMember(Scope* sc, ScopeDsymbol sds)
Expand Down Expand Up @@ -611,23 +624,91 @@ public:
extern (C++) final class AlignDeclaration : AttribDeclaration
{
public:
uint salign;
Expression ealign;
structalign_t salign = STRUCTALIGN_DEFAULT;

extern (D) this(uint sa, Dsymbols* decl)
extern (D) this(Loc loc, Expression ealign, Dsymbols* decl)
{
super(decl);
salign = sa;
this.loc = loc;
this.ealign = ealign;
}

override Dsymbol syntaxCopy(Dsymbol s)
{
assert(!s);
return new AlignDeclaration(salign, Dsymbol.arraySyntaxCopy(decl));
return new AlignDeclaration(loc,
ealign.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
}

override Scope* newScope(Scope* sc)
{
return createNewScope(sc, sc.stc, sc.linkage, sc.protection, sc.explicitProtection, this.salign, sc.inlining);
return createNewScope(sc, sc.stc, sc.linkage,
sc.protection, sc.explicitProtection, this,
sc.inlining);
}

override void setScope(Scope* sc)
{
//printf("AlignDeclaration::setScope() %p\n", this);
if (ealign && decl)
Dsymbol.setScope(sc); // for forward reference
return AttribDeclaration.setScope(sc);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This calls Dsymbol.setScope() followed by AttribDeclaration.setScope() which is surely a bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. AttribDeclaration.setScope does not set _scope intentionally because it's not used for other attributes - ProtDeclaration, ConditionDeclaration + (VersionCondition, DebugCondition), etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}

override void semantic2(Scope* sc)
{
getAlignment();
super.semantic2(sc);
}

structalign_t getAlignment()
{
if (!ealign)
return STRUCTALIGN_DEFAULT;

if (auto sc = _scope)
{
_scope = null;

sc = sc.startCTFE();
ealign = ealign.semantic(sc);
ealign = resolveProperties(sc, ealign);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems to me ctfeInterpret() should be put here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and then just do toInteger(), which will take care of most of the cases below. Then, just have one:

n >= 1 && n <= structalign_t.max && !(n & (n - 1))

should do it.

sc = sc.endCTFE();

auto errorPositiveInteger()
{
.error(loc, "positive integer expected, not %s", ealign.toChars());
return STRUCTALIGN_DEFAULT;
}

if (ealign.op == TOKerror)
return STRUCTALIGN_DEFAULT;
if (!ealign.type)
return errorPositiveInteger();
Type tb = ealign.type.toBasetype();
if (!tb.isintegral())
return errorPositiveInteger();
if (tb.ty == Tchar || tb.ty == Twchar || tb.ty == Tdchar || tb.ty == Tbool)
return errorPositiveInteger();

ealign = ealign.ctfeInterpret();
if (ealign.op == TOKerror)
return STRUCTALIGN_DEFAULT;

auto n = ealign.toInteger();
if (n < 1 || structalign_t.max < n)
return errorPositiveInteger();

if (n & (n - 1))
{
.error(loc, "alignment must be a power of 2, not %u", cast(structalign_t)n);
return STRUCTALIGN_DEFAULT;
}

salign = cast(structalign_t)n;
}
return salign;
}

override void accept(Visitor v)
Expand All @@ -642,7 +723,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
{
public:
bool isunion;
structalign_t alignment;
int sem; // 1 if successful semantic()
uint anonoffset; // offset of anonymous struct
uint anonstructsize; // size of anonymous struct
Expand All @@ -663,22 +743,23 @@ public:

override void setScope(Scope* sc)
{
super.setScope(sc);
alignment = sc.structalign;
if (decl)
Dsymbol.setScope(sc);
return AttribDeclaration.setScope(sc);
}

override void semantic(Scope* sc)
{
//printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
assert(sc.parent);
Dsymbol p = sc.parent.pastMixin();
AggregateDeclaration ad = p.isAggregateDeclaration();
auto p = sc.parent.pastMixin();
auto ad = p.isAggregateDeclaration();
if (!ad)
{
.error(loc, "%s can only be a part of an aggregate, not %s %s", kind(), p.kind(), p.toChars());
return;
}
alignment = sc.structalign;

if (decl)
{
sc = sc.push();
Expand Down Expand Up @@ -746,6 +827,9 @@ public:
anonalignsize = 1;
}

assert(_scope);
auto alignment = _scope.alignment();

/* Given the anon 'member's size and alignment,
* go ahead and place it.
*/
Expand Down Expand Up @@ -833,7 +917,9 @@ public:
else if (e.isBool(false))
inlining = PINLINEnever;
}
return createNewScope(sc, sc.stc, sc.linkage, sc.protection, sc.explicitProtection, sc.structalign, inlining);
return createNewScope(sc, sc.stc, sc.linkage,
sc.protection, sc.explicitProtection, sc.aligndecl,
inlining);
}
return sc;
}
Expand Down
9 changes: 6 additions & 3 deletions src/attrib.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,19 +117,22 @@ class ProtDeclaration : public AttribDeclaration
class AlignDeclaration : public AttribDeclaration
{
public:
unsigned salign;
Expression *ealign;
structalign_t salign;

AlignDeclaration(unsigned sa, Dsymbols *decl);
AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl);
Dsymbol *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
void setScope(Scope *sc);
void semantic2(Scope *sc);
structalign_t getAlignment();
void accept(Visitor *v) { v->visit(this); }
};

class AnonDeclaration : public AttribDeclaration
{
public:
bool isunion;
structalign_t alignment;
int sem; // 1 if successful semantic()
unsigned anonoffset; // offset of anonymous struct
unsigned anonstructsize; // size of anonymous struct
Expand Down
2 changes: 1 addition & 1 deletion src/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,7 @@ public:
/* If scope's alignment is the default, use the type's alignment,
* otherwise the scope overrrides.
*/
alignment = sc.structalign;
alignment = sc.alignment();
if (alignment == STRUCTALIGN_DEFAULT)
alignment = type.alignment(); // use type's alignment

Expand Down
12 changes: 10 additions & 2 deletions src/dscope.d
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ struct Scope
size_t fieldinit_dim;

// alignment for struct members
structalign_t structalign = STRUCTALIGN_DEFAULT;
AlignDeclaration aligndecl;

// linkage for external functions
LINK linkage = LINKd;
Expand Down Expand Up @@ -722,7 +722,7 @@ struct Scope
this.scontinue = sc.scontinue;
this.fes = sc.fes;
this.callsc = sc.callsc;
this.structalign = sc.structalign;
this.aligndecl = sc.aligndecl;
this.func = sc.func;
this.slabel = sc.slabel;
this.linkage = sc.linkage;
Expand All @@ -745,4 +745,12 @@ struct Scope
this.prevAnchor = sc.prevAnchor;
this.userAttribDecl = sc.userAttribDecl;
}

structalign_t alignment()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates logic found above. Merge into getAlignment().

{
if (aligndecl)
return aligndecl.getAlignment();
else
return STRUCTALIGN_DEFAULT;
}
}
2 changes: 1 addition & 1 deletion src/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ public:
{
protection = sc.protection;

alignment = sc.structalign;
alignment = sc.alignment();

storage_class |= sc.stc;
if (storage_class & STCdeprecated)
Expand Down
2 changes: 1 addition & 1 deletion src/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,7 @@ public:
sc2.stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STCoverride | STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | STCreturn | STCproperty | STCnothrow | STCpure | STCsafe | STCtrusted | STCsystem);
sc2.protection = Prot(PROTpublic);
sc2.explicitProtection = 0;
sc2.structalign = STRUCTALIGN_DEFAULT;
sc2.aligndecl = null;
if (this.ident != Id.require && this.ident != Id.ensure)
sc2.flags = sc.flags & ~SCOPEcontract;
sc2.flags &= ~SCOPEcompile;
Expand Down
6 changes: 3 additions & 3 deletions src/hdrgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -1201,10 +1201,10 @@ public:

override void visit(AlignDeclaration d)
{
if (d.salign == STRUCTALIGN_DEFAULT)
buf.printf("align");
if (!d.ealign)
buf.printf("align ");
else
buf.printf("align (%d)", d.salign);
buf.printf("align (%s) ", d.ealign.toChars());
visit(cast(AttribDeclaration)d);
}

Expand Down
Loading