/* Nonzero if a case label has been seen in this case stmt. */
char seenlabel;
} case_stmt;
- /* For exception contours. */
- struct
- {
- /* List of exceptions raised. This is a TREE_LIST
- of whatever you want. */
- tree raised;
- /* List of exceptions caught. This is also a TREE_LIST
- of whatever you want. As a special case, it has the
- value `void_type_node' if it handles default exceptions. */
- tree handled;
-
- /* First insn of TRY block, in case resumptive model is needed. */
- rtx first_insn;
- /* Label for the catch clauses. */
- rtx except_label;
- /* Label for unhandled exceptions. */
- rtx unhandled_label;
- /* Label at the end of whole construct. */
- rtx after_label;
- /* Label which "escapes" the exception construct.
- Like EXIT_LABEL for BREAK construct, but for exceptions. */
- rtx escape_label;
- } except_stmt;
} data;
};
/* Chain of all pending case or switch statements. */
struct nesting *case_stack;
-/* Chain of all pending exception contours. */
-struct nesting *except_stack;
-
/* Separate chain including all of the above,
chained through the `all' field. */
struct nesting *nesting_stack;
stack_block_stack = stack_block_stack->next; \
if (case_stack == this) \
case_stack = case_stack->next; \
- if (except_stack == this) \
- except_stack = except_stack->next; \
nesting_depth = nesting_stack->depth - 1; \
nesting_stack = this->all; \
obstack_free (&stmt_obstack, this); } \
return t;
}
\f
-/* The exception handling nesting looks like this:
-
- <-- Level N-1
- { <-- exception handler block
- <-- Level N
- <-- in an exception handler
- { <-- try block
- : <-- in a TRY block
- : <-- in an exception handler
- :
- }
-
- { <-- except block
- : <-- in an except block
- : <-- in an exception handler
- :
- }
-
- }
-*/
-
-/* Return nonzero iff in a try block at level LEVEL. */
-
-int
-in_try_block (level)
- int level;
-{
- struct nesting *n = except_stack;
- while (1)
- {
- while (n && n->data.except_stmt.after_label != 0)
- n = n->next;
- if (n == 0)
- return 0;
- if (level == 0)
- return n != 0;
- level--;
- n = n->next;
- }
-}
-
-/* Return nonzero iff in an except block at level LEVEL. */
-
-int
-in_except_block (level)
- int level;
-{
- struct nesting *n = except_stack;
- while (1)
- {
- while (n && n->data.except_stmt.after_label == 0)
- n = n->next;
- if (n == 0)
- return 0;
- if (level == 0)
- return n != 0;
- level--;
- n = n->next;
- }
-}
-
-/* Return nonzero iff in an exception handler at level LEVEL. */
-
-int
-in_exception_handler (level)
- int level;
-{
- struct nesting *n = except_stack;
- while (n && level--)
- n = n->next;
- return n != 0;
-}
-
-/* Record the fact that the current exception nesting raises
- exception EX. If not in an exception handler, return 0. */
-int
-expand_raise (ex)
- tree ex;
-{
- tree *raises_ptr;
-
- if (except_stack == 0)
- return 0;
- raises_ptr = &except_stack->data.except_stmt.raised;
- if (! value_member (ex, *raises_ptr))
- *raises_ptr = tree_cons (NULL_TREE, ex, *raises_ptr);
- return 1;
-}
-
-/* Generate RTL for the start of a try block.
-
- TRY_CLAUSE is the condition to test to enter the try block. */
-
-void
-expand_start_try (try_clause, exitflag, escapeflag)
- tree try_clause;
- int exitflag;
- int escapeflag;
-{
- struct nesting *thishandler = ALLOC_NESTING ();
-
- /* Make an entry on cond_stack for the cond we are entering. */
-
- thishandler->next = except_stack;
- thishandler->all = nesting_stack;
- thishandler->depth = ++nesting_depth;
- thishandler->data.except_stmt.raised = 0;
- thishandler->data.except_stmt.handled = 0;
- thishandler->data.except_stmt.first_insn = get_insns ();
- thishandler->data.except_stmt.except_label = gen_label_rtx ();
- thishandler->data.except_stmt.unhandled_label = 0;
- thishandler->data.except_stmt.after_label = 0;
- thishandler->data.except_stmt.escape_label
- = escapeflag ? thishandler->data.except_stmt.except_label : 0;
- thishandler->exit_label = exitflag ? gen_label_rtx () : 0;
- except_stack = thishandler;
- nesting_stack = thishandler;
-
- do_jump (try_clause, thishandler->data.except_stmt.except_label, NULL_RTX);
-}
-
-/* End of a TRY block. Nothing to do for now. */
-
-void
-expand_end_try ()
-{
- except_stack->data.except_stmt.after_label = gen_label_rtx ();
- expand_goto_internal (NULL_TREE, except_stack->data.except_stmt.after_label,
- NULL_RTX);
-}
-
-/* Start an `except' nesting contour.
- EXITFLAG says whether this contour should be able to `exit' something.
- ESCAPEFLAG says whether this contour should be escapable. */
-
-void
-expand_start_except (exitflag, escapeflag)
- int exitflag;
- int escapeflag;
-{
- if (exitflag)
- {
- struct nesting *n;
- /* An `exit' from catch clauses goes out to next exit level,
- if there is one. Otherwise, it just goes to the end
- of the construct. */
- for (n = except_stack->next; n; n = n->next)
- if (n->exit_label != 0)
- {
- except_stack->exit_label = n->exit_label;
- break;
- }
- if (n == 0)
- except_stack->exit_label = except_stack->data.except_stmt.after_label;
- }
- if (escapeflag)
- {
- struct nesting *n;
- /* An `escape' from catch clauses goes out to next escape level,
- if there is one. Otherwise, it just goes to the end
- of the construct. */
- for (n = except_stack->next; n; n = n->next)
- if (n->data.except_stmt.escape_label != 0)
- {
- except_stack->data.except_stmt.escape_label
- = n->data.except_stmt.escape_label;
- break;
- }
- if (n == 0)
- except_stack->data.except_stmt.escape_label
- = except_stack->data.except_stmt.after_label;
- }
- do_pending_stack_adjust ();
- emit_label (except_stack->data.except_stmt.except_label);
-}
-
-/* Generate code to `escape' from an exception contour. This
- is like `exiting', but does not conflict with constructs which
- use `exit_label'.
-
- Return nonzero if this contour is escapable, otherwise
- return zero, and language-specific code will emit the
- appropriate error message. */
-int
-expand_escape_except ()
-{
- struct nesting *n;
- last_expr_type = 0;
- for (n = except_stack; n; n = n->next)
- if (n->data.except_stmt.escape_label != 0)
- {
- expand_goto_internal (NULL_TREE,
- n->data.except_stmt.escape_label, NULL_RTX);
- return 1;
- }
-
- return 0;
-}
-
-/* Finish processing and `except' contour.
- Culls out all exceptions which might be raise but not
- handled, and returns the list to the caller.
- Language-specific code is responsible for dealing with these
- exceptions. */
-
-tree
-expand_end_except ()
-{
- struct nesting *n;
- tree raised = NULL_TREE;
-
- do_pending_stack_adjust ();
- emit_label (except_stack->data.except_stmt.after_label);
-
- n = except_stack->next;
- if (n)
- {
- /* Propagate exceptions raised but not handled to next
- highest level. */
- tree handled = except_stack->data.except_stmt.raised;
- if (handled != void_type_node)
- {
- tree prev = NULL_TREE;
- raised = except_stack->data.except_stmt.raised;
- while (handled)
- {
- tree this_raise;
- for (this_raise = raised, prev = 0; this_raise;
- this_raise = TREE_CHAIN (this_raise))
- {
- if (value_member (TREE_VALUE (this_raise), handled))
- {
- if (prev)
- TREE_CHAIN (prev) = TREE_CHAIN (this_raise);
- else
- {
- raised = TREE_CHAIN (raised);
- if (raised == NULL_TREE)
- goto nada;
- }
- }
- else
- prev = this_raise;
- }
- handled = TREE_CHAIN (handled);
- }
- if (prev == NULL_TREE)
- prev = raised;
- if (prev)
- TREE_CHAIN (prev) = n->data.except_stmt.raised;
- nada:
- n->data.except_stmt.raised = raised;
- }
- }
-
- POPSTACK (except_stack);
- last_expr_type = 0;
- return raised;
-}
-
-/* Record that exception EX is caught by this exception handler.
- Return nonzero if in exception handling construct, otherwise return 0. */
-int
-expand_catch (ex)
- tree ex;
-{
- tree *raises_ptr;
-
- if (except_stack == 0)
- return 0;
- raises_ptr = &except_stack->data.except_stmt.handled;
- if (*raises_ptr != void_type_node
- && ex != NULL_TREE
- && ! value_member (ex, *raises_ptr))
- *raises_ptr = tree_cons (NULL_TREE, ex, *raises_ptr);
- return 1;
-}
-
-/* Record that this exception handler catches all exceptions.
- Return nonzero if in exception handling construct, otherwise return 0. */
-
-int
-expand_catch_default ()
-{
- if (except_stack == 0)
- return 0;
- except_stack->data.except_stmt.handled = void_type_node;
- return 1;
-}
-
-int
-expand_end_catch ()
-{
- if (except_stack == 0 || except_stack->data.except_stmt.after_label == 0)
- return 0;
- expand_goto_internal (NULL_TREE, except_stack->data.except_stmt.after_label,
- NULL_RTX);
- return 1;
-}
-\f
/* Generate RTL for the start of an if-then. COND is the expression
whose truth should be tested.