Fix function-in-constraint internal error on bare port VarRef return (#7473) (#7480)

Fixes #7473.
This commit is contained in:
Yilou Wang 2026-04-23 16:47:39 +02:00 committed by GitHub
parent 3149f43372
commit ae642facf5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 122 additions and 2 deletions

View File

@ -2560,12 +2560,23 @@ class ConstraintExprVisitor final : public VNVisitor {
const V3TaskConnects tconnects
= V3Task::taskConnects(nodep, funcp->stmtsp(), nullptr, false);
// Clone return expression, substitute params with args
AstNodeExpr* const inlinedp = retExprp->cloneTreePure(false);
// Clone return expression, substitute params with args.
// Track the root via a local pointer: when the root itself is a VarRef to a port
// (e.g. body `F = d;`), the cloned root has no back pointer, so foreach's
// replaceWith would trip the "no back" assertion -- substitute the root pointer
// directly instead.
AstNodeExpr* inlinedp = retExprp->cloneTreePure(false);
for (const auto& tconnect : tconnects) {
const AstVar* const portp = tconnect.first;
AstArg* const argp = tconnect.second;
if (!argp || !argp->exprp()) continue;
if (AstVarRef* const rootRefp = VN_CAST(inlinedp, VarRef)) {
if (rootRefp->varp() == portp) {
inlinedp = argp->exprp()->cloneTreePure(false);
VL_DO_DANGLING(rootRefp->deleteTree(), rootRefp);
continue;
}
}
inlinedp->foreach([&](AstVarRef* refp) {
if (refp->varp() == portp) {
refp->replaceWith(argp->exprp()->cloneTreePure(false));

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,88 @@
// 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
class FassignBody;
rand int b1;
rand int b2;
function int F(input int d);
F = d;
endfunction
constraint c1 {b1 inside {[4'd1 : 4'd9]};}
constraint c2 {b2 == F(b1);}
endclass
class Freturn;
rand int b1;
rand int b2;
function int F(input int d);
return d;
endfunction
constraint c1 {b1 inside {[4'd1 : 4'd9]};}
constraint c2 {b2 == F(b1);}
endclass
class Fmultiarg;
rand int b1;
rand int b2;
rand int b3;
function int F(input int x, input int y);
F = y;
endfunction
constraint c1 {b1 inside {[4'd1 : 4'd9]};}
constraint c2 {b2 inside {[8'd20 : 8'd40]};}
constraint c3 {b3 == F(b1, b2);}
endclass
class Fnonrand;
rand int b2;
int k;
function int F(input int d);
F = d;
endfunction
constraint c {b2 == F(k);}
endclass
module t;
FassignBody o1;
Freturn o2;
Fmultiarg o3;
Fnonrand o4;
int rand_ok;
initial begin
o1 = new;
o2 = new;
o3 = new;
o4 = new;
repeat (20) begin
rand_ok = o1.randomize();
`checkd(rand_ok, 1)
`checkd(o1.b2, o1.b1)
rand_ok = o2.randomize();
`checkd(rand_ok, 1)
`checkd(o2.b2, o2.b1)
rand_ok = o3.randomize();
`checkd(rand_ok, 1)
`checkd(o3.b3, o3.b2)
o4.k = $urandom_range(32'd100, 32'd1);
rand_ok = o4.randomize();
`checkd(rand_ok, 1)
`checkd(o4.b2, o4.k)
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule