PR middle-end/98664 - inconsistent -Wfree-nonheap-object for inlined calls to system...
authorMartin Sebor <msebor@redhat.com>
Tue, 19 Jan 2021 22:10:30 +0000 (15:10 -0700)
committerMartin Sebor <msebor@redhat.com>
Tue, 19 Jan 2021 22:10:30 +0000 (15:10 -0700)
gcc/ChangeLog:

PR middle-end/98664
* tree-ssa-live.c (remove_unused_scope_block_p): Keep scopes for
all functions, even if they're not declared artificial or inline.
* tree.c (tree_inlined_location): Use macro expansion location
only if scope traversal fails to expose one.

gcc/testsuite/ChangeLog:

PR middle-end/98664
* gcc.dg/Wvla-larger-than-4.c: Adjust expected output.
* gcc.dg/plugin/diagnostic-test-inlining-3.c: Same.
* g++.dg/warn/Wfree-nonheap-object-5.C: New test.
* gcc.dg/Wfree-nonheap-object-4.c: New test.

gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-5.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wfree-nonheap-object-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wvla-larger-than-4.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c
gcc/tree-ssa-live.c
gcc/tree.c

diff --git a/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-5.C b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-5.C
new file mode 100644 (file)
index 0000000..742dba0
--- /dev/null
@@ -0,0 +1,129 @@
+/* PR middle-end/98664 - inconsistent --Wfree-nonheap-object for inlined
+   calls to system headers
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+# 7 "Wfree-nonheap-object-5.h" 1 3
+
+struct A0
+{
+  void *p;
+
+  void f0 (void *q) { p = q; }
+  void g0 (void) {
+    __builtin_free (p);       // { dg-warning "\\\[-Wfree-nonheap-object" }
+  }
+};
+
+struct A1
+{
+  void *p;
+
+  void f0 (void *q) { p = q; }
+  void f1 (void *q) { f0 (q); }
+
+  void g0 (void) {
+    __builtin_free (p);       // { dg-warning "\\\[-Wfree-nonheap-object" }
+  }
+  void g1 (void) { g0 (); }
+};
+
+struct A2
+{
+  void *p;
+
+  void f0 (void *q) { p = q; }
+  void f1 (void *q) { f0 (q); }
+  void f2 (void *q) { f1 (q); }
+
+  void g0 (void) {
+    __builtin_free (p);       // { dg-warning "\\\[-Wfree-nonheap-object" }
+  }
+  void g1 (void) { g0 (); }
+  void g2 (void) { g1 (); }
+};
+
+# 47 "Wfree-nonheap-object-5.C"
+
+#define NOIPA __attribute__ ((noipa))
+
+extern int array[];
+
+/* Verify the warning is issued even for calls in a system header inlined
+   into a function outside the header.  */
+
+NOIPA void warn_g0 (struct A0 *p)
+{
+  int *q = array + 1;
+
+  p->f0 (q);
+  p->g0 ();
+}
+
+// { dg-message "inlined from 'void warn_g0\\(A0\\*\\)'" "" { target *-*-* } 0 }
+
+
+/* Also verify the warning can be suppressed.  */
+
+NOIPA void nowarn_g0 (struct A0 *p)
+{
+  int *q = array + 2;
+
+  p->f0 (q);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  p->g0 ();
+#pragma GCC diagnostic pop
+}
+
+
+NOIPA void warn_g1 (struct A1 *p)
+{
+  int *q = array + 3;
+
+  p->f1 (q);
+  p->g1 ();
+}
+
+// { dg-message "inlined from 'void A1::g1\\(\\)'" "" { target *-*-* } 0 }
+// { dg-message "inlined from 'void warn_g1\\(A1\\*\\)'" "" { target *-*-* } 0 }
+
+
+NOIPA void nowarn_g1 (struct A2 *p)
+{
+  int *q = array + 4;
+
+  p->f1 (q);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  p->g1 ();
+#pragma GCC diagnostic pop
+}
+
+
+NOIPA void warn_g2 (struct A2 *p)
+{
+  int *q = array + 5;
+
+  p->f2 (q);
+  p->g2 ();
+}
+
+// { dg-message "inlined from 'void A2::g1\\(\\)'" "" { target *-*-* } 0 }
+// { dg-message "inlined from 'void A2::g2\\(\\)'" "" { target *-*-* } 0 }
+// { dg-message "inlined from 'void warn_g2\\(A2\\*\\)'" "" { target *-*-* } 0 }
+
+
+NOIPA void nowarn_g2 (struct A2 *p)
+{
+  int *q = array + 6;
+
+  p->f2 (q);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  p->g2 ();
+#pragma GCC diagnostic pop
+}
diff --git a/gcc/testsuite/gcc.dg/Wfree-nonheap-object-4.c b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-4.c
new file mode 100644 (file)
index 0000000..a7d9212
--- /dev/null
@@ -0,0 +1,107 @@
+/* PR middle-end/98664 - inconsistent --Wfree-nonheap-object for inlined
+   calls to system headers
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+# 7 "Wfree-nonheap-object-4.h" 1 3
+
+struct A
+{
+  void *p;
+};
+
+void f0 (struct A *p, void *q) { p->p = q; }
+void f1 (struct A *p, void *q) { f0 (p, q); }
+void f2 (struct A *p, void *q) { f1 (p, q); }
+
+void g0 (struct A *p)
+{
+  __builtin_free (p->p);      // { dg-warning "\\\[-Wfree-nonheap-object" }
+}
+
+void g1 (struct A *p) { g0 (p); }
+void g2 (struct A *p) { g1 (p); }
+
+# 26 "Wfree-nonheap-object-4.c"
+
+#define NOIPA __attribute__ ((noipa))
+
+extern int array[];
+
+/* Verify the warning is issued even for calls in a system header inlined
+   into a function outside the header.  */
+
+NOIPA void warn_g0 (struct A *p)
+{
+  int *q = array + 1;
+
+  f0 (p, q);
+  g0 (p);
+}
+
+// { dg-message "inlined from 'warn_g0'" "" { target *-*-* } 0 }
+
+
+/* Also verify the warning can be suppressed.  */
+
+NOIPA void nowarn_g0 (struct A *p)
+{
+  int *q = array + 2;
+
+  f0 (p, q);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  g0 (p);
+#pragma GCC diagnostic pop
+}
+
+
+NOIPA void warn_g1 (struct A *p)
+{
+  int *q = array + 3;
+
+  f1 (p, q);
+  g1 (p);
+}
+
+// { dg-message "inlined from 'g1'" "" { target *-*-* } 0 }
+// { dg-message "inlined from 'warn_g1'" "" { target *-*-* } 0 }
+
+
+NOIPA void nowarn_g1 (struct A *p)
+{
+  int *q = array + 4;
+
+  f1 (p, q);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  g1 (p);
+#pragma GCC diagnostic pop
+}
+
+
+NOIPA void warn_g2 (struct A *p)
+{
+  int *q = array + 5;
+
+  f2 (p, q);
+  g2 (p);
+}
+
+// { dg-message "inlined from 'g2'" "" { target *-*-* } 0 }
+// { dg-message "inlined from 'warn_g2'" "" { target *-*-* } 0 }
+
+
+NOIPA void nowarn_g2 (struct A *p)
+{
+  int *q = array + 6;
+
+  f2 (p, q);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  g2 (p);
+#pragma GCC diagnostic pop
+}
index de99afbe56e3458fb8f83822dfa40088c892b8c9..7d27829736fbdfe06b02dcd536247c833df44546 100644 (file)
@@ -17,14 +17,14 @@ static inline void inline_use_vla (unsigned n)
 static inline void use_inlined_vla (unsigned n)
 {
   inline_use_vla (n);         // this call is okay
-  inline_use_vla (n + 1);     // this one is not
+  inline_use_vla (n + 1);     // this one is not (line 20)
 }
 
 void call_inline (void)
 {
-  use_inlined_vla (31);
+  use_inlined_vla (31);       // line 25
 }
 
 /* Verify that the inlining context is included and that it points
    to the correct line number in the inlined function:
-   { dg-message "function 'inline_use_vla'..*inlined from 'call_inline' .*:20:" "" { target *-*-* } 0 }  */
+   { dg-message "function 'inline_use_vla'.*inlined from 'use_inlined_vla'.*:20:.*inlined from 'call_inline' .*:25:" "" { target *-*-* } 0 }  */
index e1a4fca2cb4be73b000b56362aed0c1719f43557..56c9546fb8497ca6069755a4674c684d0998de95 100644 (file)
@@ -35,7 +35,8 @@ int main()
    This test case captures this behavior.  */
 
 /* { dg-regexp "In function 'foo'," "" } */
-/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-inlining-3.c:15:3:" "" } */
+/* { dg-regexp "    inlined from 'bar' at .+/diagnostic-test-inlining-3.c:15:3," "" } */
+/* { dg-regexp "    inlined from 'main' at .+/diagnostic-test-inlining-3.c:20:3:" "" } */
 /* { dg-warning "3: message" "" { target *-*-* } 9 } */
 /* { dg-begin-multiline-output "" }
    __emit_warning ("message");
index 02a7a56f0f948e753a6616c9a613f6cccef58077..a2aab25e862e01adffc0d4dcf8dcd3675d8c41ef 100644 (file)
@@ -555,20 +555,17 @@ remove_unused_scope_block_p (tree scope, bool in_ctor_dtor_block)
      ;
    /* When not generating debug info we can eliminate info on unused
       variables.  */
-   else if (!flag_auto_profile && debug_info_level == DINFO_LEVEL_NONE
+   else if (!flag_auto_profile
+           && debug_info_level == DINFO_LEVEL_NONE
            && !optinfo_wants_inlining_info_p ())
      {
-       /* Even for -g0 don't prune outer scopes from artificial
-         functions, otherwise diagnostics using tree_nonartificial_location
-         will not be emitted properly.  */
+       /* Even for -g0 don't prune outer scopes from inlined functions,
+         otherwise late diagnostics from such functions will not be
+         emitted or suppressed properly.  */
        if (inlined_function_outer_scope_p (scope))
         {
-          tree ao = BLOCK_ORIGIN (scope);
-          if (ao
-              && TREE_CODE (ao) == FUNCTION_DECL
-              && DECL_DECLARED_INLINE_P (ao)
-              && lookup_attribute ("artificial", DECL_ATTRIBUTES (ao)))
-            unused = false;
+          gcc_assert (TREE_CODE (BLOCK_ORIGIN (scope)) == FUNCTION_DECL);
+          unused = false;
         }
      }
    else if (BLOCK_VARS (scope) || BLOCK_NUM_NONLOCALIZED_VARS (scope))
index a25c71f11526530677895c341792f515c017a25b..061fe43aa3157cc5fdb93e260576d4c13f7b03b1 100644 (file)
@@ -12638,10 +12638,13 @@ tree_inlined_location (tree exp, bool system_header /* = true */)
     }
 
   if (loc == UNKNOWN_LOCATION)
-    loc = EXPR_LOCATION (exp);
-
-  if (system_header)
-    return expansion_point_location_if_in_system_header (loc);
+    {
+      loc = EXPR_LOCATION (exp);
+      if (system_header)
+       /* Only consider macro expansion when the block traversal failed
+          to find a location.  Otherwise it's not relevant.  */
+       return expansion_point_location_if_in_system_header (loc);
+    }
 
   return loc;
 }