enclosed the declaration, and that has closed.
- "conditionally in scope". The "in scope" block and all parallel
- scopes have closed, and no further mention of the name has been
- seen. This state includes a secondary nest depth which records the
- outermost scope seen since the variable became conditionally in
- scope. If a use of the name is found, the variable becomes "in
- scope" and that secondary depth becomes the recorded scope depth.
- If the name is declared as a new variable, the old variable becomes
- "out of scope" and the recorded scope depth stays unchanged.
+ scopes have closed, and no further mention of the name has been seen.
+ This state includes a secondary nest depth (`min_depth`) which records
+ the outermost scope seen since the variable became conditionally in
+ scope. If a use of the name is found, the variable becomes "in scope"
+ and that secondary depth becomes the recorded scope depth. If the
+ name is declared as a new variable, the old variable becomes "out of
+ scope" and the recorded scope depth stays unchanged.
- "out of scope". The variable is neither in scope nor conditionally
in scope. It is permanently out of scope now and can be removed from
static void var_block_close(struct parse_context *c, enum closetype ct)
{
- /* Close off all variables that are in_scope */
+ /* Close off all variables that are in_scope.
+ * Some variables in c->scope may already be not-in-scope,
+ * such as when a PendingScope variable is hidden by a new
+ * variable with the same name.
+ * So we check for v->name->var != v and drop them.
+ * If we choose to make a variable OutScope, we drop it
+ * immediately too.
+ */
struct variable *v, **vp, *v2;
scope_pop(c);
(v->scope == OutScope || v->name->var != v)
? (*vp = v->in_scope, 0)
: ( vp = &v->in_scope, 0)) {
- if (v->name->var != v) {
+ v->min_depth = c->scope_depth;
+ if (v->name->var != v)
/* This is still in scope, but we haven't just
* closed the scope.
*/
continue;
- }
switch (ct) {
case CloseElse:
case CloseParallel: /* handle PendingScope */
case InScope:
case CondScope:
if (c->scope_stack->child_count == 1)
+ /* first among parallel branches */
v->scope = PendingScope;
else if (v->previous &&
v->previous->scope == PendingScope)
+ /* all previous branches used name */
v->scope = PendingScope;
else if (v->type == Tlabel) // UNTESTED
+ /* Labels remain pending even when not used */
v->scope = PendingScope; // UNTESTED
- else if (v->name->var == v) // UNTESTED
- v->scope = OutScope; // UNTESTED
if (ct == CloseElse) {
/* All Pending variables with this name
* are now Conditional */
}
break;
case PendingScope:
- for (v2 = v;
- v2 && v2->scope == PendingScope;
- v2 = v2->previous)
- if (v2->type != Tlabel)
- v2->scope = OutScope;
- break;
- case OutScope: break; // UNTESTED
+ /* Not possible as it would require
+ * parallel scope to be nested immediately
+ * in a parallel scope, and that never
+ * happens.
+ */
+ case OutScope:
+ /* Not possible as we already tested for
+ * OutScope
+ */
+ abort(); // NOTEST
}
break;
case CloseSequential:
v2 = v2->previous)
if (v2->type == Tlabel) {
v2->scope = CondScope;
- v2->min_depth = c->scope_depth;
} else
v2->scope = OutScope;
break;