From 3fc70b61d08b744b48e38ca7879024436fc8efd4 Mon Sep 17 00:00:00 2001 From: Matthew Ballance Date: Tue, 2 Dec 2025 19:05:59 -0800 Subject: [PATCH] Fix internal fault when cross-class calling with DPI (#6735) (#6742) Signed-off-by: Matthew Ballance --- src/V3Task.cpp | 16 ++++++--- test_regress/t/t_dpi_inline_new.cpp | 26 +++++++++++++++ test_regress/t/t_dpi_inline_new.py | 19 +++++++++++ test_regress/t/t_dpi_inline_new.v | 51 +++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 test_regress/t/t_dpi_inline_new.cpp create mode 100755 test_regress/t/t_dpi_inline_new.py create mode 100644 test_regress/t/t_dpi_inline_new.v diff --git a/src/V3Task.cpp b/src/V3Task.cpp index bd82d3624..0c53467f4 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1520,14 +1520,22 @@ class TaskVisitor final : public VNVisitor { if (m_inNew) { AstVar* varp = outvscp->varp(); - varp->funcLocal(true); // Create a new var that will be inside the lambda AstVar* newvarp = varp->cloneTree(false); + newvarp->funcLocal(true); - // Replace all references so they point to the new var - lambdap->stmtsp()->foreachAndNext([varp, newvarp](AstVarRef* refp) { - if (refp->varp() == varp) refp->varp(newvarp); + // Create a new VarScope for the new variable + AstVarScope* const newvscp + = new AstVarScope{newvarp->fileline(), m_scopep, newvarp}; + m_scopep->addVarsp(newvscp); + + // Replace all references so they point to the new var and varscope + lambdap->stmtsp()->foreachAndNext([outvscp, newvscp](AstVarRef* refp) { + if (refp->varScopep() == outvscp) { + refp->varScopep(newvscp); + refp->varp(newvscp->varp()); + } }); // Add variable initialization diff --git a/test_regress/t/t_dpi_inline_new.cpp b/test_regress/t/t_dpi_inline_new.cpp new file mode 100644 index 000000000..bb2877cc1 --- /dev/null +++ b/test_regress/t/t_dpi_inline_new.cpp @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: DPI stub for t_dpi_inline_new +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Include the Verilator-generated DPI header so the C prototype matches +// the SystemVerilog import expectations. +#include "Vt_dpi_inline_new__Dpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Stub implementation for _pyhdl_if_PyTuple_GetItem used by pyhdl_if package. +// Returns a null pointer; the SystemVerilog test only checks that the call +// compiles and links. +void* _pyhdl_if_PyTuple_GetItem(void* p0, unsigned long long idx) { + (void)p0; + (void)idx; + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_inline_new.py b/test_regress/t/t_dpi_inline_new.py new file mode 100755 index 000000000..d235c4eb3 --- /dev/null +++ b/test_regress/t/t_dpi_inline_new.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +# Compile the SystemVerilog test with the DPI C stub. +test.compile(v_flags2=["t/t_dpi_inline_new.cpp"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_dpi_inline_new.v b/test_regress/t/t_dpi_inline_new.v new file mode 100644 index 000000000..c14dc4927 --- /dev/null +++ b/test_regress/t/t_dpi_inline_new.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2025 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +package pyhdl_if; + + typedef chandle PyObject; + import "DPI-C" context function PyObject _pyhdl_if_PyTuple_GetItem(input PyObject p0, + input longint unsigned p1); + + function PyObject PyTuple_GetItem(input PyObject p0, input longint unsigned p1); + return _pyhdl_if_PyTuple_GetItem(p0, p1); + endfunction + + class py_object; + function new(PyObject obj); + endfunction + endclass + + class py_tuple; + + function py_object get_item(int idx); + py_object ret = new(PyTuple_GetItem(null, longint'(idx))); + return ret; + endfunction + + endclass + +endpackage + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + import pyhdl_if::*; + + initial begin + py_tuple t0 = new; + py_object o; + o = t0.get_item(1); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule