Overhaul pointer-to-member conversion and template argument handling.
authorJason Merrill <jason@redhat.com>
Sat, 10 Jun 2017 00:40:44 +0000 (20:40 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 10 Jun 2017 00:40:44 +0000 (20:40 -0400)
* 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
gcc/cp/call.c
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/pt.c
gcc/cp/typeck.c

index 8949f6b56f68196494619087f8f86533c751b26a..4e966a2e26fb8952377625694312eb7f94590622 100644 (file)
@@ -1,5 +1,16 @@
 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.
index 5e65bfbff4b56d2676427d1fc3a724f3a88924b2..a4b6a95f13e776a758e4061fbe850814ca41f9c2 100644 (file)
@@ -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)
index 8bbe950828f1e6ff5b8b97b8b03f32d4a70f2f65..ae24e4010ff11e7db805f0dcbb31dd1996da4a98 100644 (file)
@@ -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
              {
index 550dbf26a80a0ce3d81677dd3adc325a158aaa54..07da0cda5e741bf031149a1de9328fd640c80cca 100644 (file)
@@ -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);
index 6b28ef65074bfc5b30fbdf4c9562ddbae4825250..3460e1334294407238366a336c9d618a2ffa9bc1 100644 (file)
@@ -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;
index 40be3c1d22ff2302e9a3a9c0e9e5718ce81cf2b1..b537cb8a85d7d9111a1f513fdd1e3ea4afbd36b6 100644 (file)
@@ -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)
index 334a6f5938bbffe61b3bb505865fa9d5786a8179..34d475b98f0f3443b808102dcd708a82a916024f 100644 (file)
@@ -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,