Bring C++ ICE handling in line with other front ends

Zack Weinberg zack@wolery.cumb.org
Thu Jul 20 14:47:00 GMT 2000


The C++ front end has its own idea of how to report ICEs, which is
different enough from the other front ends, or the backend, to be
confusing.   It also intercepts segfaults and turns them into ICEs,
which is even more confusing.  And it turns the ICEs into ordinary
fatal errors if there were already errors in the compilation - which
just masks the bugs, in my opinion.

This patch brings C++'s handlers in line with everyone else's.  It
will expose some ICEs:

FAIL: g++.brendan/crash16.C caused compiler crash	(19990919)
FAIL: g++.brendan/parse3.C caused compiler crash	(122)
FAIL: g++.brendan/redecl1.C caused compiler crash	(19990919)
FAIL: g++.ns/template13.C caused compiler crash		(268)
FAIL: g++.other/decl4.C caused compiler crash		(segfault)
FAIL: g++.pt/spec14.C caused compiler crash		(segfault)

These all appear to be due to the code which sets up to parse a
function bailing out before all the state is initialized.  We then
fail while generating a tree for the function.

This patch expects the previous patch for top-level diagnostic
handling, but will work okay without it.

zw

	* cp-tree.h: Replace __PRETTY_FUNCTION__ with __FUNCTION__
	throughout.  Update prototypes.  Hoist the test of a
	my_friendly_assert() assertion into the caller.

	* decl.c: Don't include signal.h.  Don't trap any signals.
	(signal_catch): Delete.

	* typeck2.c (ack, abortcount, my_friendly_assert): Delete.
	(my_friendly_abort): Rename to friendly_abort.  Expect the
	file, line, and function of the caller.  Do not sugarcoat an
	ICE if there was a previous error.  Just report the code
	number if positive, then call fancy_abort.

===================================================================
Index: cp/cp-tree.h
--- cp/cp-tree.h	2000/07/16 21:04:16	1.499
+++ cp/cp-tree.h	2000/07/20 19:51:51
@@ -161,8 +161,7 @@ Boston, MA 02111-1307, USA.  */
 ({  const tree __t = NODE;					\
     enum tree_code __c = TREE_CODE(__t);			\
     if (__c != VAR_DECL && __c != FUNCTION_DECL)		\
-      tree_check_failed (__t, VAR_DECL, __FILE__,		\
-			 __LINE__, __PRETTY_FUNCTION__);	\
+      tree_check_failed (__t, VAR_DECL, __FILE__, __LINE__, __FUNCTION__); \
     __t; })
 
 #define VAR_FUNCTION_OR_PARM_DECL_CHECK(NODE)			\
@@ -171,8 +170,7 @@ Boston, MA 02111-1307, USA.  */
     if (__c != VAR_DECL 					\
 	&& __c != FUNCTION_DECL 				\
         && __c != PARM_DECL)					\
-      tree_check_failed (__t, VAR_DECL, __FILE__,		\
-			 __LINE__, __PRETTY_FUNCTION__);	\
+      tree_check_failed (__t, VAR_DECL, __FILE__, __LINE__, __FUNCTION__); \
     __t; })
 
 #define VAR_TEMPL_TYPE_OR_FUNCTION_DECL_CHECK(NODE)		\
@@ -182,16 +180,14 @@ Boston, MA 02111-1307, USA.  */
 	&& __c != FUNCTION_DECL					\
 	&& __c != TYPE_DECL					\
 	&& __c != TEMPLATE_DECL)				\
-      tree_check_failed (__t, VAR_DECL, __FILE__,		\
-			 __LINE__, __PRETTY_FUNCTION__);	\
+      tree_check_failed (__t, VAR_DECL, __FILE__, __LINE__, __FUNCTION__); \
     __t; })
 
 #define RECORD_OR_UNION_TYPE_CHECK(NODE)			\
 ({  const tree __t = NODE;					\
     enum tree_code __c = TREE_CODE(__t);			\
     if (__c != RECORD_TYPE && __c != UNION_TYPE)		\
-      tree_check_failed (__t, RECORD_TYPE, __FILE__,		\
-			 __LINE__, __PRETTY_FUNCTION__);	\
+      tree_check_failed (__t, RECORD_TYPE, __FILE__, __LINE__, __FUNCTION__); \
     __t; })
 
 #else /* not ENABLE_TREE_CHECKING, or not gcc */
@@ -4629,9 +4625,15 @@ extern tree binfo_or_else			PARAMS ((tre
 extern void readonly_error			PARAMS ((tree, const char *, int));
 extern int abstract_virtuals_error		PARAMS ((tree, tree));
 extern void incomplete_type_error		PARAMS ((tree, tree));
-extern void my_friendly_abort			PARAMS ((int))
+extern void friendly_abort			PARAMS ((int, const char *,
+							 int, const char *))
   ATTRIBUTE_NORETURN;
-extern void my_friendly_assert			PARAMS ((int, int));
+
+#define my_friendly_abort(N) \
+  friendly_abort (N, __FILE__, __LINE__, __FUNCTION__)
+#define my_friendly_assert(EXP, N) \
+ (((EXP) == 0) ? (friendly_abort (N, __FILE__, __LINE__, __FUNCTION__), 0) : 0)
+
 extern tree store_init_value			PARAMS ((tree, tree));
 extern tree digest_init				PARAMS ((tree, tree, tree *));
 extern tree build_scoped_ref			PARAMS ((tree, tree));
===================================================================
Index: cp/decl.c
--- cp/decl.c	2000/07/17 21:35:46	1.656
+++ cp/decl.c	2000/07/20 19:52:10
@@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA.  */
 #include "cp-tree.h"
 #include "decl.h"
 #include "lex.h"
-#include <signal.h>
 #include "defaults.h"
 #include "output.h"
 #include "except.h"
@@ -105,7 +104,6 @@ static void suspend_binding_level PARAMS
 static void resume_binding_level PARAMS ((struct binding_level *));
 static struct binding_level *make_binding_level PARAMS ((void));
 static void declare_namespace_level PARAMS ((void));
-static void signal_catch PARAMS ((int)) ATTRIBUTE_NORETURN;
 static int decl_jump_unsafe PARAMS ((tree));
 static void storedecls PARAMS ((tree));
 static void require_complete_types_for_parms PARAMS ((tree));
@@ -6103,26 +6101,6 @@ end_only_namespace_names ()
    through; now, it's much more passive by asking them to send the
    maintainers mail about the problem.  */
 
-static void
-signal_catch (sig)
-     int sig ATTRIBUTE_UNUSED;
-{
-  signal (SIGSEGV, SIG_DFL);
-#ifdef SIGIOT
-  signal (SIGIOT, SIG_DFL);
-#endif
-#ifdef SIGILL
-  signal (SIGILL, SIG_DFL);
-#endif
-#ifdef SIGABRT
-  signal (SIGABRT, SIG_DFL);
-#endif
-#ifdef SIGBUS
-  signal (SIGBUS, SIG_DFL);
-#endif
-  my_friendly_abort (0);
-}
-
 /* Push the declarations of builtin types into the namespace.
    RID_INDEX, if < CP_RID_MAX is the index of the builtin type
    in the array RID_POINTERS.  NAME is the name used when looking
@@ -6330,28 +6308,6 @@ init_decl_processing ()
   current_function_decl = NULL_TREE;
   current_binding_level = NULL_BINDING_LEVEL;
   free_binding_level = NULL_BINDING_LEVEL;
-
-  /* Because most segmentation signals can be traced back into user
-     code, catch them and at least give the user a chance of working
-     around compiler bugs.  */
-  signal (SIGSEGV, signal_catch);
-
-  /* We will also catch aborts in the back-end through signal_catch and
-     give the user a chance to see where the error might be, and to defeat
-     aborts in the back-end when there have been errors previously in their
-     code.  */
-#ifdef SIGIOT
-  signal (SIGIOT, signal_catch);
-#endif
-#ifdef SIGILL
-  signal (SIGILL, signal_catch);
-#endif
-#ifdef SIGABRT
-  signal (SIGABRT, signal_catch);
-#endif
-#ifdef SIGBUS
-  signal (SIGBUS, signal_catch);
-#endif
 
   build_common_tree_nodes (flag_signed_char);
 
===================================================================
Index: cp/typeck2.c
--- cp/typeck2.c	2000/07/10 03:47:36	1.85
+++ cp/typeck2.c	2000/07/20 21:45:22
@@ -40,7 +40,6 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 
 static tree process_init_constructor PARAMS ((tree, tree, tree *));
-static void ack PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1;
 
 /* Print an error message stemming from an attempt to use
    BASETYPE as a base class for TYPE.  */
@@ -246,102 +245,23 @@ retry:
     cp_error_at ("incomplete `%D' defined here", value);
 }
 
-/* Like error(), but don't call report_error_function().  */
-
-static void
-ack VPARAMS ((const char *msg, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  const char *msg;
-#endif
-  va_list ap;
-  
-  VA_START (ap, msg);
-
-#ifndef ANSI_PROTOTYPES
-  msg = va_arg (ap, const char *);
-#endif
-  
-  if (input_filename)
-    fprintf (stderr, "%s:%d: ", input_filename, lineno);
-  else
-    fprintf (stderr, "%s: ", progname);
-
-  vfprintf (stderr, msg, ap);
-  va_end (ap);
-  
-  fprintf (stderr, "\n");
-}
-  
-/* There are times when the compiler can get very confused, confused
-   to the point of giving up by aborting, simply because of previous
-   input errors.  It is much better to have the user go back and
-   correct those errors first, and see if it makes us happier, than it
-   is to abort on him.  This is because when one has a 10,000 line
-   program, and the compiler comes back with ``core dump'', the user
-   is left not knowing even where to begin to fix things and no place
-   to even try and work around things.
-
-   The parameter is to uniquely identify the problem to the user, so
-   that they can say, I am having problem 59, and know that fix 7 will
-   probably solve their problem.  Or, we can document what problem
-   59 is, so they can understand how to work around it, should they
-   ever run into it.
-
-   We used to tell people to "fix the above error[s] and try recompiling
-   the program" via a call to fatal, but that message tended to look
-   silly.  So instead, we just do the equivalent of a call to fatal in the
-   same situation (call exit).
-
-   We used to assign sequential numbers for the aborts; now we use an
-   encoding of the date the abort was added, since that has more meaning
-   when we only see the error message.  */
-
-static int abortcount = 0;
-
+/* This is a wrapper around fancy_abort, as used in the back end and
+   other front ends.  It will also report the magic number assigned to
+   this particular abort.  That is for backward compatibility with the
+   old C++ abort handler, which would just report the magic number.  */
 void
-my_friendly_abort (i)
-     int i;
+friendly_abort (where, file, line, func)
+     int where;
+     const char *file;
+     int line;
+     const char *func;
 {
-  /* if the previous error came through here, i.e. report_error_function
-     ended up calling us again, don't just exit; we want a diagnostic of
-     some kind.  */
-  if (abortcount == 1)
-    current_function_decl = NULL_TREE;
-  else if (errorcount > 0 || sorrycount > 0)
-    {
-      if (abortcount > 1)
-	{
-	  if (i == 0)
-	    ack ("Internal compiler error.");
-	  else
-	    ack ("Internal compiler error %d.", i);
-	  ack ("Please submit a full bug report.");
-	  ack ("See %s for instructions.", GCCBUGURL);
-	}
-      else
-	error ("confused by earlier errors, bailing out");
-      
-      exit (34);
-    }
-  ++abortcount;
-
-  if (i == 0)
-    error ("Internal compiler error.");
-  else
-    error ("Internal compiler error %d.", i);
+  if (where > 0)
+    error ("Internal error #%d.", where);
 
-  error ("Please submit a full bug report.");
-  fatal ("See %s for instructions.", GCCBUGURL);
+  fancy_abort (file, line, func);
 }
 
-void
-my_friendly_assert (cond, where)
-     int cond, where;
-{
-  if (cond == 0)
-    my_friendly_abort (where);
-}
 
 /* Perform appropriate conversions on the initial value of a variable,
    store it in the declaration DECL,


More information about the Gcc-patches mailing list