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]

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


On Thu, Dec 10, 2015 at 4:43 PM, Patrick Palka <patrick@parcs.ath.cx> wrote:
> 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?

Unfortunately this patch doesn't work properly on operator overloads
that are defined as friend functions.  E.g. the following now fails to
compile:

struct A
{
  friend int operator* (A);
};

template <typename T>
void func(T t)
{
  A x;
  int y = *x;
}

int main()
{
  func(0);
}

I think this happens because KOENIG_LOOKUP_P is not being properly set
in in the CALL_EXPR we are reconstructing.  Not sure how to fix that
yet.


>
> 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]