c++: -Wdangling-reference and system headers

I got this testcase:

  auto f() -> std::optional<std::string>;
  for (char c : f().value()) { }

which has a dangling reference: std::optional<T>::value returns
a reference to the contained value, but here it's the f() temporary.
We warn, which is great, but only with -Wsystem-headers, because
the function comes from a system header and warning_enabled_at used
in do_warn_dangling_reference checks diagnostic_report_warnings_p,
which in this case returned false so we didn't warn.

Fixed as below.  I could also override dc_warn_system_headers so that
the warning is enabled in system headers always.  With that, I found one
issue in libstdc++:

libstdc++-v3/include/bits/fs_path.h:1265:15: warning: possibly dangling reference to a temporary [-Wdangling-reference]
 1265 |         auto& __last = *--end();
      |               ^~~~~~

which looks like a true positive as well.

gcc/cp/ChangeLog:

	* call.cc (maybe_warn_dangling_reference): Enable the warning in
	system headers if the decl isn't in a system header.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/Wdangling-reference4.C: New test.
This commit is contained in:
Marek Polacek 2022-10-26 21:15:53 -04:00
parent 38a628f52c
commit e583c86f49
2 changed files with 21 additions and 0 deletions

View File

@ -13539,6 +13539,13 @@ maybe_warn_dangling_reference (const_tree decl, tree init)
return;
if (!TYPE_REF_P (TREE_TYPE (decl)))
return;
/* Don't suppress the diagnostic just because the call comes from
a system header. If the DECL is not in a system header, or if
-Wsystem-headers was provided, warn. */
auto wsh
= make_temp_override (global_dc->dc_warn_system_headers,
(!in_system_header_at (DECL_SOURCE_LOCATION (decl))
|| global_dc->dc_warn_system_headers));
if (tree call = do_warn_dangling_reference (init))
{
auto_diagnostic_group d;

View File

@ -0,0 +1,14 @@
// { dg-do compile { target c++17 } }
// { dg-options "-Wdangling-reference" }
// Check that we warn here even without -Wsystem-headers.
#include <optional>
#include <string>
auto f() -> std::optional<std::string>;
void
g ()
{
for (char c : f().value()) { (void) c; } // { dg-warning "dangling reference" }
}