https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118777

            Bug ID: 118777
           Summary: False positive when extending lifetime of temporary
                    containing reference, created by non-static member
                    function [-Wdangling-reference]
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: haining.cpp at gmail dot com
  Target Milestone: ---

Created attachment 60405
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=60405&action=edit
MRE to produce dangling reference warning

gcc version 15.0.1 20250206 (experimental)
(Compiler-Explorer-Build-gcc-9a409f5c862c44445b2625c4b94145031394ef28-binutils-2.42)
 


Configured with: ../gcc-trunk-20250206/configure
--prefix=/opt/compiler-explorer/gcc-build/staging
--enable-libstdcxx-backtrace=yes --build=x86_64-linux-gnu
--host=x86_64-linux-gnu --target=x86_64-linux-gnu --disable-bootstrap
--enable-multiarch --with-abi=m64 --with-multilib-list=m32,m64,mx32
--enable-multilib --enable-clocale=gnu
--enable-languages=c,c++,fortran,ada,objc,obj-c++,go,d,rust,m2 --enable-ld=yes
--enable-gold=yes --enable-libstdcxx-debug --enable-libstdcxx-time=yes
--enable-linker-build-id --enable-lto --enable-plugins --enable-threads=posix
--with-pkgversion=Compiler-Explorer-Build-gcc-9a409f5c862c44445b2625c4b94145031394ef28-binutils-2.42

I can reproduce this on 13.3 and 14.2, but not on 12.4

This program:
1. Creates a `Widget`
1. Creates a temporary callable `Wrapper`
1. Invokes `Wrapper::call` on the `Widget`, which creates and returns a
`Holder` with an lvalue reference to the `Widget`
1. Extends the lifetime of the `Holder` with a `const Holder&` in the caller.

```
struct Widget{};

struct Holder {
  Widget& data;
};

struct Wrapper {
  Holder call(Widget& w) const {
    return {w};
  }
};


int main() {
  Widget w;
  const Holder& r = Wrapper{}.call(w);
  (void)r;
}
```

```
$ g++ -Wall -Wextra -pedantic-errors -std=c++17 source.cpp
<source>: In function 'int main()':
<source>:16:17: warning: possibly dangling reference to a temporary
[-Wdangling-reference]
   16 |   const Holder& r = Wrapper{}.call(w);
      |                 ^
<source>:16:21: note: 'Wrapper' temporary created here
   16 |   const Holder& r = Wrapper{}.call(w);
      |            
```

The warning reads like gcc thinks I'm binding a reference to the `Wrapper`
object itself. There are many changes that cause the warning to go away:

1. Remove the reference from `Holder`: struct Holder { Widget data; };`
1. Mark `Wrapper::call` as `static`
    ```
    struct Wrapper {
      static Holder call(Widget& w)  {
        return {w};
      }
    };
1. Change main to not bind a reference to the `Holder`: `Holder r =
Wrapper{}.call(w);`


If `Wrapper::call` constructed `Holder` with a data member or local variable,
then this would of course be a dangling reference, but as-written I don't see
how it could be since the argument is a non-const lvalue reference. There's
also versions of this that actually *do* create a dangling reference, but that
do not trigger any warning:

```
struct Widget{};

struct Holder {
  Widget& data;
};

struct Wrapper {
  Holder call(Widget w) const {  // no &
    return {w};  // returning Holder with reference to local
  }
};


int main() {
  Widget w;
  Holder r = Wrapper{}.call(w); // r.data is dangling
  (void)r;
}
```

https://godbolt.org/z/eehbY45o5

Reply via email to