Bug 71166 - [7 Regression] ICE with nested constexpr/initializer
Summary: [7 Regression] ICE with nested constexpr/initializer
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.1.1
: P1 normal
Target Milestone: 7.0
Assignee: Marek Polacek
URL:
Keywords: ice-on-valid-code
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2016-05-17 16:33 UTC by Max Kellermann
Modified: 2018-02-07 02:45 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work: 6.2.0
Known to fail: 6.1.0, 7.0
Last reconfirmed: 2016-05-18 00:00:00


Attachments
A source file which reproduces the problem (155 bytes, text/plain)
2016-05-17 16:33 UTC, Max Kellermann
Details
slightly more reduced test case (148 bytes, text/plain)
2016-05-18 15:10 UTC, Nathan Sidwell
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Max Kellermann 2016-05-17 16:33:20 UTC
Created attachment 38508 [details]
A source file which reproduces the problem

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.1.1-3' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 6.1.1 20160511 (Debian 6.1.1-3) 


Compile the attached source with "g++ -c foo.cxx":

/tmp/foo.cxx: In constructor 'constexpr BarContainer::BarContainer()':
/tmp/foo.cxx:8:8:   in constexpr expansion of 'Bar()'
/tmp/foo.cxx:5:22:   in constexpr expansion of 'MakeFoo()'
/tmp/foo.cxx:8:8: internal compiler error: in cxx_eval_call_expression, at cp/constexpr.c:1449
 struct BarContainer {
        ^~~~~~~~~~~~
0x6f9649 cxx_eval_call_expression
        ../../src/gcc/cp/constexpr.c:1449
0x6fab6f cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:3556
0x6fae5d cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:3616
0x6fc651 cxx_eval_store_expression
        ../../src/gcc/cp/constexpr.c:3123
0x6fa39c cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:3633
0x6f9f08 cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:3901
0x6fa185 cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:3672
0x6fa185 cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:3672
0x6fab90 cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:4014
0x6f92d2 cxx_eval_call_expression
        ../../src/gcc/cp/constexpr.c:1494
0x6fab6f cxx_eval_constant_expression
        ../../src/gcc/cp/constexpr.c:3556
0x6fd1f6 cxx_eval_outermost_constant_expr
        ../../src/gcc/cp/constexpr.c:4121
0x6fec81 maybe_constant_init(tree_node*, tree_node*)
        ../../src/gcc/cp/constexpr.c:4439
0x69b07e build_vec_init(tree_node*, tree_node*, tree_node*, bool, int, int)
        ../../src/gcc/cp/init.c:4176
0x6eb43d cp_gimplify_expr(tree_node**, gimple**, gimple**)
        ../../src/gcc/cp/cp-gimplify.c:591
0x8d62b5 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        ../../src/gcc/gimplify.c:10196
0x8d9cb6 gimplify_stmt(tree_node**, gimple**)
        ../../src/gcc/gimplify.c:5688
0x8d6aa8 gimplify_cleanup_point_expr
        ../../src/gcc/gimplify.c:5464
0x8d6aa8 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int)
        ../../src/gcc/gimplify.c:10652
0x8d9cb6 gimplify_stmt(tree_node**, gimple**)
        ../../src/gcc/gimplify.c:5688
Comment 1 Martin Sebor 2016-05-18 04:14:06 UTC
Confirmed.  Both 6.1.0 and 7.0 are affected, 5.3.0 is not.  If my bisection script isn't lying it looks like r235033 introduced the ICE.
Comment 2 Jakub Jelinek 2016-05-18 07:51:31 UTC
Yes, it is indeed r235033.
I have no idea how is constexpr handling meant to work vs. gimplification though, perhaps this is also related to PR68949.
What happens in this PR is that we process some constexpr stuff, then gimplify MakeFoo and then process further constexpr stuff.  But gimplification is destructive, destroys the individual parts of DECL_SAVED_TREE as well as clears DECL_SAVED_TREE at the end.
Comment 3 Nathan Sidwell 2016-05-18 15:10:28 UTC
Created attachment 38514 [details]
slightly more reduced test case

We're invoking constexpr evaluation machinery after parsing is complete -- fini_constexpt has already been called.  This occurs during the emission of BarContainer's constructor, after we've destructively gimplified MakeFoo.  We end up in

0xa05bf2 maybe_constant_init(tree_node*, tree_node*)
	../../../src/gcc/cp/constexpr.c:4457
0x929ce6 build_vec_init(tree_node*, tree_node*, tree_node*, bool, int, int)
	../../../src/gcc/cp/init.c:4178
0x9db06b cp_gimplify_expr(tree_node**, gimple**, gimple**)
	../../../src/gcc/cp/cp-gimplify.c:592

and from there we have const_expr_eval (Bar) -> const_expr_eval (MakeFoo) -> ICE
The object we're gimplifying is a vec_init_expr
Comment 4 Nathan Sidwell 2016-05-20 13:47:37 UTC
build_vec_init_elt (tree.c) says:

/* Subroutine of build_vec_init_expr: Build up a single element
   intialization as a proxy for the full array initialization to get things
   marked as used and any appropriate diagnostics.

   Since we're deferring building the actual constructor calls until
   gimplification time, we need to build one now and throw it away so
   that the relevant constructor gets mark_used before cgraph decides
   what functions are needed.  Here we assume that init is either
   NULL_TREE, void_type_node (indicating value-initialization), or
   another array to copy.  */

With constexprs now in play, that appears to be an incorrect approach.   I'm not sure why it's even sensible to go building things early only to throw them away and redo it.  It would seem better to just build the constructor (or whatever) tree and keep it.
Comment 5 Jason Merrill 2016-05-25 20:49:44 UTC
(In reply to Nathan Sidwell from comment #4)
> build_vec_init_elt (tree.c) says:
> 
> /* Subroutine of build_vec_init_expr: Build up a single element
>    intialization as a proxy for the full array initialization to get things
>    marked as used and any appropriate diagnostics.
> 
>    Since we're deferring building the actual constructor calls until
>    gimplification time, we need to build one now and throw it away so
>    that the relevant constructor gets mark_used before cgraph decides
>    what functions are needed.  Here we assume that init is either
>    NULL_TREE, void_type_node (indicating value-initialization), or
>    another array to copy.  */
> 
> With constexprs now in play, that appears to be an incorrect approach.   I'm
> not sure why it's even sensible to go building things early only to throw
> them away and redo it.  It would seem better to just build the constructor
> (or whatever) tree and keep it.

I was trying with VEC_INIT_EXPR to get the same "floating initialization of an object to be determined later" semantics that we have with AGGR_INIT_EXPR, but indeed deferring all that building until after we've thrown away a lot of front end information doesn't make sense.

For GCC 6 the minimal fix would be to disable try_const if (at_eof > 1), but for GCC 7 we should reconsider VEC_INIT_EXPR entirely.
Comment 6 Nathan Sidwell 2016-05-26 19:46:38 UTC
Adding an at_eof check into try_const fixes the testcase.  (also) Adding an at_eof <= 1 assert into cxx_eval_outermost_constant_expr causes 261 new fails.  Although many are obviously init & ctor related, they're a fairly widely distributed bunch -- one is even abi name mangling. I don't see any a priori reason as to why those calls to cxx_eval_outermost_constant_expr couldn't end up evaluating a constexpr call.
Comment 7 Jason Merrill 2016-05-31 21:37:17 UTC
Author: jason
Date: Tue May 31 21:36:46 2016
New Revision: 236955

URL: https://gcc.gnu.org/viewcvs?rev=236955&root=gcc&view=rev
Log:
	PR c++/71166 - constexpr array init

	* decl2.c (c_parse_final_cleanups): Don't call fini_constexpr.

Added:
    branches/gcc-6-branch/gcc/testsuite/g++.dg/cpp0x/constexpr-array16.C
Modified:
    branches/gcc-6-branch/gcc/cp/ChangeLog
    branches/gcc-6-branch/gcc/cp/decl2.c
Comment 8 Jakub Jelinek 2016-06-03 11:48:34 UTC
So is this PR now fixed on the branch and still broken on the trunk?
If yes, we should turn it into [7 Regression] then.
Comment 9 Richard Biener 2016-07-08 11:41:07 UTC
Yes.  And we should have added a testcase.
Comment 10 Jakub Jelinek 2017-01-03 07:44:21 UTC
At this point it is getting too late to reconsider VEC_INIT_EXPR for GCC 7, so shall we apply the fix from GCC 7 to trunk too?
Comment 11 Jakub Jelinek 2017-01-10 13:57:02 UTC
I think this ought to be P1, because it is a regression from 6.2/6.3 to 7.
Comment 12 Marek Polacek 2017-01-13 14:09:56 UTC
Actually, this seems to be fixed on the trunk too.  Fixed in r238395.  Should I add the testcase from this PR and close it?
Comment 13 Marek Polacek 2017-01-13 14:53:23 UTC
Adding the testcase.
Comment 14 Marek Polacek 2017-01-13 17:28:26 UTC
Author: mpolacek
Date: Fri Jan 13 17:27:54 2017
New Revision: 244450

URL: https://gcc.gnu.org/viewcvs?rev=244450&root=gcc&view=rev
Log:
	PR c++/71166
	* g++.dg/cpp0x/constexpr-array18.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-array18.C
Modified:
    trunk/gcc/testsuite/ChangeLog
Comment 15 Marek Polacek 2017-01-13 17:29:41 UTC
Fixed.
Comment 16 Leslie Zhai 2018-02-07 02:45:17 UTC
But gcc-7-branch and 8.x trunk reverted the Remove?

-fini_constexpr ();