aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2001-12-24 20:52:36 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2001-12-24 20:52:36 +0000
commita56ca899555fbc7a33a6f750beb5e82243390523 (patch)
treeb6534364532f0b110ed850c1f6aa4570527c10c8 /gcc
parentfdfc290b947e036ff15e9b221f64d2bcb8c9fabc (diff)
downloadgcc-a56ca899555fbc7a33a6f750beb5e82243390523.zip
gcc-a56ca899555fbc7a33a6f750beb5e82243390523.tar.gz
gcc-a56ca899555fbc7a33a6f750beb5e82243390523.tar.bz2
re PR c++/160 (Reference variables not initialized correctly in constructor initializer list using , operator)
cp: PR c++/160 * typeck.c (build_modify_expr): Remove old unreachable code & tidy up. Don't stabilize_references when initializing a reference. testsuite: * g++.dg/other/init2.C: New test. From-SVN: r48307
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog6
-rw-r--r--gcc/cp/typeck.c202
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/other/init2.C49
4 files changed, 137 insertions, 124 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 6614ddb..529a362 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2001-12-24 Nathan Sidwell <nathan@codesourcery.com>
+
+ PR c++/160
+ * typeck.c (build_modify_expr): Remove old unreachable code & tidy
+ up. Don't stabilize_references when initializing a reference.
+
2001-12-23 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* decl2.c (lang_f_options): Const-ify.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 05c0711..fefa72e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5494,13 +5494,7 @@ build_modify_expr (lhs, modifycode, rhs)
if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
- /* Types that aren't fully specified cannot be used in assignments. */
- lhs = require_complete_type (lhs);
-
- newrhs = rhs;
-
/* Handle control structure constructs used as "lvalues". */
-
switch (TREE_CODE (lhs))
{
/* Handle --foo = 5; as these are valid constructs in C++ */
@@ -5532,13 +5526,14 @@ build_modify_expr (lhs, modifycode, rhs)
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:
- rhs = save_expr (rhs);
{
/* Produce (a ? (b = rhs) : (c = rhs))
except that the RHS goes through a save-expr
so the code to compute it is only emitted once. */
tree cond;
+ rhs = save_expr (rhs);
+
/* Check this here to avoid odd errors when trying to convert
a throw to the type of the COND_EXPR. */
if (!lvalue_or_else (lhs, "assignment"))
@@ -5558,54 +5553,27 @@ build_modify_expr (lhs, modifycode, rhs)
/* Make sure the code to compute the rhs comes out
before the split. */
return build (COMPOUND_EXPR, TREE_TYPE (lhs),
- /* Case to void to suppress warning
+ /* Cast to void to suppress warning
from warn_if_unused_value. */
cp_convert (void_type_node, rhs), cond);
}
-
+
+ case OFFSET_REF:
+ lhs = resolve_offset_ref (lhs);
+ if (lhs == error_mark_node)
+ return error_mark_node;
+ olhstype = lhstype = TREE_TYPE (lhs);
+
default:
break;
}
- if (TREE_CODE (lhs) == OFFSET_REF)
- {
- if (TREE_OPERAND (lhs, 0) == NULL_TREE)
- {
- /* Static class member? */
- tree member = TREE_OPERAND (lhs, 1);
- if (TREE_CODE (member) == VAR_DECL)
- lhs = member;
- else
- {
- compiler_error ("invalid static class member");
- return error_mark_node;
- }
- }
- else
- lhs = resolve_offset_ref (lhs);
-
- olhstype = lhstype = TREE_TYPE (lhs);
- }
-
- if (lhs == error_mark_node)
- return lhs;
-
- if (TREE_CODE (lhstype) == REFERENCE_TYPE
- && modifycode != INIT_EXPR)
- {
- lhs = convert_from_reference (lhs);
- olhstype = lhstype = TREE_TYPE (lhs);
- }
-
- /* If a binary op has been requested, combine the old LHS value with the RHS
- producing the value we should actually store into the LHS. */
-
if (modifycode == INIT_EXPR)
{
if (TREE_CODE (rhs) == CONSTRUCTOR)
{
- if (! same_type_p (TREE_TYPE (rhs), lhstype))
- abort ();
+ my_friendly_assert (same_type_p (TREE_TYPE (rhs), lhstype),
+ 20011220);
result = build (INIT_EXPR, lhstype, lhs, rhs);
TREE_SIDE_EFFECTS (result) = 1;
return result;
@@ -5622,35 +5590,55 @@ build_modify_expr (lhs, modifycode, rhs)
return result;
}
}
- else if (modifycode == NOP_EXPR)
+ else
{
- /* `operator=' is not an inheritable operator. */
- if (! IS_AGGR_TYPE (lhstype))
- /* Do the default thing */;
- else
+ if (TREE_CODE (lhstype) == REFERENCE_TYPE)
{
- result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
- if (result == NULL_TREE)
- return error_mark_node;
- return result;
+ lhs = convert_from_reference (lhs);
+ olhstype = lhstype = TREE_TYPE (lhs);
}
- lhstype = olhstype;
- }
- else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE))
- {
- my_friendly_abort (978652);
- }
- else
- {
- lhs = stabilize_reference (lhs);
- newrhs = cp_build_binary_op (modifycode, lhs, rhs);
- if (newrhs == error_mark_node)
+ lhs = require_complete_type (lhs);
+ if (lhs == error_mark_node)
+ return error_mark_node;
+
+ if (modifycode == NOP_EXPR)
{
- error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
- TREE_TYPE (lhs), TREE_TYPE (rhs));
- return error_mark_node;
+ /* `operator=' is not an inheritable operator. */
+ if (! IS_AGGR_TYPE (lhstype))
+ /* Do the default thing */;
+ else
+ {
+ result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
+ lhs, rhs, make_node (NOP_EXPR));
+ if (result == NULL_TREE)
+ return error_mark_node;
+ return result;
+ }
+ lhstype = olhstype;
+ }
+ else
+ {
+ /* A binary op has been requested. Combine the old LHS
+ value with the RHS producing the value we should actually
+ store into the LHS. */
+
+ my_friendly_assert (!PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE),
+ 978652);
+ lhs = stabilize_reference (lhs);
+ newrhs = cp_build_binary_op (modifycode, lhs, rhs);
+ if (newrhs == error_mark_node)
+ {
+ error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
+ TREE_TYPE (lhs), TREE_TYPE (rhs));
+ return error_mark_node;
+ }
+
+ /* Now it looks like a plain assignment. */
+ modifycode = NOP_EXPR;
}
+ my_friendly_assert (TREE_CODE (lhstype) != REFERENCE_TYPE, 20011220);
+ my_friendly_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE,
+ 20011220);
}
/* Handle a cast used as an "lvalue".
@@ -5669,15 +5657,16 @@ build_modify_expr (lhs, modifycode, rhs)
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
- if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
- || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
- newrhs = default_conversion (newrhs);
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
+ if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
+ || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
+ newrhs = default_conversion (newrhs);
+
/* ISO C++ 5.4/1: The result is an lvalue if T is a reference
type, otherwise the result is an rvalue. */
if (! lvalue_p (lhs))
@@ -5703,23 +5692,23 @@ build_modify_expr (lhs, modifycode, rhs)
GNU_xref_assign (lhs);
- /* Warn about storing in something that is `const'. */
- /* For C++, don't warn if this is initialization. */
+ /* Warn about modifying something that is `const'. Don't warn if
+ this is initialization. */
if (modifycode != INIT_EXPR
&& (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
/* Functions are not modifiable, even though they are
lvalues. */
|| TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
+ /* If it's an aggregate and any field is const, then it is
+ effectively const. */
|| (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
- && C_TYPE_FIELDS_READONLY (lhstype))
- || (TREE_CODE (lhstype) == REFERENCE_TYPE
- && CP_TYPE_CONST_P (TREE_TYPE (lhstype)))))
+ && C_TYPE_FIELDS_READONLY (lhstype))))
readonly_error (lhs, "assignment", 0);
- /* If storing into a structure or union member,
- it has probably been given type `int'.
- Compute the type that would go with
- the actual amount of storage the member occupies. */
+ /* If storing into a structure or union member, it has probably been
+ given type `int'. Compute the type that would go with the actual
+ amount of storage the member occupies. */
if (TREE_CODE (lhs) == COMPONENT_REF
&& (TREE_CODE (lhstype) == INTEGER_TYPE
@@ -5738,40 +5727,14 @@ build_modify_expr (lhs, modifycode, rhs)
}
}
- if (modifycode != INIT_EXPR)
+ if (TREE_CODE (lhstype) != REFERENCE_TYPE)
{
- /* Make modifycode now either a NOP_EXPR or an INIT_EXPR. */
- modifycode = NOP_EXPR;
- /* Reference-bashing */
- if (TREE_CODE (lhstype) == REFERENCE_TYPE)
- {
- tree tmp = convert_from_reference (lhs);
- lhstype = TREE_TYPE (tmp);
- if (!COMPLETE_TYPE_P (lhstype))
- {
- incomplete_type_error (lhs, lhstype);
- return error_mark_node;
- }
- lhs = tmp;
- olhstype = lhstype;
- }
- if (TREE_CODE (TREE_TYPE (newrhs)) == REFERENCE_TYPE)
- {
- tree tmp = convert_from_reference (newrhs);
- if (!COMPLETE_TYPE_P (TREE_TYPE (tmp)))
- {
- incomplete_type_error (newrhs, TREE_TYPE (tmp));
- return error_mark_node;
- }
- newrhs = tmp;
- }
+ if (TREE_SIDE_EFFECTS (lhs))
+ lhs = stabilize_reference (lhs);
+ if (TREE_SIDE_EFFECTS (newrhs))
+ newrhs = stabilize_reference (newrhs);
}
- if (TREE_SIDE_EFFECTS (lhs))
- lhs = stabilize_reference (lhs);
- if (TREE_SIDE_EFFECTS (newrhs))
- newrhs = stabilize_reference (newrhs);
-
/* Convert new value to destination type. */
if (TREE_CODE (lhstype) == ARRAY_TYPE)
@@ -5795,17 +5758,8 @@ build_modify_expr (lhs, modifycode, rhs)
}
if (modifycode == INIT_EXPR)
- {
- newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
- "initialization", NULL_TREE, 0);
- if (current_function_decl &&
- lhs == DECL_RESULT (current_function_decl))
- {
- if (DECL_INITIAL (lhs))
- warning ("return value from function receives multiple initializations");
- DECL_INITIAL (lhs) = newrhs;
- }
- }
+ newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
+ "initialization", NULL_TREE, 0);
else
{
/* Avoid warnings on enum bit fields. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c2bb361..a022e89 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2001-12-24 Nathan Sidwell <nathan@codesourcery.com>
+
+ * g++.dg/other/init2.C: New test.
+
2001-12-24 Richard Henderson <rth@redhat.com>
* gcc.dg/20011223-1.c: New.
diff --git a/gcc/testsuite/g++.dg/other/init2.C b/gcc/testsuite/g++.dg/other/init2.C
new file mode 100644
index 0000000..0b85aa6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/init2.C
@@ -0,0 +1,49 @@
+// { dg-do run }
+
+// Copyright (C) 2001 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 20 Dec 2001 <nathan@nathan@codesourcery.com>
+
+// PR 160. Wrong code emitted for some reference initializers.
+
+void Foo ()
+{
+}
+
+int fail;
+
+class C
+{
+ public:
+ int m;
+ int &r;
+
+ C () ;
+};
+
+C::C ()
+ : m (1), r ((Foo (), m))
+{
+ m = 10;
+
+ if (r != m)
+ fail = 1;
+ else if (&m != &r)
+ fail = 2;
+}
+int main ()
+{
+ int m (1);
+ int &r ((Foo (),m));
+
+ m = 10;
+ if (r != m)
+ fail = 3;
+ else if (&r != &m)
+ fail = 4;
+
+ if (!fail)
+ {
+ C c;
+ }
+ return fail;
+}