This is a new version of my -Wmeminit patch, first posted to PR c++/2972.
Jason suggested combining the Wmeminit warning with the adjacent
Weffc++ one which I agree with. The advice in the Effective C++ book
actually says not to leave members uninitialized, rather than saying
*all* members must have a mem-initializer (which is just annoying in
many cases if the type has a safe default constructor), and my patch
provides a better check for that by only warning when data is left
uninitialized.
Unfortunately this doesn't work very well in C++11 mode, as defaulted
constructors don't cause warnings when they should do e.g.
struct C
{
int i;
C() = default;
};
This doesn't produce the same warning as C() {} even though that's
what the defaulted constructor is equivalent to.
I'm posting it for comment and in case anyone else has time to work on it.
* c-family/c.opt (Wmeminit): Add new option.
* c-family/c-opts.c: Include it in Wecpp
* cp/init.c: Implement Wmeminit.
* doc/invoke.texi: document it.
* testsuite/g++.dg/warn/Wmeminit.C: New.
Index: c-family/c.opt
===================================================================
--- c-family/c.opt (revision 181096)
+++ c-family/c.opt (working copy)
@@ -461,6 +461,10 @@
C ObjC C++ ObjC++ Var(warn_main) Init(-1) Warning
Warn about suspicious declarations of \"main\"
+Wmeminit
+C++ Var(warn_meminit) Warning
+Warn about missing member initializers in constructors which leave data uninitialized
+
Wmissing-braces
C ObjC C++ ObjC++ Var(warn_missing_braces) Warning
Warn about possibly missing braces around initializers
Index: c-family/c-opts.c
===================================================================
--- c-family/c-opts.c (revision 181096)
+++ c-family/c-opts.c (working copy)
@@ -550,7 +550,14 @@
case OPT_Weffc__:
warn_ecpp = value;
if (value)
- warn_nonvdtor = true;
+ {
+ /* Effective C++ rule 12 says to prefer using a mem-initializer
+ to assignment. */
+ warn_meminit = true;
+ /* Effective C++ rule 14 says to declare destructors virtual
+ in polymorphic classes. */
+ warn_nonvdtor = true;
+ }
break;
case OPT_ansi:
Index: cp/init.c
===================================================================
--- cp/init.c (revision 181096)
+++ cp/init.c (working copy)
@@ -518,13 +518,27 @@
}
}
- /* Effective C++ rule 12 requires that all data members be
- initialized. */
- if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
- warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Weffc__,
- "%qD should be initialized in the member initialization list",
- member);
+ /* Warn if there is no initializer for a member which will leave data
+ uninitialized. */
+ if (warn_meminit && init == NULL_TREE)
+ {
+ tree field = default_init_uninitialized_part (type);
+ if (field)
+ {
+ if (DECL_P (field))
+ warning_at (DECL_SOURCE_LOCATION (current_function_decl),
+ OPT_Wmeminit,
+ "%qD is not initialized in the member initialization"
+ " list, so %q+#D is uninitialized", member, field);
+ else
+ warning_at (DECL_SOURCE_LOCATION (current_function_decl),
+ OPT_Wmeminit,
+ "%qD is not initialized in the member initialization"
+ " list", member);
+ }
+ }
+
/* Get an lvalue for the data member. */
decl = build_class_member_access_expr (current_class_ref, member,
/*access_path=*/NULL_TREE,
Index: testsuite/g++.dg/warn/Wmeminit.C
===================================================================
--- testsuite/g++.dg/warn/Wmeminit.C (revision 0)
+++ testsuite/g++.dg/warn/Wmeminit.C (revision 0)
@@ -0,0 +1,72 @@
+// PR c++/2972
+// { dg-do compile }
+// { dg-options "-Wmeminit" }
+
+// Warn when a constructor (user-declared or implicitly-declared)
+// leaves members uninitialized.
+
+struct A
+{
+ int i;
+ A() : i() { } // { dg-bogus "uninitialized" }
+};
+
+struct B
+{
+ int i;
+ B() { } // { dg-warning "'B::i' is not initialized" }
+};
+
+struct C // { dg-bogus "uninitialized" }
+{
+ int i;
+};
+
+struct D
+{
+ C c;
+ D() : c() { } // { dg-bogus "uninitialized" }
+};
+
+struct E
+{
+ int i; // { dg-warning "'F::e' is not initialized" }
+};
+
+struct F
+{
+ E e;
+ F() { }
+};
+
+struct G
+{
+ int i; // { dg-warning "'H::g' is not initialized" }
+};
+
+struct H
+{
+ G g;
+ H(const H&) { }
+};
+
+struct I // { dg-warning "'I::i' is not initialized" }
+{
+ int i;
+};
+
+struct J : I
+{
+ J() { }
+};
+
+struct K // { dg-warning "'K::i' is not initialized" }
+{
+ int i;
+};
+
+struct L : K
+{
+ L(const L&) { }
+};
+
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi (revision 181096)
+++ doc/invoke.texi (working copy)
@@ -2371,6 +2371,22 @@
base class does not have a virtual destructor. This warning is enabled
by @option{-Wall}.
+@item -Wmeminit @r{(C++ and Objective-C++ only)}
+@opindex Wmeminit
+@opindex Wno-meminit
+Warn about missing member initializers in constructors which leave data
+uninitialized. A warning will still be given even if the member is
+initialized in the constructor body e.g.
+
+@smallexample
+struct A @{
+ int i;
+ A() @{ i = 0; @} // warning: 'A::i' is not initialized
+@};
+@end smallexample
+
+This warning is enabled if -Weffc++ is specified.
+
@item -Wnarrowing @r{(C++ and Objective-C++ only)}
@opindex Wnarrowing
@opindex Wno-narrowing