blob: 1326aed32a79ec2fd9ef62cffaf04cc2f4202f57 [file] [log] [blame]
/* Verify that __builtin_has_attribute detects attributes aligned
and packed in various forms of array dereferencing and indirection
expressions correspondingly to __alignof__.
{ dg-do compile }
{ dg-options "-Wall -Wno-unused -ftrack-macro-expansion=0" }
{ dg-require-effective-target size24plus } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
#define ALIGN(N) ATTR (aligned (N))
#define Assert(expr) typedef int _Assert [1 - 2 * !(expr)]
/* Verify that __builtin_has_attribute (EXPR, align (ALIGN)) returns
the EXPECTed result. When EXPECT is true, verify that the EXPression
has the expected ALIGNment. */
#define A3(expect, expr, align) do { \
Assert (!expect || __alignof__ (expr) == align); \
Assert (expect == __builtin_has_attribute (expr, aligned (align))); \
} while (0)
#define A(expect, expr) \
Assert (expect == __builtin_has_attribute (expr, aligned)) \
enum { PA = __alignof__ (void*) };
/* Define pointer to pointer types, with different alignments
at each level of indirection. */
typedef struct S8 { char a[8]; } S8;
typedef ALIGN (8) S8 I8;
typedef ALIGN (16) I8 *P16_I8;
typedef P16_I8 *P_P16_I8;
typedef ALIGN (32) P_P16_I8 *P32_P_P16_I8;
typedef P32_P_P16_I8 *P_P32_P_P16_I8;
typedef ALIGN (64) P_P32_P_P16_I8 *P64_P_P32_P_P16_I8;
Assert ( 8 == __alignof__ (I8));
Assert (16 == __alignof__ (P16_I8));
Assert (PA == __alignof__ (P_P16_I8));
Assert (32 == __alignof__ (P32_P_P16_I8));
Assert (PA == __alignof__ (P_P32_P_P16_I8));
Assert (64 == __alignof__ (P64_P_P32_P_P16_I8));
/* Similar to the pointer of pointers above, define array of array
types, with different alignments at each level of indirection. */
typedef struct S64 { char a[64]; } S64;
typedef ALIGN (64) S64 I64;
typedef ALIGN (32) I64 A32_I64[3];
typedef A32_I64 A_A32_I64[5];
typedef ALIGN (16) A_A32_I64 A16_A_A32_I64[7];
typedef A16_A_A32_I64 A_A16_A_A32_I64[11];
typedef ALIGN (8) A_A16_A_A32_I64 A8_A_A16_A_A32_I64[13];
Assert (64 == __alignof__ (I64));
Assert (32 == __alignof__ (A32_I64));
/* With no explicit alignment, an array of overaligned elements
is considered to have the alignment of its elements. */
Assert (32 == __alignof__ (A_A32_I64));
Assert (16 == __alignof__ (A16_A_A32_I64));
Assert (16 == __alignof__ (A_A16_A_A32_I64));
Assert ( 8 == __alignof__ (A8_A_A16_A_A32_I64));
void test_arrays (void)
{
/* Verify that the aligned attribute on each of the composite types
is detected corresponding to the result of __alignof__. */
A (1, (*(A8_A_A16_A_A32_I64*)0));
A3 (1, (*(A8_A_A16_A_A32_I64*)0), 8);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 8);
/* GCC propagates the user-align bit from element types to their
arrays but it doesn't propagate the attribute itself. The built-in
considers both the bit and the attribute so it succeeds below even
though the referenced type isn't declared with the attribute. */
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 8);
A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0], 16);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0], 32);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1], 8);
A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1], 16);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1], 32);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 16);
A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 32);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2], 64);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 16);
A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 32);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3], 64);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 32);
A3 (1, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 64);
A3 (0, (*(A8_A_A16_A_A32_I64*)0)[0][1][2][3][4], 128);
A8_A_A16_A_A32_I64 a;
A3 (0, a[0], 8);
A3 (1, a[0], 16);
A3 (0, a[0], 32);
A3 (0, a[0][1], 8);
A3 (1, a[0][1], 16);
A3 (0, a[0][1], 32);
A3 (0, a[0][1][2], 16);
A3 (1, a[0][1][2], 32);
A3 (0, a[0][1][2], 64);
A3 (0, a[0][1][2][3], 16);
A3 (1, a[0][1][2][3], 32);
A3 (0, a[0][1][2][3], 64);
A3 (0, a[0][1][2][3][4], 32);
A3 (1, a[0][1][2][3][4], 64);
A3 (0, a[0][1][2][3][4], 128);
}
void test_pointers (void)
{
/* Verify that the aligned attribute on each of the composite pointer
types is detected corresponding to the result of __alignof__. */
A (1, I8);
A3 (0, I8, 4);
A3 (1, I8, 8);
A (1, P16_I8);
A3 (0, P16_I8, 8);
A3 (1, P16_I8, 16);
A (0, P_P16_I8);
A3 (0, P_P16_I8, 8);
A3 (0, P_P16_I8, 16);
A (1, P32_P_P16_I8);
A3 (0, P32_P_P16_I8, 8);
A3 (0, P32_P_P16_I8, 16);
A3 (1, P32_P_P16_I8, 32);
A (0, P_P32_P_P16_I8);
A (1, P64_P_P32_P_P16_I8);
A3 (0, P64_P_P32_P_P16_I8, 8);
A3 (0, P64_P_P32_P_P16_I8, 16);
A3 (0, P64_P_P32_P_P16_I8, 32);
A3 (1, P64_P_P32_P_P16_I8, 64);
/* Verify that the attribute on each of the composite types is detected
in the type of each of the indirection expressions. */
A (1, *(P16_I8)0);
A3 (1, *(P16_I8)0, 8);
A3 (0, *(P16_I8)0, 16);
A (1, *(P_P16_I8)0);
A3 (0, *(P_P16_I8)0, 8);
A3 (1, *(P_P16_I8)0, 16);
A (0, *(P32_P_P16_I8)0);
A3 (0, *(P32_P_P16_I8)0, 8);
A3 (0, *(P32_P_P16_I8)0, 16);
A3 (0, *(P32_P_P16_I8)0, 32);
A (1, *(P_P32_P_P16_I8)0);
A3 (1, *(P_P32_P_P16_I8)0, 32);
A (0, *(P64_P_P32_P_P16_I8)0);
/* Verify that the attribute on each of the composite types is detected
in the type of each of the subscipting expressions. */
A (1, ((P16_I8)0)[0]);
A3 (1, ((P16_I8)0)[1], 8);
A3 (0, ((P16_I8)0)[2], 16);
A (1, ((P_P16_I8)0)[3]);
A3 (0, ((P_P16_I8)0)[4], 8);
A3 (1, ((P_P16_I8)0)[5], 16);
A (0, ((P32_P_P16_I8)0)[6]);
A3 (0, ((P32_P_P16_I8)0)[7], 8);
A3 (0, ((P32_P_P16_I8)0)[8], 16);
A3 (0, ((P32_P_P16_I8)0)[9], 32);
A (1, ((P_P32_P_P16_I8)0)[10]);
A3 (1, ((P_P32_P_P16_I8)0)[11], 32);
A (0, ((P64_P_P32_P_P16_I8)0)[12]);
/* Verify that the attribute on each of the composite types is detected
in the type of each of the subscipting expression involving variables. */
I8 i8;
P16_I8 p16_i8 = &i8;
P_P16_I8 p_p16_i8 = &p16_i8;
P32_P_P16_I8 p32_p_p16_i8 = &p_p16_i8;
P_P32_P_P16_I8 p_p32_p_p16_i8 = &p32_p_p16_i8;
P64_P_P32_P_P16_I8 p64_p_p32_p_p16_i8 = &p_p32_p_p16_i8;
A (1, p16_i8[0]);
A3 (1, p16_i8[1], 8);
A3 (0, p16_i8[2], 16);
A (1, p_p16_i8[3]);
A3 (0, p_p16_i8[4], 8);
A3 (1, p_p16_i8[5], 16);
A (0, p32_p_p16_i8[6]);
A3 (0, p32_p_p16_i8[7], 8);
A3 (0, p32_p_p16_i8[8], 16);
A3 (0, p32_p_p16_i8[9], 32);
A (1, p_p32_p_p16_i8[10]);
A3 (1, p_p32_p_p16_i8[11], 32);
A (1, p_p16_i8[0][1]);
A3 (1, p_p16_i8[1][2], 8);
A3 (0, p_p16_i8[2][3], 16);
A (0, p64_p_p32_p_p16_i8[0]);
A (1, p64_p_p32_p_p16_i8[0][1]);
A3 (0, p64_p_p32_p_p16_i8[0][2], 16);
A3 (1, p64_p_p32_p_p16_i8[0][3], 32);
A3 (0, p64_p_p32_p_p16_i8[0][4], 64);
A (0, p64_p_p32_p_p16_i8[0][1][2]);
A (1, p64_p_p32_p_p16_i8[0][1][2][3]);
A3 (0, p64_p_p32_p_p16_i8[0][1][2][4], 8);
A3 (1, p64_p_p32_p_p16_i8[0][1][2][4], 16);
A3 (0, p64_p_p32_p_p16_i8[0][1][2][4], 32);
A (1, p64_p_p32_p_p16_i8[0][1][2][3][4]);
A3 (1, p64_p_p32_p_p16_i8[0][1][2][3][5], 8);
A3 (0, p64_p_p32_p_p16_i8[0][1][2][4][6], 16);
/* Same as above but using the indirection expression. */
A (0, *p64_p_p32_p_p16_i8);
A (1, **p64_p_p32_p_p16_i8);
A3 (0, **p64_p_p32_p_p16_i8, 16);
A3 (1, **p64_p_p32_p_p16_i8, 32);
A3 (0, **p64_p_p32_p_p16_i8, 64);
A (0, ***p64_p_p32_p_p16_i8);
A (1, ****p64_p_p32_p_p16_i8);
A3 (0, ****p64_p_p32_p_p16_i8, 8);
A3 (1, ****p64_p_p32_p_p16_i8, 16);
A3 (0, ****p64_p_p32_p_p16_i8, 32);
A (1, *****p64_p_p32_p_p16_i8);
A3 (1, *****p64_p_p32_p_p16_i8, 8);
A3 (0, *****p64_p_p32_p_p16_i8, 16);
}
S8 f_S8 (void);
I8 f_I8 (void);
P16_I8 f_P16_I8 (void);
P_P16_I8 f_P_P16_I8 (void);
P32_P_P16_I8 f_P32_P_P16_I8 (void);
P_P32_P_P16_I8 f_P_P32_P_P16_I8 (void);
P64_P_P32_P_P16_I8 f_P64_P_P32_P_P16_I8 (void);
void test_function_call (void)
{
/* Verify that the aligned attribute on each of the composite pointer
types returned by the functions is detected corresponding to
the result of __alignof__. */
A (0, f_S8 ());
A (1, f_I8 ());
A3 (1, f_I8 (), 8);
A3 (0, f_I8 (), 16);
A (1, f_P16_I8 ());
A3 (0, f_P16_I8 (), 8);
A3 (1, f_P16_I8 (), 16);
A3 (0, f_P16_I8 (), 32);
A (1, *f_P16_I8 ());
A3 (1, *f_P16_I8 (), 8);
A3 (0, *f_P16_I8 (), 16);
A (0, f_P_P16_I8 ());
A (1, *f_P_P16_I8 ());
A3 (0, *f_P_P16_I8 (), 8);
A3 (1, *f_P_P16_I8 (), 16);
A3 (0, *f_P_P16_I8 (), 32);
A (1, **f_P_P16_I8 ());
A3 (1, **f_P_P16_I8 (), 8);
A3 (0, **f_P_P16_I8 (), 16);
A3 (0, **f_P_P16_I8 (), 32);
}
void test_compound_literal (void)
{
A (0, (S8){ });
A (1, (I8){ });
A3 (1, (I8){ }, 8);
A3 (0, (I8){ }, 16);
A (1, (I64){ });
A3 (0, (I64){ }, 8);
A3 (0, (I64){ }, 16);
A3 (0, (I64){ }, 32);
A3 (1, (I64){ }, 64);
A (1, (A32_I64){ 0 });
A3 (0, (A32_I64){ 0 }, 8);
A3 (0, (A32_I64){ 0 }, 16);
A3 (1, (A32_I64){ 0 }, 32);
A3 (0, (A32_I64){ 0 }, 64);
A (1, ((A32_I64){ 0 })[0]);
A3 (0, ((A32_I64){ 0 })[0], 8);
A3 (0, ((A32_I64){ 0 })[0], 16);
A3 (0, ((A32_I64){ 0 })[0], 32);
A3 (1, ((A32_I64){ 0 })[0], 64);
}
void test_ternary_expression (int i)
{
A (0, (0 ? (S8){ } : (S8){ }));
A (1, (1 ? (I8){ } : (I8){ }));
A3 (1, (2 ? (I8){ } : (I8){ }), 8);
A3 (0, (3 ? (I8){ } : (I8){ }), 16);
A (1, (4 ? (I64){ } : (I64){ }));
A3 (0, (5 ? (I64){ } : (I64){ }), 8);
A3 (0, (6 ? (I64){ } : (I64){ }), 16);
A3 (0, (7 ? (I64){ } : (I64){ }), 32);
A3 (1, (8 ? (I64){ } : (I64){ }), 64);
#if !__cplusplus
/* Suppress -Wc++-compat warning: converting an array compound literal
to a pointer is ill-formed in C++ */
# pragma GCC diagnostic ignored "-Wc++-compat"
A (0, (9 ? (A32_I64){ } : (A32_I64){ }));
A3 (0, (i ? (A32_I64){ } : (A32_I64){ }), 8);
A3 (0, (i++ ? (A32_I64){ } : (A32_I64){ }), 16);
A3 (0, (++i ? (A32_I64){ } : (A32_I64){ }), 32);
A3 (0, (!i ? (A32_I64){ } : (A32_I64){ }), 64);
A (1, (0 ? (A32_I64){ } : (A32_I64){ })[0]);
A3 (0, (1 ? (A32_I64){ } : (A32_I64){ })[1], 8);
A3 (0, (2 ? (A32_I64){ } : (A32_I64){ })[2], 16);
A3 (0, (3 ? (A32_I64){ } : (A32_I64){ })[3], 32);
A3 (1, (3 ? (A32_I64){ } : (A32_I64){ })[i], 64);
#endif
}
void test_comma_expression (int i)
{
#if __cplusplus
/* In C++, the type of the comma expressions whose operand is an array
is the array itself with any attributes it was defined with. */
# define R 1
#else
/* In C, the type of the comma expressions whose operand is an array
is a pointer type that does not include any attributes the array
was defined with. */
# define R 0
/* Suppress -Wc++-compat warning: converting an array compound literal
to a pointer is ill-formed in C++
G++ accepts the conversion in unevaluated contexts without a warning. */
# pragma GCC diagnostic ignored "-Wc++-compat"
#endif
A (0, (0, (S8){ }));
A (1, (0, (I8){ }));
A3 (1, (1, (I8){ }), 8);
A3 (0, (2, (I8){ }), 16);
A (1, (3, (I64){ }));
A3 (0, (4, (I64){ }), 8);
A3 (0, (5, (I64){ }), 16);
A3 (0, (6, (I64){ }), 32);
A3 (1, (7, (I64){ }), 64);
A (R, (8, (A32_I64){ }));
A3 (0, (9, (A32_I64){ }), 8);
A3 (0, ((void)0, (A32_I64){ }), 16);
A3 (R, ((I64){ },(A32_I64){ }), 32);
A3 (0, (0, (A32_I64){ }), 64);
A (1, (1, ((A32_I64){ })[0]));
A3 (0, (2, ((A32_I64){ })[0]), 8);
A3 (0, (i++, ((A32_I64){ })[0]), 16);
A3 (0, (++i, ((A32_I64){ })[0]), 32);
A3 (1, (i = 0, ((A32_I64){ })[0]), 64);
}