Issue 107453
Summary [libc++][enhancement] Enable assertions unconditionally during constant evaluation
Labels libc++
Assignees
Reporter MitalAshok
    Undefined behaviour when calling a library function is unspecified ([[expr.const]p(6.1)](https://eel.is/c++draft/expr.const#6.1). However, it is strange that whether it is detected depends on if libc++ is built with assertions or not.

Consider <https://godbolt.org/z/Kx6ez5no5>:

```c++
#include <vector>

constexpr int f() {
  std::vector<int> v;
 v.reserve(1);
  int& i = v.front();  // Library UB
 v.push_back(4);
  return i;
}

static_assert(f() == 4);
```

This doesn't compile with assertions:

```
<source>:11:15: error: static assertion _expression_ is not an integral constant _expression_
   11 | static_assert(f() == 4);
      | ^~~~~~~~
/opt/compiler-explorer/clang-assertions-trunk-20240904/bin/../include/c++/v1/vector:652:5: note: subexpression not valid in a constant _expression_
  652 | _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector");
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-assertions-trunk-20240904/bin/../include/c++/v1/__assert:66:71: note: expanded from macro '_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS'
   66 | # define _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_expression_, message) _LIBCPP_ASSERT(_expression_, message)
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-assertions-trunk-20240904/bin/../include/c++/v1/__assert:23:10: note: expanded from macro '_LIBCPP_ASSERT'
   23 |        : _LIBCPP_ASSERTION_HANDLER(__FILE__ ":" _LIBCPP_TOSTRING(__LINE__) ": assertion " _LIBCPP_TOSTRING(            \
      | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 24 |              _expression_) " failed: " message "\n"))
      | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/clang-assertions-trunk-20240904/bin/../include/c++/v1/__assertion_handler:33:50: note: expanded from macro '_LIBCPP_ASSERTION_HANDLER'
   33 | # define _LIBCPP_ASSERTION_HANDLER(message) __builtin_verbose_trap("libc++", message)
      | ^~~~~~~~~~~~~~~~~~~~~~
<source>:6:12: note: in call to 'v.front()'
 6 |   int& i = v.front();  // Library UB
      | ^~~~~~~~~
<source>:11:15: note: in call to 'f()'
   11 | static_assert(f() == 4);
      |               ^~~
```

But does compile if assertions are disabled.

I believe libstdc++ does something like this, so this fails even without assertions enabled.

`if consteval` is not available in MSVC so this would have to be done with `__libcpp_is_constant_evaluated`/`__builtin_is_constant_evaluated`. This also removes the need for `[[maybe_unused]]` for variables used just for assertions.

The downside is the compile time would to increase on non-debug builds, where `LIBCPP_ASSERT(x)` goes from `(void) 0` to `is_constant_evaluated() && !(x) ? assert_handler(...) : (void) 0`. I haven't measured the actual impact, but I don't expect it to be much.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to