aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2003-03-07 21:19:38 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2003-03-07 21:19:38 +0000
commitaa6e8ed33a18a6185f852b6d07a2168638c7cf39 (patch)
treed541d77effe4c2a0317c197fe33a09d83658f481
parent5040d6912ccf32e1b3baed1e0a2d9dd475bbf853 (diff)
downloadgcc-aa6e8ed33a18a6185f852b6d07a2168638c7cf39.zip
gcc-aa6e8ed33a18a6185f852b6d07a2168638c7cf39.tar.gz
gcc-aa6e8ed33a18a6185f852b6d07a2168638c7cf39.tar.bz2
call.c (reference_binding): Remove REF_IS_VAR parameter.
* 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
-rw-r--r--gcc/cp/ChangeLog14
-rw-r--r--gcc/cp/call.c114
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/cvt.c2
-rw-r--r--gcc/cp/tree.c12
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/init/ref4.C18
7 files changed, 121 insertions, 46 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index afb3436..f11bba8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 15dbbe1..a25da46 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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. */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 447fd57..53a4db6 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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,
...);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index ba5fbba..88e802e 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -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;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 520aa16..94fe9fb 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2a95e09..27c6197 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..6b65d99
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/ref4.C
@@ -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.
+}