Bug 70692 - No warning when std::function<const int&(...)> binds a reference to a temporary
Summary: No warning when std::function<const int&(...)> binds a reference to a temporary
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: 13.0
Assignee: Not yet assigned to anyone
Keywords: diagnostic
: 103543 (view as bug list)
Depends on: 80472 104477
Blocks: Wreturn-local-addr
  Show dependency treegraph
Reported: 2016-04-16 13:29 UTC by Jonathan Wakely
Modified: 2023-02-16 15:36 UTC (History)
5 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2016-04-16 00:00:00

Untested patch. (950 bytes, patch)
2016-04-16 13:55 UTC, Jonathan Wakely
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2016-04-16 13:29:22 UTC
This has undefined behaviour:

#include <functional>

int f() { return 0; }

int main()
  std::function<const int&()> ff = f;
  return ff();

but the -Wreturn-local-addr warning that is enabled by default is suppressed in system headers.

In file included from fun.cc:1:0:
/home/jwakely/gcc/6/include/c++/6.0.0/functional: In instantiation of ‘static _Res std::_Function_handler<_Res(_ArgTypes ...), _Functor>::_M_invoke(const std::_Any_data&, _ArgTypes&& ...) [with _Res = const int&; _Functor = int (*)(); _ArgTypes = {}]’:
/home/jwakely/gcc/6/include/c++/6.0.0/functional:2124:19:   required from ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = int (*)(); <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = const int&; _ArgTypes = {}]’
fun.cc:7:36:   required from here
/home/jwakely/gcc/6/include/c++/6.0.0/functional:1726:40: warning: returning reference to temporary [-Wreturn-local-addr]

We should either ensure the warning is enabled, even in system headers (similar to PR 58876) or add a run-time check to _Function_handler<_Res(_ArgTypes...), _Functor>::_M_invoke (it can't be a compile-time static assertion because that function is instantiated even if it's never called, and the code is only undefined if it's invoked).
Comment 1 Jonathan Wakely 2016-04-16 13:55:28 UTC
Created attachment 38288 [details]
Untested patch.

We can enable -Wsystem-headers around the relevant function, but we also need a change to <ext/string_conversions.h> to suppress the false positive -Wsign-compare warnings in there.
Comment 2 Jonathan Wakely 2016-04-16 14:08:30 UTC
Bah, it seems that -Wsystem-headers doesn't get turned off again by the

#pragma GCC diagnostic pop
Comment 3 Jonathan Wakely 2019-03-25 23:32:47 UTC
This should get addressed more thoroughly by https://wg21.link/p0932
Comment 4 Andrew Pinski 2021-12-03 19:45:10 UTC
*** Bug 103543 has been marked as a duplicate of this bug. ***
Comment 5 Jonathan Wakely 2021-12-03 22:12:21 UTC
"A type trait to detect reference binding to temporary" https://wg21.link/p2255r2 is the current direction to resolve this.
Comment 6 Andrew Pinski 2022-02-09 20:04:11 UTC
(In reply to Jonathan Wakely from comment #5)
> "A type trait to detect reference binding to temporary"
> https://wg21.link/p2255r2 is the current direction to resolve this.

Which is now recorded as PR 104477.
Comment 7 GCC Commits 2022-09-28 23:35:39 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:


commit r13-2922-gfa9bda3ea4315a7285edbc99323e3fa7885cbbb8
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Sep 27 20:59:05 2022 +0100

    libstdc++: Make INVOKE<R> refuse to create dangling references [PR70692]
    This is the next part of the library changes from P2255R2. This makes
    INVOKE<R> ill-formed if converting the INVOKE expression to R would bind
    a reference to a temporary object.
    The is_invocable_r trait is now false if the invocation would create a
    dangling reference. This is done by adding the dangling check to the
    __is_invocable_impl partial specialization used for INVOKE<R>
    expressions. This change also slightly simplifies the nothrow checking
    recently added to that partial specialization.
    This change also removes the is_invocable_r checks from the pre-C++17
    implementation of std::__invoke_r, because there is no need for it to be
    SFINAE-friendly. None of our C++11 and C++14 uses of INVOKE<R> require
    those constraints. The std::function constructor needs to check
    is_invocable_r, but that's already done explicitly, so we don't need to
    recheck when calling __is_invoke_r in std::function::operator(). The
    other uses of std::__is_invoke_r do not need to be constrained and can
    just be ill-formed if the INVOKE<R> expression is ill-formed.
            PR libstdc++/70692
            * include/bits/invoke.h [__cplusplus < 201703] (__invoke_r):
            Remove is_invocable and is_convertible constraints.
            * include/std/type_traits (__is_invocable_impl::_S_conv): Use
            non-deduced context for parameter.
            (__is_invocable_impl::_S_test): Remove _Check_noex template
            parameter and use deduced noexcept value in its place. Add bool
            parameter to detect dangling references.
            (__is_invocable_impl::type): Adjust call to _S_test to avoid
            deducing unnecessary noexcept property..
            (__is_invocable_impl::__nothrow_type): Rename to ...
            (__is_invocable_impl::__nothrow_conv): ... this. Adjust call
            to _S_test to deduce noexcept property.
            * testsuite/20_util/bind/dangling_ref.cc: New test.
            * testsuite/20_util/function/cons/70692.cc: New test.
            * testsuite/20_util/function_objects/invoke/dangling_ref.cc:
            New test.
            * testsuite/20_util/is_invocable/dangling_ref.cc: New test.
            * testsuite/30_threads/packaged_task/cons/dangling_ref.cc:
            New test.
Comment 8 Jonathan Wakely 2022-09-28 23:38:56 UTC
Fixed for GCC 13 by implementing the changes from https://wg21.link/P2255R2

The original example is now ill-formed.