[pushed] c++: Fix DMI with lambda 'this' capture [PR94205]

Patrick Palka ppalka@redhat.com
Wed Apr 1 14:47:24 GMT 2020


On Wed, 1 Apr 2020, Jason Merrill wrote:

> We represent 'this' in a default member initializer with a PLACEHOLDER_EXPR.
> Normally in constexpr evaluation when we encounter one it refers to
> ctx->ctor, but when we're creating a temporary of class type, that replaces
> ctx->ctor, so a PLACEHOLDER_EXPR that refers to the type of the member being
> initialized needs to be replaced before that happens.
> 
> This patch fixes the testcase below, but not the original testcase from the PR,
> which is still broken due to PR94219.
> 
> Tested x86_64-pc-linux-gnu, applying to trunk and 9.
> 
> gcc/cp/ChangeLog
> 2020-03-31  Jason Merrill  <jason@redhat.com>
> 
> 	PR c++/94205
> 	* constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call
> 	replace_placeholders.
> 	* typeck2.c (store_init_value): Fix arguments to
> 	fold_non_dependent_expr.
> ---
>  gcc/cp/constexpr.c                            |  6 ++++++
>  gcc/cp/tree.c                                 |  2 +-
>  gcc/cp/typeck2.c                              |  2 +-
>  gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi2.C | 20 +++++++++++++++++++
>  gcc/testsuite/g++.dg/cpp1z/lambda-this4.C     | 13 ++++++++++++
>  5 files changed, 41 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi2.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp1z/lambda-this4.C
> 
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index e85b3c113f0..91f0c3ba269 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -5553,6 +5553,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
>  	tree init = TARGET_EXPR_INITIAL (t);
>  	if ((AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)))
>  	  {
> +	    if (ctx->object)
> +	      /* If the initializer contains any PLACEHOLDER_EXPR, we need to
> +		 resolve them before we create a new CONSTRUCTOR for the
> +		 temporary.  */
> +	      init = replace_placeholders (init, ctx->object);

I think I'm running into an issue due to this call to replace_placeholders.
After this change, the following (compiled with -std=c++17) ICEs

    struct S
    {
      int a = [this] { return 6; } ();
    };

    S
    foo()
    {
      return {};
    }

with

    internal compiler error: in gimplify_var_or_parm_decl, at gimplify.c:2830

Unsharing 'init' before before doing replace_placeholders seems to fix
this ICE.

(This came up while working on PR94034, which seems like it may admit a
fix that's similar to this one for PR94205.)

> +
>  	    /* We're being expanded without an explicit target, so start
>  	       initializing a new object; expansion with an explicit target
>  	       strips the TARGET_EXPR before we get here.  */
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index a2172dea0d8..5eb0dcd717a 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -3239,7 +3239,7 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
>     a PLACEHOLDER_EXPR has been encountered.  */
>  
>  tree
> -replace_placeholders (tree exp, tree obj, bool *seen_p)
> +replace_placeholders (tree exp, tree obj, bool *seen_p /*= NULL*/)
>  {
>    /* This is only relevant for C++14.  */
>    if (cxx_dialect < cxx14)
> diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
> index bff4ddbcf81..cf1cb5ace66 100644
> --- a/gcc/cp/typeck2.c
> +++ b/gcc/cp/typeck2.c
> @@ -871,7 +871,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
>      {
>        bool const_init;
>        tree oldval = value;
> -      value = fold_non_dependent_expr (value);
> +      value = fold_non_dependent_expr (value, tf_warning_or_error, true, decl);
>        if (DECL_DECLARED_CONSTEXPR_P (decl)
>  	  || (DECL_IN_AGGR_P (decl)
>  	      && DECL_INITIALIZED_IN_CLASS_P (decl)))
> diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi2.C
> new file mode 100644
> index 00000000000..c51f734a134
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-nsdmi2.C
> @@ -0,0 +1,20 @@
> +// PR c++/94205
> +// { dg-do compile { target c++14 } }
> +
> +struct S
> +{
> +  struct A
> +  {
> +    S *p;
> +    constexpr A(S* p): p(p) {}
> +    constexpr operator int() { p->i = 5; return 6; }
> +  };
> +  int i;
> +  int a = A(this);
> +};
> +
> +
> +constexpr S s = {};
> +
> +#define SA(X) static_assert((X),#X)
> +SA(s.i == 5 && s.a == 6);
> diff --git a/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C b/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C
> new file mode 100644
> index 00000000000..5d968791491
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C
> @@ -0,0 +1,13 @@
> +// PR c++/94205
> +// { dg-do compile { target c++17 } }
> +
> +struct S
> +{
> +  int i;
> +  int a = [this] { this->i = 5; return 6; } ();
> +};
> +
> +
> +constexpr S s = {};
> +
> +static_assert (s.i == 5 && s.a == 6);
> 
> base-commit: f14b41d27124601284347a10d496362c8b4b8e1c
> -- 
> 2.18.1
> 
> 



More information about the Gcc-patches mailing list