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]

Tentative C++0x patch: don't allow rvalue references to bind to lvalues


The attached patch disallows rvalue references from binding to
lvalues. This patch (against GCC 4.3.2) is not meant to be applied
now; rather, it is the implementation we are using to explore a change
in rvalue references that would make rvalue references much safer,
particularly in combination with concepts, and is posted here for
archival purposes.

Here's a quick summary of the behavior that is changing. Right now,
the following code is well-formed:

  struct X { };

  void f(X&&);

  void g(X x) {
    f(x); // okay: rvalue reference binds to lvalue
  }

This change makes the code ill-formed, because an rvalue reference can
no longer bind to an lvalue: it is truly an rvalue (only) reference.
Note that this does *not* impact the behavior of the common rvalue
reference idioms, e.g., given

  void f(const X&); // #1
  void f(X&&); // #2

lvalues still go to #1 and rvalues still go to #2. However, instead of
that being decided by overloading (which currently picks #1 instead of
#2 for lvalues), #1 becomes the only viable function for lvalues. Most
users won't even notice the change :)

The change in behavior becomes important if for some unrelated reason,
SFINAE kicks #1 out of the overload set. In that case, the prior
behavior would let #2 bind to the lvalue (e.g., silently moving from
lvalues) while the proposed change would produce an error (the rvalue
reference can't bind to the lvalue).

How could SFINAE kick in? It's possible to do without concepts, but
the simplest example involves std::list's push_back function with
concepts:

  requires CopyConstructible<T> void push_back(const T&); // #1
  requires MoveConstructible<T> void push_back(T&&); // #2

Now, given a move-only type (say, std::unique_ptr<int>), the function
#1 doesn't even exist , so with the current rvalue-references proposal
we'll end up silently moving from lvalues. That danger is avoided with
the proposed change, because we can't call #2 with lvalues.

There will be a paper in the next mailing (after the post-San
Francisco mailing) that describes this in far more detail, and of
course we'll be commenting on this aspect of rvalue references for
CD1.

All of the GCC and libstdc++ tests pass with this change, except the
new rvalue_streams test, which is failing due to the str() call at the
end; remove that call and rvalue stream insertion/extraction works
again. This isn't a new issue, but I wanted to call attention to it
because it has some impact on the usability of rvalue streams.

  - Doug

2008-10-10  Douglas Gregor  <doug.gregor@gmail.com>

	* typeck.c (build_unary_op): Look through NON_LVALUE_EXPR nodes.
	(build_static_cast_1): Allow static_cast'ing to an rvalue
	reference type.
	* call.c (convert_class_to_reference): Don't allow binding of
	lvalues to rvalue references.
	(reference_binding): Ditto. Also, don't force a temporary when
	we're binding to an lvalue (that we're pretending isn't an
	lvalue).

2008-10-10  Douglas Gregor  <doug.gregor@gmail.com>

	* include/debug/unordered_map (unordered_map::swap): Use lvalue
	reference.
	(unordered_multimap::swap): Ditto.
	* include/debug/unordered_set (unordered_set::swap): Use lvalue
	reference.
	(unordered_multiset::swap): Ditto.
	* include/tr1_impl/hashtable (_Hashtable::swap): Always use lvalue
	reference.
	* include/std/tuple (_Tuple_impl): Use lvalue references when
	explicitly specifying the template argument to std::move.
	* include/std/iosfwd (operator<<): Provide a forwarding operator<<
	that accepts rvalue streams.
	(operator>>): Ditto.
	* include/ext/vstring.h (__versa_string::swap): Always use lvalue
	reference.
	* include/bits/stl_list.h (list::swap): Ditto.
	* include/bits/stl_map.h (map::swap): Ditto.
	* include/bits/stl_set.h (set::swap): Ditto.
	* include/bits/stl_multimap.h (multimap::swap): Ditto.
	* include/bits/stl_pair.h (pair::swap): Ditto.
	* include/bits/stl_vector.h (vector::swap): Ditto.
	* include/bits/stl_deque.h (deque::swap): Ditto.
	* include/bits/stl_multiset.h (multiset::swap): Ditto.
	* include/bits/stl_iterator.h (move_iterator::operator*):
	Explicitly std::move the result, to convert it to an rvalue
	reference.
	* include/bits/stl_bvector.h (vector<bool>::swap): Always use
	lvalue reference.
	* include/bits/stl_tree.h (_Rb_tree::swap): Ditto.
	* include/bits/stl_move.h (forward): Forward lvalues (which may
	end up being turned into rvalues).
	(move): Explicitly static_cast to an rvalue.
	* testsuite/27_io/rvalue_streams.cc: New; test the use of rvalue
	streams. Works except for the fact that we can't call str() on the
	result. (This is an existing issue).
	* testsuite/23_containers/*/requirements/dr438/assign_neg.cc:
	Fixup line numbers.
	* testsuite/23_containers/*/requirements/dr438/insert_neg.cc:
	Ditto.
	* testsuite/23_containers/*/requirements/dr438/constructor_1_neg.cc:
	Ditto.
	* testsuite/23_containers/*/requirements/dr438/constructor_2_neg.cc:
	Ditto.

Attachment: gcc-4.3.2-rref-bind.patch
Description: Binary data


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