PR middle-end/98664 - inconsistent -Wfree-nonheap-object for inlined calls to system headers 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. 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 index 00000000000..742dba0cf58 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wfree-nonheap-object-5.C @@ -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 index 00000000000..a7d921248c4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-4.c @@ -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 +} diff --git a/gcc/testsuite/gcc.dg/Wvla-larger-than-4.c b/gcc/testsuite/gcc.dg/Wvla-larger-than-4.c index de99afbe56e..7d27829736f 100644 --- a/gcc/testsuite/gcc.dg/Wvla-larger-than-4.c +++ b/gcc/testsuite/gcc.dg/Wvla-larger-than-4.c @@ -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 } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c index e1a4fca2cb4..56c9546fb84 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-inlining-3.c @@ -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"); diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index 02a7a56f0f9..5f58bfb9168 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -555,19 +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))) + tree orig = BLOCK_ORIGIN (scope); + if (TREE_CODE (orig) == FUNCTION_DECL) unused = false; } } diff --git a/gcc/tree.c b/gcc/tree.c index a25c71f1152..061fe43aa31 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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; }