mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-09-08 20:26:41 +02:00
`typeref_t` stores the `typedef_t` selected by the parser. This binds a type
identifier before the elaborated scope is available and can select the wrong
declaration. Function and task declarations are visible throughout their
scope, so a later subroutine named `T` in the current scope hides an earlier
`T` type in an outer scope even when the type reference appears before the
subroutine declaration. Parser-time lookup can not handle this correctly.
For example:
typedef int T;
module test;
T value;
function T;
T = 0;
endfunction
endmodule
The declaration of `value` must be rejected because the local function named
`T` hides the outer typedef. The same applies to a task named `T`.
Type lookup can also depend on information that is not available to the parser.
For example, a parameterized class can extend a type parameter and inherit `T`
from the selected base class:
class Derived #(type B = DefaultBase) extends B;
T value;
endclass
Parameterized classes are not supported yet, but resolving named types during
elaboration is a prerequisite for supporting this case.
Replace `typeref_t` with `type_identifier_t`, which owns a `PEIdent`. Construct
the identifier in the parser, then resolve it through
`PEIdent::elaborate_type()` and `symbol_search()` while elaborating the data
type. Parser-time type lookup is only used to select grammar paths.
`pform_new_ident()` preserves wildcard import activation for the identifier
expression.
Enforce declaration ordering when an identifier occurs in a grammar position
that requires a data type, even when compatibility options relax it for
ordinary variable lookup. A later variable therefore does not hide an outer
type in a declaration, and a later type declaration can not satisfy an earlier
use. Keep ordinary lookup when an identifier can be either a type or a value,
such as an argument to `$bits()`. Add
`SYMBOL_SEARCH_STRICT_DECLARATION_ORDER` and a required-type elaboration context
for the former case.
For example:
typedef logic [7:0] T;
module test;
T value;
localparam int A = $bits(value);
localparam int B = $bits(T);
integer T;
endmodule
The declaration of `value` uses the outer typedef, so `A` is 8. With relaxed
variable declaration ordering, the ambiguous reference in `$bits(T)` uses the
later integer, so `B` is 32.
Check a constant's declaration position before `get_parameter()` elaborates it
on demand when declaration order is enforced. This keeps a later declaration in
`parameter T T` from recursively selecting itself as the type.
Recover a failed deferred lookup in `type_identifier_t` with a scalar logic type
after reporting the error. This keeps the existing non-null expectations of
type consumers unchanged.
Signed-off-by: Lars-Peter Clausen <[email protected]>