Fix internal error when derived class calls this.randomize() with inherited rand members (#7229) (#7234)

This commit is contained in:
Yilou Wang 2026-03-10 23:03:18 +00:00 committed by GitHub
parent 3ba9077726
commit 5bf1d060c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 106 additions and 2 deletions

View File

@ -730,6 +730,8 @@ class ConstraintExprVisitor final : public VNVisitor {
AstClass* const m_classp;
AstNodeFTask* const m_inlineInitTaskp; // Method to add write_var calls to
// (may be null, then new() is used)
AstNodeFTask* const m_memberselInitTaskp; // Fallback for membersel write_var when
// classp has no randomize() (inherited members)
AstVar* const m_genp; // VlRandomizer variable of the class
AstVar* m_randModeVarp; // Relevant randmode state variable
bool m_wantSingle = false; // Whether to merge constraint expressions with LOGAND
@ -1248,6 +1250,9 @@ class ConstraintExprVisitor final : public VNVisitor {
varp->user3(true);
if (membersel) {
initTaskp = VN_AS(m_memberMap.findMember(classp, "randomize"), NodeFTask);
// Inherited rand members may belong to a base class
// that has no randomize(); use the caller's function
if (!initTaskp) initTaskp = m_memberselInitTaskp;
UASSERT_OBJ(initTaskp, classp, "No randomize() in class");
} else {
initTaskp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask);
@ -2388,9 +2393,11 @@ public:
// CONSTRUCTORS
explicit ConstraintExprVisitor(AstClass* classp, VMemberMap& memberMap, AstNode* nodep,
AstNodeFTask* inlineInitTaskp, AstVar* genp,
AstVar* randModeVarp, std::set<std::string>& writtenVars)
AstVar* randModeVarp, std::set<std::string>& writtenVars,
AstNodeFTask* memberselInitTaskp = nullptr)
: m_classp{classp}
, m_inlineInitTaskp{inlineInitTaskp}
, m_memberselInitTaskp{memberselInitTaskp}
, m_genp{genp}
, m_randModeVarp{randModeVarp}
, m_memberMap{memberMap}
@ -3979,7 +3986,7 @@ class RandomizeVisitor final : public VNVisitor {
if (constrp->itemsp()) expandUniqueElementList(constrp->itemsp());
if (constrp->itemsp()) lowerDistConstraints(taskp, constrp->itemsp());
ConstraintExprVisitor{classp, m_memberMap, constrp->itemsp(), nullptr,
genp, randModeVarp, m_writtenVars};
genp, randModeVarp, m_writtenVars, randomizep};
if (constrp->itemsp()) {
taskp->addStmtsp(wrapIfConstraintMode(
nodep, constrp, constrp->itemsp()->unlinkFrBackWithNext()));

View File

@ -0,0 +1,21 @@
#!/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')
if not test.have_solver:
test.skip("No constraint solver installed")
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,76 @@
// 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
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
// Test: this.randomize() called in derived class with inherited rand members
// and constraints from base class. Verifies IS_RANDOMIZED propagation and
// membersel write_var fallback for ancestor classes.
class sub_cfg_c;
rand bit enabled;
constraint defaults {
soft enabled == 1'b0;
}
endclass
class base_c;
rand sub_cfg_c cfg;
rand int unsigned watchdog;
constraint override_cons {
cfg.enabled == 1'b1;
}
constraint watchdog_range {
watchdog inside {[32'd50:32'd200]};
}
function new();
cfg = new();
endfunction
endclass
// Derived class: no additional rand members, calls this.randomize()
class derived_c extends base_c;
function int do_randomize();
return this.randomize();
endfunction
endclass
// Deep inheritance: grandchild with no rand members
class grandchild_c extends derived_c;
function int do_rand_deep();
return this.randomize();
endfunction
endclass
module t;
initial begin
automatic derived_c d = new();
automatic grandchild_c g = new();
// Test derived class this.randomize()
repeat (20) begin
`checkd(d.do_randomize(), 1)
`checkd(d.cfg.enabled, 1)
`checkd(d.watchdog >= 32'd50 && d.watchdog <= 32'd200, 1)
end
// Test deep inheritance this.randomize()
repeat (20) begin
`checkd(g.do_rand_deep(), 1)
`checkd(g.cfg.enabled, 1)
`checkd(g.watchdog >= 32'd50 && g.watchdog <= 32'd200, 1)
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule