Patchwork C++ PATCH for c++/48930 (missing error on default-initialization of class with no default ctor)

login
register
mail settings
Submitter Jason Merrill
Date May 10, 2011, 6:32 p.m.
Message ID <4DC984A3.1040009@redhat.com>
Download mbox | patch
Permalink /patch/95029/
State New
Headers show

Comments

Jason Merrill - May 10, 2011, 6:32 p.m.
The introduction of = default means that now we need to separate 
TYPE_NEEDS_CONSTRUCTING from the notion that we need to call a 
constructor for non-aggregate initialization of a class.  This patch 
does that by introducing a new function type_build_ctor_call for the 
latter case and adjusting callers appropriately.

Tested x86_64-pc-linux-gnu, applied to trunk.
commit 16f7c1cf85a246874faa9b8932c11d682eb5af2e
Author: Jason Merrill <jason@redhat.com>
Date:   Mon May 9 16:46:25 2011 -0400

    	PR c++/48930
    	* class.c (type_build_ctor_call): New.
    	* cp-tree.h: Declare it.
    	* decl.c (check_initializer): Use it instead of
    	TYPE_NEEDS_CONSTRUCTING.
    	* init.c (build_value_init, build_value_init_noctor): Likewise.
    	(perform_member_init, expand_aggr_init_1, build_new_1): Likewise.
    	(build_vec_init): Likewise.
    	* typeck2.c (process_init_constructor_array): Likewise.
    	(process_init_constructor_record): Likewise.

Patch

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 198eca6..293dd1c 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4466,6 +4466,27 @@  type_has_move_assign (tree t)
   return false;
 }
 
+/* Nonzero if we need to build up a constructor call when initializing an
+   object of this class, either because it has a user-provided constructor
+   or because it doesn't have a default constructor (so we need to give an
+   error if no initializer is provided).  Use TYPE_NEEDS_CONSTRUCTING when
+   what you care about is whether or not an object can be produced by a
+   constructor (e.g. so we don't set TREE_READONLY on const variables of
+   such type); use this function when what you care about is whether or not
+   to try to call a constructor to create an object.  The latter case is
+   the former plus some cases of constructors that cannot be called.  */
+
+bool
+type_build_ctor_call (tree t)
+{
+  tree inner;
+  if (TYPE_NEEDS_CONSTRUCTING (t))
+    return true;
+  inner = strip_array_types (t);
+  return (CLASS_TYPE_P (inner) && !TYPE_HAS_DEFAULT_CONSTRUCTOR (inner)
+	  && !ANON_AGGR_TYPE_P (inner));
+}
+
 /* Remove all zero-width bit-fields from T.  */
 
 static void
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index efcdeef..1705232 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4787,6 +4787,7 @@  extern bool type_has_constexpr_default_constructor (tree);
 extern bool type_has_virtual_destructor		(tree);
 extern bool type_has_move_constructor		(tree);
 extern bool type_has_move_assign		(tree);
+extern bool type_build_ctor_call		(tree);
 extern void defaulted_late_check		(tree);
 extern bool defaultable_fn_check		(tree);
 extern void fixup_type_variants			(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ab36d18..eff2360 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5410,7 +5410,7 @@  check_initializer (tree decl, tree init, int flags, tree *cleanup)
     ;
   else if (TREE_CODE (type) == REFERENCE_TYPE)
     init = grok_reference_init (decl, type, init, cleanup);
-  else if (init || TYPE_NEEDS_CONSTRUCTING (type))
+  else if (init || type_build_ctor_call (type))
     {
       if (!init)
 	check_for_uninitialized_const_var (decl);
@@ -5445,7 +5445,7 @@  check_initializer (tree decl, tree init, int flags, tree *cleanup)
       if (type == error_mark_node)
 	return NULL_TREE;
 
-      if (TYPE_NEEDS_CONSTRUCTING (type)
+      if (type_build_ctor_call (type)
 	  || (CLASS_TYPE_P (type)
 	      && !(init && BRACE_ENCLOSED_INITIALIZER_P (init))))
 	{
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index b71ddfc..7d7adbe 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -341,7 +341,7 @@  build_value_init (tree type, tsubst_flags_t complain)
 				      NULL, type, LOOKUP_NORMAL,
 				      complain),
 	   complain);
-      else if (TYPE_NEEDS_CONSTRUCTING (type))
+      else if (type_build_ctor_call (type))
 	{
 	  /* This is a class that needs constructing, but doesn't have
 	     a user-provided constructor.  So we need to zero-initialize
@@ -371,7 +371,7 @@  build_value_init_noctor (tree type, tsubst_flags_t complain)
      SFINAE-enabled.  */
   if (CLASS_TYPE_P (type))
     {
-      gcc_assert (!TYPE_NEEDS_CONSTRUCTING (type));
+      gcc_assert (!type_build_ctor_call (type));
 	
       if (TREE_CODE (type) != UNION_TYPE)
 	{
@@ -530,7 +530,7 @@  perform_member_init (tree member, tree init)
 	  finish_expr_stmt (init);
 	}
     }
-  else if (TYPE_NEEDS_CONSTRUCTING (type))
+  else if (type_build_ctor_call (type))
     {
       if (TREE_CODE (type) == ARRAY_TYPE)
 	{
@@ -1568,7 +1568,7 @@  expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
 	/* Fall through.  */;
       /* If there isn't, but we still need to call the constructor,
 	 zero out the object first.  */
-      else if (TYPE_NEEDS_CONSTRUCTING (type))
+      else if (type_build_ctor_call (type))
 	{
 	  init = build_zero_init (type, NULL_TREE, /*static_storage_p=*/false);
 	  init = build2 (INIT_EXPR, type, exp, init);
@@ -2046,7 +2046,7 @@  build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
   if (abstract_virtuals_error_sfinae (NULL_TREE, elt_type, complain))
     return error_mark_node;
 
-  is_initialized = (TYPE_NEEDS_CONSTRUCTING (elt_type) || *init != NULL);
+  is_initialized = (type_build_ctor_call (elt_type) || *init != NULL);
 
   if (*init == NULL)
     {
@@ -2351,7 +2351,7 @@  build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
 	     rebuild it at instantiation time, so just build up a single
 	     constructor call to get any appropriate diagnostics.  */
 	  init_expr = cp_build_indirect_ref (data_addr, RO_NULL, complain);
-	  if (TYPE_NEEDS_CONSTRUCTING (elt_type))
+	  if (type_build_ctor_call (elt_type))
 	    init_expr = build_special_member_call (init_expr,
 						   complete_ctor_identifier,
 						   init, elt_type,
@@ -2408,7 +2408,7 @@  build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
 	{
 	  init_expr = cp_build_indirect_ref (data_addr, RO_NULL, complain);
 
-	  if (TYPE_NEEDS_CONSTRUCTING (type) && !explicit_value_init_p)
+	  if (type_build_ctor_call (type) && !explicit_value_init_p)
 	    {
 	      init_expr = build_special_member_call (init_expr,
 						     complete_ctor_identifier,
@@ -3164,8 +3164,7 @@  build_vec_init (tree base, tree maxindex, tree init,
     {
       if (init)
 	/* OK, we set base2 above.  */;
-      else if (TYPE_LANG_SPECIFIC (type)
-	       && TYPE_NEEDS_CONSTRUCTING (type)
+      else if (CLASS_TYPE_P (type)
 	       && ! TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
 	{
           if (complain & tf_error)
@@ -3181,7 +3180,7 @@  build_vec_init (tree base, tree maxindex, tree init,
      We do need to keep going if we're copying an array.  */
 
   if (from_array
-      || ((TYPE_NEEDS_CONSTRUCTING (type) || explicit_value_init_p)
+      || ((type_build_ctor_call (type) || explicit_value_init_p)
 	  && ! (host_integerp (maxindex, 0)
 		&& (num_initialized_elts
 		    == tree_low_cst (maxindex, 0) + 1))))
@@ -3221,7 +3220,7 @@  build_vec_init (tree base, tree maxindex, tree init,
 	  if (from_array == 2)
 	    elt_init = cp_build_modify_expr (to, NOP_EXPR, from, 
 					     complain);
-	  else if (TYPE_NEEDS_CONSTRUCTING (type))
+	  else if (type_build_ctor_call (type))
 	    elt_init = build_aggr_init (to, from, 0, complain);
 	  else if (from)
 	    elt_init = cp_build_modify_expr (to, NOP_EXPR, from,
@@ -3247,7 +3246,7 @@  build_vec_init (tree base, tree maxindex, tree init,
 	}
       else
 	{
-	  gcc_assert (TYPE_NEEDS_CONSTRUCTING (type));
+	  gcc_assert (type_build_ctor_call (type));
 	  elt_init = build_aggr_init (to, init, 0, complain);
 	}
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index ec6b5d3..26b9816 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1048,7 +1048,7 @@  process_init_constructor_array (tree type, tree init,
       {
 	tree next;
 
-	if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (type)))
+	if (type_build_ctor_call (TREE_TYPE (type)))
 	  {
 	    /* If this type needs constructors run for default-initialization,
 	      we can't rely on the back end to do it for us, so build up
@@ -1144,7 +1144,7 @@  process_init_constructor_record (tree type, tree init,
 				LOOKUP_IMPLICIT, complain);
 	  ++idx;
 	}
-      else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
+      else if (type_build_ctor_call (TREE_TYPE (field)))
 	{
 	  /* If this type needs constructors run for
 	     default-initialization, we can't rely on the back end to do it
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted25.C b/gcc/testsuite/g++.dg/cpp0x/defaulted25.C
new file mode 100644
index 0000000..2a38fed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted25.C
@@ -0,0 +1,10 @@ 
+// PR c++/48930
+// { dg-options -std=c++0x }
+// { dg-prune-output "note" }
+
+struct A
+{
+  A(const A&) = default;
+};
+
+A a;				// { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/template/crash7.C b/gcc/testsuite/g++.dg/template/crash7.C
index ae07d91..7fda9a9 100644
--- a/gcc/testsuite/g++.dg/template/crash7.C
+++ b/gcc/testsuite/g++.dg/template/crash7.C
@@ -5,11 +5,10 @@ 
 // PR c++/10108: ICE in tsubst_decl for error due to non-existence
 // nested type.
 
-template <typename> struct A
-{					// { not-dg-error "candidates" }
+template <typename> struct A	// { dg-message "A.void.::A.const A" }
+{
     template <typename> A(typename A::X) {} // { dg-error "no type" }
 };
 
-A<void> a;	// { not-dg-error "instantiated|no match" }
-// We currently don't give the "no match" error because we don't add the
-// invalid constructor template to TYPE_METHODS.
+A<void> a;	// { dg-error "instantiated|no match" }
+// { dg-prune-output "note" }