re PR c++/49118 (Endless operator-> chain causes infinite loop)
PR c++/49118 * typeck2.c (build_x_arrow): Push fake template context to produce diagnostic on acyclic endless operator-> drill-down. * call.c (build_new_op): Change Boolean overload status value to a pointer to the overload function. * cp-tree.h: Likewise. * typeck.c: Likewise. * parser.c: Likewise. * decl2.c: Likewise. * pt.c: Likewise. From-SVN: r174889
This commit is contained in:
parent
0dbe377735
commit
6904f4b401
@ -1,3 +1,16 @@
|
|||||||
|
2011-06-09 David Krauss <potswa@mac.com>
|
||||||
|
|
||||||
|
PR c++/49118
|
||||||
|
* typeck2.c (build_x_arrow): Push fake template context
|
||||||
|
to produce diagnostic on acyclic endless operator-> drill-down.
|
||||||
|
* call.c (build_new_op): Change Boolean overload status
|
||||||
|
value to a pointer to the overload function.
|
||||||
|
* cp-tree.h: Likewise.
|
||||||
|
* typeck.c: Likewise.
|
||||||
|
* parser.c: Likewise.
|
||||||
|
* decl2.c: Likewise.
|
||||||
|
* pt.c: Likewise.
|
||||||
|
|
||||||
2011-06-09 Jason Merrill <jason@redhat.com>
|
2011-06-09 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
* semantics.c (maybe_constant_value): Handle overflowed input.
|
* semantics.c (maybe_constant_value): Handle overflowed input.
|
||||||
|
@ -4791,7 +4791,7 @@ avoid_sign_compare_warnings (tree orig_arg, tree arg)
|
|||||||
|
|
||||||
static tree
|
static tree
|
||||||
build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
|
build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
|
||||||
bool *overloaded_p, tsubst_flags_t complain)
|
tree *overload, tsubst_flags_t complain)
|
||||||
{
|
{
|
||||||
tree orig_arg1 = arg1;
|
tree orig_arg1 = arg1;
|
||||||
tree orig_arg2 = arg2;
|
tree orig_arg2 = arg2;
|
||||||
@ -4958,7 +4958,7 @@ build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
|
|||||||
else
|
else
|
||||||
code = PREDECREMENT_EXPR;
|
code = PREDECREMENT_EXPR;
|
||||||
result = build_new_op_1 (code, flags, arg1, NULL_TREE, NULL_TREE,
|
result = build_new_op_1 (code, flags, arg1, NULL_TREE, NULL_TREE,
|
||||||
overloaded_p, complain);
|
overload, complain);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* The caller will deal with these. */
|
/* The caller will deal with these. */
|
||||||
@ -5005,8 +5005,8 @@ build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
|
|||||||
}
|
}
|
||||||
else if (TREE_CODE (cand->fn) == FUNCTION_DECL)
|
else if (TREE_CODE (cand->fn) == FUNCTION_DECL)
|
||||||
{
|
{
|
||||||
if (overloaded_p)
|
if (overload)
|
||||||
*overloaded_p = true;
|
*overload = cand->fn;
|
||||||
|
|
||||||
if (resolve_args (arglist, complain) == NULL)
|
if (resolve_args (arglist, complain) == NULL)
|
||||||
result = error_mark_node;
|
result = error_mark_node;
|
||||||
@ -5165,11 +5165,11 @@ build_new_op_1 (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
|
|||||||
|
|
||||||
tree
|
tree
|
||||||
build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
|
build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
|
||||||
bool *overloaded_p, tsubst_flags_t complain)
|
tree *overload, tsubst_flags_t complain)
|
||||||
{
|
{
|
||||||
tree ret;
|
tree ret;
|
||||||
bool subtime = timevar_cond_start (TV_OVERLOAD);
|
bool subtime = timevar_cond_start (TV_OVERLOAD);
|
||||||
ret = build_new_op_1 (code, flags, arg1, arg2, arg3, overloaded_p, complain);
|
ret = build_new_op_1 (code, flags, arg1, arg2, arg3, overload, complain);
|
||||||
timevar_cond_stop (TV_OVERLOAD, subtime);
|
timevar_cond_stop (TV_OVERLOAD, subtime);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -4717,7 +4717,7 @@ extern tree build_new_method_call (tree, tree, VEC(tree,gc) **,
|
|||||||
extern tree build_special_member_call (tree, tree, VEC(tree,gc) **,
|
extern tree build_special_member_call (tree, tree, VEC(tree,gc) **,
|
||||||
tree, int, tsubst_flags_t);
|
tree, int, tsubst_flags_t);
|
||||||
extern tree build_new_op (enum tree_code, int, tree,
|
extern tree build_new_op (enum tree_code, int, tree,
|
||||||
tree, tree, bool *,
|
tree, tree, tree *,
|
||||||
tsubst_flags_t);
|
tsubst_flags_t);
|
||||||
extern tree build_op_call (tree, VEC(tree,gc) **,
|
extern tree build_op_call (tree, VEC(tree,gc) **,
|
||||||
tsubst_flags_t);
|
tsubst_flags_t);
|
||||||
@ -5611,7 +5611,7 @@ extern tree cp_build_function_call_vec (tree, VEC(tree,gc) **,
|
|||||||
tsubst_flags_t);
|
tsubst_flags_t);
|
||||||
extern tree build_x_binary_op (enum tree_code, tree,
|
extern tree build_x_binary_op (enum tree_code, tree,
|
||||||
enum tree_code, tree,
|
enum tree_code, tree,
|
||||||
enum tree_code, bool *,
|
enum tree_code, tree *,
|
||||||
tsubst_flags_t);
|
tsubst_flags_t);
|
||||||
extern tree build_x_array_ref (tree, tree, tsubst_flags_t);
|
extern tree build_x_array_ref (tree, tree, tsubst_flags_t);
|
||||||
extern tree build_x_unary_op (enum tree_code, tree,
|
extern tree build_x_unary_op (enum tree_code, tree,
|
||||||
|
@ -361,7 +361,7 @@ grok_array_decl (tree array_expr, tree index_exp)
|
|||||||
if (MAYBE_CLASS_TYPE_P (type) || MAYBE_CLASS_TYPE_P (TREE_TYPE (index_exp)))
|
if (MAYBE_CLASS_TYPE_P (type) || MAYBE_CLASS_TYPE_P (TREE_TYPE (index_exp)))
|
||||||
expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
|
expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
|
||||||
array_expr, index_exp, NULL_TREE,
|
array_expr, index_exp, NULL_TREE,
|
||||||
/*overloaded_p=*/NULL, tf_warning_or_error);
|
/*overload=*/NULL, tf_warning_or_error);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tree p1, p2, i1, i2;
|
tree p1, p2, i1, i2;
|
||||||
|
@ -6585,7 +6585,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
|
|||||||
cp_token *token;
|
cp_token *token;
|
||||||
enum tree_code tree_type, lhs_type, rhs_type;
|
enum tree_code tree_type, lhs_type, rhs_type;
|
||||||
enum cp_parser_prec new_prec, lookahead_prec;
|
enum cp_parser_prec new_prec, lookahead_prec;
|
||||||
bool overloaded_p;
|
tree overload;
|
||||||
|
|
||||||
/* Parse the first expression. */
|
/* Parse the first expression. */
|
||||||
lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p, pidk);
|
lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p, pidk);
|
||||||
@ -6688,7 +6688,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
|
|||||||
else if (tree_type == TRUTH_ORIF_EXPR)
|
else if (tree_type == TRUTH_ORIF_EXPR)
|
||||||
c_inhibit_evaluation_warnings -= lhs == truthvalue_true_node;
|
c_inhibit_evaluation_warnings -= lhs == truthvalue_true_node;
|
||||||
|
|
||||||
overloaded_p = false;
|
overload = NULL;
|
||||||
/* ??? Currently we pass lhs_type == ERROR_MARK and rhs_type ==
|
/* ??? Currently we pass lhs_type == ERROR_MARK and rhs_type ==
|
||||||
ERROR_MARK for everything that is not a binary expression.
|
ERROR_MARK for everything that is not a binary expression.
|
||||||
This makes warn_about_parentheses miss some warnings that
|
This makes warn_about_parentheses miss some warnings that
|
||||||
@ -6703,7 +6703,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
|
|||||||
lhs = build2 (tree_type, boolean_type_node, lhs, rhs);
|
lhs = build2 (tree_type, boolean_type_node, lhs, rhs);
|
||||||
else
|
else
|
||||||
lhs = build_x_binary_op (tree_type, lhs, lhs_type, rhs, rhs_type,
|
lhs = build_x_binary_op (tree_type, lhs, lhs_type, rhs, rhs_type,
|
||||||
&overloaded_p, tf_warning_or_error);
|
&overload, tf_warning_or_error);
|
||||||
lhs_type = tree_type;
|
lhs_type = tree_type;
|
||||||
|
|
||||||
/* If the binary operator required the use of an overloaded operator,
|
/* If the binary operator required the use of an overloaded operator,
|
||||||
@ -6712,7 +6712,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
|
|||||||
otherwise permissible in an integral constant-expression if at
|
otherwise permissible in an integral constant-expression if at
|
||||||
least one of the operands is of enumeration type. */
|
least one of the operands is of enumeration type. */
|
||||||
|
|
||||||
if (overloaded_p
|
if (overload
|
||||||
&& cp_parser_non_integral_constant_expression (parser,
|
&& cp_parser_non_integral_constant_expression (parser,
|
||||||
NIC_OVERLOADED))
|
NIC_OVERLOADED))
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
@ -24245,8 +24245,6 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl)
|
|||||||
{
|
{
|
||||||
tree cond = cp_parser_binary_expression (parser, false, true,
|
tree cond = cp_parser_binary_expression (parser, false, true,
|
||||||
PREC_NOT_OPERATOR, NULL);
|
PREC_NOT_OPERATOR, NULL);
|
||||||
bool overloaded_p;
|
|
||||||
|
|
||||||
if (cond == error_mark_node
|
if (cond == error_mark_node
|
||||||
|| cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
|
|| cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
|
||||||
{
|
{
|
||||||
@ -24275,7 +24273,7 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl)
|
|||||||
return build_x_binary_op (TREE_CODE (cond),
|
return build_x_binary_op (TREE_CODE (cond),
|
||||||
TREE_OPERAND (cond, 0), ERROR_MARK,
|
TREE_OPERAND (cond, 0), ERROR_MARK,
|
||||||
TREE_OPERAND (cond, 1), ERROR_MARK,
|
TREE_OPERAND (cond, 1), ERROR_MARK,
|
||||||
&overloaded_p, tf_warning_or_error);
|
/*overload=*/NULL, tf_warning_or_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper function, to parse omp for increment expression. */
|
/* Helper function, to parse omp for increment expression. */
|
||||||
|
@ -12753,7 +12753,7 @@ tsubst_copy_and_build (tree t,
|
|||||||
(TREE_NO_WARNING (TREE_OPERAND (t, 1))
|
(TREE_NO_WARNING (TREE_OPERAND (t, 1))
|
||||||
? ERROR_MARK
|
? ERROR_MARK
|
||||||
: TREE_CODE (TREE_OPERAND (t, 1))),
|
: TREE_CODE (TREE_OPERAND (t, 1))),
|
||||||
/*overloaded_p=*/NULL,
|
/*overload=*/NULL,
|
||||||
complain);
|
complain);
|
||||||
|
|
||||||
case SCOPE_REF:
|
case SCOPE_REF:
|
||||||
|
@ -2035,7 +2035,7 @@ rationalize_conditional_expr (enum tree_code code, tree t,
|
|||||||
? LE_EXPR : GE_EXPR),
|
? LE_EXPR : GE_EXPR),
|
||||||
op0, TREE_CODE (op0),
|
op0, TREE_CODE (op0),
|
||||||
op1, TREE_CODE (op1),
|
op1, TREE_CODE (op1),
|
||||||
/*overloaded_p=*/NULL,
|
/*overload=*/NULL,
|
||||||
complain),
|
complain),
|
||||||
cp_build_unary_op (code, op0, 0, complain),
|
cp_build_unary_op (code, op0, 0, complain),
|
||||||
cp_build_unary_op (code, op1, 0, complain),
|
cp_build_unary_op (code, op1, 0, complain),
|
||||||
@ -2689,7 +2689,7 @@ build_x_indirect_ref (tree expr, ref_operator errorstring,
|
|||||||
}
|
}
|
||||||
|
|
||||||
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
|
rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
|
||||||
NULL_TREE, /*overloaded_p=*/NULL, complain);
|
NULL_TREE, /*overload=*/NULL, complain);
|
||||||
if (!rval)
|
if (!rval)
|
||||||
rval = cp_build_indirect_ref (expr, errorstring, complain);
|
rval = cp_build_indirect_ref (expr, errorstring, complain);
|
||||||
|
|
||||||
@ -3497,7 +3497,7 @@ convert_arguments (tree typelist, VEC(tree,gc) **values, tree fndecl,
|
|||||||
|
|
||||||
tree
|
tree
|
||||||
build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
|
build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
|
||||||
tree arg2, enum tree_code arg2_code, bool *overloaded_p,
|
tree arg2, enum tree_code arg2_code, tree *overload,
|
||||||
tsubst_flags_t complain)
|
tsubst_flags_t complain)
|
||||||
{
|
{
|
||||||
tree orig_arg1;
|
tree orig_arg1;
|
||||||
@ -3520,7 +3520,7 @@ build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code,
|
|||||||
expr = build_m_component_ref (arg1, arg2);
|
expr = build_m_component_ref (arg1, arg2);
|
||||||
else
|
else
|
||||||
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
|
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
|
||||||
overloaded_p, complain);
|
overload, complain);
|
||||||
|
|
||||||
/* Check for cases such as x+y<<z which users are likely to
|
/* 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
|
misinterpret. But don't warn about obj << x + y, since that is a
|
||||||
@ -3560,7 +3560,7 @@ build_x_array_ref (tree arg1, tree arg2, tsubst_flags_t complain)
|
|||||||
}
|
}
|
||||||
|
|
||||||
expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
|
expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL, arg1, arg2, NULL_TREE,
|
||||||
/*overloaded_p=*/NULL, complain);
|
/*overload=*/NULL, complain);
|
||||||
|
|
||||||
if (processing_template_decl && expr != error_mark_node)
|
if (processing_template_decl && expr != error_mark_node)
|
||||||
return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2,
|
return build_min_non_dep (ARRAY_REF, expr, orig_arg1, orig_arg2,
|
||||||
@ -4558,7 +4558,7 @@ build_x_unary_op (enum tree_code code, tree xarg, tsubst_flags_t complain)
|
|||||||
/* Don't look for a function. */;
|
/* Don't look for a function. */;
|
||||||
else
|
else
|
||||||
exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
|
exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
|
||||||
/*overloaded_p=*/NULL, complain);
|
/*overload=*/NULL, complain);
|
||||||
if (!exp && code == ADDR_EXPR)
|
if (!exp && code == ADDR_EXPR)
|
||||||
{
|
{
|
||||||
if (is_overloaded_fn (xarg))
|
if (is_overloaded_fn (xarg))
|
||||||
@ -5545,7 +5545,7 @@ build_x_compound_expr (tree op1, tree op2, tsubst_flags_t complain)
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
|
result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
|
||||||
/*overloaded_p=*/NULL, complain);
|
/*overload=*/NULL, complain);
|
||||||
if (!result)
|
if (!result)
|
||||||
result = cp_build_compound_expr (op1, op2, complain);
|
result = cp_build_compound_expr (op1, op2, complain);
|
||||||
|
|
||||||
@ -6650,7 +6650,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
|
|||||||
{
|
{
|
||||||
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
|
result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
|
||||||
lhs, rhs, make_node (NOP_EXPR),
|
lhs, rhs, make_node (NOP_EXPR),
|
||||||
/*overloaded_p=*/NULL,
|
/*overload=*/NULL,
|
||||||
complain);
|
complain);
|
||||||
if (result == NULL_TREE)
|
if (result == NULL_TREE)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
@ -6833,7 +6833,7 @@ build_x_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
|
|||||||
{
|
{
|
||||||
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
|
tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
|
||||||
make_node (modifycode),
|
make_node (modifycode),
|
||||||
/*overloaded_p=*/NULL,
|
/*overload=*/NULL,
|
||||||
complain);
|
complain);
|
||||||
if (rval)
|
if (rval)
|
||||||
{
|
{
|
||||||
|
@ -1429,14 +1429,20 @@ build_x_arrow (tree expr)
|
|||||||
|
|
||||||
if (MAYBE_CLASS_TYPE_P (type))
|
if (MAYBE_CLASS_TYPE_P (type))
|
||||||
{
|
{
|
||||||
|
struct tinst_level *actual_inst = current_instantiation ();
|
||||||
|
tree fn = NULL;
|
||||||
|
|
||||||
while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
|
while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
|
||||||
NULL_TREE, NULL_TREE,
|
NULL_TREE, NULL_TREE,
|
||||||
/*overloaded_p=*/NULL,
|
&fn, tf_warning_or_error)))
|
||||||
tf_warning_or_error)))
|
|
||||||
{
|
{
|
||||||
if (expr == error_mark_node)
|
if (expr == error_mark_node)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
|
|
||||||
|
if (fn && DECL_USE_TEMPLATE (fn))
|
||||||
|
push_tinst_level (fn);
|
||||||
|
fn = NULL;
|
||||||
|
|
||||||
if (vec_member (TREE_TYPE (expr), types_memoized))
|
if (vec_member (TREE_TYPE (expr), types_memoized))
|
||||||
{
|
{
|
||||||
error ("circular pointer delegation detected");
|
error ("circular pointer delegation detected");
|
||||||
@ -1447,6 +1453,9 @@ build_x_arrow (tree expr)
|
|||||||
last_rval = expr;
|
last_rval = expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (current_instantiation () != actual_inst)
|
||||||
|
pop_tinst_level ();
|
||||||
|
|
||||||
if (last_rval == NULL_TREE)
|
if (last_rval == NULL_TREE)
|
||||||
{
|
{
|
||||||
error ("base operand of %<->%> has non-pointer type %qT", type);
|
error ("base operand of %<->%> has non-pointer type %qT", type);
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
2011-06-09 David Krauss <potswa@mac.com>
|
||||||
|
|
||||||
|
* g++.dg/template/arrow1.C: New.
|
||||||
|
|
||||||
2011-06-09 Jason Merrill <jason@redhat.com>
|
2011-06-09 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
* lib/prune.exp: Prune "note"s.
|
* lib/prune.exp: Prune "note"s.
|
||||||
|
17
gcc/testsuite/g++.dg/template/arrow1.C
Normal file
17
gcc/testsuite/g++.dg/template/arrow1.C
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// PR c++/49118
|
||||||
|
// { dg-do compile }
|
||||||
|
|
||||||
|
template< int n >
|
||||||
|
struct a {
|
||||||
|
a< n+1 >
|
||||||
|
operator->()
|
||||||
|
{ return a< n+1 >(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
a<0>()->x; // { dg-error "instantiation depth exceeds maximum" }
|
||||||
|
}
|
||||||
|
|
||||||
|
// { dg-prune-output "incomplete type" }
|
||||||
|
// { dg-prune-output "declaration of" }
|
||||||
|
// { dg-prune-output "used but never defined" }
|
Loading…
Reference in New Issue
Block a user