call.c (reference_binding): Remove REF_IS_VAR parameter.
authorMark Mitchell <mark@codesourcery.com>
Fri, 7 Mar 2003 21:19:38 +0000 (21:19 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 7 Mar 2003 21:19:38 +0000 (21:19 +0000)
* call.c (reference_binding): Remove REF_IS_VAR parameter.
(implicit_conversion): Adjust call to reference_binding.
(make_temporary_var_for_ref_to_type): Add TYPE parameter.
(initialize_reference): Adjust handling for references bound to
rvalues.
* cp-tree.h (make_temporary_var_for_ref_to_temp): Change
prototype.
(real_non_cast_lvalue_p): New function.
* cvt.c (build_up_reference): Adjust use of
make_temporary_var_for_ref_to_temp.
* tree.c (real_non_cast_lvalue_p): New function.

* g++.dg/init/ref4.C: New test.

From-SVN: r63949

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/ref4.C [new file with mode: 0644]

index afb3436913dc148ffe38629752df89e698ed3cff..f11bba8a2718397b11ad2620377a8b87aa0ba18f 100644 (file)
@@ -1,3 +1,17 @@
+2003-03-07  Mark Mitchell  <mark@codesourcery.com>
+
+       * call.c (reference_binding): Remove REF_IS_VAR parameter.
+       (implicit_conversion): Adjust call to reference_binding.
+       (make_temporary_var_for_ref_to_type): Add TYPE parameter.
+       (initialize_reference): Adjust handling for references bound to
+       rvalues.
+       * cp-tree.h (make_temporary_var_for_ref_to_temp): Change
+       prototype.
+       (real_non_cast_lvalue_p): New method.
+       * cvt.c (build_up_reference): Adjust use of
+       make_temporary_var_for_ref_to_temp.
+       * tree.c (
+        
 2003-03-07  Gabriel Dos Reis  <gdr@integrable-solutions.net>
 
        * except.c (init_exception_processing): Use C90 prototype style.
index 15dbbe1d2b4322bcb92c0881d1ff35c2266becef..a25da46784bdc28da4850d023027bdda0b0aecef 100644 (file)
@@ -85,7 +85,7 @@ static struct z_candidate *add_function_candidate
        (struct z_candidate **, tree, tree, tree, tree, tree, int);
 static tree implicit_conversion (tree, tree, tree, int);
 static tree standard_conversion (tree, tree, tree);
-static tree reference_binding (tree, tree, tree, int, bool);
+static tree reference_binding (tree, tree, tree, int);
 static tree non_reference (tree);
 static tree build_conv (enum tree_code, tree, tree);
 static bool is_subseq (tree, tree);
@@ -1133,12 +1133,10 @@ direct_reference_binding (tree type, tree conv)
    purposes of reference binding.  For lvalue binding, either pass a
    reference type to FROM or an lvalue expression to EXPR.  If the
    reference will be bound to a temporary, NEED_TEMPORARY_P is set for
-   the conversion returned.  REF_IS_VAR is true iff the reference is
-   a variable (rather than, say, a parameter declaration).  */
+   the conversion returned.  */
 
 static tree
-reference_binding (tree rto, tree rfrom, tree expr, int flags,
-                  bool ref_is_var)
+reference_binding (tree rto, tree rfrom, tree expr, int flags)
 {
   tree conv = NULL_TREE;
   tree to = TREE_TYPE (rto);
@@ -1250,22 +1248,14 @@ reference_binding (tree rto, tree rfrom, tree expr, int flags,
      -- The reference is bound to the object represented by the rvalue
         or to a sub-object within that object.  
 
-     -- A temporary of type "cv1 T2" [sic] is created, and a
-        constructor is called to copy the entire rvalue object into
-        the temporary.  The reference is bound to the temporary or to
-        a sub-object within the temporary
+     -- ...
        
-     In general, we choose the first alternative, since it avoids the
-     copy.  However, if REF_IS_VAR is true, then we cannot do that; we
-     need to bind the reference to a temporary that wil live as long
-     as the reference itself.
-
-     In the first alternative, the implicit conversion sequence is
-     supposed to be same as we would obtain by generating a temporary.
-     Fortunately, if the types are reference compatible, then this is
-     either an identity conversion or the derived-to-base conversion,
-     just as for direct binding.  */
-  if (CLASS_TYPE_P (from) && compatible_p && !ref_is_var)
+     We use the first alternative.  The implicit conversion sequence
+     is supposed to be same as we would obtain by generating a
+     temporary.  Fortunately, if the types are reference compatible,
+     then this is either an identity conversion or the derived-to-base
+     conversion, just as for direct binding.  */
+  if (CLASS_TYPE_P (from) && compatible_p)
     {
       conv = build1 (IDENTITY_CONV, from, expr);
       return direct_reference_binding (rto, conv);
@@ -1321,7 +1311,7 @@ implicit_conversion (tree to, tree from, tree expr, int flags)
   complete_type (to);
 
   if (TREE_CODE (to) == REFERENCE_TYPE)
-    conv = reference_binding (to, from, expr, flags, /*ref_is_var=*/false);
+    conv = reference_binding (to, from, expr, flags);
   else
     conv = standard_conversion (to, from, expr);
 
@@ -5849,19 +5839,14 @@ perform_implicit_conversion (tree type, tree expr)
 
 /* DECL is a VAR_DECL whose type is a REFERENCE_TYPE.  The reference
    is being bound to a temporary.  Create and return a new VAR_DECL
-   whose type is the underlying type of the reference.  */
+   with the indicated TYPE; this variable will store the value to
+   which the reference is bound.  */
 
 tree 
-make_temporary_var_for_ref_to_temp (tree decl)
+make_temporary_var_for_ref_to_temp (tree decl, tree type)
 {
-  tree type;
   tree var;
 
-  /* Get the type to which the reference refers.  */
-  type = TREE_TYPE (decl);
-  my_friendly_assert (TREE_CODE (type) == REFERENCE_TYPE, 200302);
-  type = TREE_TYPE (type);
-
   /* Create the variable.  */
   var = build_decl (VAR_DECL, NULL_TREE, type);
   DECL_ARTIFICIAL (var) = 1;
@@ -5905,8 +5890,7 @@ initialize_reference (tree type, tree expr, tree decl)
   if (type == error_mark_node || error_operand_p (expr))
     return error_mark_node;
 
-  conv = reference_binding (type, TREE_TYPE (expr), expr, LOOKUP_NORMAL,
-                           decl != NULL_TREE);
+  conv = reference_binding (type, TREE_TYPE (expr), expr, LOOKUP_NORMAL);
   if (!conv || ICS_BAD_FLAG (conv))
     {
       error ("could not convert `%E' to `%T'", expr, type);
@@ -5918,7 +5902,7 @@ initialize_reference (tree type, tree expr, tree decl)
        [class.temporary]
 
        The temporary to which the reference is bound or the temporary
-       that is the complete object to which the temporary is bound
+       that is the complete object to which the reference is bound
        persists for the lifetime of the reference.
 
        The temporaries created during the evaluation of the expression
@@ -5927,22 +5911,64 @@ initialize_reference (tree type, tree expr, tree decl)
        full-expression in which they are created.
 
      In that case, we store the converted expression into a new
-     VAR_DECL in a new scope.  */
+     VAR_DECL in a new scope.  
+
+     However, we want to be careful not to create temporaries when
+     they are not required.  For example, given:
+
+       struct B {}; 
+       struct D : public B {};
+       D f();
+       const B& b = f();
+
+     there is no need to copy the return value from "f"; we can just
+     extend its lifetime.  Similarly, given:
+
+       struct S {};
+       struct T { operator S(); };
+       T t;
+       const S& s = t;
+
+    we can extend the lifetime of the returnn value of the conversion
+    operator.  */
   my_friendly_assert (TREE_CODE (conv) == REF_BIND, 20030302);
-  if (decl && NEED_TEMPORARY_P (conv))
+  if (decl)
     {
       tree var;
-      
-      /* Process the initializer for the declaration.  */
-      expr = convert_like (TREE_OPERAND (conv, 0), expr);
-      /* Create the temporary variable.  */
-      var = make_temporary_var_for_ref_to_temp (decl);
-      DECL_INITIAL (var) = expr;
-      cp_finish_decl (var, expr, NULL_TREE, 
-                     LOOKUP_ONLYCONVERTING|DIRECT_BIND);
+      tree base_conv_type;
 
-      /* Use its address to initialize the reference variable.  */
-      return build_nop (type, build_address (var));
+      /* Skip over the REF_BIND.  */
+      conv = TREE_OPERAND (conv, 0);
+      /* If the next conversion is a BASE_CONV, skip that too -- but
+        remember that the conversion was required.  */
+      if (TREE_CODE (conv) == BASE_CONV)
+       {
+         my_friendly_assert (!NEED_TEMPORARY_P (conv), 20030307);
+         base_conv_type = TREE_TYPE (conv);
+         conv = TREE_OPERAND (conv, 0);
+       }
+      else
+       base_conv_type = NULL_TREE;
+      /* Perform the remainder of the conversion.  */
+      expr = convert_like (conv, expr);
+      if (!real_non_cast_lvalue_p (expr))
+       {
+         /* Create the temporary variable.  */
+         var = make_temporary_var_for_ref_to_temp (decl, TREE_TYPE (expr));
+         DECL_INITIAL (var) = expr;
+         cp_finish_decl (var, expr, NULL_TREE, 
+                     LOOKUP_ONLYCONVERTING|DIRECT_BIND);
+         /* Use its address to initialize the reference variable.  */
+         expr = build_address (var);
+       }
+      else
+       /* Take the address of EXPR.  */
+       expr = build_unary_op (ADDR_EXPR, expr, 0);
+      /* If a BASE_CONV was required, perform it now.  */
+      if (base_conv_type)
+       expr = (perform_implicit_conversion 
+               (build_pointer_type (base_conv_type), expr));
+      return build_nop (type, expr);
     }
 
   /* Perform the conversion.  */
index 447fd57530b2fb6cc2e6da3d9665072e3b7b32ce..53a4db6de87ce305965a167e95e7bea85c2335e1 100644 (file)
@@ -3581,7 +3581,7 @@ extern tree convert_for_arg_passing (tree, tree);
 extern tree cp_convert_parm_for_inlining        (tree, tree, tree);
 extern bool is_properly_derived_from (tree, tree);
 extern tree initialize_reference (tree, tree, tree);
-extern tree make_temporary_var_for_ref_to_temp (tree);
+extern tree make_temporary_var_for_ref_to_temp (tree, tree);
 extern tree strip_top_quals (tree);
 extern tree perform_implicit_conversion (tree, tree);
 extern tree in_charge_arg_for_name (tree);
@@ -4226,6 +4226,7 @@ extern tree copy_base_binfos                      (tree, tree, tree);
 extern int member_p                            (tree);
 extern cp_lvalue_kind real_lvalue_p            (tree);
 extern int non_cast_lvalue_p                   (tree);
+extern cp_lvalue_kind real_non_cast_lvalue_p    (tree);
 extern int non_cast_lvalue_or_else             (tree, const char *);
 extern tree build_min                          (enum tree_code, tree,
                                                         ...);
index ba5fbba1a1616d25aee0d94cf9a8c503ca683032..88e802e14b0a3cda258d1958d096fb99eda67e97 100644 (file)
@@ -358,7 +358,7 @@ build_up_reference (tree type, tree arg, int flags, tree decl)
         here because it needs to live as long as DECL.  */
       tree targ = arg;
 
-      arg = make_temporary_var_for_ref_to_temp (decl);
+      arg = make_temporary_var_for_ref_to_temp (decl, TREE_TYPE (arg));
 
       /* Process the initializer for the declaration.  */
       DECL_INITIAL (arg) = targ;
index 520aa164572126143fb5eb1cd24328592b52a002..94fe9fbd903e2e013c8651b2bbeea5fddd9fd5d1 100644 (file)
@@ -212,6 +212,18 @@ real_lvalue_p (ref)
   return lvalue_p_1 (ref, /*treat_class_rvalues_as_lvalues=*/ 0, /*cast*/ 1);
 }
 
+/* Returns the kind of lvalue that REF is, in the sense of
+   [basic.lval].  This function should really be named lvalue_p; it
+   computes the C++ definition of lvalue.  */
+
+cp_lvalue_kind
+real_non_cast_lvalue_p (tree ref)
+{
+  return lvalue_p_1 (ref, 
+                    /*treat_class_rvalues_as_lvalues=*/0, 
+                    /*allow_cast_as_lvalue=*/0);
+}
+
 /* This differs from real_lvalue_p in that class rvalues are
    considered lvalues.  */
 
index 2a95e094307df1039a5b47c501371d8cb29aeb55..27c6197d9f845d22e4a926c8edec22dbdc227955 100644 (file)
@@ -1,3 +1,7 @@
+2003-03-07  Mark Mitchell  <mark@codesourcery.com>
+
+       * g++.dg/init/ref4.C: New test.
+
 Fri Mar  7 17:41:07 CET 2003  Jan Hubicka  <jh@suse.cz>
 
        * gcc.dg/i386-local2.c: Fix problems with certain versions of dejagnu.
diff --git a/gcc/testsuite/g++.dg/init/ref4.C b/gcc/testsuite/g++.dg/init/ref4.C
new file mode 100644 (file)
index 0000000..6b65d99
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do run }
+
+int c;
+
+struct Base {
+  Base() {}
+  Base(const Base &) { ++c; }
+  Base & operator = (const Base &);
+};
+
+struct Derived : public Base {};
+
+const Base &b = Derived();
+
+int main()
+{
+  return c;  // No copies should be required.
+}