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:
parent
5a233ae4d8
commit
66ecb059c9
5 changed files with 63 additions and 32 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
29
gcc/testsuite/g++.dg/warn/Wnonnull12.C
Normal file
29
gcc/testsuite/g++.dg/warn/Wnonnull12.C
Normal 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" }
|
||||
}
|
|
@ -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" }
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue