Patchwork C++ PATCH for c++/48457 (rvalue references and function lvalues)

login
register
mail settings
Submitter Jason Merrill
Date April 11, 2011, 9:47 p.m.
Message ID <4DA376EC.40908@redhat.com>
Download mbox | patch
Permalink /patch/90658/
State New
Headers show

Comments

Jason Merrill - April 11, 2011, 9:47 p.m.
Recent discussion of how to deal with rvalue references and functions 
ended with the decision that an expression of function type is always an 
lvalue, even if it is derived from an rvalue reference, but that rvalue 
references can bind to function lvalues.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit dcc37da352dd87c5f2f1f103c9794effa180e43d
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Apr 8 18:55:21 2011 -0400

    	PR c++/48457, Core 1238
    	* call.c (reference_binding): Allow rvalue reference to bind to
    	function lvalue.
    	* tree.c (lvalue_kind): Functions are always lvalues.

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 096fbbc..4d03646 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1521,8 +1521,10 @@  reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
 	   actually occurs.  */
 	conv->need_temporary_p = true;
 
-      /* Don't allow binding of lvalues to rvalue references.  */
+      /* Don't allow binding of lvalues (other than function lvalues) to
+	 rvalue references.  */
       if (is_lvalue && TYPE_REF_IS_RVALUE (rto)
+	  && TREE_CODE (to) != FUNCTION_TYPE
           && !(flags & LOOKUP_PREFER_RVALUE))
 	conv->bad_p = true;
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 3594ae4..d6b6197 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -73,7 +73,9 @@  lvalue_kind (const_tree ref)
       if (TYPE_REF_IS_RVALUE (TREE_TYPE (ref))
 	  && TREE_CODE (ref) != PARM_DECL
 	  && TREE_CODE (ref) != VAR_DECL
-	  && TREE_CODE (ref) != COMPONENT_REF)
+	  && TREE_CODE (ref) != COMPONENT_REF
+	  /* Functions are always lvalues.  */
+	  && TREE_CODE (TREE_TYPE (TREE_TYPE (ref))) != FUNCTION_TYPE)
 	return clk_rvalueref;
 
       /* lvalue references and named rvalue references are lvalues.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/rv-func.C b/gcc/testsuite/g++.dg/cpp0x/rv-func.C
new file mode 100644
index 0000000..db14296
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/rv-func.C
@@ -0,0 +1,22 @@ 
+// PR c++/48457, Core 1238
+// { dg-options -std=c++0x }
+
+template<class T>
+T&& create();
+
+template<class T, class Arg>
+void test() {
+  T t(create<Arg>());
+  (void) t;
+}
+
+void f (void (&)());
+void f (void (&&)());
+
+int main() {
+  test<void(&)(), void()>();
+  test<void(&&)(), void()>();
+  // This call should choose the lvalue reference overload.
+  // { dg-final { scan-assembler-not "_Z1fOFvvE" } }
+  f(create<void()>());
+}
diff --git a/libstdc++-v3/testsuite/20_util/is_convertible/value.cc b/libstdc++-v3/testsuite/20_util/is_convertible/value.cc
index f6282a9..fc6007a 100644
--- a/libstdc++-v3/testsuite/20_util/is_convertible/value.cc
+++ b/libstdc++-v3/testsuite/20_util/is_convertible/value.cc
@@ -93,7 +93,7 @@  void test01()
 	                                     const volatile int&>(false)) );
   VERIFY( (test_relationship<is_convertible, volatile int,
 	                                     volatile int&>(false)) );
-  VERIFY( (test_relationship<is_convertible, int(int), int(&)(int)>(false)) );
+  VERIFY( (test_relationship<is_convertible, int(int), int(&)(int)>(true)) );
 
   VERIFY( (test_relationship<is_convertible, int&, ExplicitClass>(false)) );
   VERIFY( (test_relationship<is_convertible, void*, ExplicitClass>(false)) );