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)


This patch fixes name-lookup of operators in template definitions whose
operands are non-dependent expressions, i.e. PR c++/21802 (and
incidentally 53223).

The approach that this patch takes is to detect when build_new_op()
returns a call to an overloaded function and to store a call to this
overload intothe template AST instead of storing the raw operator
(an operator would be erroneously subject to overload resolution during
instantiation).

The new function build_min_non_dep_op_overload is the workhorse of the
patch.  It reconstructs the CALL_EXPR that would have been built had an
explicit operator+, operator* etc call been used, i.e. had the overload
gone through finish_call_expr() / build_new_method_call() instead of
through build_new_op().  The parameter OVERLOAD of this new function is
probably not strictly necessary -- one can probably just look at the
CALL_EXPR_FN of the parameter NON_DEP to figure out the overload to use
-- but since the requisite plumbing from build_new_op() already existed
to conveniently get at the overload information I thought I might as
well use it.

I have also created a test case that hopefully exercises all the changes
that were made and to verify that these operator calls are being built
correctly.

Does this approach seem adequate?  Bootstrap and regtesting in progress
on x86_64, OK to commit if testing succeeds?

gcc/cp/ChangeLog:

	PR c++/21802
	PR c++/53223
	* cp-tree.h (build_min_non_dep_op_overload): Declare.
	* tree.c (build_min_non_dep_op_overload): Define.
	* 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.

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/cp-tree.h                         |   1 +
 gcc/cp/tree.c                            |  64 ++++++++
 gcc/cp/typeck.c                          | 100 +++++++++---
 gcc/testsuite/g++.dg/cpp0x/pr53223.C     |  35 ++++
 gcc/testsuite/g++.dg/lookup/pr21802.C    | 271 +++++++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/lookup/two-stage4.C |   2 +-
 6 files changed, 453 insertions(+), 20 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/cp-tree.h b/gcc/cp/cp-tree.h
index 6190f4e..3487d77 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6513,6 +6513,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/tree.c b/gcc/cp/tree.c
index 5dad0a7..2635736 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2744,6 +2744,70 @@ build_min_non_dep_call_vec (tree non_dep, tree fn, vec<tree, va_gc> *argvec)
   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;
+  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);
+
+  if (op == PREINCREMENT_EXPR
+      || op == PREDECREMENT_EXPR)
+    gcc_assert (nargs == 1);
+  else if (op == MODOP_EXPR)
+    gcc_assert (nargs == 2);
+  else
+    gcc_assert (nargs == TREE_CODE_LENGTH (op));
+
+  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)
 {
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 17671ee..2e5e46e 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
+			(MODOP_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..4ca2da1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr53223.C
@@ -0,0 +1,35 @@
+// PR c++/53223
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  int good() const;
+  int operator *() const;
+  int operator ++() 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; // { dg-bogus "invalid initialization" }
+  auto &&error2 = ++x; // { dg-bogus "invalid initialization" }
+  auto &&error3 = --x; // { dg-bogus "invalid initialization" }
+}
+
+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..4909bad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/pr21802.C
@@ -0,0 +1,271 @@
+// 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.  */
+
+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; }
+inline int operator+=(const X &, int x) { return x; }
+
+struct X
+{
+  X () : m (1) { }
+  int operator%(int 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; }
+  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*() { 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.  */
+  int operator&(int x) { return 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 >= 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); }
+}
+
+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>= (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); }
+}
+
+
+/* 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 (but 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.6.4.491.gda30757.dirty


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