diff options
author | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-12-24 20:52:36 +0000 |
---|---|---|
committer | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-12-24 20:52:36 +0000 |
commit | e6d125f72018442cefe6356446c5714fa3f1fac6 (patch) | |
tree | b6534364532f0b110ed850c1f6aa4570527c10c8 | |
parent | b6477ce7aee5ec74ff24124265f1ae4d4579f2ed (diff) | |
download | gcc-e6d125f72018442cefe6356446c5714fa3f1fac6.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@48307 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 202 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/other/init2.C | 49 |
4 files changed, 137 insertions, 124 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6614ddb74fd..529a36243d7 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 05c0711ec14..fefa72e1c41 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 c2bb361570d..a022e893476 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 00000000000..0b85aa67d0a --- /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; +} |