From d2249cd9adf5ae638577139177a50f7e62d8abd9 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Fri, 14 Oct 2022 10:05:57 -0400 Subject: c++: Implement -Wdangling-reference [PR106393] This patch implements a new experimental warning (enabled by -Wall) to detect references bound to temporaries whose lifetime has ended. The primary motivation is the Note in : Capturing the result of std::max by reference produces a dangling reference if one of the parameters is a temporary and that parameter is returned: int n = 1; const int& r = std::max(n-1, n+1); // r is dangling That's because both temporaries for n-1 and n+1 are destroyed at the end of the full expression. With this warning enabled, you'll get: g.C:3:12: warning: possibly dangling reference to a temporary [-Wdangling-reference] 3 | const int& r = std::max(n-1, n+1); | ^ g.C:3:24: note: the temporary was destroyed at the end of the full expression 'std::max((n - 1), (n + 1))' 3 | const int& r = std::max(n-1, n+1); | ~~~~~~~~^~~~~~~~~~ The warning works by checking if a reference is initialized with a function that returns a reference, and at least one parameter of the function is a reference that is bound to a temporary. It assumes that such a function actually returns one of its arguments! (I added code to check_return_expr to suppress the warning when we've seen the definition of the function and we can say that it can return a variable with static storage duration.) It warns when the function in question is a member function, but only if the function is invoked on a temporary object, otherwise the warning would emit loads of warnings for valid code like obj.emplace({0}, 0). It does detect the dangling reference in: struct S { const S& self () { return *this; } }; const S& s = S().self(); It warns in member initializer lists as well: const int& f(const int& i) { return i; } struct S { const int &r; S() : r(f(10)) { } }; I've run the testsuite/bootstrap with the warning enabled by default. There were just a few FAILs, all of which look like genuine bugs. A bootstrap with the warning enabled by default passed as well. When testing a previous version of the patch, there were many FAILs in libstdc++'s 22_locale/; all of them because the warning triggered on const test_type& obj = std::use_facet(std::locale()); but this code looks valid -- std::use_facet doesn't return a reference to its parameter. Therefore I added a #pragma and code to suppress the warning. PR c++/106393 gcc/c-family/ChangeLog: * c.opt (Wdangling-reference): New. gcc/cp/ChangeLog: * call.cc (expr_represents_temporary_p): New, factored out of... (conv_binds_ref_to_temporary): ...here. Don't return false just because a ck_base is missing. Use expr_represents_temporary_p. (do_warn_dangling_reference): New. (maybe_warn_dangling_reference): New. (extend_ref_init_temps): Call maybe_warn_dangling_reference. * cp-tree.h: Adjust comment. * typeck.cc (check_return_expr): Suppress -Wdangling-reference warnings. gcc/ChangeLog: * doc/invoke.texi: Document -Wdangling-reference. libstdc++-v3/ChangeLog: * include/bits/locale_classes.tcc: Add #pragma to disable -Wdangling-reference with std::use_facet. gcc/testsuite/ChangeLog: * g++.dg/cpp23/elision4.C: Use -Wdangling-reference, add dg-warning. * g++.dg/cpp23/elision7.C: Likewise. * g++.dg/warn/Wdangling-pointer-2.C: Use -Wno-dangling-reference. * g++.dg/warn/Wdangling-reference1.C: New test. * g++.dg/warn/Wdangling-reference2.C: New test. * g++.dg/warn/Wdangling-reference3.C: New test. --- libstdc++-v3/include/bits/locale_classes.tcc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libstdc++-v3') diff --git a/libstdc++-v3/include/bits/locale_classes.tcc b/libstdc++-v3/include/bits/locale_classes.tcc index 64cd753..9cc4f23 100644 --- a/libstdc++-v3/include/bits/locale_classes.tcc +++ b/libstdc++-v3/include/bits/locale_classes.tcc @@ -127,6 +127,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * @return Reference to facet of type Facet. * @throw std::bad_cast if @p __loc doesn't contain a facet of type _Facet. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdangling-reference" template const _Facet& use_facet(const locale& __loc) @@ -141,6 +143,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return static_cast(*__facets[__i]); #endif } +#pragma GCC diagnostic pop // Generic version does nothing. -- cgit v1.1 From 486a50374e7c6200c476e67ffbe13ad71ac3262a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 27 Oct 2022 00:18:35 +0000 Subject: Daily bump. --- libstdc++-v3/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'libstdc++-v3') diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b668b93..b3b168d 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,9 @@ +2022-10-26 Marek Polacek + + PR c++/106393 + * include/bits/locale_classes.tcc: Add #pragma to disable + -Wdangling-reference with std::use_facet. + 2022-10-21 Arsen Arsenović * acinclude.m4: Default hosted to off if building without -- cgit v1.1