Distinguish queue dimensions from `null` expressions

Queue dimensions use a `PENull` expression as an internal marker for `$`.
This also represents a source `null` expression, so declarations such as:

    integer value[null:2];

are accepted and elaborated as bounded queues.

Use a dedicated `PEQueueDimension` marker for queue dimensions. This lets
source `null` expressions follow normal range expression validation while
preserving the existing representation of dynamic and fixed dimensions.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
Lars-Peter Clausen 2026-08-09 14:45:43 -07:00
parent 72998c5415
commit 04c21e1982
6 changed files with 21 additions and 7 deletions

View File

@ -635,6 +635,12 @@ class PENull : public PExpr {
unsigned flags) const override;
};
// Internal marker for the '$' in a queue dimension.
class PEQueueDimension : public PExpr {
public:
void dump(std::ostream&) const override;
};
class PENumber : public PExpr {
public:

View File

@ -374,9 +374,8 @@ ivl_type_t elaborate_array_type(Design *des, NetScope *scope,
type = elaborate_darray_check_type(des, li, type, "Dynamic array");
type = new netdarray_t(type);
continue;
} else if (dynamic_cast<PENull*>(lidx)) {
// Special case: Detect the mark for a QUEUE declaration,
// which is the dimensions [null:max_idx].
} else if (dynamic_cast<PEQueueDimension*>(lidx)) {
// Special case: Detect the mark for a QUEUE declaration.
type = elaborate_static_array_type(des, li, type, dimensions);
type = elaborate_queue_type(des, scope, li, type, ridx);
continue;

View File

@ -1087,7 +1087,7 @@ bool evaluate_range(Design*des, NetScope*scope, const LineInfo*li,
"An unsized dimension is not allowed here." << endl;
dimension_ok = false;
des->errors += 1;
} else if (dynamic_cast<PENull*>(range.first)) {
} else if (dynamic_cast<PEQueueDimension*>(range.first)) {
cerr << li->get_fileline() << ": error: "
"A queue dimension is not allowed here." << endl;
dimension_ok = false;

View File

@ -3197,7 +3197,7 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
| '[' '$' ']'
{ // SystemVerilog queue
list<pform_range_t> *tmp = new std::list<pform_range_t>;
pform_range_t index (new PENull,0);
pform_range_t index (new PEQueueDimension,0);
pform_requires_sv(@$, "Queue declaration");
tmp->push_back(index);
$$ = tmp;
@ -3205,7 +3205,7 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
| '[' '$' ':' expression ']'
{ // SystemVerilog queue with a max size
list<pform_range_t> *tmp = new std::list<pform_range_t>;
pform_range_t index (new PENull,$4);
pform_range_t index (new PEQueueDimension,$4);
pform_requires_sv(@$, "Queue declaration");
tmp->push_back(index);
$$ = tmp;

View File

@ -506,6 +506,11 @@ void PENull::dump(ostream&out) const
out << "null";
}
void PEQueueDimension::dump(ostream&out) const
{
out << "$";
}
void PENumber::dump(ostream&out) const
{
out << value();

View File

@ -91,8 +91,12 @@ typedef std::pair<perm_string, unsigned> pform_ident_t;
* second = 0
*
* [ $ ] -- Queue type
* first = PENull
* first = PEQueueDimension
* second = 0
*
* [ $ : <expr> ] -- Bounded queue type
* first = PEQueueDimension
* second = <expr>
*/
typedef std::pair<PExpr*,PExpr*> pform_range_t;