On Tue, Apr 14, 2020 at 12:49 AM Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx> wrote: > > The problem is that now normal labels use the new label_scope > but the ones declared with __label__ use block_scope and these > 2 scopes are kinda in a different namespace of scope. Oh, I forgot about the special __label__ thing that actually declares labels. That one has an interesting behavior, in that the _lifetime_ of the symbol is the block scope, but the *use* of the symbol must remain in label scope. The most obvious fix is probably something like the appended: make the 'sym->scope' remain the lifetime scope, but then attach a "must be used in this scope' thing to any NS_LABEL case. That fairly clearly separates the two issues. Again, not actually tested outside of the obvious trivial case. Linus
parse.c | 16 +++++++++++----- scope.c | 1 + symbol.h | 3 +++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/parse.c b/parse.c index 8e238f59..b6109516 100644 --- a/parse.c +++ b/parse.c @@ -728,6 +728,7 @@ struct symbol *label_symbol(struct token *token) if (!sym) { sym = alloc_symbol(token->pos, SYM_LABEL); bind_symbol(sym, token->ident, NS_LABEL); + sym->declared_scope = label_scope; fn_local_symbol(sym); } return sym; @@ -2541,13 +2542,14 @@ static struct token *statement(struct token *token, struct statement **tree) } /* * If the scope of the label symbol is different - * from the current label scope, that means that - * it must have been used at an outer scope. + * from the declared label scope, that means that + * it must have been used or declared at an outer + * scope. * * That's not ok. */ - if (s->scope != label_scope) { - sparse_error(stmt->pos, "label '%s' used outside label expression", show_ident(s->ident)); + if (s->scope != s->declared_scope) { + sparse_error(stmt->pos, "label '%s' used outside statement expression", show_ident(s->ident)); sparse_error(s->pos, "invalid use here"); } stmt->type = STMT_LABEL; @@ -2575,9 +2577,13 @@ 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 */ + + /* it's lifetile is block-scope, but we want label namespace */ bind_symbol(sym, token->ident, NS_SYMBOL); sym->namespace = NS_LABEL; + + /* But we must define it in this label scope */ + sym->declared_scope = label_scope; fn_local_symbol(sym); token = token->next; if (!match_op(token, ',')) diff --git a/scope.c b/scope.c index 4b0f7947..11792ec4 100644 --- a/scope.c +++ b/scope.c @@ -171,6 +171,7 @@ void end_label_scope(void) /* Re-bind the symbol to the parent scope, we'll try again */ bind_scope(sym, label_scope); + sym->declared_scope = label_scope; } END_FOR_EACH_PTR(sym); end_scope(&block_scope); diff --git a/symbol.h b/symbol.h index 18476582..08e35438 100644 --- a/symbol.h +++ b/symbol.h @@ -167,6 +167,9 @@ struct symbol { int (*handler)(struct stream *, struct token **, struct token *); int normal; }; + struct /* NS_LABEL */ { + struct scope *declared_scope; + }; struct /* NS_SYMBOL */ { unsigned long offset; int bit_size;