c++: Don't ICE due to artificial constructor parameters [PR116722]

Message ID 010201921005af84-94b13c14-e527-438d-bcd9-437f012338aa-000000@eu-west-1.amazonses.com
State New
Headers
Series c++: Don't ICE due to artificial constructor parameters [PR116722] |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

Simon Martin Sept. 20, 2024, 3:21 p.m. UTC
  The following code triggers an ICE

=== cut here ===
class base {};
class derived : virtual public base {
public:
  template<typename Arg> constexpr derived(Arg) {}
};
int main() {
  derived obj(1.);
}
=== cut here ===

The problem is that cxx_bind_parameters_in_call ends up attempting to
convert a REAL_CST (the first non artificial parameter) to INTEGER_TYPE
(the type of the __in_chrg parameter), which ICEs.

This patch teaches cxx_bind_parameters_in_call to handle the __in_chrg
and __vtt_parm parameters that {con,de}structors might have.

Note that in the test case, the constructor is not constexpr-suitable,
however it's OK since it's a template according to my read of paragraph
(3) of [dcl.constexpr].

Successfully tested on x86_64-pc-linux-gnu.

	PR c++/116722

gcc/cp/ChangeLog:

	* constexpr.cc (cxx_bind_parameters_in_call): Leave artificial
	constructor parameters as is.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/constexpr-ctor22.C: New test.

---
 gcc/cp/constexpr.cc                           | 10 +++++++++-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C | 15 +++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C

-- 
2.44.0
  

Comments

Jason Merrill Sept. 20, 2024, 4:01 p.m. UTC | #1
On 9/20/24 5:21 PM, Simon Martin wrote:
> The following code triggers an ICE
> 
> === cut here ===
> class base {};
> class derived : virtual public base {
> public:
>    template<typename Arg> constexpr derived(Arg) {}
> };
> int main() {
>    derived obj(1.);
> }
> === cut here ===
> 
> The problem is that cxx_bind_parameters_in_call ends up attempting to
> convert a REAL_CST (the first non artificial parameter) to INTEGER_TYPE
> (the type of the __in_chrg parameter), which ICEs.
> 
> This patch teaches cxx_bind_parameters_in_call to handle the __in_chrg
> and __vtt_parm parameters that {con,de}structors might have.
> 
> Note that in the test case, the constructor is not constexpr-suitable,
> however it's OK since it's a template according to my read of paragraph
> (3) of [dcl.constexpr].

Agreed.

It looks like your patch doesn't correct the mismatching of arguments to 
parameters that you describe, but at least for now it should be enough 
to set *non_constant_p and return if we see a VTT or in-charge parameter.

> Successfully tested on x86_64-pc-linux-gnu.
> 
> 	PR c++/116722
> 
> gcc/cp/ChangeLog:
> 
> 	* constexpr.cc (cxx_bind_parameters_in_call): Leave artificial
> 	constructor parameters as is.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/constexpr-ctor22.C: New test.
> 
> ---
>   gcc/cp/constexpr.cc                           | 10 +++++++++-
>   gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C | 15 +++++++++++++++
>   2 files changed, 24 insertions(+), 1 deletion(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index f6fd059be46..815f93b1d47 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -1871,13 +1871,21 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
>         x = get_nth_callarg (t, i);
>         /* For member function, the first argument is a pointer to the implied
>            object.  For a constructor, it might still be a dummy object, in
> -         which case we get the real argument from ctx. */
> +	 which case we get the real argument from ctx.  */
>         if (i == 0 && DECL_CONSTRUCTOR_P (fun)
>   	  && is_dummy_object (x))
>   	{
>   	  x = ctx->object;
>   	  x = build_address (x);
>   	}
> +      /* Leave the __in_chrg and __vtt_parm parameters of *structors of classes
> +	 with virtual bases as is.  */
> +      if ((i == 1 && DECL_HAS_IN_CHARGE_PARM_P (fun))
> +	  || (i == 2 && DECL_HAS_VTT_PARM_P (fun)))
> +	{
> +	  TREE_VEC_ELT (binds, i) = arg;
> +	  continue;
> +	}
>         if (TREE_ADDRESSABLE (type))
>   	{
>   	  /* Undo convert_for_arg_passing work here.  */
> diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C
> new file mode 100644
> index 00000000000..279f6ec4454
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C
> @@ -0,0 +1,15 @@
> +// PR c++/116722
> +// We're now accepting this in spite of the virtual base class. This is OK
> +// according to [dcl.constexpr] 3: "Except for instantiated constexpr functions
> +// non-templated constexpr functions shall be constexpr-suitable".
> +// { dg-do compile { target c++11 } }
> +
> +class base {};
> +class derived : virtual public base {
> +public:
> +  template<typename Arg>
> +  constexpr derived(Arg) {}
> +};
> +int main() {
> +  derived obj(1.);
> +}
  

Patch

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index f6fd059be46..815f93b1d47 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1871,13 +1871,21 @@  cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, tree fun,
       x = get_nth_callarg (t, i);
       /* For member function, the first argument is a pointer to the implied
          object.  For a constructor, it might still be a dummy object, in
-         which case we get the real argument from ctx. */
+	 which case we get the real argument from ctx.  */
       if (i == 0 && DECL_CONSTRUCTOR_P (fun)
 	  && is_dummy_object (x))
 	{
 	  x = ctx->object;
 	  x = build_address (x);
 	}
+      /* Leave the __in_chrg and __vtt_parm parameters of *structors of classes
+	 with virtual bases as is.  */
+      if ((i == 1 && DECL_HAS_IN_CHARGE_PARM_P (fun))
+	  || (i == 2 && DECL_HAS_VTT_PARM_P (fun)))
+	{
+	  TREE_VEC_ELT (binds, i) = arg;
+	  continue;
+	}
       if (TREE_ADDRESSABLE (type))
 	{
 	  /* Undo convert_for_arg_passing work here.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C
new file mode 100644
index 00000000000..279f6ec4454
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor22.C
@@ -0,0 +1,15 @@ 
+// PR c++/116722
+// We're now accepting this in spite of the virtual base class. This is OK
+// according to [dcl.constexpr] 3: "Except for instantiated constexpr functions
+// non-templated constexpr functions shall be constexpr-suitable".
+// { dg-do compile { target c++11 } }
+
+class base {};
+class derived : virtual public base {
+public:
+  template<typename Arg>
+  constexpr derived(Arg) {}
+};
+int main() {
+  derived obj(1.);
+}