1 // RUN: %clang_cc1 -triple x86_64-linux-gnu -DALIGN_BUILTIN=__builtin_align_down -DRETURNS_BOOL=0 %s -fsyntax-only -verify -Wpedantic
2 // RUN: %clang_cc1 -triple x86_64-linux-gnu -DALIGN_BUILTIN=__builtin_align_up   -DRETURNS_BOOL=0 %s -fsyntax-only -verify -Wpedantic
3 // RUN: %clang_cc1 -triple x86_64-linux-gnu -DALIGN_BUILTIN=__builtin_is_aligned -DRETURNS_BOOL=1 %s -fsyntax-only -verify -Wpedantic
4 
5 struct Aggregate {
6   int i;
7   int j;
8 };
9 enum Enum { EnumValue1,
10             EnumValue2 };
11 typedef __SIZE_TYPE__ size_t;
12 
test_parameter_types(char * ptr,size_t size)13 void test_parameter_types(char *ptr, size_t size) {
14   struct Aggregate agg;
15   enum Enum e = EnumValue2;
16   _Bool b = 0;
17 
18   // The first parameter can be any pointer or integer type:
19   (void)ALIGN_BUILTIN(ptr, 4);
20   (void)ALIGN_BUILTIN(size, 2);
21   (void)ALIGN_BUILTIN(12345, 2);
22   (void)ALIGN_BUILTIN(agg, 2);    // expected-error {{operand of type 'struct Aggregate' where arithmetic or pointer type is required}}
23   (void)ALIGN_BUILTIN(e, 2);      // expected-error {{operand of type 'enum Enum' where arithmetic or pointer type is required}}
24   (void)ALIGN_BUILTIN(b, 2);      // expected-error {{operand of type '_Bool' where arithmetic or pointer type is required}}
25   (void)ALIGN_BUILTIN((int)e, 2); // but with a cast it is fine
26   (void)ALIGN_BUILTIN((int)b, 2); // but with a cast it is fine
27 
28   // The second parameter must be an integer type (but not enum or _Bool):
29   (void)ALIGN_BUILTIN(ptr, size);
30   (void)ALIGN_BUILTIN(ptr, ptr);    // expected-error {{used type 'char *' where integer is required}}
31   (void)ALIGN_BUILTIN(ptr, agg);    // expected-error {{used type 'struct Aggregate' where integer is required}}
32   (void)ALIGN_BUILTIN(ptr, b);      // expected-error {{used type '_Bool' where integer is required}}
33   (void)ALIGN_BUILTIN(ptr, e);      // expected-error {{used type 'enum Enum' where integer is required}}
34   (void)ALIGN_BUILTIN(ptr, (int)e); // but with a cast enums are fine
35   (void)ALIGN_BUILTIN(ptr, (int)b); // but with a cast booleans are fine
36 
37   (void)ALIGN_BUILTIN(ptr, size);
38   (void)ALIGN_BUILTIN(size, size);
39 }
40 
test_result_unused(int i,int align)41 void test_result_unused(int i, int align) {
42   // -Wunused-result does not trigger for macros so we can't use ALIGN_BUILTIN()
43   // but need to explicitly call each function.
44   __builtin_align_up(i, align);   // expected-warning{{ignoring return value of function declared with const attribute}}
45   __builtin_align_down(i, align); // expected-warning{{ignoring return value of function declared with const attribute}}
46   __builtin_is_aligned(i, align); // expected-warning{{ignoring return value of function declared with const attribute}}
47   ALIGN_BUILTIN(i, align);        // no warning here
48 }
49 
50 #define check_same_type(type1, type2) __builtin_types_compatible_p(type1, type2) && __builtin_types_compatible_p(type1 *, type2 *)
51 
test_return_type(void * ptr,int i,long l)52 void test_return_type(void *ptr, int i, long l) {
53   char array[32];
54   __extension__ typedef typeof(ALIGN_BUILTIN(ptr, 4)) result_type_ptr;
55   __extension__ typedef typeof(ALIGN_BUILTIN(i, 4)) result_type_int;
56   __extension__ typedef typeof(ALIGN_BUILTIN(l, 4)) result_type_long;
57   __extension__ typedef typeof(ALIGN_BUILTIN(array, 4)) result_type_char_array;
58 #if RETURNS_BOOL
59   _Static_assert(check_same_type(_Bool, result_type_ptr), "Should return bool");
60   _Static_assert(check_same_type(_Bool, result_type_int), "Should return bool");
61   _Static_assert(check_same_type(_Bool, result_type_long), "Should return bool");
62   _Static_assert(check_same_type(_Bool, result_type_char_array), "Should return bool");
63 #else
64   _Static_assert(check_same_type(void *, result_type_ptr), "Should return void*");
65   _Static_assert(check_same_type(int, result_type_int), "Should return int");
66   _Static_assert(check_same_type(long, result_type_long), "Should return long");
67   // Check that we can use the alignment builtins on on array types (result should decay)
68   _Static_assert(check_same_type(char *, result_type_char_array),
69                  "Using the builtins on an array should yield the decayed type");
70 #endif
71 }
72 
test_invalid_alignment_values(char * ptr,long * longptr,size_t align)73 void test_invalid_alignment_values(char *ptr, long *longptr, size_t align) {
74   int x = 1;
75   (void)ALIGN_BUILTIN(ptr, 2);
76   (void)ALIGN_BUILTIN(longptr, 1024);
77   (void)ALIGN_BUILTIN(x, 32);
78 
79   (void)ALIGN_BUILTIN(ptr, 0); // expected-error {{requested alignment must be 1 or greater}}
80   (void)ALIGN_BUILTIN(ptr, 1);
81 #if RETURNS_BOOL
82   // expected-warning@-2 {{checking whether a value is aligned to 1 byte is always true}}
83 #else
84   // expected-warning@-4 {{aligning a value to 1 byte is a no-op}}
85 #endif
86   (void)ALIGN_BUILTIN(ptr, 3); // expected-error {{requested alignment is not a power of 2}}
87   (void)ALIGN_BUILTIN(x, 7);   // expected-error {{requested alignment is not a power of 2}}
88 
89   // check the maximum range for smaller types:
90   __UINT8_TYPE__ c = ' ';
91 
92   (void)ALIGN_BUILTIN(c, 128);        // this is fine
93   (void)ALIGN_BUILTIN(c, 256);        // expected-error {{requested alignment must be 128 or smaller}}
94   (void)ALIGN_BUILTIN(x, 1ULL << 31); // this is also fine
95   (void)ALIGN_BUILTIN(x, 1LL << 31);  // this is also fine
96   __INT32_TYPE__ i32 = 3;
97   __UINT32_TYPE__ u32 = 3;
98   // Maximum is the same for int32 and uint32
99   (void)ALIGN_BUILTIN(i32, 1ULL << 32);              // expected-error {{requested alignment must be 2147483648 or smaller}}
100   (void)ALIGN_BUILTIN(u32, 1ULL << 32);              // expected-error {{requested alignment must be 2147483648 or smaller}}
101   (void)ALIGN_BUILTIN(ptr, ((__int128)1) << 65);     // expected-error {{requested alignment must be 9223372036854775808 or smaller}}
102   (void)ALIGN_BUILTIN(longptr, ((__int128)1) << 65); // expected-error {{requested alignment must be 9223372036854775808 or smaller}}
103 
104   const int bad_align = 8 + 1;
105   (void)ALIGN_BUILTIN(ptr, bad_align); // expected-error {{requested alignment is not a power of 2}}
106 }
107 
108 // Check that it can be used in constant expressions:
constant_expression(int x)109 void constant_expression(int x) {
110   _Static_assert(__builtin_is_aligned(1024, 512), "");
111   _Static_assert(!__builtin_is_aligned(256, 512ULL), "");
112   _Static_assert(__builtin_align_up(33, 32) == 64, "");
113   _Static_assert(__builtin_align_down(33, 32) == 32, "");
114 
115   // But not if one of the arguments isn't constant:
116   _Static_assert(ALIGN_BUILTIN(33, x) != 100, ""); // expected-error {{static_assert expression is not an integral constant expression}}
117   _Static_assert(ALIGN_BUILTIN(x, 4) != 100, "");  // expected-error {{static_assert expression is not an integral constant expression}}
118 }
119 
120 // Check that it is a constant expression that can be assigned to globals:
121 int global1 = __builtin_align_down(33, 8);
122 int global2 = __builtin_align_up(33, 8);
123 _Bool global3 = __builtin_is_aligned(33, 8);
124 
125 extern void test_ptr(char *c);
test_array_and_fnptr(void)126 char *test_array_and_fnptr(void) {
127   char buf[1024];
128   // The builtins should also work on arrays (decaying the return type)
129   (void)(ALIGN_BUILTIN(buf, 16));
130   // But not on functions and function pointers:
131   (void)(ALIGN_BUILTIN(test_array_and_fnptr, 16));  // expected-error{{operand of type 'char *(void)' where arithmetic or pointer type is required}}
132   (void)(ALIGN_BUILTIN(&test_array_and_fnptr, 16)); // expected-error{{operand of type 'char *(*)(void)' where arithmetic or pointer type is required}}
133 }
134