c++: constantness of call to function pointer [PR111703]
Checks
Commit Message
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
for trunk/13/12 (to match the PR107939 / r13-6525-ge09bc034d1b4d6 backports)?
-- >8 --
potential_constant_expression for a CALL_EXPR to a non-overload tests
FUNCTION_POINTER_TYPE_P on the callee rather than on the type of the
callee, which means we always pass want_rval=any when recursing and so
may fail to properly treat a non-constant function pointer callee as such.
Fixing this turns out to further work around the PR111703 issue.
PR c++/111703
PR c++/107939
gcc/cp/ChangeLog:
* constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
Fix FUNCTION_POINTER_TYPE_P test.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/concepts-fn8.C: Extend test.
* g++.dg/diagnostic/constexpr4.C: New test.
---
gcc/cp/constexpr.cc | 4 +++-
gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C | 2 ++
gcc/testsuite/g++.dg/diagnostic/constexpr4.C | 9 +++++++++
3 files changed, 14 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/g++.dg/diagnostic/constexpr4.C
Comments
On 11/15/23 13:03, Patrick Palka wrote:
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK
> for trunk/13/12 (to match the PR107939 / r13-6525-ge09bc034d1b4d6 backports)?
>
> -- >8 --
>
> potential_constant_expression for a CALL_EXPR to a non-overload tests
> FUNCTION_POINTER_TYPE_P on the callee rather than on the type of the
> callee, which means we always pass want_rval=any when recursing and so
> may fail to properly treat a non-constant function pointer callee as such.
> Fixing this turns out to further work around the PR111703 issue.
>
> PR c++/111703
> PR c++/107939
>
> gcc/cp/ChangeLog:
>
> * constexpr.cc (potential_constant_expression_1) <case CALL_EXPR>:
> Fix FUNCTION_POINTER_TYPE_P test.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/concepts-fn8.C: Extend test.
> * g++.dg/diagnostic/constexpr4.C: New test.
> ---
> gcc/cp/constexpr.cc | 4 +++-
> gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C | 2 ++
> gcc/testsuite/g++.dg/diagnostic/constexpr4.C | 9 +++++++++
> 3 files changed, 14 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/g++.dg/diagnostic/constexpr4.C
>
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 8a6b210144a..5ecc30117a1 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -9547,7 +9547,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
> }
> else if (fun)
> {
> - if (RECUR (fun, FUNCTION_POINTER_TYPE_P (fun) ? rval : any))
> + if (RECUR (fun, (TREE_TYPE (fun)
> + && FUNCTION_POINTER_TYPE_P (TREE_TYPE (fun))
> + ? rval : any)))
We might break this ?: out into a variable? OK either way.
> /* Might end up being a constant function pointer. But it
> could also be a function object with constexpr op(), so
> we pass 'any' so that the underlying VAR_DECL is deemed
> diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C b/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
> index 3f63a5b28d7..c63d26c931d 100644
> --- a/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
> +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-fn8.C
> @@ -15,10 +15,12 @@ struct P {
> };
>
> void (*f)(P);
> +P (*h)(P);
>
> template<class T>
> constexpr bool g() {
> P x;
> f(x); // { dg-bogus "from here" }
> + f(h(x)); // { dg-bogus "from here" }
> return true;
> }
> diff --git a/gcc/testsuite/g++.dg/diagnostic/constexpr4.C b/gcc/testsuite/g++.dg/diagnostic/constexpr4.C
> new file mode 100644
> index 00000000000..f971f533b08
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/diagnostic/constexpr4.C
> @@ -0,0 +1,9 @@
> +// Verify we diagnose a call to a non-constant function pointer ahead of time.
> +// { dg-do compile { target c++11 } }
> +
> +int (*f)(int);
> +
> +template<int N>
> +void g() {
> + static_assert(f(N) == 0, ""); // { dg-error "non-constant|'f' is not usable" }
> +}
@@ -9547,7 +9547,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
}
else if (fun)
{
- if (RECUR (fun, FUNCTION_POINTER_TYPE_P (fun) ? rval : any))
+ if (RECUR (fun, (TREE_TYPE (fun)
+ && FUNCTION_POINTER_TYPE_P (TREE_TYPE (fun))
+ ? rval : any)))
/* Might end up being a constant function pointer. But it
could also be a function object with constexpr op(), so
we pass 'any' so that the underlying VAR_DECL is deemed
@@ -15,10 +15,12 @@ struct P {
};
void (*f)(P);
+P (*h)(P);
template<class T>
constexpr bool g() {
P x;
f(x); // { dg-bogus "from here" }
+ f(h(x)); // { dg-bogus "from here" }
return true;
}
new file mode 100644
@@ -0,0 +1,9 @@
+// Verify we diagnose a call to a non-constant function pointer ahead of time.
+// { dg-do compile { target c++11 } }
+
+int (*f)(int);
+
+template<int N>
+void g() {
+ static_assert(f(N) == 0, ""); // { dg-error "non-constant|'f' is not usable" }
+}