[PATCH] c++: -Wdangling-reference and system headers
I got this testcase: auto f() -> std::optional; for (char c : f().value()) { } which has a dangling reference: std::optional::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. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? 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. --- gcc/cp/call.cc | 7 +++ gcc/testsuite/g++.dg/warn/Wdangling-reference4.C | 14 ++ 2 files changed, 21 insertions(+) create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference4.C diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 951b9fd2a88..c7c7a122045 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -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; diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference4.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference4.C new file mode 100644 index 000..aee7a29019b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference4.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-Wdangling-reference" } +// Check that we warn here even without -Wsystem-headers. + +#include +#include + +auto f() -> std::optional; + +void +g () +{ + for (char c : f().value()) { (void) c; } // { dg-warning "dangling reference" } +} base-commit: f95d3d5de72a1c43e8d529bad3ef59afc3214705 -- 2.37.3
Re: [PATCH] c++: -Wdangling-reference and system headers
On 10/27/22 11:39, Marek Polacek wrote: I got this testcase: auto f() -> std::optional; for (char c : f().value()) { } which has a dangling reference: std::optional::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. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? 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. --- gcc/cp/call.cc | 7 +++ gcc/testsuite/g++.dg/warn/Wdangling-reference4.C | 14 ++ 2 files changed, 21 insertions(+) create mode 100644 gcc/testsuite/g++.dg/warn/Wdangling-reference4.C diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 951b9fd2a88..c7c7a122045 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -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)); Hmm, this is OK, but maybe we want a warning_enabled_at_ignore_system_header? if (tree call = do_warn_dangling_reference (init)) { auto_diagnostic_group d; diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-reference4.C b/gcc/testsuite/g++.dg/warn/Wdangling-reference4.C new file mode 100644 index 000..aee7a29019b --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wdangling-reference4.C @@ -0,0 +1,14 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-Wdangling-reference" } +// Check that we warn here even without -Wsystem-headers. + +#include +#include + +auto f() -> std::optional; + +void +g () +{ + for (char c : f().value()) { (void) c; } // { dg-warning "dangling reference" } +} base-commit: f95d3d5de72a1c43e8d529bad3ef59afc3214705