Annex F (informative) Core undefined behavior [ub]

F.5 [dcl]: Declarations [ub.dcl]

F.5.1[ub:dcl.type.cv.modify.const.obj]
Specified in: [dcl.type.cv]

Any attempt to modify a const object during its lifetime results in undefined behavior.
[Example 1: const int* ciq = new const int(3); // initialized as required int* iq = const_cast<int*>(ciq); // cast required *iq = 4; // undefined behavior, modifies a const object — end example]

F.5.2[ub:dcl.type.cv.access.volatile]
Specified in: [dcl.type.cv]

If an attempt is made to access an object defined with a volatile-qualified type through the use of a non-volatile glvalue, the behavior is undefined
[Example 1: volatile int x = 0; int& y = const_cast<int&>(x); std::cout << y; // undefined behavior, accessing volatile through non-volatile glvalue — end example]

F.5.3[ub:dcl.ref.incompatible.function]
Specified in: [dcl.ref]

Initializing a reference to a function with a value that is a function that is not call-compatible ([expr.call]) with the type of the reference has undefined behavior.
[Example 1: void f(float x); void (&g)(int) = reinterpret_cast<void (&)(int)>(f); // undefined behavior — end example]

F.5.4[ub:dcl.ref.incompatible.type]
Specified in: [dcl.ref]

Initializing a reference to an object with a value that is not type-accessible ([basic.lval]) through the type of the reference has undefined behavior.
[Example 1: float g; int& i = reinterpret_cast<int&>(g); // undefined behavior — end example]

F.5.5[ub:dcl.ref.uninitialized.reference]
Specified in: [dcl.ref]

Evaluating a reference prior to initializing that reference has undefined behavior.
[Example 1: extern int &ir1; int i2 = ir1; // undefined behavior, ir1 not yet initialized int i3 = 17; int &ir1 = i3; — end example]

F.5.6[ub:dcl.fct.def.coroutine.resume.not.suspended]

Invoking a resumption member function for a coroutine that is not suspended results in undefined behavior.
[Example 1: #include <coroutine> struct minig { struct promise_type { int val; minig get_return_object() { return {*this}; } constexpr suspend_always initial_suspend() noexcept { return {}; } constexpr suspend_always final_suspend() noexcept { return {}; } constexpr void return_void() noexcept {} [[noreturn]] void unhandled_exception() noexcept { throw; } suspend_always yield_value(int v) noexcept { val = v; return {}; } }; using HDL = coroutine_handle<promise_type>; HDL coro; minig(promise_type& p) : coro(HDL::from_promise(p)) {} ~minig() { coro.destroy(); } bool move_next() { coro.resume(); return !coro.done(); } int current_value() { return coro.promise().val; } }; static minig f(int n) { for (int i = 0; i < n; ++i) co_yield i; } int main() { auto g = f(10); int sum = 0; while (g.move_next()) sum += g.current_value(); g.move_next(); // undefined behavior, will call coro.resume() but final_suspend // has already returned, even though it returned suspend_always return sum; } — end example]

F.5.7[ub:dcl.fct.def.coroutine.destroy.not.suspended]

Invoking destroy() on a coroutine that is not suspended has undefined behavior.
[Example 1: #include <coroutine> struct minig { struct promise_type { int val; minig get_return_object() { return {*this}; } constexpr suspend_always initial_suspend() noexcept { return {}; } constexpr suspend_always final_suspend() noexcept { return {}; } constexpr void return_void() noexcept {} [[noreturn]] void unhandled_exception() { throw; } suspend_always yield_value(int v) noexcept { val = v; return {}; } }; using HDL = coroutine_handle<promise_type>; HDL coro; minig(promise_type& p) : coro(HDL::from_promise(p)) {} ~minig() { coro.destroy(); } bool move_next() { coro.resume(); return !coro.done(); } int current_value() { // this coroutine is not suspended therefore a call to destroy has undefined behavior coro.destroy(); return coro.promise().val; } }; static minig f(int n) { for (int i = 0; i < n; ++i) co_yield i; } int main() { auto g = f(10); int sum = 0; while (g.move_next()) sum += g.current_value(); return sum; } — end example]

F.5.8[ub:dcl.attr.assume.false]
Specified in: [dcl.attr.assume]

If an assumption expression would not evaluate to true at the point where it appears the behavior is undefined.
[Example 1: int g(int x) { [[assume(x >= 0)]]; return x/32; } int f() { return g(-10); // undefined behavior, assumption in g is false } — end example]

F.5.9[ub:dcl.attr.noreturn.eventually.returns]
Specified in: [dcl.attr.noreturn]

If a function f is called where f was previously declared with the noreturn attribute and f eventually returns, the behavior is undefined.
[Example 1: [[noreturn]] void f(int i) { if (i > 0) throw "positive"; } int main() { f(0); // undefined behavior, returns from a [[noreturn]] function } — end example]