diff mbox series

[C++,1/3] Fix various latent issues revealed by P0732 work.

Message ID 20181105020608.27036-1-jason@redhat.com
State New
Headers show
Series [C++,1/3] Fix various latent issues revealed by P0732 work. | expand

Commit Message

Jason Merrill Nov. 5, 2018, 2:06 a.m. UTC
The initialized_type hunk fixes handling of void AGGR_INIT_EXPRs that call a
non-constructor; an AGGR_INIT_EXPR can have void type if its initialization
semantics are more complicated than just expanding the call.

The cxx_eval_vec_init_1 hunk corrects AGGR_INIT_EXPRs that were
nonsensically built to initialize an object of void type.  And the
build_aggr_init_expr hunk makes sure we don't do that again.

The ocp_convert and cxx_eval_outermost_constant_expr hunks deal with making
sure that a constant CONSTRUCTOR has the right type.

Tested x86_64-pc-linux-gnu, applying to trunk.

	* cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
	* constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
	(cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
	(cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
	right type.  Don't wrap a CONSTRUCTOR if one was passed in.
	* tree.c (build_aggr_init_expr): Check for void.
---
 gcc/cp/constexpr.c | 22 +++++++++++++---------
 gcc/cp/cvt.c       | 10 +++++++++-
 gcc/cp/tree.c      |  2 ++
 gcc/cp/ChangeLog   |  7 +++++++
 4 files changed, 31 insertions(+), 10 deletions(-)


base-commit: 703d2f69fad4772dc4aedb5327b5e3d88e8e1843

Comments

Matthew Malcomson Nov. 9, 2018, 10:28 a.m. UTC | #1
(Third attempt to put this on the mailing list now -- today is not a good day for my email skills :-[)

Hi there,

This patch has caused a few g++ and libstdc++ regression test failures on arm,

I've included the g++ failures below.

Do you mind looking into this?
Cheers,

Matthew


dg-cmp-results.sh: Verbosity is 2, Variant is ""

Older log file: just-before-problemcase-g++.sum
Test Run By matthew on Thu Nov  8 16:45:40 2018
Target is arm-none-eabi
Host   is x86_64-pc-linux-gnu

Newer log file: g++-after-problem.sum
Test Run By matthew on Thu Nov  8 21:36:14 2018
Target is arm-none-eabi
Host   is x86_64-pc-linux-gnu

PASS->FAIL: g++.dg/cpp0x/constexpr-static12.C  -std=c++14 scan-assembler-not _ZNSt10unique_ptrC1Ei
PASS->FAIL: g++.dg/cpp0x/constexpr-static12.C  -std=c++17 scan-assembler-not _ZNSt10unique_ptrC1Ei
PASS->FAIL: g++.dg/cpp0x/constexpr-static3.C  -std=gnu++14 scan-assembler-not static_initialization
PASS->FAIL: g++.dg/cpp0x/constexpr-static3.C  -std=gnu++17 scan-assembler-not static_initialization
PASS->FAIL: g++.dg/cpp0x/constexpr-static.C  -std=gnu++14 scan-assembler-not static_initialization
PASS->FAIL: g++.dg/cpp0x/constexpr-static.C  -std=gnu++17 scan-assembler-not static_initialization
PASS->FAIL: g++.dg/cpp0x/implicit13.C  -std=c++14 scan-assembler-not _ZN1BC1Ev
PASS->FAIL: g++.dg/cpp0x/implicit13.C  -std=c++17 scan-assembler-not _ZN1BC1Ev
NA->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++14 (internal compiler error)
PASS->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++14 (test for excess errors)
NA->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++17 (internal compiler error)
PASS->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++17 (test for excess errors)
PASS->FAIL: g++.dg/cpp1y/constexpr-empty3.C  -std=c++14 scan-assembler-not static_init
PASS->FAIL: g++.dg/cpp1y/constexpr-empty3.C  -std=c++17 scan-assembler-not static_init


On 05/11/18 02:06, Jason Merrill wrote:
The initialized_type hunk fixes handling of void AGGR_INIT_EXPRs that call a
non-constructor; an AGGR_INIT_EXPR can have void type if its initialization
semantics are more complicated than just expanding the call.

The cxx_eval_vec_init_1 hunk corrects AGGR_INIT_EXPRs that were
nonsensically built to initialize an object of void type.  And the
build_aggr_init_expr hunk makes sure we don't do that again.

The ocp_convert and cxx_eval_outermost_constant_expr hunks deal with making
sure that a constant CONSTRUCTOR has the right type.

Tested x86_64-pc-linux-gnu, applying to trunk.

    * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
    * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
    (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
    (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
    right type.  Don't wrap a CONSTRUCTOR if one was passed in.
    * tree.c (build_aggr_init_expr): Check for void.
---
  gcc/cp/constexpr.c | 22 +++++++++++++---------
  gcc/cp/cvt.c       | 10 +++++++++-
  gcc/cp/tree.c      |  2 ++
  gcc/cp/ChangeLog   |  7 +++++++
  4 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 7692b1727da..4fb1ba527e3 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2778,8 +2778,10 @@ initialized_type (tree t)
  {
    if (TYPE_P (t))
      return t;
-  tree type = cv_unqualified (TREE_TYPE (t));
-  if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
+  tree type = TREE_TYPE (t);
+  if (!VOID_TYPE_P (type))
+    /* No need to look deeper.  */;
+  else if (TREE_CODE (t) == CALL_EXPR)
      {
        /* A constructor call has void type, so we need to look deeper.  */
        tree fn = get_function_named_in_call (t);
@@ -2787,7 +2789,9 @@ initialized_type (tree t)
        && DECL_CXX_CONSTRUCTOR_P (fn))
      type = DECL_CONTEXT (fn);
      }
-  return type;
+  else if (TREE_CODE (t) == AGGR_INIT_EXPR)
+    type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
+  return cv_unqualified (type);
  }
    /* We're about to initialize element INDEX of an array or class from VALUE.
@@ -3000,7 +3004,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
                      &argvec, elttype, LOOKUP_NORMAL,
                      complain);
        release_tree_vector (argvec);
-      init = build_aggr_init_expr (TREE_TYPE (init), init);
+      init = build_aggr_init_expr (elttype, init);
        pre_init = true;
      }
  @@ -5089,7 +5093,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
      r = build_nop (TREE_TYPE (r), r);
        TREE_CONSTANT (r) = false;
      }
-  else if (non_constant_p || r == t)
+  else if (non_constant_p)
      return t;
      if (should_unshare)
@@ -5097,18 +5101,18 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
      if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
      {
+      r = adjust_temp_type (type, r);
        if (TREE_CODE (t) == TARGET_EXPR
        && TARGET_EXPR_INITIAL (t) == r)
      return t;
-      else
+      else if (TREE_CODE (t) != CONSTRUCTOR)
      {
        r = get_target_expr (r);
        TREE_CONSTANT (r) = true;
-      return r;
      }
      }
-  else
-    return r;
+
+  return r;
  }
    /* Returns true if T is a valid subexpression of a constant expression,
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 315b0d6a65a..b04e9a70652 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -725,7 +725,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
      /* We need a new temporary; don't take this shortcut.  */;
    else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
      {
-      if (same_type_p (type, TREE_TYPE (e)))
+      tree etype = TREE_TYPE (e);
+      if (same_type_p (type, etype))
      /* The call to fold will not always remove the NOP_EXPR as
         might be expected, since if one of the types is a typedef;
         the comparison in fold is just equality of pointers, not a
@@ -743,9 +744,16 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
      {
        /* Don't build a NOP_EXPR of class type.  Instead, change the
           type of the temporary.  */
+      gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
        TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
        return e;
      }
+      else if (TREE_CODE (e) == CONSTRUCTOR)
+    {
+      gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
+      TREE_TYPE (e) = type;
+      return e;
+    }
        else
      {
        /* We shouldn't be treating objects of ADDRESSABLE type as
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 74018e97bb7..51af9f2015e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -576,6 +576,8 @@ build_aggr_init_expr (tree type, tree init)
    tree rval;
    int is_ctor;
  +  gcc_assert (!VOID_TYPE_P (type));
+
    /* Don't build AGGR_INIT_EXPR in a template.  */
    if (processing_template_decl)
      return init;
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7e9c0e2642a..4f40627a226 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,12 @@
  2018-11-04  Jason Merrill  <jason@redhat.com><mailto:jason@redhat.com>
  +    * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
+    * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
+    (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
+    (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
+    right type.  Don't wrap a CONSTRUCTOR if one was passed in.
+    * tree.c (build_aggr_init_expr): Check for void.
+
      PR c++/60503 - wrong lambda attribute syntax.
      * parser.c (cp_parser_lambda_declarator_opt): Fix attribute
      handling.

base-commit: 703d2f69fad4772dc4aedb5327b5e3d88e8e1843


On 05/11/18 02:06, Jason Merrill wrote:

The initialized_type hunk fixes handling of void AGGR_INIT_EXPRs that call a
non-constructor; an AGGR_INIT_EXPR can have void type if its initialization
semantics are more complicated than just expanding the call.

The cxx_eval_vec_init_1 hunk corrects AGGR_INIT_EXPRs that were
nonsensically built to initialize an object of void type.  And the
build_aggr_init_expr hunk makes sure we don't do that again.

The ocp_convert and cxx_eval_outermost_constant_expr hunks deal with making
sure that a constant CONSTRUCTOR has the right type.

Tested x86_64-pc-linux-gnu, applying to trunk.

        * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
        * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
        (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
        (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
        right type.  Don't wrap a CONSTRUCTOR if one was passed in.
        * tree.c (build_aggr_init_expr): Check for void.
---
 gcc/cp/constexpr.c | 22 +++++++++++++---------
 gcc/cp/cvt.c       | 10 +++++++++-
 gcc/cp/tree.c      |  2 ++
 gcc/cp/ChangeLog   |  7 +++++++
 4 files changed, 31 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 7692b1727da..4fb1ba527e3 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2778,8 +2778,10 @@ initialized_type (tree t)
 {
   if (TYPE_P (t))
     return t;
-  tree type = cv_unqualified (TREE_TYPE (t));
-  if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
+  tree type = TREE_TYPE (t);
+  if (!VOID_TYPE_P (type))
+    /* No need to look deeper.  */;
+  else if (TREE_CODE (t) == CALL_EXPR)
     {
       /* A constructor call has void type, so we need to look deeper.  */
       tree fn = get_function_named_in_call (t);
@@ -2787,7 +2789,9 @@ initialized_type (tree t)
          && DECL_CXX_CONSTRUCTOR_P (fn))
        type = DECL_CONTEXT (fn);
     }
-  return type;
+  else if (TREE_CODE (t) == AGGR_INIT_EXPR)
+    type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
+  return cv_unqualified (type);
 }

 /* We're about to initialize element INDEX of an array or class from VALUE.
@@ -3000,7 +3004,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
                                        &argvec, elttype, LOOKUP_NORMAL,
                                        complain);
       release_tree_vector (argvec);
-      init = build_aggr_init_expr (TREE_TYPE (init), init);
+      init = build_aggr_init_expr (elttype, init);
       pre_init = true;
     }

@@ -5089,7 +5093,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
        r = build_nop (TREE_TYPE (r), r);
       TREE_CONSTANT (r) = false;
     }
-  else if (non_constant_p || r == t)
+  else if (non_constant_p)
     return t;

   if (should_unshare)
@@ -5097,18 +5101,18 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,

   if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
     {
+      r = adjust_temp_type (type, r);
       if (TREE_CODE (t) == TARGET_EXPR
          && TARGET_EXPR_INITIAL (t) == r)
        return t;
-      else
+      else if (TREE_CODE (t) != CONSTRUCTOR)
        {
          r = get_target_expr (r);
          TREE_CONSTANT (r) = true;
-         return r;
        }
     }
-  else
-    return r;
+
+  return r;
 }

 /* Returns true if T is a valid subexpression of a constant expression,
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 315b0d6a65a..b04e9a70652 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -725,7 +725,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
     /* We need a new temporary; don't take this shortcut.  */;
   else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
     {
-      if (same_type_p (type, TREE_TYPE (e)))
+      tree etype = TREE_TYPE (e);
+      if (same_type_p (type, etype))
        /* The call to fold will not always remove the NOP_EXPR as
           might be expected, since if one of the types is a typedef;
           the comparison in fold is just equality of pointers, not a
@@ -743,9 +744,16 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
        {
          /* Don't build a NOP_EXPR of class type.  Instead, change the
             type of the temporary.  */
+         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
          TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
          return e;
        }
+      else if (TREE_CODE (e) == CONSTRUCTOR)
+       {
+         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
+         TREE_TYPE (e) = type;
+         return e;
+       }
       else
        {
          /* We shouldn't be treating objects of ADDRESSABLE type as
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 74018e97bb7..51af9f2015e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -576,6 +576,8 @@ build_aggr_init_expr (tree type, tree init)
   tree rval;
   int is_ctor;

+  gcc_assert (!VOID_TYPE_P (type));
+
   /* Don't build AGGR_INIT_EXPR in a template.  */
   if (processing_template_decl)
     return init;
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7e9c0e2642a..4f40627a226 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,12 @@
 2018-11-04  Jason Merrill  <jason@redhat.com><mailto:jason@redhat.com>

+       * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
+       * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
+       (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
+       (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
+       right type.  Don't wrap a CONSTRUCTOR if one was passed in.
+       * tree.c (build_aggr_init_expr): Check for void.
+
        PR c++/60503 - wrong lambda attribute syntax.
        * parser.c (cp_parser_lambda_declarator_opt): Fix attribute
        handling.

base-commit: 703d2f69fad4772dc4aedb5327b5e3d88e8e1843
Kyrill Tkachov Nov. 9, 2018, 10:31 a.m. UTC | #2
On 09/11/18 10:28, Matthew Malcomson wrote:
> (Third attempt to put this on the mailing list now -- today is not a good day for my email skills :-[)
>
> Hi there,
>
> This patch has caused a few g++ and libstdc++ regression test failures on arm,
>
> I've included the g++ failures below.
>
> Do you mind looking into this?
> Cheers,
>
> Matthew
>
>
> dg-cmp-results.sh: Verbosity is 2, Variant is ""
>
> Older log file: just-before-problemcase-g++.sum
> Test Run By matthew on Thu Nov  8 16:45:40 2018
> Target is arm-none-eabi
> Host   is x86_64-pc-linux-gnu
>
> Newer log file: g++-after-problem.sum
> Test Run By matthew on Thu Nov  8 21:36:14 2018
> Target is arm-none-eabi
> Host   is x86_64-pc-linux-gnu
>
> PASS->FAIL: g++.dg/cpp0x/constexpr-static12.C  -std=c++14 scan-assembler-not _ZNSt10unique_ptrC1Ei
> PASS->FAIL: g++.dg/cpp0x/constexpr-static12.C  -std=c++17 scan-assembler-not _ZNSt10unique_ptrC1Ei
> PASS->FAIL: g++.dg/cpp0x/constexpr-static3.C -std=gnu++14 scan-assembler-not static_initialization
> PASS->FAIL: g++.dg/cpp0x/constexpr-static3.C -std=gnu++17 scan-assembler-not static_initialization
> PASS->FAIL: g++.dg/cpp0x/constexpr-static.C  -std=gnu++14 scan-assembler-not static_initialization
> PASS->FAIL: g++.dg/cpp0x/constexpr-static.C  -std=gnu++17 scan-assembler-not static_initialization
> PASS->FAIL: g++.dg/cpp0x/implicit13.C  -std=c++14 scan-assembler-not _ZN1BC1Ev
> PASS->FAIL: g++.dg/cpp0x/implicit13.C  -std=c++17 scan-assembler-not _ZN1BC1Ev
> NA->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++14 (internal compiler error)
> PASS->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++14 (test for excess errors)
> NA->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++17 (internal compiler error)
> PASS->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++17 (test for excess errors)
> PASS->FAIL: g++.dg/cpp1y/constexpr-empty3.C  -std=c++14 scan-assembler-not static_init
> PASS->FAIL: g++.dg/cpp1y/constexpr-empty3.C  -std=c++17 scan-assembler-not static_init
>
>

I believe these are tracked in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87935 FWIW.

Kyrill

> On 05/11/18 02:06, Jason Merrill wrote:
> The initialized_type hunk fixes handling of void AGGR_INIT_EXPRs that call a
> non-constructor; an AGGR_INIT_EXPR can have void type if its initialization
> semantics are more complicated than just expanding the call.
>
> The cxx_eval_vec_init_1 hunk corrects AGGR_INIT_EXPRs that were
> nonsensically built to initialize an object of void type. And the
> build_aggr_init_expr hunk makes sure we don't do that again.
>
> The ocp_convert and cxx_eval_outermost_constant_expr hunks deal with making
> sure that a constant CONSTRUCTOR has the right type.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.
>
>     * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
>     * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
>     (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
>     (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
>     right type.  Don't wrap a CONSTRUCTOR if one was passed in.
>     * tree.c (build_aggr_init_expr): Check for void.
> ---
>   gcc/cp/constexpr.c | 22 +++++++++++++---------
>   gcc/cp/cvt.c       | 10 +++++++++-
>   gcc/cp/tree.c      |  2 ++
>   gcc/cp/ChangeLog   |  7 +++++++
>   4 files changed, 31 insertions(+), 10 deletions(-)
>
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 7692b1727da..4fb1ba527e3 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -2778,8 +2778,10 @@ initialized_type (tree t)
>   {
>     if (TYPE_P (t))
>       return t;
> -  tree type = cv_unqualified (TREE_TYPE (t));
> -  if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
> +  tree type = TREE_TYPE (t);
> +  if (!VOID_TYPE_P (type))
> +    /* No need to look deeper.  */;
> +  else if (TREE_CODE (t) == CALL_EXPR)
>       {
>         /* A constructor call has void type, so we need to look deeper.  */
>         tree fn = get_function_named_in_call (t);
> @@ -2787,7 +2789,9 @@ initialized_type (tree t)
>         && DECL_CXX_CONSTRUCTOR_P (fn))
>       type = DECL_CONTEXT (fn);
>       }
> -  return type;
> +  else if (TREE_CODE (t) == AGGR_INIT_EXPR)
> +    type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
> +  return cv_unqualified (type);
>   }
>     /* We're about to initialize element INDEX of an array or class from VALUE.
> @@ -3000,7 +3004,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
>                       &argvec, elttype, LOOKUP_NORMAL,
>                       complain);
>         release_tree_vector (argvec);
> -      init = build_aggr_init_expr (TREE_TYPE (init), init);
> +      init = build_aggr_init_expr (elttype, init);
>         pre_init = true;
>       }
>   @@ -5089,7 +5093,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
>       r = build_nop (TREE_TYPE (r), r);
>         TREE_CONSTANT (r) = false;
>       }
> -  else if (non_constant_p || r == t)
> +  else if (non_constant_p)
>       return t;
>       if (should_unshare)
> @@ -5097,18 +5101,18 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
>       if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
>       {
> +      r = adjust_temp_type (type, r);
>         if (TREE_CODE (t) == TARGET_EXPR
>         && TARGET_EXPR_INITIAL (t) == r)
>       return t;
> -      else
> +      else if (TREE_CODE (t) != CONSTRUCTOR)
>       {
>         r = get_target_expr (r);
>         TREE_CONSTANT (r) = true;
> -      return r;
>       }
>       }
> -  else
> -    return r;
> +
> +  return r;
>   }
>     /* Returns true if T is a valid subexpression of a constant expression,
> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> index 315b0d6a65a..b04e9a70652 100644
> --- a/gcc/cp/cvt.c
> +++ b/gcc/cp/cvt.c
> @@ -725,7 +725,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
>       /* We need a new temporary; don't take this shortcut. */;
>     else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
>       {
> -      if (same_type_p (type, TREE_TYPE (e)))
> +      tree etype = TREE_TYPE (e);
> +      if (same_type_p (type, etype))
>       /* The call to fold will not always remove the NOP_EXPR as
>          might be expected, since if one of the types is a typedef;
>          the comparison in fold is just equality of pointers, not a
> @@ -743,9 +744,16 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
>       {
>         /* Don't build a NOP_EXPR of class type.  Instead, change the
>            type of the temporary.  */
> +      gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
>         TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
>         return e;
>       }
> +      else if (TREE_CODE (e) == CONSTRUCTOR)
> +    {
> +      gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
> +      TREE_TYPE (e) = type;
> +      return e;
> +    }
>         else
>       {
>         /* We shouldn't be treating objects of ADDRESSABLE type as
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index 74018e97bb7..51af9f2015e 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -576,6 +576,8 @@ build_aggr_init_expr (tree type, tree init)
>     tree rval;
>     int is_ctor;
>   +  gcc_assert (!VOID_TYPE_P (type));
> +
>     /* Don't build AGGR_INIT_EXPR in a template.  */
>     if (processing_template_decl)
>       return init;
> diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
> index 7e9c0e2642a..4f40627a226 100644
> --- a/gcc/cp/ChangeLog
> +++ b/gcc/cp/ChangeLog
> @@ -1,5 +1,12 @@
>   2018-11-04  Jason Merrill <jason@redhat.com><mailto:jason@redhat.com>
>   +    * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
> +    * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
> +    (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
> +    (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
> +    right type.  Don't wrap a CONSTRUCTOR if one was passed in.
> +    * tree.c (build_aggr_init_expr): Check for void.
> +
>       PR c++/60503 - wrong lambda attribute syntax.
>       * parser.c (cp_parser_lambda_declarator_opt): Fix attribute
>       handling.
>
> base-commit: 703d2f69fad4772dc4aedb5327b5e3d88e8e1843
>
>
> On 05/11/18 02:06, Jason Merrill wrote:
>
> The initialized_type hunk fixes handling of void AGGR_INIT_EXPRs that call a
> non-constructor; an AGGR_INIT_EXPR can have void type if its initialization
> semantics are more complicated than just expanding the call.
>
> The cxx_eval_vec_init_1 hunk corrects AGGR_INIT_EXPRs that were
> nonsensically built to initialize an object of void type. And the
> build_aggr_init_expr hunk makes sure we don't do that again.
>
> The ocp_convert and cxx_eval_outermost_constant_expr hunks deal with making
> sure that a constant CONSTRUCTOR has the right type.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.
>
>         * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
>         * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
>         (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
>         (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
>         right type.  Don't wrap a CONSTRUCTOR if one was passed in.
>         * tree.c (build_aggr_init_expr): Check for void.
> ---
>  gcc/cp/constexpr.c | 22 +++++++++++++---------
>  gcc/cp/cvt.c       | 10 +++++++++-
>  gcc/cp/tree.c      |  2 ++
>  gcc/cp/ChangeLog   |  7 +++++++
>  4 files changed, 31 insertions(+), 10 deletions(-)
>
> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> index 7692b1727da..4fb1ba527e3 100644
> --- a/gcc/cp/constexpr.c
> +++ b/gcc/cp/constexpr.c
> @@ -2778,8 +2778,10 @@ initialized_type (tree t)
>  {
>    if (TYPE_P (t))
>      return t;
> -  tree type = cv_unqualified (TREE_TYPE (t));
> -  if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
> +  tree type = TREE_TYPE (t);
> +  if (!VOID_TYPE_P (type))
> +    /* No need to look deeper.  */;
> +  else if (TREE_CODE (t) == CALL_EXPR)
>      {
>        /* A constructor call has void type, so we need to look deeper.  */
>        tree fn = get_function_named_in_call (t);
> @@ -2787,7 +2789,9 @@ initialized_type (tree t)
>           && DECL_CXX_CONSTRUCTOR_P (fn))
>         type = DECL_CONTEXT (fn);
>      }
> -  return type;
> +  else if (TREE_CODE (t) == AGGR_INIT_EXPR)
> +    type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
> +  return cv_unqualified (type);
>  }
>
>  /* We're about to initialize element INDEX of an array or class from VALUE.
> @@ -3000,7 +3004,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
>                                         &argvec, elttype, LOOKUP_NORMAL,
>                                         complain);
>        release_tree_vector (argvec);
> -      init = build_aggr_init_expr (TREE_TYPE (init), init);
> +      init = build_aggr_init_expr (elttype, init);
>        pre_init = true;
>      }
>
> @@ -5089,7 +5093,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
>         r = build_nop (TREE_TYPE (r), r);
>        TREE_CONSTANT (r) = false;
>      }
> -  else if (non_constant_p || r == t)
> +  else if (non_constant_p)
>      return t;
>
>    if (should_unshare)
> @@ -5097,18 +5101,18 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
>
>    if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
>      {
> +      r = adjust_temp_type (type, r);
>        if (TREE_CODE (t) == TARGET_EXPR
>           && TARGET_EXPR_INITIAL (t) == r)
>         return t;
> -      else
> +      else if (TREE_CODE (t) != CONSTRUCTOR)
>         {
>           r = get_target_expr (r);
>           TREE_CONSTANT (r) = true;
> -         return r;
>         }
>      }
> -  else
> -    return r;
> +
> +  return r;
>  }
>
>  /* Returns true if T is a valid subexpression of a constant expression,
> diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> index 315b0d6a65a..b04e9a70652 100644
> --- a/gcc/cp/cvt.c
> +++ b/gcc/cp/cvt.c
> @@ -725,7 +725,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
>      /* We need a new temporary; don't take this shortcut. */;
>    else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
>      {
> -      if (same_type_p (type, TREE_TYPE (e)))
> +      tree etype = TREE_TYPE (e);
> +      if (same_type_p (type, etype))
>         /* The call to fold will not always remove the NOP_EXPR as
>            might be expected, since if one of the types is a typedef;
>            the comparison in fold is just equality of pointers, not a
> @@ -743,9 +744,16 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
>         {
>           /* Don't build a NOP_EXPR of class type.  Instead, change the
>              type of the temporary.  */
> +         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
>           TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
>           return e;
>         }
> +      else if (TREE_CODE (e) == CONSTRUCTOR)
> +       {
> +         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
> +         TREE_TYPE (e) = type;
> +         return e;
> +       }
>        else
>         {
>           /* We shouldn't be treating objects of ADDRESSABLE type as
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index 74018e97bb7..51af9f2015e 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -576,6 +576,8 @@ build_aggr_init_expr (tree type, tree init)
>    tree rval;
>    int is_ctor;
>
> +  gcc_assert (!VOID_TYPE_P (type));
> +
>    /* Don't build AGGR_INIT_EXPR in a template.  */
>    if (processing_template_decl)
>      return init;
> diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
> index 7e9c0e2642a..4f40627a226 100644
> --- a/gcc/cp/ChangeLog
> +++ b/gcc/cp/ChangeLog
> @@ -1,5 +1,12 @@
>  2018-11-04  Jason Merrill <jason@redhat.com><mailto:jason@redhat.com>
>
> +       * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
> +       * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
> +       (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
> +       (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
> +       right type.  Don't wrap a CONSTRUCTOR if one was passed in.
> +       * tree.c (build_aggr_init_expr): Check for void.
> +
>         PR c++/60503 - wrong lambda attribute syntax.
>         * parser.c (cp_parser_lambda_declarator_opt): Fix attribute
>         handling.
>
> base-commit: 703d2f69fad4772dc4aedb5327b5e3d88e8e1843
>
Christophe Lyon Nov. 9, 2018, 11:33 a.m. UTC | #3
On Fri, 9 Nov 2018 at 11:32, Kyrill Tkachov <kyrylo.tkachov@foss.arm.com> wrote:
>
>
> On 09/11/18 10:28, Matthew Malcomson wrote:
> > (Third attempt to put this on the mailing list now -- today is not a good day for my email skills :-[)
> >
> > Hi there,
> >
> > This patch has caused a few g++ and libstdc++ regression test failures on arm,
> >
> > I've included the g++ failures below.
> >
> > Do you mind looking into this?
> > Cheers,
> >
> > Matthew
> >
> >
> > dg-cmp-results.sh: Verbosity is 2, Variant is ""
> >
> > Older log file: just-before-problemcase-g++.sum
> > Test Run By matthew on Thu Nov  8 16:45:40 2018
> > Target is arm-none-eabi
> > Host   is x86_64-pc-linux-gnu
> >
> > Newer log file: g++-after-problem.sum
> > Test Run By matthew on Thu Nov  8 21:36:14 2018
> > Target is arm-none-eabi
> > Host   is x86_64-pc-linux-gnu
> >
> > PASS->FAIL: g++.dg/cpp0x/constexpr-static12.C  -std=c++14 scan-assembler-not _ZNSt10unique_ptrC1Ei
> > PASS->FAIL: g++.dg/cpp0x/constexpr-static12.C  -std=c++17 scan-assembler-not _ZNSt10unique_ptrC1Ei
> > PASS->FAIL: g++.dg/cpp0x/constexpr-static3.C -std=gnu++14 scan-assembler-not static_initialization
> > PASS->FAIL: g++.dg/cpp0x/constexpr-static3.C -std=gnu++17 scan-assembler-not static_initialization
> > PASS->FAIL: g++.dg/cpp0x/constexpr-static.C  -std=gnu++14 scan-assembler-not static_initialization
> > PASS->FAIL: g++.dg/cpp0x/constexpr-static.C  -std=gnu++17 scan-assembler-not static_initialization
> > PASS->FAIL: g++.dg/cpp0x/implicit13.C  -std=c++14 scan-assembler-not _ZN1BC1Ev
> > PASS->FAIL: g++.dg/cpp0x/implicit13.C  -std=c++17 scan-assembler-not _ZN1BC1Ev
> > NA->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++14 (internal compiler error)
> > PASS->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++14 (test for excess errors)
> > NA->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++17 (internal compiler error)
> > PASS->FAIL: g++.dg/cpp0x/pr83734.C  -std=gnu++17 (test for excess errors)
> > PASS->FAIL: g++.dg/cpp1y/constexpr-empty3.C  -std=c++14 scan-assembler-not static_init
> > PASS->FAIL: g++.dg/cpp1y/constexpr-empty3.C  -std=c++17 scan-assembler-not static_init
> >
> >
>
> I believe these are tracked in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87935 FWIW.
>

Yes, that was my intention.

> Kyrill
>
> > On 05/11/18 02:06, Jason Merrill wrote:
> > The initialized_type hunk fixes handling of void AGGR_INIT_EXPRs that call a
> > non-constructor; an AGGR_INIT_EXPR can have void type if its initialization
> > semantics are more complicated than just expanding the call.
> >
> > The cxx_eval_vec_init_1 hunk corrects AGGR_INIT_EXPRs that were
> > nonsensically built to initialize an object of void type. And the
> > build_aggr_init_expr hunk makes sure we don't do that again.
> >
> > The ocp_convert and cxx_eval_outermost_constant_expr hunks deal with making
> > sure that a constant CONSTRUCTOR has the right type.
> >
> > Tested x86_64-pc-linux-gnu, applying to trunk.
> >
> >     * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
> >     * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
> >     (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
> >     (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
> >     right type.  Don't wrap a CONSTRUCTOR if one was passed in.
> >     * tree.c (build_aggr_init_expr): Check for void.
> > ---
> >   gcc/cp/constexpr.c | 22 +++++++++++++---------
> >   gcc/cp/cvt.c       | 10 +++++++++-
> >   gcc/cp/tree.c      |  2 ++
> >   gcc/cp/ChangeLog   |  7 +++++++
> >   4 files changed, 31 insertions(+), 10 deletions(-)
> >
> > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> > index 7692b1727da..4fb1ba527e3 100644
> > --- a/gcc/cp/constexpr.c
> > +++ b/gcc/cp/constexpr.c
> > @@ -2778,8 +2778,10 @@ initialized_type (tree t)
> >   {
> >     if (TYPE_P (t))
> >       return t;
> > -  tree type = cv_unqualified (TREE_TYPE (t));
> > -  if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
> > +  tree type = TREE_TYPE (t);
> > +  if (!VOID_TYPE_P (type))
> > +    /* No need to look deeper.  */;
> > +  else if (TREE_CODE (t) == CALL_EXPR)
> >       {
> >         /* A constructor call has void type, so we need to look deeper.  */
> >         tree fn = get_function_named_in_call (t);
> > @@ -2787,7 +2789,9 @@ initialized_type (tree t)
> >         && DECL_CXX_CONSTRUCTOR_P (fn))
> >       type = DECL_CONTEXT (fn);
> >       }
> > -  return type;
> > +  else if (TREE_CODE (t) == AGGR_INIT_EXPR)
> > +    type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
> > +  return cv_unqualified (type);
> >   }
> >     /* We're about to initialize element INDEX of an array or class from VALUE.
> > @@ -3000,7 +3004,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
> >                       &argvec, elttype, LOOKUP_NORMAL,
> >                       complain);
> >         release_tree_vector (argvec);
> > -      init = build_aggr_init_expr (TREE_TYPE (init), init);
> > +      init = build_aggr_init_expr (elttype, init);
> >         pre_init = true;
> >       }
> >   @@ -5089,7 +5093,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
> >       r = build_nop (TREE_TYPE (r), r);
> >         TREE_CONSTANT (r) = false;
> >       }
> > -  else if (non_constant_p || r == t)
> > +  else if (non_constant_p)
> >       return t;
> >       if (should_unshare)
> > @@ -5097,18 +5101,18 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
> >       if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
> >       {
> > +      r = adjust_temp_type (type, r);
> >         if (TREE_CODE (t) == TARGET_EXPR
> >         && TARGET_EXPR_INITIAL (t) == r)
> >       return t;
> > -      else
> > +      else if (TREE_CODE (t) != CONSTRUCTOR)
> >       {
> >         r = get_target_expr (r);
> >         TREE_CONSTANT (r) = true;
> > -      return r;
> >       }
> >       }
> > -  else
> > -    return r;
> > +
> > +  return r;
> >   }
> >     /* Returns true if T is a valid subexpression of a constant expression,
> > diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> > index 315b0d6a65a..b04e9a70652 100644
> > --- a/gcc/cp/cvt.c
> > +++ b/gcc/cp/cvt.c
> > @@ -725,7 +725,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
> >       /* We need a new temporary; don't take this shortcut. */;
> >     else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
> >       {
> > -      if (same_type_p (type, TREE_TYPE (e)))
> > +      tree etype = TREE_TYPE (e);
> > +      if (same_type_p (type, etype))
> >       /* The call to fold will not always remove the NOP_EXPR as
> >          might be expected, since if one of the types is a typedef;
> >          the comparison in fold is just equality of pointers, not a
> > @@ -743,9 +744,16 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
> >       {
> >         /* Don't build a NOP_EXPR of class type.  Instead, change the
> >            type of the temporary.  */
> > +      gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
> >         TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
> >         return e;
> >       }
> > +      else if (TREE_CODE (e) == CONSTRUCTOR)
> > +    {
> > +      gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
> > +      TREE_TYPE (e) = type;
> > +      return e;
> > +    }
> >         else
> >       {
> >         /* We shouldn't be treating objects of ADDRESSABLE type as
> > diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> > index 74018e97bb7..51af9f2015e 100644
> > --- a/gcc/cp/tree.c
> > +++ b/gcc/cp/tree.c
> > @@ -576,6 +576,8 @@ build_aggr_init_expr (tree type, tree init)
> >     tree rval;
> >     int is_ctor;
> >   +  gcc_assert (!VOID_TYPE_P (type));
> > +
> >     /* Don't build AGGR_INIT_EXPR in a template.  */
> >     if (processing_template_decl)
> >       return init;
> > diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
> > index 7e9c0e2642a..4f40627a226 100644
> > --- a/gcc/cp/ChangeLog
> > +++ b/gcc/cp/ChangeLog
> > @@ -1,5 +1,12 @@
> >   2018-11-04  Jason Merrill <jason@redhat.com><mailto:jason@redhat.com>
> >   +    * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
> > +    * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
> > +    (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
> > +    (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
> > +    right type.  Don't wrap a CONSTRUCTOR if one was passed in.
> > +    * tree.c (build_aggr_init_expr): Check for void.
> > +
> >       PR c++/60503 - wrong lambda attribute syntax.
> >       * parser.c (cp_parser_lambda_declarator_opt): Fix attribute
> >       handling.
> >
> > base-commit: 703d2f69fad4772dc4aedb5327b5e3d88e8e1843
> >
> >
> > On 05/11/18 02:06, Jason Merrill wrote:
> >
> > The initialized_type hunk fixes handling of void AGGR_INIT_EXPRs that call a
> > non-constructor; an AGGR_INIT_EXPR can have void type if its initialization
> > semantics are more complicated than just expanding the call.
> >
> > The cxx_eval_vec_init_1 hunk corrects AGGR_INIT_EXPRs that were
> > nonsensically built to initialize an object of void type. And the
> > build_aggr_init_expr hunk makes sure we don't do that again.
> >
> > The ocp_convert and cxx_eval_outermost_constant_expr hunks deal with making
> > sure that a constant CONSTRUCTOR has the right type.
> >
> > Tested x86_64-pc-linux-gnu, applying to trunk.
> >
> >         * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
> >         * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
> >         (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
> >         (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
> >         right type.  Don't wrap a CONSTRUCTOR if one was passed in.
> >         * tree.c (build_aggr_init_expr): Check for void.
> > ---
> >  gcc/cp/constexpr.c | 22 +++++++++++++---------
> >  gcc/cp/cvt.c       | 10 +++++++++-
> >  gcc/cp/tree.c      |  2 ++
> >  gcc/cp/ChangeLog   |  7 +++++++
> >  4 files changed, 31 insertions(+), 10 deletions(-)
> >
> > diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
> > index 7692b1727da..4fb1ba527e3 100644
> > --- a/gcc/cp/constexpr.c
> > +++ b/gcc/cp/constexpr.c
> > @@ -2778,8 +2778,10 @@ initialized_type (tree t)
> >  {
> >    if (TYPE_P (t))
> >      return t;
> > -  tree type = cv_unqualified (TREE_TYPE (t));
> > -  if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
> > +  tree type = TREE_TYPE (t);
> > +  if (!VOID_TYPE_P (type))
> > +    /* No need to look deeper.  */;
> > +  else if (TREE_CODE (t) == CALL_EXPR)
> >      {
> >        /* A constructor call has void type, so we need to look deeper.  */
> >        tree fn = get_function_named_in_call (t);
> > @@ -2787,7 +2789,9 @@ initialized_type (tree t)
> >           && DECL_CXX_CONSTRUCTOR_P (fn))
> >         type = DECL_CONTEXT (fn);
> >      }
> > -  return type;
> > +  else if (TREE_CODE (t) == AGGR_INIT_EXPR)
> > +    type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
> > +  return cv_unqualified (type);
> >  }
> >
> >  /* We're about to initialize element INDEX of an array or class from VALUE.
> > @@ -3000,7 +3004,7 @@ cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
> >                                         &argvec, elttype, LOOKUP_NORMAL,
> >                                         complain);
> >        release_tree_vector (argvec);
> > -      init = build_aggr_init_expr (TREE_TYPE (init), init);
> > +      init = build_aggr_init_expr (elttype, init);
> >        pre_init = true;
> >      }
> >
> > @@ -5089,7 +5093,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
> >         r = build_nop (TREE_TYPE (r), r);
> >        TREE_CONSTANT (r) = false;
> >      }
> > -  else if (non_constant_p || r == t)
> > +  else if (non_constant_p)
> >      return t;
> >
> >    if (should_unshare)
> > @@ -5097,18 +5101,18 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
> >
> >    if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
> >      {
> > +      r = adjust_temp_type (type, r);
> >        if (TREE_CODE (t) == TARGET_EXPR
> >           && TARGET_EXPR_INITIAL (t) == r)
> >         return t;
> > -      else
> > +      else if (TREE_CODE (t) != CONSTRUCTOR)
> >         {
> >           r = get_target_expr (r);
> >           TREE_CONSTANT (r) = true;
> > -         return r;
> >         }
> >      }
> > -  else
> > -    return r;
> > +
> > +  return r;
> >  }
> >
> >  /* Returns true if T is a valid subexpression of a constant expression,
> > diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
> > index 315b0d6a65a..b04e9a70652 100644
> > --- a/gcc/cp/cvt.c
> > +++ b/gcc/cp/cvt.c
> > @@ -725,7 +725,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
> >      /* We need a new temporary; don't take this shortcut. */;
> >    else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
> >      {
> > -      if (same_type_p (type, TREE_TYPE (e)))
> > +      tree etype = TREE_TYPE (e);
> > +      if (same_type_p (type, etype))
> >         /* The call to fold will not always remove the NOP_EXPR as
> >            might be expected, since if one of the types is a typedef;
> >            the comparison in fold is just equality of pointers, not a
> > @@ -743,9 +744,16 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
> >         {
> >           /* Don't build a NOP_EXPR of class type.  Instead, change the
> >              type of the temporary.  */
> > +         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
> >           TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
> >           return e;
> >         }
> > +      else if (TREE_CODE (e) == CONSTRUCTOR)
> > +       {
> > +         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
> > +         TREE_TYPE (e) = type;
> > +         return e;
> > +       }
> >        else
> >         {
> >           /* We shouldn't be treating objects of ADDRESSABLE type as
> > diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> > index 74018e97bb7..51af9f2015e 100644
> > --- a/gcc/cp/tree.c
> > +++ b/gcc/cp/tree.c
> > @@ -576,6 +576,8 @@ build_aggr_init_expr (tree type, tree init)
> >    tree rval;
> >    int is_ctor;
> >
> > +  gcc_assert (!VOID_TYPE_P (type));
> > +
> >    /* Don't build AGGR_INIT_EXPR in a template.  */
> >    if (processing_template_decl)
> >      return init;
> > diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
> > index 7e9c0e2642a..4f40627a226 100644
> > --- a/gcc/cp/ChangeLog
> > +++ b/gcc/cp/ChangeLog
> > @@ -1,5 +1,12 @@
> >  2018-11-04  Jason Merrill <jason@redhat.com><mailto:jason@redhat.com>
> >
> > +       * cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
> > +       * constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
> > +       (cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
> > +       (cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
> > +       right type.  Don't wrap a CONSTRUCTOR if one was passed in.
> > +       * tree.c (build_aggr_init_expr): Check for void.
> > +
> >         PR c++/60503 - wrong lambda attribute syntax.
> >         * parser.c (cp_parser_lambda_declarator_opt): Fix attribute
> >         handling.
> >
> > base-commit: 703d2f69fad4772dc4aedb5327b5e3d88e8e1843
> >
>
diff mbox series

Patch

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 7692b1727da..4fb1ba527e3 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2778,8 +2778,10 @@  initialized_type (tree t)
 {
   if (TYPE_P (t))
     return t;
-  tree type = cv_unqualified (TREE_TYPE (t));
-  if (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR)
+  tree type = TREE_TYPE (t);
+  if (!VOID_TYPE_P (type))
+    /* No need to look deeper.  */;
+  else if (TREE_CODE (t) == CALL_EXPR)
     {
       /* A constructor call has void type, so we need to look deeper.  */
       tree fn = get_function_named_in_call (t);
@@ -2787,7 +2789,9 @@  initialized_type (tree t)
 	  && DECL_CXX_CONSTRUCTOR_P (fn))
 	type = DECL_CONTEXT (fn);
     }
-  return type;
+  else if (TREE_CODE (t) == AGGR_INIT_EXPR)
+    type = TREE_TYPE (AGGR_INIT_EXPR_SLOT (t));
+  return cv_unqualified (type);
 }
 
 /* We're about to initialize element INDEX of an array or class from VALUE.
@@ -3000,7 +3004,7 @@  cxx_eval_vec_init_1 (const constexpr_ctx *ctx, tree atype, tree init,
 					&argvec, elttype, LOOKUP_NORMAL,
 					complain);
       release_tree_vector (argvec);
-      init = build_aggr_init_expr (TREE_TYPE (init), init);
+      init = build_aggr_init_expr (elttype, init);
       pre_init = true;
     }
 
@@ -5089,7 +5093,7 @@  cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 	r = build_nop (TREE_TYPE (r), r);
       TREE_CONSTANT (r) = false;
     }
-  else if (non_constant_p || r == t)
+  else if (non_constant_p)
     return t;
 
   if (should_unshare)
@@ -5097,18 +5101,18 @@  cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 
   if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r)))
     {
+      r = adjust_temp_type (type, r);
       if (TREE_CODE (t) == TARGET_EXPR
 	  && TARGET_EXPR_INITIAL (t) == r)
 	return t;
-      else
+      else if (TREE_CODE (t) != CONSTRUCTOR)
 	{
 	  r = get_target_expr (r);
 	  TREE_CONSTANT (r) = true;
-	  return r;
 	}
     }
-  else
-    return r;
+
+  return r;
 }
 
 /* Returns true if T is a valid subexpression of a constant expression,
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 315b0d6a65a..b04e9a70652 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -725,7 +725,8 @@  ocp_convert (tree type, tree expr, int convtype, int flags,
     /* We need a new temporary; don't take this shortcut.  */;
   else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
     {
-      if (same_type_p (type, TREE_TYPE (e)))
+      tree etype = TREE_TYPE (e);
+      if (same_type_p (type, etype))
 	/* The call to fold will not always remove the NOP_EXPR as
 	   might be expected, since if one of the types is a typedef;
 	   the comparison in fold is just equality of pointers, not a
@@ -743,9 +744,16 @@  ocp_convert (tree type, tree expr, int convtype, int flags,
 	{
 	  /* Don't build a NOP_EXPR of class type.  Instead, change the
 	     type of the temporary.  */
+	  gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
 	  TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
 	  return e;
 	}
+      else if (TREE_CODE (e) == CONSTRUCTOR)
+	{
+	  gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
+	  TREE_TYPE (e) = type;
+	  return e;
+	}
       else
 	{
 	  /* We shouldn't be treating objects of ADDRESSABLE type as
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 74018e97bb7..51af9f2015e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -576,6 +576,8 @@  build_aggr_init_expr (tree type, tree init)
   tree rval;
   int is_ctor;
 
+  gcc_assert (!VOID_TYPE_P (type));
+
   /* Don't build AGGR_INIT_EXPR in a template.  */
   if (processing_template_decl)
     return init;
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7e9c0e2642a..4f40627a226 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,12 @@ 
 2018-11-04  Jason Merrill  <jason@redhat.com>
 
+	* cvt.c (ocp_convert): Don't wrap a CONSTRUCTOR in a NOP_EXPR.
+	* constexpr.c (initialized_type): Fix AGGR_INIT_EXPR handling.
+	(cxx_eval_vec_init_1): Correct type of AGGR_INIT_EXPR.
+	(cxx_eval_outermost_constant_expr): Make sure a CONSTRUCTOR has the
+	right type.  Don't wrap a CONSTRUCTOR if one was passed in.
+	* tree.c (build_aggr_init_expr): Check for void.
+
 	PR c++/60503 - wrong lambda attribute syntax.
 	* parser.c (cp_parser_lambda_declarator_opt): Fix attribute
 	handling.