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