From 08e17d9d1121f0ce5869ddf1283db2449a4bc458 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Thu, 21 Oct 2004 21:23:42 +0000 Subject: [PATCH] re PR c++/18073 (mmintrin.h rejected by C++ frontend) PR c++/18073 PR c++/10841 * cp-tree.h (convert_to_base): Change prototype. (build_ptrmemfunc): Likewise. (convert_ptrmem): New function. * call.c (struct conversion): Adjust documentation for base_p. (standard_conversion): Set base_p for ck_pmem conversions as appropriate. (convert_like_real): Use convert_to_base for ck_pmem and ck_ptr conversions. * class.c (convert_to_base): Handle both pointers and objects. Add nonnull parameter. (build_vfield_ref): Adjust call to convert_to_base. * cvt.c (cp_convert_to_pointer): Adjust call to build_ptrmemfunc. (convert_force): Likewise. * typeck.c (build_unary_op): Likewise. (convert_ptrmem): New function. (build_static_cast_1): Use it. (build_reinterpret_cast): Allow conversions to vector types. (get_delta_difference): Add c_cast_p parameter. (build_ptrmemfunc): Likewise. Adjust calls to get_delta_difference. PR c++/10841 * g++.dg/conversion/cast1.C: New test. * g++.dg/overload/pmf1.C: Adjust error marker. From-SVN: r89403 --- gcc/cp/ChangeLog | 25 +++++++ gcc/cp/call.c | 26 +++----- gcc/cp/class.c | 27 ++++++-- gcc/cp/cp-tree.h | 5 +- gcc/cp/cvt.c | 13 ++-- gcc/cp/typeck.c | 89 ++++++++++++++++--------- gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/g++.dg/conversion/cast1.C | 22 ++++++ gcc/testsuite/g++.dg/overload/pmf1.C | 2 +- 9 files changed, 154 insertions(+), 61 deletions(-) create mode 100644 gcc/testsuite/g++.dg/conversion/cast1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 3adc303036d..2c78f23b265 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,28 @@ +2004-10-21 Mark Mitchell + + PR c++/18073 + PR c++/10841 + * cp-tree.h (convert_to_base): Change prototype. + (build_ptrmemfunc): Likewise. + (convert_ptrmem): New function. + * call.c (struct conversion): Adjust documentation for base_p. + (standard_conversion): Set base_p for ck_pmem conversions as + appropriate. + (convert_like_real): Use convert_to_base for ck_pmem and ck_ptr + conversions. + * class.c (convert_to_base): Handle both pointers and objects. + Add nonnull parameter. + (build_vfield_ref): Adjust call to convert_to_base. + * cvt.c (cp_convert_to_pointer): Adjust call to build_ptrmemfunc. + (convert_force): Likewise. + * typeck.c (build_unary_op): Likewise. + (convert_ptrmem): New function. + (build_static_cast_1): Use it. + (build_reinterpret_cast): Allow conversions to vector types. + (get_delta_difference): Add c_cast_p parameter. + (build_ptrmemfunc): Likewise. Adjust calls to + get_delta_difference. + 2004-10-21 Andrew Pinski PR c++/13560 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 46b270e3ff3..aedc9278b9d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -92,8 +92,8 @@ struct conversion { copy constructor must be accessible, even though it is not being used. */ BOOL_BITFIELD check_copy_constructor_p : 1; - /* If KIND is ck_ptr, true to indicate that a conversion from a - pointer-to-derived to pointer-to-base is being performed. */ + /* If KIND is ck_ptr or ck_pmem, true to indicate that a conversion + from a pointer-to-derived to pointer-to-base is being performed. */ BOOL_BITFIELD base_p : 1; /* The type of the expression resulting from the conversion. */ tree type; @@ -779,6 +779,7 @@ standard_conversion (tree to, tree from, tree expr) TREE_CHAIN (TYPE_ARG_TYPES (fromfn))); from = build_ptrmemfunc_type (build_pointer_type (from)); conv = build_conv (ck_pmem, from, conv); + conv->base_p = true; } else if (tcode == BOOLEAN_TYPE) { @@ -4270,8 +4271,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, check_constructor_callable (TREE_TYPE (expr), expr); /* Build an expression for `*((base*) &expr)'. */ expr = build_unary_op (ADDR_EXPR, expr, 0); - expr = perform_implicit_conversion (build_pointer_type (totype), - expr); + expr = convert_to_base (expr, build_pointer_type (totype), + !c_cast_p, /*nonnull=*/true); expr = build_indirect_ref (expr, "implicit conversion"); return expr; } @@ -4338,19 +4339,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, case ck_ptr: if (convs->base_p) - { - tree binfo; - - binfo = lookup_base (TREE_TYPE (TREE_TYPE (expr)), - TREE_TYPE (totype), - c_cast_p ? ba_unique : ba_check, - NULL); - if (binfo == error_mark_node) - return error_mark_node; - expr = build_base_path (PLUS_EXPR, expr, binfo, /*nonnull=*/0); - } + expr = convert_to_base (expr, totype, !c_cast_p, + /*nonnull=*/false); return build_nop (totype, expr); + case ck_pmem: + return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false, + c_cast_p); + default: break; } diff --git a/gcc/cp/class.c b/gcc/cp/class.c index a0a2ed48bce..15ca26ad460 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -426,22 +426,34 @@ build_simple_base_path (tree expr, tree binfo) gcc_unreachable (); } -/* Convert OBJECT to the base TYPE. If CHECK_ACCESS is true, an error - message is emitted if TYPE is inaccessible. OBJECT is assumed to - be non-NULL. */ +/* Convert OBJECT to the base TYPE. OBJECT is an expression whose + type is a class type or a pointer to a class type. In the former + case, TYPE is also a class type; in the latter it is another + pointer type. If CHECK_ACCESS is true, an error message is emitted + if TYPE is inaccessible. If OBJECT has pointer type, the value is + assumed to be non-NULL. */ tree -convert_to_base (tree object, tree type, bool check_access) +convert_to_base (tree object, tree type, bool check_access, bool nonnull) { tree binfo; + tree object_type; - binfo = lookup_base (TREE_TYPE (object), type, + if (TYPE_PTR_P (TREE_TYPE (object))) + { + object_type = TREE_TYPE (TREE_TYPE (object)); + type = TREE_TYPE (type); + } + else + object_type = TREE_TYPE (object); + + binfo = lookup_base (object_type, type, check_access ? ba_check : ba_unique, NULL); if (!binfo || binfo == error_mark_node) return error_mark_node; - return build_base_path (PLUS_EXPR, object, binfo, /*nonnull=*/1); + return build_base_path (PLUS_EXPR, object, binfo, nonnull); } /* EXPR is an expression with unqualified class type. BASE is a base @@ -485,7 +497,8 @@ build_vfield_ref (tree datum, tree type) /* First, convert to the requested type. */ if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (datum), type)) - datum = convert_to_base (datum, type, /*check_access=*/false); + datum = convert_to_base (datum, type, /*check_access=*/false, + /*nonnull=*/true); /* Second, the requested type may not be the owner of its own vptr. If not, convert to the base class that owns it. We cannot use diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0f75fce3812..580a73b4db8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3594,7 +3594,7 @@ extern void validate_conversion_obstack (void); /* in class.c */ extern tree build_base_path (enum tree_code, tree, tree, int); -extern tree convert_to_base (tree, tree, bool); +extern tree convert_to_base (tree, tree, bool, bool); extern tree convert_to_base_statically (tree, tree); extern tree build_vtbl_ref (tree, tree); extern tree build_vfn_ref (tree, tree); @@ -4267,7 +4267,7 @@ extern tree dubious_conversion_warnings (tree, tree, const char *, tree, extern tree convert_for_initialization (tree, tree, tree, int, const char *, tree, int); extern int comp_ptr_ttypes (tree, tree); extern int ptr_reasonably_similar (tree, tree); -extern tree build_ptrmemfunc (tree, tree, int); +extern tree build_ptrmemfunc (tree, tree, int, bool); extern int cp_type_quals (tree); extern bool cp_has_mutable_p (tree); extern bool at_least_as_qualified_p (tree, tree); @@ -4291,6 +4291,7 @@ extern tree non_reference (tree); extern tree lookup_anon_field (tree, tree); extern bool invalid_nonstatic_memfn_p (tree); extern tree convert_member_func_to_ptr (tree, tree); +extern tree convert_ptrmem (tree, tree, bool, bool); /* in typeck2.c */ extern void require_complete_eh_spec_types (tree, tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 02230301117..7f0f64c9c46 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -217,7 +217,8 @@ cp_convert_to_pointer (tree type, tree expr, bool force) return build_nop (type, expr); } else if (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)) - return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0); + return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0, + /*c_cast_p=*/false); else if (TYPE_PTRMEMFUNC_P (intype)) { if (!warn_pmf2ptr) @@ -241,7 +242,8 @@ cp_convert_to_pointer (tree type, tree expr, bool force) if (integer_zerop (expr)) { if (TYPE_PTRMEMFUNC_P (type)) - return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0); + return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0, + /*c_cast_p=*/false); if (TYPE_PTRMEM_P (type)) { @@ -960,10 +962,9 @@ convert_force (tree type, tree expr, int convtype) || integer_zerop (e) || TYPE_PTRMEMFUNC_P (TREE_TYPE (e))) && TYPE_PTRMEMFUNC_P (type)) - { - /* compatible pointer to member functions. */ - return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1); - } + /* compatible pointer to member functions. */ + return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1, + /*c_cast_p=*/1); return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL); } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 0f6f65b4188..cc91b653aae 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -52,7 +52,7 @@ static bool comp_except_types (tree, tree, bool); static bool comp_array_types (tree, tree, bool); static tree common_base_type (tree, tree); static tree pointer_diff (tree, tree, tree); -static tree get_delta_difference (tree, tree, int); +static tree get_delta_difference (tree, tree, bool, bool); static void casts_away_constness_r (tree *, tree *); static bool casts_away_constness (tree, tree); static void maybe_warn_about_returning_address_of_local (tree); @@ -4146,7 +4146,8 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert) && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE) { build_ptrmemfunc_type (argtype); - addr = build_ptrmemfunc (argtype, addr, 0); + addr = build_ptrmemfunc (argtype, addr, 0, + /*c_cast_p=*/false); } return addr; @@ -4485,6 +4486,38 @@ check_for_casting_away_constness (tree src_type, tree dest_type, description, src_type, dest_type); } +/* Convert EXPR (an expression with pointer-to-member type) to TYPE + (another pointer-to-member type in the same hierarchy) and return + the converted expression. If ALLOW_INVERSE_P is permitted, a + pointer-to-derived may be converted to pointer-to-base; otherwise, + only the other direction is permitted. If C_CAST_P is true, this + conversion is taking place as part of a C-style cast. */ + +tree +convert_ptrmem (tree type, tree expr, bool allow_inverse_p, + bool c_cast_p) +{ + if (TYPE_PTRMEM_P (type)) + { + tree delta; + + if (TREE_CODE (expr) == PTRMEM_CST) + expr = cplus_expand_constant (expr); + delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)), + TYPE_PTRMEM_CLASS_TYPE (type), + allow_inverse_p, + c_cast_p); + if (!integer_zerop (delta)) + expr = cp_build_binary_op (PLUS_EXPR, + build_nop (ptrdiff_type_node, expr), + delta); + return build_nop (type, expr); + } + else + return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, + allow_inverse_p, c_cast_p); +} + /* Perform a static_cast from EXPR to TYPE. When C_CAST_P is true, this static_cast is being attempted as one of the possible casts allowed by a C-style cast. (In that case, accessibility of base @@ -4691,23 +4724,10 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p, if (can_convert (t1, t2)) { if (!c_cast_p) - check_for_casting_away_constness (intype, type, diag_fn, desc); - if (TYPE_PTRMEM_P (type)) - { - tree delta; - - if (TREE_CODE (expr) == PTRMEM_CST) - expr = cplus_expand_constant (expr); - delta = get_delta_difference (c1, c2, /*force=*/1); - if (!integer_zerop (delta)) - expr = cp_build_binary_op (PLUS_EXPR, - build_nop (ptrdiff_type_node, expr), - delta); - return build_nop (type, expr); - } - else - return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, - /*force=*/1); + check_for_casting_away_constness (intype, type, diag_fn, + desc); + return convert_ptrmem (type, expr, /*allow_inverse_p=*/1, + c_cast_p); } } @@ -4945,6 +4965,8 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, expr = decl_constant_value (expr); return fold_if_not_in_template (build_nop (type, expr)); } + else if (TREE_CODE (type) == VECTOR_TYPE) + return fold_if_not_in_template (convert_to_vector (type, expr)); else { if (valid_p) @@ -5546,8 +5568,10 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) /* Get difference in deltas for different pointer to member function types. Returns an integer constant of type PTRDIFF_TYPE_NODE. If - the conversion is invalid, the constant is zero. If FORCE is true, - then allow reverse conversions as well. + the conversion is invalid, the constant is zero. If + ALLOW_INVERSE_P is true, then allow reverse conversions as well. + If C_CAST_P is true this conversion is taking place as part of a + C-style cast. Note that the naming of FROM and TO is kind of backwards; the return value is what we add to a TO in order to get a FROM. They are named @@ -5555,7 +5579,9 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs) a pointer to member of FROM to a pointer to member of TO. */ static tree -get_delta_difference (tree from, tree to, int force) +get_delta_difference (tree from, tree to, + bool allow_inverse_p, + bool c_cast_p) { tree binfo; tree virt_binfo; @@ -5564,19 +5590,20 @@ get_delta_difference (tree from, tree to, int force) /* Assume no conversion is required. */ result = integer_zero_node; - binfo = lookup_base (to, from, ba_check, &kind); + binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind); if (kind == bk_inaccessible || kind == bk_ambig) error (" in pointer to member function conversion"); else if (!binfo) { - if (!force) + if (!allow_inverse_p) { error_not_base_type (from, to); error (" in pointer to member conversion"); } else { - binfo = lookup_base (from, to, ba_check, &kind); + binfo = lookup_base (from, to, c_cast_p ? ba_unique : ba_check, + &kind); if (binfo) { virt_binfo = binfo_from_vbase (binfo); @@ -5597,7 +5624,7 @@ get_delta_difference (tree from, tree to, int force) else { /* This is a reinterpret cast, we choose to do nothing. */ - if (force) + if (allow_inverse_p) warning ("pointer to member cast via virtual base %qT", BINFO_TYPE (virt_binfo)); else @@ -5648,12 +5675,12 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn) If FORCE is nonzero, then force this conversion, even if we would rather not do it. Usually set when using an explicit - cast. + cast. A C-style cast is being processed iff C_CAST_P is true. Return error_mark_node, if something goes wrong. */ tree -build_ptrmemfunc (tree type, tree pfn, int force) +build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p) { tree fn; tree pfn_type; @@ -5679,7 +5706,8 @@ build_ptrmemfunc (tree type, tree pfn, int force) n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type), TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type), - force); + force, + c_cast_p); /* We don't have to do any conversion to convert a pointer-to-member to its own type. But, we don't want to @@ -5754,7 +5782,8 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn) ptr_class = TYPE_PTRMEMFUNC_OBJECT_TYPE (type); /* First, calculate the adjustment to the function's class. */ - *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0); + *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0, + /*c_cast_p=*/0); if (!DECL_VIRTUAL_P (fn)) *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b7f25ddf4dd..ae6231295cb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2004-10-21 Mark Mitchell + + PR c++/10841 + * g++.dg/conversion/cast1.C: New test. + * g++.dg/overload/pmf1.C: Adjust error marker. + 2004-10-21 Andrew Pinski PR objc/17923 diff --git a/gcc/testsuite/g++.dg/conversion/cast1.C b/gcc/testsuite/g++.dg/conversion/cast1.C new file mode 100644 index 00000000000..f90b42165a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/conversion/cast1.C @@ -0,0 +1,22 @@ +// PR c++/10841 + +int main() { + class Base { + public: + int i, j, k; + void f(); }; + + class Derived : private Base { + public: + int m, n, p; + void g(); + }; + + Derived derived; + Base &base = (Base &)derived; + (int Base::*)&Derived::n; + (int Derived::*)&Base::j; + (void (Base::*)(void))&Derived::g; + (void (Derived::*)(void))&Base::f; +} + diff --git a/gcc/testsuite/g++.dg/overload/pmf1.C b/gcc/testsuite/g++.dg/overload/pmf1.C index b97f64e764b..d2007493179 100644 --- a/gcc/testsuite/g++.dg/overload/pmf1.C +++ b/gcc/testsuite/g++.dg/overload/pmf1.C @@ -17,5 +17,5 @@ void f (C) {} // even though this would be well-formed int main () { - f (aip); // { dg-error "'A' is an inaccessible base of 'B'" "" } + f (aip); // { dg-error "'A' is an inaccessible base of 'B'|conversion" "" } } -- 2.30.2