blob: 190f352c26d4a1d7cc23de2619e76a24899b9e6a [file] [log] [blame]
Alex Richardson8c387cb2020-01-09 20:48:06 +00001// C++-specific checks for the alignment builtins
2// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 -o - %s -fsyntax-only -verify
3
4// Check that we don't crash when using dependent types in __builtin_align:
5template <typename a, a b>
6void *c(void *d) { // expected-note{{candidate template ignored}}
7 return __builtin_align_down(d, b);
8}
9
10struct x {};
11x foo;
12void test(void *value) {
13 c<int, 16>(value);
14 c<struct x, foo>(value); // expected-error{{no matching function for call to 'c'}}
15}
16
17template <typename T, long Alignment, long ArraySize = 16>
18void test_templated_arguments() {
19 T array[ArraySize]; // expected-error{{variable has incomplete type 'fwddecl'}}
20 static_assert(__is_same(decltype(__builtin_align_up(array, Alignment)), T *), // expected-error{{requested alignment is not a power of 2}}
21 "return type should be the decayed array type");
22 static_assert(__is_same(decltype(__builtin_align_down(array, Alignment)), T *),
23 "return type should be the decayed array type");
24 static_assert(__is_same(decltype(__builtin_is_aligned(array, Alignment)), bool),
25 "return type should be bool");
26 T *x1 = __builtin_align_up(array, Alignment);
27 T *x2 = __builtin_align_down(array, Alignment);
28 bool x3 = __builtin_align_up(array, Alignment);
29}
30
31void test() {
32 test_templated_arguments<int, 32>(); // fine
33 test_templated_arguments<struct fwddecl, 16>();
34 // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments<fwddecl, 16, 16>'}}
35 // expected-note@-2{{forward declaration of 'fwddecl'}}
36 test_templated_arguments<int, 7>(); // invalid alignment value
37 // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments<int, 7, 16>'}}
38}
39
40template <typename T>
41void test_incorrect_alignment_without_instatiation(T value) {
42 int array[32];
43 static_assert(__is_same(decltype(__builtin_align_up(array, 31)), int *), // expected-error{{requested alignment is not a power of 2}}
44 "return type should be the decayed array type");
45 static_assert(__is_same(decltype(__builtin_align_down(array, 7)), int *), // expected-error{{requested alignment is not a power of 2}}
46 "return type should be the decayed array type");
47 static_assert(__is_same(decltype(__builtin_is_aligned(array, -1)), bool), // expected-error{{requested alignment must be 1 or greater}}
48 "return type should be bool");
49 __builtin_align_up(array); // expected-error{{too few arguments to function call, expected 2, have 1}}
50 __builtin_align_up(array, 31); // expected-error{{requested alignment is not a power of 2}}
51 __builtin_align_down(array, 31); // expected-error{{requested alignment is not a power of 2}}
52 __builtin_align_up(array, 31); // expected-error{{requested alignment is not a power of 2}}
53 __builtin_align_up(value, 31); // This shouldn't want since the type is dependent
54 __builtin_align_up(value); // Same here
55}
56
57// The original fix for the issue above broke some legitimate code.
58// Here is a regression test:
59typedef __SIZE_TYPE__ size_t;
60void *allocate_impl(size_t size);
61template <typename T>
62T *allocate() {
63 constexpr size_t allocation_size =
64 __builtin_align_up(sizeof(T), sizeof(void *));
65 return static_cast<T *>(
66 __builtin_assume_aligned(allocate_impl(allocation_size), sizeof(void *)));
67}
68struct Foo {
69 int value;
70};
71void *test2() {
72 return allocate<struct Foo>();
73}
74
75// Check that pointers-to-members cannot be used:
76class MemPtr {
77public:
78 int data;
79 void func();
80 virtual void vfunc();
81};
82void test_member_ptr() {
83 __builtin_align_up(&MemPtr::data, 64); // expected-error{{operand of type 'int MemPtr::*' where arithmetic or pointer type is required}}
84 __builtin_align_down(&MemPtr::func, 64); // expected-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}
85 __builtin_is_aligned(&MemPtr::vfunc, 64); // expected-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}
86}
87
88void test_references(Foo &i) {
89 // Check that the builtins look at the referenced type rather than the reference itself.
90 (void)__builtin_align_up(i, 64); // expected-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
91 (void)__builtin_align_up(static_cast<Foo &>(i), 64); // expected-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
92 (void)__builtin_align_up(static_cast<const Foo &>(i), 64); // expected-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}
93 (void)__builtin_align_up(static_cast<Foo &&>(i), 64); // expected-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
94 (void)__builtin_align_up(static_cast<const Foo &&>(i), 64); // expected-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}
95 (void)__builtin_align_up(&i, 64);
96}
97
98// Check that constexpr wrapper functions can be constant-evaluated.
99template <typename T>
100constexpr bool wrap_is_aligned(T ptr, long align) {
101 return __builtin_is_aligned(ptr, align);
102 // expected-note@-1{{requested alignment -3 is not a positive power of two}}
103 // expected-note@-2{{requested alignment 19 is not a positive power of two}}
104 // expected-note@-3{{requested alignment must be 128 or less for type 'char'; 4194304 is invalid}}
105}
106template <typename T>
107constexpr T wrap_align_up(T ptr, long align) {
108 return __builtin_align_up(ptr, align);
109 // expected-note@-1{{requested alignment -2 is not a positive power of two}}
110 // expected-note@-2{{requested alignment 18 is not a positive power of two}}
111 // expected-note@-3{{requested alignment must be 2147483648 or less for type 'int'; 8589934592 is invalid}}
112 // expected-error@-4{{operand of type 'bool' where arithmetic or pointer type is required}}
113}
114
115template <typename T>
116constexpr T wrap_align_down(T ptr, long align) {
117 return __builtin_align_down(ptr, align);
118 // expected-note@-1{{requested alignment -1 is not a positive power of two}}
119 // expected-note@-2{{requested alignment 17 is not a positive power of two}}
120 // expected-note@-3{{requested alignment must be 32768 or less for type 'short'; 1048576 is invalid}}
121}
122
123constexpr int a1 = wrap_align_up(22, 32);
124static_assert(a1 == 32, "");
125constexpr int a2 = wrap_align_down(22, 16);
126static_assert(a2 == 16, "");
127constexpr bool a3 = wrap_is_aligned(22, 32);
128static_assert(!a3, "");
129static_assert(wrap_align_down(wrap_align_up(22, 16), 32) == 32, "");
130static_assert(wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 32), "");
131static_assert(!wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 64), "");
132
133constexpr long const_value(long l) { return l; }
134// Check some invalid values during constant-evaluation
135static_assert(wrap_align_down(1, const_value(-1)), ""); // expected-error{{not an integral constant expression}}
136// expected-note@-1{{in call to 'wrap_align_down(1, -1)'}}
137static_assert(wrap_align_up(1, const_value(-2)), ""); // expected-error{{not an integral constant expression}}
138// expected-note@-1{{in call to 'wrap_align_up(1, -2)'}}
139static_assert(wrap_is_aligned(1, const_value(-3)), ""); // expected-error{{not an integral constant expression}}
140// expected-note@-1{{in call to 'wrap_is_aligned(1, -3)'}}
141static_assert(wrap_align_down(1, const_value(17)), ""); // expected-error{{not an integral constant expression}}
142// expected-note@-1{{in call to 'wrap_align_down(1, 17)'}}
143static_assert(wrap_align_up(1, const_value(18)), ""); // expected-error{{not an integral constant expression}}
144// expected-note@-1{{in call to 'wrap_align_up(1, 18)'}}
145static_assert(wrap_is_aligned(1, const_value(19)), ""); // expected-error{{not an integral constant expression}}
146// expected-note@-1{{in call to 'wrap_is_aligned(1, 19)'}}
147
148// Check invalid values for smaller types:
149static_assert(wrap_align_down(static_cast<short>(1), const_value(1 << 20)), ""); // expected-error{{not an integral constant expression}}
150// expected-note@-1{{in call to 'wrap_align_down(1, 1048576)'}}
151// Check invalid boolean type
152static_assert(wrap_align_up(static_cast<int>(1), const_value(1ull << 33)), ""); // expected-error{{not an integral constant expression}}
153// expected-note@-1{{in call to 'wrap_align_up(1, 8589934592)'}}
154static_assert(wrap_is_aligned(static_cast<char>(1), const_value(1 << 22)), ""); // expected-error{{not an integral constant expression}}
155// expected-note@-1{{in call to 'wrap_is_aligned(1, 4194304)'}}
156
157// Check invalid boolean type
158static_assert(wrap_align_up(static_cast<bool>(1), const_value(1 << 21)), ""); // expected-error{{not an integral constant expression}}
159// expected-note@-1{{in instantiation of function template specialization 'wrap_align_up<bool>' requested here}}
160
161// Check constant evaluation for pointers:
162_Alignas(32) char align32array[128];
163static_assert(&align32array[0] == &align32array[0], "");
164// __builtin_align_up/down can be constant evaluated as a no-op for values
165// that are known to have greater alignment:
166static_assert(__builtin_align_up(&align32array[0], 32) == &align32array[0], "");
167static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
168static_assert(__builtin_align_down(&align32array[0], 4) == __builtin_align_up(&align32array[0], 8), "");
169// But it can not be evaluated if the alignment is greater than the minimum
170// known alignment, since in that case the value might be the same if it happens
171// to actually be aligned to 64 bytes at run time.
172static_assert(&align32array[0] == __builtin_align_up(&align32array[0], 64), ""); // expected-error{{not an integral constant expression}}
173// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}
174static_assert(__builtin_align_up(&align32array[0], 64) == __builtin_align_up(&align32array[0], 64), ""); // expected-error{{not an integral constant expression}}
175// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}
176
177// However, we can compute in case the requested alignment is less than the
178// base alignment:
179static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
180static_assert(__builtin_align_up(&align32array[1], 4) == &align32array[4], "");
181static_assert(__builtin_align_up(&align32array[2], 4) == &align32array[4], "");
182static_assert(__builtin_align_up(&align32array[3], 4) == &align32array[4], "");
183static_assert(__builtin_align_up(&align32array[4], 4) == &align32array[4], "");
184static_assert(__builtin_align_up(&align32array[5], 4) == &align32array[8], "");
185static_assert(__builtin_align_up(&align32array[6], 4) == &align32array[8], "");
186static_assert(__builtin_align_up(&align32array[7], 4) == &align32array[8], "");
187static_assert(__builtin_align_up(&align32array[8], 4) == &align32array[8], "");
188
189static_assert(__builtin_align_down(&align32array[0], 4) == &align32array[0], "");
190static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");
191static_assert(__builtin_align_down(&align32array[2], 4) == &align32array[0], "");
192static_assert(__builtin_align_down(&align32array[3], 4) == &align32array[0], "");
193static_assert(__builtin_align_down(&align32array[4], 4) == &align32array[4], "");
194static_assert(__builtin_align_down(&align32array[5], 4) == &align32array[4], "");
195static_assert(__builtin_align_down(&align32array[6], 4) == &align32array[4], "");
196static_assert(__builtin_align_down(&align32array[7], 4) == &align32array[4], "");
197static_assert(__builtin_align_down(&align32array[8], 4) == &align32array[8], "");
198
199// Achiving the same thing using casts to uintptr_t is not allowed:
200static_assert((char *)((__UINTPTR_TYPE__)&align32array[7] & ~3) == &align32array[4], ""); // expected-error{{not an integral constant expression}}
201
202static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");
203static_assert(__builtin_align_down(&align32array[1], 64) == &align32array[0], ""); // expected-error{{not an integral constant expression}}
204// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}
205
206// Add some checks for __builtin_is_aligned:
207static_assert(__builtin_is_aligned(&align32array[0], 32), "");
208static_assert(__builtin_is_aligned(&align32array[4], 4), "");
209// We cannot constant evaluate whether the array is aligned to > 32 since this
210// may well be true at run time.
211static_assert(!__builtin_is_aligned(&align32array[0], 64), ""); // expected-error{{not an integral constant expression}}
212// expected-note@-1{{cannot constant evaluate whether run-time alignment is at least 64}}
213
214// However, if the alignment being checked is less than the minimum alignment of
215// the base object we can check the low bits of the alignment:
216static_assert(__builtin_is_aligned(&align32array[0], 4), "");
217static_assert(!__builtin_is_aligned(&align32array[1], 4), "");
218static_assert(!__builtin_is_aligned(&align32array[2], 4), "");
219static_assert(!__builtin_is_aligned(&align32array[3], 4), "");
220static_assert(__builtin_is_aligned(&align32array[4], 4), "");
221
222// TODO: this should evaluate to true even though we can't evaluate the result
223// of __builtin_align_up() to a concrete value
224static_assert(__builtin_is_aligned(__builtin_align_up(&align32array[0], 64), 64), ""); // expected-error{{not an integral constant expression}}
225// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}
226
227// Check different source and alignment type widths are handled correctly.
228static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed short>(4)), "");
229static_assert(!__builtin_is_aligned(static_cast<signed short>(7), static_cast<signed long>(4)), "");
230// Also check signed -- unsigned mismatch.
231static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed long>(4)), "");
232static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<unsigned long>(4)), "");
233static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned long>(4)), "");
234static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<signed long>(4)), "");
235static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned short>(4)), "");
236static_assert(!__builtin_is_aligned(static_cast<unsigned short>(7), static_cast<signed long>(4)), "");