Fix PR c++/21802 (two-stage name lookup fails for operators)
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. From-SVN: r231640
This commit is contained in:
parent
8d3586e4e2
commit
fcb9363eb9
10 changed files with 548 additions and 24 deletions
|
@ -1,3 +1,25 @@
|
|||
2015-12-15 Patrick Palka <ppalka@gcc.gnu.org>
|
||||
|
||||
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.
|
||||
|
||||
2015-12-14 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/68309
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
100
gcc/cp/typeck.c
100
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
2015-12-14svn commit Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
||||
2015-12-15 Patrick Palka <ppalka@gcc.gnu.org>
|
||||
|
||||
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.
|
||||
|
||||
2015-12-14 Jerry DeLisle <jvdelisle@gcc.gnu.org>
|
||||
|
||||
* gfortran.dg/quad_2.f90: Update test.
|
||||
|
||||
|
|
45
gcc/testsuite/g++.dg/cpp0x/pr53223.C
Normal file
45
gcc/testsuite/g++.dg/cpp0x/pr53223.C
Normal file
|
@ -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);
|
||||
}
|
||||
|
276
gcc/testsuite/g++.dg/lookup/pr21802.C
Normal file
276
gcc/testsuite/g++.dg/lookup/pr21802.C
Normal file
|
@ -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);
|
||||
}
|
|
@ -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> >);
|
||||
|
|
Loading…
Add table
Reference in a new issue