PR c++/99251 - inconsistent -Wnonnull warning behaviour with dynamic_cast

gcc/cp/ChangeLog:

	PR c++/99251
	* class.c (build_base_path): Call build_if_nonnull.
	* cp-tree.h (build_if_nonnull): Declare.
	* rtti.c (ifnonnull): Rename...
	(build_if_nonnull): ...to this.  Set no-warning bit on COND_EXPR.
	(build_dynamic_cast_1): Adjust to name change.

gcc/testsuite/ChangeLog:

	PR c++/99251
	* g++.dg/warn/Wnonnull9.C: Expect no warnings.
	* g++.dg/warn/Wnonnull12.C: New test.
This commit is contained in:
Martin Sebor 2021-03-02 11:12:50 -07:00
parent 5a233ae4d8
commit 66ecb059c9
5 changed files with 63 additions and 32 deletions

View file

@ -402,16 +402,9 @@ build_base_path (enum tree_code code,
if (TREE_SIDE_EFFECTS (expr) && (null_test || virtual_access))
expr = save_expr (expr);
/* Now that we've saved expr, build the real null test. */
/* Store EXPR and build the real null test just before returning. */
if (null_test)
{
tree zero = cp_convert (TREE_TYPE (expr), nullptr_node, complain);
null_test = build2_loc (input_location, NE_EXPR, boolean_type_node,
expr, zero);
/* This is a compiler generated comparison, don't emit
e.g. -Wnonnull-compare warning for it. */
TREE_NO_WARNING (null_test) = 1;
}
null_test = expr;
/* If this is a simple base reference, express it as a COMPONENT_REF. */
if (code == PLUS_EXPR && !virtual_access
@ -516,14 +509,8 @@ build_base_path (enum tree_code code,
out:
if (null_test)
{
expr = fold_build3_loc (input_location, COND_EXPR, target_type, null_test,
expr, build_zero_cst (target_type));
/* Avoid warning for the whole conditional expression (in addition
to NULL_TEST itself -- see above) in case the result is used in
a nonnull context that the front end -Wnonnull checks. */
TREE_NO_WARNING (expr) = 1;
}
/* Wrap EXPR in a null test. */
expr = build_if_nonnull (null_test, expr, complain);
return expr;
}

View file

@ -7279,6 +7279,7 @@ extern void emit_support_tinfos (void);
extern bool emit_tinfo_decl (tree);
extern unsigned get_pseudo_tinfo_index (tree);
extern tree get_pseudo_tinfo_type (unsigned);
extern tree build_if_nonnull (tree, tree, tsubst_flags_t);
/* in search.c */
extern tree get_parent_with_private_access (tree decl, tree binfo);

View file

@ -121,7 +121,6 @@ vec<tree, va_gc> *unemitted_tinfo_decls;
and are generated as needed. */
static GTY (()) vec<tinfo_s, va_gc> *tinfo_descs;
static tree ifnonnull (tree, tree, tsubst_flags_t);
static tree tinfo_name (tree, bool);
static tree build_dynamic_cast_1 (location_t, tree, tree, tsubst_flags_t);
static tree throw_bad_cast (void);
@ -529,16 +528,23 @@ get_typeid (tree type, tsubst_flags_t complain)
/* Check whether TEST is null before returning RESULT. If TEST is used in
RESULT, it must have previously had a save_expr applied to it. */
static tree
ifnonnull (tree test, tree result, tsubst_flags_t complain)
tree
build_if_nonnull (tree test, tree result, tsubst_flags_t complain)
{
tree cond = build2 (NE_EXPR, boolean_type_node, test,
cp_convert (TREE_TYPE (test), nullptr_node, complain));
tree null_ptr = cp_convert (TREE_TYPE (test), nullptr_node, complain);
tree cond = build2 (NE_EXPR, boolean_type_node, test, null_ptr);
/* This is a compiler generated comparison, don't emit
e.g. -Wnonnull-compare warning for it. */
TREE_NO_WARNING (cond) = 1;
return build3 (COND_EXPR, TREE_TYPE (result), cond, result,
cp_convert (TREE_TYPE (result), nullptr_node, complain));
null_ptr = cp_convert (TREE_TYPE (result), nullptr_node, complain);
cond = build3 (COND_EXPR, TREE_TYPE (result), cond, result, null_ptr);
/* Likewise, don't emit -Wnonnull for using the result to call
a member function. */
TREE_NO_WARNING (cond) = 1;
return cond;
}
/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
@ -671,7 +677,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
expr1 = build_headof (expr);
if (TREE_TYPE (expr1) != type)
expr1 = build1 (NOP_EXPR, type, expr1);
return ifnonnull (expr, expr1, complain);
return build_if_nonnull (expr, expr1, complain);
}
else
{
@ -786,7 +792,7 @@ build_dynamic_cast_1 (location_t loc, tree type, tree expr,
/* Now back to the type we want from a void*. */
result = cp_convert (type, result, complain);
return ifnonnull (expr, result, complain);
return build_if_nonnull (expr, result, complain);
}
}
else

View file

@ -0,0 +1,29 @@
/* PR c++/99251 - inconsistent -Wnonnull warning behaviour with dynamic_cast
{ dg-do compile }
{ dg-options "-Wall" } */
struct A
{
virtual ~A ();
};
struct B: A
{
int f (int);
};
int f1 (A *p)
{
if (!p)
return 0;
return (dynamic_cast<B *>(p))->f (1);
}
int f2 (A *p)
{
if (!p)
return 0;
return dynamic_cast<B *>(p)->f (2); // { dg-bogus "\\\[-Wnonnull" }
}

View file

@ -38,13 +38,17 @@ void static_cast_const_C_ptr (B *p)
void dynamic_cast_C_ptr (B *p)
{
// The dynamic_cast might fail so a warning is justified.
dynamic_cast<C*>(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" }
/* Unlike static_cast, dynamic cast may return null even for a nonnull
operand but detecting assumptions to the contrary isn't -Wnonnull's
purpose. Verify -Wnonnull isn't issued, either for the implicitly
emitted null check or for other reasons (the latter may be worth
warning for by some other warning). See also pr99251. */
dynamic_cast<C*>(p->bptr ())->g (); // { dg-bogus "\\\[-Wnonnull" }
}
void dynamic_cast_const_C_ptr (B *p)
{
dynamic_cast<const C*>(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" }
dynamic_cast<const C*>(p->bptr ())->g (); // { dg-bogus "\\\[-Wnonnull" }
}
@ -107,11 +111,15 @@ void static_cast_const_D_ptr (B *p)
void dynamic_cast_D_ptr (B *p)
{
// The dynamic_cast might fail so a warning is justified.
dynamic_cast<D*>(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" }
/* Unlike static_cast, dynamic cast may return null even for a nonnull
operand but detecting assumptions to the contrary isn't -Wnonnull's
purpose. Verify -Wnonnull isn't issued, either for the implicitly
emitted null check or for other reasons (the latter may be worth
warning for by some other warning). See also pr99251. */
dynamic_cast<D*>(p->bptr ())->g (); // { dg-bogus "\\\[-Wnonnull" }
}
void dynamic_cast_const_D_ptr (B *p)
{
dynamic_cast<const D*>(p->bptr ())->g (); // { dg-warning "\\\[-Wnonnull" }
dynamic_cast<const D*>(p->bptr ())->g (); // { dg-bogus "\\\[-Wnonnull" }
}