* typeck.c (build_static_cast): Don't allow static_casts that cast
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 24 May 1999 15:26:25 +0000 (15:26 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 24 May 1999 15:26:25 +0000 (15:26 +0000)
away constness.
(casts_away_constness_r): New function.
(casts_away_constness): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@27128 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/typeck.c
gcc/testsuite/g++.old-deja/g++.other/sc1.C [new file with mode: 0644]

index cf71347..250f063 100644 (file)
@@ -1,5 +1,10 @@
 1999-05-24  Mark Mitchell  <mark@codesourcery.com>
 
+       * typeck.c (build_static_cast): Don't allow static_casts that cast
+       away constness.
+       (casts_away_constness_r): New function.
+       (casts_away_constness): Likewise.
+
        * decl.c (lookup_tag): Remove code no longer needed after
        name-lookup improvements.
        * decl2.c (handle_class_head): Make error-recovery more robust.
index 1514ed7..13a490b 100644 (file)
@@ -59,6 +59,8 @@ static tree build_component_addr PROTO((tree, tree));
 static tree qualify_type PROTO((tree, tree));
 static tree get_delta_difference PROTO((tree, tree, int));
 static int comp_cv_target_types PROTO((tree, tree, int));
+static void casts_away_constness_r PROTO((tree *, tree *));
+static int casts_away_constness PROTO ((tree, tree));
 
 /* Return the target type of TYPE, which meas return T for:
    T*, T&, T[], T (...), and otherwise, just T.  */
@@ -5546,6 +5548,17 @@ build_static_cast (type, expr)
           && can_convert (intype, type))
     ok = 1;
 
+  /* [expr.static.cast]
+
+     The static_cast operator shall not be used to cast away
+     constnes.  */
+  if (ok && casts_away_constness (intype, type))
+    {
+      cp_error ("static_cast from `%T' to `%T' casts away constness",
+               intype, type);
+      return error_mark_node;
+    }
+
   if (ok)
     return build_c_cast (type, expr);
 
@@ -7738,3 +7751,114 @@ cp_has_mutable_p (type)
 
   return CLASS_TYPE_P (type) && CLASSTYPE_HAS_MUTABLE (type);
 }
+
+/* Subroutine of casts_away_constness.  Make T1 and T2 point at
+   exemplar types such that casting T1 to T2 is casting away castness
+   if and only if there is no implicit conversion from T1 to T2.  */
+
+static void
+casts_away_constness_r (t1, t2)
+     tree *t1;
+     tree *t2;
+{
+  int quals1;
+  int quals2;
+
+  /* [expr.const.cast]
+
+     For multi-level pointer to members and multi-level mixed pointers
+     and pointers to members (conv.qual), the "member" aspect of a
+     pointer to member level is ignored when determining if a const
+     cv-qualifier has been cast away.  */
+  if (TYPE_PTRMEM_P (*t1))
+    *t1 = build_pointer_type (TREE_TYPE (*t1));
+  if (TYPE_PTRMEM_P (*t2))
+    *t2 = build_pointer_type (TREE_TYPE (*t2));
+
+  /* [expr.const.cast]
+
+     For  two  pointer types:
+
+            X1 is T1cv1,1 * ... cv1,N *   where T1 is not a pointer type
+            X2 is T2cv2,1 * ... cv2,M *   where T2 is not a pointer type
+            K is min(N,M)
+
+     casting from X1 to X2 casts away constness if, for a non-pointer
+     type T there does not exist an implicit conversion (clause
+     _conv_) from:
+
+            Tcv1,(N-K+1) * cv1,(N-K+2) * ... cv1,N *
+      
+     to
+
+            Tcv2,(M-K+1) * cv2,(M-K+2) * ... cv2,M *.  */
+
+  if (TREE_CODE (*t1) != POINTER_TYPE
+      || TREE_CODE (*t2) != POINTER_TYPE)
+    {
+      *t1 = cp_build_qualified_type (void_type_node,
+                                    CP_TYPE_QUALS (*t1));
+      *t2 = cp_build_qualified_type (void_type_node,
+                                    CP_TYPE_QUALS (*t2));
+      return;
+    }
+  
+  quals1 = CP_TYPE_QUALS (*t1);
+  quals2 = CP_TYPE_QUALS (*t2);
+  *t1 = TREE_TYPE (*t1);
+  *t2 = TREE_TYPE (*t2);
+  casts_away_constness_r (t1, t2);
+  *t1 = build_pointer_type (*t1);
+  *t2 = build_pointer_type (*t2);
+  *t1 = cp_build_qualified_type (*t1, quals1);
+  *t2 = cp_build_qualified_type (*t2, quals2);
+}
+
+/* Returns non-zero if casting from TYPE1 to TYPE2 casts away
+   constness.  */
+
+static int
+casts_away_constness (t1, t2)
+     tree t1;
+     tree t2;
+{
+  if (TREE_CODE (t2) == REFERENCE_TYPE)
+    {
+      /* [expr.const.cast]
+        
+        Casting from an lvalue of type T1 to an lvalue of type T2
+        using a reference cast casts away constness if a cast from an
+        rvalue of type "pointer to T1" to the type "pointer to T2"
+        casts away constness.  */
+      t1 = (TREE_CODE (t1) == REFERENCE_TYPE
+           ? TREE_TYPE (t1) : t1);
+      return casts_away_constness (build_pointer_type (t1),
+                                  build_pointer_type (TREE_TYPE (t2)));
+    }
+
+  if (TYPE_PTRMEM_P (t1) && TYPE_PTRMEM_P (t2))
+    /* [expr.const.cast]
+       
+       Casting from an rvalue of type "pointer to data member of X
+       of type T1" to the type "pointer to data member of Y of type
+       T2" casts away constness if a cast from an rvalue of type
+       "poitner to T1" to the type "pointer to T2" casts away
+       constness.  */
+    return casts_away_constness (build_pointer_type (TREE_TYPE (t1)),
+                                build_pointer_type (TREE_TYPE (t2)));
+
+  /* Casting away constness is only something that makes sense for
+     pointer or reference types.  */
+  if (TREE_CODE (t1) != POINTER_TYPE 
+      || TREE_CODE (t2) != POINTER_TYPE)
+    return 0;
+
+  /* Top-level qualifiers don't matter.  */
+  t1 = TYPE_MAIN_VARIANT (t1);
+  t2 = TYPE_MAIN_VARIANT (t2);
+  casts_away_constness_r (&t1, &t2);
+  if (!can_convert (t2, t1))
+    return 1;
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/sc1.C b/gcc/testsuite/g++.old-deja/g++.other/sc1.C
new file mode 100644 (file)
index 0000000..8d99ed0
--- /dev/null
@@ -0,0 +1,10 @@
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+void f() {
+  int *i = 0;
+  const int *c = 0;
+
+  static_cast <const int *>(i);
+  static_cast <int *>(c);  // ERROR - casts away constness
+}