Bug 70353 - [5 regression] ICE on __PRETTY_FUNCTION__ in a constexpr function
Summary: [5 regression] ICE on __PRETTY_FUNCTION__ in a constexpr function
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 5.2.1
: P2 normal
Target Milestone: 5.4
Assignee: Jason Merrill
URL:
Keywords: ice-on-valid-code
: 66460 70532 70770 (view as bug list)
Depends on: 70422
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2016-03-22 10:49 UTC by Andriy Lysnevych
Modified: 2022-11-29 03:28 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Known to work: 6.0
Known to fail: 5.2.1
Last reconfirmed: 2016-03-22 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andriy Lysnevych 2016-03-22 10:49:10 UTC
I use out-of-the-box GCC 5.2.1 in Ubuntu 15.10:

gcc version 5.2.1 20151010 (Ubuntu 5.2.1-22ubuntu2)

This code makes GCC crash when I define standard --std=c++14 or --std=c++17:

#include <cassert>

constexpr int ce(int r) {
  assert(r == 3);
  return r;
}

static_assert(ce(3) == 3, "static asser error");


Command to reproduce:
$ gcc --std=c++14 bug.cpp
bug.cpp:8:17:   in constexpr expansion of ‘ce(3)’
bug.cpp:8:48: internal compiler error: Segmentation fault
 static_assert(ce(3) == 3, "static asser error");
                                                ^
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-5/README.Bugs> for instructions.
Comment 1 Marek Polacek 2016-03-22 12:59:42 UTC
Confirmed.

void foo (const char *);
constexpr int
ce (int r)
{
  r == 3 ? static_cast<void> (0) : foo (__PRETTY_FUNCTION__);
  return r;
}
static_assert (ce (3) == 3, "");
Comment 2 Marek Polacek 2016-03-22 13:03:16 UTC
Started with r217663:

commit 9c96033c877975303250d6f6156eacba52fc8b44
Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Mon Nov 17 18:16:14 2014 +0000

        C++14 constexpr support (minus loops and multiple returns)
Comment 3 Andriy Lysnevych 2016-03-22 19:39:35 UTC
static_assert is not required. This code also crashes:

#include <cassert>

constexpr int ce(int r) {
  assert(r == 3);
  return r;
}

const auto c = ce(3);

Problem is in assert called from constexpr function.
Comment 4 Marek Polacek 2016-03-22 19:42:41 UTC
But we want to avoid the #include <cassert>.
Comment 5 Martin Sebor 2016-03-22 20:15:49 UTC
The trigger seems to be __PRETTY_FUNCTION__.  Below is a smaller test case:
constexpr int ce (int r)
{
   const char *s = __PRETTY_FUNCTION__;
   return r;
}

constexpr int i = ce (3);

v.c: In function ‘constexpr int ce(int)’:
v.c:3:16: warning: unused variable ‘s’ [-Wunused-variable]
    const char *s = __PRETTY_FUNCTION__;
                ^
v.c: At global scope:
v.c:7:22:   in constexpr expansion of ‘ce(3)’
v.c:7:24: internal compiler error: Segmentation fault
 constexpr int i = ce (3);
                        ^
0x10d5326 crash_signal
	/src/gcc/trunk/gcc/toplev.c:335
0x7ce697 bool vec_safe_reserve<tree_node*, va_gc>(vec<tree_node*, va_gc, vl_embed>*&, unsigned int, bool)
	/src/gcc/trunk/gcc/vec.h:553
0x7ce1aa tree_node** vec_safe_push<tree_node*, va_gc>(vec<tree_node*, va_gc, vl_embed>*&, tree_node* const&)
	/src/gcc/trunk/gcc/vec.h:647
0xd48a73 add_local_decl(function*, tree_node*)
	/src/gcc/trunk/gcc/function.c:6795
0x1169cf1 remap_decls
	/src/gcc/trunk/gcc/tree-inline.c:620
0x116a19a remap_block
	/src/gcc/trunk/gcc/tree-inline.c:688
0x116a55d copy_bind_expr
	/src/gcc/trunk/gcc/tree-inline.c:761
0x116ba51 copy_tree_body_r(tree_node**, int*, void*)
	/src/gcc/trunk/gcc/tree-inline.c:1095
0x140ec4b walk_tree_1(tree_node**, tree_node* (*)(tree_node**, int*, void*), void*, hash_set<tree_node*, default_hash_traits<tree_node*> >*, tree_node* (*)(tree_node**, int*, tree_node* (*)(tree_node**, int*, void*), void*, hash_set<tree_node*, default_hash_traits<tree_node*> >*))
	/src/gcc/trunk/gcc/tree.c:11531
0x11720b8 copy_tree_body
	/src/gcc/trunk/gcc/tree-inline.c:2946
0x117b678 copy_fn(tree_node*, tree_node*&, tree_node*&)
	/src/gcc/trunk/gcc/tree-inline.c:6151
0xa7a19d cxx_eval_call_expression
	/src/gcc/trunk/gcc/cp/constexpr.c:1368
0xa81d72 cxx_eval_constant_expression
	/src/gcc/trunk/gcc/cp/constexpr.c:3407
0xa83fb3 cxx_eval_outermost_constant_expr
	/src/gcc/trunk/gcc/cp/constexpr.c:3973
0xa84611 cxx_constant_value(tree_node*, tree_node*)
	/src/gcc/trunk/gcc/cp/constexpr.c:4062
0x89f86c store_init_value(tree_node*, tree_node*, vec<tree_node*, va_gc, vl_embed>**, int)
	/src/gcc/trunk/gcc/cp/typeck2.c:822
0x7ec411 check_initializer
	/src/gcc/trunk/gcc/cp/decl.c:6155
0x7ef3db cp_finish_decl(tree_node*, tree_node*, bool, tree_node*, int)
	/src/gcc/trunk/gcc/cp/decl.c:6800
0x9282b6 cp_parser_init_declarator
	/src/gcc/trunk/gcc/cp/parser.c:18658
0x91d806 cp_parser_simple_declaration
	/src/gcc/trunk/gcc/cp/parser.c:12379
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.
Comment 6 Martin Sebor 2016-03-22 20:26:25 UTC
GCC 4.9 doesn't crash on the code so technically this could be considered a regression.  Although 4.9 doesn't support C++ 14 constexpr functions consisting of more than just a return statement, one might say it's not regression.  But the 5.x and 5.0 both ICE even on the test C++ 11 case below, so I think considering this a regression would be appropriate.  I've taken the liberty to do that and also to adjust the Summary to better reflect the root cause of the ICE.

$ cat v.c && /home/msebor/build/gcc-4.9.3/gcc/xgcc -B/home/msebor/build/gcc-4.9.3/gcc -S -Wall -Wextra -Wpedantic -std=c++14 -xc++ v.c
constexpr int f () {
    return __PRETTY_FUNCTION__ [0];
}

constexpr int i = f ();
v.c: In function ‘constexpr int f()’:
v.c:3:1: error: body of constexpr function ‘constexpr int f()’ not a return-statement
 }
 ^
v.c: At global scope:
v.c:5:22: error: ‘constexpr int f()’ called in a constant expression
 constexpr int i = f ();
                      ^
Comment 7 Martin Sebor 2016-03-23 01:33:30 UTC
I haven't had time to debug it beyond observing in the debugger that remap_decls() defined in tree-inline.c calls add_local_decl() with the first argument of null.  The argument is cfun (function*).

Both __func__ and __FUNCTION__ also trigger the same ICE.
Comment 8 Andriy Lysnevych 2016-03-23 11:22:30 UTC
Smaller test case:

constexpr const char* ce ()
{
   return __func__;
}

const char* c = ce ();
Comment 9 Jakub Jelinek 2016-03-23 15:38:05 UTC
The reason for the ICE is that __PRETTY_FUNCTION__/__FUNCTION__/__func__ are TREE_STATIC (artificial) VAR_DECLs in the context of the corresponding constexpr function, because of the TREE_STATIC we don't want to remap it, and constexpr.c calls copy_fn with NULL cfun (most other callers of inlining APIs have cfun non-NULL and usually cfun->decl matching id->dst_fn).
For the ICE, I guess we can do something like:
--- gcc/tree-inline.c.jj	2016-03-16 18:50:47.000000000 +0100
+++ gcc/tree-inline.c	2016-03-23 16:27:08.723926525 +0100
@@ -614,9 +614,11 @@ remap_decls (tree decls, vec<tree, va_gc
       if (can_be_nonlocal (old_var, id))
 	{
 	  /* We need to add this variable to the local decls as otherwise
-	     nothing else will do so.  */
+	     nothing else will do so.  Don't do this if there is no current
+	     function, e.g. during constexpr handling calling copy_fn.  */
 	  if (TREE_CODE (old_var) == VAR_DECL
-	      && ! DECL_EXTERNAL (old_var))
+	      && ! DECL_EXTERNAL (old_var)
+	      && cfun)
 	    add_local_decl (cfun, old_var);
 	  if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
 	      && !DECL_IGNORED_P (old_var)
But, that is insufficient, as e.g. for the #c8 testcase we then get unresolved external symbol, because the definition of the static var is never emitted.
Comment 10 Patrick Palka 2016-03-24 13:13:02 UTC
It's a hack, but we could pull the STRING_CST out from the artificial VAR_DECL during constexpr evaluation to avoid referring to __func__'s symbol.

--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -3354,6 +3354,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,

     case VAR_DECL:
     case CONST_DECL:
+      if (VAR_P (t)
+         && DECL_ARTIFICIAL (t)
+         && TREE_STATIC (t)
+         && TREE_CODE (DECL_INITIAL (t)) == STRING_CST)
+       return DECL_INITIAL (t);
       /* We used to not check lval for CONST_DECL, but darwin.c uses
         CONST_DECL for aggregate constants.  */
       if (lval)
Comment 11 Jason Merrill 2016-03-24 21:18:11 UTC
Core issue 1962 talks about changing __func__ et al to be const char * rather than array; Martin was investigating that change but it fell off my radar.  I'll look at finishing up his patch.
Comment 12 Jason Merrill 2016-03-25 21:29:58 UTC
Author: jason
Date: Fri Mar 25 21:29:26 2016
New Revision: 234484

URL: https://gcc.gnu.org/viewcvs?rev=234484&root=gcc&view=rev
Log:
	PR c++/64266
	PR c++/70353
	Core issue 1962
	* decl.c (cp_fname_init): Decay the initializer to pointer.
	(cp_make_fname_decl): Set DECL_DECLARED_CONSTEXPR_P,
	DECL_VALUE_EXPR, DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P.
	Don't call cp_finish_decl.
	* pt.c (tsubst_expr) [DECL_EXPR]: Set DECL_VALUE_EXPR,
	DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P.  Don't call cp_finish_decl.
	* constexpr.c (cxx_eval_constant_expression) [VAR_DECL]:
	Handle DECL_VALUE_EXPR.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-__func__2.C
    trunk/gcc/testsuite/g++.dg/ext/fnname5.C
Removed:
    trunk/gcc/testsuite/g++.old-deja/g++.ext/pretty4.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/constexpr.c
    trunk/gcc/cp/decl.c
    trunk/gcc/cp/pt.c
Comment 13 Jason Merrill 2016-03-25 21:35:26 UTC
Fixed for 6, but the patch isn't really suitable for backporting since it's a change in behavior.  Since 4.9 didn't accept the code, I'm going to close this.
Comment 14 Jason Merrill 2016-03-28 20:16:53 UTC
Author: jason
Date: Mon Mar 28 20:16:21 2016
New Revision: 234511

URL: https://gcc.gnu.org/viewcvs?rev=234511&root=gcc&view=rev
Log:
	PR c++/70422

	PR c++/64266
	PR c++/70353
	* decl.c, pt.c, constexpr.c: Revert last patch.

Added:
    trunk/gcc/testsuite/g++.old-deja/g++.ext/pretty4.C
Removed:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-__func__2.C
    trunk/gcc/testsuite/g++.dg/ext/fnname5.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/constexpr.c
    trunk/gcc/cp/decl.c
    trunk/gcc/cp/pt.c
Comment 15 Jason Merrill 2016-03-28 20:17:49 UTC
Reverted the fix because it broke bootstrap on some targets.
Comment 16 Martin Sebor 2016-03-28 20:22:53 UTC
I was just about commit the following patch for the failure (false positive) in the test.

Index: gcc/testsuite/ChangeLog
===================================================================
--- gcc/testsuite/ChangeLog	(revision 234510)
+++ gcc/testsuite/ChangeLog	(working copy)
@@ -1,3 +1,8 @@
+2016-03-28  Martin Sebor  <msebor@redhat.com>
+
+	* g++.dg/ext/fnname5.C: Adjust ERE pattern to anticipate any
+	whitespace character after the .string assembler directive.
+
 2016-03-28  Dominique d'Humieres  <dominiq@lps.ens.fr>
 
 	g++.dg/ext/fnname5.C: Update the test for Darwin.
Index: gcc/testsuite/g++.dg/ext/fnname5.C
===================================================================
--- gcc/testsuite/g++.dg/ext/fnname5.C	(revision 234510)
+++ gcc/testsuite/g++.dg/ext/fnname5.C	(working copy)
@@ -29,5 +29,5 @@ main ()
 /* { dg-final { scan-assembler-not "_ZZN1A3fooEvE12__FUNCTION__" } } */
 /* { dg-final { scan-assembler-not "_ZZN1A3fooEiE12__FUNCTION__" } } */
 /* { dg-final { scan-assembler-not "_ZZN1A3fooEiE19__PRETTY_FUNCTION__" } } */
-/* { dg-final { scan-assembler ".(string|ascii) \"void A::foo\\(int\\)(.0)?\"" } } */
-/* { dg-final { scan-assembler ".(string|ascii) \"foo(.0)?\"" } } */
+/* { dg-final { scan-assembler ".(string|ascii)\[\[:space:\]\]*\"void A::foo\\(int\\)(.0)?\"" } } */
+/* { dg-final { scan-assembler ".(string|ascii)\[\[:space:\]\]*\"foo(.0)?\"" } } */
Comment 17 Jason Merrill 2016-03-29 18:40:34 UTC
Author: jason
Date: Tue Mar 29 18:40:02 2016
New Revision: 234530

URL: https://gcc.gnu.org/viewcvs?rev=234530&root=gcc&view=rev
Log:
	PR c++/70353

gcc/
	* tree-inline.c (remap_decls): Don't add_local_decl if
	cfun is null.
gcc/cp/
	* decl.c (make_rtl_for_nonlocal_decl): Don't defer local statics
	in constexpr functions.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-__func__2.C
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/decl.c
    trunk/gcc/tree-inline.c
Comment 18 Jason Merrill 2016-03-29 18:44:47 UTC
Fixed again for 6.
Comment 19 Martin Sebor 2016-04-04 19:54:03 UTC
*** Bug 70532 has been marked as a duplicate of this bug. ***
Comment 20 Martin Sebor 2016-04-04 20:03:14 UTC
*** Bug 66460 has been marked as a duplicate of this bug. ***
Comment 21 Markus Trippelsdorf 2016-04-23 21:06:09 UTC
*** Bug 70770 has been marked as a duplicate of this bug. ***
Comment 22 Jason Merrill 2016-05-18 15:59:31 UTC
Author: jason
Date: Wed May 18 15:59:00 2016
New Revision: 236408

URL: https://gcc.gnu.org/viewcvs?rev=236408&root=gcc&view=rev
Log:
	PR c++/70353 - __func__ and constexpr

gcc/
	* tree-inline.c (remap_decls): Don't add_local_decl if
	cfun is null.
gcc/cp/
	* decl.c (make_rtl_for_nonlocal_decl): Don't defer local statics
	in constexpr functions.

Added:
    branches/gcc-5-branch/gcc/testsuite/g++.dg/cpp0x/constexpr-__func__2.C
Modified:
    branches/gcc-5-branch/gcc/ChangeLog
    branches/gcc-5-branch/gcc/cp/ChangeLog
    branches/gcc-5-branch/gcc/cp/decl.c
    branches/gcc-5-branch/gcc/tree-inline.c
Comment 23 Richard Biener 2016-06-03 10:06:39 UTC
GCC 5.4 is being released, adjusting target milestone.
Comment 24 Jakub Jelinek 2017-10-10 15:05:43 UTC
Should be fixed in 5.4.