Repository navigation
Reject binding reference holders to temporaries - #454
Merged
Merged
Conversation
…om_temporary polyfills The C++23 traits use the compiler builtin where __has_builtin reports it. Elsewhere (GCC 12, MSVC) an emulation answers: it reports a temporary only where the binding rules make one certain, because a false report would reject valid code on those compilers alone. It misses a temporary created by converting a class source not reference-related to the referent, which the documentation states. The tests also run against the standard traits in C++23 validation builds, and test the emulation directly so it runs on every compiler. Assisted-by: Claude:claude-opus-5-5
Implement the [optional.ref.ctor] and [optional.ref.assign] guards in pfn::optional<T&> and fn::optional<T&>: each converting constructor has a deleted twin selected where reference_constructs_from_temporary_v holds, and the in_place_t constructor and emplace are constrained on it. As in the standard, an xvalue of the referenced type is refused too. Assisted-by: Claude:claude-opus-5-5
[func.require]/2 makes INVOKE<R> ill-formed when
reference_converts_from_temporary_v holds. libstdc++ applies this inside
is_invocable_r_v even in C++20; libc++ does not, so with libc++
pfn::invoke_r<int const &>([] { return 42; }) compiled and dangled.
Assisted-by: Claude:claude-opus-5-5
append(std::in_place_type<T &>, ...) asks the trait as a forwarding parameter deduces, so an xvalue is refused alongside a prvalue, as optional<T&> refuses both. The spelled as_pack gives a reference element a parameter whose constructor deduces the argument, keeping every element type spelled and braced lists working for value elements. Assisted-by: Claude:claude-opus-5-5
…G.md Assisted-by: Claude:claude-opus-5-5
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
🤖 Augment PR SummarySummary: Reject reference bindings that would leave holders dangling.
🤖 Was this summary useful? React with 👍 or 👎 |
MSVC's preprocessor rejects __has_builtin, so MSVC is gated by _MSC_FULL_VER: 19.51.36246 (Visual Studio 2026 18.6) is the earliest version with both builtins, checked on Compiler Explorer, where 19.44 and 19.50 have neither. CI's Visual Studio 2026 lanes take the builtin arm, its Visual Studio 2022 lanes the emulation. The emulation and the dispatch become trait specializations and variable templates: as consteval functions they only ran at compile time, which line coverage reports as uncovered. Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
fn's apply_r paths were constrained by std::is_invocable_r_v but called pfn::invoke_r. Where the trait predates [func.require]/2 (libc++, and libstdc++ without the builtin), the constraint allowed calls that invoke_r rejected: fn::is_applicable_r_v<int const &, int (*)(), std::tuple<>> was a hard error instead of false, and the pack<> form returned true for a call that could not be made. pfn::is_invocable_r and pfn::is_nothrow_invocable_r give the C++23 answer on every standard library; pfn::invoke_r and fn's apply_r paths now use them. Assisted-by: Claude:claude-opus-5-5
Member
Author
|
augment review |
A function reference binds only a function lvalue, never a temporary. Only object references need argument deduction; using it for function references broke overload resolution in as_pack<int (&)(int)>(f). Assisted-by: Claude:claude-opus-5-5
Member
Author
|
augment review |
Direct-initializing the reference member also considered explicit conversion functions, so binding could differ from the implicit conversion checked by the constraint and noexcept-specifier. clang rejected such a source as ambiguous. The overloaded function-reference test skips its constant-evaluation check on MSVC, whose evaluator reads a function-reference member of an aggregate base as uninitialized. Assisted-by: Claude:claude-opus-5-5
Member
Author
|
augment review |
The standard's VAL<U> is a prvalue with cv qualification removed when U is a non-reference, non-class, non-array type. The emulation kept it, so reference_constructs_from_temporary_v<int &&, const int> returned false; Clang 19 and 20 builtins do the same. Both the emulation and builtins now use the cv-unqualified type. Comparisons with the builtins found that the emulation reported temporaries for array references where GCC's builtin did not. Compilers disagree on these bindings, so the emulation now reports none for array referents, documented alongside missed temporaries from class sources. Assisted-by: Claude:claude-opus-5-5
Member
Author
|
augment review |
Bronek
force-pushed
the
bronek/dangling_references_from_ctor_fix
branch
from
October 12, 2026 19:53
7e7d2fc to
2e7f402
Compare
Assisted-by: Codex:gpt-6.1-sol
Bronek
force-pushed
the
bronek/dangling_references_from_ctor_fix
branch
from
October 12, 2026 20:03
2e7f402 to
d3484c8
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Addresses the
pfnandpackparts of #447:optional<T&>,packelements andinvoke_r's reference result no longer bind to temporaries.pfn::reference_constructs_from_temporaryandpfn::reference_converts_from_temporary(new<pfn/type_traits.hpp>): use the compiler builtin where available; elsewhere (GCC 12, MSVC), an emulation that never reports a false temporary but misses one created by converting an unrelated class source.pfn::optional<T&>andfn::optional<T&>: the [optional.ref.ctor] / [optional.ref.assign] guards replace the documented deferral.pfn::invoke_r: not viable when its reference result would bind to a temporary ([func.require]/2); libc++ previously accepted such a call.pack:append(std::in_place_type<T&>, ...)andas_packwith explicit element types reject a temporary; value elements still convert, including braced lists.Breaking: as in the standard, xvalues of the referenced type are also rejected, e.g.
optional<int const &>{std::move(x)}.copack/choicereference alternatives (#451) andjust<T&>(#437) adopt the traits after rebasing, so this does not close #447.Assisted-by: Claude:claude-opus-5-5