The recent enhancement to treat the implicit this pointer argument
as nonnull in member functions triggers spurious -Wnonnull for
the synthesized conditional expression the C++ front end replaces
the pointer with in some static_cast expressions. The front end
already sets the no-warning bit for the test but not for the whole
conditional expression, so the attached fix extends the same solution
to it.
The consequence of this fix is that user-written code like this:
static_cast<T*>(p ? p : 0)->f ();
or
static_cast<T*>(p ? p : nullptr)->f ();
don't trigger the warning because they are both transformed into
the same expression as:
static_cast<T*>(p)->f ();
What still does trigger it is this:
static_cast<T*>(p ? p : (T*)0)->f ();
because here it's the inner COND_EXPR's no-warning bit that's set
(the outer one is clear), whereas in the former expressions it's
the other way around. It would be nice if this worked consistently
but I didn't see an easy way to do that and more than a quick fix
seems outside the scope for this bug.
Another case reported by someone else in the same bug involves
a dynamic_cast. A simplified test case goes something like this:
if (dynamic_cast<T*>(p))
dynamic_cast<T*>(p)->f ();
The root cause is the same: the front end emitting the COND_EXPR
((p != 0) ? ((T*)__dynamic_cast(p, (& _ZTI1B), (& _ZTI1C), 0)) : 0)
I decided not to suppress the warning in this case because doing
so would also suppress it in unconditional calls with the result
of the cast:
dynamic_cast<T*>(p)->f ();
and that doesn't seem helpful. Instead, I'd suggest to make
the second cast in the if statement to reference to T&:
if (dynamic_cast<T*>(p))
dynamic_cast<T&>(*p).f ();
Martin
PR c++/96003 spurious -Wnonnull calling a member on the result of static_cast
gcc/c-family/ChangeLog:
PR c++/96003
* c-common.c (check_function_arguments_recurse): Return early when
no-warning bit is set.
gcc/cp/ChangeLog:
PR c++/96003
* class.c (build_base_path): Set no-warning bit on the synthesized
conditional expression in static_cast.
gcc/testsuite/ChangeLog:
PR c++/96003
* g++.dg/warn/Wnonnull7.C: New test.
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 51ecde69f2d..7ab9966b7c0 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -5821,6 +5821,11 @@ check_function_arguments_recurse (void (*callback)
void *ctx, tree param,
unsigned HOST_WIDE_INT param_num)
{
+ /* Avoid warning in synthesized expressions like C++ static_cast.
+ See PR 96003. */
+ if (TREE_NO_WARNING (param))
+ return;
+
if (CONVERT_EXPR_P (param)
&& (TYPE_PRECISION (TREE_TYPE (param))
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (param, 0)))))
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 14380c7a08c..b460f8aefcd 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -516,8 +516,14 @@ 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));
+ {
+ 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;
+ }
return expr;
}
diff --git a/gcc/testsuite/g++.dg/warn/Wnonnull7.C b/gcc/testsuite/g++.dg/warn/Wnonnull7.C
new file mode 100644
index 00000000000..b7a64c83436
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wnonnull7.C
@@ -0,0 +1,25 @@
+/* PR c++/96003 - spurious -Wnonnull calling a member on the result
+ of static_cast
+ { dg-do compile }
+ { dg-options "-Wall" } */
+
+struct D;
+struct B
+{
+ B* next;
+ D* Next ();
+};
+
+struct D: B
+{
+ virtual ~D ();
+};
+
+struct Iterator
+{
+ D* p;
+ void advance ()
+ {
+ p = static_cast<B*>(p)->Next (); // { dg-bogus "\\\[-Wnonnull" }
+ }
+};