diff mbox

[C++] PR 44908 (SFINAE vs pointer to member via virtual base)

Message ID 4C3BA535.6060307@oracle.com
State New
Headers show

Commit Message

Paolo Carlini July 12, 2010, 11:28 p.m. UTC
Hi again,

these further bits from my __is_convertible_to work fix the SFINAE issue
with pointers to members when virtual inheritance is involved. Even if
the patch seems large, is indeed largely mechanical and ultimately very
focused on propagating tf_none to get_delta_difference_1 in case of SFINAE.

Tested x86_64-linux. Ok for mainline?

Thanks,
Paolo.

////////////////////
cp/
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.

Comments

Jason Merrill July 13, 2010, 1:01 a.m. UTC | #1
OK.

Jason
diff mbox

Patch

Index: testsuite/g++.dg/template/sfinae21.C
===================================================================
--- testsuite/g++.dg/template/sfinae21.C	(revision 0)
+++ testsuite/g++.dg/template/sfinae21.C	(revision 0)
@@ -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];
Index: testsuite/g++.dg/template/sfinae22.C
===================================================================
--- testsuite/g++.dg/template/sfinae22.C	(revision 0)
+++ testsuite/g++.dg/template/sfinae22.C	(revision 0)
@@ -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, "");
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 162112)
+++ cp/typeck.c	(working copy)
@@ -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,
 	{
 	  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, t
 
 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_i
       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_i
     }
   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_
 	  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 modi
 
 /* 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;
 
-  binfo = lookup_base (to, from, c_cast_p ? ba_unique : ba_check, &kind);
+  /* 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);
+
   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 @@  static tree
 	/* 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 @@  static tree
 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 @@  tree
       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
 
   /* 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: cp/call.c
===================================================================
--- cp/call.c	(revision 162113)
+++ cp/call.c	(working copy)
@@ -5246,7 +5246,7 @@  convert_like_real (conversion *convs, tree expr, t
 
     case ck_pmem:
       return convert_ptrmem (totype, expr, /*allow_inverse_p=*/false,
-			     c_cast_p);
+			     c_cast_p, complain);
 
     default:
       break;
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 162112)
+++ cp/cvt.c	(working copy)
@@ -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: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 162112)
+++ cp/cp-tree.h	(working copy)
@@ -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);