From 8b8b203a26bdac3dede77e76d06e4e7084f79acc Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 9 Jun 2017 20:40:44 -0400 Subject: [PATCH] Overhaul pointer-to-member conversion and template argument handling. * call.c (standard_conversion): Avoid creating ck_pmem when the class type is the same. * cvt.c (can_convert_qual): Split from perform_qualification_conversions. * constexpr.c (cxx_eval_constant_expression): Check it. * typeck.c (convert_ptrmem): Only cplus_expand_constant if adjustment is necessary. * pt.c (check_valid_ptrmem_cst_expr): Compare class types. (convert_nontype_argument): Avoid redundant error. From-SVN: r249088 --- gcc/cp/ChangeLog | 11 +++++++++++ gcc/cp/call.c | 10 ++++++---- gcc/cp/constexpr.c | 3 ++- gcc/cp/cp-tree.h | 1 + gcc/cp/cvt.c | 29 +++++++++++++++++++++-------- gcc/cp/pt.c | 45 +++++++++++++++------------------------------ gcc/cp/typeck.c | 7 +++++-- 7 files changed, 61 insertions(+), 45 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8949f6b56f6..4e966a2e26f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,16 @@ 2017-06-09 Jason Merrill + Overhaul pointer-to-member conversion and template argument handling. + * call.c (standard_conversion): Avoid creating ck_pmem when the + class type is the same. + * cvt.c (can_convert_qual): Split from + perform_qualification_conversions. + * constexpr.c (cxx_eval_constant_expression): Check it. + * typeck.c (convert_ptrmem): Only cplus_expand_constant if + adjustment is necessary. + * pt.c (check_valid_ptrmem_cst_expr): Compare class types. + (convert_nontype_argument): Avoid redundant error. + * call.c (convert_like_real): Remove "inner" parameter. Don't replace a constant with its value. * cp-gimplify.c (cp_fully_fold): Use cp_fold_rvalue. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 5e65bfbff4b..a4b6a95f13e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -1262,14 +1262,16 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, tree fbase = TYPE_PTRMEM_CLASS_TYPE (from); tree tbase = TYPE_PTRMEM_CLASS_TYPE (to); - if (DERIVED_FROM_P (fbase, tbase) - && (same_type_ignoring_top_level_qualifiers_p - (from_pointee, to_pointee))) + if (same_type_p (fbase, tbase)) + /* No base conversion needed. */; + else if (DERIVED_FROM_P (fbase, tbase) + && (same_type_ignoring_top_level_qualifiers_p + (from_pointee, to_pointee))) { from = build_ptrmem_type (tbase, from_pointee); conv = build_conv (ck_pmem, from, conv); } - else if (!same_type_p (fbase, tbase)) + else return NULL; } else if (CLASS_TYPE_P (from_pointee) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 8bbe950828f..ae24e4010ff 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4399,7 +4399,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (op) == PTRMEM_CST && tcode == NOP_EXPR) { if (same_type_ignoring_top_level_qualifiers_p (type, - TREE_TYPE (op))) + TREE_TYPE (op)) + || can_convert_qual (type, op)) return cp_fold_convert (type, op); else { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 550dbf26a80..07da0cda5e7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6022,6 +6022,7 @@ extern tree convert_force (tree, tree, int, tsubst_flags_t); extern tree build_expr_type_conversion (int, tree, bool); extern tree type_promotes_to (tree); +extern bool can_convert_qual (tree, tree); extern tree perform_qualification_conversions (tree, tree); extern bool tx_safe_fn_type_p (tree); extern tree tx_unsafe_fn_variant (tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 6b28ef65074..3460e133429 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1890,6 +1890,26 @@ type_promotes_to (tree type) closely. Although they are used only in pt.c at the moment, they should presumably be used everywhere in the future. */ +/* True iff EXPR can be converted to TYPE via a qualification conversion. + Callers should check for identical types before calling this function. */ + +bool +can_convert_qual (tree type, tree expr) +{ + tree expr_type = TREE_TYPE (expr); + gcc_assert (!same_type_p (type, expr_type)); + + if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type)) + return comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type)); + else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (expr_type)) + return (same_type_p (TYPE_PTRMEM_CLASS_TYPE (type), + TYPE_PTRMEM_CLASS_TYPE (expr_type)) + && comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type), + TYPE_PTRMEM_POINTED_TO_TYPE (expr_type))); + else + return false; +} + /* Attempt to perform qualification conversions on EXPR to convert it to TYPE. Return the resulting expression, or error_mark_node if the conversion was impossible. */ @@ -1903,14 +1923,7 @@ perform_qualification_conversions (tree type, tree expr) if (same_type_p (type, expr_type)) return expr; - else if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type) - && comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type))) - return build_nop (type, expr); - else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (expr_type) - && same_type_p (TYPE_PTRMEM_CLASS_TYPE (type), - TYPE_PTRMEM_CLASS_TYPE (expr_type)) - && comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type), - TYPE_PTRMEM_POINTED_TO_TYPE (expr_type))) + else if (can_convert_qual (type, expr)) return build_nop (type, expr); else return error_mark_node; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 40be3c1d22f..b537cb8a85d 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6124,8 +6124,14 @@ static bool check_valid_ptrmem_cst_expr (tree type, tree expr, tsubst_flags_t complain) { + location_t loc = EXPR_LOC_OR_LOC (expr, input_location); + tree orig_expr = expr; STRIP_NOPS (expr); - if (expr && (null_ptr_cst_p (expr) || TREE_CODE (expr) == PTRMEM_CST)) + if (null_ptr_cst_p (expr)) + return true; + if (TREE_CODE (expr) == PTRMEM_CST + && same_type_p (TYPE_PTRMEM_CLASS_TYPE (type), + PTRMEM_CST_CLASS (expr))) return true; if (cxx_dialect >= cxx11 && null_member_pointer_value_p (expr)) return true; @@ -6135,9 +6141,12 @@ check_valid_ptrmem_cst_expr (tree type, tree expr, return true; if (complain & tf_error) { - error ("%qE is not a valid template argument for type %qT", - expr, type); - error ("it must be a pointer-to-member of the form %<&X::Y%>"); + error_at (loc, "%qE is not a valid template argument for type %qT", + orig_expr, type); + if (TREE_CODE (expr) != PTRMEM_CST) + inform (loc, "it must be a pointer-to-member of the form %<&X::Y%>"); + else + inform (loc, "because it is a member of %qT", PTRMEM_CST_CLASS (expr)); } return false; } @@ -6880,36 +6889,12 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) expression must be a pointer-to-member constant. */ if (!value_dependent_expression_p (expr) && !check_valid_ptrmem_cst_expr (type, expr, complain)) - return error_mark_node; + return NULL_TREE; /* Repeated conversion can't deal with a conversion that turns PTRMEM_CST into a CONSTRUCTOR, so build up a new PTRMEM_CST instead. */ if (fnptr_conv_p (type, TREE_TYPE (expr))) expr = make_ptrmem_cst (type, PTRMEM_CST_MEMBER (expr)); - - /* There is no way to disable standard conversions in - resolve_address_of_overloaded_function (called by - instantiate_type). It is possible that the call succeeded by - converting &B::I to &D::I (where B is a base of D), so we need - to reject this conversion here. - - Actually, even if there was a way to disable standard conversions, - it would still be better to reject them here so that we can - provide a superior diagnostic. */ - if (!same_type_p (TREE_TYPE (expr), type)) - { - if (complain & tf_error) - { - error ("%qE is not a valid template argument for type %qT " - "because it is of type %qT", expr, type, - TREE_TYPE (expr)); - /* If we are just one standard conversion off, explain. */ - if (can_convert_standard (type, TREE_TYPE (expr), complain)) - inform (input_location, - "standard conversions are not allowed in this context"); - } - return NULL_TREE; - } } /* [temp.arg.nontype]/5, bullet 7 @@ -6921,7 +6906,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) expression must be a pointer-to-member constant. */ if (!value_dependent_expression_p (expr) && !check_valid_ptrmem_cst_expr (type, expr, complain)) - return error_mark_node; + return NULL_TREE; expr = perform_qualification_conversions (type, expr); if (expr == error_mark_node) diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 334a6f5938b..34d475b98f0 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -6710,12 +6710,13 @@ tree convert_ptrmem (tree type, tree expr, bool allow_inverse_p, bool c_cast_p, tsubst_flags_t complain) { + if (same_type_p (type, TREE_TYPE (expr))) + return expr; + if (TYPE_PTRDATAMEM_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, @@ -6727,6 +6728,8 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p, { tree cond, op1, op2; + if (TREE_CODE (expr) == PTRMEM_CST) + expr = cplus_expand_constant (expr); cond = cp_build_binary_op (input_location, EQ_EXPR, expr, -- 2.30.2