From ff056ffb0dc2f80a0c81b98656e04b774924a97f Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Thu, 12 Feb 2026 18:15:47 +0100 Subject: [PATCH] Fix inside operator crash with impure expression and unsized range literals When the inside operator is used with an impure LHS expression (e.g. associative array element access) and unsized integer range literals, the temp variable created to purify the expression inherits an unsized dtype, triggering "How can LHS be unsized?" assertion in visit(AstNodeAssign). Ensure the temp variable dtype is sized before creation. Co-Authored-By: Claude Opus 4.6 --- src/V3Width.cpp | 11 ++++++- test_regress/t/t_inside_impure_unsized.py | 18 +++++++++++ test_regress/t/t_inside_impure_unsized.v | 37 +++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_inside_impure_unsized.py create mode 100644 test_regress/t/t_inside_impure_unsized.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index ad8607d69..22a044aac 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3159,8 +3159,17 @@ class WidthVisitor final : public VNVisitor { // executed so, there is no need for purification since they cannot generate sideeffects. if (!m_constraintp && !nodep->exprp()->isPure()) { FileLine* const fl = nodep->exprp()->fileline(); + // Ensure sized dtype for temp variable + AstNodeDType* const exprDtp = nodep->exprp()->dtypep(); + const int w = exprDtp->width(); + AstNodeDType* const tempDTypep + = exprDtp->widthSized() + ? exprDtp + : exprDtp->isFourstate() + ? nodep->findLogicDType(w, w, exprDtp->numeric()) + : nodep->findBitDType(w, w, exprDtp->numeric()); AstVar* const varp = new AstVar{fl, VVarType::XTEMP, m_insideTempNames.get(nodep), - nodep->exprp()->dtypep()}; + tempDTypep}; exprp = new AstVarRef{fl, varp, VAccess::READ}; exprStmtp = new AstExprStmt{fl, new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, diff --git a/test_regress/t/t_inside_impure_unsized.py b/test_regress/t/t_inside_impure_unsized.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_inside_impure_unsized.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_inside_impure_unsized.v b/test_regress/t/t_inside_impure_unsized.v new file mode 100644 index 000000000..7d41a2236 --- /dev/null +++ b/test_regress/t/t_inside_impure_unsized.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +module t; + bit [7:0] str_arr[string]; + string str_key; + + bit [7:0] int_arr[int]; + int int_key; + + int counter = 0; + function bit [7:0] get_val(); + counter++; + return 25; + endfunction + + initial begin + str_arr["test"] = 25; + str_key = "test"; + if (!(str_arr[str_key] inside {[10:50]})) $stop; + if (str_arr[str_key] inside {[100:200]}) $stop; + + int_arr[0] = 25; + int_key = 0; + if (!(int_arr[int_key] inside {[10:50]})) $stop; + if (int_arr[int_key] inside {[100:200]}) $stop; + + if (!(get_val() inside {[10:50]})) $stop; + if (get_val() inside {[100:200]}) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule