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

Reply via email to