This adds a new warning, -Wglobal-constructors, that warns whenever a decl requires a global constructor or destructor. This new warning fires whenever a thread_local or global variable is declared whose type has a non-trivial constructor or destructor. When faced with both a constructor and a destructor, the error message mentions the destructor and is only fired once.
This warning mirrors the Clang option -Wglobal-constructors, which warns on the same thing. -Wglobal-constructors was present in Apple's GCC and later made its way into Clang. Bootstrapped and regression-tested on x86-64 linux, new tests passing. gcc/ChangeLog: 2019-05-28 Sean Gillespie <s...@swgillespie.me> * doc/invoke.texi: Add new flag -Wglobal-constructors. gcc/c-family/ChangeLog: 2019-05-28 Sean Gillespie <s...@swgillespie.me> * c.opt: Add new flag -Wglobal-constructors. gcc/cp/ChangeLog: 2019-05-28 Sean Gillespie <s...@swgillespie.me> * decl.c (expand_static_init): Warn if a thread local or static decl requires a non-trivial constructor or destructor. gcc/testsuite/ChangeLog: 2019-05-28 Sean Gillespie <s...@swgillespie.me> * g++.dg/warn/global-constructors-1.C: New test. * g++.dg/warn/global-constructors-2.C: New test. --- gcc/c-family/c.opt | 4 +++ gcc/cp/decl.c | 17 ++++++++++--- gcc/doc/invoke.texi | 7 ++++++ .../g++.dg/warn/global-constructors-1.C | 25 +++++++++++++++++++ .../g++.dg/warn/global-constructors-2.C | 23 +++++++++++++++++ 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/global-constructors-1.C create mode 100644 gcc/testsuite/g++.dg/warn/global-constructors-2.C diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 046d489f7eb..cf62625ca42 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -613,6 +613,10 @@ Wformat-truncation= C ObjC C++ LTO ObjC++ Joined RejectNegative UInteger Var(warn_format_trunc) Warning LangEnabledBy(C ObjC C++ LTO ObjC++,Wformat=, warn_format >= 1, 0) IntegerRange(0, 2) Warn about calls to snprintf and similar functions that truncate output. +Wglobal-constructors +C++ ObjC++ Var(warn_global_constructors) Warning +Warn when a global declaration requires a constructor to initialize. + Wif-not-aligned C ObjC C++ ObjC++ Var(warn_if_not_aligned) Init(1) Warning Warn when the field in a struct is not aligned. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 19d14a6a5e9..c1d66195bd7 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8467,10 +8467,21 @@ expand_static_init (tree decl, tree init) finish_then_clause (if_stmt); finish_if_stmt (if_stmt); } - else if (CP_DECL_THREAD_LOCAL_P (decl)) - tls_aggregates = tree_cons (init, decl, tls_aggregates); else - static_aggregates = tree_cons (init, decl, static_aggregates); + { + if (CP_DECL_THREAD_LOCAL_P (decl)) + tls_aggregates = tree_cons (init, decl, tls_aggregates); + else + static_aggregates = tree_cons (init, decl, static_aggregates); + + if (warn_global_constructors) + { + if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) + warning(OPT_Wglobal_constructors, "declaration requires a global destructor"); + else + warning(OPT_Wglobal_constructors, "declaration requires a global constructor"); + } + } } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 4964cc41ba3..a9b2e47a302 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -312,6 +312,7 @@ Objective-C and Objective-C++ Dialects}. -Wformat-security -Wformat-signedness -Wformat-truncation=@var{n} @gol -Wformat-y2k -Wframe-address @gol -Wframe-larger-than=@var{byte-size} -Wno-free-nonheap-object @gol +-Wglobal-constructors @gol -Wjump-misses-init @gol -Whsa -Wif-not-aligned @gol -Wignored-qualifiers -Wignored-attributes -Wincompatible-pointer-types @gol @@ -6509,6 +6510,12 @@ to @option{-Wframe-larger-than=}@samp{SIZE_MAX} or larger. Do not warn when attempting to free an object that was not allocated on the heap. +@item -Wglobal-constructors @r{(C++ and Objective-C++ only)} +@opindex Wglobal-constructors +@opindex Wno-global-constructors +Warn if the compiler detects a global declaration that requires +a constructor to initialize. + @item -Wstack-usage=@var{byte-size} @opindex Wstack-usage @opindex Wno-stack-usage diff --git a/gcc/testsuite/g++.dg/warn/global-constructors-1.C b/gcc/testsuite/g++.dg/warn/global-constructors-1.C new file mode 100644 index 00000000000..5a6869e9dcd --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/global-constructors-1.C @@ -0,0 +1,25 @@ +// { dg-do compile } +// { dg-options "-Wglobal-constructors" } + +struct with_ctor { + int x; + with_ctor() : x(42) {} +}; + +struct with_dtor { + ~with_dtor() {} +}; + +struct with_both { + int x; + with_both() : x(42) {} + ~with_both() {} +}; + +with_ctor global_var; /* { dg-warning "declaration requires a global constructor" } */ +with_dtor global_var2; /* { dg-warning "declaration requires a global destructor" } */ +with_both global_var3; /* { dg-warning "declaration requires a global destructor" } */ + +int main() { + static with_ctor global_var; /* { dg-bogus "declaration requires a global constructor" } */ +} diff --git a/gcc/testsuite/g++.dg/warn/global-constructors-2.C b/gcc/testsuite/g++.dg/warn/global-constructors-2.C new file mode 100644 index 00000000000..e753b9cb507 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/global-constructors-2.C @@ -0,0 +1,23 @@ +// { dg-do compile } +// { dg-require-effective-target c++11 } +// { dg-options "-Wglobal-constructors" } + +struct with_ctor { + int x; + + with_ctor() : x(42) {} +}; + +struct with_dtor { + ~with_dtor() {} +}; + +struct with_both { + int x; + with_both() : x(42) {} + ~with_both() {} +}; + +thread_local with_ctor global_var; /* { dg-warning "declaration requires a global constructor" } */ +thread_local with_dtor global_var2; /* { dg-warning "declaration requires a global destructor" } */ +thread_local with_both global_var3; /* { dg-warning "declaration requires a global destructor" } */ -- 2.20.1