semantics.c: New file, containing routines to perform the semantic phase of parsing.

* semantics.c: New file, containing routines to perform the
	semantic phase of parsing.
	* parse.y: Use it.
	* pt.c (tsubst_expr): Likewise.
	* cp-tree.h: Declare the various functions in semantics.c.
	Provide macros to access _STMT tree nodes.
	* cp-tree.def: Add ASM_STMT tree node.
	* Makefile.in, Make-lang.in: Add dependencies on and for
	semantics.c.

From-SVN: r18658
This commit is contained in:
Mark Mitchell 1998-03-18 10:52:04 +00:00 committed by Mark Mitchell
parent cbe3672526
commit ad32129310
9 changed files with 4140 additions and 4167 deletions

View File

@ -1,3 +1,15 @@
Wed Mar 18 10:09:51 1998 Mark Mitchell <mmitchell@usa.net>
* semantics.c: New file, containing routines to perform the
semantic phase of parsing.
* parse.y: Use it.
* pt.c (tsubst_expr): Likewise.
* cp-tree.h: Declare the various functions in semantics.c.
Provide macros to access _STMT tree nodes.
* cp-tree.def: Add ASM_STMT tree node.
* Makefile.in, Make-lang.in: Add dependencies on and for
semantics.c.
Wed Mar 18 00:24:10 1998 Jason Merrill <jason@yorick.cygnus.com>
* pt.c (push_template_decl): Only check primary templates.

View File

@ -122,7 +122,7 @@ CXX_SRCS = $(srcdir)/cp/call.c $(srcdir)/cp/decl2.c \
$(srcdir)/cp/search.c $(srcdir)/cp/typeck.c $(srcdir)/cp/decl.c \
$(srcdir)/cp/error.c $(srcdir)/cp/friend.c $(srcdir)/cp/init.c \
$(srcdir)/cp/parse.y $(srcdir)/cp/sig.c $(srcdir)/cp/typeck2.c \
$(srcdir)/cp/repo.c
$(srcdir)/cp/repo.c $(srcdir)/cp/semantics.c
cc1plus: $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o c-pragma.o \
$(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def

View File

@ -166,7 +166,7 @@ INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../config
CXX_OBJS = call.o decl.o errfn.o expr.o pt.o sig.o typeck2.o \
class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o \
except.o friend.o init.o method.o search.o tree.o xref.o repo.o
except.o friend.o init.o method.o search.o semantics.o tree.o xref.o repo.o
# Language-independent object files.
OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
@ -259,6 +259,8 @@ error.o : error.c $(CONFIG_H) $(CXX_TREE_H)
errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H)
sig.o : sig.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H)
semantics.o: semantics.c $(CONFIG_H) $(CXX_TREE_H) lex.h $(srcdir)/../except.h
#
# These exist for maintenance purposes.

View File

@ -200,6 +200,7 @@ DEFTREECODE (BREAK_STMT, "break_stmt", 'e', 0)
DEFTREECODE (CONTINUE_STMT, "continue_stmt", 'e', 0)
DEFTREECODE (SWITCH_STMT, "switch_stmt", 'e', 2)
DEFTREECODE (GOTO_STMT, "goto_stmt", 'e', 1)
DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 5)
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
DEFTREECODE (CASE_LABEL, "case_label", 'e', 2)

View File

@ -1524,6 +1524,37 @@ extern int flag_new_for_scope;
#define builtin_function(NAME, TYPE, CODE, LIBNAME) \
define_function (NAME, TYPE, CODE, (void (*) PROTO((tree)))pushdecl, LIBNAME)
/* These macros provide convenient access to the various _STMT nodes
created when parsing template declarations. */
#define IF_COND(NODE) TREE_OPERAND (NODE, 0)
#define THEN_CLAUSE(NODE) TREE_OPERAND (NODE, 1)
#define ELSE_CLAUSE(NODE) TREE_OPERAND (NODE, 2)
#define WHILE_COND(NODE) TREE_OPERAND (NODE, 0)
#define WHILE_BODY(NODE) TREE_OPERAND (NODE, 1)
#define DO_COND(NODE) TREE_OPERAND (NODE, 0)
#define DO_BODY(NODE) TREE_OPERAND (NODE, 1)
#define RETURN_EXPR(NODE) TREE_OPERAND (NODE, 0)
#define EXPR_STMT_EXPR(NODE) TREE_OPERAND (NODE, 0)
#define FOR_INIT_STMT(NODE) TREE_OPERAND (NODE, 0)
#define FOR_COND(NODE) TREE_OPERAND (NODE, 1)
#define FOR_EXPR(NODE) TREE_OPERAND (NODE, 2)
#define FOR_BODY(NODE) TREE_OPERAND (NODE, 3)
#define SWITCH_COND(NODE) TREE_OPERAND (NODE, 0)
#define SWITCH_BODY(NODE) TREE_OPERAND (NODE, 1)
#define CASE_LOW(NODE) TREE_OPERAND (NODE, 0)
#define CASE_HIGH(NODE) TREE_OPERAND (NODE, 1)
#define GOTO_DESTINATION(NODE) TREE_OPERAND (NODE, 0)
#define TRY_STMTS(NODE) TREE_OPERAND (NODE, 0)
#define TRY_HANDLERS(NODE) TREE_OPERAND (NODE, 1)
#define HANDLER_PARMS(NODE) TREE_OPERAND (NODE, 0)
#define HANDLER_BODY(NODE) TREE_OPERAND (NODE, 1)
#define COMPOUND_BODY(NODE) TREE_OPERAND (NODE, 0)
#define ASM_CV_QUAL(NODE) TREE_OPERAND (NODE, 0)
#define ASM_STRING(NODE) TREE_OPERAND (NODE, 1)
#define ASM_OUTPUTS(NODE) TREE_OPERAND (NODE, 2)
#define ASM_INPUTS(NODE) TREE_OPERAND (NODE, 3)
#define ASM_CLOBBERS(NODE) TREE_OPERAND (NODE, 4)
/* An enumeration of the kind of tags that C++ accepts. */
enum tag_types { record_type, class_type, union_type, enum_type,
signature_type };
@ -2511,6 +2542,42 @@ extern tree current_scope PROTO((void));
extern tree lookup_conversions PROTO((tree));
extern tree get_template_base PROTO((tree, tree));
/* in semantics.c */
extern void finish_expr_stmt PROTO((tree));
extern tree begin_if_stmt PROTO((void));
extern void finish_if_stmt_cond PROTO((tree, tree));
extern tree finish_then_clause PROTO((tree));
extern void begin_else_clause PROTO((void));
extern void finish_else_clause PROTO((tree));
extern void finish_if_stmt PROTO((void));
extern tree begin_while_stmt PROTO((void));
extern void finish_while_stmt_cond PROTO((tree, tree));
extern void finish_while_stmt PROTO((tree));
extern tree begin_do_stmt PROTO((void));
extern void finish_do_body PROTO((tree));
extern void finish_do_stmt PROTO((tree, tree));
extern void finish_return_stmt PROTO((tree));
extern tree begin_for_stmt PROTO((void));
extern void finish_for_init_stmt PROTO((tree));
extern void finish_for_cond PROTO((tree, tree));
extern void finish_for_expression PROTO((tree, tree));
extern void finish_for_stmt PROTO((tree, tree));
extern void finish_break_stmt PROTO((void));
extern void finish_continue_stmt PROTO((void));
extern void begin_switch_stmt PROTO((void));
extern tree finish_switch_cond PROTO((tree));
extern void finish_switch_stmt PROTO((tree, tree));
extern void finish_case_label PROTO((tree, tree));
extern void finish_goto_stmt PROTO((tree));
extern tree begin_try_block PROTO((void));
extern void finish_try_block PROTO((tree));
extern void finish_handler_sequence PROTO((tree));
extern tree begin_handler PROTO((void));
extern void finish_handler_parms PROTO((tree));
extern void finish_handler PROTO((tree));
extern tree begin_compound_stmt PROTO((int));
extern tree finish_compound_stmt PROTO((int, tree));
extern void finish_asm_stmt PROTO((tree, tree, tree, tree, tree));
/* in sig.c */
extern tree build_signature_pointer_type PROTO((tree, int, int));
extern tree build_signature_reference_type PROTO((tree, int, int));

File diff suppressed because it is too large Load Diff

View File

@ -263,7 +263,7 @@ empty_parms ()
%type <ttype> complete_type_name notype_identifier nonnested_type
%type <ttype> complex_type_name nested_name_specifier_1
%type <ttype> new_initializer new_placement
%type <ttype> using_decl .poplevel
%type <ttype> using_decl
%type <ttype> typename_sub typename_sub0 typename_sub1 typename_sub2
%type <ttype> explicit_template_type
/* in order to recognize aggr tags as defining and thus shadowing. */
@ -1002,7 +1002,7 @@ paren_expr_or_null:
cond_stmt_keyword);
$$ = integer_zero_node; }
| '(' expr ')'
{ $$ = condition_conversion ($2); }
{ $$ = $2; }
;
paren_cond_or_null:
@ -1011,7 +1011,7 @@ paren_cond_or_null:
cond_stmt_keyword);
$$ = integer_zero_node; }
| '(' condition ')'
{ $$ = condition_conversion ($2); }
{ $$ = $2; }
;
xcond:
@ -1062,24 +1062,9 @@ compstmtend:
already_scoped_stmt:
'{'
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (COMPOUND_STMT, NULL_TREE);
COMPOUND_STMT_NO_SCOPE ($<ttype>$) = 1;
add_tree ($<ttype>$);
}
}
{ $<ttype>$ = begin_compound_stmt (1); }
compstmtend
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 0) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
finish_stmt ();
}
{ finish_compound_stmt (1, $<ttype>2); }
| simple_stmt
;
@ -3437,20 +3422,6 @@ errstmt:
error ';'
;
/* build the LET_STMT node before parsing its contents,
so that any LET_STMTs within the context can have their display pointers
set up to point at this one. */
.pushlevel:
/* empty */
{ do_pushlevel (); }
;
.poplevel:
/* empty */
{ $$ = do_poplevel (); }
;
/* Read zero or more forward-declarations for labels
that nested functions can jump to. */
maybe_label_decls:
@ -3487,92 +3458,33 @@ compstmt_or_error:
compstmt:
'{'
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (COMPOUND_STMT, NULL_TREE);
add_tree ($<ttype>$);
}
}
.pushlevel compstmtend .poplevel
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 0) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
$$ = $5;
}
{ $<ttype>$ = begin_compound_stmt (0); }
compstmtend
{ $$ = finish_compound_stmt (0, $<ttype>2); }
;
simple_if:
IF
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE,
NULL_TREE);
add_tree ($<ttype>$);
}
$<ttype>$ = begin_if_stmt ();
cond_stmt_keyword = "if";
}
.pushlevel paren_cond_or_null
{
if (processing_template_decl)
{
if (last_tree != $<ttype>2)
{
TREE_OPERAND ($<ttype>2, 0) = last_tree;
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
TREE_OPERAND ($<ttype>2, 0) = $4;
}
else
{
emit_line_note (input_filename, lineno);
expand_start_cond ($4, 0);
}
}
paren_cond_or_null
{ finish_if_stmt_cond ($3, $<ttype>2); }
implicitly_scoped_stmt
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 1) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
$<ttype>$ = last_tree = $<ttype>2;
}
}
{ $<ttype>$ = finish_then_clause ($<ttype>2); }
;
implicitly_scoped_stmt:
compstmt
{ finish_stmt (); }
| .pushlevel
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (COMPOUND_STMT, NULL_TREE);
add_tree ($<ttype>$);
}
}
simple_stmt .poplevel
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 0) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
$$ = $4;
}
| { $<ttype>$ = begin_compound_stmt (0); }
simple_stmt
{ $$ = finish_compound_stmt (0, $<ttype>1); }
;
stmt:
compstmt
{ finish_stmt (); }
{}
| simple_stmt
;
@ -3580,346 +3492,93 @@ simple_stmt:
decl
{ finish_stmt (); }
| expr ';'
{
tree expr = $1;
if (! processing_template_decl)
{
emit_line_note (input_filename, lineno);
/* Do default conversion if safe and possibly important,
in case within ({...}). */
if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& lvalue_p (expr))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr);
}
cplus_expand_expr_stmt (expr);
clear_momentary ();
finish_stmt (); }
{ finish_expr_stmt ($1); }
| simple_if ELSE
{ if (! processing_template_decl) expand_start_else (); }
{ begin_else_clause (); }
implicitly_scoped_stmt
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>1, 2) = TREE_CHAIN ($<ttype>1);
TREE_CHAIN ($<ttype>1) = NULL_TREE;
last_tree = $<ttype>1;
finish_else_clause ($<ttype>1);
finish_if_stmt ();
}
else
expand_end_cond ();
}
.poplevel
{ finish_stmt (); }
| simple_if %prec IF
{ if (! processing_template_decl) expand_end_cond ();
do_poplevel ();
finish_stmt (); }
{ finish_if_stmt (); }
| WHILE
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (WHILE_STMT, NULL_TREE, NULL_TREE);
add_tree ($<ttype>$);
}
else
{
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop (1);
}
$<ttype>$ = begin_while_stmt ();
cond_stmt_keyword = "while";
}
.pushlevel paren_cond_or_null
{
if (processing_template_decl)
{
if (last_tree != $<ttype>2)
{
TREE_OPERAND ($<ttype>2, 0) = last_tree;
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
TREE_OPERAND ($<ttype>2, 0) = $4;
}
else
{
emit_line_note (input_filename, lineno);
expand_exit_loop_if_false (0, $4);
}
/* If the condition wasn't a declaration, clear out the
block we made for it and start a new one here so the
optimization in expand_end_loop will work. */
if (getdecls () == NULL_TREE)
{
do_poplevel ();
do_pushlevel ();
}
}
already_scoped_stmt .poplevel
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 1) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
expand_end_loop ();
finish_stmt ();
}
paren_cond_or_null
{ finish_while_stmt_cond ($3, $<ttype>2); }
already_scoped_stmt
{ finish_while_stmt ($<ttype>2); }
| DO
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (DO_STMT, NULL_TREE, NULL_TREE);
add_tree ($<ttype>$);
}
else
{
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1);
}
}
{ $<ttype>$ = begin_do_stmt (); }
implicitly_scoped_stmt WHILE
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 0) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
{
expand_loop_continue_here ();
finish_do_body ($<ttype>2);
cond_stmt_keyword = "do";
}
}
paren_expr_or_null ';'
{
if (processing_template_decl)
TREE_OPERAND ($<ttype>2, 1) = $6;
else
{
emit_line_note (input_filename, lineno);
expand_exit_loop_if_false (0, $6);
expand_end_loop ();
}
clear_momentary ();
finish_stmt ();
}
{ finish_do_stmt ($6, $<ttype>2); }
| FOR
{ if (processing_template_decl)
{
$<ttype>$ = build_min_nt (FOR_STMT, NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE);
add_tree ($<ttype>$);
}
else
emit_line_note (input_filename, lineno);
if (flag_new_for_scope > 0)
{
/* Conditionalize .pushlevel */
pushlevel (0);
note_level_for_for ();
clear_last_expr ();
push_momentary ();
expand_start_bindings (0);
}
}
{ $<ttype>$ = begin_for_stmt (); }
'(' for.init.statement
{
if (processing_template_decl)
{
if (last_tree != $<ttype>2)
{
TREE_OPERAND ($<ttype>2, 0) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
}
else
{
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1);
}
}
.pushlevel xcond ';'
{
if (processing_template_decl)
{
if (last_tree != $<ttype>2)
{
TREE_OPERAND ($<ttype>2, 1) = last_tree;
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
TREE_OPERAND ($<ttype>2, 1) = $7;
}
else
{
emit_line_note (input_filename, lineno);
if ($7) expand_exit_loop_if_false (0, $7);
}
/* If the condition wasn't a declaration, clear out the
block we made for it and start a new one here so the
optimization in expand_end_loop will work. */
if (getdecls () == NULL_TREE)
{
do_poplevel ();
do_pushlevel ();
}
}
{ finish_for_init_stmt ($<ttype>2); }
xcond ';'
{ finish_for_cond ($6, $<ttype>2); }
xexpr ')'
/* Don't let the tree nodes for $10 be discarded
by clear_momentary during the parsing of the next stmt. */
{
if (processing_template_decl)
TREE_OPERAND ($<ttype>2, 2) = $10;
push_momentary ();
}
already_scoped_stmt .poplevel
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 3) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
{
emit_line_note (input_filename, lineno);
expand_loop_continue_here ();
if ($10) cplus_expand_expr_stmt ($10);
expand_end_loop ();
}
pop_momentary ();
if (flag_new_for_scope > 0)
{
do_poplevel ();
}
finish_stmt (); }
| SWITCH .pushlevel '(' condition ')'
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (SWITCH_STMT, $4, NULL_TREE);
add_tree ($<ttype>$);
}
else
{
emit_line_note (input_filename, lineno);
c_expand_start_case ($4);
}
push_switch ();
/* Don't let the tree nodes for $4 be discarded by
clear_momentary during the parsing of the next stmt. */
push_momentary ();
}
{ finish_for_expr ($9, $<ttype>2); }
already_scoped_stmt
{ finish_for_stmt ($9, $<ttype>2); }
| SWITCH
{ begin_switch_stmt (); }
'(' condition ')'
{ $<ttype>$ = finish_switch_cond ($4); }
implicitly_scoped_stmt
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>6, 1) = TREE_CHAIN ($<ttype>6);
TREE_CHAIN ($<ttype>6) = NULL_TREE;
last_tree = $<ttype>6;
}
else
expand_end_case ($4);
pop_momentary ();
pop_switch ();
}
.poplevel
{ finish_stmt (); }
{ finish_switch_stmt ($4, $<ttype>6); }
| CASE expr_no_commas ':'
{ do_case ($2, NULL_TREE); }
{ finish_case_label ($2, NULL_TREE); }
stmt
| CASE expr_no_commas ELLIPSIS expr_no_commas ':'
{ do_case ($2, $4); }
{ finish_case_label ($2, $4); }
stmt
| DEFAULT ':'
{ do_case (NULL_TREE, NULL_TREE); }
{ finish_case_label (NULL_TREE, NULL_TREE); }
stmt
| BREAK ';'
{ emit_line_note (input_filename, lineno);
if (processing_template_decl)
add_tree (build_min_nt (BREAK_STMT));
else if ( ! expand_exit_something ())
error ("break statement not within loop or switch"); }
{ finish_break_stmt (); }
| CONTINUE ';'
{ emit_line_note (input_filename, lineno);
if (processing_template_decl)
add_tree (build_min_nt (CONTINUE_STMT));
else if (! expand_continue_loop (0))
error ("continue statement not within a loop"); }
{ finish_continue_stmt (); }
| RETURN ';'
{ emit_line_note (input_filename, lineno);
c_expand_return (NULL_TREE); }
{ finish_return_stmt (NULL_TREE); }
| RETURN expr ';'
{ emit_line_note (input_filename, lineno);
c_expand_return ($2);
finish_stmt ();
}
{ finish_return_stmt ($2); }
| asm_keyword maybe_cv_qualifier '(' string ')' ';'
{ if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
emit_line_note (input_filename, lineno);
expand_asm ($4);
finish_stmt ();
{
finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE,
NULL_TREE);
}
/* This is the case with just output operands. */
| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ')' ';'
{ if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
emit_line_note (input_filename, lineno);
c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
$2 == ridpointers[(int)RID_VOLATILE],
input_filename, lineno);
finish_stmt ();
{
finish_asm_stmt ($2, $4, $6, NULL_TREE,
NULL_TREE);
}
/* This is the case with input operands as well. */
| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':' asm_operands ')' ';'
{ if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
emit_line_note (input_filename, lineno);
c_expand_asm_operands ($4, $6, $8, NULL_TREE,
$2 == ridpointers[(int)RID_VOLATILE],
input_filename, lineno);
finish_stmt ();
}
{ finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
/* This is the case with clobbered registers as well. */
| asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
asm_operands ':' asm_clobbers ')' ';'
{ if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
emit_line_note (input_filename, lineno);
c_expand_asm_operands ($4, $6, $8, $10,
$2 == ridpointers[(int)RID_VOLATILE],
input_filename, lineno);
finish_stmt ();
}
{ finish_asm_stmt ($2, $4, $6, $8, $10); }
| GOTO '*' expr ';'
{
if (processing_template_decl)
add_tree (build_min_nt (GOTO_STMT, $3));
else
{ emit_line_note (input_filename, lineno);
expand_computed_goto ($3); }
if (pedantic)
pedwarn ("ANSI C++ forbids computed gotos");
finish_goto_stmt ($3);
}
| GOTO identifier ';'
{
if (processing_template_decl)
add_tree (build_min_nt (GOTO_STMT, $2));
else
{
tree decl;
emit_line_note (input_filename, lineno);
decl = lookup_label ($2);
TREE_USED (decl) = 1;
expand_goto (decl);
}
}
{ finish_goto_stmt ($2); }
| label_colon stmt
{ finish_stmt (); }
| label_colon '}'
@ -3951,41 +3610,11 @@ function_try_block:
try_block:
TRY
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (TRY_BLOCK, NULL_TREE,
NULL_TREE);
add_tree ($<ttype>$);
}
else
{
emit_line_note (input_filename, lineno);
expand_start_try_stmts ();
}
}
{ $<ttype>$ = begin_try_block (); }
compstmt
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 0) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
expand_start_all_catch ();
}
{ finish_try_block ($<ttype>2); }
handler_seq
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 1) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
expand_end_all_catch ();
}
{ finish_handler_sequence ($<ttype>2); }
;
handler_seq:
@ -3995,35 +3624,11 @@ handler_seq:
handler:
CATCH
{
if (processing_template_decl)
{
$<ttype>$ = build_min_nt (HANDLER, NULL_TREE,
NULL_TREE);
add_tree ($<ttype>$);
}
}
.pushlevel handler_args
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 0) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
}
{ $<ttype>$ = begin_handler(); }
handler_args
{ finish_handler_parms ($<ttype>2); }
compstmt
{
if (processing_template_decl)
{
TREE_OPERAND ($<ttype>2, 1) = TREE_CHAIN ($<ttype>2);
TREE_CHAIN ($<ttype>2) = NULL_TREE;
last_tree = $<ttype>2;
}
else
expand_end_catch_block ();
}
.poplevel
{ finish_handler ($<ttype>2); }
;
type_specifier_seq:

View File

@ -4690,24 +4690,14 @@ tsubst_expr (t, args, in_decl)
{
case RETURN_STMT:
lineno = TREE_COMPLEXITY (t);
emit_line_note (input_filename, lineno);
c_expand_return
(tsubst_expr (TREE_OPERAND (t, 0), args, in_decl));
finish_stmt ();
finish_return_stmt (tsubst_expr (RETURN_EXPR (t),
args, in_decl));
break;
case EXPR_STMT:
lineno = TREE_COMPLEXITY (t);
emit_line_note (input_filename, lineno);
t = tsubst_expr (TREE_OPERAND (t, 0), args, in_decl);
/* Do default conversion if safe and possibly important,
in case within ({...}). */
if ((TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE && lvalue_p (t))
|| TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
t = default_conversion (t);
cplus_expand_expr_stmt (t);
clear_momentary ();
finish_stmt ();
finish_expr_stmt (tsubst_expr (EXPR_STMT_EXPR (t),
args, in_decl));
break;
case DECL_STMT:
@ -4731,184 +4721,117 @@ tsubst_expr (t, args, in_decl)
case FOR_STMT:
{
tree tmp;
int init_scope = (flag_new_for_scope > 0 && TREE_OPERAND (t, 0)
&& TREE_CODE (TREE_OPERAND (t, 0)) == DECL_STMT);
int cond_scope = (TREE_OPERAND (t, 1)
&& TREE_CODE (TREE_OPERAND (t, 1)) == DECL_STMT);
lineno = TREE_COMPLEXITY (t);
emit_line_note (input_filename, lineno);
if (init_scope)
do_pushlevel ();
for (tmp = TREE_OPERAND (t, 0); tmp; tmp = TREE_CHAIN (tmp))
begin_for_stmt ();
for (tmp = FOR_INIT_STMT (t); tmp; tmp = TREE_CHAIN (tmp))
tsubst_expr (tmp, args, in_decl);
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1);
if (cond_scope)
do_pushlevel ();
tmp = tsubst_expr (TREE_OPERAND (t, 1), args, in_decl);
emit_line_note (input_filename, lineno);
if (tmp)
expand_exit_loop_if_false (0, condition_conversion (tmp));
if (! cond_scope)
do_pushlevel ();
tsubst_expr (TREE_OPERAND (t, 3), args, in_decl);
do_poplevel ();
emit_line_note (input_filename, lineno);
expand_loop_continue_here ();
tmp = tsubst_expr (TREE_OPERAND (t, 2), args, in_decl);
if (tmp)
cplus_expand_expr_stmt (tmp);
expand_end_loop ();
if (init_scope)
do_poplevel ();
finish_stmt ();
finish_for_init_stmt (NULL_TREE);
finish_for_cond (tsubst_expr (FOR_COND (t), args,
in_decl),
NULL_TREE);
tmp = tsubst_expr (FOR_EXPR (t), args, in_decl);
finish_for_expr (tmp, NULL_TREE);
tsubst_expr (FOR_BODY (t), args, in_decl);
finish_for_stmt (tmp, NULL_TREE);
}
break;
case WHILE_STMT:
{
tree cond;
lineno = TREE_COMPLEXITY (t);
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop (1);
cond = TREE_OPERAND (t, 0);
if (TREE_CODE (cond) == DECL_STMT)
do_pushlevel ();
cond = tsubst_expr (cond, args, in_decl);
emit_line_note (input_filename, lineno);
expand_exit_loop_if_false (0, condition_conversion (cond));
if (TREE_CODE (TREE_OPERAND (t, 0)) != DECL_STMT)
do_pushlevel ();
tsubst_expr (TREE_OPERAND (t, 1), args, in_decl);
do_poplevel ();
expand_end_loop ();
finish_stmt ();
begin_while_stmt ();
finish_while_stmt_cond (tsubst_expr (WHILE_COND (t),
args, in_decl),
NULL_TREE);
tsubst_expr (WHILE_BODY (t), args, in_decl);
finish_while_stmt (NULL_TREE);
}
break;
case DO_STMT:
{
tree cond;
lineno = TREE_COMPLEXITY (t);
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1);
tsubst_expr (TREE_OPERAND (t, 0), args, in_decl);
expand_loop_continue_here ();
cond = tsubst_expr (TREE_OPERAND (t, 1), args, in_decl);
emit_line_note (input_filename, lineno);
expand_exit_loop_if_false (0, condition_conversion (cond));
expand_end_loop ();
clear_momentary ();
finish_stmt ();
begin_do_stmt ();
tsubst_expr (DO_BODY (t), args, in_decl);
finish_do_body (NULL_TREE);
finish_do_stmt (tsubst_expr (DO_COND (t), args,
in_decl),
NULL_TREE);
}
break;
case IF_STMT:
{
tree tmp;
int cond_scope = (TREE_CODE (TREE_OPERAND (t, 0)) == DECL_STMT);
lineno = TREE_COMPLEXITY (t);
if (cond_scope)
do_pushlevel ();
tmp = tsubst_expr (TREE_OPERAND (t, 0), args, in_decl);
emit_line_note (input_filename, lineno);
expand_start_cond (condition_conversion (tmp), 0);
begin_if_stmt ();
finish_if_stmt_cond (tsubst_expr (IF_COND (t),
args, in_decl),
NULL_TREE);
if (tmp = TREE_OPERAND (t, 1), tmp)
tsubst_expr (tmp, args, in_decl);
if (tmp = TREE_OPERAND (t, 2), tmp)
if (tmp = THEN_CLAUSE (t), tmp)
{
expand_start_else ();
tsubst_expr (tmp, args, in_decl);
finish_then_clause (NULL_TREE);
}
expand_end_cond ();
if (tmp = ELSE_CLAUSE (t), tmp)
{
begin_else_clause ();
tsubst_expr (tmp, args, in_decl);
finish_else_clause (NULL_TREE);
}
if (cond_scope)
do_poplevel ();
finish_stmt ();
finish_if_stmt ();
}
break;
case COMPOUND_STMT:
{
tree substmt = TREE_OPERAND (t, 0);
tree substmt;
lineno = TREE_COMPLEXITY (t);
if (COMPOUND_STMT_NO_SCOPE (t) == 0)
do_pushlevel ();
for (; substmt; substmt = TREE_CHAIN (substmt))
begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
for (substmt = COMPOUND_BODY (t);
substmt != NULL_TREE;
substmt = TREE_CHAIN (substmt))
tsubst_expr (substmt, args, in_decl);
if (COMPOUND_STMT_NO_SCOPE (t) == 0)
return do_poplevel ();
return finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t),
NULL_TREE);
}
break;
case BREAK_STMT:
lineno = TREE_COMPLEXITY (t);
emit_line_note (input_filename, lineno);
if (! expand_exit_something ())
error ("break statement not within loop or switch");
finish_break_stmt ();
break;
case CONTINUE_STMT:
lineno = TREE_COMPLEXITY (t);
emit_line_note (input_filename, lineno);
if (! expand_continue_loop (0))
error ("continue statement not within a loop");
finish_continue_stmt ();
break;
case SWITCH_STMT:
{
tree val, tmp;
int cond_scope = (TREE_CODE (TREE_OPERAND (t, 0)) == DECL_STMT);
lineno = TREE_COMPLEXITY (t);
if (cond_scope)
do_pushlevel ();
val = tsubst_expr (TREE_OPERAND (t, 0), args, in_decl);
emit_line_note (input_filename, lineno);
c_expand_start_case (val);
push_switch ();
begin_switch_stmt ();
val = tsubst_expr (SWITCH_COND (t), args, in_decl);
finish_switch_cond (val);
if (tmp = TREE_OPERAND (t, 1), tmp)
tsubst_expr (tmp, args, in_decl);
expand_end_case (val);
pop_switch ();
if (cond_scope)
do_poplevel ();
finish_stmt ();
finish_switch_stmt (val, NULL_TREE);
}
break;
case CASE_LABEL:
do_case (tsubst_expr (TREE_OPERAND (t, 0), args, in_decl),
tsubst_expr (TREE_OPERAND (t, 1), args, in_decl));
finish_case_label (tsubst_expr (CASE_LOW (t), args, in_decl),
tsubst_expr (CASE_HIGH (t), args, in_decl));
break;
case LABEL_DECL:
@ -4920,47 +4843,47 @@ tsubst_expr (t, args, in_decl)
case GOTO_STMT:
lineno = TREE_COMPLEXITY (t);
emit_line_note (input_filename, lineno);
if (TREE_CODE (TREE_OPERAND (t, 0)) == IDENTIFIER_NODE)
{
tree decl = lookup_label (TREE_OPERAND (t, 0));
TREE_USED (decl) = 1;
expand_goto (decl);
}
else
expand_computed_goto
(tsubst_expr (TREE_OPERAND (t, 0), args, in_decl));
finish_goto_stmt (tsubst_expr (GOTO_DESTINATION (t),
args, in_decl));
break;
case ASM_STMT:
lineno = TREE_COMPLEXITY (t);
finish_asm_stmt (tsubst_expr (ASM_CV_QUAL (t), args, in_decl),
tsubst_expr (ASM_STRING (t), args, in_decl),
tsubst_expr (ASM_OUTPUTS (t), args, in_decl),
tsubst_expr (ASM_INPUTS (t), args, in_decl),
tsubst_expr (ASM_CLOBBERS (t), args, in_decl));
break;
case TRY_BLOCK:
lineno = TREE_COMPLEXITY (t);
emit_line_note (input_filename, lineno);
expand_start_try_stmts ();
tsubst_expr (TREE_OPERAND (t, 0), args, in_decl);
expand_start_all_catch ();
begin_try_block ();
tsubst_expr (TRY_STMTS (t), args, in_decl);
finish_try_block (NULL_TREE);
{
tree handler = TREE_OPERAND (t, 1);
tree handler = TRY_HANDLERS (t);
for (; handler; handler = TREE_CHAIN (handler))
tsubst_expr (handler, args, in_decl);
}
expand_end_all_catch ();
finish_handler_sequence (NULL_TREE);
break;
case HANDLER:
lineno = TREE_COMPLEXITY (t);
do_pushlevel ();
if (TREE_OPERAND (t, 0))
begin_handler ();
if (HANDLER_PARMS (t))
{
tree d = TREE_OPERAND (t, 0);
tree d = HANDLER_PARMS (t);
expand_start_catch_block
(tsubst (TREE_OPERAND (d, 1), args, in_decl),
tsubst (TREE_OPERAND (d, 0), args, in_decl));
}
else
expand_start_catch_block (NULL_TREE, NULL_TREE);
tsubst_expr (TREE_OPERAND (t, 1), args, in_decl);
expand_end_catch_block ();
do_poplevel ();
finish_handler_parms (NULL_TREE);
tsubst_expr (HANDLER_BODY (t), args, in_decl);
finish_handler (NULL_TREE);
break;
case TAG_DEFN:

748
gcc/cp/semantics.c Normal file
View File

@ -0,0 +1,748 @@
/* Perform the semantic phase of parsing, i.e., the process of
building tree structure, checking semantic consistency, and
building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
Copyright (C) 1998 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
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 2, 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, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "config.h"
#include <stdio.h>
#include "tree.h"
#include "cp-tree.h"
#include "except.h"
#include "lex.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
during template instantiation, which may be regarded as a
degenerate form of parsing. Since the current g++ parser is
lacking in several respects, and will be reimplemented, we are
attempting to move most code that is not directly related to
parsing into this file; that will make implementing the new parser
much easier since it will be able to make use of these routines. */
/* When parsing a template, LAST_TREE contains the last statement
parsed. These are chained together through the TREE_CHAIN field,
but often need to be re-organized since the parse is performed
bottom-up. This macro makes LAST_TREE the indicated SUBSTMT of
STMT. */
#define RECHAIN_STMTS(stmt, substmt, last) \
do { \
substmt = last; \
TREE_CHAIN (stmt) = NULL_TREE; \
last_tree = stmt; \
} while (0)
#define RECHAIN_STMTS_FROM_LAST(stmt, substmt) \
RECHAIN_STMTS (stmt, substmt, last_tree)
#define RECHAIN_STMTS_FROM_CHAIN(stmt, substmt) \
RECHAIN_STMTS (stmt, substmt, TREE_CHAIN (stmt))
/* Finish an expression-statement, whose EXPRESSION is as indicated. */
void
finish_expr_stmt (expr)
tree expr;
{
if (!processing_template_decl)
{
emit_line_note (input_filename, lineno);
/* Do default conversion if safe and possibly important,
in case within ({...}). */
if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& lvalue_p (expr))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr);
}
cplus_expand_expr_stmt (expr);
clear_momentary ();
finish_stmt ();
}
/* Begin an if-statement. Returns a newly created IF_STMT if
appropriate. */
tree
begin_if_stmt ()
{
tree r;
if (processing_template_decl)
{
r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
add_tree (r);
}
else
r = NULL_TREE;
do_pushlevel ();
return r;
}
/* Process the COND of an if-statement, which may be given by
IF_STMT. */
void
finish_if_stmt_cond (cond, if_stmt)
tree cond;
tree if_stmt;
{
if (processing_template_decl)
{
if (last_tree != if_stmt)
RECHAIN_STMTS_FROM_LAST (if_stmt, IF_COND (if_stmt));
else
IF_COND (if_stmt) = cond;
}
else
{
emit_line_note (input_filename, lineno);
expand_start_cond (condition_conversion (cond), 0);
}
}
/* Finish the then-clause of an if-statement, which may be given by
IF_STMT. */
tree
finish_then_clause (if_stmt)
tree if_stmt;
{
if (processing_template_decl)
{
RECHAIN_STMTS_FROM_CHAIN (if_stmt,
THEN_CLAUSE (if_stmt));
last_tree = if_stmt;
return if_stmt;
}
else
return NULL_TREE;
}
/* Begin the else-clause of an if-statement. */
void
begin_else_clause ()
{
if (!processing_template_decl)
expand_start_else ();
}
/* Finish the else-clause of an if-statement, which may be given by
IF_STMT. */
void
finish_else_clause (if_stmt)
tree if_stmt;
{
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (if_stmt, ELSE_CLAUSE (if_stmt));
}
/* Finsh an if-statement. */
void
finish_if_stmt ()
{
if (!processing_template_decl)
expand_end_cond ();
do_poplevel ();
finish_stmt ();
}
/* Begin a while-statement. Returns a newly created WHILE_STMT if
appropriate. */
tree
begin_while_stmt ()
{
tree r;
if (processing_template_decl)
{
r = build_min_nt (WHILE_STMT, NULL_TREE, NULL_TREE);
add_tree (r);
}
else
{
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop (1);
r = NULL_TREE;
}
do_pushlevel ();
return r;
}
/* Process the COND of an if-statement, which may be given by
WHILE_STMT. */
void
finish_while_stmt_cond (cond, while_stmt)
tree cond;
tree while_stmt;
{
if (processing_template_decl)
{
if (last_tree != while_stmt)
RECHAIN_STMTS_FROM_LAST (while_stmt,
WHILE_COND (while_stmt));
else
TREE_OPERAND (while_stmt, 0) = cond;
}
else
{
emit_line_note (input_filename, lineno);
expand_exit_loop_if_false (0, condition_conversion (cond));
}
/* If COND wasn't a declaration, clear out the
block we made for it and start a new one here so the
optimization in expand_end_loop will work. */
if (getdecls () == NULL_TREE)
{
do_poplevel ();
do_pushlevel ();
}
}
/* Finish a while-statement, which may be given by WHILE_STMT. */
void
finish_while_stmt (while_stmt)
tree while_stmt;
{
do_poplevel ();
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (while_stmt, WHILE_BODY (while_stmt));
else
expand_end_loop ();
finish_stmt ();
}
/* Begin a do-statement. Returns a newly created DO_STMT if
appropriate. */
tree
begin_do_stmt ()
{
if (processing_template_decl)
{
tree r = build_min_nt (DO_STMT, NULL_TREE, NULL_TREE);
add_tree (r);
return r;
}
else
{
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1);
return NULL_TREE;
}
}
/* Finish the body of a do-statement, which may be given by DO_STMT. */
void
finish_do_body (do_stmt)
tree do_stmt;
{
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (do_stmt, DO_BODY (do_stmt));
else
expand_loop_continue_here ();
}
/* Finish a do-statement, which may be given by DO_STMT, and whose
COND is as indicated. */
void
finish_do_stmt (cond, do_stmt)
tree cond;
tree do_stmt;
{
if (processing_template_decl)
DO_COND (do_stmt) = cond;
else
{
emit_line_note (input_filename, lineno);
expand_exit_loop_if_false (0, condition_conversion (cond));
expand_end_loop ();
}
clear_momentary ();
finish_stmt ();
}
/* Finish a return-statement. The EXPRESSION returned, if any, is as
indicated. */
void
finish_return_stmt (expr)
tree expr;
{
emit_line_note (input_filename, lineno);
c_expand_return (expr);
finish_stmt ();
}
/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */
tree
begin_for_stmt ()
{
tree r;
if (processing_template_decl)
{
r = build_min_nt (FOR_STMT, NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE);
add_tree (r);
}
else
r = NULL_TREE;
if (flag_new_for_scope > 0)
{
do_pushlevel ();
note_level_for_for ();
}
return r;
}
/* Finish the for-init-statement of a for-statement, which may be
given by FOR_STMT. */
void
finish_for_init_stmt (for_stmt)
tree for_stmt;
{
if (processing_template_decl)
{
if (last_tree != for_stmt)
RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_INIT_STMT (for_stmt));
}
else
{
emit_nop ();
emit_line_note (input_filename, lineno);
expand_start_loop_continue_elsewhere (1);
}
do_pushlevel ();
}
/* Finish the COND of a for-statement, which may be given by
FOR_STMT. */
void
finish_for_cond (cond, for_stmt)
tree cond;
tree for_stmt;
{
if (processing_template_decl)
{
if (last_tree != for_stmt)
RECHAIN_STMTS_FROM_LAST (for_stmt, FOR_COND (for_stmt));
else
FOR_COND (for_stmt) = cond;
}
else
{
emit_line_note (input_filename, lineno);
if (cond)
expand_exit_loop_if_false (0, cond);
}
/* If the cond wasn't a declaration, clear out the
block we made for it and start a new one here so the
optimization in expand_end_loop will work. */
if (getdecls () == NULL_TREE)
{
do_poplevel ();
do_pushlevel ();
}
}
/* Finish the increment-EXPRESSION in a for-statement, which may be
given by FOR_STMT. */
void
finish_for_expr (expr, for_stmt)
tree expr;
tree for_stmt;
{
if (processing_template_decl)
FOR_EXPR (for_stmt) = expr;
/* Don't let the tree nodes for EXPR be discarded
by clear_momentary during the parsing of the next stmt. */
push_momentary ();
}
/* Finish the body of a for-statement, which may be given by
FOR_STMT. The increment-EXPR for the loop must be
provided. */
void
finish_for_stmt (expr, for_stmt)
tree expr;
tree for_stmt;
{
/* Pop the scope for the body of the loop. */
do_poplevel ();
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_BODY (for_stmt));
else
{
emit_line_note (input_filename, lineno);
expand_loop_continue_here ();
if (expr)
cplus_expand_expr_stmt (expr);
expand_end_loop ();
}
pop_momentary ();
if (flag_new_for_scope > 0)
do_poplevel ();
finish_stmt ();
}
/* Finish a break-statement. */
void
finish_break_stmt ()
{
emit_line_note (input_filename, lineno);
if (processing_template_decl)
add_tree (build_min_nt (BREAK_STMT));
else if ( ! expand_exit_something ())
cp_error ("break statement not within loop or switch");
}
/* Finish a continue-statement. */
void
finish_continue_stmt ()
{
emit_line_note (input_filename, lineno);
if (processing_template_decl)
add_tree (build_min_nt (CONTINUE_STMT));
else if (! expand_continue_loop (0))
cp_error ("continue statement not within a loop");
}
/* Begin a switch-statement. */
void
begin_switch_stmt ()
{
do_pushlevel ();
}
/* Finish the cond of a switch-statement. Returns a new
SWITCH_STMT if appropriate. */
tree
finish_switch_cond (cond)
tree cond;
{
tree r;
if (processing_template_decl)
{
r = build_min_nt (SWITCH_STMT, cond, NULL_TREE);
add_tree (r);
}
else
{
emit_line_note (input_filename, lineno);
c_expand_start_case (cond);
r = NULL_TREE;
}
push_switch ();
/* Don't let the tree nodes for COND be discarded by
clear_momentary during the parsing of the next stmt. */
push_momentary ();
return r;
}
/* Finish the body of a switch-statement, which may be given by
SWITCH_STMT. The COND to switch on is indicated. */
void
finish_switch_stmt (cond, switch_stmt)
tree cond;
tree switch_stmt;
{
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (switch_stmt, SWITCH_BODY (switch_stmt));
else
expand_end_case (cond);
pop_momentary ();
pop_switch ();
do_poplevel ();
finish_stmt ();
}
/* Finish a case-label. */
void
finish_case_label (low_value, high_value)
tree low_value;
tree high_value;
{
do_case (low_value, high_value);
}
/* Finish a goto-statement. */
void
finish_goto_stmt (destination)
tree destination;
{
if (processing_template_decl)
add_tree (build_min_nt (GOTO_STMT, destination));
else
{
emit_line_note (input_filename, lineno);
if (TREE_CODE (destination) == IDENTIFIER_NODE)
{
tree decl = lookup_label (destination);
TREE_USED (decl) = 1;
expand_goto (decl);
}
else
expand_computed_goto (destination);
}
}
/* Begin a try-block. Returns a newly-created TRY_BLOCK if
appropriate. */
tree
begin_try_block ()
{
if (processing_template_decl)
{
tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
NULL_TREE);
add_tree (r);
return r;
}
else
{
emit_line_note (input_filename, lineno);
expand_start_try_stmts ();
return NULL_TREE;
}
}
/* Finish a try-block, which may be given by TRY_BLOCK. */
void
finish_try_block (try_block)
tree try_block;
{
if (processing_template_decl)
RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
else
expand_start_all_catch ();
}
/* Finish a handler-sequence for a try-block, which may be given by
TRY_BLOCK. */
void
finish_handler_sequence (try_block)
tree try_block;
{
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
else
expand_end_all_catch ();
}
/* Begin a handler. Returns a HANDLER if appropriate. */
tree
begin_handler ()
{
tree r;
if (processing_template_decl)
{
r = build_min_nt (HANDLER, NULL_TREE, NULL_TREE);
add_tree (r);
}
else
r = NULL_TREE;
do_pushlevel ();
return r;
}
/* Finish the handler-parameters for a handler, which may be given by
HANDLER. */
void
finish_handler_parms (handler)
tree handler;
{
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_PARMS (handler));
}
/* Finish a handler, which may be given by HANDLER. */
void
finish_handler (handler)
tree handler;
{
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_BODY (handler));
else
expand_end_catch_block ();
do_poplevel ();
}
/* Begin a compound-statement. If HAS_NO_SCOPE is non-zero, the
compound-statement does not define a scope. Returns a new
COMPOUND_STMT if appropriate. */
tree
begin_compound_stmt (has_no_scope)
int has_no_scope;
{
tree r;
if (processing_template_decl)
{
r = build_min_nt (COMPOUND_STMT, NULL_TREE);
add_tree (r);
if (has_no_scope)
COMPOUND_STMT_NO_SCOPE (r) = 1;
}
else
r = NULL_TREE;
if (!has_no_scope)
do_pushlevel ();
return r;
}
/* Finish a compound-statement, which may be given by COMPOUND_STMT.
If HAS_NO_SCOPE is non-zero, the compound statement does not define
a scope. */
tree
finish_compound_stmt (has_no_scope, compound_stmt)
int has_no_scope;
tree compound_stmt;
{
tree r;
if (!has_no_scope)
r = do_poplevel ();
else
r = NULL_TREE;
if (processing_template_decl)
RECHAIN_STMTS_FROM_CHAIN (compound_stmt,
COMPOUND_BODY (compound_stmt));
finish_stmt ();
return r;
}
/* Finish an asm-statement, whose components are a CV_QUALIFIER, a
STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, and some
CLOBBERS. */
void
finish_asm_stmt (cv_qualifier, string, output_operands,
input_operands, clobbers)
tree cv_qualifier;
tree string;
tree output_operands;
tree input_operands;
tree clobbers;
{
if (TREE_CHAIN (string))
combine_strings (string);
if (processing_template_decl)
{
tree r = build_min_nt (ASM_STMT, cv_qualifier, string,
output_operands, input_operands,
clobbers);
add_tree (r);
}
else
{
emit_line_note (input_filename, lineno);
if (output_operands != NULL_TREE)
{
if (cv_qualifier != NULL_TREE
&& cv_qualifier != ridpointers[(int) RID_VOLATILE])
cp_warning ("%s qualifier ignored on asm",
IDENTIFIER_POINTER (cv_qualifier));
c_expand_asm_operands (string, output_operands,
input_operands,
clobbers,
cv_qualifier
== ridpointers[(int) RID_VOLATILE],
input_filename, lineno);
}
else
{
if (cv_qualifier != NULL_TREE)
cp_warning ("%s qualifier ignored on asm",
IDENTIFIER_POINTER (cv_qualifier));
expand_asm (string);
}
finish_stmt ();
}
}