]> gcc.gnu.org Git - gcc.git/commitdiff
re PR c++/160 (Reference variables not initialized correctly in constructor initializ...
authorNathan Sidwell <nathan@codesourcery.com>
Mon, 24 Dec 2001 20:52:36 +0000 (20:52 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Mon, 24 Dec 2001 20:52:36 +0000 (20:52 +0000)
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

gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/other/init2.C [new file with mode: 0644]

index 6614ddb74fd1e1af75c881712f2d6bd815b78d4f..529a36243d73f7f7cf775b6c21160906d928505c 100644 (file)
@@ -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.
index 05c0711ec14eb7984c3c6761f8e967e9afe06298..fefa72e1c419d2622d0da3f2587aa83605a4a5a3 100644 (file)
@@ -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.  */
index c2bb361570d8c3050b056fc12f06baa822f00e12..a022e893476209f15834752bb38b57e9cb7c67e5 100644 (file)
@@ -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 (file)
index 0000000..0b85aa6
--- /dev/null
@@ -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;
+}
This page took 0.101183 seconds and 5 git commands to generate.