c++: Don't reject pointer to virtual method during constant evaluation [PR117615]
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Test passed
|
Commit Message
We currently reject the following valid code:
=== cut here ===
struct Base {
virtual void doit (int v) const {}
};
struct Derived : Base {
void doit (int v) const {}
};
using fn_t = void (Base::*)(int) const;
struct Helper {
fn_t mFn;
constexpr Helper (auto && fn) : mFn(static_cast<fn_t>(fn)) {}
};
void foo () {
constexpr Helper h (&Derived::doit);
}
=== cut here ===
The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
represented with an expression with type pointer to method and using an
INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects any
such expression with a non-null INTEGER_CST.
This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix for
PR c++/102786), and simply lets such expressions go through.
Successfully tested on x86_64-pc-linux-gnu.
PR c++/117615
gcc/cp/ChangeLog:
* constexpr.cc (cxx_eval_constant_expression): Don't reject
INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/constexpr-virtual22.C: New test.
---
gcc/cp/constexpr.cc | 27 ++++++++++++-------
.../g++.dg/cpp2a/constexpr-virtual22.C | 22 +++++++++++++++
2 files changed, 40 insertions(+), 9 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
Comments
On 12/3/24 12:25 PM, Simon Martin wrote:
> We currently reject the following valid code:
>
> === cut here ===
> struct Base {
> virtual void doit (int v) const {}
> };
> struct Derived : Base {
> void doit (int v) const {}
> };
> using fn_t = void (Base::*)(int) const;
> struct Helper {
> fn_t mFn;
> constexpr Helper (auto && fn) : mFn(static_cast<fn_t>(fn)) {}
> };
> void foo () {
> constexpr Helper h (&Derived::doit);
> }
> === cut here ===
>
> The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
> represented with an expression with type pointer to method and using an
> INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects any
> such expression with a non-null INTEGER_CST.
>
> This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix for
> PR c++/102786), and simply lets such expressions go through.
>
> Successfully tested on x86_64-pc-linux-gnu.
>
> PR c++/117615
>
> gcc/cp/ChangeLog:
>
> * constexpr.cc (cxx_eval_constant_expression): Don't reject
> INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.
>
> gcc/testsuite/ChangeLog:
>
> * g++.dg/cpp2a/constexpr-virtual22.C: New test.
>
> ---
> gcc/cp/constexpr.cc | 27 ++++++++++++-------
> .../g++.dg/cpp2a/constexpr-virtual22.C | 22 +++++++++++++++
> 2 files changed, 40 insertions(+), 9 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
>
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 5a87fa485c6..d9636bad683 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -8277,15 +8277,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
> }
> else
> {
> - /* This detects for example:
> - reinterpret_cast<void*>(sizeof 0)
> - */
> - if (!ctx->quiet)
> - error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
> - "a constant expression",
> - type, op);
> - *non_constant_p = true;
> - return t;
> + if (TYPE_PTR_P (type)
> + && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
> + /* INTEGER_CST with pointer-to-method type is only used
> + for a virtual method in a pointer to member function.
> + Don't reject those. */
> + ;
This could be "else if" added before the existing else so it doesn't
need to be reindented. OK with that change.
> + else
> + {
> + /* This detects for example:
> + reinterpret_cast<void*>(sizeof 0)
> + */
> + if (!ctx->quiet)
> + error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
> + "a constant expression",
> + type, op);
> + *non_constant_p = true;
> + return t;
> + }
> }
> }
>
> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
> new file mode 100644
> index 00000000000..89330bf8620
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
> @@ -0,0 +1,22 @@
> +// PR c++/117615
> +// { dg-do "compile" { target c++20 } }
> +
> +struct Base {
> + virtual void doit (int v) const {}
> +};
> +
> +struct Derived : Base {
> + void doit (int v) const {}
> +};
> +
> +using fn_t = void (Base::*)(int) const;
> +
> +struct Helper {
> + fn_t mFn;
> + constexpr Helper (auto && fn) : mFn(static_cast<fn_t>(fn)) {}
> +};
> +
> +void foo () {
> + constexpr Helper h (&Derived::doit);
> + constexpr Helper h2 (&Base::doit);
> +}
Hi Jason,
On 3 Dec 2024, at 22:37, Jason Merrill wrote:
> On 12/3/24 12:25 PM, Simon Martin wrote:
>> We currently reject the following valid code:
>>
>> === cut here ===
>> struct Base {
>> virtual void doit (int v) const {}
>> };
>> struct Derived : Base {
>> void doit (int v) const {}
>> };
>> using fn_t = void (Base::*)(int) const;
>> struct Helper {
>> fn_t mFn;
>> constexpr Helper (auto && fn) : mFn(static_cast<fn_t>(fn)) {}
>> };
>> void foo () {
>> constexpr Helper h (&Derived::doit);
>> }
>> === cut here ===
>>
>> The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
>> represented with an expression with type pointer to method and using
>> an
>> INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects
>> any
>> such expression with a non-null INTEGER_CST.
>>
>> This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix
>> for
>> PR c++/102786), and simply lets such expressions go through.
>>
>> Successfully tested on x86_64-pc-linux-gnu.
>>
>> PR c++/117615
>>
>> gcc/cp/ChangeLog:
>>
>> * constexpr.cc (cxx_eval_constant_expression): Don't reject
>> INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.
>>
>> gcc/testsuite/ChangeLog:
>>
>> * g++.dg/cpp2a/constexpr-virtual22.C: New test.
>>
>> ---
>> gcc/cp/constexpr.cc | 27
>> ++++++++++++-------
>> .../g++.dg/cpp2a/constexpr-virtual22.C | 22 +++++++++++++++
>> 2 files changed, 40 insertions(+), 9 deletions(-)
>> create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
>>
>> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
>> index 5a87fa485c6..d9636bad683 100644
>> --- a/gcc/cp/constexpr.cc
>> +++ b/gcc/cp/constexpr.cc
>> @@ -8277,15 +8277,24 @@ cxx_eval_constant_expression (const
>> constexpr_ctx *ctx, tree t,
>> }
>> else
>> {
>> - /* This detects for example:
>> - reinterpret_cast<void*>(sizeof 0)
>> - */
>> - if (!ctx->quiet)
>> - error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
>> - "a constant expression",
>> - type, op);
>> - *non_constant_p = true;
>> - return t;
>> + if (TYPE_PTR_P (type)
>> + && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
>> + /* INTEGER_CST with pointer-to-method type is only used
>> + for a virtual method in a pointer to member function.
>> + Don't reject those. */
>> + ;
>
> This could be "else if" added before the existing else so it doesn't
> need to be reindented. OK with that change.
Thanks, merged as r15-5920-g72a2380a306a1c with the suggested change.
Since this is a reject-valid, also OK for active branches?
Simon
On 12/4/24 5:52 AM, Simon Martin wrote:
> Hi Jason,
>
> On 3 Dec 2024, at 22:37, Jason Merrill wrote:
>
>> On 12/3/24 12:25 PM, Simon Martin wrote:
>>> We currently reject the following valid code:
>>>
>>> === cut here ===
>>> struct Base {
>>> virtual void doit (int v) const {}
>>> };
>>> struct Derived : Base {
>>> void doit (int v) const {}
>>> };
>>> using fn_t = void (Base::*)(int) const;
>>> struct Helper {
>>> fn_t mFn;
>>> constexpr Helper (auto && fn) : mFn(static_cast<fn_t>(fn)) {}
>>> };
>>> void foo () {
>>> constexpr Helper h (&Derived::doit);
>>> }
>>> === cut here ===
>>>
>>> The problem is that since r6-4014-gdcdbc004d531b4, &Derived::doit is
>>> represented with an expression with type pointer to method and using
>>> an
>>> INTEGER_CST (here 1), and that cxx_eval_constant_expression rejects
>>> any
>>> such expression with a non-null INTEGER_CST.
>>>
>>> This patch uses the same strategy as r12-4491-gf45610a45236e9 (fix
>>> for
>>> PR c++/102786), and simply lets such expressions go through.
>>>
>>> Successfully tested on x86_64-pc-linux-gnu.
>>>
>>> PR c++/117615
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> * constexpr.cc (cxx_eval_constant_expression): Don't reject
>>> INTEGER_CSTs with type POINTER_TYPE to METHOD_TYPE.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * g++.dg/cpp2a/constexpr-virtual22.C: New test.
>>>
>>> ---
>>> gcc/cp/constexpr.cc | 27
>>> ++++++++++++-------
>>> .../g++.dg/cpp2a/constexpr-virtual22.C | 22 +++++++++++++++
>>> 2 files changed, 40 insertions(+), 9 deletions(-)
>>> create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-virtual22.C
>>>
>>> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
>>> index 5a87fa485c6..d9636bad683 100644
>>> --- a/gcc/cp/constexpr.cc
>>> +++ b/gcc/cp/constexpr.cc
>>> @@ -8277,15 +8277,24 @@ cxx_eval_constant_expression (const
>>> constexpr_ctx *ctx, tree t,
>>> }
>>> else
>>> {
>>> - /* This detects for example:
>>> - reinterpret_cast<void*>(sizeof 0)
>>> - */
>>> - if (!ctx->quiet)
>>> - error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
>>> - "a constant expression",
>>> - type, op);
>>> - *non_constant_p = true;
>>> - return t;
>>> + if (TYPE_PTR_P (type)
>>> + && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
>>> + /* INTEGER_CST with pointer-to-method type is only used
>>> + for a virtual method in a pointer to member function.
>>> + Don't reject those. */
>>> + ;
>>
>> This could be "else if" added before the existing else so it doesn't
>> need to be reindented. OK with that change.
> Thanks, merged as r15-5920-g72a2380a306a1c with the suggested change.
>
> Since this is a reject-valid, also OK for active branches?
Yes.
Jason
@@ -8277,15 +8277,24 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
}
else
{
- /* This detects for example:
- reinterpret_cast<void*>(sizeof 0)
- */
- if (!ctx->quiet)
- error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
- "a constant expression",
- type, op);
- *non_constant_p = true;
- return t;
+ if (TYPE_PTR_P (type)
+ && TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ /* INTEGER_CST with pointer-to-method type is only used
+ for a virtual method in a pointer to member function.
+ Don't reject those. */
+ ;
+ else
+ {
+ /* This detects for example:
+ reinterpret_cast<void*>(sizeof 0)
+ */
+ if (!ctx->quiet)
+ error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
+ "a constant expression",
+ type, op);
+ *non_constant_p = true;
+ return t;
+ }
}
}
new file mode 100644
@@ -0,0 +1,22 @@
+// PR c++/117615
+// { dg-do "compile" { target c++20 } }
+
+struct Base {
+ virtual void doit (int v) const {}
+};
+
+struct Derived : Base {
+ void doit (int v) const {}
+};
+
+using fn_t = void (Base::*)(int) const;
+
+struct Helper {
+ fn_t mFn;
+ constexpr Helper (auto && fn) : mFn(static_cast<fn_t>(fn)) {}
+};
+
+void foo () {
+ constexpr Helper h (&Derived::doit);
+ constexpr Helper h2 (&Base::doit);
+}