c++: -Wdangling-reference and lambda false warning [PR109640]

-Wdangling-reference checks if a function receives a temporary as its
argument, and only warns if any of the arguments was a temporary.  But
we should not warn when the temporary represents a lambda or we generate
false positives as in the attached testcases.

	PR c++/113256
	PR c++/111607
	PR c++/109640

gcc/cp/ChangeLog:

	* call.cc (do_warn_dangling_reference): Don't warn if the temporary
	is of lambda type.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/Wdangling-reference14.C: New test.
	* g++.dg/warn/Wdangling-reference15.C: New test.
	* g++.dg/warn/Wdangling-reference16.C: New test.
This commit is contained in:
Marek Polacek 2024-01-19 13:59:41 -05:00
parent ed4c7893de
commit 9010fdba68
4 changed files with 72 additions and 3 deletions

View file

@ -14123,7 +14123,10 @@ do_warn_dangling_reference (tree expr, bool arg_p)
tree e = expr;
while (handled_component_p (e))
e = TREE_OPERAND (e, 0);
if (!reference_like_class_p (TREE_TYPE (e)))
tree type = TREE_TYPE (e);
/* If the temporary represents a lambda, we don't really know
what's going on here. */
if (!reference_like_class_p (type) && !LAMBDA_TYPE_P (type))
return expr;
}
@ -14180,10 +14183,10 @@ do_warn_dangling_reference (tree expr, bool arg_p)
initializing this reference parameter. */
if (do_warn_dangling_reference (arg, /*arg_p=*/true))
return expr;
/* Don't warn about member function like:
/* Don't warn about member functions like:
std::any a(...);
S& s = a.emplace<S>({0}, 0);
which constructs a new object and returns a reference to it, but
which construct a new object and return a reference to it, but
we still want to detect:
struct S { const S& self () { return *this; } };
const S& s = S().self();

View file

@ -0,0 +1,22 @@
// PR c++/113256
// { dg-do compile { target c++14 } }
// { dg-options "-Wdangling-reference" }
#include <utility>
#include <cassert>
template<class M, class T, class A> auto bind(M T::* pm, A)
{
return [=]( auto&& x ) -> M const& { return x.*pm; };
}
template<int I> struct arg {};
arg<1> _1;
int main()
{
std::pair<int, int> pair;
int const& x = bind( &std::pair<int, int>::first, _1 )( pair ); // { dg-bogus "dangling reference" }
assert( &x == &pair.first );
}

View file

@ -0,0 +1,31 @@
// PR c++/111607
// { dg-do compile { target c++20 } }
// { dg-options "-Wdangling-reference" }
#include <variant>
struct S {
constexpr S(int i_) : i(i_) {}
S(S const &) = delete;
S & operator=(S const &) = delete;
S(S &&) = delete;
S & operator=(S &&) = delete;
int i;
};
struct A {
S s{0};
};
using V = std::variant<A>;
consteval auto f(V const & v) {
auto const & s = std::visit([](auto const & v) -> S const & { return v.s; }, v); // { dg-bogus "dangling reference" }
return s.i;
}
int main() {
constexpr V a{std::in_place_type<A>};
constexpr auto i = f(a);
return i;
}

View file

@ -0,0 +1,13 @@
// PR c++/109640
// { dg-do compile { target c++11 } }
// { dg-options "-Wdangling-reference" }
bool
fn0 ()
{
int a;
int&& i = [](int& r) -> int&& { return static_cast<int&&>(r); }(a); // { dg-bogus "dangling reference" }
auto const l = [](int& r) -> int&& { return static_cast<int&&>(r); };
int&& j = l(a);
return &i == &j;
}