Author: Timm Baeder
Date: 2026-03-23T12:30:10+01:00
New Revision: 69fb96ba659fba8a720bcfa2b102182367fc63c6

URL: 
https://github.com/llvm/llvm-project/commit/69fb96ba659fba8a720bcfa2b102182367fc63c6
DIFF: 
https://github.com/llvm/llvm-project/commit/69fb96ba659fba8a720bcfa2b102182367fc63c6.diff

LOG: [clang][bytecode] __builtin_is_aligned needs a declaration (#188011)

Reject pointers to expressions.
Also remove the bytecode version of this test.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/InterpBuiltin.cpp
    clang/test/SemaCXX/builtin-align-cxx.cpp

Removed: 
    clang/test/AST/ByteCode/builtin-align-cxx.cpp


################################################################################
diff  --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp 
b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 96c97d1df0f38..214013396e885 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1221,12 +1221,23 @@ static bool 
interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC,
   if (!Ptr.isBlockPointer())
     return false;
 
+  const ValueDecl *PtrDecl = Ptr.getDeclDesc()->asValueDecl();
+  // We need a pointer for a declaration here.
+  if (!PtrDecl) {
+    if (BuiltinOp == Builtin::BI__builtin_is_aligned)
+      S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_compute)
+          << Alignment;
+    else
+      S.FFDiag(Call->getArg(0), diag::note_constexpr_alignment_adjust)
+          << Alignment;
+    return false;
+  }
+
   // For one-past-end pointers, we can't call getIndex() since it asserts.
   // Use getNumElems() instead which gives the correct index for past-end.
   unsigned PtrOffset =
       Ptr.isElementPastEnd() ? Ptr.getNumElems() : Ptr.getIndex();
-  CharUnits BaseAlignment =
-      S.getASTContext().getDeclAlign(Ptr.getDeclDesc()->asValueDecl());
+  CharUnits BaseAlignment = S.getASTContext().getDeclAlign(PtrDecl);
   CharUnits PtrAlign =
       BaseAlignment.alignmentAtOffset(CharUnits::fromQuantity(PtrOffset));
 

diff  --git a/clang/test/AST/ByteCode/builtin-align-cxx.cpp 
b/clang/test/AST/ByteCode/builtin-align-cxx.cpp
deleted file mode 100644
index 636d58383867a..0000000000000
--- a/clang/test/AST/ByteCode/builtin-align-cxx.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-// C++-specific checks for the alignment builtins
-// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only 
-verify=expected,both -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 %s -fsyntax-only 
-verify=ref,both
-
-// Check that we don't crash when using dependent types in __builtin_align:
-template <typename a, a b>
-void *c(void *d) { // both-note{{candidate template ignored}}
-  return __builtin_align_down(d, b);
-}
-
-struct x {};
-x foo;
-void test(void *value) {
-  c<int, 16>(value);
-  c<struct x, foo>(value); // both-error{{no matching function for call to 
'c'}}
-}
-
-template <typename T, long Alignment, long ArraySize = 16>
-void test_templated_arguments() {
-  T array[ArraySize];                                                          
 // both-error{{variable has incomplete type 'fwddecl'}}
-  static_assert(__is_same(decltype(__builtin_align_up(array, Alignment)), T 
*), // both-error{{requested alignment is not a power of 2}}
-                "return type should be the decayed array type");
-  static_assert(__is_same(decltype(__builtin_align_down(array, Alignment)), T 
*),
-                "return type should be the decayed array type");
-  static_assert(__is_same(decltype(__builtin_is_aligned(array, Alignment)), 
bool),
-                "return type should be bool");
-  T *x1 = __builtin_align_up(array, Alignment);
-  T *x2 = __builtin_align_down(array, Alignment);
-  bool x3 = __builtin_align_up(array, Alignment);
-}
-
-void test() {
-  test_templated_arguments<int, 32>(); // fine
-  test_templated_arguments<struct fwddecl, 16>();
-  // both-note@-1{{in instantiation of function template specialization 
'test_templated_arguments<fwddecl, 16L, 16L>'}}
-  // both-note@-2{{forward declaration of 'fwddecl'}}
-  test_templated_arguments<int, 7>(); // invalid alignment value
-  // both-note@-1{{in instantiation of function template specialization 
'test_templated_arguments<int, 7L, 16L>'}}
-}
-
-template <typename T, long ArraySize>
-void test_incorrect_alignment_without_instatiation(T value) {
-  int array[32];
-  static_assert(__is_same(decltype(__builtin_align_up(array, 31)), int *), // 
both-error{{requested alignment is not a power of 2}}
-                "return type should be the decayed array type");
-  static_assert(__is_same(decltype(__builtin_align_down(array, 7)), int *), // 
both-error{{requested alignment is not a power of 2}}
-                "return type should be the decayed array type");
-  static_assert(__is_same(decltype(__builtin_is_aligned(array, -1)), bool), // 
both-error{{requested alignment must be 1 or greater}}
-                "return type should be bool");
-  __builtin_align_up(array);       // both-error{{too few arguments to 
function call, expected 2, have 1}}
-  __builtin_align_up(array, 31);   // both-error{{requested alignment is not a 
power of 2}}
-  __builtin_align_down(array, 31); // both-error{{requested alignment is not a 
power of 2}}
-  __builtin_align_up(array, 31);   // both-error{{requested alignment is not a 
power of 2}}
-  __builtin_align_up(value, 31);   // This shouldn't want since the type is 
dependent
-  __builtin_align_up(value);       // Same here
-
-  __builtin_align_up(array, sizeof(sizeof(value)) - 1); // 
both-error{{requested alignment is not a power of 2}}
-  __builtin_align_up(array, value); // no diagnostic as the alignment is value 
dependent.
-  (void)__builtin_align_up(array, ArraySize); // The same above here
-}
-
-// The original fix for the issue above broke some legitimate code.
-// Here is a regression test:
-typedef __SIZE_TYPE__ size_t;
-void *allocate_impl(size_t size);
-template <typename T>
-T *allocate() {
-  constexpr size_t allocation_size =
-      __builtin_align_up(sizeof(T), sizeof(void *));
-  return static_cast<T *>(
-      __builtin_assume_aligned(allocate_impl(allocation_size), sizeof(void 
*)));
-}
-struct Foo {
-  int value;
-};
-void *test2() {
-  return allocate<struct Foo>();
-}
-
-// Check that pointers-to-members cannot be used:
-class MemPtr {
-public:
-  int data;
-  void func();
-  virtual void vfunc();
-};
-void test_member_ptr() {
-  __builtin_align_up(&MemPtr::data, 64);    // both-error{{operand of type 
'int MemPtr::*' where arithmetic or pointer type is required}}
-  __builtin_align_down(&MemPtr::func, 64);  // both-error{{operand of type 
'void (MemPtr::*)()' where arithmetic or pointer type is required}}
-  __builtin_is_aligned(&MemPtr::vfunc, 64); // both-error{{operand of type 
'void (MemPtr::*)()' where arithmetic or pointer type is required}}
-}
-
-void test_references(Foo &i) {
-  // Check that the builtins look at the referenced type rather than the 
reference itself.
-  (void)__builtin_align_up(i, 64);                            // 
both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
-  (void)__builtin_align_up(static_cast<Foo &>(i), 64);        // 
both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
-  (void)__builtin_align_up(static_cast<const Foo &>(i), 64);  // 
both-error{{operand of type 'const Foo' where arithmetic or pointer type is 
required}}
-  (void)__builtin_align_up(static_cast<Foo &&>(i), 64);       // 
both-error{{operand of type 'Foo' where arithmetic or pointer type is required}}
-  (void)__builtin_align_up(static_cast<const Foo &&>(i), 64); // 
both-error{{operand of type 'const Foo' where arithmetic or pointer type is 
required}}
-  (void)__builtin_align_up(&i, 64);
-}
-
-// Check that constexpr wrapper functions can be constant-evaluated.
-template <typename T>
-constexpr bool wrap_is_aligned(T ptr, long align) {
-  return __builtin_is_aligned(ptr, align);
-  // both-note@-1{{requested alignment -3 is not a positive power of two}}
-  // both-note@-2{{requested alignment 19 is not a positive power of two}}
-  // both-note@-3{{requested alignment must be 128 or less for type 'char'; 
4194304 is invalid}}
-}
-template <typename T>
-constexpr T wrap_align_up(T ptr, long align) {
-  return __builtin_align_up(ptr, align);
-  // both-note@-1{{requested alignment -2 is not a positive power of two}}
-  // both-note@-2{{requested alignment 18 is not a positive power of two}}
-  // both-note@-3{{requested alignment must be 2147483648 or less for type 
'int'; 8589934592 is invalid}}
-  // both-error@-4{{operand of type 'bool' where arithmetic or pointer type is 
required}}
-}
-
-template <typename T>
-constexpr T wrap_align_down(T ptr, long align) {
-  return __builtin_align_down(ptr, align);
-  // both-note@-1{{requested alignment -1 is not a positive power of two}}
-  // both-note@-2{{requested alignment 17 is not a positive power of two}}
-  // both-note@-3{{requested alignment must be 32768 or less for type 'short'; 
1048576 is invalid}}
-}
-
-constexpr int a1 = wrap_align_up(22, 32);
-static_assert(a1 == 32, "");
-constexpr int a2 = wrap_align_down(22, 16);
-static_assert(a2 == 16, "");
-constexpr bool a3 = wrap_is_aligned(22, 32);
-static_assert(!a3, "");
-static_assert(wrap_align_down(wrap_align_up(22, 16), 32) == 32, "");
-static_assert(wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 32), 
"");
-static_assert(!wrap_is_aligned(wrap_align_down(wrap_align_up(22, 16), 32), 
64), "");
-
-constexpr long const_value(long l) { return l; }
-// Check some invalid values during constant-evaluation
-static_assert(wrap_align_down(1, const_value(-1)), ""); // both-error{{not an 
integral constant expression}}
-// both-note@-1{{in call to}}
-static_assert(wrap_align_up(1, const_value(-2)), ""); // both-error{{not an 
integral constant expression}}
-// both-note@-1{{in call to}}
-static_assert(wrap_is_aligned(1, const_value(-3)), ""); // both-error{{not an 
integral constant expression}}
-// both-note@-1{{in call to}}
-static_assert(wrap_align_down(1, const_value(17)), ""); // both-error{{not an 
integral constant expression}}
-// both-note@-1{{in call to}}
-static_assert(wrap_align_up(1, const_value(18)), ""); // both-error{{not an 
integral constant expression}}
-// both-note@-1{{in call to}}
-static_assert(wrap_is_aligned(1, const_value(19)), ""); // both-error{{not an 
integral constant expression}}
-// both-note@-1{{in call to}}
-
-// Check invalid values for smaller types:
-static_assert(wrap_align_down(static_cast<short>(1), const_value(1 << 20)), 
""); // both-error{{not an integral constant expression}}
-// both-note@-1{{in call to }}
-// Check invalid boolean type
-static_assert(wrap_align_up(static_cast<int>(1), const_value(1ull << 33)), 
""); // both-error{{not an integral constant expression}}
-// both-note@-1{{in call to}}
-static_assert(wrap_is_aligned(static_cast<char>(1), const_value(1 << 22)), 
""); // both-error{{not an integral constant expression}}
-// both-note@-1{{in call to}}
-
-// Check invalid boolean type
-static_assert(wrap_align_up(static_cast<bool>(1), const_value(1 << 21)), ""); 
// both-error{{not an integral constant expression}}
-// both-note@-1{{in instantiation of function template specialization 
'wrap_align_up<bool>' requested here}}
-
-// Check constant evaluation for pointers:
-_Alignas(32) char align32array[128];
-static_assert(&align32array[0] == &align32array[0], "");
-// __builtin_align_up/down can be constant evaluated as a no-op for values
-// that are known to have greater alignment:
-static_assert(__builtin_align_up(&align32array[0], 32) == &align32array[0], 
"");
-static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
-static_assert(__builtin_align_down(&align32array[0], 4) == 
__builtin_align_up(&align32array[0], 8), "");
-// But it can not be evaluated if the alignment is greater than the minimum
-// known alignment, since in that case the value might be the same if it 
happens
-// to actually be aligned to 64 bytes at run time.
-static_assert(&align32array[0] == __builtin_align_up(&align32array[0], 64), 
""); // both-error{{not an integral constant expression}}
-// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 
64}}
-static_assert(__builtin_align_up(&align32array[0], 64) == 
__builtin_align_up(&align32array[0], 64), ""); // both-error{{not an integral 
constant expression}}
-// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 
64}}
-
-// However, we can compute in case the requested alignment is less than the
-// base alignment:
-static_assert(__builtin_align_up(&align32array[0], 4) == &align32array[0], "");
-static_assert(__builtin_align_up(&align32array[1], 4) == &align32array[4], "");
-static_assert(__builtin_align_up(&align32array[2], 4) == &align32array[4], "");
-static_assert(__builtin_align_up(&align32array[3], 4) == &align32array[4], "");
-static_assert(__builtin_align_up(&align32array[4], 4) == &align32array[4], "");
-static_assert(__builtin_align_up(&align32array[5], 4) == &align32array[8], "");
-static_assert(__builtin_align_up(&align32array[6], 4) == &align32array[8], "");
-static_assert(__builtin_align_up(&align32array[7], 4) == &align32array[8], "");
-static_assert(__builtin_align_up(&align32array[8], 4) == &align32array[8], "");
-
-static_assert(__builtin_align_down(&align32array[0], 4) == &align32array[0], 
"");
-static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], 
"");
-static_assert(__builtin_align_down(&align32array[2], 4) == &align32array[0], 
"");
-static_assert(__builtin_align_down(&align32array[3], 4) == &align32array[0], 
"");
-static_assert(__builtin_align_down(&align32array[4], 4) == &align32array[4], 
"");
-static_assert(__builtin_align_down(&align32array[5], 4) == &align32array[4], 
"");
-static_assert(__builtin_align_down(&align32array[6], 4) == &align32array[4], 
"");
-static_assert(__builtin_align_down(&align32array[7], 4) == &align32array[4], 
"");
-static_assert(__builtin_align_down(&align32array[8], 4) == &align32array[8], 
"");
-
-// Achieving the same thing using casts to uintptr_t is not allowed:
-static_assert((char *)((__UINTPTR_TYPE__)&align32array[7] & ~3) == 
&align32array[4], ""); // both-error{{not an integral constant expression}}
-
-static_assert(__builtin_align_down(&align32array[1], 4) == &align32array[0], 
"");
-static_assert(__builtin_align_down(&align32array[1], 64) == &align32array[0], 
""); // both-error{{not an integral constant expression}}
-// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 
64}}
-
-// Add some checks for __builtin_is_aligned:
-static_assert(__builtin_is_aligned(&align32array[0], 32), "");
-static_assert(__builtin_is_aligned(&align32array[4], 4), "");
-// We cannot constant evaluate whether the array is aligned to > 32 since this
-// may well be true at run time.
-static_assert(!__builtin_is_aligned(&align32array[0], 64), ""); // 
both-error{{not an integral constant expression}}
-// both-note@-1{{cannot constant evaluate whether run-time alignment is at 
least 64}}
-
-// However, if the alignment being checked is less than the minimum alignment 
of
-// the base object we can check the low bits of the alignment:
-static_assert(__builtin_is_aligned(&align32array[0], 4), "");
-static_assert(!__builtin_is_aligned(&align32array[1], 4), "");
-static_assert(!__builtin_is_aligned(&align32array[2], 4), "");
-static_assert(!__builtin_is_aligned(&align32array[3], 4), "");
-static_assert(__builtin_is_aligned(&align32array[4], 4), "");
-
-// TODO: this should evaluate to true even though we can't evaluate the result
-//  of __builtin_align_up() to a concrete value
-static_assert(__builtin_is_aligned(__builtin_align_up(&align32array[0], 64), 
64), ""); // both-error{{not an integral constant expression}}
-// both-note@-1{{cannot constant evaluate the result of adjusting alignment to 
64}}
-
-// Check 
diff erent source and alignment type widths are handled correctly.
-static_assert(!__builtin_is_aligned(static_cast<signed long>(7), 
static_cast<signed short>(4)), "");
-static_assert(!__builtin_is_aligned(static_cast<signed short>(7), 
static_cast<signed long>(4)), "");
-// Also check signed -- unsigned mismatch.
-static_assert(!__builtin_is_aligned(static_cast<signed long>(7), 
static_cast<signed long>(4)), "");
-static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), 
static_cast<unsigned long>(4)), "");
-static_assert(!__builtin_is_aligned(static_cast<signed long>(7), 
static_cast<unsigned long>(4)), "");
-static_assert(!__builtin_is_aligned(static_cast<unsigned long>(7), 
static_cast<signed long>(4)), "");
-static_assert(!__builtin_is_aligned(static_cast<signed long>(7), 
static_cast<unsigned short>(4)), "");
-static_assert(!__builtin_is_aligned(static_cast<unsigned short>(7), 
static_cast<signed long>(4)), "");
-
-// Check that one-past-end pointers work correctly (GH#178647).
-static_assert(__builtin_align_up(&align32array[128], 4) == align32array + 128, 
"");
-
-// Check the diagnostic message
-_Alignas(void) char align_void_array[1]; // both-error {{invalid application 
of '_Alignas' to an incomplete type 'void'}}

diff  --git a/clang/test/SemaCXX/builtin-align-cxx.cpp 
b/clang/test/SemaCXX/builtin-align-cxx.cpp
index d18bc2bf66551..806bb660e0042 100644
--- a/clang/test/SemaCXX/builtin-align-cxx.cpp
+++ b/clang/test/SemaCXX/builtin-align-cxx.cpp
@@ -1,5 +1,6 @@
 // C++-specific checks for the alignment builtins
 // RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 -o - %s 
-fsyntax-only -verify
+// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -std=c++11 -o - %s 
-fsyntax-only -verify -fexperimental-new-constant-interpreter
 
 // Check that we don't crash when using dependent types in __builtin_align:
 template <typename a, a b>
@@ -239,5 +240,11 @@ static_assert(!__builtin_is_aligned(static_cast<unsigned 
long>(7), static_cast<s
 static_assert(!__builtin_is_aligned(static_cast<signed long>(7), 
static_cast<unsigned short>(4)), "");
 static_assert(!__builtin_is_aligned(static_cast<unsigned short>(7), 
static_cast<signed long>(4)), "");
 
+// Check that one-past-end pointers work correctly (GH#178647).
+static_assert(__builtin_align_up(&align32array[128], 4) == align32array + 128, 
"");
+
 // Check the diagnostic message
 _Alignas(void) char align_void_array[1]; // expected-error {{invalid 
application of '_Alignas' to an incomplete type 'void'}}
+
+static_assert(!__builtin_is_aligned(&"", 4), ""); // expected-error {{not an 
integral constant expression}} \
+                                                  // expected-note {{cannot 
constant evaluate whether run-time alignment is at least 4}}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to