public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCHes to list-value-initialization
@ 2011-06-29 14:58 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2011-06-29 14:58 UTC (permalink / raw)
  To: gcc-patches List

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

The first patch implements the resolution of DR 990, which clarifies 
that {} means value-initialization if the type has a default constructor.

The second patch fixes a bug in the standard I noticed while looking at 
related issues: it says that if a class has any user-provided 
constructor, we just call the default constructor.  This wording should 
have been adjusted when we added defaulted functions; I've raised the 
issue with the committee, but am also applying the obvious fix to the 
compiler, namely to only consider the user-providedness of the default 
constructor when deciding whether or not to zero-initialize first.

Tested x86_64-pc-linux-gnu, applying to trunk.

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

commit 2bd88a2546673c5f10bedefff0dcfa3565d5b6fa
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jun 28 10:20:50 2011 -0400

    	DR 990
    	* call.c (convert_like_real) [ck_user]: Handle value-initialization.
    	(build_new_method_call_1): Likewise.
    	* init.c (expand_default_init): Handle direct list-initialization
    	of aggregates.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index cfaef7d..e2d455a 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5592,6 +5592,18 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	tree convfn = cand->fn;
 	unsigned i;
 
+	/* If we're initializing from {}, it's value-initialization.  */
+	if (BRACE_ENCLOSED_INITIALIZER_P (expr)
+	    && CONSTRUCTOR_NELTS (expr) == 0
+	    && TYPE_HAS_DEFAULT_CONSTRUCTOR (totype))
+	  {
+	    expr = build_value_init (totype, complain);
+	    expr = get_target_expr_sfinae (expr, complain);
+	    if (expr != error_mark_node)
+	      TARGET_EXPR_LIST_INIT_P (expr) = true;
+	    return expr;
+	  }
+
 	expr = mark_rvalue_use (expr);
 
 	/* When converting from an init list we consider explicit
@@ -5634,7 +5646,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	{
 	  int nelts = CONSTRUCTOR_NELTS (expr);
 	  if (nelts == 0)
-	    expr = build_value_init (totype, tf_warning_or_error);
+	    expr = build_value_init (totype, complain);
 	  else if (nelts == 1)
 	    expr = CONSTRUCTOR_ELT (expr, 0)->value;
 	  else
@@ -7138,10 +7150,29 @@ build_new_method_call_1 (tree instance, tree fns, VEC(tree,gc) **args,
       && BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *args, 0))
       && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *args, 0)))
     {
+      tree init_list = VEC_index (tree, *args, 0);
+
       gcc_assert (VEC_length (tree, *args) == 1
 		  && !(flags & LOOKUP_ONLYCONVERTING));
 
-      add_list_candidates (fns, first_mem_arg, VEC_index (tree, *args, 0),
+      /* If the initializer list has no elements and T is a class type with
+	 a default constructor, the object is value-initialized.  Handle
+	 this here so we don't need to handle it wherever we use
+	 build_special_member_call.  */
+      if (CONSTRUCTOR_NELTS (init_list) == 0
+	  && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
+	  && !processing_template_decl)
+	{
+	  tree ob, init = build_value_init (basetype, complain);
+	  if (integer_zerop (instance_ptr))
+	    return get_target_expr_sfinae (init, complain);
+	  ob = build_fold_indirect_ref (instance_ptr);
+	  init = build2 (INIT_EXPR, TREE_TYPE (ob), ob, init);
+	  TREE_SIDE_EFFECTS (init) = true;
+	  return init;
+	}
+
+      add_list_candidates (fns, first_mem_arg, init_list,
 			   basetype, explicit_targs, template_only,
 			   conversion_path, access_binfo, flags, &candidates);
     }
@@ -8365,7 +8396,7 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
    permitted.  If the conversion is valid, the converted expression is
    returned.  Otherwise, NULL_TREE is returned, except in the case
    that TYPE is a class type; in that case, an error is issued.  If
-   C_CAST_P is true, then this direction initialization is taking
+   C_CAST_P is true, then this direct-initialization is taking
    place as part of a static_cast being attempted as part of a C-style
    cast.  */
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3ceed90..1719339 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1443,6 +1443,17 @@ expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags,
   tree rval;
   VEC(tree,gc) *parms;
 
+  /* If we have direct-initialization from an initializer list, pull
+     it out of the TREE_LIST so the code below can see it.  */
+  if (init && TREE_CODE (init) == TREE_LIST
+      && BRACE_ENCLOSED_INITIALIZER_P (TREE_VALUE (init))
+      && CONSTRUCTOR_IS_DIRECT_INIT (TREE_VALUE (init)))
+    {
+      gcc_checking_assert ((flags & LOOKUP_ONLYCONVERTING) == 0
+			   && TREE_CHAIN (init) == NULL_TREE);
+      init = TREE_VALUE (init);
+    }
+
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
       && CP_AGGREGATE_TYPE_P (type))
     {
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist4.C
new file mode 100644
index 0000000..8151857
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-initlist4.C
@@ -0,0 +1,8 @@
+// { dg-options -std=c++0x }
+
+struct A { int i; };
+struct B: A { constexpr B(): A{} {} };
+struct B2: A { constexpr B2(): A{1} {} };
+
+struct C { protected: int i; };
+struct D: C { constexpr D(): C{} {} };
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-value.C b/gcc/testsuite/g++.dg/cpp0x/initlist-value.C
new file mode 100644
index 0000000..25a3373
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-value.C
@@ -0,0 +1,26 @@
+// Test for value-initialization via {}
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+// Empty base so A isn't an aggregate
+struct B {};
+struct A: B {
+  int i;
+};
+
+struct C: A {
+  C(): A{} {}
+};
+
+int f(A a) { return a.i; }
+
+int main()
+{
+  A a{};
+  C c;
+  if (a.i != 0
+      || c.i != 0
+      || A{}.i != 0
+      || f({}) != 0)
+    return 1;
+}

[-- Attachment #3: value2.patch --]
[-- Type: text/x-patch, Size: 2307 bytes --]

commit 900881b6124897c0384ee970fde989785ddaf49e
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Jun 28 17:25:40 2011 -0400

    	* init.c (build_value_init): Decide whether or not to zero-initialize
    	based on user-providedness of default ctor, not any ctor.
    	(build_value_init_noctor): Adjust assert.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 1719339..ac2b733 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -334,14 +334,20 @@ build_value_init (tree type, tsubst_flags_t complain)
 
   if (CLASS_TYPE_P (type))
     {
-      if (type_has_user_provided_constructor (type))
+      /* Instead of the above, only consider the user-providedness of the
+	 default constructor itself so value-initializing a class with an
+	 explicitly defaulted default constructor and another user-provided
+	 constructor works properly (c++std-core-19883).  */
+      if (type_has_user_provided_default_constructor (type)
+	  || (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)
+	      && type_has_user_provided_constructor (type)))
 	return build_aggr_init_expr
 	  (type,
 	   build_special_member_call (NULL_TREE, complete_ctor_identifier,
 				      NULL, type, LOOKUP_NORMAL,
 				      complain),
 	   complain);
-      else if (type_build_ctor_call (type))
+      else if (TYPE_HAS_COMPLEX_DFLT (type))
 	{
 	  /* This is a class that needs constructing, but doesn't have
 	     a user-provided constructor.  So we need to zero-initialize
@@ -371,7 +377,7 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
      SFINAE-enabled.  */
   if (CLASS_TYPE_P (type))
     {
-      gcc_assert (!type_build_ctor_call (type));
+      gcc_assert (!TYPE_HAS_COMPLEX_DFLT (type));
 	
       if (TREE_CODE (type) != UNION_TYPE)
 	{
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-value2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-value2.C
new file mode 100644
index 0000000..2b78241
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-value2.C
@@ -0,0 +1,20 @@
+// Test that we properly value-initialize a class with a user-provided
+// constructor but defaulted default constructor.  The FDIS got this
+// wrong; see c++std-core-19883.
+
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+struct A
+{
+  int i;
+  A() = default;
+  A(int);
+};
+
+int main()
+{
+  A a{};
+  if (a.i != 0)
+    return 1;
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-06-29 14:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-29 14:58 C++ PATCHes to list-value-initialization Jason Merrill

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