https://gcc.gnu.org/g:34d947134403e7482ba4f153d8faabee0bc4933e

commit r15-2727-g34d947134403e7482ba4f153d8faabee0bc4933e
Author: Marek Polacek <pola...@redhat.com>
Date:   Wed Jul 31 17:33:55 2024 -0400

    c++: fix -Wdangling-reference false positive [PR115987]
    
    This fixes another false positive.  When a function is taking a
    temporary of scalar type that couldn't be bound to the return type
    of the function, don't warn, such a program would be ill-formed.
    
    Thanks to Jonathan for reporting the problem.
    
            PR c++/115987
    
    gcc/cp/ChangeLog:
    
            * call.cc (do_warn_dangling_reference): Don't consider a
            temporary with a scalar type that cannot bind to the return type.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ext/attr-no-dangling6.C: Adjust.
            * g++.dg/ext/attr-no-dangling7.C: Likewise.
            * g++.dg/warn/Wdangling-reference22.C: New test.

Diff:
---
 gcc/cp/call.cc                                    | 14 ++++++++++++--
 gcc/testsuite/g++.dg/ext/attr-no-dangling6.C      | 22 +++++++++++-----------
 gcc/testsuite/g++.dg/ext/attr-no-dangling7.C      |  8 ++++----
 gcc/testsuite/g++.dg/warn/Wdangling-reference22.C | 19 +++++++++++++++++++
 4 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 40cb582acc70..a75e2e5e3afd 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -14290,8 +14290,18 @@ do_warn_dangling_reference (tree expr, bool arg_p)
            /* Recurse to see if the argument is a temporary.  It could also
               be another call taking a temporary and returning it and
               initializing this reference parameter.  */
-           if (do_warn_dangling_reference (arg, /*arg_p=*/true))
-             return expr;
+           if ((arg = do_warn_dangling_reference (arg, /*arg_p=*/true)))
+             {
+               /* If we know the temporary could not bind to the return type,
+                  don't warn.  This is for scalars only because for classes
+                  we can't be sure we are not returning its sub-object.  */
+               if (SCALAR_TYPE_P (TREE_TYPE (arg))
+                   && TYPE_REF_P (rettype)
+                   && !reference_related_p (TREE_TYPE (arg),
+                                            TREE_TYPE (rettype)))
+                 continue;
+               return expr;
+             }
          /* Don't warn about member functions like:
              std::any a(...);
              S& s = a.emplace<S>({0}, 0);
diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C 
b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C
index 235a5fd86c55..5b349e8e6827 100644
--- a/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C
+++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling6.C
@@ -12,26 +12,26 @@ struct SF { static constexpr bool value = false; };
 
 template<typename T>
 [[gnu::no_dangling(T::value)]]
-const X& get (const int& i)
+const X& get (const int& i, const X&)
 {
    return i == 0 ? x1 : x2;
 }
 
 template<bool B = true>
 [[gnu::no_dangling(B)]]
-const X& foo (const int& i)
+const X& foo (const int& i, const X&)
 {
    return i == 0 ? x1 : x2;
 }
 
 [[gnu::no_dangling(val ())]]
-const X& bar (const int& i)
+const X& bar (const int& i, const X&)
 {
    return i == 0 ? x1 : x2;
 }
 
 [[gnu::no_dangling(!val ())]]
-const X& baz (const int& i)
+const X& baz (const int& i, const X&)
 {
    return i == 0 ? x1 : x2;
 }
@@ -52,13 +52,13 @@ auto gety() -> Span<SF>;
 void
 test ()
 {
-  [[maybe_unused]] const X& x1 = get<ST> (10);   // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x2 = get<SF> (10);   // { dg-warning "dangling" }
-  [[maybe_unused]] const X& x3 = foo<true> (10);  // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x4 = foo<false> (10); // { dg-warning "dangling" }
-  [[maybe_unused]] const X& x7 = foo<> (10);     // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x5 = bar (10);       // { dg-bogus "dangling" }
-  [[maybe_unused]] const X& x6 = baz (10);       // { dg-warning "dangling" }
+  [[maybe_unused]] const X& x1 = get<ST> (10, X{});      // { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x2 = get<SF> (10, X{});      // { dg-warning 
"dangling" }
+  [[maybe_unused]] const X& x3 = foo<true> (10, X{});  // { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x4 = foo<false> (10, X{}); // { dg-warning 
"dangling" }
+  [[maybe_unused]] const X& x7 = foo<> (10, X{});        // { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x5 = bar (10, X{});          // { dg-bogus 
"dangling" }
+  [[maybe_unused]] const X& x6 = baz (10, X{});          // { dg-warning 
"dangling" }
 
   [[maybe_unused]] const auto &b1 = geti()[0];   // { dg-bogus "dangling" }
   [[maybe_unused]] const auto &b2 = gety()[0];   // { dg-warning "dangling" }
diff --git a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C 
b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C
index 3c392ed409f8..a5fb809e6bdb 100644
--- a/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C
+++ b/gcc/testsuite/g++.dg/ext/attr-no-dangling7.C
@@ -16,16 +16,16 @@ const X& foo(const int& i);
 bool val () { return true; }
 
 [[gnu::no_dangling(val ())]]   // { dg-error "call" }
-const X& bar (const int& i);
+const X& bar (const int& i, const X&);
 
-[[gnu::no_dangling(20)]] const X& fn1 (const int &);
+[[gnu::no_dangling(20)]] const X& fn1 (const int &, const X&);
 
 void
 test ()
 {
-  [[maybe_unused]] const X& x1 = bar (10);       // { dg-warning "dangling" }
+  [[maybe_unused]] const X& x1 = bar (10, X{});          // { dg-warning 
"dangling" }
   [[maybe_unused]] const X& x2 = foo<int> (10);          // { dg-error "no 
matching" }
   [[maybe_unused]] const X& x3                   // { dg-warning "dangling" }
-    = fn1 (10);                                          // { dg-error 
"narrowing" }
+    = fn1 (10, X{});                             // { dg-error "narrowing" }
 }
 
diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference22.C 
b/gcc/testsuite/g++.dg/warn/Wdangling-reference22.C
new file mode 100644
index 000000000000..0381f9313fb7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference22.C
@@ -0,0 +1,19 @@
+// PR c++/115987
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wdangling-reference" }
+
+template <typename T>
+struct Wrapper {
+    T val;
+};
+
+template <typename T, typename FUNC>
+    const T& unwrap_2(const Wrapper<T>& r, FUNC&&) {
+  return r.val;
+}
+
+int main(int, char**) {
+  const Wrapper<int> w{1234};
+  const auto& u = unwrap_2(w, 1L);  // { dg-bogus "dangling reference" }
+  __builtin_printf("Unwrapped value : %d\n", u);
+}

Reply via email to