]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/11431 (static_cast behavior with subclasses when default constructor available)
authorMark Mitchell <mark@codesourcery.com>
Sun, 6 Jul 2003 03:30:57 +0000 (03:30 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Sun, 6 Jul 2003 03:30:57 +0000 (03:30 +0000)
PR c++/11431
* typeck.c (build_static_cast): Check for reference conversions
earlier.

* cp-tree.h (perform_integral_promotions): Declare.
* call.c (build_addr_func): Use decay_conversion.
(convert_arg_to_ellipsis): Likewise.  Remove misleading comment.
(convert_for_arg_passing): Use perform_integral_promotions.
* cvt.c (build_expr_type_conversion): Use decay_conversion.
(type_promotes_to): Do not return a cv-qualified type.
* decl.c (grok_reference_init): Fix formatting.
(get_atexit_node): Use decay_conversion.
(build_enumerator): Use perform_integral_promotions.
* init.c (build_vec_init): Use decay_conversion.
* semantics.c (finish_expr_stmt): Likewise.
(finish_switch_cond): Use perform_integral_promotions.
* typeck.c (default_conversion): Likewise.
(perform_integral_promotions): New function.
(build_indirect_ref): Use decay_conversion.
(build_array_ref): Use perform_integral_promotions.
(convert_arguments): Use decay_conversion.
(build_unary_op): Use perform_integral_promotions.
(build_c_cast): Use decay_conversion.
(build_modify_expr): Likewise.
(convert_for_initialization): Likewise.
* typeck2.c (build_x_arrow): Likewise.

* g++.old-deja/g++.jason/typeid1.C: Make it a compile test, not a
run test.

PR c++/11431
* g++.dg/expr/static_cast3.C: New test.

From-SVN: r68989

12 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/expr/static_cast3.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.jason/typeid1.C

index 768fe65154f0cac9271a8fb4c5a7023a62e65ef8..62d989d89a8399835aa5753034b4c6d7a0ebac1b 100644 (file)
@@ -1,3 +1,34 @@
+2003-07-05  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/11431
+       * typeck.c (build_static_cast): Check for reference conversions
+       earlier.
+
+2003-07-04  Mark Mitchell  <mark@codesourcery.com>
+
+       * cp-tree.h (perform_integral_promotions): Declare.
+       * call.c (build_addr_func): Use decay_conversion.
+       (convert_arg_to_ellipsis): Likewise.  Remove misleading comment.
+       (convert_for_arg_passing): Use perform_integral_promotions.
+       * cvt.c (build_expr_type_conversion): Use decay_conversion.
+       (type_promotes_to): Do not return a cv-qualified type.
+       * decl.c (grok_reference_init): Fix formatting.
+       (get_atexit_node): Use decay_conversion.
+       (build_enumerator): Use perform_integral_promotions.
+       * init.c (build_vec_init): Use decay_conversion.
+       * semantics.c (finish_expr_stmt): Likewise.
+       (finish_switch_cond): Use perform_integral_promotions.
+       * typeck.c (default_conversion): Likewise.
+       (perform_integral_promotions): New function.
+       (build_indirect_ref): Use decay_conversion.
+       (build_array_ref): Use perform_integral_promotions.
+       (convert_arguments): Use decay_conversion.
+       (build_unary_op): Use perform_integral_promotions.
+       (build_c_cast): Use decay_conversion.
+       (build_modify_expr): Likewise.
+       (convert_for_initialization): Likewise.
+       * typeck2.c (build_x_arrow): Likewise.
+
 2003-07-04  Kazu Hirata  <kazu@cs.umass.edu>
 
        * call.c: Fix comment typos.
index 2ae13193afb5ab06de2113723636f42083ff9d0b..0832df70f920f13b627d22a7d8b3d984d6356946 100644 (file)
@@ -326,7 +326,7 @@ build_addr_func (tree function)
       function = build_address (function);
     }
   else
-    function = default_conversion (function);
+    function = decay_conversion (function);
 
   return function;
 }
@@ -4339,20 +4339,29 @@ call_builtin_trap (void)
 }
 
 /* ARG is being passed to a varargs function.  Perform any conversions
-   required.  Array/function to pointer decay must have already happened.
-   Return the converted value.  */
+   required.  Return the converted value.  */
 
 tree
 convert_arg_to_ellipsis (tree arg)
 {
+  /* [expr.call]
+
+     The lvalue-to-rvalue, array-to-pointer, and function-to-pointer
+     standard conversions are performed.  */
+  arg = decay_conversion (arg);
+  /* [expr.call]
+
+     If the argument has integral or enumeration type that is subject
+     to the integral promotions (_conv.prom_), or a floating point
+     type that is subject to the floating point promotion
+     (_conv.fpprom_), the value of the argument is converted to the
+     promoted type before the call.  */
   if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE
       && (TYPE_PRECISION (TREE_TYPE (arg))
          < TYPE_PRECISION (double_type_node)))
-    /* Convert `float' to `double'.  */
     arg = cp_convert (double_type_node, arg);
-  else
-    /* Convert `short' and `char' to full-size `int'.  */
-    arg = default_conversion (arg);
+  else if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg)))
+    arg = perform_integral_promotions (arg);
 
   arg = require_complete_type (arg);
   
@@ -4487,7 +4496,7 @@ convert_for_arg_passing (tree type, tree val)
   else if (PROMOTE_PROTOTYPES
           && INTEGRAL_TYPE_P (type)
           && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-    val = default_conversion (val);
+    val = perform_integral_promotions (val);
   return val;
 }
 
index a8955f8e269a056923b376df8e9460236d2526b4..f58f8be2902607854dfbcf969fc51ebf0250c0b0 100644 (file)
@@ -4255,6 +4255,7 @@ extern tree cxx_sizeof_or_alignof_type    (tree, enum tree_code, int);
 #define cxx_sizeof_nowarn(T) cxx_sizeof_or_alignof_type (T, SIZEOF_EXPR, false)
 extern tree inline_conversion                  (tree);
 extern tree decay_conversion                   (tree);
+extern tree perform_integral_promotions         (tree);
 extern tree build_class_member_access_expr      (tree, tree, tree, bool);
 extern tree finish_class_member_access_expr     (tree, tree);
 extern tree build_x_indirect_ref               (tree, const char *);
index 008ff4bf980ca1354ade28dff53aa602c06749b0..081d3b8caca9dd6f53915df7751d8701cfc311d6 100644 (file)
@@ -1056,7 +1056,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
        
       case FUNCTION_TYPE:
       case ARRAY_TYPE:
-       return (desires & WANT_POINTER) ? default_conversion (expr)
+       return (desires & WANT_POINTER) ? decay_conversion (expr)
                                        : NULL_TREE;
       default:
        return NULL_TREE;
@@ -1131,12 +1131,9 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
 tree
 type_promotes_to (tree type)
 {
-  int type_quals;
-
   if (type == error_mark_node)
     return error_mark_node;
 
-  type_quals = cp_type_quals (type);
   type = TYPE_MAIN_VARIANT (type);
 
   /* bool always promotes to int (not unsigned), even if it's the same
@@ -1169,8 +1166,8 @@ type_promotes_to (tree type)
     }
   else if (type == float_type_node)
     type = double_type_node;
-
-  return cp_build_qualified_type (type, type_quals);
+    
+  return type;
 }
 
 /* The routines below this point are carefully written to conform to
index 9b1cdee9dd9c8e02a7fca87cb72384e172e2538a..e44153e4462cbf638de373a6926e0ad544d60693 100644 (file)
@@ -7213,10 +7213,8 @@ grok_reference_init (tree decl, tree type, tree init)
 
   if (TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE
       && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE)
-    {
-      /* Note: default conversion is only called in very special cases.  */
-      init = default_conversion (init);
-    }
+    /* Note: default conversion is only called in very special cases.  */
+    init = decay_conversion (init);
 
   /* Convert INIT to the reference type TYPE.  This may involve the
      creation of a temporary, whose lifetime must be the same as that
@@ -8356,7 +8354,7 @@ get_atexit_node (void)
   atexit_fndecl = build_library_fn_ptr (name, fn_type);
   mark_used (atexit_fndecl);
   pop_lang_context ();
-  atexit_node = default_conversion (atexit_fndecl);
+  atexit_node = decay_conversion (atexit_fndecl);
 
   return atexit_node;
 }
@@ -13180,7 +13178,7 @@ build_enumerator (tree name, tree value, tree enumtype)
 
          if (TREE_CODE (value) == INTEGER_CST)
            {
-             value = default_conversion (value);
+             value = perform_integral_promotions (value);
              constant_expression_warning (value);
            }
          else
index 3d4d81bc329aea827e863c04f893f4dd6399e8fa..18a4dcf988ea80586dbffa2f3b2bb3a3b82a512c 100644 (file)
@@ -2656,7 +2656,7 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
   ptype = build_pointer_type (type);
   size = size_in_bytes (type);
   if (TREE_CODE (TREE_TYPE (base)) == ARRAY_TYPE)
-    base = cp_convert (ptype, default_conversion (base));
+    base = cp_convert (ptype, decay_conversion (base));
 
   /* The code we are generating looks like:
 
@@ -2739,7 +2739,7 @@ build_vec_init (tree base, tree maxindex, tree init, int from_array)
         checking.  */ 
       if (init)
        {
-         base2 = default_conversion (init);
+         base2 = decay_conversion (init);
          itype = TREE_TYPE (base2);
          base2 = get_temp_regvar (itype, base2);
          itype = TREE_TYPE (itype);
index b7b5d853102aa9302e67ffc630833dac2d12d0c0..d89aa5af3467861ef217efc8c8c25be196da738e 100644 (file)
@@ -425,7 +425,7 @@ finish_expr_stmt (tree expr)
          && ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
               && lvalue_p (expr))
              || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE))
-       expr = default_conversion (expr);
+       expr = decay_conversion (expr);
       
       /* Remember the type of the expression.  */
       expr_type = TREE_TYPE (expr);
@@ -748,7 +748,10 @@ finish_switch_cond (tree cond, tree switch_stmt)
       orig_type = TREE_TYPE (cond);
       if (cond != error_mark_node)
        {
-         cond = default_conversion (cond);
+         /* [stmt.switch]
+
+            Integral promotions are performed.  */
+         cond = perform_integral_promotions (cond);
          cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
        }
 
index cd3bc10ea85e4d2bebb4d0de703650602412bb24..eef1781a1383a942603b57d45e9a6d89e9c7927d 100644 (file)
@@ -1483,11 +1483,11 @@ expr_sizeof (tree e)
 }
   
 \f
-/* Perform the array-to-pointer and function-to-pointer conversions
-   for 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.
 
-   In addition, references are converted to lvalues and manifest
-   constants are replaced by their values.  */
+   In addition manifest constants are replaced by their values.  */
 
 tree
 decay_conversion (tree exp)
@@ -1609,24 +1609,32 @@ decay_conversion (tree exp)
 tree
 default_conversion (tree exp)
 {
-  tree type;
-  enum tree_code code;
-
   exp = decay_conversion (exp);
 
-  type = TREE_TYPE (exp);
-  code = TREE_CODE (type);
-
-  if (INTEGRAL_CODE_P (code))
-    {
-      tree t = type_promotes_to (type);
-      if (t != type)
-       return cp_convert (t, exp);
-    }
+  if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (exp)))
+    exp = perform_integral_promotions (exp);
 
   return exp;
 }
 
+/* EXPR is an expression with an integral or enumeration type.
+   Perform the integral promotions in [conv.prom], and return the
+   converted value.  */
+
+tree
+perform_integral_promotions (tree expr)
+{
+  tree type;
+  tree promoted_type;
+
+  type = TREE_TYPE (expr);
+  my_friendly_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type), 20030703);
+  promoted_type = type_promotes_to (type);
+  if (type != promoted_type)
+    expr = cp_convert (promoted_type, expr);
+  return expr;
+}
+
 /* Take the address of an inline function without setting TREE_ADDRESSABLE
    or TREE_USED.  */
 
@@ -2232,7 +2240,7 @@ build_indirect_ref (ptr, errorstring)
     return current_class_ref;
 
   pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
-            ? ptr : default_conversion (ptr));
+            ? ptr : decay_conversion (ptr));
   type = TREE_TYPE (pointer);
 
   if (TYPE_PTR_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
@@ -2350,15 +2358,19 @@ build_array_ref (array, idx)
          && TYPE_MAIN_VARIANT (TREE_TYPE (idx)) == char_type_node)
        warning ("array subscript has type `char'");
 
-      /* Apply default promotions *after* noticing character types.  */
-      idx = default_conversion (idx);
-
-      if (TREE_CODE (TREE_TYPE (idx)) != INTEGER_TYPE)
+      if (!INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (idx)))
        {
          error ("array subscript is not an integer");
          return error_mark_node;
        }
 
+      /* Apply integral promotions *after* noticing character types.
+        (It is unclear why we do these promotions -- the standard
+        does not say that we should.  In fact, the natual thing would
+        seem to be to convert IDX to ptrdiff_t; we're performing
+        pointer arithmetic.)  */
+      idx = perform_integral_promotions (idx);
+
       /* An array that is indexed by a non-constant
         cannot be stored in a register; we must be able to do
         address arithmetic on its address.
@@ -2742,7 +2754,7 @@ convert_arguments (typelist, values, fndecl, flags)
          if (TREE_CODE (TREE_TYPE (val)) == ARRAY_TYPE
              || TREE_CODE (TREE_TYPE (val)) == FUNCTION_TYPE
              || TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
-           val = default_conversion (val);
+           val = decay_conversion (val);
        }
 
       if (val == error_mark_node)
@@ -4039,8 +4051,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
     case NEGATE_EXPR:
       if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, true)))
        errstring = "wrong type argument to unary minus";
-      else if (!noconvert)
-       arg = default_conversion (arg);
+      else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+       arg = perform_integral_promotions (arg);
       break;
 
     case BIT_NOT_EXPR:
@@ -4054,7 +4066,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
                                                   arg, true)))
        errstring = "wrong type argument to bit-complement";
       else if (!noconvert)
-       arg = default_conversion (arg);
+       arg = perform_integral_promotions (arg);
       break;
 
     case ABS_EXPR:
@@ -4778,22 +4790,6 @@ build_static_cast (tree type, tree expr)
 
   intype = TREE_TYPE (expr);
 
-  /* [expr.static.cast]
-
-     An expression e can be explicitly converted to a type T using a
-     static_cast of the form static_cast<T>(e) if the declaration T
-     t(e);" is well-formed, for some invented temporary variable
-     t.  */
-  result = perform_direct_initialization_if_possible (type, expr);
-  if (result)
-    return convert_from_reference (result);
-  
-  /* [expr.static.cast]
-
-     Any expression can be explicitly converted to type cv void.  */
-  if (TREE_CODE (type) == VOID_TYPE)
-    return convert_to_void (expr, /*implicit=*/NULL);
-
   /* [expr.static.cast]
 
      An lvalue of type "cv1 B", where B is a class type, can be cast
@@ -4802,6 +4798,17 @@ build_static_cast (tree type, tree expr)
      "pointer to D" to "pointer to B" exists (_conv.ptr_), cv2 is the
      same cv-qualification as, or greater cv-qualification than, cv1,
      and B is not a virtual base class of D.  */
+  /* We check this case before checking the validity of "TYPE t =
+     EXPR;" below because for this case:
+
+       struct B {};
+       struct D : public B { D(const B&); };
+       extern B& b;
+       void f() { static_cast<const D&>(b); }
+
+     we want to avoid constructing a new D.  The standard is not
+     completely clear about this issue, but our interpretation is
+     consistent with other compilers.  */
   if (TREE_CODE (type) == REFERENCE_TYPE
       && CLASS_TYPE_P (TREE_TYPE (type))
       && CLASS_TYPE_P (intype)
@@ -4825,6 +4832,22 @@ build_static_cast (tree type, tree expr)
       return convert_from_reference (build_nop (type, expr));
     }
 
+  /* [expr.static.cast]
+
+     An expression e can be explicitly converted to a type T using a
+     static_cast of the form static_cast<T>(e) if the declaration T
+     t(e);" is well-formed, for some invented temporary variable
+     t.  */
+  result = perform_direct_initialization_if_possible (type, expr);
+  if (result)
+    return convert_from_reference (result);
+  
+  /* [expr.static.cast]
+
+     Any expression can be explicitly converted to type cv void.  */
+  if (TREE_CODE (type) == VOID_TYPE)
+    return convert_to_void (expr, /*implicit=*/NULL);
+
   /* [expr.static.cast]
 
      The inverse of any standard conversion sequence (clause _conv_),
@@ -5158,7 +5181,7 @@ build_c_cast (tree type, tree expr)
                    && bound_pmf_p (value)))
          || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
          || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
-       value = default_conversion (value);
+       value = decay_conversion (value);
     }
   else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
     /* However, even for class types, we still need to strip away
@@ -5422,7 +5445,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
            || 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);
+         newrhs = decay_conversion (newrhs);
        
        /* ISO C++ 5.4/1: The result is an lvalue if T is a reference
           type, otherwise the result is an rvalue.  */
@@ -6078,7 +6101,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
          && (TREE_CODE (type) != REFERENCE_TYPE
              || TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE))
       || TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
-    rhs = default_conversion (rhs);
+    rhs = decay_conversion (rhs);
 
   rhstype = TREE_TYPE (rhs);
   coder = TREE_CODE (rhstype);
index 9d9ade150451a933fb14eac76191dad7817ac514..edb9f5d5b212d77d01753e03ee52eb7ca31c09cd 100644 (file)
@@ -1030,7 +1030,7 @@ build_x_arrow (tree datum)
        last_rval = convert_from_reference (last_rval);
     }
   else
-    last_rval = default_conversion (rval);
+    last_rval = decay_conversion (rval);
 
   if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
     return build_indirect_ref (last_rval, NULL);
index d67d0b74693e02dc6a2f8d3ff8729fd6c22809d6..3d067f575e9e8f97e946a42b5961baa5108bce3c 100644 (file)
@@ -1,3 +1,11 @@
+2003-07-05  Mark Mitchell  <mark@codesourcery.com>
+
+       * g++.old-deja/g++.jason/typeid1.C: Make it a compile test, not a
+       run test.
+       
+       PR c++/11431
+       * g++.dg/expr/static_cast3.C: New test.
+
 2003-07-04  Zack Weinberg  <zack@codesourcery.com>
 
        * gcc.c-torture/execute/wchar_t-1.x: New file; XFAIL wchar_t-1.c
diff --git a/gcc/testsuite/g++.dg/expr/static_cast3.C b/gcc/testsuite/g++.dg/expr/static_cast3.C
new file mode 100644 (file)
index 0000000..744648c
--- /dev/null
@@ -0,0 +1,24 @@
+template <class T> struct static_abort {};
+
+template <class E>
+struct any
+{
+  const E& self() const { return static_cast<const E&>(*this); }
+};
+
+struct range : public any<range>
+{
+  range() {}
+
+  template <class U>
+  range(const U&)
+  {
+    typedef typename static_abort<U>::ret t;
+  }
+};
+
+int main()
+{
+  const any<range>& r = *new range();
+  r.self();
+}
index 678ab5fcdd556f97274c1d0ac4f99a3078813c28..ec5156e0cd0bcba2d9599980b494258bb6693710 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-do run  }
+// { dg-do compile }
 #include <typeinfo>
 #include <iostream>