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]

PING: [PATCH] rvalue reference implementation for C++0x


Just pinging a patch I submitted two weeks ago. The patch attached to
this post is mostly the same as the one I originally posted, but the
template type deduction logic has been simplified and now follows DR606
(http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#606).

The original patch submission is at
http://gcc.gnu.org/ml/gcc-patches/2007-02/msg01760.html

-- 
-  Russell Yanofsky (PGP ID: 0x5FAA0216)
-  http://russ.yanofsky.org/
--
2007-02-20  Russell Yanofsky <russ@yanofsky.org>
            Pedro Lamarao <pedro.lamarao@mndfck.org>
            Doug Gregor <doug.gregor@gmail.com>
            Howard Hinnant <howard.hinnant@gmail.com>

	Add support for rvalue references to G++ under --std=c++0x mode
	* gcc/cp/call.c (conversion): new "valuedness_matches_p" member
	(convert_class_to_reference): require reference type as first
	parameter instead of base type
	(reference_binding): add logic to handle rvalue references
	(implicit_conversion): update inaccurate comment
	(convert_like_real): disable creation of temporaries that are
	impossible to initialize for types with move constructors
	(maybe_handle_implicit_object): set "valuedness_matches_p"
	(maybe_handle_ref_bind): return conversion instead of type node
	(compare_ics): add logic to use "valuedness_matches_p" values to
	determine preferred conversion sequences
	* gcc/cp/cp-tree.h (declarator): new "rvalue_ref" flag
	(LOOKUP_PREFER_RVALUE): new lookup flag
	* gcc/cp/decl.c (grokdeclarator): implement reference collapsing
	(copy_fn_p): don't consider constructors taking rvalue references
	to be copy constructors
	* gcc/cp/error.c (dump_type_prefix): format rvalue reference types
	correctly in error messages
	* gcc/cp/except.c (build_throw): move from certain lvalues when
	throwing.
	* gcc/cp/mangle.c (write_type): mangle rvalue references differently
	than regular references
	* gcc/cp/parser.c (make_reference_declarator): new boolean parameter
	(cp_parser_make_indirect_declarator): new function
	(cp_parser_new_declarator_opt): call cp_parser_make_indirect_declarator
	(cp_parser_conversion_declarator_opt): same
	(cp_parser_declarator): same
	(cp_parser_ptr_operator): parse "&&" tokens into rvalue reference
	declarators
	* gcc/cp/pt.c (tsubst): implement reference collapsing
	(maybe_adjust_types_for_deduction): implement special template
	parameter deduction rule for rvalue references
	(type_unification_real, try_one_overload): update calls to
	maybe_adjust_types_for_deduction
	* gcc/cp/tree.c (lvalue_p_1): handle rvalue reference types
	* gcc/cp/typeck.c (comptypes): don't consider rvalue and lvalue
	reference types to be equivalent
	(check_return_expr): move from certain lvalues when returning them
	* gcc/tree.h
	(TYPE_REF_IS_RVALUE): new macro for REFERENCE_TYPE nodes
	(build_rval_reference_type_for_mode): new function
	(build_rval_reference_type): new function
	* gcc/tree.c (build_rval_reference_type_for_mode): new function
	(build_rval_reference_type): new function
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/tree.c	(.../trunk)	(revision 88)
@@ -5324,8 +5324,8 @@ build_pointer_type (tree to_type)
 /* Same as build_pointer_type_for_mode, but for REFERENCE_TYPE.  */
 
 tree
-build_reference_type_for_mode (tree to_type, enum machine_mode mode,
-			       bool can_alias_all)
+build_rval_reference_type_for_mode (tree to_type, enum machine_mode mode,
+				    bool can_alias_all, bool rval)
 {
   tree t;
 
@@ -5344,7 +5344,8 @@ build_reference_type_for_mode (tree to_t
   /* First, if we already have a type for pointers to TO_TYPE and it's
      the proper mode, use it.  */
   for (t = TYPE_REFERENCE_TO (to_type); t; t = TYPE_NEXT_REF_TO (t))
-    if (TYPE_MODE (t) == mode && TYPE_REF_CAN_ALIAS_ALL (t) == can_alias_all)
+    if (TYPE_MODE (t) == mode && TYPE_REF_CAN_ALIAS_ALL (t) == can_alias_all
+	&& TYPE_REF_IS_RVALUE(t) == rval)
       return t;
 
   t = make_node (REFERENCE_TYPE);
@@ -5352,6 +5353,7 @@ build_reference_type_for_mode (tree to_t
   TREE_TYPE (t) = to_type;
   TYPE_MODE (t) = mode;
   TYPE_REF_CAN_ALIAS_ALL (t) = can_alias_all;
+  TYPE_REF_IS_RVALUE(t) = rval;
   TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (to_type);
   TYPE_REFERENCE_TO (to_type) = t;
 
@@ -5359,19 +5361,35 @@ build_reference_type_for_mode (tree to_t
     SET_TYPE_STRUCTURAL_EQUALITY (t);
   else if (TYPE_CANONICAL (to_type) != to_type)
     TYPE_CANONICAL (t) 
-      = build_reference_type_for_mode (TYPE_CANONICAL (to_type),
-				       mode, can_alias_all);
+      = build_rval_reference_type_for_mode (TYPE_CANONICAL (to_type),
+					    mode, can_alias_all, rval);
 
   layout_type (t);
 
   return t;
 }
 
+tree
+build_reference_type_for_mode (tree to_type, enum machine_mode mode,
+			       bool can_alias_all)
+{
+  return build_rval_reference_type_for_mode (to_type, mode,
+					     can_alias_all,
+					     false);
+}
 
 /* Build the node for the type of references-to-TO_TYPE by default
    in ptr_mode.  */
 
 tree
+build_rval_reference_type (tree to_type, bool rval)
+{
+  return build_rval_reference_type_for_mode (to_type, ptr_mode, false, rval);
+}
+
+/* Build the node for lvalue references. */
+
+tree
 build_reference_type (tree to_type)
 {
   return build_reference_type_for_mode (to_type, ptr_mode, false);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/tree.h	(.../trunk)	(revision 88)
@@ -484,6 +484,8 @@ struct gimple_stmt GTY(())
 	   ..._DECL
        CALL_FROM_THUNK_P in
            CALL_EXPR
+       TYPE_REF_IS_RVALUE in
+	 REFERENCE_TYPE
 
    side_effects_flag:
 
@@ -1282,6 +1284,10 @@ extern void omp_clause_range_check_faile
 #define CALL_FROM_THUNK_P(NODE) \
   (CALL_EXPR_CHECK (NODE)->base.protected_flag)
 
+/* In a REFERENCE_TYPE, means that reference is an rvalue reference */
+#define TYPE_REF_IS_RVALUE(NODE) \
+  (REFERENCE_TYPE_CHECK (NODE)->base.protected_flag)
+
 /* In a type, nonzero means that all objects of the type are guaranteed by the
    language or front-end to be properly aligned, so we can indicate that a MEM
    of this type is aligned at least to the alignment of the type, even if it
@@ -3748,7 +3754,10 @@ extern void set_sizetype (tree);
 extern void fixup_unsigned_type (tree);
 extern tree build_pointer_type_for_mode (tree, enum machine_mode, bool);
 extern tree build_pointer_type (tree);
+extern tree build_rval_reference_type_for_mode
+  (tree, enum machine_mode, bool, bool);
 extern tree build_reference_type_for_mode (tree, enum machine_mode, bool);
+extern tree build_rval_reference_type (tree, bool);
 extern tree build_reference_type (tree);
 extern tree build_vector_type_for_mode (tree, enum machine_mode);
 extern tree build_vector_type (tree innertype, int nunits);
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv7p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv8p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/not_special.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/elision.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/named_refs.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/unnamed_refs.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/reference_collapsing.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/template_deduction.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/README
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv1n.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv2n.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/iop.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv3n.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv1p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv4n.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv2p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv3p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/cast.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv5n.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv4p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/elision_neg.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv6n.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv5p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv7n.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref.hh/rv6p.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/overload.py
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/collapse.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/implicit-copy.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/temp-constructor-bug.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/named.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/cast-bug.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/deduce.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/elision_weak.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/overload.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/temp-va-arg-bug.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/README
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/bind.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/overload-conv-1.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/collapse-bug.C
===================================================================
Index: gcc/testsuite/g++.dg/cpp0x/rref/overload-conv-2.C
===================================================================
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/typeck.c	(.../trunk)	(revision 88)
@@ -1027,8 +1027,12 @@ structural_comptypes (tree t1, tree t2, 
 	return false;
       break;
 
-    case POINTER_TYPE:
     case REFERENCE_TYPE:
+      if (TYPE_REF_IS_RVALUE(t1) != TYPE_REF_IS_RVALUE(t2))
+	return false;
+      /* fall through to checks for pointer types */
+
+    case POINTER_TYPE:
       if (TYPE_MODE (t1) != TYPE_MODE (t2)
 	  || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)
 	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
@@ -6737,18 +6741,40 @@ check_return_expr (tree retval, bool *no
     {
       /* The type the function is declared to return.  */
       tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
+      int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
 
       /* The functype's return type will have been set to void, if it
 	 was an incomplete type.  Just treat this as 'return;' */
       if (VOID_TYPE_P (functype))
 	return error_mark_node;
 
+      /* Under C++0x [12.8/16 class.copy], a returned lvalue is sometimes
+	 treated as an rvalue for the purposes of overload resolution to
+	 favor move constructors over copy constructors.  */
+      if (/* Must be a local, automatic variable.  */
+	  TREE_CODE (retval) == VAR_DECL
+	  && DECL_CONTEXT (retval) == current_function_decl
+	  && ! TREE_STATIC (retval)
+	  && (DECL_ALIGN (retval)
+	      >= DECL_ALIGN (DECL_RESULT (current_function_decl)))
+	   /* The variable much not have the `volatile' qualifier.  */
+	  && !(cp_type_quals (TREE_TYPE (retval)) & TYPE_QUAL_VOLATILE)
+	  /* The return type must be a class type.  */
+	  && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
+	  /* The cv-unqualified type of the returned value must be the
+	     same as the cv-unqualified return type of the
+	     function.  */
+	  && same_type_p ((TYPE_MAIN_VARIANT
+			   (TREE_TYPE (retval))),
+			  (TYPE_MAIN_VARIANT
+			   (TREE_TYPE (TREE_TYPE (current_function_decl))))))
+	flags = flags | LOOKUP_PREFER_RVALUE;
+
       /* First convert the value to the function's return type, then
 	 to the type of return value's location to handle the
 	 case that functype is smaller than the valtype.  */
       retval = convert_for_initialization
-	(NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
-	 "return", NULL_TREE, 0);
+	(NULL_TREE, functype, retval, flags, "return", NULL_TREE, 0);
       retval = convert (valtype, retval);
 
       /* If the conversion failed, treat this just like `return;'.  */
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/decl.c	(.../trunk)	(revision 88)
@@ -7747,10 +7747,24 @@ grokdeclarator (const cp_declarator *dec
 
 	  if (TREE_CODE (type) == REFERENCE_TYPE)
 	    {
-	      error (declarator->kind == cdk_reference
-		     ? "cannot declare reference to %q#T"
-		     : "cannot declare pointer to %q#T", type);
-	      type = TREE_TYPE (type);
+	      if (declarator->kind != cdk_reference)
+		{
+		  error ("cannot declare pointer to %q#T", type);
+		  type = TREE_TYPE (type);
+		}
+
+	      /* In C++0x, we allow reference to reference declarations
+		 that occur indirectly through typedefs [7.1.3/8 dcl.typedef]
+		 and template type arguments [14.3.1/4 temp.arg.type]. The
+		 check for direct reference to reference declarations, which
+		 are still forbidden, occurs below. Reasoning behind the change
+		 can be found in DR106, DR540, and the rvalue reference
+		 proposals. */
+	      else if (!flag_cpp0x)
+		{
+		  error ("cannot declare reference to %q#T", type);
+		  type = TREE_TYPE (type);
+		}
 	    }
 	  else if (VOID_TYPE_P (type))
 	    {
@@ -7776,8 +7790,32 @@ grokdeclarator (const cp_declarator *dec
 
 	  if (declarator->kind == cdk_reference)
 	    {
+	      /* In C++0x, the type we are creating a reference to might be
+		 a typedef which is itself a reference type. In that case,
+		 we follow the reference collapsing rules in
+		 [7.1.3/8 dcl.typedef] to create the final reference type. */
 	      if (!VOID_TYPE_P (type))
-		type = build_reference_type (type);
+		type = build_rval_reference_type
+		       ((TREE_CODE (type) == REFERENCE_TYPE
+			 ? TREE_TYPE (type) : type),
+			(declarator->u.pointer.rvalue_ref
+			 && (TREE_CODE(type) != REFERENCE_TYPE
+			     || TYPE_REF_IS_RVALUE (type))));
+
+	      /* In C++0x, we need this check for direct reference to
+		 reference declarations, which are forbidden by
+		 [8.3.2/5 dcl.ref]. Reference to reference declarations
+		 are only allowed indirectly through typedefs and template
+		 type arguments. Example:
+
+		   void foo(int & &);      // invalid ref-to-ref decl
+
+		   typedef int & int_ref;
+		   void foo(int_ref &);    // valid ref-to-ref decl
+	      */
+	      if (inner_declarator && inner_declarator->kind == cdk_reference)
+		error ("cannot declare reference to %q#T, which is not "
+		       "a typedef or a template type argument", type);
 	    }
 	  else if (TREE_CODE (type) == METHOD_TYPE)
 	    type = build_ptrmemfunc_type (build_pointer_type (type));
@@ -9000,6 +9038,7 @@ copy_fn_p (tree d)
       result = -1;
     }
   else if (TREE_CODE (arg_type) == REFERENCE_TYPE
+	   && !TYPE_REF_IS_RVALUE(arg_type)
 	   && TYPE_MAIN_VARIANT (TREE_TYPE (arg_type)) == DECL_CONTEXT (d))
     {
       if (CP_TYPE_CONST_P (TREE_TYPE (arg_type)))
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/call.c	(.../trunk)	(revision 88)
@@ -97,6 +97,10 @@ struct conversion {
   /* If KIND is ck_ptr or ck_pmem, true to indicate that a conversion
      from a pointer-to-derived to pointer-to-base is being performed.  */
   BOOL_BITFIELD base_p : 1;
+  /* If KIND is ck_ref_bind, true when either an lvalue reference is
+     being bound to an lvalue expression or an rvalue reference is
+     being bound to an rvalue expression. */
+  BOOL_BITFIELD valuedness_matches_p: 1;
   /* The type of the expression resulting from the conversion.  */
   tree type;
   union {
@@ -176,7 +180,7 @@ static conversion *standard_conversion (
 static conversion *reference_binding (tree, tree, tree, int);
 static conversion *build_conv (conversion_kind, tree, conversion *);
 static bool is_subseq (conversion *, conversion *);
-static tree maybe_handle_ref_bind (conversion **);
+static conversion *maybe_handle_ref_bind (conversion **);
 static void maybe_handle_implicit_object (conversion **);
 static struct z_candidate *add_candidate
 	(struct z_candidate **, tree, tree, size_t,
@@ -900,12 +904,12 @@ reference_compatible_p (tree t1, tree t2
    converted to T as in [over.match.ref].  */
 
 static conversion *
-convert_class_to_reference (tree t, tree s, tree expr)
+convert_class_to_reference (tree reference_type, tree s, tree expr)
 {
   tree conversions;
   tree arglist;
   conversion *conv;
-  tree reference_type;
+  tree t;
   struct z_candidate *candidates;
   struct z_candidate *cand;
   bool any_viable_p;
@@ -939,7 +943,7 @@ convert_class_to_reference (tree t, tree
   arglist = build_int_cst (build_pointer_type (s), 0);
   arglist = build_tree_list (NULL_TREE, arglist);
 
-  reference_type = build_reference_type (t);
+  t = TREE_TYPE (reference_type);
 
   while (conversions)
     {
@@ -1002,6 +1006,9 @@ convert_class_to_reference (tree t, tree
 	      cand->second_conv
 		= (direct_reference_binding
 		   (reference_type, identity_conv));
+	      cand->second_conv->valuedness_matches_p
+		= TYPE_REF_IS_RVALUE (TREE_TYPE (TREE_TYPE (cand->fn)))
+		  == TYPE_REF_IS_RVALUE(reference_type);
 	      cand->second_conv->bad_p |= cand->convs[0]->bad_p;
 	    }
 	}
@@ -1122,7 +1129,16 @@ reference_binding (tree rto, tree rfrom,
   related_p = reference_related_p (to, from);
   compatible_p = reference_compatible_p (to, from);
 
-  if (lvalue_p && compatible_p)
+  /* Directly bind reference when target expression's type is compatible with
+     the reference and expression is an lvalue. In C++0x, the wording in
+     [8.5.3/5 dcl.init.ref] is changed to also allow direct bindings for const
+     and rvalue references to rvalues of compatible class type, as part of
+     DR391. */
+  if (compatible_p
+      && (lvalue_p
+	  || (flag_cpp0x
+	      && (CP_TYPE_CONST_NON_VOLATILE_P(to) || TYPE_REF_IS_RVALUE(rto))
+	      && CLASS_TYPE_P (from))))
     {
       /* [dcl.init.ref]
 
@@ -1135,6 +1151,16 @@ reference_binding (tree rto, tree rfrom,
 	 lvalue.  */
       conv = build_identity_conv (from, expr);
       conv = direct_reference_binding (rto, conv);
+
+      if (flags & LOOKUP_PREFER_RVALUE)
+	/* The top-level caller requested that we pretend that the lvalue
+	   be treated as an rvalue.  */
+	conv->valuedness_matches_p = TYPE_REF_IS_RVALUE (rto);
+      else
+	conv->valuedness_matches_p
+	  = ((lvalue_p && !TYPE_REF_IS_RVALUE (rto)))
+	     || (!lvalue_p && TYPE_REF_IS_RVALUE (rto));
+
       if ((lvalue_p & clk_bitfield) != 0
 	  || ((lvalue_p & clk_packed) != 0 && !TYPE_PACKED (to)))
 	/* For the purposes of overload resolution, we ignore the fact
@@ -1167,7 +1193,7 @@ reference_binding (tree rto, tree rfrom,
 
 	the reference is bound to the lvalue result of the conversion
 	in the second case.  */
-      conv = convert_class_to_reference (to, from, expr);
+      conv = convert_class_to_reference (rto, from, expr);
       if (conv)
 	return conv;
     }
@@ -1190,8 +1216,10 @@ reference_binding (tree rto, tree rfrom,
 
   /* [dcl.init.ref]
 
-     Otherwise, the reference shall be to a non-volatile const type.  */
-  if (!CP_TYPE_CONST_NON_VOLATILE_P (to))
+     Otherwise, the reference shall be to a non-volatile const type.
+
+     Under C++0x, [8.5.3/5 dcl.init.ref] it may also be an rvalue reference */
+  if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
     return NULL;
 
   /* [dcl.init.ref]
@@ -1214,6 +1242,7 @@ reference_binding (tree rto, tree rfrom,
     {
       conv = build_identity_conv (from, expr);
       conv = direct_reference_binding (rto, conv);
+      conv->valuedness_matches_p = TYPE_REF_IS_RVALUE(rto);
       if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE))
 	conv->u.next->check_copy_constructor_p = true;
       return conv;
@@ -1238,6 +1267,7 @@ reference_binding (tree rto, tree rfrom,
   /* This reference binding, unlike those above, requires the
      creation of a temporary.  */
   conv->need_temporary_p = true;
+  conv->valuedness_matches_p = TYPE_REF_IS_RVALUE(rto);
 
   return conv;
 }
@@ -1279,7 +1309,7 @@ implicit_conversion (tree to, tree from,
 	conv = cand->second_conv;
 
       /* We used to try to bind a reference to a temporary here, but that
-	 is now handled by the recursive call to this function at the end
+	 is now handled after the recursive call to this function at the end
 	 of reference_binding.  */
       return conv;
     }
@@ -4404,13 +4434,22 @@ convert_like_real (conversion *convs, tr
       {
 	tree ref_type = totype;
 
-	/* If necessary, create a temporary.  */
-	if (convs->need_temporary_p || !lvalue_p (expr))
+	/* If necessary, create a temporary.
+
+	   ??? VA_ARG_EXPR and CONSTRUCTOR expressions are special cases
+	   that seem to need temporaries, even when their types are
+	   reference compatible with the type of reference being bound,
+	   so the upcoming call to build_unary_op (ADDR_EXPR, expr, ...)
+	   doesn't fail.  */
+	if (convs->need_temporary_p
+	    || TREE_CODE (expr) == CONSTRUCTOR
+	    || TREE_CODE (expr) == VA_ARG_EXPR)
 	  {
 	    tree type = convs->u.next->type;
 	    cp_lvalue_kind lvalue = real_lvalue_p (expr);
 
-	    if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
+	    if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type))
+		&& !TYPE_REF_IS_RVALUE(ref_type))
 	      {
 		/* If the reference is volatile or non-const, we
 		   cannot create a temporary.  */
@@ -5646,28 +5685,28 @@ maybe_handle_implicit_object (conversion
 	t = t->u.next;
       t = build_identity_conv (TREE_TYPE (t->type), NULL_TREE);
       t = direct_reference_binding (reference_type, t);
+      t->valuedness_matches_p = 1;
       *ics = t;
     }
 }
 
 /* If *ICS is a REF_BIND set *ICS to the remainder of the conversion,
-   and return the type to which the reference refers.  Otherwise,
-   leave *ICS unchanged and return NULL_TREE.  */
+   and return the initial reference binding conversion. Otherwise,
+   leave *ICS unchanged and return NULL.  */
 
-static tree
+static conversion *
 maybe_handle_ref_bind (conversion **ics)
 {
   if ((*ics)->kind == ck_ref_bind)
     {
       conversion *old_ics = *ics;
-      tree type = TREE_TYPE (old_ics->type);
       *ics = old_ics->u.next;
       (*ics)->user_conv_p = old_ics->user_conv_p;
       (*ics)->bad_p = old_ics->bad_p;
-      return type;
+      return old_ics;
     }
 
-  return NULL_TREE;
+  return NULL;
 }
 
 /* Compare two implicit conversion sequences according to the rules set out in
@@ -5691,18 +5730,18 @@ compare_ics (conversion *ics1, conversio
   conversion_rank rank1, rank2;
 
   /* REF_BINDING is nonzero if the result of the conversion sequence
-     is a reference type.   In that case TARGET_TYPE is the
-     type referred to by the reference.  */
-  tree target_type1;
-  tree target_type2;
+     is a reference type.   In that case REF_CONV is the reference
+     binding conversion. */
+  conversion *ref_conv1;
+  conversion *ref_conv2;
 
   /* Handle implicit object parameters.  */
   maybe_handle_implicit_object (&ics1);
   maybe_handle_implicit_object (&ics2);
 
   /* Handle reference parameters.  */
-  target_type1 = maybe_handle_ref_bind (&ics1);
-  target_type2 = maybe_handle_ref_bind (&ics2);
+  ref_conv1 = maybe_handle_ref_bind (&ics1);
+  ref_conv2 = maybe_handle_ref_bind (&ics2);
 
   /* [over.ics.rank]
 
@@ -5993,15 +6032,31 @@ compare_ics (conversion *ics1, conversio
 
   /* [over.ics.rank]
 
+     --S1 and S2 are reference bindings (_dcl.init.ref_) and neither refers
+     to an implicit object parameter, and either S1 binds an lvalue reference
+     to an lvalue and S2 binds an rvalue reference or S1 binds an rvalue
+     reference to an rvalue and S2 binds an lvalue reference
+     (C++0x draft standard, 13.3.3.2)
+
      --S1 and S2 are reference bindings (_dcl.init.ref_), and the
      types to which the references refer are the same type except for
      top-level cv-qualifiers, and the type to which the reference
      initialized by S2 refers is more cv-qualified than the type to
      which the reference initialized by S1 refers */
 
-  if (target_type1 && target_type2
+  if (ref_conv1 && ref_conv2
       && same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
-    return comp_cv_qualification (target_type2, target_type1);
+    {
+      if (ref_conv1->valuedness_matches_p
+	  && !ref_conv2->valuedness_matches_p)
+	return 1;
+      else if (!ref_conv1->valuedness_matches_p
+	  && ref_conv2->valuedness_matches_p)
+	return -1;
+
+      return comp_cv_qualification (TREE_TYPE (ref_conv2->type),
+				    TREE_TYPE (ref_conv1->type));
+    }
 
   /* Neither conversion sequence is better than the other.  */
   return 0;
Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/except.c	(.../trunk)	(revision 88)
@@ -709,12 +709,25 @@ build_throw (tree exp)
       /* And initialize the exception object.  */
       if (CLASS_TYPE_P (temp_type))
 	{
+	  int flags = LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING;
+
+	  /* Under C++0x [12.8/16 class.copy], a thrown lvalue is sometimes
+	     treated as an rvalue for the purposes of overload resolution
+	     to favor move constructors over copy constructors.  */
+	  if (/* Must be a local, automatic variable.  */
+	      TREE_CODE (exp) == VAR_DECL
+	      && DECL_CONTEXT (exp) == current_function_decl
+	      && ! TREE_STATIC (exp)
+	      /* The variable much not have the `volatile' qualifier.  */
+	      && !(cp_type_quals (TREE_TYPE (exp)) & TYPE_QUAL_VOLATILE))
+	    flags = flags | LOOKUP_PREFER_RVALUE;
+
 	  /* Call the copy constructor.  */
 	  exp = (build_special_member_call
 		 (object, complete_ctor_identifier,
 		  build_tree_list (NULL_TREE, exp),
 		  TREE_TYPE (object),
-		  LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING));
+		  flags));
 	  if (exp == error_mark_node)
 	    {
 	      error ("  in thrown expression");
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/error.c	(.../trunk)	(revision 88)
@@ -509,7 +509,15 @@ dump_type_prefix (tree t, int flags)
 	    pp_cxx_whitespace (cxx_pp);
 	    pp_cxx_left_paren (cxx_pp);
 	  }
-	pp_character (cxx_pp, "&*"[TREE_CODE (t) == POINTER_TYPE]);
+	if (TREE_CODE (t) == POINTER_TYPE)
+	  pp_character(cxx_pp, '*');
+	else if (TREE_CODE (t) == REFERENCE_TYPE)
+	{
+	  if (TYPE_REF_IS_RVALUE (t))
+	    pp_string (cxx_pp, "&&");
+	  else
+	    pp_character (cxx_pp, '&');
+	}
 	pp_base (cxx_pp)->padding = pp_before;
 	pp_cxx_cv_qualifier_seq (cxx_pp, t);
       }
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/tree.c	(.../trunk)	(revision 88)
@@ -64,8 +64,26 @@ lvalue_p_1 (tree ref,
   cp_lvalue_kind op1_lvalue_kind = clk_none;
   cp_lvalue_kind op2_lvalue_kind = clk_none;
 
+  /* Expressions of reference type are sometimes wrapped in
+     INDIRECT_REFs */
+  if (TREE_CODE (ref) == INDIRECT_REF
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0)))
+	  == REFERENCE_TYPE)
+    return lvalue_p_1(TREE_OPERAND (ref, 0),
+		      treat_class_rvalues_as_lvalues);
+
   if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
-    return clk_ordinary;
+    {
+      /* unnamed rvalue references are rvalues */
+      if (TYPE_REF_IS_RVALUE (TREE_TYPE (ref))
+	  && TREE_CODE (ref) != PARM_DECL
+	  && TREE_CODE (ref) != VAR_DECL
+	  && TREE_CODE (ref) != COMPONENT_REF)
+	return clk_none;
+
+      /* lvalue references and named rvalue refences are lvalues */
+      return clk_ordinary;
+    }
 
   if (ref == current_class_ptr)
     return clk_none;
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/mangle.c	(.../trunk)	(revision 88)
@@ -1621,6 +1621,8 @@ write_type (tree type)
 	  break;
 
 	case REFERENCE_TYPE:
+	  if TYPE_REF_IS_RVALUE(type)
+	    write_string("U6rvalue");
 	  write_char ('R');
 	  write_type (TREE_TYPE (type));
 	  break;
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/cp-tree.h	(.../trunk)	(revision 88)
@@ -3531,6 +3531,8 @@ enum overload_flags { NO_SPECIAL = 0, DT
    (Normally, these entities are registered in the symbol table, but
    not found by lookup.)  */
 #define LOOKUP_HIDDEN (LOOKUP_CONSTRUCTOR_CALLABLE << 1)
+/* Prefer that the lvalue be treated as an rvalue.  */
+#define LOOKUP_PREFER_RVALUE (LOOKUP_HIDDEN << 1)
 
 #define LOOKUP_NAMESPACES_ONLY(F)  \
   (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -3847,6 +3849,8 @@ struct cp_declarator {
       cp_cv_quals qualifiers;
       /* For cdk_ptrmem, the class type containing the member.  */
       tree class_type;
+      /* For cdk_reference, is this rvalue reference */
+      bool rvalue_ref;
     } pointer;
   } u;
 };
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/pt.c	(.../trunk)	(revision 88)
@@ -116,7 +116,8 @@ static void tsubst_enum	(tree, tree, tre
 static tree add_to_template_args (tree, tree);
 static tree add_outermost_template_args (tree, tree);
 static bool check_instantiated_args (tree, tree, tsubst_flags_t);
-static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*);
+static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
+					     tree);
 static int  type_unification_real (tree, tree, tree, tree,
 				   int, unification_kind_t, int);
 static void note_template_header (int);
@@ -7624,8 +7625,13 @@ tsubst (tree t, tree args, tsubst_flags_
 
 	   -- Attempting to create a pointer to reference type.
 	   -- Attempting to create a reference to a reference type or
-	      a reference to void.  */
-	if (TREE_CODE (type) == REFERENCE_TYPE
+	      a reference to void.
+
+	  Under C++0x [14.8.2/2 temp.deduct], as part of the solution to
+	  DR106, creating a reference to a reference type during type
+	  deduction is no longer a cause for failure.   */
+	if ((TREE_CODE (type) == REFERENCE_TYPE
+	     && (!flag_cpp0x || code != REFERENCE_TYPE))
 	    || (code == REFERENCE_TYPE && TREE_CODE (type) == VOID_TYPE))
 	  {
 	    static location_t last_loc;
@@ -7659,8 +7665,15 @@ tsubst (tree t, tree args, tsubst_flags_
 	    if (TREE_CODE (type) == METHOD_TYPE)
 	      r = build_ptrmemfunc_type (r);
 	  }
+	else if (TREE_CODE (type) == REFERENCE_TYPE)
+	  /* In C++0x, during template argument substitution, when there is an
+	     attempt to create a reference to a reference type, reference
+	     collapsing is applied as described in [14.3.1/4 temp.arg.type]. */
+	  r = build_rval_reference_type
+	      (TREE_TYPE (type),
+	       TYPE_REF_IS_RVALUE (t) && TYPE_REF_IS_RVALUE (type));
 	else
-	  r = build_reference_type (type);
+	  r = build_rval_reference_type (type, TYPE_REF_IS_RVALUE (t));
 	r = cp_build_qualified_type_real (r, TYPE_QUALS (t), complain);
 
 	if (r != error_mark_node)
@@ -9889,12 +9902,14 @@ fn_type_unification (tree fn,
    sections are symmetric.  PARM is the type of a function parameter
    or the return type of the conversion function.  ARG is the type of
    the argument passed to the call, or the type of the value
-   initialized with the result of the conversion function.  */
+   initialized with the result of the conversion function.
+   ARG_EXPR is the original argument expression, which may be null.  */
 
 static int
 maybe_adjust_types_for_deduction (unification_kind_t strict,
 				  tree* parm,
-				  tree* arg)
+				  tree* arg,
+				  tree arg_expr)
 {
   int result = 0;
 
@@ -9948,6 +9963,16 @@ maybe_adjust_types_for_deduction (unific
 	*arg = TYPE_MAIN_VARIANT (*arg);
     }
 
+  /* From C++0x [14.8.2.1/3 temp.deduct.call] (after DR606), "If P is
+     of the form T&&, where T is a template parameter, and the argument
+     is an lvalue, T is deduced as A& */
+  if (TREE_CODE (*parm) == REFERENCE_TYPE
+      && TYPE_REF_IS_RVALUE (*parm)
+      && TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM
+      && cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED
+      && arg_expr && real_lvalue_p (arg_expr))
+    *arg = build_reference_type (*arg);
+
   /* [temp.deduct.call]
 
      If P is a cv-qualified type, the top level cv-qualifiers
@@ -9984,7 +10009,7 @@ type_unification_real (tree tparms,
 		       unification_kind_t strict,
 		       int flags)
 {
-  tree parm, arg;
+  tree parm, arg, arg_expr;
   int i;
   int ntparms = TREE_VEC_LENGTH (tparms);
   int sub_strict;
@@ -10026,6 +10051,7 @@ type_unification_real (tree tparms,
       parms = TREE_CHAIN (parms);
       arg = TREE_VALUE (args);
       args = TREE_CHAIN (args);
+      arg_expr = NULL;
 
       if (arg == error_mark_node)
 	return 1;
@@ -10074,6 +10100,7 @@ type_unification_real (tree tparms,
 		return 1;
 	      continue;
 	    }
+	  arg_expr = arg;
 	  arg = TREE_TYPE (arg);
 	  if (arg == error_mark_node)
 	    return 1;
@@ -10083,7 +10110,8 @@ type_unification_real (tree tparms,
 	int arg_strict = sub_strict;
 
 	if (!subr)
-	  arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);
+	  arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg,
+							  arg_expr);
 
 	if (unify (tparms, targs, parm, arg, arg_strict))
 	  return 1;
@@ -10258,7 +10286,7 @@ try_one_overload (tree tparms,
   else if (addr_p)
     arg = build_pointer_type (arg);
 
-  sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);
+  sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg, NULL);
 
   /* We don't copy orig_targs for this because if we have already deduced
      some template args from previous args, unify would complain when we
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(.../vendor/gcc/svn-122166)	(revision 88)
+++ gcc/cp/parser.c	(.../trunk)	(revision 88)
@@ -858,7 +858,7 @@ static cp_declarator *make_array_declara
 static cp_declarator *make_pointer_declarator
   (cp_cv_quals, cp_declarator *);
 static cp_declarator *make_reference_declarator
-  (cp_cv_quals, cp_declarator *);
+  (cp_cv_quals, cp_declarator *, bool);
 static cp_parameter_declarator *make_parameter_declarator
   (cp_decl_specifier_seq *, cp_declarator *, tree);
 static cp_declarator *make_ptrmem_declarator
@@ -952,7 +952,8 @@ make_pointer_declarator (cp_cv_quals cv_
 /* Like make_pointer_declarator -- but for references.  */
 
 cp_declarator *
-make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
+make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target,
+			   bool rvalue_ref)
 {
   cp_declarator *declarator;
 
@@ -960,6 +961,7 @@ make_reference_declarator (cp_cv_quals c
   declarator->declarator = target;
   declarator->u.pointer.qualifiers = cv_qualifiers;
   declarator->u.pointer.class_type = NULL_TREE;
+  declarator->u.pointer.rvalue_ref = rvalue_ref;
 
   return declarator;
 }
@@ -1943,6 +1945,8 @@ static bool cp_parser_is_keyword
   (cp_token *, enum rid);
 static tree cp_parser_make_typename_type
   (cp_parser *, tree, tree);
+static cp_declarator * cp_parser_make_indirect_declarator
+  (enum tree_code, tree, cp_cv_quals, cp_declarator *);
 
 /* Returns nonzero if we are parsing tentatively.  */
 
@@ -2615,6 +2619,27 @@ cp_parser_make_typename_type (cp_parser 
   return make_typename_type (scope, id, typename_type, tf_error);
 }
 
+/* This is a wrapper around the
+   make_{pointer,ptrmem,reference}_declarator functions that decides
+   which one to call based on the CODE and CLASS_TYPE arguments. The
+   CODE argument should be one of the values returned by
+   cp_parser_ptr_operator. */
+static cp_declarator *
+cp_parser_make_indirect_declarator (enum tree_code code, tree class_type,
+				    cp_cv_quals cv_qualifiers,
+				    cp_declarator *target)
+{
+  if (code == INDIRECT_REF)
+    if (class_type == NULL_TREE)
+      return make_pointer_declarator (cv_qualifiers, target);
+    else
+      return make_ptrmem_declarator (cv_qualifiers, class_type, target);
+  else if (code == ADDR_EXPR && class_type == NULL_TREE)
+    return make_reference_declarator (cv_qualifiers, target, false);
+  else if (code == NON_LVALUE_EXPR && class_type == NULL_TREE)
+    return make_reference_declarator (cv_qualifiers, target, true);
+  gcc_unreachable ();
+}
 
 /* Create a new C++ parser.  */
 
@@ -5384,15 +5409,8 @@ cp_parser_new_declarator_opt (cp_parser*
       /* Parse another optional declarator.  */
       declarator = cp_parser_new_declarator_opt (parser);
 
-      /* Create the representation of the declarator.  */
-      if (type)
-	declarator = make_ptrmem_declarator (cv_quals, type, declarator);
-      else if (code == INDIRECT_REF)
-	declarator = make_pointer_declarator (cv_quals, declarator);
-      else
-	declarator = make_reference_declarator (cv_quals, declarator);
-
-      return declarator;
+      return cp_parser_make_indirect_declarator
+	(code, type, cv_quals, declarator);
     }
 
   /* If the next token is a `[', there is a direct-new-declarator.  */
@@ -8121,16 +8139,8 @@ cp_parser_conversion_declarator_opt (cp_
       /* Parse another optional declarator.  */
       declarator = cp_parser_conversion_declarator_opt (parser);
 
-      /* Create the representation of the declarator.  */
-      if (class_type)
-	declarator = make_ptrmem_declarator (cv_quals, class_type,
-					     declarator);
-      else if (code == INDIRECT_REF)
-	declarator = make_pointer_declarator (cv_quals, declarator);
-      else
-	declarator = make_reference_declarator (cv_quals, declarator);
-
-      return declarator;
+      return cp_parser_make_indirect_declarator
+	(code, class_type, cv_quals, declarator);
    }
 
   return NULL;
@@ -11589,15 +11599,8 @@ cp_parser_declarator (cp_parser* parser,
 	  && !cp_parser_parse_definitely (parser))
 	declarator = NULL;
 
-      /* Build the representation of the ptr-operator.  */
-      if (class_type)
-	declarator = make_ptrmem_declarator (cv_quals,
-					     class_type,
-					     declarator);
-      else if (code == INDIRECT_REF)
-	declarator = make_pointer_declarator (cv_quals, declarator);
-      else
-	declarator = make_reference_declarator (cv_quals, declarator);
+      declarator = cp_parser_make_indirect_declarator
+	(code, class_type, cv_quals, declarator);
     }
   /* Everything else is a direct-declarator.  */
   else
@@ -12038,12 +12041,15 @@ cp_parser_direct_declarator (cp_parser* 
      & cv-qualifier-seq [opt]
 
    Returns INDIRECT_REF if a pointer, or pointer-to-member, was used.
-   Returns ADDR_EXPR if a reference was used.  In the case of a
-   pointer-to-member, *TYPE is filled in with the TYPE containing the
-   member.  *CV_QUALS is filled in with the cv-qualifier-seq, or
-   TYPE_UNQUALIFIED, if there are no cv-qualifiers.  Returns
-   ERROR_MARK if an error occurred.  */
-
+   Returns ADDR_EXPR if a reference was used, or NON_LVALUE_EXPR for
+   an rvalue reference. In the case of a pointer-to-member, *TYPE is
+   filled in with the TYPE containing the member.  *CV_QUALS is
+   filled in with the cv-qualifier-seq, or TYPE_UNQUALIFIED, if there
+   are no cv-qualifiers.  Returns ERROR_MARK if an error occurred.
+   Note that the tree codes returned by this function have nothing
+   to do with the types of trees that will be eventually be created
+   to represent the pointer or reference type being parsed. They are
+   just constants with suggestive names. */
 static enum tree_code
 cp_parser_ptr_operator (cp_parser* parser,
 			tree* type,
@@ -12059,13 +12065,18 @@ cp_parser_ptr_operator (cp_parser* parse
 
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
-  /* If it's a `*' or `&' we have a pointer or reference.  */
-  if (token->type == CPP_MULT || token->type == CPP_AND)
-    {
-      /* Remember which ptr-operator we were processing.  */
-      code = (token->type == CPP_AND ? ADDR_EXPR : INDIRECT_REF);
 
-      /* Consume the `*' or `&'.  */
+  /* If it's a `*', `&' or `&&' we have a pointer or reference.  */
+  if (token->type == CPP_MULT)
+    code = INDIRECT_REF;
+  else if (token->type == CPP_AND)
+    code = ADDR_EXPR;
+  else if (flag_cpp0x && token->type == CPP_AND_AND) /* C++0x only */
+    code = NON_LVALUE_EXPR;
+
+  if (code != ERROR_MARK)
+    {
+      /* Consume the `*', `&' or `&&'.  */
       cp_lexer_consume_token (parser->lexer);
 
       /* A `*' can be followed by a cv-qualifier-seq, and so can a
Index: ChangeLog
===================================================================

Attachment: tests.tar.bz2
Description: application/bzip-compressed-tar

Attachment: signature.asc
Description: This is a digitally signed message part


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