Patchwork PR c++/51633 - ICEs with constexpr constructor

login
register
mail settings
Submitter Dodji Seketeli
Date Jan. 11, 2012, 10:57 p.m.
Message ID <m3pqepzw2z.fsf@redhat.com>
Download mbox | patch
Permalink /patch/135518/
State New
Headers show

Comments

Dodji Seketeli - Jan. 11, 2012, 10:57 p.m.
Hello,

Consider this short code snippet:

    struct A
    {
	~A();
    };

    struct B
    {
	A a;
	constexpr B() {}
    };

As explained in the audit trail, this is valid code.

G++ ICEs on it because build_constexpr_constructor_member_initializers
chokes on a CLEANUP_STMT.

The CLEANUP_STMT is put into the constructor of B to ensure that the
destructor for 'a' is called.

As this CLEANUP_STMT is not related to the representation of
mem-initializer-list that
build_constexpr_constructor_member_initializers was expecting to see
as part of its analysis of the constructor body my understanding is
that it should just ignore it.

I noted that build_data_member_initialization that is called elsewhere
in build_constexpr_constructor_member_initializers already knows how
to ignore those CLEANUP_STMT, so I tried in this patch to take
advantage of that function.

The other case of ICE reported in this issue is in:

    struct A2
    {
	constexpr A2() {}
	~A2();
    };

    struct B2
    {
      A2 a;
	constexpr B2() { return;}
    };

where check_constexpr_ctor_body fails to recognize that the body of
the constexpr constructor B2 is not empty.  It turned out this is
because it's not passed the proper last statement of the constructor,
before the body (as written in the source code) is parsed.  Fixed
thus.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	* semantics.c (cp_parser_ctor_initializer_opt_and_function_body):
	Set the pointer to the last block of the constructor to the
	current statement.
	(build_constexpr_constructor_member_initializers): Get
	build_data_member_initialization a chance to deal with more
	statements before we choke.

gcc/testsuite/

	* g++.dg/cpp0x/constexpr-diag4.C: New test.
---
 gcc/cp/parser.c                              |    2 +-
 gcc/cp/semantics.c                           |    2 +
 gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C |   28 +++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/constexpr-diag5.C |   48 ++++++++++++++++++++++++++
 4 files changed, 79 insertions(+), 1 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-diag5.C
Paolo Carlini - Jan. 11, 2012, 11:20 p.m.
... watch out trailing blank lines ;)

Thanks!
Paolo
Jason Merrill - Jan. 12, 2012, 1:59 p.m.
On 01/11/2012 05:57 PM, Dodji Seketeli wrote:
> +      list = cur_stmt_list;
>         if (TREE_CODE (list) == BIND_EXPR)
>   	list = BIND_EXPR_BODY (list);
>         if (TREE_CODE (list) == STATEMENT_LIST

cur_stmt_list should always be a STATEMENT_LIST, so these tests are 
unnecessary.

Jason

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 0ae55a2..ea9ccfc 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -17418,7 +17418,7 @@  cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
      cp_parser_function_body changed its state.  */
   if (check_body_p)
     {
-      list = body;
+      list = cur_stmt_list;
       if (TREE_CODE (list) == BIND_EXPR)
 	list = BIND_EXPR_BODY (list);
       if (TREE_CODE (list) == STATEMENT_LIST
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fbb74e1..9369179 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5930,6 +5930,8 @@  build_constexpr_constructor_member_initializers (tree type, tree body)
 	    break;
 	}
     }
+  else if (EXPR_P (body))
+    ok = build_data_member_initialization (body, &vec);
   else
     gcc_assert (errorcount > 0);
   if (ok)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C
new file mode 100644
index 0000000..08373c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag4.C
@@ -0,0 +1,28 @@ 
+// Origin: PR c++/51633
+// { dg-options "-std=c++11" }
+
+struct A
+{
+    ~A();
+};
+
+struct B
+{
+    A a;
+    constexpr B() {}
+};
+
+struct A1
+{
+    int a;
+    ~A1();
+};
+
+struct B1
+{
+    A1 a1;
+    constexpr B1() {} // { dg-error "uninitialized member" }
+};
+
+
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-diag5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag5.C
new file mode 100644
index 0000000..c0cbfdd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-diag5.C
@@ -0,0 +1,48 @@ 
+// Origin: PR c++/51633
+// { dg-options "-std=c++11" }
+
+struct A
+{
+    constexpr A() {}
+    ~A();
+};
+
+struct B
+{
+    A a;
+    A b;
+    A c;
+    constexpr B() {}
+};
+
+struct C
+{
+    A a;
+    constexpr C() {}
+};
+
+struct D
+{
+    constexpr D() { return;} // { dg-error "does not have empty body" }
+};
+
+struct D1
+{
+    A a;
+    constexpr D1() { return;} // { dg-error "does not have empty body" }
+};
+
+struct D2
+{
+    A a;
+    A b;
+    constexpr D2() { return;} // { dg-error "does not have empty body" }
+};
+
+struct D3
+{
+    A a;
+    A b;
+    A c;
+    constexpr D3() { return;} // { dg-error "does not have empty body" }
+};