DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T c

⟦e5623c57f⟧ TextFile

    Length: 21812 (0x5534)
    Types: TextFile
    Names: »cplus-except.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦6f889378a⟧ »./g++-1.36.1.tar.Z« 
        └─⟦3aa9a3deb⟧ 
            └─⟦this⟧ »g++-1.36.1/cplus-except.c« 

TextFile

/* Handle exceptional things in C++.
   Copyright (C) 1989 Free Software Foundation, Inc.
   Contributed by Michael Tiemann (tiemann@mcc.com)

This file is part of GNU CC.

GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */


/* High-level class interface. */

#define NULL 0
#define EXCEPTION_NAME_PREFIX "__exception_"
#define EXCEPTION_NAME_LENGTH 12

#include "config.h"
#include "tree.h"
#include "cplus-tree.h"
#include "flags.h"
#include "assert.h"
/* On Suns this can get you to the right definition if you
   set the right value for TARGET.  */
#include <setjmp.h>
#ifdef sequent
/* Can you believe they forgot this?  */
#define _JBLEN 11
#endif

#ifndef _JBLEN
#define _JBLEN (sizeof(jmp_buf)/sizeof(int))
#endif

tree exception_label_decl;

/* The exception `type' currently in scope, or NULL_TREE if none.  */
tree current_exception_type;

/* The exception handler object for the given scope.  */
tree current_exception_decl;

/* The ``object'' view of the current exception parameters.
   We cast up from the `parms' field to `current_exception_type'.  */
tree current_exception_object;

/* Low-level rtl interface.  */
#include "rtl.h"

/* Cache `setjmp' and `longjmp'.  Maybe later they will get built-in.  */
static tree BISJ, BILJ;

/* Local variables which give the appearance that exception
   handling is part of the language and the execution model.  */

/* The type of the exception handler stack.  */
static tree EHS_type;

/* The global handler stack.  */
static tree EHS_decl;

/* Cached component refs to fields of `EHS_decl'.  */
static tree EHS_prev, EHS_handler, EHS_parms, EHS_name;

/* The parameter names of this exception type.  */

static tree last_exception_fields;
static tree last_exception_field_types;

/* When ID is VOID_TYPE_NODE, it means ``raise all''.
   Cannot be inline, since it uses `alloca', and that
   breaks code which pushes the result of this function
   on the stack.  */
static tree
exception_object_name (prefix, id)
     tree prefix;
     tree id;
{
  /* First, cons up the `name' of this exception.  */
  char *name;
  int length = (id == void_type_node ? 3 : IDENTIFIER_LENGTH (id)) + EXCEPTION_NAME_LENGTH;

  if (prefix)
    length += IDENTIFIER_LENGTH (prefix) + 2;

  name = (char *)alloca (length);
  strcpy (name, EXCEPTION_NAME_PREFIX);
  length = EXCEPTION_NAME_LENGTH;
  if (prefix)
    {
      strcpy (name + length, IDENTIFIER_POINTER (prefix));
      name[length + IDENTIFIER_LENGTH (prefix)] = JOINER;
      length += IDENTIFIER_LENGTH (prefix) + 1;
    }
  if (id == void_type_node)
    strcpy (name + length, "all");
  else
    strcpy (name + length, IDENTIFIER_POINTER (id));
  return get_identifier (name);
}

tree
lookup_exception_cname (ctype, cname, raise_id)
     tree ctype, cname;
     tree raise_id;
{
  tree this_cname = TREE_PURPOSE (raise_id);
  if (this_cname == NULL_TREE)
    {
      if (cname)
	{
	  tree name = TREE_VALUE (raise_id);
	  if (purpose_member (name, CLASSTYPE_TAGS (ctype)))
	    this_cname = cname;
	}
    }
  else if (this_cname == void_type_node)
    this_cname = NULL_TREE;
  else if (TREE_CODE (this_cname) != IDENTIFIER_NODE)
    {
      sorry ("multiple scope refs in `expand_cplus_raise_stmt'");
      this_cname = error_mark_node;
    }
  return this_cname;
}

tree
lookup_exception_tname (oname)
     tree oname;
{
  return get_identifier (IDENTIFIER_POINTER (oname) + EXCEPTION_NAME_LENGTH);
}

tree
lookup_exception_object (cname, name, complain)
     tree cname, name;
     int complain;
{
  tree oname;
  tree decl;

  if (cname == void_type_node)
    cname = NULL_TREE;
  else if (cname && TREE_CODE (cname) != IDENTIFIER_NODE)
    {
      sorry ("multiple scope refs in `lookup_exception_object'");
      cname = NULL_TREE;
    }
  oname = exception_object_name (cname, name);
  decl = IDENTIFIER_GLOBAL_VALUE (oname);
  if (decl == NULL_TREE || TREE_CODE (decl) != VAR_DECL)
    {
      if (complain)
	{
	  if (cname)
	    error ("no exception name object for name `%s::%s'",
		   IDENTIFIER_POINTER (cname),
		   IDENTIFIER_POINTER (name));
	  else
	    error ("no exception name object for name `%s'",
		   IDENTIFIER_POINTER (name));
	  /* Avoid further error messages.  */
	  pushdecl_top_level (build_lang_field_decl (VAR_DECL,
						     exception_object_name (cname, name),
						     error_mark_node));
	}
      return NULL_TREE;
    }
  return decl;
}

tree
lookup_exception_type (ctype, cname, raise_id)
     tree ctype, cname;
     tree raise_id;
{
  tree name = TREE_VALUE (raise_id);
  tree purpose = TREE_PURPOSE (raise_id);

  if (cname && purpose == NULL_TREE)
    purpose = cname;

  if (purpose && purpose != void_type_node)
    {
      tree assoc = NULL_TREE;

      if (TREE_CODE (purpose) != IDENTIFIER_NODE)
	{
	  sorry ("multiple scope refs in `lookup_exception_type'");
	  TREE_PURPOSE (raise_id) = NULL_TREE;
	  return NULL_TREE;
	}
      if (! is_aggr_typedef (purpose, 1))
	return NULL_TREE;
      ctype = TREE_TYPE (TREE_TYPE (purpose));
      assoc = purpose_member (name, CLASSTYPE_TAGS (ctype));
      if (assoc)
	return TREE_VALUE (assoc);
    }

  ctype = lookup_name (name);
  if (ctype && TREE_CODE (ctype) == TYPE_DECL)
    ctype = TREE_TYPE (ctype);
  if (ctype && TREE_CODE (ctype) == RECORD_TYPE
      && CLASSTYPE_DECLARED_EXCEPTION (ctype))
    return ctype;
  return NULL_TREE;
}

tree
finish_exception (e, list_of_fieldlists)
     tree e;
     tree list_of_fieldlists;
{
  tree parmtypes = NULL_TREE, name_field;
  tree cname = TYPE_NAME (e);

  if (TREE_CODE (cname) == TYPE_DECL)
    cname = DECL_NAME (cname);

  if (last_exception_fields)
    error ("cannot declare exceptions within exceptions");
  if (list_of_fieldlists && ! ANON_AGGRNAME_P (cname))
    error_with_aggr_type (e, "exception name `%s' must follow body declaration");
  if (list_of_fieldlists)
    {
      tree prev, field;

      /* Note: no public, private, or protected allowed.  */
      if (TREE_CHAIN (list_of_fieldlists))
	error ("visibility declarations invalid in exception declaration");
      else if (TREE_PURPOSE (list_of_fieldlists) != (tree)visibility_default)
	error ("visibility declarations invalid in exception declaration");
      TREE_PURPOSE (list_of_fieldlists) = (tree)visibility_default;

      /* Note also: no member function declarations allowed.  */
      for (prev = 0, field = TREE_VALUE (list_of_fieldlists);
	   field; prev = field, field = TREE_CHAIN (field))
	{
	  switch (TREE_CODE (field))
	    {
	    case FIELD_DECL:
	      /* ok.  */
	      parmtypes = tree_cons (NULL_TREE, TREE_TYPE (field), parmtypes);
	      continue;
	    case FUNCTION_DECL:
	      error_with_decl (field, "declaration of function `%s' in exception invalid");
	      break;
	    case VAR_DECL:
	      if (TREE_STATIC (field))
		error_with_decl (field, "declaration of static variable `%s' in exception invalid");
	      else
		error_with_decl (field, "declaration of constant field `%s' in exception invalid");
	      break;
	    case CONST_DECL:
	      error_with_decl (field, "declaration of enum value `%s' in exception invalid");
	      break;
	    case SCOPE_REF:
	      error ("use of `::' in exception context invalid");
	      break;
	    }
	  if (prev)
	    TREE_CHAIN (prev) = TREE_CHAIN (field);
	  else
	    TREE_VALUE (list_of_fieldlists) = TREE_CHAIN (field);
	}
    }

  /* Now that we've cleaned up the fields, add a name identifier at front.  */
  name_field = build_lang_field_decl (FIELD_DECL, get_identifier ("__name"),
				      ptr_type_node);
  if (list_of_fieldlists)
    {
      TREE_CHAIN (name_field) = TREE_VALUE (list_of_fieldlists);
      TREE_VALUE (list_of_fieldlists) = name_field;
    }
  else
    list_of_fieldlists = build_tree_list (NULL_TREE, name_field);

  last_exception_fields = TREE_VALUE (list_of_fieldlists);
  if (parmtypes)
    {
      last_exception_field_types = nreverse (parmtypes);
      /* Set the TREE_CHAIN of what is now at the end of the
	 list to `void_list_node'.  */
      TREE_CHAIN (parmtypes) = void_list_node;
    }
  else
    last_exception_field_types = void_list_node;

  popclass (0);

#if 0
  /* Remove aggregate types from the list of tags,
     since these appear at global scope.  */
  while (x && IS_AGGR_TYPE (TREE_VALUE (x)))
    x = TREE_CHAIN (x);
  CLASSTYPE_TAGS (t) = x;
  y = x;
  while (x)
    {
      if (IS_AGGR_TYPE (TREE_VALUE (x)))
	TREE_CHAIN (y) = TREE_CHAIN (x);
      x = TREE_CHAIN (x);
    }
#endif

  return e;
}

void
finish_exception_decl (cname, decl)
     tree cname, decl;
{
  /* In cplus-decl.h.  */
  extern tree last_function_parms;

  /* An exception declaration.  */
  tree t, ctor;
  tree parmdecls = NULL_TREE, fields;
  tree list_of_fieldlists = temp_tree_cons (NULL_TREE,
					    copy_list (last_exception_fields),
					    NULL_TREE);
  tree edecl = build_lang_field_decl (VAR_DECL,
				      exception_object_name (cname, DECL_NAME (decl)),
				      ptr_type_node);

  DECL_LANGUAGE (edecl) = lang_c;
  TREE_STATIC (edecl) = 1;
  TREE_PUBLIC (edecl) = 1;
  finish_decl (pushdecl (edecl), 0, 0);

  /* Now instantiate the exception decl.  */
  t = xref_tag (exception_type_node, DECL_NAME (decl), NULL_TREE);

  /* finish_struct will pop this.  */
  pushclass (t, 0);

  /* Now add a constructor which takes as parameters all the types we
     just defined.  */
  ctor = build_lang_decl (FUNCTION_DECL, DECL_NAME (decl),
			  build_cplus_method_type (t, TYPE_POINTER_TO (t),
						   last_exception_field_types));
  /* Don't take `name'.  The constructor handles that.  */
  fields = TREE_CHAIN (TREE_VALUE (list_of_fieldlists));
  while (fields)
    {
      tree parm = build_decl (PARM_DECL, DECL_NAME (fields), TREE_TYPE (fields));
      /* Since there is a prototype, args are passed in their own types.  */
      DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
#ifdef PROMOTE_PROTOTYPES
      if (TREE_CODE (TREE_TYPE (fields)) == INTEGER_TYPE
	  && TYPE_PRECISION (TREE_TYPE (fields)) < TYPE_PRECISION (integer_type_node))
	DECL_ARG_TYPE (parm) = integer_type_node;
#endif
      TREE_CHAIN (parm) = parmdecls;
      parmdecls = parm;
      fields = TREE_CHAIN (fields);
    }
  fields = TREE_VALUE (list_of_fieldlists);
  last_function_parms = nreverse (parmdecls);

  DECL_CONSTRUCTOR_P (ctor) = 1;
  TYPE_HAS_CONSTRUCTOR (t) = 1;
  grokclassfn (t, DECL_NAME (decl), ctor, NO_SPECIAL, 0, NULL_TREE);
  TREE_EXTERNAL (ctor) = 1;
  TREE_STATIC (ctor) = 1;
  TREE_PUBLIC (ctor) = 0;
  TREE_INLINE (ctor) = 1;
  make_decl_rtl (ctor, 0, 1);
  finish_decl (ctor, NULL_TREE, 0);
  TREE_CHAIN (ctor) = TREE_VALUE (list_of_fieldlists);
  TREE_VALUE (list_of_fieldlists) = ctor;

  finish_struct (t, list_of_fieldlists, 0, 0);

  if (current_function_decl)
    error ("cannot define exception inside function scope");
  else
    {
      /* Now build the constructor for this exception.
	 Pretending that CTOR is not a constructor simplifies
	 things here.  */
      DECL_CONSTRUCTOR_P (ctor) = 0;
      parmdecls = DECL_ARGUMENTS (ctor);
      start_function (NULL_TREE, ctor, 0, 1);
      store_parm_decls (parmdecls);
      pushlevel (0);
      clear_last_expr ();
      push_momentary ();
      expand_start_bindings (0);

      /* Move all the parameters to the fields, skipping `this'.  */
      parmdecls = TREE_CHAIN (parmdecls);
      /* Install `name' of this exception handler.  */
      expand_assignment (build (COMPONENT_REF, TREE_TYPE (fields), C_C_D, fields),
			 build_unary_op (ADDR_EXPR, edecl, 0), 0, 0);
      fields = TREE_CHAIN (fields);
      /* Install all the values.  */
      while (parmdecls)
	{
	  expand_expr_stmt (build_modify_expr (build (COMPONENT_REF, TREE_TYPE (fields), C_C_D, fields),
					       INIT_EXPR,
					       parmdecls));
	  fields = TREE_CHAIN (fields);
	  parmdecls = TREE_CHAIN (parmdecls);
	}
      c_expand_return (current_class_decl);
      expand_end_bindings (getdecls (), 1, 0);
      poplevel (1, 0, 1);
      pop_momentary ();

      finish_function (DECL_SOURCE_LINE (ctor), 0);
      DECL_CONSTRUCTOR_P (ctor) = 1;
    }
}

void
end_exception_decls ()
{
  last_exception_field_types = NULL_TREE;
  last_exception_fields = NULL_TREE;
}
\f


/* Statement-level exception semantics.  */

void
cplus_expand_start_try ()
{
  tree call_to_setjmp;
  tree handler, ref;

  /* Start a new block enclosing the whole handler.  */
  pushlevel (0);
  clear_last_expr ();
  push_momentary ();
  expand_start_bindings (0);

  /* Allocate handler in that block.  It's real name will come later.
     Note that it will be the only name in this binding contour.  */
  handler = get_temp_name (EHS_type, 0);
  DECL_INITIAL (handler) = error_mark_node;
  finish_decl (handler, NULL_TREE, 0);

  /* Catch via `setjmp'.  */
  ref = build_component_ref (handler, get_identifier ("handler"), NULL_TREE, 0);
  call_to_setjmp = build_function_call (BISJ, build_tree_list (NULL_TREE, ref));
  expand_start_cond (build_binary_op (EQ_EXPR, call_to_setjmp, integer_zero_node), 0);
}

tree
cplus_expand_end_try ()
{
  /* Get the exception handler object built by `...start_try'.  */
  tree decl = getdecls ();

  assert (TREE_CODE (decl) == VAR_DECL && TREE_TYPE (decl) == EHS_type);

  /* Pass it back so that its rtl can be bound to its name
     (or vice versa).  */
  return decl;
}

void
cplus_expand_start_except (name, decl)
     tree name, decl;
{
  int yes;
  tree tmp;

  expand_start_else ();

  /* Cheap way to get nesting properties we want.
     Not a real loop.  */
  expand_start_loop (1);

  /* This is internal `eh'.  */
  current_exception_decl = decl;
  /* Get the exception object into scope (user declared `ex').  */
  tmp = pushdecl (build_decl (VAR_DECL, name, ptr_type_node));
  DECL_INITIAL (tmp) = error_mark_node;
  finish_decl (tmp, build (COMPONENT_REF, ptr_type_node, decl, TREE_OPERAND (EHS_parms, 1)), 0);
  current_exception_type = NULL_TREE;
  yes = suspend_momentary ();
  /* From now on, send the user to our faked-up object.  */
  current_exception_object = build1 (INDIRECT_REF, void_type_node, tmp);
  IDENTIFIER_LOCAL_VALUE (name) = current_exception_object;
  resume_momentary (yes);

  /* Pop exception handler stack.  */
  expand_assignment (EHS_decl, EHS_prev, 0, 0);
}

/* Note that this must be mirror image of `...start_try'.  */
void
cplus_expand_end_except ()
{
  tree decls;

  expand_end_loop ();
  expand_end_else ();

  decls = getdecls ();
  expand_end_bindings (decls, decls != 0, 1);
  poplevel (decls != 0, 1, 0);
  pop_momentary ();
}

void
expand_cplus_raise_stmt (raise_id, parms)
     tree raise_id;
     tree parms;
{
  /* Allocate new exception of appropriate type, passing
     PARMS to its constructor.  */
  tree cname, name;
  tree decl;
  tree exp;

  cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
  if (cname == error_mark_node)
    return;
  name = TREE_VALUE (raise_id);

  decl = lookup_exception_object (cname, name, 1);
#if 0
  /* Check that it is valid for this function to raise the
     given exception.  */
  if (! value_member (decl, TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))))
    {
      error ("current function not declared to raise exception `%s'",
	     IDENTIFIER_POINTER (name));
      return;
    }
#endif

  if (decl == NULL_TREE)
    return;

  exp = build_method_call (NULL_TREE, name, parms, NULL_TREE, LOOKUP_COMPLAIN);
  if (exp == error_mark_node)
    return;

  expand_assignment (EHS_parms, exp, 0, 0);

  /* Set the global exception handler stack's NAME field
     to the `name' of this exception.  */
  expand_assignment (EHS_name, build_unary_op (ADDR_EXPR, decl, 0), 0, 0);
  
  /* Invoke destructors for current procedure.  */
  if (exception_label_decl == 0)
    exception_label_decl = build_decl (LABEL_DECL, 0, 0);
  /* Invoke destructors for current procedure...done by fixup_cleanups.  */
  expand_goto (exception_label_decl);
  /* Throw via `longjmp'... Done at end of function.  */
}

void
expand_cplus_reraise_stmt (exceptions)
     tree exceptions;
{
  while (exceptions)
    {
      printf ("reraising exception `%s'\n",
	      IDENTIFIER_POINTER (TREE_VALUE (exceptions)));
      exceptions = TREE_CHAIN (exceptions);
    }
}

void
expand_cplus_exception_label ()
{
  tree call_to_longjmp;
  tree past_longjmp_label_decl = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);

  /* Jump around the longjmp.  */
  expand_goto (past_longjmp_label_decl);

  expand_label (exception_label_decl);

  /* Throw via `longjmp'.  */
  call_to_longjmp = build_function_call (BILJ, tree_cons (NULL_TREE, EHS_handler,
							  build_tree_list (0, integer_one_node)));
  expand_expr (call_to_longjmp, 0, 0, 0);

  /* Normal returns (of whatever sort) will get to here.  */
  expand_label (past_longjmp_label_decl);
}

void
expand_cplus_start_exception (raise_id)
     tree raise_id;
{
  tree cname = lookup_exception_cname (current_class_type, current_class_name, raise_id);
  tree decl;
  tree ref, cond;

  if (cname == error_mark_node)
    cond = error_mark_node;
  else
    {
      decl = lookup_exception_object (cname, TREE_VALUE (raise_id), 1);
      if (decl == NULL_TREE)
	{
	  cond = error_mark_node;
	}
      else
	{
	  ref = build (COMPONENT_REF, ptr_type_node,
		       current_exception_decl, TREE_OPERAND (EHS_name, 1));
	  cond = build_binary_op (EQ_EXPR, build_unary_op (ADDR_EXPR, decl, 0), ref);
	}
    }
  expand_start_cond (cond, 0);
  if (current_exception_type
      && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
    {
      /* Make a cleanup for the name-specific exception object now in scope.  */
      tree cleanup = maybe_build_cleanup (current_exception_object);
      expand_start_bindings (0);
      expand_decl (NULL_TREE, cleanup);
    }
}

void
expand_cplus_end_exception ()
{
  if (current_exception_type
      && TYPE_NEEDS_DESTRUCTOR (current_exception_type))
    {
      /* Destroy the specific exception object now in scope.  */
      expand_end_bindings (getdecls (), 1, 1);
    }
  expand_exit_something ();
  expand_end_cond ();
}

void
init_exception_processing ()
{
  tree cname = get_identifier ("ExceptionHandler");
  tree field, chain;
  tree ctor, dtor;
  tree EHS_DECL;
  tree jmp_buf_type = build_array_type (integer_type_node,
					build_index_type (build_int_2 (_JBLEN-1, 0)));
  tree jmp_buf_arg_type = build_pointer_type (integer_type_node);

  tree parmtypes = hash_tree_chain (jmp_buf_arg_type, NULL_TREE);
  tree setjmp_fndecl, longjmp_fndecl;

  EHS_type = xref_tag (record_type_node, cname, NULL_TREE);

  setjmp_fndecl = build_lang_decl (FUNCTION_DECL, get_identifier ("setjmp"),
				   build_function_type (integer_type_node,
							parmtypes));
  make_function_rtl (setjmp_fndecl);
  BISJ = default_conversion (setjmp_fndecl);
  longjmp_fndecl = build_lang_decl (FUNCTION_DECL, get_identifier ("longjmp"),
				    build_function_type (integer_type_node,
							 hash_tree_chain (jmp_buf_arg_type,
									  hash_tree_chain (integer_type_node, NULL_TREE))));
  make_function_rtl (longjmp_fndecl);
  BILJ = default_conversion (longjmp_fndecl);

  /* finish_struct will pop this.  */
  pushclass (EHS_type, 0);
  field = build_lang_field_decl (FIELD_DECL, get_identifier ("parms"), ptr_type_node);
  chain = field;
  field = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
				 build_pointer_type (default_function_type));
  TREE_CHAIN (field) = chain;
  chain = field;
  field = build_lang_field_decl (FIELD_DECL, get_identifier ("handler"), jmp_buf_type);
  TREE_CHAIN (field) = chain;
  chain = field;
  field = build_lang_field_decl (FIELD_DECL, get_identifier ("prev"),
				 TYPE_POINTER_TO (EHS_type));
  TREE_CHAIN (field) = chain;
  chain = field;

  ctor = build_lang_decl (FUNCTION_DECL, cname,
			  build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
  DECL_CONSTRUCTOR_P (ctor) = 1;
  TREE_STATIC (ctor) = 1;
  TREE_PUBLIC (ctor) = 1;
  grokclassfn (EHS_type, cname, ctor, NO_SPECIAL, 0, 0);
  finish_decl (ctor, 0, 0);
  TREE_CHAIN (ctor) = chain;
  chain = ctor;
  dtor = build_lang_decl (FUNCTION_DECL, cname,
			  build_cplus_method_type (EHS_type, TYPE_POINTER_TO (EHS_type), void_list_node));
  TREE_STATIC (dtor) = 1;
  TREE_PUBLIC (dtor) = 1;
  grokclassfn (EHS_type, cname, dtor, DTOR_FLAG, 0, 0);
  finish_decl (dtor, 0, 0);
  TREE_CHAIN (dtor) = chain;
  chain = dtor;
  TYPE_HAS_CONSTRUCTOR (EHS_type) = 1;
  TYPE_HAS_DESTRUCTOR (EHS_type) = 1;
  finish_struct (EHS_type, temp_tree_cons (NULL_TREE, chain, NULL_TREE), 0, 0);
  EHS_decl = build_decl (VAR_DECL, get_identifier ("exceptionHandlerStack"),
			 TYPE_POINTER_TO (EHS_type));
  /* If we don't push this, its definition, should it be encountered,
     will not be seen.  */
  EHS_decl = pushdecl (EHS_decl);
  EHS_DECL = build1 (INDIRECT_REF, EHS_type, EHS_decl);
  TREE_EXTERNAL (EHS_decl) = 1;
  TREE_STATIC (EHS_decl) = 1;
  TREE_PUBLIC (EHS_decl) = 1;
  finish_decl (EHS_decl, 0, 0);
  EHS_prev = build_component_ref (EHS_DECL, get_identifier ("prev"), 0, 0);
  EHS_handler = build_component_ref (EHS_DECL, get_identifier ("handler"), 0, 0);
  EHS_parms = build_component_ref (EHS_DECL, get_identifier ("parms"), 0, 0);
  EHS_name = build_component_ref (EHS_DECL, get_identifier ("name"), 0, 0);
}