aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>1999-05-24 15:26:25 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1999-05-24 15:26:25 +0000
commitaf7b99029065dd164c850082195d70d6f46fb28e (patch)
treeca3847974001bbec2a339db5d2379484a1d6c8c5
parent671d0648e08e746d404b9f6422965ef52e6fc77c (diff)
downloadgcc-af7b99029065dd164c850082195d70d6f46fb28e.zip
gcc-af7b99029065dd164c850082195d70d6f46fb28e.tar.gz
gcc-af7b99029065dd164c850082195d70d6f46fb28e.tar.bz2
typeck.c (build_static_cast): Don't allow static_casts that cast away constness.
* typeck.c (build_static_cast): Don't allow static_casts that cast away constness. (casts_away_constness_r): New function. (casts_away_constness): Likewise. From-SVN: r27128
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/typeck.c124
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/sc1.C10
3 files changed, 139 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index cf71347..250f063 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 1514ed7..13a490b 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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
index 0000000..8d99ed0
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/sc1.C
@@ -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
+}