diff --git a/Changes b/Changes index 19005bf77..9ff7dc354 100644 --- a/Changes +++ b/Changes @@ -23,6 +23,7 @@ Verilator 5.041 devel * Add IMPLICITSTATIC also on procedure variables. * Add FUNCTIMCTL error on function invoking task or time-controlling statements (#6385). * Add error on `virtual new` (#6486). [Alex Solomatnikov] +* Add error on ranges with tristate values (#6534). [Alex Solomatnikov] * Deprecate sensitivity list on public_flat_rw attributes (#6443). [Geza Lore] * Deprecate clocker attribute and --clk option (#6463). [Geza Lore] * Change default `--expand-limit` to 256 (#3419). diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 506769313..babe67c01 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -956,8 +956,12 @@ class WidthVisitor final : public VNVisitor { UINFO(6, "RANGE " << nodep); V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node - checkConstantOrReplace(nodep->leftp(), "left side of bit range isn't a constant"); - checkConstantOrReplace(nodep->rightp(), "right side of bit range isn't a constant"); + checkConstantOrReplace(nodep->leftp(), true, + "left side of bit range isn't a two-state constant" + " (IEEE 1800-2023 6.9.1)"); + checkConstantOrReplace(nodep->rightp(), true, + "right side of bit range isn't a two-state constant" + " (IEEE 1800-2023 6.9.1)"); if (m_vup->prelim()) { // Don't need to iterate because V3Const already constified const int width = nodep->elementsConst(); @@ -2643,8 +2647,9 @@ class WidthVisitor final : public VNVisitor { if (!nodep->varp()) { if (m_paramsOnly && VN_IS(nodep, VarXRef)) { checkConstantOrReplace( - nodep, "Parameter-resolved constants must not use dotted references: " - + nodep->prettyNameQ()); + nodep, false, + "Parameter-resolved constants must not use dotted references: " + + nodep->prettyNameQ()); VL_DANGLING(nodep); return; } else { @@ -8831,13 +8836,15 @@ class WidthVisitor final : public VNVisitor { nodep->v3fatalSrc("No dtype expected at statement " << nodep->prettyTypeName()); } } - void checkConstantOrReplace(AstNode* nodep, const string& message) { + void checkConstantOrReplace(AstNode* nodep, bool noFourState, const string& message) { // See also V3WidthSel::checkConstantOrReplace // Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us! - if (!VN_IS(nodep, Const)) { + AstConst* const constp = VN_CAST(nodep, Const); + if (!constp || (noFourState && constp->num().isFourState())) { nodep->v3error(message); nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::Unsized32{}, 1}); VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; } } static AstVarRef* newVarRefDollarUnit(AstVar* nodep) { diff --git a/test_regress/t/t_assoc_default_func.v b/test_regress/t/t_assoc_default_func.v index e4a3be8f8..e6f73bfad 100644 --- a/test_regress/t/t_assoc_default_func.v +++ b/test_regress/t/t_assoc_default_func.v @@ -9,6 +9,7 @@ module t; type T = bit ); static function int get_type(); + return 0; endfunction endclass diff --git a/test_regress/t/t_lint_range_negative_bad.out b/test_regress/t/t_lint_range_negative_bad.out index ffbe1b72b..61a0510aa 100644 --- a/test_regress/t/t_lint_range_negative_bad.out +++ b/test_regress/t/t_lint_range_negative_bad.out @@ -7,4 +7,8 @@ : ... note: In instance 't' 9 | int array2_bad[-1]; | ^ +%Error: t/t_lint_range_negative_bad.v:11:10: left side of bit range isn't a two-state constant (IEEE 1800-2023 6.9.1) + : ... note: In instance 't' + 11 | logic [X:0] x; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_lint_range_negative_bad.v b/test_regress/t/t_lint_range_negative_bad.v index 300efb1ec..a9689b70e 100644 --- a/test_regress/t/t_lint_range_negative_bad.v +++ b/test_regress/t/t_lint_range_negative_bad.v @@ -7,6 +7,8 @@ module t; int array_bad[0]; // <--- Error: Must be positive size int array2_bad[-1]; // <--- Error: Must be positive size + localparam X = 32'bz; + logic [X:0] x; // <--- Error: X range sub #(1) u_sub(); endmodule