This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH for core issue 253: const objects and explicit initializers


Issue 253 was raised in 2000, but was considered low priority at the time; it pointed out that classes with no actual data don't really need an initializer, so we shouldn't require one. This becomes more important now that we have non-static data member initializers that can initialize all the members without a user-provided constructor.

Tested x86_64-pc-linux-gnu, applied to trunk. I'm also considering applying it to 4.6 since we got more strict about the pre-253 rule in 4.6.
commit f8bbf6bb2853ef073807b5e275fa40edae3d8aa0
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Sep 15 17:15:34 2011 -0400

    	Core 253 - allow const objects with no initializer or
    	user-provided default constructor if the defaulted constructor
    	initializes all the subobjects.
    	PR c++/20039
    	PR c++/42844
    	* class.c (default_init_uninitialized_part): New.
    	* cp-tree.h: Declare it.
    	* decl.c (check_for_uninitialized_const_var): Use it.
    	* init.c (perform_member_init): Likewise.
    	(build_new_1): Likewise.
    	* method.c (walk_field_subobs): Likewise.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index e398416..1887526 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4356,6 +4356,40 @@ type_has_user_provided_default_constructor (tree t)
   return false;
 }
 
+/* If default-initialization leaves part of TYPE uninitialized, returns
+   a DECL for the field or TYPE itself (DR 253).  */
+
+tree
+default_init_uninitialized_part (tree type)
+{
+  tree t, r, binfo;
+  int i;
+
+  type = strip_array_types (type);
+  if (!CLASS_TYPE_P (type))
+    return type;
+  if (type_has_user_provided_default_constructor (type))
+    return NULL_TREE;
+  for (binfo = TYPE_BINFO (type), i = 0;
+       BINFO_BASE_ITERATE (binfo, i, t); ++i)
+    {
+      r = default_init_uninitialized_part (BINFO_TYPE (t));
+      if (r)
+	return r;
+    }
+  for (t = TYPE_FIELDS (type); t; t = DECL_CHAIN (t))
+    if (TREE_CODE (t) == FIELD_DECL
+	&& !DECL_ARTIFICIAL (t)
+	&& !DECL_INITIAL (t))
+      {
+	r = default_init_uninitialized_part (TREE_TYPE (t));
+	if (r)
+	  return DECL_P (r) ? r : t;
+      }
+
+  return NULL_TREE;
+}
+
 /* Returns true iff for class T, a trivial synthesized default constructor
    would be constexpr.  */
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bcfc3b3..573c166 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4838,6 +4838,7 @@ extern tree in_class_defaulted_default_constructor (tree);
 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 bool trivial_default_constructor_is_constexpr (tree);
 extern bool type_has_constexpr_default_constructor (tree);
 extern bool type_has_virtual_destructor		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 709deca..495d8a0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4899,15 +4899,16 @@ check_for_uninitialized_const_var (tree decl)
   if (TREE_CODE (decl) == VAR_DECL
       && TREE_CODE (type) != REFERENCE_TYPE
       && CP_TYPE_CONST_P (type)
-      && (!TYPE_NEEDS_CONSTRUCTING (type)
-	  || !type_has_user_provided_default_constructor (type))
       && !DECL_INITIAL (decl))
     {
+      tree field = default_init_uninitialized_part (type);
+      if (!field)
+	return;
+
       permerror (DECL_SOURCE_LOCATION (decl),
 		 "uninitialized const %qD", decl);
 
-      if (CLASS_TYPE_P (type)
-	  && !type_has_user_provided_default_constructor (type))
+      if (CLASS_TYPE_P (type))
 	{
 	  tree defaulted_ctor;
 
@@ -4918,6 +4919,8 @@ check_for_uninitialized_const_var (tree decl)
 	    inform (DECL_SOURCE_LOCATION (defaulted_ctor),
 		    "constructor is not user-provided because it is "
 		    "explicitly defaulted in the class body");
+	  inform (0, "and the implicitly-defined constructor does not "
+		  "initialize %q+#D", field);
 	}
     }
 }
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index ff1884b..68d4e68 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -579,7 +579,7 @@ perform_member_init (tree member, tree init)
 	    flags |= LOOKUP_DEFAULTED;
 	  if (CP_TYPE_CONST_P (type)
 	      && init == NULL_TREE
-	      && !type_has_user_provided_default_constructor (type))
+	      && default_init_uninitialized_part (type))
 	    /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a
 	       vtable; still give this diagnostic.  */
 	    permerror (DECL_SOURCE_LOCATION (current_function_decl),
@@ -2088,7 +2088,7 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
     }
 
   if (CP_TYPE_CONST_P (elt_type) && *init == NULL
-      && !type_has_user_provided_default_constructor (elt_type))
+      && default_init_uninitialized_part (elt_type))
     {
       if (complain & tf_error)
         error ("uninitialized const in %<new%> of %q#T", elt_type);
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 5b24f8f..757e711 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1015,8 +1015,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 	{
 	  bool bad = true;
 	  if (CP_TYPE_CONST_P (mem_type)
-	      && (!CLASS_TYPE_P (mem_type)
-		  || !type_has_user_provided_default_constructor (mem_type)))
+	      && default_init_uninitialized_part (mem_type))
 	    {
 	      if (msg)
 		error ("uninitialized non-static const member %q#D",
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C
index 3af8509..4ff398b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-object1.C
@@ -7,7 +7,7 @@
 
 // p 1 constexpr specifier
 // objects, static const data
-struct A1 { };	   // { dg-message "no user-provided default constructor" }
+struct A1 { int i; };	   // { dg-message "no user-provided default constructor" }
 
 constexpr int i1 = 1024;
 constexpr A1 a1 = A1();
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted2.C b/gcc/testsuite/g++.dg/cpp0x/defaulted2.C
index 1f400f4..e3aac8f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted2.C
@@ -17,7 +17,8 @@ void g() = delete;		// { dg-error "redefinition" }
 
 struct B // { dg-message "user-provided default constructor" }
 {
-    B() = default;		// { dg-message "not user-provided" }
+  int i;
+  B() = default;		// { dg-message "not user-provided" }
 };
 
 const B b;			// { dg-error "uninitialized const" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C b/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C
index 5af4ff2..4425aac 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr42844-2.C
@@ -4,6 +4,7 @@
 
 struct A // { dg-message "user-provided default constructor" }
 {
+    int i;
     A() = default; // { dg-message "not user-provided" }
 };
 
@@ -14,17 +15,20 @@ struct Base
 
 struct Derived : Base // { dg-message "user-provided default constructor" }
 {
+    int i;
     Derived() = default; // { dg-message "not user-provided" }
 };
 
 struct Derived2 : Base // { dg-message "user-provided default constructor" }
 {
+    int i;
     Derived2() = default; // { dg-message "not user-provided" }
     Derived2( Derived2 const& ) = default;
 };
 
 struct Derived3 : Base // { dg-message "user-provided default constructor" }
 {
+    int i;
     Derived3( Derived3 const& ) = default;
     Derived3() = default; // { dg-message "not user-provided" }
 };
diff --git a/gcc/testsuite/g++.dg/init/const8.C b/gcc/testsuite/g++.dg/init/const8.C
new file mode 100644
index 0000000..4eb293d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/const8.C
@@ -0,0 +1,11 @@
+// DR 234 - it should be OK to leave off the initializer of a const
+// variable if the default constructor fully initializes the object.
+
+struct A { };
+const A a;
+
+struct B { A a; };
+const B b;
+
+struct C { virtual void f(); };
+const C c;
diff --git a/gcc/testsuite/g++.dg/init/pr20039.C b/gcc/testsuite/g++.dg/init/pr20039.C
index 9b0c12d..aaac8bd 100644
--- a/gcc/testsuite/g++.dg/init/pr20039.C
+++ b/gcc/testsuite/g++.dg/init/pr20039.C
@@ -10,6 +10,7 @@ struct M
 struct X
 {
   M m;
+  int i;
 };
 
 int mymain()
diff --git a/gcc/testsuite/g++.dg/init/pr42844.C b/gcc/testsuite/g++.dg/init/pr42844.C
index 7b423cc..299a30a 100644
--- a/gcc/testsuite/g++.dg/init/pr42844.C
+++ b/gcc/testsuite/g++.dg/init/pr42844.C
@@ -6,19 +6,19 @@ struct A
   A(){}
 };
 
-struct B : A {}; // { dg-message "user-provided default constructor" }
+struct B : A { int i; }; // { dg-message "user-provided default constructor" }
 
-struct C : A {}; // { dg-message "user-provided default constructor" }
+struct C : A { int i; }; // { dg-message "user-provided default constructor" }
 
 struct D : B { D() {} };
 
-struct E {}; // { dg-message "user-provided default constructor" }
+struct E { int i; }; // { dg-message "user-provided default constructor" }
 
 template <class T>
-struct F : A {}; // { dg-message "user-provided default constructor" }
+struct F : A { T t; }; // { dg-message "user-provided default constructor" }
 
 template <class T>
-struct G {}; // { dg-message "user-provided default constructor" }
+struct G { T t; }; // { dg-message "user-provided default constructor" }
 
 void f ()
 {
@@ -41,9 +41,9 @@ void f ()
   extern G<int> const gext;
 }
 
-struct H {}; // { dg-message "user-provided default constructor" }
+struct H { int i; }; // { dg-message "user-provided default constructor" }
 
-struct I : A {}; // { dg-message "user-provided default constructor" }
+struct I : A { int i; }; // { dg-message "user-provided default constructor" }
 
 template <class T>
 void g ()

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]