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:
Nathan Sidwell 2003-09-05 08:24:28 +00:00 committed by Nathan Sidwell
parent 7976070c71
commit 8e1daa3412
12 changed files with 223 additions and 37 deletions

View File

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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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),

View File

@ -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));
}

View File

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

View File

@ -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;
}

View File

@ -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))
{

View File

@ -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++.)

View 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" "" }
}