public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
@ 2011-11-07 21:47 Jonathan Wakely
  2011-11-07 21:58 ` Jason Merrill
  2011-11-07 22:42 ` Gabriel Dos Reis
  0 siblings, 2 replies; 10+ messages in thread
From: Jonathan Wakely @ 2011-11-07 21:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 1097 bytes --]

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.

[-- Attachment #2: 2972.patch --]
[-- Type: text/x-patch, Size: 4608 bytes --]

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-07 21:47 [patch] c++/2972 warn when ctor-initializer leaves uninitialized data Jonathan Wakely
@ 2011-11-07 21:58 ` Jason Merrill
  2011-11-10 20:17   ` Jonathan Wakely
  2011-11-07 22:42 ` Gabriel Dos Reis
  1 sibling, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2011-11-07 21:58 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches

On 11/07/2011 04:43 PM, Jonathan Wakely wrote:
> Unfortunately this doesn't work very well in C++11 mode, as defaulted
> constructors don't cause warnings when they should do e.g.

Maybe check this in defaulted_late_check?

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-07 21:47 [patch] c++/2972 warn when ctor-initializer leaves uninitialized data Jonathan Wakely
  2011-11-07 21:58 ` Jason Merrill
@ 2011-11-07 22:42 ` Gabriel Dos Reis
  2011-11-07 22:42   ` Jason Merrill
  2011-11-07 23:28   ` Jonathan Wakely
  1 sibling, 2 replies; 10+ messages in thread
From: Gabriel Dos Reis @ 2011-11-07 22:42 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches, Jason Merrill

On Mon, Nov 7, 2011 at 3:43 PM, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> 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.

so the defaulted constructor does not initialize C::i?

>
> 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.
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-07 22:42 ` Gabriel Dos Reis
@ 2011-11-07 22:42   ` Jason Merrill
  2011-11-08  0:18     ` Gabriel Dos Reis
  2011-11-07 23:28   ` Jonathan Wakely
  1 sibling, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2011-11-07 22:42 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: Jonathan Wakely, gcc-patches

On 11/07/2011 05:38 PM, Gabriel Dos Reis wrote:
>> struct C
>> {
>>   int i;
>>   C() = default;
>> };
>
> so the defaulted constructor does not initialize C::i?

No, it doesn't.  value-initialization of a C will initialize it, but not 
default-initialization.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-07 22:42 ` Gabriel Dos Reis
  2011-11-07 22:42   ` Jason Merrill
@ 2011-11-07 23:28   ` Jonathan Wakely
  1 sibling, 0 replies; 10+ messages in thread
From: Jonathan Wakely @ 2011-11-07 23:28 UTC (permalink / raw)
  To: Gabriel Dos Reis; +Cc: gcc-patches, Jason Merrill

On 7 November 2011 22:38, Gabriel Dos Reis wrote:
>> 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.
>
> so the defaulted constructor does not initialize C::i?

[class.ctor] p6

A default constructor that is defaulted and not defined as deleted is
implicitly defined when it is odr-used (3.2) to create an object of its
class type (1.8) or when it is explicitly defaulted after its first
declaration. The implicitly-defined default constructor performs the
set of initializations of the class that would be
performed by a user-written default constructor for that class with no
ctor-initializer (12.6.2) and an empty compound-statement.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-07 22:42   ` Jason Merrill
@ 2011-11-08  0:18     ` Gabriel Dos Reis
  0 siblings, 0 replies; 10+ messages in thread
From: Gabriel Dos Reis @ 2011-11-08  0:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jonathan Wakely, gcc-patches

On Mon, Nov 7, 2011 at 4:39 PM, Jason Merrill <jason@redhat.com> wrote:
> On 11/07/2011 05:38 PM, Gabriel Dos Reis wrote:
>>>
>>> struct C
>>> {
>>>  int i;
>>>  C() = default;
>>> };
>>
>> so the defaulted constructor does not initialize C::i?
>
> No, it doesn't.  value-initialization of a C will initialize it, but not
> default-initialization.
>

Thanks! (obvously I was stuck with earlier variation of the proposal.)

-- Gaby

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-07 21:58 ` Jason Merrill
@ 2011-11-10 20:17   ` Jonathan Wakely
  2011-11-10 20:25     ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Jonathan Wakely @ 2011-11-10 20:17 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 423 bytes --]

On 7 November 2011 21:47, Jason Merrill wrote:
> On 11/07/2011 04:43 PM, Jonathan Wakely wrote:
>>
>> Unfortunately this doesn't work very well in C++11 mode, as defaulted
>> constructors don't cause warnings when they should do e.g.
>
> Maybe check this in defaulted_late_check?

I tried that (attached) and it does cause warnings in defaulted
constructed, but even for members with an NSDMI, which are not
uninitialized.

[-- Attachment #2: 2972.patch --]
[-- Type: text/x-patch, Size: 4719 bytes --]

Index: c-family/c.opt
===================================================================
--- c-family/c.opt	(revision 181173)
+++ c-family/c.opt	(working copy)
@@ -461,6 +461,10 @@ Wmain
 C ObjC C++ ObjC++ Var(warn_main) Init(-1) Warning
 Warn about suspicious declarations of \"main\"
 
+Wmeminit
+C++ Var(warn_meminit) Warning
+Warn about POD members which are not initialized in a constructor initialization list
+
 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 181173)
+++ c-family/c-opts.c	(working copy)
@@ -550,7 +550,14 @@ c_common_handle_option (size_t scode, co
     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 181173)
+++ cp/init.c	(working copy)
@@ -485,6 +485,42 @@ build_value_init_noctor (tree type, tsub
   return build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
 }
 
+/* Warn if default initialization of MEMBER of type TYPE in constructor
+ * CONS will leave some parts uninitialized.  */
+
+static void
+warn_meminit_leaves_uninitialized (tree member, tree type, tree cons)
+{
+  tree field = default_init_uninitialized_part (type);
+  if (!field)
+    return;
+
+  if (DECL_P (field))
+    warning_at (DECL_SOURCE_LOCATION (cons), OPT_Wmeminit,
+                "no member initializer for %qD so %q+#D is uninitialized",
+                member, field);
+  else
+    warning_at (DECL_SOURCE_LOCATION (cons), OPT_Wmeminit,
+                "no member initializer for %qD so it is uninitialized",
+                member);
+}
+
+/* Warn if defaulted constructor CONS for TYPE with no mem-initializer-list
+   will leave uninitialized data.  */
+
+void
+warn_missing_meminits (tree type, tree cons)
+{
+  tree mem_inits = sort_mem_initializers (type, NULL_TREE);
+  while (mem_inits)
+    {
+      tree member = TREE_PURPOSE (mem_inits);
+      /* TODO do not warn if brace-or-equal-initializer */
+      warn_meminit_leaves_uninitialized (member, TREE_TYPE (member), cons);
+      mem_inits = TREE_CHAIN (mem_inits);
+    }
+}
+
 /* Initialize MEMBER, a FIELD_DECL, with INIT, a TREE_LIST of
    arguments.  If TREE_LIST is void_type_node, an empty initializer
    list was given; if NULL_TREE no initializer was given.  */
@@ -518,12 +554,10 @@ perform_member_init (tree member, tree i
 	}
     }
 
-  /* 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 be left
+     uninitialized.  */
+  if (warn_meminit && init == NULL_TREE)
+      warn_meminit_leaves_uninitialized (member, type, current_function_decl);
 
   /* Get an lvalue for the data member.  */
   decl = build_class_member_access_expr (current_class_ref, member,
Index: cp/method.c
===================================================================
--- cp/method.c	(revision 181173)
+++ cp/method.c	(working copy)
@@ -1655,6 +1655,10 @@ defaulted_late_check (tree fn)
 
   if (DECL_DELETED_FN (implicit_fn))
     DECL_DELETED_FN (fn) = 1;
+
+  if (warn_meminit && (kind == sfk_constructor || kind == sfk_copy_constructor
+        || kind == sfk_move_constructor))
+    warn_missing_meminits (current_class_type, fn);
 }
 
 /* Returns true iff FN can be explicitly defaulted, and gives any
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 181173)
+++ cp/cp-tree.h	(working copy)
@@ -4915,6 +4915,7 @@ extern bool user_provided_p			(tree);
 extern bool type_has_user_provided_constructor  (tree);
 extern bool type_has_user_provided_default_constructor (tree);
 extern tree default_init_uninitialized_part (tree);
+extern void warn_missing_meminits (tree, tree);
 extern bool trivial_default_constructor_is_constexpr (tree);
 extern bool type_has_constexpr_default_constructor (tree);
 extern bool type_has_virtual_destructor		(tree);

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-10 20:17   ` Jonathan Wakely
@ 2011-11-10 20:25     ` Jason Merrill
  2011-11-10 20:28       ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2011-11-10 20:25 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches

On 11/10/2011 02:48 PM, Jonathan Wakely wrote:
> +warn_missing_meminits (tree type, tree cons)
> +{
> +  tree mem_inits = sort_mem_initializers (type, NULL_TREE);
> +  while (mem_inits)
> +    {
> +      tree member = TREE_PURPOSE (mem_inits);
> +      /* TODO do not warn if brace-or-equal-initializer */
> +      warn_meminit_leaves_uninitialized (member, TREE_TYPE (member), cons);
> +      mem_inits = TREE_CHAIN (mem_inits);
> +    }
> +}

Check DECL_INITIAL (member) to tell if it has an NSDMI.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-10 20:25     ` Jason Merrill
@ 2011-11-10 20:28       ` Jason Merrill
  2011-11-11  0:00         ` Jonathan Wakely
  0 siblings, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2011-11-10 20:28 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: gcc-patches

On 11/10/2011 03:10 PM, Jason Merrill wrote:
> On 11/10/2011 02:48 PM, Jonathan Wakely wrote:
>> +warn_missing_meminits (tree type, tree cons)
>> +{
>> + tree mem_inits = sort_mem_initializers (type, NULL_TREE);
>> + while (mem_inits)
>> + {
>> + tree member = TREE_PURPOSE (mem_inits);
>> + /* TODO do not warn if brace-or-equal-initializer */
>> + warn_meminit_leaves_uninitialized (member, TREE_TYPE (member), cons);
>> + mem_inits = TREE_CHAIN (mem_inits);
>> + }
>> +}
>
> Check DECL_INITIAL (member) to tell if it has an NSDMI.

Actually, why not just use default_init_uninitialized_part (type)?

> +  if (warn_meminit && (kind == sfk_constructor || kind == sfk_copy_constructor
> +        || kind == sfk_move_constructor))
> +    warn_missing_meminits (current_class_type, fn);

We only want to do this for sfk_constructor; the others initialize all 
fields.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [patch] c++/2972 warn when ctor-initializer leaves uninitialized data
  2011-11-10 20:28       ` Jason Merrill
@ 2011-11-11  0:00         ` Jonathan Wakely
  0 siblings, 0 replies; 10+ messages in thread
From: Jonathan Wakely @ 2011-11-11  0:00 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On 10 November 2011 20:17, Jason Merrill wrote:
> On 11/10/2011 03:10 PM, Jason Merrill wrote:
>>
>> On 11/10/2011 02:48 PM, Jonathan Wakely wrote:
>>>
>>> +warn_missing_meminits (tree type, tree cons)
>>> +{
>>> + tree mem_inits = sort_mem_initializers (type, NULL_TREE);
>>> + while (mem_inits)
>>> + {
>>> + tree member = TREE_PURPOSE (mem_inits);
>>> + /* TODO do not warn if brace-or-equal-initializer */
>>> + warn_meminit_leaves_uninitialized (member, TREE_TYPE (member), cons);
>>> + mem_inits = TREE_CHAIN (mem_inits);
>>> + }
>>> +}
>>
>> Check DECL_INITIAL (member) to tell if it has an NSDMI.
>
> Actually, why not just use default_init_uninitialized_part (type)?
>
>> +  if (warn_meminit && (kind == sfk_constructor || kind ==
>> sfk_copy_constructor
>> +        || kind == sfk_move_constructor))
>> +    warn_missing_meminits (current_class_type, fn);
>
> We only want to do this for sfk_constructor; the others initialize all
> fields.

Doh, of course.  Thanks for the pointers, I'll have another stab at
it. I really want to get this warning implemented eventually.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-11-10 23:24 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-07 21:47 [patch] c++/2972 warn when ctor-initializer leaves uninitialized data Jonathan Wakely
2011-11-07 21:58 ` Jason Merrill
2011-11-10 20:17   ` Jonathan Wakely
2011-11-10 20:25     ` Jason Merrill
2011-11-10 20:28       ` Jason Merrill
2011-11-11  0:00         ` Jonathan Wakely
2011-11-07 22:42 ` Gabriel Dos Reis
2011-11-07 22:42   ` Jason Merrill
2011-11-08  0:18     ` Gabriel Dos Reis
2011-11-07 23:28   ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).