aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c73
1 files changed, 55 insertions, 18 deletions
diff --git a/parse.c b/parse.c
index c1a72ae2..1ec95228 100644
--- a/parse.c
+++ b/parse.c
@@ -721,12 +721,14 @@ static struct symbol * alloc_indirect_symbol(struct position pos, struct ctype *
* it also ends up using function scope instead of the
* regular symbol scope.
*/
-struct symbol *label_symbol(struct token *token)
+struct symbol *label_symbol(struct token *token, int used)
{
struct symbol *sym = lookup_symbol(token->ident, NS_LABEL);
if (!sym) {
sym = alloc_symbol(token->pos, SYM_LABEL);
bind_symbol(sym, token->ident, NS_LABEL);
+ if (used)
+ sym->used = 1;
fn_local_symbol(sym);
}
return sym;
@@ -2127,7 +2129,7 @@ static struct token *parse_asm_labels(struct token *token, struct statement *stm
token = token->next; /* skip ':' and ',' */
if (token_type(token) != TOKEN_IDENT)
return token;
- label = label_symbol(token);
+ label = label_symbol(token, 1);
add_symbol(labels, label);
token = token->next;
} while (match_op(token, ','));
@@ -2218,7 +2220,7 @@ static void start_iterator(struct statement *stmt)
{
struct symbol *cont, *brk;
- start_symbol_scope();
+ start_block_scope();
cont = alloc_symbol(stmt->pos, SYM_NODE);
bind_symbol(cont, &continue_ident, NS_ITERATOR);
brk = alloc_symbol(stmt->pos, SYM_NODE);
@@ -2233,7 +2235,7 @@ static void start_iterator(struct statement *stmt)
static void end_iterator(struct statement *stmt)
{
- end_symbol_scope();
+ end_block_scope();
}
static struct statement *start_function(struct symbol *sym)
@@ -2278,7 +2280,7 @@ static void start_switch(struct statement *stmt)
{
struct symbol *brk, *switch_case;
- start_symbol_scope();
+ start_block_scope();
brk = alloc_symbol(stmt->pos, SYM_NODE);
bind_symbol(brk, &break_ident, NS_ITERATOR);
@@ -2298,7 +2300,7 @@ static void end_switch(struct statement *stmt)
{
if (!stmt->switch_case->symbol_list)
warning(stmt->pos, "switch with no cases");
- end_symbol_scope();
+ end_block_scope();
}
static void add_case_statement(struct statement *stmt)
@@ -2468,6 +2470,27 @@ static struct token *parse_switch_statement(struct token *token, struct statemen
return token;
}
+static void warn_label_usage(struct position def, struct position use, struct ident *ident)
+{
+ const char *id = show_ident(ident);
+ sparse_error(use, "label '%s' used outside statement expression", id);
+ info(def, " label '%s' defined here", id);
+ current_fn->bogus_linear = 1;
+}
+
+void check_label_usage(struct symbol *label, struct position use_pos)
+{
+ struct statement *def = label->stmt;
+
+ if (def) {
+ if (!is_in_scope(def->label_scope, label_scope))
+ warn_label_usage(def->pos, use_pos, label->ident);
+ } else if (!label->label_scope) {
+ label->label_scope = label_scope;
+ label->label_pos = use_pos;
+ }
+}
+
static struct token *parse_goto_statement(struct token *token, struct statement *stmt)
{
stmt->type = STMT_GOTO;
@@ -2476,7 +2499,9 @@ static struct token *parse_goto_statement(struct token *token, struct statement
token = parse_expression(token->next, &stmt->goto_expression);
add_statement(&function_computed_goto_list, stmt);
} else if (token_type(token) == TOKEN_IDENT) {
- stmt->goto_label = label_symbol(token);
+ struct symbol *label = label_symbol(token, 1);
+ stmt->goto_label = label;
+ check_label_usage(label, stmt->pos);
token = token->next;
} else {
sparse_error(token->pos, "Expected identifier or goto expression");
@@ -2517,6 +2542,15 @@ static struct token *parse_range_statement(struct token *token, struct statement
return expect(token, ';', "after range statement");
}
+static struct token *handle_label_attributes(struct token *token, struct symbol *label)
+{
+ struct decl_state ctx = { };
+
+ token = handle_attributes(token, &ctx, KW_ATTRIBUTE);
+ label->label_modifiers = ctx.ctype.modifiers;
+ return token;
+}
+
static struct token *statement(struct token *token, struct statement **tree)
{
struct statement *stmt = alloc_statement(token->pos, STMT_NONE);
@@ -2528,8 +2562,8 @@ static struct token *statement(struct token *token, struct statement **tree)
return s->op->statement(token, stmt);
if (match_op(token->next, ':')) {
- struct symbol *s = label_symbol(token);
- token = skip_attributes(token->next->next);
+ struct symbol *s = label_symbol(token, 0);
+ token = handle_label_attributes(token->next->next, s);
if (s->stmt) {
sparse_error(stmt->pos, "label '%s' redefined", show_ident(s->ident));
// skip the label to avoid multiple definitions
@@ -2537,17 +2571,18 @@ static struct token *statement(struct token *token, struct statement **tree)
}
stmt->type = STMT_LABEL;
stmt->label_identifier = s;
+ stmt->label_scope = label_scope;
+ if (s->label_scope) {
+ if (!is_in_scope(label_scope, s->label_scope))
+ warn_label_usage(stmt->pos, s->label_pos, s->ident);
+ }
s->stmt = stmt;
return statement(token, &stmt->label_statement);
}
}
if (match_op(token, '{')) {
- stmt->type = STMT_COMPOUND;
- start_symbol_scope();
token = compound_statement(token->next, stmt);
- end_symbol_scope();
-
return expect(token, '}', "at end of compound statement");
}
@@ -2561,8 +2596,7 @@ static struct token *label_statement(struct token *token)
while (token_type(token) == TOKEN_IDENT) {
struct symbol *sym = alloc_symbol(token->pos, SYM_LABEL);
/* it's block-scope, but we want label namespace */
- bind_symbol(sym, token->ident, NS_SYMBOL);
- sym->namespace = NS_LABEL;
+ bind_symbol_with_scope(sym, token->ident, NS_LABEL, block_scope);
fn_local_symbol(sym);
token = token->next;
if (!match_op(token, ','))
@@ -2654,7 +2688,10 @@ static struct token *parameter_type_list(struct token *token, struct symbol *fn)
struct token *compound_statement(struct token *token, struct statement *stmt)
{
+ stmt->type = STMT_COMPOUND;
+ start_block_scope();
token = statement_list(token, &stmt->stmts);
+ end_block_scope();
return token;
}
@@ -2806,15 +2843,15 @@ static struct token *parse_function_body(struct token *token, struct symbol *dec
decl->ctype.modifiers |= MOD_EXTERN;
stmt = start_function(decl);
-
*p = stmt;
+
FOR_EACH_PTR (base_type->arguments, arg) {
declare_argument(arg, base_type);
} END_FOR_EACH_PTR(arg);
- token = compound_statement(token->next, stmt);
-
+ token = statement_list(token->next, &stmt->stmts);
end_function(decl);
+
if (!(decl->ctype.modifiers & MOD_INLINE))
add_symbol(list, decl);
check_declaration(decl);