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