Patchwork C++ PATCHes to fix ref binding to array temporaries

login
register
mail settings
Submitter Jason Merrill
Date March 28, 2011, 4:13 p.m.
Message ID <4D90B3AB.1090003@redhat.com>
Download mbox | patch
Permalink /patch/88627/
State New
Headers show

Comments

Jason Merrill - March 28, 2011, 4:13 p.m.
In discussion of core issue 1232 we realized that we already do allow 
array temporaries in some cases (primarily as subobjects of class 
temporaries), so we ought to handle them consistently.

The first patch fixes direct binding to array prvalues, which has been 
specified for a while.

The second patch specifies the semantics of a conversion from 
initializer-list to array for binding the temporary to a reference.

Tested x86_64-pc-linux-gnu, applying to trunk and 4.6.
commit 43d838d444e21ec34ed9d72e2e64315129d02291
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Mar 24 14:48:44 2011 +0100

    	* call.c (reference_binding): Allow direct binding to an array
    	rvalue.
commit e84d467f48170f6b8fda35b38569cdab4104427f
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Mar 24 15:36:12 2011 +0100

    	Core 1232
    	* call.c (build_array_conv): New.
    	(implicit_conversion): Use it.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 9a9ac76..a1cfa96 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -801,6 +801,53 @@ build_aggr_conv (tree type, tree ctor, int flags)
   return c;
 }
 
+/* Represent a conversion from CTOR, a braced-init-list, to TYPE, an
+   array type, if such a conversion is possible.  */
+
+static conversion *
+build_array_conv (tree type, tree ctor, int flags)
+{
+  conversion *c;
+  unsigned HOST_WIDE_INT len = CONSTRUCTOR_NELTS (ctor);
+  tree elttype = TREE_TYPE (type);
+  unsigned i;
+  tree val;
+  bool bad = false;
+  bool user = false;
+  enum conversion_rank rank = cr_exact;
+
+  if (TYPE_DOMAIN (type))
+    {
+      unsigned HOST_WIDE_INT alen = tree_low_cst (array_type_nelts_top (type), 1);
+      if (alen < len)
+	return NULL;
+    }
+
+  FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), i, val)
+    {
+      conversion *sub
+	= implicit_conversion (elttype, TREE_TYPE (val), val,
+			       false, flags);
+      if (sub == NULL)
+	return NULL;
+
+      if (sub->rank > rank)
+	rank = sub->rank;
+      if (sub->user_conv_p)
+	user = true;
+      if (sub->bad_p)
+	bad = true;
+    }
+
+  c = alloc_conversion (ck_aggr);
+  c->type = type;
+  c->rank = rank;
+  c->user_conv_p = user;
+  c->bad_p = bad;
+  c->u.next = NULL;
+  return c;
+}
+
 /* Build a representation of the identity conversion from EXPR to
    itself.  The TYPE should match the type of EXPR, if EXPR is non-NULL.  */
 
@@ -1623,6 +1670,8 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
 	      return conv;
 	    }
 	}
+      else if (TREE_CODE (to) == ARRAY_TYPE)
+	return build_array_conv (to, expr, flags);
     }
 
   if (expr != NULL_TREE
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-array2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-array2.C
new file mode 100644
index 0000000..19eec33
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-array2.C
@@ -0,0 +1,12 @@
+// { dg-options -std=c++0x }
+
+typedef int IA[2];
+typedef double DA[2];
+
+void f(const IA&) { }
+void f(const DA&);
+
+int main()
+{
+  f({1,2});
+}

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 93383c6..9a9ac76 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1429,7 +1429,9 @@  reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
 	  || (((CP_TYPE_CONST_NON_VOLATILE_P (to)
 		&& !(flags & LOOKUP_NO_TEMP_BIND))
 	       || TYPE_REF_IS_RVALUE (rto))
-	      && (CLASS_TYPE_P (from) || (expr && lvalue_p (expr))))))
+	      && (CLASS_TYPE_P (from)
+		  || TREE_CODE (from) == ARRAY_TYPE
+		  || (expr && lvalue_p (expr))))))
     {
       /* [dcl.init.ref]
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-arrray1.C b/gcc/testsuite/g++.dg/cpp0x/initlist-arrray1.C
new file mode 100644
index 0000000..25113d7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-arrray1.C
@@ -0,0 +1,5 @@ 
+// { dg-options -std=c++0x }
+
+typedef int IRT[2];
+
+const IRT& ir = IRT{1,2};