re PR c++/12037 (Spurious "statement has no effect" in templates)
cp: PR c++/12037 * cp-tree.h (COMPOUND_EXPR_OVERLOADED): New. (build_min_non_dep): Declare. * tree.c (build_min): Propagate TREE_SIDE_EFFECTS. (build_min_non_dep): New. * cvt.c (convert_to_void): Don't explicitly copy TREE_SIDE_EFFECTS, TREE_NO_UNUSED_WARNING. * call.c (build_new_method_call): Use build_min_non_dep. * decl2.c (grok_array_decl): Likewise. (build_offset_ref_call_from_tree): Likewise. * typeck.c (finish_class_member_access_expr, build_x_indirect_ref, build_x_binary_op, build_x_unary_op, build_x_conditional_expr, build_x_compound_expr): Likewise. (build_static_cast, build_reinterpret_cast, build_const_cast): Propagate TREE_SIDE_EFFECTS inside a template. * typeck2.c (build_x_arrow): Use build_min_non_dep. (build_functional_cast): Propagate TREE_SIDE_EFFECTS inside a template. * rtti.c (build_dynamic_cast_1): Set DECL_IS_PURE. (build_dynamic_cast): Set TREE_SIDE_EFFECTS. * pt.c (build_non_dependent_expr): Check COMPOUND_EXPR_OVERLOADED. testsuite: PR c++/12037 * g++.dg/warn/noeffect4.C: New test. From-SVN: r71108
This commit is contained in:
parent
7976070c71
commit
8e1daa3412
@ -1,3 +1,27 @@
|
||||
2003-09-05 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
PR c++/12037
|
||||
* cp-tree.h (COMPOUND_EXPR_OVERLOADED): New.
|
||||
(build_min_non_dep): Declare.
|
||||
* tree.c (build_min): Propagate TREE_SIDE_EFFECTS.
|
||||
(build_min_non_dep): New.
|
||||
* cvt.c (convert_to_void): Don't explicitly copy
|
||||
TREE_SIDE_EFFECTS, TREE_NO_UNUSED_WARNING.
|
||||
* call.c (build_new_method_call): Use build_min_non_dep.
|
||||
* decl2.c (grok_array_decl): Likewise.
|
||||
(build_offset_ref_call_from_tree): Likewise.
|
||||
* typeck.c (finish_class_member_access_expr,
|
||||
build_x_indirect_ref, build_x_binary_op, build_x_unary_op,
|
||||
build_x_conditional_expr, build_x_compound_expr): Likewise.
|
||||
(build_static_cast, build_reinterpret_cast,
|
||||
build_const_cast): Propagate TREE_SIDE_EFFECTS inside a template.
|
||||
* typeck2.c (build_x_arrow): Use build_min_non_dep.
|
||||
(build_functional_cast): Propagate TREE_SIDE_EFFECTS inside a
|
||||
template.
|
||||
* rtti.c (build_dynamic_cast_1): Set DECL_IS_PURE.
|
||||
(build_dynamic_cast): Set TREE_SIDE_EFFECTS.
|
||||
* pt.c (build_non_dependent_expr): Check COMPOUND_EXPR_OVERLOADED.
|
||||
|
||||
2003-09-04 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* decl2.c (mark_member_pointers_and_eh_handlers): Update for
|
||||
|
@ -5081,9 +5081,10 @@ build_new_method_call (tree instance, tree fns, tree args,
|
||||
finish:;
|
||||
|
||||
if (processing_template_decl && call != error_mark_node)
|
||||
return build_min (CALL_EXPR, TREE_TYPE (call),
|
||||
build_min_nt (COMPONENT_REF, orig_instance, orig_fns),
|
||||
orig_args);
|
||||
return build_min_non_dep
|
||||
(CALL_EXPR, call,
|
||||
build_min_nt (COMPONENT_REF, orig_instance, orig_fns),
|
||||
orig_args);
|
||||
return call;
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ struct diagnostic_context;
|
||||
IDENTIFIER_MARKED (IDENTIFIER_NODEs)
|
||||
NEW_EXPR_USE_GLOBAL (in NEW_EXPR).
|
||||
DELETE_EXPR_USE_GLOBAL (in DELETE_EXPR).
|
||||
COMPOUND_EXPR_OVERLOADED (in COMPOUND_EXPR).
|
||||
TREE_INDIRECT_USING (in NAMESPACE_DECL).
|
||||
ICS_USER_FLAG (in _CONV)
|
||||
CLEANUP_P (in TRY_BLOCK)
|
||||
@ -2294,6 +2295,10 @@ struct lang_decl GTY(())
|
||||
#define DELETE_EXPR_USE_GLOBAL(NODE) TREE_LANG_FLAG_0 (NODE)
|
||||
#define DELETE_EXPR_USE_VEC(NODE) TREE_LANG_FLAG_1 (NODE)
|
||||
|
||||
/* Indicates that this is a non-dependent COMPOUND_EXPR which will
|
||||
resolve to a function call. */
|
||||
#define COMPOUND_EXPR_OVERLOADED(NODE) TREE_LANG_FLAG_0 (NODE)
|
||||
|
||||
/* In a CALL_EXPR appearing in a template, true if Koenig lookup
|
||||
should be performed at instantiation time. */
|
||||
#define KOENIG_LOOKUP_P(NODE) TREE_LANG_FLAG_0(NODE)
|
||||
@ -4166,9 +4171,9 @@ extern tree canonical_type_variant (tree);
|
||||
extern tree copy_base_binfos (tree, tree, tree);
|
||||
extern int member_p (tree);
|
||||
extern cp_lvalue_kind real_lvalue_p (tree);
|
||||
extern tree build_min (enum tree_code, tree,
|
||||
...);
|
||||
extern tree build_min (enum tree_code, tree, ...);
|
||||
extern tree build_min_nt (enum tree_code, ...);
|
||||
extern tree build_min_non_dep (enum tree_code, tree, ...);
|
||||
extern tree build_cplus_new (tree, tree);
|
||||
extern tree get_target_expr (tree);
|
||||
extern tree build_cplus_staticfn_type (tree, tree, tree);
|
||||
|
@ -835,8 +835,6 @@ convert_to_void (tree expr, const char *implicit)
|
||||
{
|
||||
tree t = build (COMPOUND_EXPR, TREE_TYPE (new_op1),
|
||||
TREE_OPERAND (expr, 0), new_op1);
|
||||
TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (expr);
|
||||
TREE_NO_UNUSED_WARNING (t) = TREE_NO_UNUSED_WARNING (expr);
|
||||
expr = t;
|
||||
}
|
||||
|
||||
|
@ -463,8 +463,8 @@ grok_array_decl (tree array_expr, tree index_exp)
|
||||
expr = build_array_ref (array_expr, index_exp);
|
||||
}
|
||||
if (processing_template_decl && expr != error_mark_node)
|
||||
return build_min (ARRAY_REF, TREE_TYPE (expr), orig_array_expr,
|
||||
orig_index_exp);
|
||||
return build_min_non_dep (ARRAY_REF, expr,
|
||||
orig_array_expr, orig_index_exp);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -3029,7 +3029,7 @@ build_offset_ref_call_from_tree (tree fn, tree args)
|
||||
|
||||
expr = build_function_call (fn, args);
|
||||
if (processing_template_decl && expr != error_mark_node)
|
||||
return build_min (CALL_EXPR, TREE_TYPE (expr), orig_fn, orig_args);
|
||||
return build_min_non_dep (CALL_EXPR, expr, orig_fn, orig_args);
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
@ -11811,7 +11811,8 @@ build_non_dependent_expr (tree expr)
|
||||
TREE_OPERAND (expr, 0),
|
||||
build_non_dependent_expr (TREE_OPERAND (expr, 1)),
|
||||
build_non_dependent_expr (TREE_OPERAND (expr, 2)));
|
||||
if (TREE_CODE (expr) == COMPOUND_EXPR)
|
||||
if (TREE_CODE (expr) == COMPOUND_EXPR
|
||||
&& !COMPOUND_EXPR_OVERLOADED (expr))
|
||||
return build (COMPOUND_EXPR,
|
||||
TREE_TYPE (expr),
|
||||
TREE_OPERAND (expr, 0),
|
||||
|
@ -652,6 +652,7 @@ build_dynamic_cast_1 (tree type, tree expr)
|
||||
(NULL_TREE, ptrdiff_type_node, void_list_node))));
|
||||
tmp = build_function_type (ptr_type_node, tmp);
|
||||
dcast_fn = build_library_fn_ptr (name, tmp);
|
||||
DECL_IS_PURE (dcast_fn) = 1;
|
||||
pop_nested_namespace (ns);
|
||||
dynamic_cast_node = dcast_fn;
|
||||
}
|
||||
@ -686,7 +687,12 @@ build_dynamic_cast (tree type, tree expr)
|
||||
return error_mark_node;
|
||||
|
||||
if (processing_template_decl)
|
||||
return build_min (DYNAMIC_CAST_EXPR, type, expr);
|
||||
{
|
||||
expr = build_min (DYNAMIC_CAST_EXPR, type, expr);
|
||||
TREE_SIDE_EFFECTS (expr) = 1;
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
return convert_from_reference (build_dynamic_cast_1 (type, expr));
|
||||
}
|
||||
|
@ -1265,11 +1265,8 @@ break_out_target_exprs (tree t)
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Obstack used for allocating nodes in template function and variable
|
||||
definitions. */
|
||||
|
||||
/* Similar to `build_nt', except that we set TREE_COMPLEXITY to be the
|
||||
current line number. */
|
||||
/* Similar to `build_nt', but for template definitions of dependent
|
||||
expressions */
|
||||
|
||||
tree
|
||||
build_min_nt (enum tree_code code, ...)
|
||||
@ -1295,8 +1292,7 @@ build_min_nt (enum tree_code code, ...)
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Similar to `build', except we set TREE_COMPLEXITY to the current
|
||||
line-number. */
|
||||
/* Similar to `build', but for template definitions. */
|
||||
|
||||
tree
|
||||
build_min (enum tree_code code, tree tt, ...)
|
||||
@ -1317,12 +1313,49 @@ build_min (enum tree_code code, tree tt, ...)
|
||||
{
|
||||
tree x = va_arg (p, tree);
|
||||
TREE_OPERAND (t, i) = x;
|
||||
if (x && TREE_SIDE_EFFECTS (x))
|
||||
TREE_SIDE_EFFECTS (t) = 1;
|
||||
}
|
||||
|
||||
va_end (p);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Similar to `build', but for template definitions of non-dependent
|
||||
expressions. NON_DEP is the non-dependent expression that has been
|
||||
built. */
|
||||
|
||||
tree
|
||||
build_min_non_dep (enum tree_code code, tree non_dep, ...)
|
||||
{
|
||||
register tree t;
|
||||
register int length;
|
||||
register int i;
|
||||
va_list p;
|
||||
|
||||
va_start (p, non_dep);
|
||||
|
||||
t = make_node (code);
|
||||
length = TREE_CODE_LENGTH (code);
|
||||
TREE_TYPE (t) = TREE_TYPE (non_dep);
|
||||
TREE_COMPLEXITY (t) = input_line;
|
||||
TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (non_dep);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
tree x = va_arg (p, tree);
|
||||
TREE_OPERAND (t, i) = x;
|
||||
}
|
||||
|
||||
if (code == COMPOUND_EXPR && TREE_CODE (non_dep) != COMPOUND_EXPR)
|
||||
/* This should not be considered a COMPOUND_EXPR, because it
|
||||
resolves to an overload. */
|
||||
COMPOUND_EXPR_OVERLOADED (t) = 1;
|
||||
|
||||
va_end (p);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Returns an INTEGER_CST (of type `int') corresponding to I.
|
||||
Multiple calls with the same value of I may or may not yield the
|
||||
same node; therefore, callers should never modify the node
|
||||
|
@ -1936,8 +1936,8 @@ finish_class_member_access_expr (tree object, tree name)
|
||||
expr = build_class_member_access_expr (object, member, access_path,
|
||||
/*preserve_reference=*/false);
|
||||
if (processing_template_decl && expr != error_mark_node)
|
||||
return build_min (COMPONENT_REF, TREE_TYPE (expr), orig_object,
|
||||
orig_name);
|
||||
return build_min_non_dep (COMPONENT_REF, expr,
|
||||
orig_object, orig_name);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -1994,7 +1994,7 @@ build_x_indirect_ref (tree expr, const char *errorstring)
|
||||
rval = build_indirect_ref (expr, errorstring);
|
||||
|
||||
if (processing_template_decl && rval != error_mark_node)
|
||||
return build_min (INDIRECT_REF, TREE_TYPE (rval), orig_expr);
|
||||
return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
|
||||
else
|
||||
return rval;
|
||||
}
|
||||
@ -2637,7 +2637,7 @@ build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
|
||||
expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
|
||||
|
||||
if (processing_template_decl && expr != error_mark_node)
|
||||
return build_min (code, TREE_TYPE (expr), orig_arg1, orig_arg2);
|
||||
return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
|
||||
|
||||
return expr;
|
||||
}
|
||||
@ -3537,7 +3537,8 @@ build_x_unary_op (enum tree_code code, tree xarg)
|
||||
}
|
||||
|
||||
if (processing_template_decl && exp != error_mark_node)
|
||||
return build_min (code, TREE_TYPE (exp), orig_expr, NULL_TREE);
|
||||
return build_min_non_dep (code, exp, orig_expr,
|
||||
/*For {PRE,POST}{INC,DEC}REMENT_EXPR*/NULL_TREE);
|
||||
return exp;
|
||||
}
|
||||
|
||||
@ -4277,8 +4278,8 @@ build_x_conditional_expr (tree ifexp, tree op1, tree op2)
|
||||
|
||||
expr = build_conditional_expr (ifexp, op1, op2);
|
||||
if (processing_template_decl && expr != error_mark_node)
|
||||
return build_min (COND_EXPR, TREE_TYPE (expr),
|
||||
orig_ifexp, orig_op1, orig_op2);
|
||||
return build_min_non_dep (COND_EXPR, expr,
|
||||
orig_ifexp, orig_op1, orig_op2);
|
||||
return expr;
|
||||
}
|
||||
|
||||
@ -4324,8 +4325,8 @@ build_x_compound_expr (tree op1, tree op2)
|
||||
result = build_compound_expr (op1, op2);
|
||||
|
||||
if (processing_template_decl && result != error_mark_node)
|
||||
return build_min (COMPOUND_EXPR, TREE_TYPE (result),
|
||||
orig_op1, orig_op2);
|
||||
return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -4382,8 +4383,10 @@ build_static_cast (tree type, tree expr)
|
||||
|
||||
if (processing_template_decl)
|
||||
{
|
||||
tree t = build_min (STATIC_CAST_EXPR, type, expr);
|
||||
return t;
|
||||
expr = build_min (STATIC_CAST_EXPR, type, expr);
|
||||
/* We don't know if it will or will not have side effects. */
|
||||
TREE_SIDE_EFFECTS (expr) = 1;
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
|
||||
@ -4473,9 +4476,10 @@ build_static_cast (tree type, tree expr)
|
||||
converted to an enumeration type. */
|
||||
|| (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
|
||||
&& INTEGRAL_OR_ENUMERATION_TYPE_P (intype)))
|
||||
/* Really, build_c_cast should defer to this function rather
|
||||
than the other way around. */
|
||||
return build_c_cast (type, expr);
|
||||
/* Really, build_c_cast should defer to this function rather
|
||||
than the other way around. */
|
||||
return build_c_cast (type, expr);
|
||||
|
||||
if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
|
||||
&& CLASS_TYPE_P (TREE_TYPE (type))
|
||||
&& CLASS_TYPE_P (TREE_TYPE (intype))
|
||||
@ -4491,6 +4495,7 @@ build_static_cast (tree type, tree expr)
|
||||
ba_check | ba_quiet, NULL);
|
||||
return build_base_path (MINUS_EXPR, expr, base, /*nonnull=*/false);
|
||||
}
|
||||
|
||||
if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
|
||||
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
|
||||
{
|
||||
@ -4567,6 +4572,11 @@ build_reinterpret_cast (tree type, tree expr)
|
||||
if (processing_template_decl)
|
||||
{
|
||||
tree t = build_min (REINTERPRET_CAST_EXPR, type, expr);
|
||||
|
||||
if (!TREE_SIDE_EFFECTS (t)
|
||||
&& type_dependent_expression_p (expr))
|
||||
/* There might turn out to be side effects inside expr. */
|
||||
TREE_SIDE_EFFECTS (t) = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -4651,6 +4661,11 @@ build_const_cast (tree type, tree expr)
|
||||
if (processing_template_decl)
|
||||
{
|
||||
tree t = build_min (CONST_CAST_EXPR, type, expr);
|
||||
|
||||
if (!TREE_SIDE_EFFECTS (t)
|
||||
&& type_dependent_expression_p (expr))
|
||||
/* There might turn out to be side effects inside expr. */
|
||||
TREE_SIDE_EFFECTS (t) = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -4720,6 +4735,8 @@ build_c_cast (tree type, tree expr)
|
||||
{
|
||||
tree t = build_min (CAST_EXPR, type,
|
||||
tree_cons (NULL_TREE, value, NULL_TREE));
|
||||
/* We don't know if it will or will not have side effects. */
|
||||
TREE_SIDE_EFFECTS (t) = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -1023,9 +1023,12 @@ build_x_arrow (tree expr)
|
||||
if (TREE_CODE (TREE_TYPE (last_rval)) == POINTER_TYPE)
|
||||
{
|
||||
if (processing_template_decl)
|
||||
return build_min (ARROW_EXPR,
|
||||
TREE_TYPE (TREE_TYPE (last_rval)),
|
||||
orig_expr);
|
||||
{
|
||||
expr = build_min_non_dep (ARROW_EXPR, last_rval, orig_expr);
|
||||
/* It will be dereferenced. */
|
||||
TREE_TYPE (expr) = TREE_TYPE (TREE_TYPE (last_rval));
|
||||
return expr;
|
||||
}
|
||||
|
||||
return build_indirect_ref (last_rval, NULL);
|
||||
}
|
||||
@ -1120,7 +1123,12 @@ build_functional_cast (tree exp, tree parms)
|
||||
type = exp;
|
||||
|
||||
if (processing_template_decl)
|
||||
return build_min (CAST_EXPR, type, parms);
|
||||
{
|
||||
tree t = build_min (CAST_EXPR, type, parms);
|
||||
/* We don't know if it will or will not have side effects. */
|
||||
TREE_SIDE_EFFECTS (t) = 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
if (! IS_AGGR_TYPE (type))
|
||||
{
|
||||
|
@ -1,3 +1,8 @@
|
||||
2003-09-05 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
PR c++/12037
|
||||
* g++.dg/warn/noeffect4.C: New test.
|
||||
|
||||
2003-09-04 Matt Austern <austern@apple.com>
|
||||
|
||||
* g++.dg/ext/fnname1.C: New test. (__func__ for C++.)
|
||||
|
88
gcc/testsuite/g++.dg/warn/noeffect4.C
Normal file
88
gcc/testsuite/g++.dg/warn/noeffect4.C
Normal file
@ -0,0 +1,88 @@
|
||||
// { dg-do compile }
|
||||
// { dg-options "-Wall" }
|
||||
|
||||
// Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
// Contributed by Nathan Sidwell 2 Sep 2003 <nathan@codesourcery.com>
|
||||
|
||||
// PR 12037.
|
||||
|
||||
struct X
|
||||
{
|
||||
int operator+(int);
|
||||
int operator-(int);
|
||||
int operator*(int);
|
||||
int operator/(int);
|
||||
int operator%(int);
|
||||
int operator>>(int);
|
||||
int operator<<(int);
|
||||
int operator&(int);
|
||||
int operator|(int);
|
||||
int operator^(int);
|
||||
int operator&&(int);
|
||||
int operator||(int);
|
||||
int operator==(int);
|
||||
int operator!=(int);
|
||||
int operator<(int);
|
||||
int operator<=(int);
|
||||
int operator>(int);
|
||||
int operator>=(int);
|
||||
int operator*();
|
||||
int operator!();
|
||||
int operator~();
|
||||
int operator++();
|
||||
int operator--();
|
||||
int operator++(int);
|
||||
int operator--(int);
|
||||
int operator()();
|
||||
int operator,(int);
|
||||
X *operator->();
|
||||
operator int () const;
|
||||
int m;
|
||||
virtual ~X ();
|
||||
X &Foo ();
|
||||
};
|
||||
struct Y : X
|
||||
{
|
||||
};
|
||||
|
||||
template<int I> void Foo (X &x)
|
||||
{
|
||||
x + I;
|
||||
x - I;
|
||||
x * I;
|
||||
x / I;
|
||||
x % I;
|
||||
x >> I;
|
||||
x << I;
|
||||
x & I;
|
||||
x | I;
|
||||
x && I;
|
||||
x || I;
|
||||
x == I;
|
||||
x != I;
|
||||
x < I;
|
||||
x <= I;
|
||||
x > I;
|
||||
x >= I;
|
||||
*x;
|
||||
!x;
|
||||
~x;
|
||||
x++;
|
||||
x--;
|
||||
++x;
|
||||
--x;
|
||||
x ();
|
||||
x, I;
|
||||
x->m;
|
||||
static_cast<int> (x);
|
||||
dynamic_cast<Y &> (x);
|
||||
reinterpret_cast<int> (x.Foo ());
|
||||
const_cast<X &> (x.Foo ());
|
||||
|
||||
reinterpret_cast<int *> (&x);// { dg-warning "no effect" "" }
|
||||
const_cast<X &> (x); // { dg-warning "no effect" "" }
|
||||
sizeof (x++); // { dg-warning "no effect" "" }
|
||||
__alignof__ (x++); // { dg-warning "no effect" "" }
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user