The following with -std=c++17 -Waddress: int meow() { return 1; } void kitty(int); template <int (*F)()> void test() { if constexpr (F) { kitty(F()); } else { kitty(2); } } template void test<nullptr>(); template void test<meow>(); gives a spurious/pointless warning: <source>: In instantiation of 'void test() [with int (* F)() = meow]': <source>:12:26: required from here <source>:5:5: warning: the address of 'int meow()' will never be NULL [-Waddress] 5 | if constexpr (F) { | ^~ The warning should be suppressed in "if constexpr" contexts, because of course it's going to be always true or always false. Clang errors on this case, so it's possible that my code is invalid: Is it legal to compare a function pointer against null in a constant-expression?
I don't think this warning should be suppressed in "if constexpr" contexts. What's the point of such code?
Templates that take an optional function pointer as a template parameter. It lets you have templates that change behavior if a null function pointer is passed.
(In reply to Melissa from comment #0) > Clang errors on this case, so it's possible that my code is invalid: Is it > legal to compare a function pointer against null in a constant-expression? The example is ill-formed because the condition of 'if constexpr' is more restricted than that of normal 'if': It expects "a contextually converted constant expression of type bool" and [expr.const] p10 lists the allowed conversions in this case. This list omits the boolean conversions ([conv.bool]). But the example would become valid when rewritten as follows: int meow() { return 1; } void kitty(int); template <int (*F)()> void test() { if constexpr (bool(F)) { kitty(F()); } else { kitty(2); } } template void test<nullptr>(); template void test<meow>();
The code can be modified to be well formed if changed to: if constexpr (F != nullptr )) { g++ still emits the bogus warning in that case which is a bug I believe!
I don't think g++ is totally wrong here, Actually, if any, it should be stronger in making the error clearer and louder, as per sé it's fine to consider that you're for real not comparing something constant and the function address may not be known at compile time, so not wrong to check. However, something that will not error but work can be something like: #include <iostream> #include <type_traits> using namespace std; int meow() { return 1; } void kitty(int i) { std::cout << "Mowed vlaue " << i << "\n"; } template <int (*F)()> void test() { using NullType = std::integral_constant<decltype(F), nullptr>; using ActualType = std::integral_constant<decltype(F), F>; if constexpr (!std::is_same_v<ActualType, NullType>) { kitty(F()); } else { kitty(222222); } } int main() { test<nullptr>(); test<meow>(); return 0; }
(In reply to Daniel Krügler from comment #3) > The example is ill-formed because the condition of 'if constexpr' is more > restricted than that of normal 'if': It expects "a contextually converted > constant expression of type bool" and [expr.const] p10 lists the allowed > conversions in this case. This list omits the boolean conversions > ([conv.bool]). This was changed by wg21.link/p1401 so the conversion is allowed in this context as well.
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:124a9e08b7a83795bd4d09001955f0eef68ecd00 commit r13-1219-g124a9e08b7a83795bd4d09001955f0eef68ecd00 Author: Jason Merrill <jason@redhat.com> Date: Thu Jun 23 00:24:22 2022 -0400 c++: -Waddress and if constexpr [PR94554] Like we avoid various warnings for seemingly tautological expressions when substituting a template, we should avoid warning for the implicit conversion to bool in an if statement. I considered also doing this for the conditions in loop expressions, but that seems unnecessary, as a loop condition is unlikely to be a constant. The change to finish_if_stmt_cond isn't necessary since dependent_operand_p looks through IMPLICIT_CONV_EXPR, but makes it more constent with e.g. build_x_binary_op that determines the type of an expression and then builds it using the original operands. PR c++/94554 gcc/cp/ChangeLog: * pt.cc (dependent_operand_p): Split out from... (tsubst_copy_and_build): ...here. (tsubst_expr) [IF_STMT]: Use it. * semantics.cc (finish_if_stmt_cond): Keep the pre-conversion condition in the template tree. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/constexpr-if38.C: New test.
Fixed for GCC 13.