summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/builtin-object-size-16.c
blob: 15721e5ce897d5309d6ec6b201fefe5c6b1cf58c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/* PR 71831 - __builtin_object_size poor results with no optimization
   Verify that even without optimization __builtin_object_size returns
   a meaningful result for a subset of simple expressins.  In cases
   where the result could not easily be made to match the one obtained
   with optimization the built-in was made to fail instead.  */
/* { dg-do run } */
/* { dg-options "-O0" } */

static int nfails;

#define TEST_FAILURE(line, obj, type, expect, result)		\
  __builtin_printf ("FAIL: line %i: __builtin_object_size("	\
		    #obj ", %i) == %zu, got %zu\n",		\
		    line, type, expect, result), ++nfails

#define bos(obj, type) __builtin_object_size (obj, type)
#define size(obj, n) ((size_t)n == X ? sizeof *obj : (size_t)n)

#define test(expect, type, obj)						\
  do {									\
    if (bos (obj, type)	!= size (obj, expect))				\
      TEST_FAILURE (__LINE__, obj, type, size (obj, expect), bos (obj, type)); \
  } while (0)

#define T(r0, r1, r2, r3, obj)			\
  do {						\
    test (r0, 0, obj);				\
    test (r1, 1, obj);				\
    test (r2, 2, obj);				\
    test (r3, 3, obj);				\
  } while (0)

/* For convenience.  Substitute for 'sizeof object' in test cases where
   the size can vary from target to target.  */
#define X  (size_t)0xdeadbeef

/* __builtin_object_size checking results are inconsistent for equivalent
   expressions (see bug 71831).  To avoid having duplicate the inconsistency
   at -O0 the built-in simply fails.  The results hardcoded in this test
   are those obtained with optimization (for easy comparison) but without
   optimization the macros below turn them into expected failures .  */
#if __OPTIMIZE__
#  define F0(n)    n
#  define F1(n)    n
#  define F2(n)    n
#  define F3(n)    n
#else
#  define F0(n)   -1
#  define F1(n)   -1
#  define F2(n)    0
#  define F3(n)    0
#endif

typedef __SIZE_TYPE__ size_t;

extern char ax[];
char ax2[];               /* { dg-warning "assumed to have one element" } */

extern char a0[0];
static char a1[1];
static char a2[2];
static char a9[9];

#if __SIZEOF_SHORT__ == 4
extern short ia0[0];
static short ia1[1];
static short ia9[9];
#elif __SIZEOF_INT__ == 4
extern int ia0[0];
static int ia1[1];
static int ia9[9];
#endif

static char a2x2[2][2];
static char a3x5[3][5];

struct Sx { char n, a[]; } sx;
struct S0 { char n, a[0]; } s0;
struct S1 { char n, a[1]; } s1;
struct S2 { char n, a[2]; } s2;
struct S9 { char n, a[9]; } s9;

struct S2x2 { char n, a[2][2]; } s2x2;
struct S3x5 { char n, a[3][5]; } s3x5;

static __attribute__ ((noclone, noinline)) void
test_arrays ()
{
  T (    -1,      -1,       0,       0,   ax);

  T (     0,       0,       0,       0,   a0);
  T (     1,       1,       1,       1,   ax2);

  T (     1,       1,       1,       1,   a1);
  T (     2,       2,       2,       2,   a2);
  T (     9,       9,       9,       9,   a9);

  T (     0,       0,       0,       0,   a0);
  T (     1,       1,       1,       1,   ax2);

  T (     0,       0,       0,       0,   ia0);
  T (     4,       4,       4,       4,   ia1);
  T (    36,      36,      36,      36,   ia9);

  /* Not all results for multidimensional arrays make sense (see
     bug 77293).  The expected results below simply reflect those
     obtained at -O2 (modulo the known limitations at -O1).  */
  T (     4,       4,       4,       4,   a2x2);
  T (     4,       4,       4,       4,   &a2x2[0]);
  T (     4,       2,       4,       2,   &a2x2[0][0]);
  T (     0,  F1  (0),      0,       0,   &a2x2 + 1);
  T (     2,  F1 ( 2),      2,  F3 ( 2),  &a2x2[0] + 1);
  T (     3,  F1 ( 1),      3,  F3 ( 3),  &a2x2[0][0] + 1);

  T (    15,      15,      15,      15,   a3x5);
  T (    15,       5,      15,       5,   &a3x5[0][0] + 0);
  T (    14,  F1 ( 4),     14,  F3 (14),  &a3x5[0][0] + 1);

  T (     1,       1,       1,       1,   a1 + 0);
  T (     0,  F1  (0),      0,       0,   a1 + 1);
  T (     0,  F1 ( 0),      0,       0,   &a1 + 1);
  /* In the following the offset is out of bounds which makes
     the expression undefined.  Still, verify that the returned
     size is zero (and not some large number).  */
  T (     0,  F1  (0),      0,       0,   a1 + 2);

  T (     2,       2,       2,       2,   a2 + 0);
  T (     1,  F1 ( 1),      1, F3 ( 1),   a2 + 1);
  T (     0,  F1 ( 0),      0,       0,   a2 + 2);
}

static __attribute__ ((noclone, noinline)) void
test_structs (struct Sx *psx, struct S0 *ps0, struct S1 *ps1, struct S9 *ps9)
{
  /* The expected size of a declared object with a flexible array member
     is sizeof sx in all __builtin_object_size types.  */
  T (     X,       X,       X,       X,   &sx);

  /* The expected size of an unknown object with a flexible array member
     is unknown in all __builtin_object_size types.  */
  T (    -1,      -1,       0,       0,   psx);

  /* The expected size of a flexible array member of a declared object
     is zero.  */
  T (     0,       0,       0,       0,   sx.a);

  /* The expected size of a flexible array member of an unknown object
     is unknown.  */
  T (    -1,      -1,       0,       0,   psx->a);

  /* The expected size of a declared object with a zero-length array member
     is sizeof sx in all __builtin_object_size types.  */
  T (     X,       X,       X,       X,   &s0);

  /* The expected size of an unknown object with a zero-length array member
     is unknown in all __builtin_object_size types.  */
  T (    -1,      -1,       0,       0,   ps0);

  /* The expected size of a zero-length array member of a declared object
     is zero.  */
  T (     0,       0,       0,       0,   s0.a);

  /* The expected size of a zero-length array member of an unknown object
     is unknown.  */
  T (    -1,      -1,       0,       0,   ps0->a);

  T (     X,       X,       X,       X,   &s1);
  T (     1,       1,       1,       1,   s1.a);
  T (     0,  F1 (0),       0,       0,   s1.a + 1);

  /* GCC treats arrays of all sizes that are the last member of a struct
     as flexible array members.  */
  T (    -1,      -1,       0,       0,   ps1);
  T (    -1,      -1,       0,       0,   ps1->a);
  T (    -1,      -1,       0,       0,   ps1->a + 1);

  T (     X,       X,       X,       X,   &s9);
  T (     9,       9,       9,       9,   s9.a);
  T (     9,       9,       9,       9,   s9.a + 0);
  T (     8,  F1 ( 8),      8, F3 (  8),  s9.a + 1);
  T (     7,  F1 ( 7),      7, F3 (  7),  s9.a + 2);
  T (     0,  F1 ( 0),      0, F3 (  0),  s9.a + 9);

  /* The following make little sense but see bug 77301.  */
  T (    -1,      -1,       0,       0,   ps9);
  T (    -1,      -1,       0,       0,   ps9->a);
  T (    -1,      -1,       0,       0,   ps9->a + 1);
}

int
main()
{
  test_arrays ();

  test_structs (&sx, &s0, &s1, &s9);

  if (nfails)
    __builtin_abort ();

  return 0;
}