[PATCH] middle-end: Preserve frontend diagnostics in free-lang-data [PR101551, PR106274] gcc/ChangeLog: PR lto/106274 PR middle-end/101551 * ipa-free-lang-data.cc (free_lang_data_in_decl): Preserve DECL_CONTEXT for class member functions. (free_lang_data): Do not reset frontend diagnostics customizations. gcc/testsuite/ChangeLog: PR lto/106274 PR middle-end/101551 * c-c++-common/diag-after-fld-1.c: New test. * g++.dg/diag-after-fld-1.C: New test. * g++.dg/diag-after-fld-2.C: New test. * gfortran.dg/allocatable_uninitialized_2.f90: New test. * objc.dg/diag-after-fld-1.m: New test. diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc index ccdbf849c25..391b7689639 100644 --- a/gcc/ipa-free-lang-data.cc +++ b/gcc/ipa-free-lang-data.cc @@ -682,10 +682,8 @@ free_lang_data_in_decl (tree decl, class free_lang_data_d *fld) devirutalization code we always walk through aliases and we need context to be preserved too. See PR89335 */ if (TREE_CODE (decl) != FIELD_DECL - && ((TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) - || (!DECL_VIRTUAL_P (decl) - && (TREE_CODE (decl) != FUNCTION_DECL - || !DECL_CXX_DESTRUCTOR_P (decl))))) + && TREE_CODE (decl) != VAR_DECL + && TREE_CODE (decl) != FUNCTION_DECL) DECL_CONTEXT (decl) = fld_decl_context (DECL_CONTEXT (decl)); } @@ -1115,7 +1113,6 @@ free_lang_data (void) /* Reset some langhooks. Do not reset types_compatible_p, it may still be used indirectly via the get_alias_set langhook. */ lang_hooks.dwarf_name = lhd_dwarf_name; - lang_hooks.decl_printable_name = gimple_decl_printable_name; lang_hooks.gimplify_expr = lhd_gimplify_expr; lang_hooks.overwrite_decl_assembler_name = lhd_overwrite_decl_assembler_name; lang_hooks.print_xnode = lhd_print_tree_nothing; @@ -1141,9 +1138,6 @@ free_lang_data (void) make sure we never call decl_assembler_name on local symbols and devise a separate, middle-end private scheme for it. */ - /* Reset diagnostic machinery. */ - tree_diagnostics_defaults (global_dc); - rebuild_type_inheritance_graph (); delete fld_incomplete_types; diff --git a/gcc/testsuite/c-c++-common/diag-after-fld-1.c b/gcc/testsuite/c-c++-common/diag-after-fld-1.c new file mode 100644 index 00000000000..c1fc87a03f3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/diag-after-fld-1.c @@ -0,0 +1,25 @@ +/* Make sure that post-ipa-free-lang-data diagnostics expand macros as + expected. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target lto } */ +/* { dg-options "-flto -O2 -Wnonnull-compare" } */ + +#define X(p) p == 0 /* { dg-warning {-Wnonnull-compare} } */ +int f (void *) __attribute__((nonnull)); +int f (void *p) +{ + return X (p); /* { dg-note {in expansion of macro 'X'} } */ +} + +#define X2(p) p == 0 /* { dg-warning {-Wnonnull-compare} } */ +#define Y2(p) X2(p) /* { dg-note {in expansion of macro 'X2'} } */ + +#define MAKE_F2 \ + int f2 (void *) __attribute__((nonnull)); \ + int f2 (void *p) \ + { \ + return Y2 (p); /* { dg-note {in expansion of macro 'Y2'} } */ \ + } + +MAKE_F2 /* { dg-note {in expansion of macro 'MAKE_F2'} } */ diff --git a/gcc/testsuite/g++.dg/diag-after-fld-1.C b/gcc/testsuite/g++.dg/diag-after-fld-1.C new file mode 100644 index 00000000000..0f8d10b7848 --- /dev/null +++ b/gcc/testsuite/g++.dg/diag-after-fld-1.C @@ -0,0 +1,470 @@ +/* Based on 20090121-1.C; verify these middle-end diagnostics work fine after + ipa-free-lang data pass. Try to exercise most code paths in cp/error.cc: + dump_function_decl(), i.e. various combinations of templates and member + functions. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target lto } */ +/* { dg-options "-flto -Wuninitialized -O2" } */ + +int y; + +int w1 (int) +{ + struct S + { + S () /* { dg-regexp {.*: In constructor 'w1\(int\)::S::S\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S(), y; +} + +template +int w2 (T) +{ + struct S + { + S () /* { dg-regexp {.*: In constructor 'w2\(T\)::S::S\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S (), y; +} +int w2a () +{ + return w2('\0'); +} + +int w3 (int) +{ + struct S + { + void f2 () /* { dg-regexp {.*: In member function 'void w3\(int\)::S::f2\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S().f2 (), y; +} + +template +int w4 (T) +{ + struct S + { + void f2 () /* { dg-regexp {.*: In member function 'void w4\(T\)::S::f2\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S().f2 (), y; +} +int w4a () +{ + return w4 ('\0'); +} + +struct A1 +{ + A1 () /* { dg-regexp {.*: In constructor 'A1::A1\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + void f2 () /* { dg-regexp {.*: In member function 'void A1::f2\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + void f3 () /* { dg-regexp {.*: In member function 'void A1::f3\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + static int f4() /* { dg-regexp {.*: In static member function 'static int A1::f4\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + operator int () /* { dg-regexp {.*: In member function 'A1::operator int\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + operator T* () /* { dg-regexp {.*: In member function 'A1::operator T\*\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + return 0; + } +}; + +int f1 () +{ + return A1 (), y; +} + +int f2 () +{ + return A1 ().f2 (), y; +} + +int f3 () +{ + return A1 ().f3 (), y; +} + +int f4 () +{ + return A1 ().f4 (); +} + +int f5 () +{ + return A1 (); +} + +int f6 () +{ + char *s = A1 (); + return y; +} + +template +struct A2 +{ + A2 () /* { dg-regexp {.*: In constructor 'A2::A2\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + void f2 () /* { dg-regexp {.*: In member function 'void A2::f2\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + void f3 () /* { dg-regexp {.*: In member function 'void A2::f3\(\) \[with U = char; T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + static int f4() /* { dg-regexp {.*: In static member function 'static int A2::f4\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + operator int () /* { dg-regexp {.*: In member function 'A2::operator int\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + operator U* () /* { dg-regexp {.*: In member function 'A2::operator U\*\(\) \[with U = char; T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + return 0; + } +}; + +int g1 () +{ + return A2 (), y; +} + +int g2 () +{ + return A2 ().f2 (), y; +} + +int g3 () +{ + return A2 ().f3 (), y; +} + +int g4 () +{ + return A2 ().f4 (); +} + +int g5 () +{ + return A2 (); +} + +int g6 () +{ + char *s = A2 (); + return y; +} + +struct A3 +{ + ~A3 () /* { dg-regexp {.*: In destructor 'A3::~A3\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } +}; + +int h1 () +{ + { + A3 a; + } + return y; +} + +/* Let's do it all again inside a namespace too. */ +namespace N { + +int w1 (int) +{ + struct S + { + S () /* { dg-regexp {.*: In constructor 'N::w1\(int\)::S::S\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S(), y; +} + +template +int w2 (T) +{ + struct S + { + S () /* { dg-regexp {.*: In constructor 'N::w2\(T\)::S::S\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S (), y; +} +int w2a () +{ + return w2('\0'); +} + +int w3 (int) +{ + struct S + { + void f2 () /* { dg-regexp {.*: In member function 'void N::w3\(int\)::S::f2\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S().f2 (), y; +} + +template +int w4 (T) +{ + struct S + { + void f2 () /* { dg-regexp {.*: In member function 'void N::w4\(T\)::S::f2\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + }; + return S().f2 (), y; +} +int w4a () +{ + return w4 ('\0'); +} + +struct A1 +{ + A1 () /* { dg-regexp {.*: In constructor 'N::A1::A1\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + void f2 () /* { dg-regexp {.*: In member function 'void N::A1::f2\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + void f3 () /* { dg-regexp {.*: In member function 'void N::A1::f3\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + static int f4() /* { dg-regexp {.*: In static member function 'static int N::A1::f4\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + operator int () /* { dg-regexp {.*: In member function 'N::A1::operator int\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + operator T* () /* { dg-regexp {.*: In member function 'N::A1::operator T\*\(\) \[with T = char\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + return 0; + } + +}; + +int f1 () +{ + return A1 (), y; +} + +int f2 () +{ + return A1 ().f2 (), y; +} + +int f3 () +{ + return A1 ().f3 (), y; +} + +int f4 () +{ + return A1 ().f4 (); +} + +int f5 () +{ + return A1 (); +} + +int f6 () +{ + char *s = A1 (); + return y; +} + +template +struct A2 +{ + A2 () /* { dg-regexp {.*: In constructor 'N::A2::A2\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + void f2 () /* { dg-regexp {.*: In member function 'void N::A2::f2\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + void f3 () /* { dg-regexp {.*: In member function 'void N::A2::f3\(\) \[with U = char; T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + static int f4() /* { dg-regexp {.*: In static member function 'static int N::A2::f4\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + operator int () /* { dg-regexp {.*: In member function 'N::A2::operator int\(\) \[with T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } + + template + operator U* () /* { dg-regexp {.*: In member function 'N::A2::operator U\*\(\) \[with U = char; T = void\]':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + return 0; + } + +}; + +int g1 () +{ + return A2 (), y; +} + +int g2 () +{ + return A2 ().f2 (), y; +} + +int g3 () +{ + return A2 ().f3 (), y; +} + +int g4 () +{ + return A2 ().f4 (); +} + +int g5 () +{ + return A2 (); +} + +int g6 () +{ + char *s = A2 (); + return y; +} + +struct A3 +{ + ~A3 () /* { dg-regexp {.*: In destructor 'N::A3::~A3\(\)':} } */ + { + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {'x' is used uninitialized} } */ + } +}; + +int h1 () +{ + { + A3 a; + } + return y; +} + + +} /* namespace N */ diff --git a/gcc/testsuite/g++.dg/diag-after-fld-2.C b/gcc/testsuite/g++.dg/diag-after-fld-2.C new file mode 100644 index 00000000000..ffc5ae5c635 --- /dev/null +++ b/gcc/testsuite/g++.dg/diag-after-fld-2.C @@ -0,0 +1,27 @@ +/* Continuation of diag-after-fld-1.C for C++11 features. */ +/* { dg-do compile { target c++11 } } */ +/* { dg-require-effective-target lto } */ +/* { dg-options "-flto -Wuninitialized -O2" } */ + +int y; + +int f1 (int) +{ + return [] () { /* { dg-regexp {.*: In lambda function:} } */ + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } (); +} + +template +int f2 (T) +{ + return [] () { /* { dg-regexp {.*: In lambda function:} } */ + int x; /* { dg-note {'x' was declared here} } */ + return y = x; /* { dg-warning {'x' is used uninitialized} } */ + } (); +} +int f2a () +{ + return f2('\0'); +} diff --git a/gcc/testsuite/gfortran.dg/allocatable_uninitialized_2.f90 b/gcc/testsuite/gfortran.dg/allocatable_uninitialized_2.f90 new file mode 100644 index 00000000000..9664ad63ba9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/allocatable_uninitialized_2.f90 @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-require-effective-target lto } +! { dg-options "-O -Wall -flto" } +! { dg-additional-options "-fdiagnostics-show-caret -fdiagnostics-show-line-numbers" } + +program main + real,allocatable:: a(:),b(:) + + a(1)=2*b(1) + +end + +! { dg-allow-blank-lines-in-output 1 } +! { dg-regexp {.*allocatable_uninitialized_2\.f90:9:14:\n\n 9 \| a\(1\)=2\*b\(1\)\n \| \^\nWarning: 'b.offset' is used uninitialized \[-Wuninitialized\]\n} } +! { dg-regexp {.*allocatable_uninitialized_2\.f90:7:30:\n\n 7 \| real,allocatable:: a\(:\),b\(:\)\n \| \^\nnote: 'b' declared here\n} } +! { dg-regexp {.*allocatable_uninitialized_2\.f90:9:14:\n\n 9 \| a\(1\)=2\*b\(1\)\n \| \^\nWarning: 'a.offset' is used uninitialized \[-Wuninitialized\]\n} } +! { dg-regexp {.*allocatable_uninitialized_2\.f90:7:25:\n\n 7 \| real,allocatable:: a\(:\),b\(:\)\n \| \^\nnote: 'a' declared here\n} } diff --git a/gcc/testsuite/objc.dg/diag-after-fld-1.m b/gcc/testsuite/objc.dg/diag-after-fld-1.m new file mode 100644 index 00000000000..3bc4aa18997 --- /dev/null +++ b/gcc/testsuite/objc.dg/diag-after-fld-1.m @@ -0,0 +1,24 @@ +/* Make sure that post-ipa-free-lang-data diagnostics call objc_printable_name + as expected. */ + +/* { dg-do compile } */ +/* { dg-require-effective-target lto } */ +/* { dg-options "-flto -O2 -Wuninitialized" } */ + +#include "../objc-obj-c++-shared/TestsuiteObject.m" + +@interface T : TestsuiteObject ++ (void) f; +@end + +int y; + +@implementation T +/* This dg-regexp is the main test; prior to this patch, we output the mangled + name '_c_T__f' here. */ ++ (void) f /* { dg-regexp {.*: In function '\+\[T f\]':} } */ +{ + int x; /* { dg-note {'x' was declared here} } */ + y = x; /* { dg-warning {-Wuninitialized} } */ +} +@end