[clang] [Clang] Make __builtin_assume_dereferenceable constexpr (PR #169869)

Nikolas Klauser via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 28 01:07:59 PST 2025


================
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -triple x86_64-unknown-unknown %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 -triple x86_64-unknown-unknown %s -fexperimental-new-constant-interpreter
+
+constexpr int arr[10] = {};
+
+constexpr bool test_constexpr_valid() {
+  __builtin_assume_dereferenceable(arr, 40);
+  return true;
+}
+static_assert(test_constexpr_valid(), "");
+
+constexpr bool test_constexpr_partial() {
+  __builtin_assume_dereferenceable(&arr[5], 20);
+  return true;
+}
+static_assert(test_constexpr_partial(), "");
+
+constexpr bool test_constexpr_nullptr() {
+  __builtin_assume_dereferenceable(nullptr, 4);
+  return true;
+}
+static_assert(test_constexpr_nullptr(), ""); // expected-error {{not an integral constant expression}}
+
+constexpr bool test_constexpr_too_large() {
+  __builtin_assume_dereferenceable(arr, 100);
+  return true;
+}
+static_assert(test_constexpr_too_large(), ""); // expected-error {{not an integral constant expression}}
+
+constexpr int single_var = 42;
+constexpr bool test_single_var() {
+  __builtin_assume_dereferenceable(&single_var, 4);
+  return true;
+}
+static_assert(test_single_var(), "");
+
+constexpr bool test_exact_boundary() {
+  __builtin_assume_dereferenceable(&arr[9], 4);
+  return true;
+}
+static_assert(test_exact_boundary(), "");
+
+constexpr bool test_one_over() {
+  __builtin_assume_dereferenceable(&arr[9], 5);
+  return true;
+}
+static_assert(test_one_over(), ""); // expected-error {{not an integral constant expression}}
+
+constexpr bool test_zero_size() {
+  __builtin_assume_dereferenceable(arr, 0);
+  return true;
+}
+static_assert(test_zero_size(), ""); // expected-error {{not an integral constant expression}}
+
+struct S {
+  int x;
+  int y;
+};
+constexpr S s = {1, 2};
+constexpr bool test_struct_member() {
+  __builtin_assume_dereferenceable(&s.x, 4);
+  return true;
+}
+static_assert(test_struct_member(), "");
----------------
philnik777 wrote:

It would be a valid implementation to just ignore the builtin I guess, but I'd be much happier if it actually checked that bytes are dereferenceable. That's quite useful to catch problems in loops that can return early. e.g. `find_if` requires the whole range to be dereferenceable, but may never actually reach the end of the data. The compiler is still allowed to read past the element that is returned, resulting potentially in crashes.

In general my goal is to catch all the UB possible during constant evaluation that the compiler can optimize on. With `__builtin_assume_dereferenceable` we currently can produce a program which, with identical inputs, is accepted during constant evaluation by the compiler but crashes during runtime. I'm aware of some other places this is the case, but I'd rather reduce that number, not increase it.

I'm not quite sure what you're asking in your example. It's not a constant expression at this point, is it?

https://github.com/llvm/llvm-project/pull/169869


More information about the cfe-commits mailing list