2017-06-09 Jason Merrill <jason@redhat.com>
+ 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.
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)
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
{
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);
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. */
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;
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;
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;
}
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
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)
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,
{
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,