mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 05:00:16 +03:00
The gnu attribute aligned() allows specifying the alignment of an entire struct, mostly as a syntatic convenience. This attribute allows compile-time integer expressions, but the parser was trying to evaluate them ahead of time by checking for an integer literal. Instead we need to preserve the expression and defer it to a later semantic stage. Accomplish this by emulating the behavior by specifying the alignment of the first member of the struct. I didn't change how __declspec(align(#)) parses as from the documentation it seems to only allow integer literals. Some light testing with cl.exe gives syntax errors when trying to use _Alignof() in that position.
This commit is contained in:
parent
69b2b10aef
commit
7dd0506aaf
6 changed files with 114 additions and 34 deletions
|
@ -1913,10 +1913,14 @@ final class CParser(AST) : Parser!AST
|
|||
break;
|
||||
}
|
||||
|
||||
if (specifier.alignExps && dt.isTypeFunction())
|
||||
error("no alignment-specifier for function declaration"); // C11 6.7.5-2
|
||||
if (specifier.alignExps && specifier.scw == SCW.xregister)
|
||||
error("no alignment-specifier for `register` storage class"); // C11 6.7.5-2
|
||||
|
||||
// Check alignasExp and not alignExps so that gnu
|
||||
// __atribute__((aligned())) is silently allowed, matching the
|
||||
// behavior of other compilers.
|
||||
if (specifier.alignasExp && dt.isTypeFunction())
|
||||
error(specifier.alignasExp.loc, "no alignment-specifier for function declaration"); // C11 6.7.5-2
|
||||
if (specifier.alignasExp && specifier.scw == SCW.xregister)
|
||||
error(specifier.alignasExp.loc, "no alignment-specifier for `register` storage class"); // C11 6.7.5-2
|
||||
|
||||
/* C11 6.9.1 Function Definitions
|
||||
* function-definition:
|
||||
|
@ -1960,8 +1964,8 @@ final class CParser(AST) : Parser!AST
|
|||
{
|
||||
if (token.value == TOK.assign)
|
||||
error("no initializer for typedef declaration");
|
||||
if (specifier.alignExps)
|
||||
error("no alignment-specifier for typedef declaration"); // C11 6.7.5-2
|
||||
if (specifier.alignasExp)
|
||||
error(specifier.alignasExp.loc, "no alignment-specifier for typedef declaration"); // C11 6.7.5-2
|
||||
|
||||
if (specifier.vector_size)
|
||||
{
|
||||
|
@ -2474,7 +2478,7 @@ final class CParser(AST) : Parser!AST
|
|||
else
|
||||
break;
|
||||
}
|
||||
t = cparseStruct(sloc, structOrUnion, tagSpecifier.packalign, symbols);
|
||||
t = cparseStruct(sloc, structOrUnion, tagSpecifier, symbols);
|
||||
tkwx = TKW.xtag;
|
||||
break;
|
||||
}
|
||||
|
@ -2536,6 +2540,7 @@ final class CParser(AST) : Parser!AST
|
|||
if (!specifier.alignExps)
|
||||
specifier.alignExps = new AST.Expressions(0);
|
||||
specifier.alignExps.push(exp);
|
||||
specifier.alignasExp = exp;
|
||||
|
||||
check(TOK.rightParenthesis);
|
||||
break;
|
||||
|
@ -3620,26 +3625,18 @@ final class CParser(AST) : Parser!AST
|
|||
if (token.value == TOK.leftParenthesis)
|
||||
{
|
||||
nextToken();
|
||||
if (token.value == TOK.int32Literal)
|
||||
{
|
||||
const n = token.unsvalue;
|
||||
if (n < 1 || n & (n - 1) || ushort.max < n)
|
||||
error("__attribute__((aligned(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n);
|
||||
specifier.packalign.set(cast(uint)n);
|
||||
specifier.packalign.setPack(true);
|
||||
nextToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
error("alignment value expected, not `%s`", token.toChars());
|
||||
nextToken();
|
||||
}
|
||||
|
||||
AST.Expression exp = cparseConstantExp();
|
||||
if (!specifier.alignExps)
|
||||
specifier.alignExps = new AST.Expressions(0);
|
||||
specifier.alignExps.push(exp);
|
||||
check(TOK.rightParenthesis);
|
||||
}
|
||||
/* ignore __attribute__((aligned)), which sets the alignment to the largest value for any data
|
||||
* type on the target machine. It's the opposite of __attribute__((packed))
|
||||
*/
|
||||
else
|
||||
{
|
||||
/* ignore __attribute__((aligned)), which sets the alignment to the largest value for any data
|
||||
* type on the target machine. It's the opposite of __attribute__((packed))
|
||||
*/
|
||||
}
|
||||
}
|
||||
else if (token.ident == Id.packed)
|
||||
{
|
||||
|
@ -3978,9 +3975,10 @@ final class CParser(AST) : Parser!AST
|
|||
* Returns:
|
||||
* type of the struct
|
||||
*/
|
||||
private AST.Type cparseStruct(Loc loc, TOK structOrUnion, structalign_t packalign, ref AST.Dsymbols* symbols)
|
||||
private AST.Type cparseStruct(Loc loc, TOK structOrUnion, ref Specifier specifier, ref AST.Dsymbols* symbols)
|
||||
{
|
||||
Identifier tag;
|
||||
auto packalign = specifier.packalign;
|
||||
|
||||
if (token.value == TOK.identifier)
|
||||
{
|
||||
|
@ -4013,7 +4011,7 @@ final class CParser(AST) : Parser!AST
|
|||
/* GNU Extensions
|
||||
* Parse the postfix gnu-attributes (opt)
|
||||
*/
|
||||
Specifier specifier;
|
||||
specifier.packalign = structalign_t();
|
||||
if (token.value == TOK.__attribute__)
|
||||
cparseGnuAttributes(specifier);
|
||||
if (!specifier.packalign.isUnknown)
|
||||
|
@ -4022,11 +4020,40 @@ final class CParser(AST) : Parser!AST
|
|||
packalign.setPack(specifier.packalign.isPack());
|
||||
foreach (ref d; (*members)[])
|
||||
{
|
||||
// skip possible static assert declarations
|
||||
if (d.isStaticAssert()) continue;
|
||||
|
||||
auto decls = new AST.Dsymbols(1);
|
||||
(*decls)[0] = d;
|
||||
d = new AST.AlignDeclaration(d.loc, specifier.packalign, decls);
|
||||
}
|
||||
}
|
||||
if (specifier.alignExps && specifier.alignExps.length)
|
||||
{
|
||||
// Align the entire struct by aligning the first member.
|
||||
if (members)
|
||||
{
|
||||
foreach (ref d; (*members)[])
|
||||
{
|
||||
// skip possible static assert declarations
|
||||
if (d.isStaticAssert()) continue;
|
||||
|
||||
if (AST.AlignDeclaration ad = d.isAlignDeclaration())
|
||||
{
|
||||
foreach (exp; *specifier.alignExps)
|
||||
ad.exps.push(exp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto decls = new AST.Dsymbols(1);
|
||||
(*decls)[0] = d;
|
||||
d = new AST.AlignDeclaration(d.loc, specifier.alignExps, decls);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!tag)
|
||||
error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
|
||||
|
@ -4178,8 +4205,8 @@ final class CParser(AST) : Parser!AST
|
|||
error("specifier-qualifier-list required");
|
||||
else if (width)
|
||||
{
|
||||
if (specifier.alignExps)
|
||||
error("no alignment-specifier for bit field declaration"); // C11 6.7.5-2
|
||||
if (specifier.alignasExp)
|
||||
error(specifier.alignasExp.loc, "no alignment-specifier for bit field declaration"); // C11 6.7.5-2
|
||||
auto s = new AST.BitFieldDeclaration(width.loc, dt, id, width);
|
||||
members.push(s);
|
||||
}
|
||||
|
@ -5155,6 +5182,7 @@ final class CParser(AST) : Parser!AST
|
|||
SCW scw; /// storage-class specifiers
|
||||
MOD mod; /// type qualifiers
|
||||
AST.Expressions* alignExps; /// alignment
|
||||
AST.Expression alignasExp; /// Last _Alignas() for errors
|
||||
structalign_t packalign; /// #pragma pack alignment value
|
||||
}
|
||||
|
||||
|
|
|
@ -1226,6 +1226,7 @@ extern (C++) class Dsymbol : ASTNode
|
|||
return null;
|
||||
}
|
||||
}
|
||||
inout(AlignDeclaration) isAlignDeclaration() inout { return dsym == DSYM.alignDeclaration ? cast(inout(AlignDeclaration)) cast(void*) this : null; }
|
||||
inout(AnonDeclaration) isAnonDeclaration() inout { return dsym == DSYM.anonDeclaration ? cast(inout(AnonDeclaration)) cast(void*) this : null; }
|
||||
inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return dsym == DSYM.cppNamespaceDeclaration ? cast(inout(CPPNamespaceDeclaration)) cast(void*) this : null; }
|
||||
inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return dsym == DSYM.visibilityDeclaration ? cast(inout(VisibilityDeclaration)) cast(void*) this : null; }
|
||||
|
|
|
@ -96,6 +96,7 @@ class Import;
|
|||
class EnumDeclaration;
|
||||
class SymbolDeclaration;
|
||||
class AttribDeclaration;
|
||||
class AlignDeclaration;
|
||||
class AnonDeclaration;
|
||||
class VisibilityDeclaration;
|
||||
class OverloadSet;
|
||||
|
@ -674,6 +675,7 @@ public:
|
|||
EnumDeclaration* isEnumDeclaration();
|
||||
SymbolDeclaration* isSymbolDeclaration();
|
||||
AttribDeclaration* isAttribDeclaration();
|
||||
AlignDeclaration* isAlignDeclaration();
|
||||
AnonDeclaration* isAnonDeclaration();
|
||||
CPPNamespaceDeclaration* isCPPNamespaceDeclaration();
|
||||
VisibilityDeclaration* isVisibilityDeclaration();
|
||||
|
|
43
compiler/test/compilable/test21150.c
Normal file
43
compiler/test/compilable/test21150.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
// https://github.com/dlang/dmd/issues/21150
|
||||
|
||||
struct S
|
||||
{
|
||||
char z[16][256];
|
||||
} __attribute__((aligned(_Alignof(unsigned int))));
|
||||
_Static_assert(_Alignof(struct S) == _Alignof(unsigned int), "S");
|
||||
|
||||
struct T {
|
||||
_Static_assert(1, "");
|
||||
char x;
|
||||
} __attribute__((aligned(_Alignof(struct S))));
|
||||
|
||||
_Static_assert(_Alignof(struct T) == _Alignof(unsigned int), "T");
|
||||
|
||||
|
||||
struct __attribute__ ((aligned(8))) Q {
|
||||
short f[3];
|
||||
};
|
||||
_Static_assert(sizeof(struct Q) == 8, "Q1");
|
||||
_Static_assert(_Alignof(struct Q) == 8, "Q2");
|
||||
|
||||
|
||||
struct __attribute__ ((aligned(8))) R {
|
||||
short f[3];
|
||||
char c;
|
||||
};
|
||||
_Static_assert(sizeof(struct R) == 8, "R1");
|
||||
_Static_assert(_Alignof(struct R) == 8, "R2");
|
||||
|
||||
struct C {
|
||||
unsigned _Alignas(2) _Alignas(4) char c;
|
||||
}
|
||||
__attribute__((aligned(8)));
|
||||
|
||||
_Static_assert(_Alignof(struct C)==8, "C");
|
||||
|
||||
struct __attribute__((aligned(4))) D {
|
||||
unsigned char c;
|
||||
}
|
||||
__attribute__((aligned(8)));
|
||||
|
||||
_Static_assert(_Alignof(struct D)==8, "D");
|
|
@ -2,13 +2,10 @@
|
|||
---
|
||||
fail_compilation/alignedext.i(10): Error: __decspec(align(123)) must be an integer positive power of 2 and be <= 8,192
|
||||
fail_compilation/alignedext.i(11): Error: __decspec(align(16384)) must be an integer positive power of 2 and be <= 8,192
|
||||
fail_compilation/alignedext.i(13): Error: __attribute__((aligned(123))) must be an integer positive power of 2 and be <= 32,768
|
||||
fail_compilation/alignedext.i(14): Error: __attribute__((aligned(65536))) must be an integer positive power of 2 and be <= 32,768
|
||||
|
||||
|
||||
---
|
||||
*/
|
||||
|
||||
typedef struct __declspec(align(123)) S { int a; } S;
|
||||
struct __declspec(align(16384)) T { int a; };
|
||||
|
||||
typedef struct __attribute__((aligned(123))) U { int a; } S;
|
||||
struct __attribute__((aligned(65536))) V { int a; };
|
||||
|
|
9
compiler/test/fail_compilation/alignedext2.i
Normal file
9
compiler/test/fail_compilation/alignedext2.i
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/alignedext2.i(8): Error: alignment must be an integer positive power of 2, not 0x7b
|
||||
fail_compilation/alignedext2.i(9): Error: alignment must be an integer positive power of 2, not 0x10000
|
||||
---
|
||||
*/
|
||||
|
||||
typedef struct __attribute__((aligned(123))) U { int a; } S;
|
||||
struct __attribute__((aligned(65536))) V { int a; };
|
Loading…
Add table
Add a link
Reference in a new issue