diff --git a/changelog.dd b/changelog.dd index a881975062cf..1bb2d938b134 100644 --- a/changelog.dd +++ b/changelog.dd @@ -14,6 +14,8 @@ $(BUGSTITLE Language Changes, It is up to the programmer to call them appropriately. ) ) + + $(LI $(RELATIVE_LINK2 align_by_ctfe, Align attribute can be used with CTFEable expression.)) ) $(BUGSTITLE Compiler Changes, @@ -51,6 +53,28 @@ $(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, diff --git a/src/aggregate.d b/src/aggregate.d index 8b557c4af054..fad9b39673a1 100644 --- a/src/aggregate.d +++ b/src/aggregate.d @@ -119,7 +119,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol sc2.inunion = 1; sc2.protection = Prot(PROTpublic); sc2.explicitProtection = 0; - sc2.structalign = STRUCTALIGN_DEFAULT; + sc2.aligndecl = null; sc2.userAttribDecl = null; return sc2; } diff --git a/src/attrib.d b/src/attrib.d index cd39fcfe4925..7059a44a1bc8 100644 --- a/src/attrib.d +++ b/src/attrib.d @@ -77,10 +77,18 @@ extern (C++) abstract class AttribDeclaration : Dsymbol * If the returned scope != sc, the caller should pop * the scope after it used. */ - static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage, CPPMANGLE cppmangle, Prot protection, int explicitProtection, structalign_t structalign, PINLINE inlining) + static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage, + CPPMANGLE cppmangle, Prot protection, int explicitProtection, + AlignDeclaration aligndecl, PINLINE inlining) { Scope* sc2 = sc; - if (stc != sc.stc || linkage != sc.linkage || cppmangle != sc.cppmangle || !protection.isSubsetOf(sc.protection) || explicitProtection != sc.explicitProtection || structalign != sc.structalign || inlining != sc.inlining) + if (stc != sc.stc || + linkage != sc.linkage || + cppmangle != sc.cppmangle || + !protection.isSubsetOf(sc.protection) || + explicitProtection != sc.explicitProtection || + aligndecl !is sc.aligndecl || + inlining != sc.inlining) { // create new one for changes sc2 = sc.copy(); @@ -89,7 +97,7 @@ extern (C++) abstract class AttribDeclaration : Dsymbol sc2.cppmangle = cppmangle; sc2.protection = protection; sc2.explicitProtection = explicitProtection; - sc2.structalign = structalign; + sc2.aligndecl = aligndecl; sc2.inlining = inlining; } return sc2; @@ -351,7 +359,8 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration scstc &= ~(STCsafe | STCtrusted | STCsystem); scstc |= stc; //printf("scstc = x%llx\n", scstc); - return createNewScope(sc, scstc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.structalign, sc.inlining); + return createNewScope(sc, scstc, sc.linkage, sc.cppmangle, + sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining); } override final bool oneMember(Dsymbol* ps, Identifier ident) @@ -496,7 +505,8 @@ extern (C++) final class LinkDeclaration : AttribDeclaration override Scope* newScope(Scope* sc) { - return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.structalign, sc.inlining); + return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, + sc.aligndecl, sc.inlining); } override const(char)* toChars() const @@ -531,7 +541,8 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration override Scope* newScope(Scope* sc) { - return createNewScope(sc, sc.stc, LINKcpp, cppmangle, sc.protection, sc.explicitProtection, sc.structalign, sc.inlining); + return createNewScope(sc, sc.stc, LINKcpp, cppmangle, sc.protection, sc.explicitProtection, + sc.aligndecl, sc.inlining); } override const(char)* toChars() const @@ -594,7 +605,7 @@ extern (C++) final class ProtDeclaration : AttribDeclaration { if (pkg_identifiers) semantic(sc); - return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.protection, 1, sc.structalign, sc.inlining); + return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.protection, 1, sc.aligndecl, sc.inlining); } override void addMember(Scope* sc, ScopeDsymbol sds) @@ -641,23 +652,72 @@ extern (C++) final class ProtDeclaration : AttribDeclaration */ extern (C++) final class AlignDeclaration : AttribDeclaration { - 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.cppmangle, sc.protection, sc.explicitProtection, this.salign, sc.inlining); + return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, 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); + } + + 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); + sc = sc.endCTFE(); + ealign = ealign.ctfeInterpret(); + + if (ealign.op == TOKerror) + return STRUCTALIGN_DEFAULT; + + Type tb = ealign.type.toBasetype(); + auto n = ealign.toInteger(); + + if (n < 1 || n & (n - 1) || structalign_t.max < n || !tb.isintegral()) + { + .error(loc, "alignment must be an integer positive power of 2, not %s", ealign.toChars()); + return STRUCTALIGN_DEFAULT; + } + + salign = cast(structalign_t)n; + } + return salign; } override void accept(Visitor v) @@ -671,7 +731,6 @@ extern (C++) final class AlignDeclaration : AttribDeclaration extern (C++) final class AnonDeclaration : AttribDeclaration { bool isunion; - structalign_t alignment; int sem; // 1 if successful semantic() uint anonoffset; // offset of anonymous struct uint anonstructsize; // size of anonymous struct @@ -692,22 +751,23 @@ extern (C++) final class AnonDeclaration : AttribDeclaration 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(); @@ -775,6 +835,9 @@ extern (C++) final class AnonDeclaration : AttribDeclaration anonalignsize = 1; } + assert(_scope); + auto alignment = _scope.alignment(); + /* Given the anon 'member's size and alignment, * go ahead and place it. */ @@ -861,7 +924,7 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration else if (e.isBool(false)) inlining = PINLINEnever; } - return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.structalign, inlining); + return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining); } return sc; } diff --git a/src/attrib.h b/src/attrib.h index 48654a237767..3e4a51daaea2 100644 --- a/src/attrib.h +++ b/src/attrib.h @@ -120,11 +120,15 @@ class ProtDeclaration : public AttribDeclaration class AlignDeclaration : public AttribDeclaration { -public: - unsigned salign; + Expression *ealign; + structalign_t salign; + 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); } }; @@ -132,7 +136,6 @@ 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 diff --git a/src/declaration.d b/src/declaration.d index b349ffd4b1fe..851c07557096 100644 --- a/src/declaration.d +++ b/src/declaration.d @@ -1116,7 +1116,7 @@ extern (C++) class VarDeclaration : Declaration /* 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 diff --git a/src/dscope.d b/src/dscope.d index 0f597abd255b..769fba84f974 100644 --- a/src/dscope.d +++ b/src/dscope.d @@ -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; @@ -725,7 +725,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; @@ -749,4 +749,12 @@ struct Scope this.prevAnchor = sc.prevAnchor; this.userAttribDecl = sc.userAttribDecl; } + + structalign_t alignment() + { + if (aligndecl) + return aligndecl.getAlignment(); + else + return STRUCTALIGN_DEFAULT; + } } diff --git a/src/dstruct.d b/src/dstruct.d index 229f67b6e22b..a1dc22d6bce5 100644 --- a/src/dstruct.d +++ b/src/dstruct.d @@ -300,7 +300,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration { protection = sc.protection; - alignment = sc.structalign; + alignment = sc.alignment(); storage_class |= sc.stc; if (storage_class & STCdeprecated) diff --git a/src/func.d b/src/func.d index ee47fae52908..f9ef85f583f1 100644 --- a/src/func.d +++ b/src/func.d @@ -1444,7 +1444,7 @@ extern (C++) class FuncDeclaration : Declaration 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; diff --git a/src/hdrgen.d b/src/hdrgen.d index 30f22a34c740..7f5f45554e61 100644 --- a/src/hdrgen.d +++ b/src/hdrgen.d @@ -1221,10 +1221,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); } diff --git a/src/parse.d b/src/parse.d index 9e2dc816dd4a..1b12931ebb94 100644 --- a/src/parse.d +++ b/src/parse.d @@ -226,7 +226,8 @@ struct PrefixAttributes Expression depmsg; LINK link; Prot protection; - uint alignment; + bool setAlignment; + Expression ealign; Expressions* udas; const(char)* comment; } @@ -991,59 +992,34 @@ final class Parser : Lexer } case TOKalign: { + const attrLoc = token.loc; + nextToken(); - uint n; + Expression e = null; // default if (token.value == TOKlparen) { nextToken(); - if (token.value == TOKint32v && token.uns64value > 0) - { - if (token.uns64value & (token.uns64value - 1)) - error("align(%s) must be a power of 2", token.toChars()); - n = cast(uint)token.uns64value; - } - else - { - error("positive integer expected, not %s", token.toChars()); - n = 1; - } - nextToken(); + e = parseAssignExp(); check(TOKrparen); } - else - n = STRUCTALIGN_DEFAULT; // default - if (pAttrs.alignment != 0) + if (pAttrs.setAlignment) { - const(char)* s1 = ""; - OutBuffer buf1; - if (n != STRUCTALIGN_DEFAULT) - { - buf1.printf("(%d)", n); - s1 = buf1.peekString(); - } - if (pAttrs.alignment != n) - { - OutBuffer buf2; - const(char)* s2 = ""; - if (pAttrs.alignment != STRUCTALIGN_DEFAULT) - { - buf2.printf("(%d)", pAttrs.alignment); - s2 = buf2.peekString(); - } - error("conflicting alignment attribute align%s and align%s", s2, s1); - } + if (e) + error("redundant alignment attribute align(%s)", e.toChars()); else - error("redundant alignment attribute align%s", s1); + error("redundant alignment attribute align"); } - pAttrs.alignment = n; + pAttrs.setAlignment = true; + pAttrs.ealign = e; a = parseBlock(pLastDecl, pAttrs); - if (pAttrs.alignment != 0) + if (pAttrs.setAlignment) { - s = new AlignDeclaration(pAttrs.alignment, a); - pAttrs.alignment = 0; + s = new AlignDeclaration(attrLoc, pAttrs.ealign, a); + pAttrs.setAlignment = false; + pAttrs.ealign = null; } break; } @@ -3961,7 +3937,8 @@ final class Parser : Lexer return ts; } - void parseStorageClasses(ref StorageClass storage_class, ref LINK link, ref uint structalign, ref Expressions* udas) + void parseStorageClasses(ref StorageClass storage_class, ref LINK link, + ref bool setAlignment, ref Expression ealign, ref Expressions* udas) { StorageClass stc; bool sawLinkage = false; // seen a linkage declaration @@ -4085,21 +4062,13 @@ final class Parser : Lexer case TOKalign: { nextToken(); + setAlignment = true; if (token.value == TOKlparen) { nextToken(); - if (token.value == TOKint32v && token.uns64value > 0) - structalign = cast(uint)token.uns64value; - else - { - error("positive integer expected, not %s", token.toChars()); - structalign = 1; - } - nextToken(); + ealign = parseExpression(); check(TOKrparen); } - else - structalign = STRUCTALIGN_DEFAULT; // default continue; } default: @@ -4125,7 +4094,8 @@ final class Parser : Lexer Identifier ident; TOK tok = TOKreserved; LINK link = linkage; - uint structalign = 0; + bool setAlignment = false; + Expression ealign; auto loc = token.loc; Expressions* udas = null; Token* tk; @@ -4219,9 +4189,10 @@ final class Parser : Lexer storage_class = STCundefined; link = linkage; - structalign = 0; + setAlignment = false; + ealign = null; udas = null; - parseStorageClasses(storage_class, link, structalign, udas); + parseStorageClasses(storage_class, link, setAlignment, ealign, udas); if (udas) error("user defined attributes not allowed for %s declarations", Token.toChars(tok)); @@ -4282,9 +4253,12 @@ final class Parser : Lexer // alias StorageClasses type ident; } - parseStorageClasses(storage_class, link, structalign, udas); + parseStorageClasses(storage_class, link, setAlignment, ealign, udas); - if (token.value == TOKstruct || token.value == TOKunion || token.value == TOKclass || token.value == TOKinterface) + if (token.value == TOKstruct || + token.value == TOKunion || + token.value == TOKclass || + token.value == TOKinterface) { Dsymbol s = parseAggregate(); auto a = new Dsymbols(); @@ -4296,9 +4270,9 @@ final class Parser : Lexer a = new Dsymbols(); a.push(s); } - if (structalign != 0) + if (setAlignment) { - s = new AlignDeclaration(structalign, a); + s = new AlignDeclaration(s.loc, ealign, a); a = new Dsymbols(); a.push(s); } @@ -4524,11 +4498,11 @@ final class Parser : Lexer auto tempdecl = new TemplateDeclaration(loc, ident, tpl, null, a2, 0); s = tempdecl; } - if (structalign != 0) + if (setAlignment) { auto ax = new Dsymbols(); ax.push(s); - s = new AlignDeclaration(structalign, ax); + s = new AlignDeclaration(v.loc, ealign, ax); } if (link != linkage) { diff --git a/src/scope.h b/src/scope.h index 0a3ecf7a3d04..c041391d2a22 100644 --- a/src/scope.h +++ b/src/scope.h @@ -105,7 +105,8 @@ struct Scope unsigned *fieldinit; size_t fieldinit_dim; - structalign_t structalign; // alignment for struct members + AlignDeclaration *aligndecl; // alignment for struct members + LINK linkage; // linkage for external functions PINLINE inlining; // inlining strategy for functions @@ -153,6 +154,8 @@ struct Scope ClassDeclaration *getClassScope(); AggregateDeclaration *getStructClassScope(); void setNoFree(); + + structalign_t alignment(); }; #endif /* DMD_SCOPE_H */ diff --git a/test/compilable/extra-files/header1.di b/test/compilable/extra-files/header1.di index f932d3c042ab..06625fa62991 100644 --- a/test/compilable/extra-files/header1.di +++ b/test/compilable/extra-files/header1.di @@ -323,7 +323,7 @@ version (unittest) { public {} extern (C) {} - align{} + align {} } template Foo10334(T) if (Bar10334!()) { diff --git a/test/compilable/extra-files/header1i.di b/test/compilable/extra-files/header1i.di index 44f9b4f06343..e7e4987056be 100644 --- a/test/compilable/extra-files/header1i.di +++ b/test/compilable/extra-files/header1i.di @@ -448,7 +448,7 @@ version (unittest) { public {} extern (C) {} - align{} + align {} } template Foo10334(T) if (Bar10334!()) { diff --git a/test/compilable/extra-files/header2.d b/test/compilable/extra-files/header2.d index b0d8019e2c4d..f211c784c433 100644 --- a/test/compilable/extra-files/header2.d +++ b/test/compilable/extra-files/header2.d @@ -139,3 +139,13 @@ void test13275() foreach (shared (int) e; [1,2]) {} foreach (shared const(int) e; [1,2]) {} } + +// 9766 +align (1) struct S9766 +{ +align (true ? 2 : 3): + int var1; + +align: + int var2; +} diff --git a/test/compilable/extra-files/header2.di b/test/compilable/extra-files/header2.di index d35bf91e0032..d729b6c8a275 100644 --- a/test/compilable/extra-files/header2.di +++ b/test/compilable/extra-files/header2.di @@ -97,3 +97,11 @@ void foo11217()(inout int[] arr) { } void test13275(); +align (1) struct S9766 +{ + align (true ? 2 : 3) + { + int var1; + align int var2; + } +} diff --git a/test/compilable/extra-files/header2i.di b/test/compilable/extra-files/header2i.di index dbc88fe4dc31..c578dbc27e7e 100644 --- a/test/compilable/extra-files/header2i.di +++ b/test/compilable/extra-files/header2i.di @@ -199,3 +199,11 @@ void test13275() { } } +align (1) struct S9766 +{ + align (true ? 2 : 3) + { + int var1; + align int var2; + } +} diff --git a/test/compilable/test9766.d b/test/compilable/test9766.d new file mode 100644 index 000000000000..3cfc22f0464c --- /dev/null +++ b/test/compilable/test9766.d @@ -0,0 +1,77 @@ +// PERMUTE_ARGS: + +size_t getAlign9766(size_t n) { return n; } + +struct S9766 +{ +align(getAlign9766(1)): + ubyte[5] pad1; + ubyte var1; + +align(getAlign9766(2)): + ubyte[5] pad2; + ubyte var2; + +align(getAlign9766(4)): + ubyte[5] pad3; + ubyte var3; + +align(getAlign9766(8)): + ubyte[5] pad4; + ubyte var4; +} + +static assert(S9766.pad1.offsetof == 0); +static assert(S9766.var1.offsetof == 5); + +static assert(S9766.pad2.offsetof == 6); +static assert(S9766.var2.offsetof == 12); + +static assert(S9766.pad3.offsetof == 16); +static assert(S9766.var3.offsetof == 24); + +static assert(S9766.pad4.offsetof == 32); +static assert(S9766.var4.offsetof == 40); + +union U9766 +{ + struct + { + align(getAlign9766(1)): + ubyte[5] pad1; + ubyte var1; + + align(getAlign9766(2)): + ubyte[5] pad2; + ubyte var2; + + align(getAlign9766(4)): + ubyte[5] pad3; + ubyte var3; + + align(getAlign9766(8)): + ubyte[5] pad4; + ubyte var4; + } +} + +static assert(U9766.pad1.offsetof == 0); +static assert(U9766.var1.offsetof == 5); + +static assert(U9766.pad2.offsetof == 6); +static assert(U9766.var2.offsetof == 12); + +static assert(U9766.pad3.offsetof == 16); +static assert(U9766.var3.offsetof == 24); + +static assert(U9766.pad4.offsetof == 32); +static assert(U9766.var4.offsetof == 40); + +struct TestMaxAlign +{ +align(1u << 31): + ubyte a; + ubyte b; +} + +static assert(TestMaxAlign.b.offsetof == 2147483648u); diff --git a/test/fail_compilation/fail9766.d b/test/fail_compilation/fail9766.d new file mode 100644 index 000000000000..d75d1bc44e72 --- /dev/null +++ b/test/fail_compilation/fail9766.d @@ -0,0 +1,27 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9766.d(14): Error: cannot interpret Foo!int at compile time +fail_compilation/fail9766.d(17): Error: alignment must be an integer positive power of 2, not -1 +fail_compilation/fail9766.d(20): Error: alignment must be an integer positive power of 2, not 0 +fail_compilation/fail9766.d(23): Error: alignment must be an integer positive power of 2, not 3 +fail_compilation/fail9766.d(26): Error: alignment must be an integer positive power of 2, not 2147483649u +--- +*/ + +template Foo(T) {} + +align(Foo!int) +struct S9766a {} + +align(-1) +struct S9766b {} + +align(0) +struct S9766c {} + +align(3) +struct S9766d {} + +align((1u << 31) + 1) +struct S9766e {} diff --git a/test/fail_compilation/parseStc2.d b/test/fail_compilation/parseStc2.d index 840024a3472e..24bc822026e8 100644 --- a/test/fail_compilation/parseStc2.d +++ b/test/fail_compilation/parseStc2.d @@ -55,9 +55,9 @@ TEST_OUTPUT: --- fail_compilation/parseStc2.d(63): Error: redundant alignment attribute align fail_compilation/parseStc2.d(64): Error: redundant alignment attribute align(1) -fail_compilation/parseStc2.d(65): Error: conflicting alignment attribute align and align(1) -fail_compilation/parseStc2.d(66): Error: conflicting alignment attribute align(1) and align -fail_compilation/parseStc2.d(67): Error: conflicting alignment attribute align(1) and align(2) +fail_compilation/parseStc2.d(65): Error: redundant alignment attribute align(1) +fail_compilation/parseStc2.d(66): Error: redundant alignment attribute align +fail_compilation/parseStc2.d(67): Error: redundant alignment attribute align(2) --- */ align align void f11() {}