Transforming a by-value arguments to by-reference as GCC does for some
class types can trigger -Wdangling-pointer when the argument is used
to store the address of a local variable. Since the stored value is
not accessible in the caller the warning is a false positive.
The attached patch handles this case by excluding PARM_DECLs with
the DECL_BY_REFERENCE bit set from consideration.
While testing the patch I noticed some instances of the warning are
uninitentionally duplicated as the pass runs more than once. To avoid
that, I also introduce warning suppression into the handler for this
instance of the warning. (There might still be others.)
Tested on x86_64-linux.
Martin
Avoid -Wdangling-pointer for by-transparent-reference arguments [PR104436].
Resolves:
PR middle-end/104436 - spurious -Wdangling-pointer assigning local address to a class passed by value
gcc/ChangeLog:
PR middle-end/104436
* gimple-ssa-warn-access.cc (pass_waccess::check_dangling_stores):
Check for warning suppression. Avoid by-value arguments transformed
into by-transparent-reference.
gcc/testsuite/ChangeLog:
PR middle-end/104436
* c-c++-common/Wdangling-pointer-7.c: New test.
* g++.dg/warn/Wdangling-pointer-4.C: New test.
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 80d41ea4383..0c319a32b70 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -4517,6 +4517,9 @@ pass_waccess::check_dangling_stores (basic_block bb,
if (!stmt)
break;
+ if (warning_suppressed_p (stmt, OPT_Wdangling_pointer_))
+ continue;
+
if (is_gimple_call (stmt)
&& !(gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE)))
/* Avoid looking before nonconst, nonpure calls since those might
@@ -4542,10 +4545,16 @@ pass_waccess::check_dangling_stores (basic_block bb,
}
else if (TREE_CODE (lhs_ref.ref) == SSA_NAME)
{
- /* Avoid looking at or before stores into unknown objects. */
gimple *def_stmt = SSA_NAME_DEF_STMT (lhs_ref.ref);
if (!gimple_nop_p (def_stmt))
+ /* Avoid looking at or before stores into unknown objects. */
return;
+
+ tree var = SSA_NAME_VAR (lhs_ref.ref);
+ if (DECL_BY_REFERENCE (var))
+ /* Avoid by-value arguments transformed into by-reference. */
+ continue;
+
}
else if (TREE_CODE (lhs_ref.ref) == MEM_REF)
{
@@ -4578,6 +4587,8 @@ pass_waccess::check_dangling_stores (basic_block bb,
"storing the address of local variable %qD in %qE",
rhs_ref.ref, lhs))
{
+ suppress_warning (stmt, OPT_Wdangling_pointer_);
+
location_t loc = DECL_SOURCE_LOCATION (rhs_ref.ref);
inform (loc, "%qD declared here", rhs_ref.ref);
diff --git a/gcc/testsuite/c-c++-common/Wdangling-pointer-7.c b/gcc/testsuite/c-c++-common/Wdangling-pointer-7.c
new file mode 100644
index 00000000000..433727dd845
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wdangling-pointer-7.c
@@ -0,0 +1,20 @@
+/* Verify -Wdangling-pointer is issued only once.
+ { dg-do compile }
+ { dg-options "-O -Wall" } */
+
+void *p;
+
+void escape_global_warn_once (void)
+{
+ int x[5];
+
+ p = &x[3]; // { dg-regexp "\[^\n\r\]+: warning: \[^\n\r\]+ \\\[-Wdangling-pointer.?\\\]" "message" }
+}
+
+
+void escape_param_warn_once (void **p)
+{
+ int x[5];
+
+ *p = &x[3]; // { dg-regexp "\[^\n\r\]+: warning: \[^\n\r\]+ \\\[-Wdangling-pointer.?\\\]" "message" }
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wdangling-pointer-4.C b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-4.C
new file mode 100644
index 00000000000..b3d144a9e6d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wdangling-pointer-4.C
@@ -0,0 +1,34 @@
+/* PR middle-end/104436 - spurious -Wdangling-pointer assigning local
+ address to a class passed by value
+ { dg-do compile }
+ { dg-options "-O1 -Wall" } */
+
+struct S
+{
+ S (void *p): p (p) { }
+ S (const S &s): p (s.p) { }
+
+ void *p;
+};
+
+
+void nowarn_assign_by_value (S s)
+{
+ int i;
+ S t (&i);
+ s = t; // { dg-bogus "-Wdangling-pointer" }
+}
+
+void nowarn_assign_by_value_arg (S s)
+{
+ S t (&s);
+ s = t; // { dg-bogus "-Wdangling-pointer" }
+}
+
+
+void warn_assign_local_by_reference (S &s)
+{
+ int i;
+ S t (&i);
+ s = t; // { dg-warning "-Wdangling-pointer" }
+}