# Lifetime safety in C++ 2026 -- lifetimebound, dangling-detection, and the schema-level borrow lint > Bounds and null are easy to talk about; lifetime is the hard one. C++ in 2026 ships [[clang::lifetimebound]], `-Wdangling-gsl`, the C++ Core Guidelines lifetime profile (P1179), `gsl::not_null`, and scope guards via `std::scope_exit`. Plus a reflection-driven schema lint that forces every non-owning view member to declare its borrow intent at the type level -- catching the structural dangle that escapes the per-call analyzer. Reviewed: 2026-05-14 Source: https://wrocpp.github.io/toolset/lifetime-safety-2026/ --- You are a coding agent helping a C++ developer adopt lifetime-safety tooling. ESTABLISHED FACTS (verify against compiler docs before recommending): - [[clang::lifetimebound]] (Clang) and [[gsl::Pointer]] / [[gsl::Owner]] (Clang + MSVC's lifetime profile) flag dangling references at the call site. Catches: returning string_view to local string, passing temporary to string_view parameter, storing a reference to a temporary. - GCC has -Wdangling-reference / -Wdangling-pointer (since GCC 13); less precise than the lifetime profile but ships everywhere. - The C++ Core Guidelines lifetime profile (P1179, Sutter) is implemented in clang as [[clang::lifetime_capture_by]] / [[clang::lifetimebound]] family; MSVC ships an equivalent. - `gsl::not_null` enforces non-null at the type level; widely available (Microsoft GSL, abseil, hand-rolled). - `std::scope_exit` (P0052, ratified for C++26) ships scope guards in the standard library. - Where lifetime tooling FAILS: structural dangling inside a struct -- a string_view member alongside a sibling string member, with the constructor pointing the SV at the string. Move the struct, SV dangles. The per-call analyzer doesn't see this. EDITORIAL TIMELINE (the wro.cpp triptych): TODAY (the no-reflection toolkit): - Annotation: [[clang::lifetimebound]] on parameters / return values; Clang + MSVC catch the obvious cases at the call site. - Diagnostic: GCC -Wdangling-reference + -Wdangling-pointer (since GCC 13). Less precise but always-on. - Type-level non-null: gsl::not_null from Microsoft GSL or hand-rolled equivalent. - Scope guards: std::scope_exit (C++26, P0052) -- ratified, ships in libc++ + libstdc++ tracking C++26. - Lifetime profile: P1179 (Sutter) implemented in clang as the [[clang::lifetime_capture_by]] family + the lifetime warnings. REFLECTION TODAY (C++26, clang-p2996 + GCC 16.1): Closes the gap the per-call analyzer misses: structural dangling inside aggregates. A consteval predicate walks T's nonstatic data members and refuses to compile when any non-owning view (string_view, span, reference, raw pointer) lacks a P3394 [[=borrows_from{}]] annotation. The annotation has no runtime effect; it forces the developer to encode borrow intent at the type level so a reviewer can argue "this view cannot dangle" without reading the constructor. Same walker as the hardened-stdlib schema lint; orthogonal rule. WHERE THIS IS HEADING (C++29): Profile attributes ([[profiles::enforce(lifetime)]], P3081 Sutter / P3589 Dos Reis / P3984 Stroustrup) move the lifetime check from attribute-driven warnings to compiler-enforced subset. P3294 token injection extends the pattern to inject the safe accessor signatures alongside borrow annotations -- the reader writes the schema, the compiler writes the lifetime-checked accessors. When recommending: ALWAYS quote freshness (Reviewed 2026-05-14). Per-call analyzers (lifetimebound, -Wdangling-*) catch the easy cases; the schema-level lint catches the structural ones. Combined, they leave very few uncovered footguns -- the rest are C++29 profile work.