This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR c++/21802 (two-stage name lookup fails for operators)


On Mon, 14 Dec 2015, Jason Merrill wrote:

> On 12/12/2015 06:32 PM, Patrick Palka wrote:
>>> >This should use cp_tree_operand_length.
>> Hmm, I don't immediately see how I can use this function here.  It
>> expects a tree but I dont have an appropriate tree to give to it, only a
>> tree_code.
>
> True.  So let's introduce cp_tree_code_length next to cp_tree_operand_length.
>
> Jason
>
>

Like this?  Incremental diff followed by patch v4:

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
 index 3487d77..59c70b2 100644
 --- a/gcc/cp/cp-tree.h
 +++ b/gcc/cp/cp-tree.h
 @@ -6477,6 +6477,7 @@ extern bool is_lambda_ignored_entity            (tree);

 /* in tree.c */
 extern int cp_tree_operand_length		(const_tree);
+extern int cp_tree_code_length			(enum tree_code);
 void cp_free_lang_data 				(tree t);
 extern tree force_target_expr			(tree, tree, tsubst_flags_t);
 extern tree build_target_expr_with_type		(tree, tree, tsubst_flags_t);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
 index ca72877..6e671b7 100644
 --- a/gcc/cp/tree.c
 +++ b/gcc/cp/tree.c
 @@ -2766,14 +2766,10 @@ build_min_non_dep_op_overload (enum tree_code op,

   nargs = call_expr_nargs (non_dep);

-  if (op == PREINCREMENT_EXPR
-      || op == PREDECREMENT_EXPR)
-    expected_nargs = 1;
-  else if (op == MODOP_EXPR
-	   || op == ARRAY_REF)
-    expected_nargs = 2;
-  else
-    expected_nargs = TREE_CODE_LENGTH (op);
+  expected_nargs = cp_tree_code_length (op);
+  if (op == POSTINCREMENT_EXPR
+      || op == POSTDECREMENT_EXPR)
+    expected_nargs += 1;
   gcc_assert (nargs == expected_nargs);

   args = make_tree_vector ();
 @@ -4450,6 +4446,32 @@ cp_tree_operand_length (const_tree t)
     }
 }

+/* Like cp_tree_operand_length, but takes a tree_code CODE.  */
+
+int
+cp_tree_code_length (enum tree_code code)
+{
+  gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      return 1;
+
+    case ARRAY_REF:
+      return 2;
+
+    case EXPR_PACK_EXPANSION:
+      return 1;
+
+    default:
+      return TREE_CODE_LENGTH (code);
+    }
+}
+
 /* Implement -Wzero_as_null_pointer_constant.  Return true if the
    conditions for the warning hold, false otherwise.  */
 bool
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
 index 2e5e46e..39c1af2 100644
 --- a/gcc/cp/typeck.c
 +++ b/gcc/cp/typeck.c
 @@ -7864,7 +7864,7 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
 	    {
 	      if (overload != NULL_TREE)
 		return (build_min_non_dep_op_overload
-			(MODOP_EXPR, rval, overload, orig_lhs, orig_rhs));
+			(MODIFY_EXPR, rval, overload, orig_lhs, orig_rhs));

 	      return (build_min_non_dep
 		      (MODOP_EXPR, rval, orig_lhs, op, orig_rhs));

-- 8< --

Bootstrapped and regtested on x86_64-pc-linux-gnu.

gcc/cp/ChangeLog:

	PR c++/21802
	PR c++/53223
	* cp-tree.h (cp_tree_code_length): Declare.
	(build_min_non_dep_op_overload): Declare.
	* tree.c (cp_tree_code_length): Define.
	(build_min_non_dep_op_overload): Define.
	(build_win_non_dep_call_vec): Copy the KOENIG_LOOKUP_P flag.
	* typeck.c (build_x_indirect_ref): Use
	build_min_non_dep_op_overload when the given expression
	has been resolved to an operator overload.
	(build_x_binary_op): Likewise.
	(build_x_array_ref): Likewise.
	(build_x_unary_op): Likewise.
	(build_x_compound_expr): Likewise.
	(build_x_modify_expr): Likewise.
	* decl2.c (grok_array_decl): Likewise.
	* call.c (build_new_op_1): If during template processing we
	chose an operator overload that is a hidden friend function, set
	the call's KOENIG_LOOKUP_P flag to 1.

gcc/testsuite/ChangeLog:

	PR c++/21802
	PR c++/53223
	* g++.dg/cpp0x/pr53223.C: New test.
	* g++.dg/lookup/pr21802.C: New test.
	* g++.dg/lookup/two-stage4.C: Remove XFAIL.
---
 gcc/cp/call.c                            |  13 ++
 gcc/cp/cp-tree.h                         |   2 +
 gcc/cp/decl2.c                           |  13 +-
 gcc/cp/tree.c                            |  89 ++++++++++
 gcc/cp/typeck.c                          | 100 ++++++++---
 gcc/testsuite/g++.dg/cpp0x/pr53223.C     |  45 +++++
 gcc/testsuite/g++.dg/lookup/pr21802.C    | 276 +++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/lookup/two-stage4.C |   2 +-
 8 files changed, 517 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/pr53223.C
 create mode 100644 gcc/testsuite/g++.dg/lookup/pr21802.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 117dd79..cdfa01a 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5630,6 +5630,19 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
 	    result = error_mark_node;
 	  else
 	    result = build_over_call (cand, LOOKUP_NORMAL, complain);
+
+	  if (processing_template_decl
+	      && result != NULL_TREE
+	      && result != error_mark_node
+	      && DECL_HIDDEN_FRIEND_P (cand->fn))
+	    {
+	      tree call = result;
+	      if (REFERENCE_REF_P (call))
+		call = TREE_OPERAND (call, 0);
+	      /* This prevents build_new_function_call from discarding this
+		 function during instantiation of the enclosing template.  */
+	      KOENIG_LOOKUP_P (call) = 1;
+	    }
 	}
       else
 	{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6190f4e..d5e3acd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6477,6 +6477,7 @@ extern bool is_lambda_ignored_entity            (tree);
 
 /* in tree.c */
 extern int cp_tree_operand_length		(const_tree);
+extern int cp_tree_code_length			(enum tree_code);
 void cp_free_lang_data 				(tree t);
 extern tree force_target_expr			(tree, tree, tsubst_flags_t);
 extern tree build_target_expr_with_type		(tree, tree, tsubst_flags_t);
@@ -6513,6 +6514,7 @@ extern tree build_min				(enum tree_code, tree, ...);
 extern tree build_min_nt_loc			(location_t, enum tree_code,
 						 ...);
 extern tree build_min_non_dep			(enum tree_code, tree, ...);
+extern tree build_min_non_dep_op_overload	(enum tree_code, tree, tree, ...);
 extern tree build_min_non_dep_call_vec		(tree, tree, vec<tree, va_gc> *);
 extern tree build_cplus_new			(tree, tree, tsubst_flags_t);
 extern tree build_aggr_init_expr		(tree, tree);
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 2cc51d6..5ae6266 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -354,6 +354,7 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
   tree expr;
   tree orig_array_expr = array_expr;
   tree orig_index_exp = index_exp;
+  tree overload = NULL_TREE;
 
   if (error_operand_p (array_expr) || error_operand_p (index_exp))
     return error_mark_node;
@@ -379,7 +380,7 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
       if (decltype_p)
 	complain |= tf_decltype;
       expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, array_expr,
-			   index_exp, NULL_TREE, /*overload=*/NULL, complain);
+			   index_exp, NULL_TREE, &overload, complain);
     }
   else
     {
@@ -424,8 +425,14 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
       expr = build_array_ref (input_location, array_expr, index_exp);
     }
   if (processing_template_decl && expr != error_mark_node)
-    return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp,
-			      NULL_TREE, NULL_TREE);
+    {
+      if (overload != NULL_TREE)
+	return (build_min_non_dep_op_overload
+		(ARRAY_REF, expr, overload, orig_array_expr, orig_index_exp));
+
+      return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp,
+				NULL_TREE, NULL_TREE);
+    }
   return expr;
 }
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 5dad0a7..0c0987d 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2741,9 +2741,72 @@ build_min_non_dep_call_vec (tree non_dep, tree fn, vec<tree, va_gc> *argvec)
     non_dep = TREE_OPERAND (non_dep, 0);
   TREE_TYPE (t) = TREE_TYPE (non_dep);
   TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (non_dep);
+  KOENIG_LOOKUP_P (t) = KOENIG_LOOKUP_P (non_dep);
   return convert_from_reference (t);
 }
 
+/* Similar to build_min_non_dep, but for expressions that have been resolved to
+   a call to an operator overload.  OP is the operator that has been
+   overloaded.  NON_DEP is the non-dependent expression that's been built,
+   which should be a CALL_EXPR or an INDIRECT_REF to a CALL_EXPR.  OVERLOAD is
+   the overload that NON_DEP is calling.  */
+
+tree
+build_min_non_dep_op_overload (enum tree_code op,
+			       tree non_dep,
+			       tree overload, ...)
+{
+  va_list p;
+  int nargs, expected_nargs;
+  tree fn, call;
+  vec<tree, va_gc> *args;
+
+  if (REFERENCE_REF_P (non_dep))
+    non_dep = TREE_OPERAND (non_dep, 0);
+
+  nargs = call_expr_nargs (non_dep);
+
+  expected_nargs = cp_tree_code_length (op);
+  if (op == POSTINCREMENT_EXPR
+      || op == POSTDECREMENT_EXPR)
+    expected_nargs += 1;
+  gcc_assert (nargs == expected_nargs);
+
+  args = make_tree_vector ();
+  va_start (p, overload);
+
+  if (TREE_CODE (TREE_TYPE (overload)) == FUNCTION_TYPE)
+    {
+      fn = overload;
+      for (int i = 0; i < nargs; i++)
+	{
+	  tree arg = va_arg (p, tree);
+	  vec_safe_push (args, arg);
+	}
+    }
+  else if (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE)
+    {
+      tree object = va_arg (p, tree);
+      tree binfo = TYPE_BINFO (TREE_TYPE (object));
+      tree method = build_baselink (binfo, binfo, overload, NULL_TREE);
+      fn = build_min (COMPONENT_REF, TREE_TYPE (overload),
+		      object, method, NULL_TREE);
+      for (int i = 1; i < nargs; i++)
+	{
+	  tree arg = va_arg (p, tree);
+	  vec_safe_push (args, arg);
+	}
+    }
+  else
+   gcc_unreachable ();
+
+  va_end (p);
+  call = build_min_non_dep_call_vec (non_dep, fn, args);
+  release_tree_vector (args);
+
+  return call;
+}
+
 tree
 get_type_decl (tree t)
 {
@@ -4383,6 +4446,32 @@ cp_tree_operand_length (const_tree t)
     }
 }
 
+/* Like cp_tree_operand_length, but takes a tree_code CODE.  */
+
+int
+cp_tree_code_length (enum tree_code code)
+{
+  gcc_assert (TREE_CODE_CLASS (code) != tcc_vl_exp);
+
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      return 1;
+
+    case ARRAY_REF:
+      return 2;
+
+    case EXPR_PACK_EXPANSION:
+      return 1;
+
+    default:
+      return TREE_CODE_LENGTH (code);
+    }
+}
+
 /* Implement -Wzero_as_null_pointer_constant.  Return true if the
    conditions for the warning hold, false otherwise.  */
 bool
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 17671ee..39c1af2 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2905,6 +2905,7 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring,
 {
   tree orig_expr = expr;
   tree rval;
+  tree overload = NULL_TREE;
 
   if (processing_template_decl)
     {
@@ -2917,12 +2918,18 @@ build_x_indirect_ref (location_t loc, tree expr, ref_operator errorstring,
     }
 
   rval = build_new_op (loc, INDIRECT_REF, LOOKUP_NORMAL, expr,
-		       NULL_TREE, NULL_TREE, /*overload=*/NULL, complain);
+		       NULL_TREE, NULL_TREE, &overload, complain);
   if (!rval)
     rval = cp_build_indirect_ref (expr, errorstring, complain);
 
   if (processing_template_decl && rval != error_mark_node)
-    return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
+    {
+      if (overload != NULL_TREE)
+	return (build_min_non_dep_op_overload
+		(INDIRECT_REF, rval, overload, orig_expr));
+
+      return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
+    }
   else
     return rval;
 }
@@ -3814,12 +3821,13 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
 tree
 build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
 		   enum tree_code arg1_code, tree arg2,
-		   enum tree_code arg2_code, tree *overload,
+		   enum tree_code arg2_code, tree *overload_p,
 		   tsubst_flags_t complain)
 {
   tree orig_arg1;
   tree orig_arg2;
   tree expr;
+  tree overload = NULL_TREE;
 
   orig_arg1 = arg1;
   orig_arg2 = arg2;
@@ -3837,7 +3845,10 @@ build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
     expr = build_m_component_ref (arg1, arg2, complain);
   else
     expr = build_new_op (loc, code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
-			 overload, complain);
+			 &overload, complain);
+
+  if (overload_p != NULL)
+    *overload_p = overload;
 
   /* Check for cases such as x+y<<z which users are likely to
      misinterpret.  But don't warn about obj << x + y, since that is a
@@ -3853,7 +3864,13 @@ build_x_binary_op (location_t loc, enum tree_code code, tree arg1,
 			    arg2_code, orig_arg2);
 
   if (processing_template_decl && expr != error_mark_node)
-    return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
+    {
+      if (overload != NULL_TREE)
+	return (build_min_non_dep_op_overload
+		(code, expr, overload, orig_arg1, orig_arg2));
+
+      return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
+    }
 
   return expr;
 }
@@ -3867,6 +3884,7 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2,
   tree orig_arg1 = arg1;
   tree orig_arg2 = arg2;
   tree expr;
+  tree overload = NULL_TREE;
 
   if (processing_template_decl)
     {
@@ -3879,11 +3897,17 @@ build_x_array_ref (location_t loc, tree arg1, tree arg2,
     }
 
   expr = build_new_op (loc, ARRAY_REF, LOOKUP_NORMAL, arg1, arg2,
-		       NULL_TREE, /*overload=*/NULL, complain);
+		       NULL_TREE, &overload, complain);
 
   if (processing_template_decl && expr != error_mark_node)
-    return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2,
-			      NULL_TREE, NULL_TREE);
+    {
+      if (overload != NULL_TREE)
+	return (build_min_non_dep_op_overload
+		(ARRAY_REF, expr, overload, orig_arg1, orig_arg2));
+
+      return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2,
+				NULL_TREE, NULL_TREE);
+    }
   return expr;
 }
 
@@ -5278,6 +5302,7 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
   tree orig_expr = xarg;
   tree exp;
   int ptrmem = 0;
+  tree overload = NULL_TREE;
 
   if (processing_template_decl)
     {
@@ -5305,7 +5330,8 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
     /* Don't look for a function.  */;
   else
     exp = build_new_op (loc, code, LOOKUP_NORMAL, xarg, NULL_TREE,
-			NULL_TREE, /*overload=*/NULL, complain);
+			NULL_TREE, &overload, complain);
+
   if (!exp && code == ADDR_EXPR)
     {
       if (is_overloaded_fn (xarg))
@@ -5371,8 +5397,14 @@ build_x_unary_op (location_t loc, enum tree_code code, cp_expr xarg,
     }
 
   if (processing_template_decl && exp != error_mark_node)
-    exp = build_min_non_dep (code, exp, orig_expr,
-			     /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE);
+    {
+      if (overload != NULL_TREE)
+	return (build_min_non_dep_op_overload
+		(code, exp, overload, orig_expr, integer_zero_node));
+
+      exp = build_min_non_dep (code, exp, orig_expr,
+			       /*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE);
+    }
   if (TREE_CODE (exp) == ADDR_EXPR)
     PTRMEM_OK_P (exp) = ptrmem;
   return exp;
@@ -6335,6 +6367,7 @@ build_x_compound_expr (location_t loc, tree op1, tree op2,
   tree result;
   tree orig_op1 = op1;
   tree orig_op2 = op2;
+  tree overload = NULL_TREE;
 
   if (processing_template_decl)
     {
@@ -6346,12 +6379,18 @@ build_x_compound_expr (location_t loc, tree op1, tree op2,
     }
 
   result = build_new_op (loc, COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2,
-			 NULL_TREE, /*overload=*/NULL, complain);
+			 NULL_TREE, &overload, complain);
   if (!result)
     result = cp_build_compound_expr (op1, op2, complain);
 
   if (processing_template_decl && result != error_mark_node)
-    return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
+    {
+      if (overload != NULL_TREE)
+	return (build_min_non_dep_op_overload
+		(COMPOUND_EXPR, result, overload, orig_op1, orig_op2));
+
+      return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
+    }
 
   return result;
 }
@@ -7794,19 +7833,42 @@ cp_expr
 build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
 		     tree rhs, tsubst_flags_t complain)
 {
+  tree orig_lhs = lhs;
+  tree orig_rhs = rhs;
+  tree overload = NULL_TREE;
+  tree op = build_nt (modifycode, NULL_TREE, NULL_TREE);
+
   if (processing_template_decl)
-    return build_min_nt_loc (loc, MODOP_EXPR, lhs,
-			     build_min_nt_loc (loc, modifycode, NULL_TREE,
-					       NULL_TREE), rhs);
+    {
+      if (modifycode == NOP_EXPR
+	  || type_dependent_expression_p (lhs)
+	  || type_dependent_expression_p (rhs))
+        return build_min_nt_loc (loc, MODOP_EXPR, lhs,
+				 build_min_nt_loc (loc, modifycode, NULL_TREE,
+						   NULL_TREE), rhs);
+
+      lhs = build_non_dependent_expr (lhs);
+      rhs = build_non_dependent_expr (rhs);
+    }
 
   if (modifycode != NOP_EXPR)
     {
-      tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
-				make_node (modifycode), /*overload=*/NULL,
-				complain);
+      tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL,
+				lhs, rhs, op, &overload, complain);
       if (rval)
 	{
+	  if (rval == error_mark_node)
+	    return rval;
 	  TREE_NO_WARNING (rval) = 1;
+	  if (processing_template_decl)
+	    {
+	      if (overload != NULL_TREE)
+		return (build_min_non_dep_op_overload
+			(MODIFY_EXPR, rval, overload, orig_lhs, orig_rhs));
+
+	      return (build_min_non_dep
+		      (MODOP_EXPR, rval, orig_lhs, op, orig_rhs));
+	    }
 	  return rval;
 	}
     }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53223.C b/gcc/testsuite/g++.dg/cpp0x/pr53223.C
new file mode 100644
index 0000000..b6ccd50
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr53223.C
@@ -0,0 +1,45 @@
+// PR c++/53223
+// { dg-do compile { target c++11 } }
+
+#include <type_traits>
+
+#define SA(x) static_assert ((x), #x)
+
+struct A
+{
+  int good() const;
+  int operator *() const;
+  int operator ++() const;
+  int operator [](int) const;
+};
+
+int operator-- (const A&);
+
+template<typename T>
+void func(T t)
+{
+  A x;
+  auto &&g1 = x.good();
+  auto &&g2 = x.operator*();
+  auto &&error1 = *x;
+  auto &&error2 = ++x;
+  auto &&error3 = --x;
+  auto &&error4 = x[5];
+  SA ((std::is_same<int &&, decltype (error1)>::value));
+  SA ((std::is_same<int &&, decltype (error2)>::value));
+  SA ((std::is_same<int &&, decltype (error3)>::value));
+  SA ((std::is_same<int &&, decltype (error4)>::value));
+}
+
+void func2(int)
+{
+  A x;
+  auto &&g = *x;
+}
+
+int main()
+{
+  func(0);
+  func2(0);
+}
+
diff --git a/gcc/testsuite/g++.dg/lookup/pr21802.C b/gcc/testsuite/g++.dg/lookup/pr21802.C
new file mode 100644
index 0000000..139f7b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/pr21802.C
@@ -0,0 +1,276 @@
+// PR c++/21802
+// { dg-do run }
+#include <cassert>
+
+struct X;
+int I = 6;
+
+/* A mostly exhaustive and ad-hoc assortment of operator overloads and calls
+   thereof, to stress-test two-stage name lookup of operators inside template
+   definitions and then to verify that the calls get built correctly.  */
+
+template <typename T>
+inline int operator+(const X &, T x) { return x; }
+inline int operator-(const X &, int x) { return x; }
+inline int operator*(const X &, int x) { return x; }
+inline int operator/(const X &, int x) { return x; }
+inline int operator+=(const X &, int x) { return x; }
+
+struct X
+{
+  X () : m (1) { }
+  template <typename T>
+  int operator%(T x) { return m + x; }
+  virtual int operator>>(int x) { return m + x; }
+  int operator<<(int x) { return m + x; }
+  int operator&(int x) { return m + x; }
+  int operator|(int x) { return m + x; }
+  int operator^(int x) { return m + x; }
+  int operator&&(int x) { return m + x; }
+  int operator||(int x) { return m + x; }
+  friend int operator==(X o, int x) { return o.m + x; }
+  int operator!=(int x) { return m + x; }
+  int operator<(int x) { return m + x; }
+  int operator<=(int x) { return m + x; }
+  int operator>(int x) { return m + x; }
+  int operator>=(int x) { return m + x; }
+  int operator*() { return m + I; }
+  int operator!() { return m + I; }
+  int operator~() { return m + I; }
+  int operator++() { return m + I + 100; }
+  int operator--() { return m + I + 100; }
+  int operator++(int) { return m + I; }
+  int operator--(int) { return m + I; }
+  int operator()() { return m + I; }
+  int operator,(int x) { return m + x; }
+  int operator[](int x) { return m + x; }
+  int operator*=(int x) { return m + x; }
+  int operator-=(int x) { return m + x; }
+  int operator/=(int x) { return m + x; }
+  virtual int operator& () { return m + I; }
+  int m;
+};
+struct Y : virtual X
+{
+  /* Virtual override.  */
+  int operator>>(int x) { return m + x + 1; }
+  int operator& () { return m + I + 1; }
+
+  /* Not virtual.  */
+  template <typename T>
+  int operator&(T x) { return m + x + 1; }
+  friend int operator==(Y o, int x) { return o.m + x + 1; }
+};
+
+/* The folloiwng "FooN" functions each contain a different way to call and to
+   resolve these operator overloads.  */
+
+template <typename T>
+void
+Foo1 (T)
+{
+  Y x;
+  { int t = x + I; assert (t == 6); }
+  { int t = x - I; assert (t == 6); }
+  { int t = x * I; assert (t == 6); }
+  { int t = x / I; assert (t == 6); }
+  { int t = (x+=I); assert (t == 6); }
+
+  { int t = x % I; assert (t == 7); }
+  { int t = x << I; assert (t == 7); }
+  { int t = x | I; assert (t == 7); }
+  { int t = x && I; assert (t == 7); }
+  { int t = x || I; assert (t == 7); }
+  { int t = x != I; assert (t == 7); }
+  { int t = x < I; assert (t == 7); }
+  { int t = x <= I; assert (t == 7); }
+  { int t = x > I; assert (t == 7); }
+  { int t = x >= I; assert (t == 7); }
+  { int t = *x; assert (t == 7); }
+  { int t = !x; assert (t == 7); }
+  { int t = ~x; assert (t == 7); }
+  { int t = x++; assert (t == 7); }
+  { int t = x--; assert (t == 7); }
+  { int t = ++x; assert (t == 107); }
+  { int t = --x; assert (t == 107); }
+  { int t = x (); assert (t == 7); }
+  { int t = (x, I); assert (t == 7); }
+  { int t = x[I]; assert (t == 7); }
+  { int t = (x-=I); assert (t == 7); }
+  { int t = (x/=I); assert (t == 7); }
+  { int t = (x*=I); assert (t == 7); }
+
+  { int t = x >> I; assert (t == 8); }
+  { int t = x & I; assert (t == 8); }
+  { int t = &x; assert (t == 8); }
+  { int t = x == I; assert (t == 8); }
+}
+
+template <typename T>
+void
+Foo2 (T)
+{
+  X x;
+  { int t = x + I; assert (t == 6); }
+  { int t = x - I; assert (t == 6); }
+  { int t = x * I; assert (t == 6); }
+  { int t = x / I; assert (t == 6); }
+  { int t = (x+=I); assert (t == 6); }
+
+  { int t = x % I; assert (t == 7); }
+  { int t = x >> I; assert (t == 7); }
+  { int t = x << I; assert (t == 7); }
+  { int t = x | I; assert (t == 7); }
+  { int t = x && I; assert (t == 7); }
+  { int t = x || I; assert (t == 7); }
+  { int t = x == I; assert (t == 7); }
+  { int t = x != I; assert (t == 7); }
+  { int t = x < I; assert (t == 7); }
+  { int t = x <= I; assert (t == 7); }
+  { int t = x > I; assert (t == 7); }
+  { int t = x >= I; assert (t == 7); }
+  { int t = *x; assert (t == 7); }
+  { int t = !x; assert (t == 7); }
+  { int t = ~x; assert (t == 7); }
+  { int t = x++; assert (t == 7); }
+  { int t = x--; assert (t == 7); }
+  { int t = ++x; assert (t == 107); }
+  { int t = --x; assert (t == 107); }
+  { int t = x (); assert (t == 7); }
+  { int t = (x, I); assert (t == 7); }
+  { int t = x[I]; assert (t == 7); }
+  { int t = &x; assert (t == 7); }
+  { int t = (x-=I); assert (t == 7); }
+  { int t = (x/=I); assert (t == 7); }
+  { int t = (x*=I); assert (t == 7); }
+  { int t = x & I; assert (t == 7); }
+}
+
+template <typename T>
+void
+Foo3 (T)
+{
+  Y o;
+  X &x = o;
+  { int t = x + I; assert (t == 6); }
+  { int t = x - I; assert (t == 6); }
+  { int t = x * I; assert (t == 6); }
+  { int t = x / I; assert (t == 6); }
+  { int t = (x+=I); assert (t == 6); }
+
+  { int t = x % I; assert (t == 7); }
+  { int t = x << I; assert (t == 7); }
+  { int t = x | I; assert (t == 7); }
+  { int t = x && I; assert (t == 7); }
+  { int t = x || I; assert (t == 7); }
+  { int t = x == I; assert (t == 7); }
+  { int t = x != I; assert (t == 7); }
+  { int t = x < I; assert (t == 7); }
+  { int t = x <= I; assert (t == 7); }
+  { int t = x > I; assert (t == 7); }
+  { int t = x >= I; assert (t == 7); }
+  { int t = *x; assert (t == 7); }
+  { int t = !x; assert (t == 7); }
+  { int t = ~x; assert (t == 7); }
+  { int t = x++; assert (t == 7); }
+  { int t = x--; assert (t == 7); }
+  { int t = ++x; assert (t == 107); }
+  { int t = --x; assert (t == 107); }
+  { int t = x (); assert (t == 7); }
+  { int t = (x, I); assert (t == 7); }
+  { int t = x[I]; assert (t == 7); }
+  { int t = (x-=I); assert (t == 7); }
+  { int t = (x/=I); assert (t == 7); }
+  { int t = (x*=I); assert (t == 7); }
+
+  { int t = x & I; assert (t == 7); }
+  { int t = x >> I; assert (t == 8); }
+  { int t = &x; assert (t == 8); }
+}
+
+template <typename T>
+void
+Foo4 (T)
+{
+  Y x;
+  { int t = operator+ (x, I); assert (t == 6); }
+  { int t = operator- (x, I); assert (t == 6); }
+  { int t = operator* (x, I); assert (t == 6); }
+  { int t = operator/ (x, I); assert (t == 6); }
+  { int t = operator+= (x, I); assert (t == 6); }
+
+  { int t = x.operator% (I); assert (t == 7); }
+  { int t = x.operator<< (I); assert (t == 7); }
+  { int t = x.operator| (I); assert (t == 7); }
+  { int t = x.operator&& (I); assert (t == 7); }
+  { int t = x.operator|| (I); assert (t == 7); }
+  { int t = x.operator!= (I); assert (t == 7); }
+  { int t = x.operator< (I); assert (t == 7); }
+  { int t = x.operator<= (I); assert (t == 7); }
+  { int t = x.operator> (I); assert (t == 7); }
+  { int t = x.operator>= (I); assert (t == 7); }
+  { int t = x.operator* (); assert (t == 7); }
+  { int t = x.operator! (); assert (t == 7); }
+  { int t = x.operator~ (); assert (t == 7); }
+  { int t = x.operator++ (0); assert (t == 7); }
+  { int t = x.operator-- (0); assert (t == 7); }
+  { int t = x.operator++ (); assert (t == 107); }
+  { int t = x.operator-- (); assert (t == 107); }
+  { int t = x.operator() (); assert (t == 7); }
+  { int t = x.operator, (I); assert (t == 7); }
+  { int t = x.operator[] (I); assert (t == 7); }
+  { int t = x.operator-= (I); assert (t == 7); }
+  { int t = x.operator/= (I); assert (t == 7); }
+  { int t = x.operator*= (I); assert (t == 7); }
+
+  { int t = x.operator>> (I); assert (t == 8); }
+  { int t = x.operator& (); assert (t == 8); }
+  { int t = x.operator& (I); assert (t == 8); }
+  { int t = operator== (x, I); assert (t == 8); }
+}
+
+
+/* These definitions should be irrelevant to operator lookup of non-dependent
+   expressions inside the above templates since they are not in scope at
+   template-definition time (even though they are in scope at instantiation
+   time).  */
+inline int operator+(const Y&, int) { return 11; }
+inline int operator-(const Y&, int) { return 11; }
+inline int operator*(const Y&, int) { return 11; }
+inline int operator/(const Y&, int) { return 11; }
+inline int operator%(const Y&, int) { return 11; }
+inline int operator>>(const Y&, int) { return 11; }
+inline int operator<<(const Y&, int) { return 11; }
+inline int operator&(const Y&, int) { return 11; }
+inline int operator|(const Y&, int) { return 11; }
+inline int operator^(const Y&, int) { return 11; }
+inline int operator&&(const Y&, int) { return 11; }
+inline int operator||(const Y&, int) { return 11; }
+inline int operator==(const Y&, int) { return 11; }
+inline int operator!=(const Y&, int) { return 11; }
+inline int operator<(const Y&, int) { return 11; }
+inline int operator<=(const Y&, int) { return 11; }
+inline int operator>(const Y&, int) { return 11; }
+inline int operator>=(const Y&, int) { return 11; }
+inline int operator*(const Y&) { return 11; }
+inline int operator!(const Y&) { return 11; }
+inline int operator~(const Y&) { return 11; }
+inline int operator++(const Y&) { return 11; }
+inline int operator--(const Y&) { return 11; }
+inline int operator++(const Y&, int) { return 11; }
+inline int operator--(const Y&, int) { return 11; }
+inline int operator,(const Y&, int) { return 11; }
+inline int operator&(const Y&) { return 11; }
+inline int operator+=(const Y&, int x) { return 11; }
+inline int operator*=(const Y&, int x) { return 11; }
+inline int operator-=(const Y&, int x) { return 11; }
+inline int operator/=(const Y&, int x) { return 11; }
+
+int
+main ()
+{
+  Foo1 (0);
+  Foo2 (0);
+  Foo3 (0);
+  Foo4 (0);
+}
diff --git a/gcc/testsuite/g++.dg/lookup/two-stage4.C b/gcc/testsuite/g++.dg/lookup/two-stage4.C
index 7d97109..a89e618 100644
--- a/gcc/testsuite/g++.dg/lookup/two-stage4.C
+++ b/gcc/testsuite/g++.dg/lookup/two-stage4.C
@@ -8,7 +8,7 @@ template<typename T> bool operator==(wrap<T>, wrap<T>);
 template<typename T>
 void g(T, wrap<wrap<int> > x)
 {
-  bool b = x == x; // { dg-bogus "" "" { xfail *-*-* } }
+  bool b = x == x; // { dg-bogus "" "" }
 }
 
 template<typename T> void operator==(wrap<wrap<T> >, wrap<wrap<T> >);
-- 
2.7.0.rc0.50.g1470d8f.dirty


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]