brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.6 KiB · d18bc2b Raw
244 lines · cpp
1// C++-specific checks for the alignment builtins2// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 -o - %s -fsyntax-only -verify3 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>(); // fine33  test_templated_arguments<struct fwddecl, 16>();34  // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments<fwddecl, 16L, 16L>'}}35  // expected-note@-2{{forward declaration of 'fwddecl'}}36  test_templated_arguments<int, 7>(); // invalid alignment value37  // expected-note@-1{{in instantiation of function template specialization 'test_templated_arguments<int, 7L, 16L>'}}38}39 40template <typename T, long ArraySize>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 dependent54  __builtin_align_up(value);       // Same here55 56  __builtin_align_up(array, sizeof(sizeof(value)) - 1); // expected-error{{requested alignment is not a power of 2}}57  __builtin_align_up(array, value); // no diagnostic as the alignment is value dependent.58  (void)__builtin_align_up(array, ArraySize); // The same above here59}60 61// The original fix for the issue above broke some legitimate code.62// Here is a regression test:63typedef __SIZE_TYPE__ size_t;64void *allocate_impl(size_t size);65template <typename T>66T *allocate() {67  constexpr size_t allocation_size =68      __builtin_align_up(sizeof(T), sizeof(void *));69  return static_cast<T *>(70      __builtin_assume_aligned(allocate_impl(allocation_size), sizeof(void *)));71}72struct Foo {73  int value;74};75void *test2() {76  return allocate<struct Foo>();77}78 79// Check that pointers-to-members cannot be used:80class MemPtr {81public:82  int data;83  void func();84  virtual void vfunc();85};86void test_member_ptr() {87  __builtin_align_up(&MemPtr::data, 64);    // expected-error{{operand of type 'int MemPtr::*' where arithmetic or pointer type is required}}88  __builtin_align_down(&MemPtr::func, 64);  // expected-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}89  __builtin_is_aligned(&MemPtr::vfunc, 64); // expected-error{{operand of type 'void (MemPtr::*)()' where arithmetic or pointer type is required}}90}91 92void test_references(Foo &i) {93  // Check that the builtins look at the referenced type rather than the reference itself.94  (void)__builtin_align_up(i, 64);                            // expected-error{{operand of type 'Foo' where arithmetic or pointer type is required}}95  (void)__builtin_align_up(static_cast<Foo &>(i), 64);        // expected-error{{operand of type 'Foo' where arithmetic or pointer type is required}}96  (void)__builtin_align_up(static_cast<const Foo &>(i), 64);  // expected-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}97  (void)__builtin_align_up(static_cast<Foo &&>(i), 64);       // expected-error{{operand of type 'Foo' where arithmetic or pointer type is required}}98  (void)__builtin_align_up(static_cast<const Foo &&>(i), 64); // expected-error{{operand of type 'const Foo' where arithmetic or pointer type is required}}99  (void)__builtin_align_up(&i, 64);100}101 102// Check that constexpr wrapper functions can be constant-evaluated.103template <typename T>104constexpr bool wrap_is_aligned(T ptr, long align) {105  return __builtin_is_aligned(ptr, align);106  // expected-note@-1{{requested alignment -3 is not a positive power of two}}107  // expected-note@-2{{requested alignment 19 is not a positive power of two}}108  // expected-note@-3{{requested alignment must be 128 or less for type 'char'; 4194304 is invalid}}109}110template <typename T>111constexpr T wrap_align_up(T ptr, long align) {112  return __builtin_align_up(ptr, align);113  // expected-note@-1{{requested alignment -2 is not a positive power of two}}114  // expected-note@-2{{requested alignment 18 is not a positive power of two}}115  // expected-note@-3{{requested alignment must be 2147483648 or less for type 'int'; 8589934592 is invalid}}116  // expected-error@-4{{operand of type 'bool' where arithmetic or pointer type is required}}117}118 119template <typename T>120constexpr T wrap_align_down(T ptr, long align) {121  return __builtin_align_down(ptr, align);122  // expected-note@-1{{requested alignment -1 is not a positive power of two}}123  // expected-note@-2{{requested alignment 17 is not a positive power of two}}124  // expected-note@-3{{requested alignment must be 32768 or less for type 'short'; 1048576 is invalid}}125}126 127constexpr int a1 = wrap_align_up(22, 32);128static_assert(a1 == 32, "");129constexpr int a2 = wrap_align_down(22, 16);130static_assert(a2 == 16, "");131constexpr bool a3 = wrap_is_aligned(22, 32);132static_assert(!a3, "");133static_assert(wrap_align_down(wrap_align_up(22, 16), 32) == 32, "");134static_assert(wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 32), "");135static_assert(!wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 64), "");136 137constexpr long const_value(long l) { return l; }138// Check some invalid values during constant-evaluation139static_assert(wrap_align_down(1, const_value(-1)), ""); // expected-error{{not an integral constant expression}}140// expected-note@-1{{in call to 'wrap_align_down<int>(1, -1)'}}141static_assert(wrap_align_up(1, const_value(-2)), ""); // expected-error{{not an integral constant expression}}142// expected-note@-1{{in call to 'wrap_align_up<int>(1, -2)'}}143static_assert(wrap_is_aligned(1, const_value(-3)), ""); // expected-error{{not an integral constant expression}}144// expected-note@-1{{in call to 'wrap_is_aligned<int>(1, -3)'}}145static_assert(wrap_align_down(1, const_value(17)), ""); // expected-error{{not an integral constant expression}}146// expected-note@-1{{in call to 'wrap_align_down<int>(1, 17)'}}147static_assert(wrap_align_up(1, const_value(18)), ""); // expected-error{{not an integral constant expression}}148// expected-note@-1{{in call to 'wrap_align_up<int>(1, 18)'}}149static_assert(wrap_is_aligned(1, const_value(19)), ""); // expected-error{{not an integral constant expression}}150// expected-note@-1{{in call to 'wrap_is_aligned<int>(1, 19)'}}151 152// Check invalid values for smaller types:153static_assert(wrap_align_down(static_cast<short>(1), const_value(1 << 20)), ""); // expected-error{{not an integral constant expression}}154// expected-note@-1{{in call to 'wrap_align_down<short>(1, 1048576)'}}155// Check invalid boolean type156static_assert(wrap_align_up(static_cast<int>(1), const_value(1ull << 33)), ""); // expected-error{{not an integral constant expression}}157// expected-note@-1{{in call to 'wrap_align_up<int>(1, 8589934592)'}}158static_assert(wrap_is_aligned(static_cast<char>(1), const_value(1 << 22)), ""); // expected-error{{not an integral constant expression}}159// expected-note@-1{{in call to 'wrap_is_aligned<char>(1, 4194304)'}}160 161// Check invalid boolean type162static_assert(wrap_align_up(static_cast<bool>(1), const_value(1 << 21)), ""); // expected-error{{not an integral constant expression}}163// expected-note@-1{{in instantiation of function template specialization 'wrap_align_up<bool>' requested here}}164 165// Check constant evaluation for pointers:166_Alignas(32) char align32array[128];167static_assert(&align32array[0] == &align32array[0], "");168// __builtin_align_up/down can be constant evaluated as a no-op for values169// that are known to have greater alignment:170static_assert(__builtin_align_up(&align32array[0], 32) == &align32array[0], "");171static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");172static_assert(__builtin_align_down(&align32array[0], 4) == __builtin_align_up(&align32array[0], 8), "");173// But it can not be evaluated if the alignment is greater than the minimum174// known alignment, since in that case the value might be the same if it happens175// to actually be aligned to 64 bytes at run time.176static_assert(&align32array[0] == __builtin_align_up(&align32array[0], 64), ""); // expected-error{{not an integral constant expression}}177// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}178static_assert(__builtin_align_up(&align32array[0], 64) == __builtin_align_up(&align32array[0], 64), ""); // expected-error{{not an integral constant expression}}179// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}180 181// However, we can compute in case the requested alignment is less than the182// base alignment:183static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");184static_assert(__builtin_align_up(&align32array[1], 4) == &align32array[4], "");185static_assert(__builtin_align_up(&align32array[2], 4) == &align32array[4], "");186static_assert(__builtin_align_up(&align32array[3], 4) == &align32array[4], "");187static_assert(__builtin_align_up(&align32array[4], 4) == &align32array[4], "");188static_assert(__builtin_align_up(&align32array[5], 4) == &align32array[8], "");189static_assert(__builtin_align_up(&align32array[6], 4) == &align32array[8], "");190static_assert(__builtin_align_up(&align32array[7], 4) == &align32array[8], "");191static_assert(__builtin_align_up(&align32array[8], 4) == &align32array[8], "");192 193static_assert(__builtin_align_down(&align32array[0], 4) == &align32array[0], "");194static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");195static_assert(__builtin_align_down(&align32array[2], 4) == &align32array[0], "");196static_assert(__builtin_align_down(&align32array[3], 4) == &align32array[0], "");197static_assert(__builtin_align_down(&align32array[4], 4) == &align32array[4], "");198static_assert(__builtin_align_down(&align32array[5], 4) == &align32array[4], "");199static_assert(__builtin_align_down(&align32array[6], 4) == &align32array[4], "");200static_assert(__builtin_align_down(&align32array[7], 4) == &align32array[4], "");201static_assert(__builtin_align_down(&align32array[8], 4) == &align32array[8], "");202 203// Achieving the same thing using casts to uintptr_t is not allowed:204static_assert((char *)((__UINTPTR_TYPE__)&align32array[7] & ~3) == &align32array[4], ""); // expected-error{{not an integral constant expression}}205 206static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], "");207static_assert(__builtin_align_down(&align32array[1], 64) == &align32array[0], ""); // expected-error{{not an integral constant expression}}208// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}209 210// Add some checks for __builtin_is_aligned:211static_assert(__builtin_is_aligned(&align32array[0], 32), "");212static_assert(__builtin_is_aligned(&align32array[4], 4), "");213// We cannot constant evaluate whether the array is aligned to > 32 since this214// may well be true at run time.215static_assert(!__builtin_is_aligned(&align32array[0], 64), ""); // expected-error{{not an integral constant expression}}216// expected-note@-1{{cannot constant evaluate whether run-time alignment is at least 64}}217 218// However, if the alignment being checked is less than the minimum alignment of219// the base object we can check the low bits of the alignment:220static_assert(__builtin_is_aligned(&align32array[0], 4), "");221static_assert(!__builtin_is_aligned(&align32array[1], 4), "");222static_assert(!__builtin_is_aligned(&align32array[2], 4), "");223static_assert(!__builtin_is_aligned(&align32array[3], 4), "");224static_assert(__builtin_is_aligned(&align32array[4], 4), "");225 226// TODO: this should evaluate to true even though we can't evaluate the result227//  of __builtin_align_up() to a concrete value228static_assert(__builtin_is_aligned(__builtin_align_up(&align32array[0], 64), 64), ""); // expected-error{{not an integral constant expression}}229// expected-note@-1{{cannot constant evaluate the result of adjusting alignment to 64}}230 231// Check different source and alignment type widths are handled correctly.232static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed short>(4)), "");233static_assert(!__builtin_is_aligned(static_cast<signed short>(7), static_cast<signed long>(4)), "");234// Also check signed -- unsigned mismatch.235static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<signed long>(4)), "");236static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<unsigned long>(4)), "");237static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned long>(4)), "");238static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), static_cast<signed long>(4)), "");239static_assert(!__builtin_is_aligned(static_cast<signed long>(7), static_cast<unsigned short>(4)), "");240static_assert(!__builtin_is_aligned(static_cast<unsigned short>(7), static_cast<signed long>(4)), "");241 242// Check the diagnostic message243_Alignas(void) char align_void_array[1]; // expected-error {{invalid application of '_Alignas' to an incomplete type 'void'}}244