OSDN Git Service

cp/
authorpaolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Jul 2010 11:47:58 +0000 (11:47 +0000)
committerpaolo <paolo@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Jul 2010 11:47:58 +0000 (11:47 +0000)
2010-07-13  Paolo Carlini  <paolo.carlini@oracle.com>

PR c++/44908
* call.c (convert_like_real): Adjust convert_ptrmem call, pass
complain argument.
* typeck.c (get_delta_difference): Update prototype, add a
tsubst_flags_t parameter; update get_delta_difference_1 calls and
add checks for error_mark_node.
(get_delta_difference_1): Update prototype, add a tsubst_flags_t
parameter; update lookup_base call.
(build_ptrmemfunc): Update prototype, add a tsubst_flags_t
parameter; update get_delta_difference call and add check for
error_mark_node.
(convert_ptrmem): Update prototype, add a tsubst_flags_t
parameter; update get_delta_difference call and add check for
error_mark_node;  update build_ptrmemfunc call.
(build_static_cast_1): Adjust convert_ptrmem call.
(expand_ptrmemfunc_cst): Adjust get_delta_difference call.
(cp_build_unary_op): Adjust build_ptrmemfunc call.
* cvt.c (cp_convert_to_pointer, convert_force): Adjust convert_ptrmem
and build_ptrmemfunc calls.
* cp-tree.h: Update build_ptrmemfunc and convert_ptrmem prototypes.

testsuite/
2010-07-13  Paolo Carlini  <paolo.carlini@oracle.com>

PR c++/44908
* g++.dg/template/sfinae21.C: New.
* g++.dg/template/sfinae22.C: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@162138 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/template/sfinae21.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/sfinae22.C [new file with mode: 0644]

index 27061ad..4e2c0e4 100644 (file)
@@ -1,3 +1,26 @@
+2010-07-13  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/44908
+       * call.c (convert_like_real): Adjust convert_ptrmem call, pass
+       complain argument.
+       * typeck.c (get_delta_difference): Update prototype, add a
+       tsubst_flags_t parameter; update get_delta_difference_1 calls and
+       add checks for error_mark_node.
+       (get_delta_difference_1): Update prototype, add a tsubst_flags_t
+       parameter; update lookup_base call.
+       (build_ptrmemfunc): Update prototype, add a tsubst_flags_t
+       parameter; update get_delta_difference call and add check for
+       error_mark_node.
+       (convert_ptrmem): Update prototype, add a tsubst_flags_t
+       parameter; update get_delta_difference call and add check for
+       error_mark_node;  update build_ptrmemfunc call.
+       (build_static_cast_1): Adjust convert_ptrmem call.
+       (expand_ptrmemfunc_cst): Adjust get_delta_difference call.
+       (cp_build_unary_op): Adjust build_ptrmemfunc call.
+       * cvt.c (cp_convert_to_pointer, convert_force): Adjust convert_ptrmem
+       and build_ptrmemfunc calls.
+       * cp-tree.h: Update build_ptrmemfunc and convert_ptrmem prototypes.
+
 2010-07-12  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/44907
index ca34a6c..1c64149 100644 (file)
@@ -5246,7 +5246,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
     case ck_pmem:
       return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
-                            c_cast_p);
+                            c_cast_p, complain);
 
     default:
       break;
index 08398aa..cf128dc 100644 (file)
@@ -5488,7 +5488,8 @@ extern int comp_ptr_ttypes                        (tree, tree);
 extern bool comp_ptr_ttypes_const              (tree, tree);
 extern bool error_type_p                       (const_tree);
 extern int ptr_reasonably_similar              (const_tree, const_tree);
-extern tree build_ptrmemfunc                   (tree, tree, int, bool);
+extern tree build_ptrmemfunc                   (tree, tree, int, bool,
+                                                tsubst_flags_t);
 extern int cp_type_quals                       (const_tree);
 extern int type_memfn_quals                    (const_tree);
 extern tree apply_memfn_quals                  (tree, cp_cv_quals);
@@ -5517,7 +5518,8 @@ extern tree non_reference                 (tree);
 extern tree lookup_anon_field                  (tree, tree);
 extern bool invalid_nonstatic_memfn_p          (const_tree, tsubst_flags_t);
 extern tree convert_member_func_to_ptr         (tree, tree);
-extern tree convert_ptrmem                     (tree, tree, bool, bool);
+extern tree convert_ptrmem                     (tree, tree, bool, bool,
+                                                tsubst_flags_t);
 extern int lvalue_or_else                      (tree, enum lvalue_use,
                                                  tsubst_flags_t);
 extern void check_template_keyword             (tree);
index 4fcba45..26c4442 100644 (file)
@@ -176,7 +176,7 @@ cp_convert_to_pointer (tree type, tree expr)
   else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
           || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
     return convert_ptrmem (type, expr, /*allow_inverse_p=*/false,
-                          /*c_cast_p=*/false);
+                          /*c_cast_p=*/false, tf_warning_or_error);
   else if (TYPE_PTRMEMFUNC_P (intype))
     {
       if (!warn_pmf2ptr)
@@ -200,7 +200,7 @@ cp_convert_to_pointer (tree type, tree expr)
     {
       if (TYPE_PTRMEMFUNC_P (type))
        return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
-                                /*c_cast_p=*/false);
+                                /*c_cast_p=*/false, tf_warning_or_error);
 
       if (TYPE_PTRMEM_P (type))
        {
@@ -1376,7 +1376,7 @@ convert_force (tree type, tree expr, int convtype)
       && TYPE_PTRMEMFUNC_P (type))
     /* compatible pointer to member functions.  */
     return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1,
-                            /*c_cast_p=*/1);
+                            /*c_cast_p=*/1, tf_warning_or_error);
 
   return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
 }
index fd8221c..d5e43de 100644 (file)
@@ -1,6 +1,6 @@
 /* Build expressions with type checking for C++ compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
@@ -53,7 +53,7 @@ static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
 static tree pointer_diff (tree, tree, tree);
-static tree get_delta_difference (tree, tree, bool, bool);
+static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 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);
@@ -5254,7 +5254,8 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
        {
          build_ptrmemfunc_type (argtype);
          val = build_ptrmemfunc (argtype, val, 0,
-                                 /*c_cast_p=*/false);
+                                 /*c_cast_p=*/false,
+                                 tf_warning_or_error);
        }
 
       return val;
@@ -5669,7 +5670,7 @@ check_for_casting_away_constness (tree src_type, tree dest_type,
 
 tree
 convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
-               bool c_cast_p)
+               bool c_cast_p, tsubst_flags_t complain)
 {
   if (TYPE_PTRMEM_P (type))
     {
@@ -5680,7 +5681,10 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
       delta = get_delta_difference (TYPE_PTRMEM_CLASS_TYPE (TREE_TYPE (expr)),
                                    TYPE_PTRMEM_CLASS_TYPE (type),
                                    allow_inverse_p,
-                                   c_cast_p);
+                                   c_cast_p, complain);
+      if (delta == error_mark_node)
+       return error_mark_node;
+
       if (!integer_zerop (delta))
        {
          tree cond, op1, op2;
@@ -5704,7 +5708,7 @@ convert_ptrmem (tree type, tree expr, bool allow_inverse_p,
     }
   else
     return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr,
-                            allow_inverse_p, c_cast_p);
+                            allow_inverse_p, c_cast_p, complain);
 }
 
 /* If EXPR is an INTEGER_CST and ORIG is an arithmetic constant, return
@@ -5940,7 +5944,7 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
          if (!c_cast_p)
            check_for_casting_away_constness (intype, type, STATIC_CAST_EXPR);
          return convert_ptrmem (type, expr, /*allow_inverse_p=*/1,
-                                c_cast_p);
+                                c_cast_p, tf_warning_or_error);
        }
     }
 
@@ -6855,20 +6859,32 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 
 /* Helper function for get_delta_difference which assumes FROM is a base
    class of TO.  Returns a delta for the conversion of pointer-to-member
-   of FROM to pointer-to-member of TO.  If the conversion is invalid,
+   of FROM to pointer-to-member of TO.  If the conversion is invalid and 
+   tf_error is not set in COMPLAIN returns error_mark_node, otherwise
    returns zero.  If FROM is not a base class of TO, returns NULL_TREE.
-   If C_CAST_P is true, this conversion is taking place as part of a C-style
-   cast.  */
+   If C_CAST_P is true, this conversion is taking place as part of a 
+   C-style cast.  */
 
 static tree
-get_delta_difference_1 (tree from, tree to, bool c_cast_p)
+get_delta_difference_1 (tree from, tree to, bool c_cast_p,
+                       tsubst_flags_t complain)
 {
   tree binfo;
   base_kind kind;
+  base_access access = c_cast_p ? ba_unique : ba_check;
+
+  /* Note: ba_quiet does not distinguish between access control and
+     ambiguity.  */
+  if (!(complain & tf_error))
+    access |= ba_quiet;
+
+  binfo = lookup_base (to, from, access, &kind);
 
-  binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
   if (kind == bk_inaccessible || kind == bk_ambig)
     {
+      if (!(complain & tf_error))
+       return error_mark_node;
+
       error ("   in pointer to member function conversion");
       return size_zero_node;
     }
@@ -6880,22 +6896,26 @@ get_delta_difference_1 (tree from, tree to, bool c_cast_p)
        /* FROM is a virtual base class of TO.  Issue an error or warning
           depending on whether or not this is a reinterpret cast.  */
        {
+         if (!(complain & tf_error))
+           return error_mark_node;
+
          error ("pointer to member conversion via virtual base %qT",
                 BINFO_TYPE (binfo_from_vbase (binfo)));
 
          return size_zero_node;
        }
       }
-    else
-      return NULL_TREE;
+  else
+    return NULL_TREE;
 }
 
 /* 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
-   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.
+   types.  If the conversion is invalid and tf_error is not set in
+   COMPLAIN, returns error_mark_node, otherwise returns an integer
+   constant of type PTRDIFF_TYPE_NODE and its value is zero if the
+   conversion is invalid.  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
@@ -6905,7 +6925,7 @@ get_delta_difference_1 (tree from, tree to, bool c_cast_p)
 static tree
 get_delta_difference (tree from, tree to,
                      bool allow_inverse_p,
-                     bool c_cast_p)
+                     bool c_cast_p, tsubst_flags_t complain)
 {
   tree result;
 
@@ -6913,25 +6933,37 @@ get_delta_difference (tree from, tree to,
     /* Pointer to member of incomplete class is permitted*/
     result = size_zero_node;
   else
-    result = get_delta_difference_1 (from, to, c_cast_p);
+    result = get_delta_difference_1 (from, to, c_cast_p, complain);
+
+  if (result == error_mark_node)
+    return error_mark_node;
 
   if (!result)
   {
     if (!allow_inverse_p)
       {
+       if (!(complain & tf_error))
+         return error_mark_node;
+
        error_not_base_type (from, to);
        error ("   in pointer to member conversion");
-       result = size_zero_node;
+       result = size_zero_node;
       }
     else
       {
-       result = get_delta_difference_1 (to, from, c_cast_p);
+       result = get_delta_difference_1 (to, from, c_cast_p, complain);
+
+       if (result == error_mark_node)
+         return error_mark_node;
 
        if (result)
          result = size_diffop_loc (input_location,
-                               size_zero_node, result);
+                                   size_zero_node, result);
        else
          {
+           if (!(complain & tf_error))
+             return error_mark_node;
+
            error_not_base_type (from, to);
            error ("   in pointer to member conversion");
            result = size_zero_node;
@@ -6990,7 +7022,8 @@ build_ptrmemfunc1 (tree type, tree delta, tree pfn)
    Return error_mark_node, if something goes wrong.  */
 
 tree
-build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
+build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p,
+                 tsubst_flags_t complain)
 {
   tree fn;
   tree pfn_type;
@@ -7017,7 +7050,9 @@ build_ptrmemfunc (tree type, tree pfn, int force, bool c_cast_p)
       n = get_delta_difference (TYPE_PTRMEMFUNC_OBJECT_TYPE (pfn_type),
                                TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type),
                                force,
-                               c_cast_p);
+                               c_cast_p, complain);
+      if (n == error_mark_node)
+       return error_mark_node;
 
       /* We don't have to do any conversion to convert a
         pointer-to-member to its own type.  But, we don't want to
@@ -7100,7 +7135,7 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
 
   /* First, calculate the adjustment to the function's class.  */
   *delta = get_delta_difference (fn_class, ptr_class, /*force=*/0,
-                                /*c_cast_p=*/0);
+                                /*c_cast_p=*/0, tf_warning_or_error);
 
   if (!DECL_VIRTUAL_P (fn))
     *pfn = convert (TYPE_PTRMEMFUNC_FN_TYPE (type), build_addr_func (fn));
index 9e53f92..186a4c6 100644 (file)
@@ -1,3 +1,9 @@
+2010-07-13  Paolo Carlini  <paolo.carlini@oracle.com>
+
+       PR c++/44908
+       * g++.dg/template/sfinae21.C: New.
+       * g++.dg/template/sfinae22.C: Likewise.
+
 2010-07-13  Kaz Kojima  <kkojima@gcc.gnu.org>
 
        * gcc.c-torture/execute/pr44683.x: New.
diff --git a/gcc/testsuite/g++.dg/template/sfinae21.C b/gcc/testsuite/g++.dg/template/sfinae21.C
new file mode 100644 (file)
index 0000000..6086f2f
--- /dev/null
@@ -0,0 +1,40 @@
+// PR c++/44908
+
+struct A { };
+
+struct B
+: public virtual A { };
+
+template<bool, typename T = void> struct enable_if { typedef T type; };
+template<typename T> struct enable_if<false, T> { };
+
+template<typename From, typename To>
+  class mini_is_convertible
+  {
+    typedef char one;
+    typedef struct { char arr[2]; } two;
+
+    template<typename To1>
+      static void test_aux(To1);
+
+    template<typename To1, typename From1>
+      static typename
+      enable_if<(sizeof(test_aux<To1>(From1()), 1) > 0), one>::type
+      test(int);
+
+    template<typename, typename>
+      static two test(...);
+
+    public:
+      static const bool value = sizeof(test<To, From>(0)) == 1;
+  }; 
+
+template<typename From, typename To>
+  const bool mini_is_convertible<From, To>::value;
+
+int Test1[mini_is_convertible<int (B::*) (int),
+         int (A::*) (int)>::value ? -1 : 1];
+int Test2[mini_is_convertible<int (B::*), int (A::*)>::value ? -1 : 1];
+int Test3[mini_is_convertible<int (A::*) (int),
+         int (B::*) (int)>::value ? -1 : 1];
+int Test4[mini_is_convertible<int (A::*), int (B::*)>::value ? -1 : 1];
diff --git a/gcc/testsuite/g++.dg/template/sfinae22.C b/gcc/testsuite/g++.dg/template/sfinae22.C
new file mode 100644 (file)
index 0000000..cdac99d
--- /dev/null
@@ -0,0 +1,39 @@
+// PR c++/44908
+// { dg-options "-std=c++0x" }
+
+#include <utility> 
+
+struct A { };
+
+struct B
+: public virtual A { };
+
+template<typename From, typename To>
+  class mini_is_convertible
+  {
+    typedef char one;
+    typedef struct { char arr[2]; } two;
+
+    template<typename To1>
+      static void test_aux(To1);
+
+    template<typename To1, typename From1>
+      static decltype(test_aux<To1>(std::declval<From1>()), one())
+      test(int);
+
+    template<typename, typename>
+      static two test(...);
+
+    public:
+      static const bool value = sizeof(test<To, From>(0)) == 1;
+  }; 
+
+template<typename From, typename To>
+  const bool mini_is_convertible<From, To>::value;
+
+static_assert (!mini_is_convertible<int (B::*) (int),
+              int (A::*) (int)>::value, "");
+static_assert (!mini_is_convertible<int (B::*), int (A::*)>::value, "");
+static_assert (!mini_is_convertible<int (A::*) (int),
+              int (B::*) (int)>::value, ""); 
+static_assert (!mini_is_convertible<int (A::*), int (B::*)>::value, "");