]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/27471 (ICE within build_c_cast cp/typeck.c:5434)
authorMark Mitchell <mark@codesourcery.com>
Fri, 19 May 2006 03:01:14 +0000 (03:01 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Fri, 19 May 2006 03:01:14 +0000 (03:01 +0000)
PR c++/27471
PR c++/27506
* typeck.c (decay_conversion): Convert bitfields to their declared
types here.  Improve documentation.  Avoid use of cp_convert.
(default_conversion): Make it static.  Perform integral promotions
before lvalue-to-rvalue, function-to-pointer, and array-to-pointer
conversions.
* init.c (build_init): Remove.
(expand_default_init): Do not call rvalue.
* call.c (null_ptr_cst_p): Robustify.
(build_conditional_expr): Tidy.
* except.c (build_throw): Do not perform lvalue-to-rvalue
conversion on operand before initializing temporary.
* tree.c (convert.h): Include it.
(convert_bitfield_to_declared_type): Use convert_to_integer, not
cp_convert.
(rvalue): Don't convert bitfields to their declared type here.
* cp-tree.h (build_init): Remove.
(default_conversion): Likewise.
* typeck2.c (build_m_component_ref): Do not perform
lvalue-to-rvalue, function-to-pointer, or array-to-pointer
conversions here.  Correct error message.
PR c++/27471
PR c++/27506
* g++.dg/conversion/bitfield5.C: New test.
* g++.dg/conversion/bitfield6.C: New test.

From-SVN: r113902

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/except.c
gcc/cp/init.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/conversion/bitfield5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/conversion/bitfield6.C [new file with mode: 0644]

index 0d990506d028951fce0258b07848cc96068aa4e4..3c13cc00077a0699ef49ceab1af7cda9ae9ccf35 100644 (file)
@@ -1,3 +1,28 @@
+2006-05-18  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/27471
+       PR c++/27506
+       * typeck.c (decay_conversion): Convert bitfields to their declared
+       types here.  Improve documentation.  Avoid use of cp_convert.
+       (default_conversion): Make it static.  Perform integral promotions
+       before lvalue-to-rvalue, function-to-pointer, and array-to-pointer
+       conversions.
+       * init.c (build_init): Remove.
+       (expand_default_init): Do not call rvalue.
+       * call.c (null_ptr_cst_p): Robustify.
+       (build_conditional_expr): Tidy.
+       * except.c (build_throw): Do not perform lvalue-to-rvalue
+       conversion on operand before initializing temporary.
+       * tree.c (convert.h): Include it.
+       (convert_bitfield_to_declared_type): Use convert_to_integer, not
+       cp_convert.
+       (rvalue): Don't convert bitfields to their declared type here.
+       * cp-tree.h (build_init): Remove.
+       (default_conversion): Likewise.
+       * typeck2.c (build_m_component_ref): Do not perform
+       lvalue-to-rvalue, function-to-pointer, or array-to-pointer
+       conversions here.  Correct error message.
+
 2006-05-17  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/26122
index a7cb22aab2f12a7a38b0ec697568e1be42e4ad5e..9e69772954c804572d3c28b1163a59f3c8c7b779 100644 (file)
@@ -426,11 +426,14 @@ null_ptr_cst_p (tree t)
      A null pointer constant is an integral constant expression
      (_expr.const_) rvalue of integer type that evaluates to zero.  */
   t = integral_constant_value (t);
-  if (t == null_node
-      || (CP_INTEGRAL_TYPE_P (TREE_TYPE (t))
-         && integer_zerop (t)
-         && !TREE_CONSTANT_OVERFLOW (t)))
+  if (t == null_node)
     return true;
+  if (CP_INTEGRAL_TYPE_P (TREE_TYPE (t)) && integer_zerop (t))
+    {
+      STRIP_NOPS (t);
+      if (!TREE_CONSTANT_OVERFLOW (t))
+       return true;
+    }
   return false;
 }
 
@@ -3518,16 +3521,18 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3)
   /* We can't use result_type below, as fold might have returned a
      throw_expr.  */
 
-  /* Expand both sides into the same slot, hopefully the target of the
-     ?: expression.  We used to check for TARGET_EXPRs here, but now we
-     sometimes wrap them in NOP_EXPRs so the test would fail.  */
-  if (!lvalue_p && CLASS_TYPE_P (TREE_TYPE (result)))
-    result = get_target_expr (result);
-
-  /* If this expression is an rvalue, but might be mistaken for an
-     lvalue, we must add a NON_LVALUE_EXPR.  */
-  if (!lvalue_p && real_lvalue_p (result))
-    result = rvalue (result);
+  if (!lvalue_p)
+    {
+      /* Expand both sides into the same slot, hopefully the target of
+        the ?: expression.  We used to check for TARGET_EXPRs here,
+        but now we sometimes wrap them in NOP_EXPRs so the test would
+        fail.  */
+      if (CLASS_TYPE_P (TREE_TYPE (result)))
+       result = get_target_expr (result);
+      /* If this expression is an rvalue, but might be mistaken for an
+        lvalue, we must add a NON_LVALUE_EXPR.  */
+      result = rvalue (result);
+    }
 
   return result;
 }
index 38376288ef9af3cac1c5bec23cf0e33eb56b8794..cac801d7514c5e40a10942ccb846c166d909ca28 100644 (file)
@@ -3973,7 +3973,6 @@ extern tree do_friend                             (tree, tree, tree, tree, enum overload_flags, bool);
 extern tree expand_member_init                 (tree);
 extern void emit_mem_initializers              (tree);
 extern tree build_aggr_init                    (tree, tree, int);
-extern tree build_init                         (tree, tree, int);
 extern int is_aggr_type                                (tree, int);
 extern tree get_type_value                     (tree);
 extern tree build_zero_init                    (tree, tree, bool);
@@ -4357,7 +4356,6 @@ extern tree cxx_sizeof_or_alignof_type            (tree, enum tree_code, bool);
 extern tree inline_conversion                  (tree);
 extern tree is_bitfield_expr_with_lowered_type  (tree); 
 extern tree decay_conversion                   (tree);
-extern tree default_conversion                 (tree);
 extern tree build_class_member_access_expr      (tree, tree, tree, bool);
 extern tree finish_class_member_access_expr     (tree, tree, bool);
 extern tree build_x_indirect_ref               (tree, const char *);
index d82c07ff3292beffb7da4da8db3d4ae378baf075..efdbd91e85730c0b0e68b4be27c8ffc5aee36692 100644 (file)
@@ -638,6 +638,7 @@ build_throw (tree exp)
   else if (exp)
     {
       tree throw_type;
+      tree temp_type;
       tree cleanup;
       tree object, ptr;
       tree tmp;
@@ -666,9 +667,17 @@ build_throw (tree exp)
          fn = push_throw_library_fn (fn, tmp);
        }
 
-      /* throw expression */
-      /* First, decay it.  */
-      exp = decay_conversion (exp);
+      /* [except.throw] 
+        
+         A throw-expression initializes a temporary object, the type
+        of which is determined by removing any top-level
+        cv-qualifiers from the static type of the operand of throw
+        and adjusting the type from "array of T" or "function return
+        T" to "pointer to T" or "pointer to function returning T"
+        respectively.  */
+      temp_type = is_bitfield_expr_with_lowered_type (exp);
+      if (!temp_type)
+       temp_type = type_decays_to (TYPE_MAIN_VARIANT (TREE_TYPE (exp)));
 
       /* OK, this is kind of wacky.  The standard says that we call
         terminate when the exception handling mechanism, after
@@ -684,21 +693,32 @@ build_throw (tree exp)
         matter, since it can't throw).  */
 
       /* Allocate the space for the exception.  */
-      allocate_expr = do_allocate_exception (TREE_TYPE (exp));
+      allocate_expr = do_allocate_exception (temp_type);
       allocate_expr = get_target_expr (allocate_expr);
       ptr = TARGET_EXPR_SLOT (allocate_expr);
-      object = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (exp)), ptr);
+      object = build_nop (build_pointer_type (temp_type), ptr);
       object = build_indirect_ref (object, NULL);
 
       elided = (TREE_CODE (exp) == TARGET_EXPR);
 
       /* And initialize the exception object.  */
-      exp = build_init (object, exp, LOOKUP_ONLYCONVERTING);
-      if (exp == error_mark_node)
+      if (CLASS_TYPE_P (temp_type))
        {
-         error ("  in thrown expression");
-         return error_mark_node;
+         /* Call the copy constructor.  */
+         exp = (build_special_member_call 
+                (object, complete_ctor_identifier,
+                 build_tree_list (NULL_TREE, exp),
+                 TREE_TYPE (object),
+                 LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING));
+         if (exp == error_mark_node)
+           {
+             error ("  in thrown expression");
+             return error_mark_node;
+           }
        }
+      else
+       exp = build2 (INIT_EXPR, temp_type, object, 
+                     decay_conversion (exp));
 
       /* Pre-evaluate the thrown expression first, since if we allocated
         the space first we would have to deal with cleaning it up if
index bc6df20457349b4b86cdfd5bd51e9395d346194a..e9528f2aab221f19f0fe1524b78e0843a812e1d1 100644 (file)
@@ -1142,26 +1142,6 @@ build_aggr_init (tree exp, tree init, int flags)
   return stmt_expr;
 }
 
-/* Like build_aggr_init, but not just for aggregates.  */
-
-tree
-build_init (tree decl, tree init, int flags)
-{
-  tree expr;
-
-  if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
-    expr = build_aggr_init (decl, init, flags);
-  else if (CLASS_TYPE_P (TREE_TYPE (decl)))
-    expr = build_special_member_call (decl, complete_ctor_identifier,
-                                     build_tree_list (NULL_TREE, init),
-                                     TREE_TYPE (decl),
-                                     LOOKUP_NORMAL|flags);
-  else
-    expr = build2 (INIT_EXPR, TREE_TYPE (decl), decl, init);
-
-  return expr;
-}
-
 static void
 expand_default_init (tree binfo, tree true_exp, tree exp, tree init, int flags)
 {
@@ -2057,7 +2037,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
   rval = build_nop (pointer_type, rval);
 
   /* A new-expression is never an lvalue.  */
-  rval = rvalue (rval);
+  gcc_assert (!lvalue_p (rval));
 
   return rval;
 }
index bc8e737578934a180c0b103621c74037d7595f71..81b37d615c2ec1107d9e1818a18b6b99a9974110 100644 (file)
@@ -35,6 +35,7 @@ Boston, MA 02110-1301, USA.  */
 #include "tree-inline.h"
 #include "debug.h"
 #include "target.h"
+#include "convert.h"
 
 static tree bot_manip (tree *, int *, void *);
 static tree bot_replace (tree *, int *, void *);
@@ -373,7 +374,8 @@ convert_bitfield_to_declared_type (tree expr)
 
   bitfield_type = is_bitfield_expr_with_lowered_type (expr);
   if (bitfield_type)
-    expr = cp_convert (TYPE_MAIN_VARIANT (bitfield_type), expr);
+    expr = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type),
+                              expr);
   return expr;
 }
 
@@ -383,18 +385,23 @@ convert_bitfield_to_declared_type (tree expr)
 tree
 rvalue (tree expr)
 {
-  expr = convert_bitfield_to_declared_type (expr);
-  if (real_lvalue_p (expr))
-    {
-      tree type;
-      /* [basic.lval]
-        
-         Non-class rvalues always have cv-unqualified types.  */
-      type = TREE_TYPE (expr);
-      if (!CLASS_TYPE_P (type))
-       type = TYPE_MAIN_VARIANT (type);
-      expr = build1 (NON_LVALUE_EXPR, type, expr);
-    }
+  tree type;
+
+  if (error_operand_p (expr))
+    return expr;
+
+  /* [basic.lval]
+
+     Non-class rvalues always have cv-unqualified types.  */
+  type = TREE_TYPE (expr);
+  if (!CLASS_TYPE_P (type) && cp_type_quals (type))
+    type = TYPE_MAIN_VARIANT (type);
+
+  if (!processing_template_decl && real_lvalue_p (expr))
+    expr = build1 (NON_LVALUE_EXPR, type, expr);
+  else if (type != TREE_TYPE (expr))
+    expr = build_nop (type, expr);
+
   return expr;
 }
 
index 3eeb8375f1e380a0bf3b3d4ea58c64df74ca1baf..e275f76a20f29ac1624623d4a368b4c8f17e5ece 100644 (file)
@@ -1426,10 +1426,14 @@ is_bitfield_expr_with_lowered_type (tree exp)
 
 /* Perform the conversions in [expr] that apply when an lvalue appears
    in an rvalue context: the lvalue-to-rvalue, array-to-pointer, and
-   function-to-pointer conversions.
+   function-to-pointer conversions.  In addition, manifest constants
+   are replaced by their values, and bitfield references are converted
+   to their declared types.
 
-   In addition, manifest constants are replaced by their values, and
-   bitfield references are converted to their declared types.  */
+   Although the returned value is being used as an rvalue, this
+   function does not wrap the returned expression in a
+   NON_LVALUE_EXPR; the caller is expected to be mindful of the fact
+   that the return value is no longer an lvalue.  */
 
 tree
 decay_conversion (tree exp)
@@ -1448,6 +1452,8 @@ decay_conversion (tree exp)
     }
 
   exp = decl_constant_value (exp);
+  if (error_operand_p (exp))
+    return error_mark_node;
 
   /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
      Leave such NOP_EXPRs, since RHS is being used in non-lvalue context.  */
@@ -1498,22 +1504,52 @@ decay_conversion (tree exp)
       adr = build_unary_op (ADDR_EXPR, exp, 1);
       return cp_convert (ptrtype, adr);
     }
+  
+  /* If a bitfield is used in a context where integral promotion
+     applies, then the caller is expected to have used
+     default_conversion.  That function promotes bitfields correctly
+     before calling this function.  At this point, if we have a
+     bitfield referenced, we may assume that is not subject to
+     promotion, and that, therefore, the type of the resulting rvalue
+     is the declared type of the bitfield.  */
+  exp = convert_bitfield_to_declared_type (exp);
 
-  /* [basic.lval]: Class rvalues can have cv-qualified types; non-class
-     rvalues always have cv-unqualified types.  */
-  if (! CLASS_TYPE_P (type))
-    exp = cp_convert (TYPE_MAIN_VARIANT (type), exp);
+  /* We do not call rvalue() here because we do not want to wrap EXP
+     in a NON_LVALUE_EXPR.  */
+
+  /* [basic.lval]
+
+     Non-class rvalues always have cv-unqualified types.  */
+  type = TREE_TYPE (exp);
+  if (!CLASS_TYPE_P (type) && cp_type_quals (type))
+    exp = build_nop (TYPE_MAIN_VARIANT (type), exp);
 
   return exp;
 }
 
-tree
+/* Perform prepatory conversions, as part of the "usual arithmetic
+   conversions".  In particular, as per [expr]:
+
+     Whenever an lvalue expression appears as an operand of an
+     operator that expects the rvalue for that operand, the
+     lvalue-to-rvalue, array-to-pointer, or function-to-pointer
+     standard conversions are applied to convert the expression to an
+     rvalue.
+
+   In addition, we perform integral promotions here, as those are
+   applied to both operands to a binary operator before determining
+   what additional conversions should apply.  */
+
+static tree
 default_conversion (tree exp)
 {
-  exp = decay_conversion (exp);
-
+  /* Perform the integral promotions first so that bitfield
+     expressions (which may promote to "int", even if the bitfield is
+     declared "unsigned") are promoted correctly.  */  
   if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (exp)))
     exp = perform_integral_promotions (exp);
+  /* Perform the other conversions.  */
+  exp = decay_conversion (exp);
 
   return exp;
 }
index 52d7a9e69fa6163ffc224a3591c730727a26e31a..5356faa25fa0f1c6b5a61236743288d6c3ebb41f 100644 (file)
@@ -1200,8 +1200,6 @@ build_m_component_ref (tree datum, tree component)
   tree binfo;
   tree ctype;
 
-  datum = decay_conversion (datum);
-
   if (datum == error_mark_node || component == error_mark_node)
     return error_mark_node;
 
@@ -1218,7 +1216,7 @@ build_m_component_ref (tree datum, tree component)
   if (! IS_AGGR_TYPE (objtype))
     {
       error ("cannot apply member pointer %qE to %qE, which is of "
-            "non-aggregate type %qT",
+            "non-class type %qT",
             component, datum, objtype);
       return error_mark_node;
     }
index 8f57ec3879d3abaf6948ca284869bec47dfb50b4..540995b97c5c569b9591876b638c0a03945c0f44 100644 (file)
@@ -1,3 +1,10 @@
+2006-05-18  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/27471
+       PR c++/27506
+       * g++.dg/conversion/bitfield5.C: New test.
+       * g++.dg/conversion/bitfield6.C: New test.
+
 2006-05-18  Mike Stump  <mrs@apple.com>
 
        * gcc.dg/c90-arraydecl-1.c: Update for vla, vm [*] fixups.
diff --git a/gcc/testsuite/g++.dg/conversion/bitfield5.C b/gcc/testsuite/g++.dg/conversion/bitfield5.C
new file mode 100644 (file)
index 0000000..b931ec9
--- /dev/null
@@ -0,0 +1,14 @@
+// PR c++/27506
+
+enum EBorderStyle
+  {
+    BNATIVE, BHIDDEN
+  };
+struct BorderValue
+{
+  enum EBorderStyle style:8;
+};
+enum EBorderStyle f(const struct BorderValue *border)
+{
+  return border ?  border->style : BNATIVE;
+}
diff --git a/gcc/testsuite/g++.dg/conversion/bitfield6.C b/gcc/testsuite/g++.dg/conversion/bitfield6.C
new file mode 100644 (file)
index 0000000..79664ab
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/27471
+
+struct A { unsigned a:8; };
+
+extern void b(unsigned char);
+
+void breakme (A f)
+{
+  b((unsigned char) f.a);
+}