There are a few different concepts getting mixed together here:
- The scope where a name is declared
- Whether that name can be referenced hierarchically
- The lifetime of the object represented by that name
- For
disable, which active executions are affected
static and automatic affect lifetime. They do not by themselves define the lexical scope of the declaration.
Q1
The key point is that blk02.a is being referenced from within blk02 itself.
The variable a has automatic lifetime, meaning its storage is created when execution enters the block activation and destroyed when execution leaves that activation. But the declaration of a is still known statically from the source code. The compiler can resolve the name blk02.a because it is a qualified reference to a declaration in the current named block scope.
So this is legal:
$display("%0d", blk02.a);
inside blk02, because it is still within the locally declared scope where a exists as a declared name.
By contrast, this is illegal:
$display("%0d", blk01.a);
from inside blk02, because it attempts to reach into a differently named block and access an automatic variable declared there. An automatic variable may be referenced hierarchically only from within its locally declared scope, or from scopes nested inside that scope. It is not available for arbitrary external hierarchical access from a sibling or enclosing scope.
So the issue is not that automatic variables cannot have qualified names. They can. The issue is where the reference is made from.
Q2
The class object is dynamically created, and each call to kill_proc() creates a runtime activation of that task. But the class, task, and named block declarations are all statically known from the source code.
So kill_proc.blk names the block declaration blk inside the task declaration kill_proc. The fact that the object is created dynamically does not prevent the compiler from resolving the name of the declaration.
However, disable kill_proc.blk; does not mean “disable only the blk in this particular object instance” or “disable only my local sibling branch.” It disables all currently active executions of the named block blk declared inside kill_proc.
That distinction matters if kill_proc() is re-entered or called concurrently. Multiple active task calls could each have an active execution of blk, and a named-block disable can terminate all of them.
So:
disable kill_proc.blk;
names a statically declared block, and at runtime disables all active executions of that named block.
If the intent is only to terminate the other branch of the current fork created by the current process, then disable fork is usually the more appropriate construct:
That disables the child processes of the current fork context rather than all active executions of a named block declaration.