Commit Graph

824 Commits

Author SHA1 Message Date
Lars-Peter Clausen 173f6af729 Support shadowing type identifiers in procedural labels
SystemVerilog procedural labels use ordinary identifiers. A visible type
identifier can therefore also be used as a label:

    typedef int T;
    module test;
      initial begin
        T value;
        T: assert (1);
      end
    endmodule

The parser currently handles procedural declarations and statements as
separate lists. After `T value;`, it must decide whether the next
`TYPE_IDENTIFIER` starts another declaration before it can see that the
following `:` makes it an assertion label. Extending the label rule alone
therefore introduces parser conflicts.

Replace the separate lists with a mixed procedural item accumulator so the
parser can keep the declaration-or-statement decision open. Track whether
declarations have been seen, use allocation of the statement vector to record
whether a statement has been seen, collect concrete statements and old-style
task/function ports, and reject a declaration after a statement. A null
statement allocates an empty statement vector and therefore also starts the
statement section, preserving the existing declaration ordering rule. Own the
accumulated statement and port vectors with `unique_ptr` and release old-style
port vectors only when transferring them to a task or function.

Parse assertion labels as `identifier_name ':'` and use the accumulator for
constructors, functions, tasks, and sequential and parallel blocks. Keep the
temporary scope for an unnamed block until its body has been classified. If it
has no declarations, move nested named scopes into the enclosing scope and
reparent them before discarding the temporary scope.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-19 20:12:11 -07:00
Lars-Peter Clausen 36f013f97f Factor statement-or-null grammar
`statement_or_null` currently reaches statements and null statements through
an optional attribute list. Reducing that empty prefix before the parser knows
which form follows makes the rule difficult to use in a mixed procedural item
list without conflicts.

Expand the rule into explicit attributed and unattributed statement and null
forms. This preserves attribute binding and null-statement behavior while
allowing the parser to distinguish the forms from their leading token.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-19 20:12:11 -07:00
Lars-Peter Clausen 97928cfb15 Factor block variable declaration grammar
Block variable declarations currently combine optional `const` and lifetime
qualifiers with the data type. This requires reducing empty qualifier rules
before the parser can determine which declaration form follows, making the
rule difficult to use in a mixed procedural item list without conflicts.

Split the declaration productions according to their leading syntax. Share
required and optional variable lifetime handling and add a rule for data types
following the historical leading `reg` extension. This keeps the declaration
behavior unchanged while allowing the parser to distinguish each form from
its leading token.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-19 20:12:11 -07:00
Lars-Peter Clausen 7792b5ab8a Fix locations of unattributed statements
The `statement` and null-statement rules start with an optional attribute
list. When it is empty, the reduced location starts at the previous token
instead of the statement. Diagnostics using that location can consequently
point to the beginning of the source file.

Use the statement or semicolon location when no attributes are present.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-19 20:12:11 -07:00
Lars-Peter Clausen 60f366790b Remove special interface identifier token
The lexer currently returns `INTERFACE_IDENTIFIER` for names of interfaces
that have already been parsed. There are two issues with this approach:

1. Once an interface has been parsed, its name can no longer be used in
   grammar positions that accept an ordinary identifier.
2. The LRM allows an interface to be used before its declaration. Before the
   declaration has been parsed, however, the name remains an ordinary
   identifier and can not be accepted by productions requiring
   `INTERFACE_IDENTIFIER`. Lexer lookahead tries to recognize forward
   interface port types, but this depends on parser-managed port-list state
   and does not cover all cases.

Parse interface port declarations from ordinary `IDENTIFIER` tokens instead.
An interface port can not simply be added to `port_declaration` using an
`IDENTIFIER` token. This creates a shift/reduce conflict on the identifier at
the start of the port list. Shifting starts an old-style `port_reference`,
while reducing the empty `attribute_list_opt` starts an interface
`port_declaration`. The parser has not yet seen the following identifier or
`.` that distinguishes the two forms.

Add leading interface port declarations as base cases of
`list_of_port_declarations`. Both the old-style and ANSI port-list rules can
then shift the common identifier and use the following identifier or `.` to
distinguish the interface port. Keep a separate base case for a non-empty
attribute list so no empty reduction is needed before the identifier. Handle
later interface ports in the recursive list rule and use
`interface_port_modport_opt` to share the forms with and without a modport.
Interface instances can use the existing module instantiation rules.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-18 11:22:09 -07:00
mjoekhan e3222e77ad SV: queue/darray locator methods (find*, unique*, min/max)
Add find*, unique*, min/max, and with-predicate locator methods for
queues and dynamic arrays, with VVP runtime support and ivtest.

Split from steveicarus/iverilog#1330 (part 03/6).
2026-07-15 22:49:12 +05:00
Cary R. 55250457ed
Fix formatting in parse.y for call_chain_expr 2026-07-13 22:50:55 -07:00
mjoekhan 4a505546a1 SV: chained method calls a().b()
Add parsing and elaboration for chained calls on expression results,
with sv_call_chain_method1 regression.

Split from steveicarus/iverilog#1330 (part 02/6).
2026-07-13 18:48:30 +05:00
Lars-Peter Clausen 1d623a67d1 Support discipline and nature names shadowing type identifiers
Verilog-AMS nature and discipline declarations can use names that are also
visible as type identifiers. The `potential` and `flow` discipline items can
likewise reference a nature whose name is returned as `TYPE_IDENTIFIER` by the
lexer. These grammar positions currently only accept `IDENTIFIER`.

Use `identifier_name` for nature and discipline declaration names and for the
`potential` and `flow` nature references.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-11 17:44:54 -07:00
Lars-Peter Clausen 9ec8f8e2dd Support for and foreach identifiers shadowing type identifiers
SystemVerilog allows a declaration in an inner scope to use the same name as
a type identifier from an outer scope. The lexer reports such names as
`TYPE_IDENTIFIER` until the new declaration has been installed.

The parser previously created the synthetic loop scope and declared the loop
variable only after parsing the complete `for` header. When the variable name
matches a visible typedef, this is too late: the lexer can continue returning
`TYPE_IDENTIFIER` for references to the variable in the initializer,
condition, and step expressions. Accept `identifier_name` for the declaration
name and create the loop scope and variable in a mid-rule action immediately
after it, so the declaration is visible while the rest of the header is
parsed.

The executable foreach grammar also used to require the array expression name
before the index list to be an `IDENTIFIER`. Use `identifier_name` there as
well, since this position is an expression name followed by `[` and not a type
name.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-11 15:58:18 -07:00
Lars-Peter Clausen ee14022127 Support type identifier names in attributes
Standard attribute names and target names in both forms of the Icarus
`$attribute` extension are unambiguous identifier positions. When such a name
matches a visible typedef the lexer returns `TYPE_IDENTIFIER`, while the
grammar only accepts `IDENTIFIER`.

Use `identifier_name` for all of these positions.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-11 15:58:02 -07:00
Cary R. f8069416f2
Merge pull request #1434 from larsclausen/parameter-omit-implicit-type
parser: Reject implicit parameter types without parameter
2026-07-10 10:42:15 -07:00
Lars-Peter Clausen 20a34d33c6 parser: Reject implicit parameter types without `parameter`
The LRM allows omitting the `parameter` keyword in a module parameter port
list, but the optional type in that form is a data_type, not an implicit
data type. A parameter port list like this is therefore invalid:

    module M #([3:0] P = 1);

The parameter declaration grammar was reusing the general
value_parameter_assign_with_type rule for the omitted-keyword form. That rule
also accepts implicit types so that ordinary `parameter signed P = 1`
declarations work, which made the omitted-keyword form accept implicit types
as well.

Add a separate rule for value parameter assignments without the `parameter`
keyword. The rule still accepts bare identifiers and explicit data types so a
parameter name can shadow a visible typedef name, but it rejects implicit
types.

Fixes: e56c93a2be ("Support shadowing type identifiers in parameter declarations")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-09 20:49:01 -07:00
Lars-Peter Clausen 6844ed4194 Accept type-identifier tokens in named binding selectors
A named binding selector such as `.T(expr)` names an existing formal port,
parameter, task or function argument, or constructor argument. It is not a
declaration of a new identifier. If a visible typedef named `T` exists at the
use site the lexer returns `TYPE_IDENTIFIER`, which made the parser reject the
binding selector.

Modport simple port aliases use the same grammar, but are slightly different:
the selector is the modport-visible port name and can shadow a visible typedef
name in the interface scope.

Use `identifier_name` for the selector name in `named_expression` and
`named_expression_opt`. This covers named parameter overrides, named task and
function arguments, named constructor arguments, and modport simple port
aliases. Also use `identifier_name` in the named module port connection rules,
including implicit named port connections and error recovery.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-09 20:08:25 -07:00
Lars-Peter Clausen 17ca0948f4 Support event names shadowing type identifiers
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to named event
declarations. The lexer reports such names as `TYPE_IDENTIFIER` before the
event has been installed, which made constructs such as:

    typedef int T;
    module test;
      event T;
    endmodule

fail in the event declaration grammar.

Event declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. The name in `event_variable` is
always the event name. Use `identifier_name` so a `TYPE_IDENTIFIER` token can
be accepted as the event name.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-05 21:44:44 -07:00
Lars-Peter Clausen 06740d0dda Support block labels shadowing type identifiers
SystemVerilog allows a named block label in an inner scope to use the same
name as a visible type identifier from an outer scope. The lexer reports such
names as `TYPE_IDENTIFIER` before the label has been installed, which made
constructs such as:

    typedef int T;
    module test;
      initial begin
        begin : T
        end : T
      end
    endmodule

fail in the block label grammar.

The affected grammar positions are label names, not declarations with an
adjacent type/name ambiguity. Use `identifier_name` for `label_opt` and for the
anachronistic named generate begin form so a token returned as `TYPE_IDENTIFIER`
can still be accepted as the label name. With `label_opt` able to handle
`TYPE_IDENTIFIER`, the separate class end-label rule is no longer needed.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-05 21:36:32 -07:00
Lars-Peter Clausen ca5c6fc59f Support package names shadowing type identifiers
SystemVerilog allows a package declaration to use a name that is also visible
as a type identifier. The lexer reports such names as `TYPE_IDENTIFIER` before
the package has been installed, which made constructs such as:

    package p;
      typedef int T;
    endpackage
    import p::*;
    package T;
    endpackage

fail in the package declaration grammar.

Package declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. After the optional lifetime the next
token is always the package name. Use `identifier_name` so a
`TYPE_IDENTIFIER` token can be accepted as the package name.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-05 21:36:18 -07:00
Lars-Peter Clausen ff0b4a3154 parser: Fix parameter assignment grammar conflict
The parameter declaration grammar allows a visible type identifier to be used
as a parameter name. The assignment continuation rule still used
`identifier_name`, which made Bison reduce a `TYPE_IDENTIFIER` before it had
seen whether following dimensions belonged to the parameter name or to an
explicit type identifier.

Match ordinary and type identifiers directly in `parameter_assign` so the
parser can shift dimensions before deciding between a parameter name and an
explicit parameter type.

Fixes: e56c93a2be ("Support shadowing type identifiers in parameter declarations")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-05 21:36:03 -07:00
Lars-Peter Clausen 56c42dcf37 Support UDP names shadowing type identifiers
SystemVerilog allows a UDP primitive or UDP port declaration to use the same
name as a visible type identifier from another namespace or outer scope. The
lexer reports such names as `TYPE_IDENTIFIER` before the UDP name has been
installed, which made constructs such as:

    typedef int T;
    primitive T (Q, A);
      output Q;
      input A;
      table
        0 : 0;
      endtable
    endprimitive

fail in the UDP grammar.

UDP primitive and port names do not have the local type/name ambiguity that
exists for variable, net, or parameter declarations. Use `identifier_name` for
the primitive name, the UDP port list, UDP port declarations, and the UDP
initial target so a `TYPE_IDENTIFIER` token can be accepted as the UDP name.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-05 13:58:11 -07:00
Cary R. 025cbcc81f
Merge pull request #1426 from larsclausen/enum-item-type-id-shadow
Support enum items shadowing type identifiers
2026-07-04 07:29:07 -07:00
Lars-Peter Clausen 0c7341be37 Support enum items shadowing type identifiers
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to enum item names. The
lexer reports such names as `TYPE_IDENTIFIER` before the enum item has been
installed, which made constructs such as:

    typedef int T;
    module test;
      enum { T = 1 } e;
    endmodule

fail in the enum item grammar.

Enum item declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. The name in each `enum_name`
production is always the enum item name, including the sequence forms like
`T[2]` and `T[1:2]`. Use `identifier_name` for these names so they can shadow a
visible type identifier.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-03 18:10:54 -07:00
Lars-Peter Clausen 24743af7d5 Support task and function names shadowing type identifiers
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to task and function
names. The lexer reports such names as `TYPE_IDENTIFIER` before the new task or
function has been installed, which made constructs such as:

    typedef int T;
    module test;
      function int T(input int value);
        return value;
      endfunction
      task T;
      endtask
    endmodule

fail in the task and function declaration grammar. A class method with the same
name as the class itself hits the same problem because the class name is visible
as a type identifier in the class scope.

The task grammar can accept `identifier_name` directly, because a task has no
return type and the token after `task` and the optional lifetime is always the
task name.

Function declarations have a local return-type/name ambiguity. After
`function T` the parser does not know yet whether `T` is the function name with
no explicit return type, or whether a following identifier will make `T` the
explicit return type as in `function T f`. Parse the optional function return
type and function name together. This allows a `TYPE_IDENTIFIER` token to be
interpreted as the function name when no separate function name follows, while
still parsing typed forms and `void` return types correctly.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-03 17:29:40 -07:00
Cary R. 60a81493cd
Merge pull request #1424 from larsclausen/type-id-parameter-declarations
Support shadowing type identifiers in parameter declarations
2026-07-03 07:14:53 -07:00
Lars-Peter Clausen e56c93a2be Support shadowing type identifiers in parameter declarations
SystemVerilog allows a visible type identifier to be shadowed by a
parameter declaration name. Parameter declarations still required the
parameter name to be an `IDENTIFIER` token and rejected declarations like:

    typedef int P;
    module test;
      parameter int P = 1;
    endmodule

The parameter grammar can not just accept `TYPE_IDENTIFIER` in every name
position. After `parameter P` the parser does not know yet whether `P` is
the parameter name, or whether a following identifier will make `P` the
parameter type.

Parse the optional value parameter type and the first parameter assignment
together. This allows a `TYPE_IDENTIFIER` token to be interpreted as the
parameter name when no explicit type is present, while still parsing a
following identifier as the parameter name for typed parameters.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-02 19:32:32 -07:00
Lars-Peter Clausen dc66f2fe7e Support class properties shadowing type names
SystemVerilog allows a class property to have the same name as a visible
type. The lexer reports the visible type name as `TYPE_IDENTIFIER` before
the property has been installed, which made constructs such as
`typedef int T; class C; int T; endclass` fail in the class item grammar.
A class property with the same name as the class itself hits the same
problem. Member references such as `obj.T` or `obj.C` can also hit the
same tokenization problem in hierarchical names.

Parse class properties through the same declaration helper used for
variables so the first type/name pair can be disambiguated. Also let
hierarchical member names use `identifier_name`.

Stop type lookup when a class scope already has a property with the same
name. This makes method body references resolve as properties instead of
visible types, including type names found through wildcard imports.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-07-02 16:58:42 -07:00
Lars-Peter Clausen 7cffbf440d Support declaration names shadowing type identifiers
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. The lexer reports such names as
`TYPE_IDENTIFIER` before the new declaration has been installed, which made
constructs such as `int T;`, `wire T;`, and `input T` fail when `T` was a
visible typedef.

The affected declaration forms have a local type/name/dimension ambiguity. For
example, after `input T` or `wire T` the parser does not know whether `T` is the
declared name, or whether a following identifier will make `T` the declaration
type in `input T x` or `wire T x`. With dimensions, `input T [1:0]` and
`wire T [1:0]` can be either a declaration named `T` with unpacked dimensions or
a declaration using typedef `T` as a packed type followed by another name.

Parse these declaration forms with productions that decide the first declarator
and carry the selected declaration type across the rest of the list. This covers
variable declarations, net declarations, ANSI and non-ANSI module port
declarations, and task/function port declarations. Other identifier uses still
need separate grammar changes.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-06-30 14:41:06 -07:00
Lars-Peter Clausen d2a97663b9 Allow type identifiers to be shadowed in more places
SystemVerilog allows an identifier that is visible as a typedef to be
shadowed by a declaration in a nested scope or reused as a declaration
name in another namespace. The lexer can return `TYPE_IDENTIFIER` before
the new name has been installed, so these grammar positions reject
otherwise valid code.

This is not a complete conversion of all identifier grammar sites. Only
handle the trivial conflict-free cases where `IDENTIFIER` can be replaced
by `identifier_name` without any surrounding grammar changes.

Also stop type lookup when the current scope already has a local symbol
with the same name. This makes later references to a shadowing
declaration use the local symbol instead of an outer typedef.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-06-29 09:52:44 -07:00
Cary R aafda65b99 Cppcheck cleanup 2026-05-21 05:21:35 -07:00
Lars-Peter Clausen 3495889112 Support SystemVerilog net declaration assignments
SystemVerilog allows initialized and uninitialized net declaration entries to
be mixed in the same declaration, e.g. `wire x, y = 1'b1`. In Verilog,
either all nets need to have an initializer or non can have one.

In addition SystemVerilog also allows assignments to arrays of wires during
declaration. E.g. `wire a[3:0] = b;`

Currently there are two different rules for net declarations, one for each
of the Verilog variants. Combine these into a single rule to support
SystemVerilog mixed declarations as well as the assignment to array nets.

When running in Verilog mode still reject mixed initialized and
uninitialized with a check after the parsing.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-05-17 11:06:44 -07:00
Lars-Peter Clausen 46c0526dab Add support for restricted type parameters
SystemVerilog 2023 allows type parameters to be restricted to a
specific kind of type, e.g. `parameter type struct T = T0`.

This is very similar to the type restrictions that can be applied to
forward typedefs.

Factor the support code from the typedefs into a standalone helper and
reuse it for both.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-05-16 17:20:40 -07:00
Lars-Peter Clausen fb3be420b4 Support soft packed unions
SystemVerilog 2023 adds soft packed unions. They are pretty much the same
as regular packed unions except they remove the restriction that all
elements have to have the same packed width.

The packed with of the union itself is the maximum packed width of any
element.

The bits of each member are right-justified towards the LSBs and this
representation is applied recursively to nested soft packed unions. The
existing packed union member offsets already use that layout. When
accessing a field that is smaller than the union itself upper bits are
ignored for both reading and writing.

The `soft` qualifier implies a packed union so both `union soft U { ... }`
and `union soft packed U { ... }` declare a soft packed union.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-05-16 16:43:06 -07:00
Cary R. 00325f3efb
Merge pull request #1348 from jotego/interface-ports
Support SystemVerilog interface-typed module ports
2026-05-16 15:33:56 -07:00
Lars-Peter Clausen f1c71eff5c parse.y: Remove unused fields from union
The parser union still has a few fields that are not used by any
grammar rule. They do not have matching semantic type tags and no
action references them.

Remove the unused fields.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-05-14 20:18:28 -07:00
Jose Tejada 56afcb6e75 fix(interface): allow forward interface port types 2026-05-11 22:25:32 +02:00
Jose Tejada 377881b723 fix(interface): address port array review feedback 2026-05-11 07:44:43 +02:00
Jose Tejada 417ab54445 feat(interface): support interface port arrays 2026-05-10 17:30:54 +02:00
Jose Tejada 39072cd452 feat(interface): broaden interface port binding 2026-05-10 16:34:21 +02:00
Jose Tejada c963809709 feat(sv): support interface-typed module ports 2026-05-10 14:45:33 +02:00
Lars-Peter Clausen c2b63e69a4 Allow lifetime specifier for variables declared in packages
The LRM allows to add a lifetime specified for variables declared in
package scope. It is not particular useful since only static lifetime is
allowed. But it is legal syntax, so support it.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-05-07 22:14:20 -07:00
Lars-Peter Clausen 11c619e265 Fix drive strength in net declaration parsing
The drive strength of a net must be declared between the net type and the data type. E.g.

    wire (weak0, strong1) [7:0] x;

The current implementation expects the drive strength after the data type. Update the parser to fix this.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
2026-05-03 17:30:56 -07:00
Cary R c172a0d3a7 More cppcheck cleanup 2026-01-05 18:59:08 -08:00
Cary R cc496c3cf3 More ivl cppcheck cleanup 2025-10-23 10:01:06 -07:00
Cary R 860761f9c6 More cppcheck fixes - part 2 2025-10-20 23:54:15 -07:00
Cary R b979441de2 Improve error messages when bad code is passed to the parser 2025-07-21 14:46:56 -07:00
Martin Whitaker dd714d78c4 Make -gno-specify suppress unsupported timing check warnings (issue #1258) 2025-07-05 22:44:59 +01:00
Cary R 03835c9d50 Report each line that has a var decl in an unnamed block 2024-12-28 20:51:30 -08:00
Cary R 788a94b310 Nested generate regions are illegal 2024-12-28 18:46:37 -08:00
Cary R 8edf14ae68 Check for primitive port mismatches and other error cleanup 2024-12-08 22:21:51 -08:00
Martin Whitaker b2eaedfc94 Emit "sorry" message for unpacked array parameter declarations (issue #1180)
These aren't yet supported. Make it an error if not compiling fpr a
SystemVerilog generation.
2024-11-15 21:01:12 +00:00
Martin Whitaker 0695c1fe9a Only allow null for-loop initialisation/termination/step for SV 2012+.
As discussed in issue #1143, the for loop initialisation statement,
termination condition, and step statement were only made optional in
IEEE 1800-2012. So check all three are present when compiling for
ealier generations.
2024-07-13 11:28:18 +01:00