* C++ PATCH: Yet another whack at references
@ 2003-03-07 21:20 Mark Mitchell
2003-03-07 23:03 ` Michael Matz
0 siblings, 1 reply; 4+ messages in thread
From: Mark Mitchell @ 2003-03-07 21:20 UTC (permalink / raw)
To: gcc-patches
This reference mole is taking a lot of whacks.
Anyhow, here's another go, fixing the extra copy problem Jason
discovered yesterday.
Tested on i686-pc-linux-gnu, applied on the mainline and on the
branch.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
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 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.
2003-03-07 Mark Mitchell <mark@codesourcery.com>
* g++.dg/init/ref4.C: New test.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.362
diff -c -5 -p -r1.362 call.c
*** cp/call.c 7 Mar 2003 07:02:00 -0000 1.362
--- cp/call.c 7 Mar 2003 21:17:47 -0000
*************** static struct z_candidate *add_conv_cand
*** 83,93 ****
(struct z_candidate **, tree, tree, tree, tree, tree);
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 non_reference (tree);
static tree build_conv (enum tree_code, tree, tree);
static bool is_subseq (tree, tree);
static tree maybe_handle_ref_bind (tree *);
static void maybe_handle_implicit_object (tree *);
--- 83,93 ----
(struct z_candidate **, tree, tree, tree, tree, tree);
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);
static tree non_reference (tree);
static tree build_conv (enum tree_code, tree, tree);
static bool is_subseq (tree, tree);
static tree maybe_handle_ref_bind (tree *);
static void maybe_handle_implicit_object (tree *);
*************** direct_reference_binding (tree type, tre
*** 1131,1146 ****
/* Returns the conversion path from type FROM to reference type TO for
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). */
static tree
! reference_binding (tree rto, tree rfrom, tree expr, int flags,
! bool ref_is_var)
{
tree conv = NULL_TREE;
tree to = TREE_TYPE (rto);
tree from = rfrom;
bool related_p;
--- 1131,1144 ----
/* Returns the conversion path from type FROM to reference type TO for
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. */
static tree
! reference_binding (tree rto, tree rfrom, tree expr, int flags)
{
tree conv = NULL_TREE;
tree to = TREE_TYPE (rto);
tree from = rfrom;
bool related_p;
*************** reference_binding (tree rto, tree rfrom,
*** 1248,1273 ****
is bound in one of the following ways:
-- 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)
{
conv = build1 (IDENTITY_CONV, from, expr);
return direct_reference_binding (rto, conv);
}
--- 1246,1263 ----
is bound in one of the following ways:
-- The reference is bound to the object represented by the rvalue
or to a sub-object within that object.
! -- ...
! 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);
}
*************** implicit_conversion (tree to, tree from,
*** 1319,1329 ****
user-defined conversions are available. */
complete_type (from);
complete_type (to);
if (TREE_CODE (to) == REFERENCE_TYPE)
! conv = reference_binding (to, from, expr, flags, /*ref_is_var=*/false);
else
conv = standard_conversion (to, from, expr);
if (conv)
return conv;
--- 1309,1319 ----
user-defined conversions are available. */
complete_type (from);
complete_type (to);
if (TREE_CODE (to) == REFERENCE_TYPE)
! conv = reference_binding (to, from, expr, flags);
else
conv = standard_conversion (to, from, expr);
if (conv)
return conv;
*************** perform_implicit_conversion (tree type,
*** 5847,5869 ****
return convert_like (conv, 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. */
tree
! make_temporary_var_for_ref_to_temp (tree decl)
{
- 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;
TREE_USED (var) = 1;
--- 5837,5854 ----
return convert_like (conv, 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
! 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, tree type)
{
tree var;
/* Create the variable. */
var = build_decl (VAR_DECL, NULL_TREE, type);
DECL_ARTIFICIAL (var) = 1;
TREE_USED (var) = 1;
*************** initialize_reference (tree type, tree ex
*** 5903,5914 ****
tree conv;
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);
if (!conv || ICS_BAD_FLAG (conv))
{
error ("could not convert `%E' to `%T'", expr, type);
return error_mark_node;
}
--- 5888,5898 ----
tree conv;
if (type == error_mark_node || error_operand_p (expr))
return error_mark_node;
! 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);
return error_mark_node;
}
*************** initialize_reference (tree type, tree ex
*** 5916,5950 ****
/* If DECL is non-NULL, then this special rule applies:
[class.temporary]
The temporary to which the reference is bound or the temporary
! that is the complete object to which the temporary is bound
persists for the lifetime of the reference.
The temporaries created during the evaluation of the expression
initializing the reference, except the temporary to which the
reference is bound, are destroyed at the end of the
full-expression in which they are created.
In that case, we store the converted expression into a new
! VAR_DECL in a new scope. */
my_friendly_assert (TREE_CODE (conv) == REF_BIND, 20030302);
! if (decl && NEED_TEMPORARY_P (conv))
{
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);
! /* Use its address to initialize the reference variable. */
! return build_nop (type, build_address (var));
}
/* Perform the conversion. */
return convert_like (conv, expr);
}
--- 5900,5976 ----
/* If DECL is non-NULL, then this special rule applies:
[class.temporary]
The temporary to which the reference is bound or the temporary
! 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
initializing the reference, except the temporary to which the
reference is bound, are destroyed at the end of the
full-expression in which they are created.
In that case, we store the converted expression into a new
! 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)
{
tree var;
! tree base_conv_type;
! /* 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. */
return convert_like (conv, expr);
}
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.818
diff -c -5 -p -r1.818 cp-tree.h
*** cp/cp-tree.h 4 Mar 2003 23:23:16 -0000 1.818
--- cp/cp-tree.h 7 Mar 2003 21:17:48 -0000
*************** extern tree cxx_type_promotes_to (tree);
*** 3579,3589 ****
extern tree type_passed_as (tree);
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 strip_top_quals (tree);
extern tree perform_implicit_conversion (tree, tree);
extern tree in_charge_arg_for_name (tree);
/* in class.c */
--- 3579,3589 ----
extern tree type_passed_as (tree);
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, tree);
extern tree strip_top_quals (tree);
extern tree perform_implicit_conversion (tree, tree);
extern tree in_charge_arg_for_name (tree);
/* in class.c */
*************** extern int zero_init_p (tree);
*** 4224,4233 ****
--- 4224,4234 ----
extern tree canonical_type_variant (tree);
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,
...);
extern tree build_min_nt (enum tree_code, ...);
extern tree build_cplus_new (tree, tree);
Index: cp/cvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v
retrieving revision 1.133
diff -c -5 -p -r1.133 cvt.c
*** cp/cvt.c 3 Mar 2003 21:55:22 -0000 1.133
--- cp/cvt.c 7 Mar 2003 21:17:48 -0000
*************** build_up_reference (tree type, tree arg,
*** 356,366 ****
{
/* Create a new temporary variable. We can't just use a TARGET_EXPR
here because it needs to live as long as DECL. */
tree targ = arg;
! arg = make_temporary_var_for_ref_to_temp (decl);
/* Process the initializer for the declaration. */
DECL_INITIAL (arg) = targ;
cp_finish_decl (arg, targ, NULL_TREE,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
--- 356,366 ----
{
/* Create a new temporary variable. We can't just use a TARGET_EXPR
here because it needs to live as long as DECL. */
tree targ = arg;
! arg = make_temporary_var_for_ref_to_temp (decl, TREE_TYPE (arg));
/* Process the initializer for the declaration. */
DECL_INITIAL (arg) = targ;
cp_finish_decl (arg, targ, NULL_TREE,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.318
diff -c -5 -p -r1.318 tree.c
*** cp/tree.c 20 Feb 2003 17:51:43 -0000 1.318
--- cp/tree.c 7 Mar 2003 21:17:48 -0000
*************** real_lvalue_p (ref)
*** 210,219 ****
--- 210,231 ----
tree 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. */
int
lvalue_p (ref)
Index: testsuite/g++.dg/init/ref4.C
===================================================================
RCS file: testsuite/g++.dg/init/ref4.C
diff -N testsuite/g++.dg/init/ref4.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/ref4.C 7 Mar 2003 21:17:51 -0000
***************
*** 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.
+ }
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: C++ PATCH: Yet another whack at references
2003-03-07 21:20 C++ PATCH: Yet another whack at references Mark Mitchell
@ 2003-03-07 23:03 ` Michael Matz
2003-03-08 8:45 ` Mark Mitchell
0 siblings, 1 reply; 4+ messages in thread
From: Michael Matz @ 2003-03-07 23:03 UTC (permalink / raw)
To: Mark Mitchell; +Cc: gcc-patches
Hi,
On Fri, 7 Mar 2003, Mark Mitchell wrote:
> Anyhow, here's another go, fixing the extra copy problem Jason
> discovered yesterday.
Cool. This also fixes the testcase with the abstract base I posted. Many
thanks. I noticed just one thing in the actual committed state of the 3.3
branch, namely the ChangeLog entry (I only saw it because I manyally
copied it to a different version of GCC ;) ), which there looks like:
* 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 (
Note the apparent cut-off at the last line.
Ciao,
Michael.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: C++ PATCH: Yet another whack at references
2003-03-07 23:03 ` Michael Matz
@ 2003-03-08 8:45 ` Mark Mitchell
2003-03-13 16:28 ` Michael Matz
0 siblings, 1 reply; 4+ messages in thread
From: Mark Mitchell @ 2003-03-08 8:45 UTC (permalink / raw)
To: Michael Matz; +Cc: gcc-patches
--On Saturday, March 08, 2003 12:03:37 AM +0100 Michael Matz <matz@suse.de>
wrote:
> * tree.c (
>
> Note the apparent cut-off at the last line.
Grr. Fixed in CVS.
Thanks,
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: C++ PATCH: Yet another whack at references
2003-03-08 8:45 ` Mark Mitchell
@ 2003-03-13 16:28 ` Michael Matz
0 siblings, 0 replies; 4+ messages in thread
From: Michael Matz @ 2003-03-13 16:28 UTC (permalink / raw)
To: Mark Mitchell; +Cc: gcc-patches
Hi Mark,
On Fri, 7 Mar 2003, Mark Mitchell wrote:
> --On Saturday, March 08, 2003 12:03:37 AM +0100 Michael Matz <matz@suse.de>
> wrote:
>
> > * tree.c (
> >
> > Note the apparent cut-off at the last line.
>
> Grr. Fixed in CVS.
Sorry, to be a pain in the ass ;), but the reference stuff is still not
completely right. The above patch, which indeed fixed some cases breaks
another one, namely this:
------- snip --------
struct A { };
struct B : public A { };
struct X {
operator B();
};
X x;
int main()
{
const A& r = x;
return 0;
}
------- snap --------
In HEAD and 3.3 branch this currently gives:
bla.cc:10: internal compiler error: in initialize_reference, at
cp/call.c:6093
If going back to just before your patch went in, it compiles.
Ciao,
Michael.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2003-03-13 16:15 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-03-07 21:20 C++ PATCH: Yet another whack at references Mark Mitchell
2003-03-07 23:03 ` Michael Matz
2003-03-08 8:45 ` Mark Mitchell
2003-03-13 16:28 ` Michael Matz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).