From 64b83f2a4ae301d941b18bc77fe6c5e2f1cb0c61 Mon Sep 17 00:00:00 2001 From: Steven Grady Date: Fri, 17 Mar 2000 00:56:12 +0000 Subject: [PATCH] rtti.c (build_dynamic_cast_1): Improve diagnostics. * rtti.c (build_dynamic_cast_1): Improve diagnostics. Co-Authored-By: Jason Merrill From-SVN: r32599 --- gcc/cp/ChangeLog | 5 ++ gcc/cp/rtti.c | 126 +++++++++++++++++++++++++++++------------------ 2 files changed, 82 insertions(+), 49 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 02d7de871b5..425bc630865 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2000-03-16 Steven Grady + Jason Merrill + + * rtti.c (build_dynamic_cast_1): Improve diagnostics. + 2000-03-16 Nathan Sidwell * decl2.c (grokfield): Bail out if type is error_mark_node. diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index e8034c3840e..0c1986dbfd1 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -548,69 +548,98 @@ build_dynamic_cast_1 (type, expr) { enum tree_code tc = TREE_CODE (type); tree exprtype; - enum tree_code ec; tree dcast_fn; tree old_expr = expr; + char* errstr = NULL; - if (TREE_CODE (expr) == OFFSET_REF) - expr = resolve_offset_ref (expr); - - exprtype = TREE_TYPE (expr); - assert (exprtype != NULL_TREE); - ec = TREE_CODE (exprtype); - + /* T shall be a pointer or reference to a complete class type, or + `pointer to cv void''. */ switch (tc) { case POINTER_TYPE: - if (ec == REFERENCE_TYPE) - { - expr = convert_from_reference (expr); - exprtype = TREE_TYPE (expr); - ec = TREE_CODE (exprtype); - } - if (ec != POINTER_TYPE) - goto fail; - if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE) - goto fail; - if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE) - goto fail; - if (!at_least_as_qualified_p (TREE_TYPE (type), - TREE_TYPE (exprtype))) - goto fail; - if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node) + if (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE) break; - /* else fall through */ case REFERENCE_TYPE: - if (TREE_CODE (TREE_TYPE (type)) != RECORD_TYPE) - goto fail; + if (! IS_AGGR_TYPE (TREE_TYPE (type))) + { + errstr = "target is not pointer or reference to class"; + goto fail; + } if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE) - goto fail; + { + errstr = "target is not pointer or reference to complete type"; + goto fail; + } break; - /* else fall through */ + default: + errstr = "target is not pointer or reference"; goto fail; } - /* Apply trivial conversion T -> T& for dereferenced ptrs. */ - if (ec == RECORD_TYPE) + if (TREE_CODE (expr) == OFFSET_REF) + expr = resolve_offset_ref (expr); + + exprtype = TREE_TYPE (expr); + assert (exprtype != NULL_TREE); + + if (tc == POINTER_TYPE) + expr = convert_from_reference (expr); + else if (TREE_CODE (exprtype) != REFERENCE_TYPE) { + /* Apply trivial conversion T -> T& for dereferenced ptrs. */ exprtype = build_reference_type (exprtype); expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT, LOOKUP_NORMAL, NULL_TREE); - ec = REFERENCE_TYPE; } - if (tc == REFERENCE_TYPE) + exprtype = TREE_TYPE (expr); + + if (tc == POINTER_TYPE) + { + /* If T is a pointer type, v shall be an rvalue of a pointer to + complete class type, and the result is an rvalue of type T. */ + + if (TREE_CODE (exprtype) != POINTER_TYPE) + { + errstr = "source is not a pointer"; + goto fail; + } + if (! IS_AGGR_TYPE (TREE_TYPE (exprtype))) + { + errstr = "source is not a pointer to class"; + goto fail; + } + if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE) + { + errstr = "source is a pointer to incomplete type"; + goto fail; + } + } + else { - if (ec != REFERENCE_TYPE) - goto fail; - if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE) - goto fail; + /* T is a reference type, v shall be an lvalue of a complete class + type, and the result is an lvalue of the type referred to by T. */ + + if (! IS_AGGR_TYPE (TREE_TYPE (exprtype))) + { + errstr = "source is not of class type"; + goto fail; + } if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE) - goto fail; - if (!at_least_as_qualified_p (TREE_TYPE (type), - TREE_TYPE (exprtype))) - goto fail; + { + errstr = "source is of incomplete class type"; + goto fail; + } + + } + + /* The dynamic_cast operator shall not cast away constness. */ + if (!at_least_as_qualified_p (TREE_TYPE (type), + TREE_TYPE (exprtype))) + { + errstr = "conversion casts away constness"; + goto fail; } /* If *type is an unambiguous accessible base class of *exprtype, @@ -669,7 +698,7 @@ build_dynamic_cast_1 (type, expr) /* If we got here, we can't convert statically. Therefore, dynamic_cast(b) (b an object) cannot succeed. */ - if (ec == REFERENCE_TYPE) + if (tc == REFERENCE_TYPE) { if (TREE_CODE (old_expr) == VAR_DECL && TREE_CODE (TREE_TYPE (old_expr)) == RECORD_TYPE) @@ -717,7 +746,7 @@ build_dynamic_cast_1 (type, expr) tree expr2 = build_headof (expr1); tree td1 = expr; - if (ec == POINTER_TYPE) + if (tc == POINTER_TYPE) td1 = build_indirect_ref (td1, NULL_PTR); td1 = get_tinfo_decl_dynamic (td1); @@ -802,13 +831,12 @@ build_dynamic_cast_1 (type, expr) return ifnonnull (expr, result); } } - - cp_error ("dynamic_cast from non-polymorphic type `%#T'", exprtype); - return error_mark_node; + else + errstr = "source type is not polymorphic"; fail: - cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'", - expr, exprtype, type); + cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T' (%s)", + expr, exprtype, type, errstr); return error_mark_node; } @@ -1275,7 +1303,7 @@ tinfo_base_init (desc, target) init = tree_cons (NULL_TREE, decay_conversion (name_string), init); - init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse(init)); + init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init)); TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1; init = tree_cons (NULL_TREE, init, NULL_TREE); -- 2.30.2