Fix extern class method rejects matching virtual interface argument type #8525 (#8526)

This commit is contained in:
Kristof Marien
2026-09-29 16:53:54 -04:00
committed by GitHub
parent 68439fbb72
commit feb1f64be8
6 changed files with 276 additions and 1 deletions
+8 -1
View File
@@ -1010,7 +1010,14 @@ public:
void dumpJson(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; }
bool similarDTypeNode(const AstNodeDType* samep) const override { return this == samep; }
bool similarDTypeNode(const AstNodeDType* samep) const override {
// Each occurrence of a virtual interface type parses to its own node,
// so pointer identity is insufficient; compare the referenced
// interface instead, same equivalence as AstNode::computeCastable uses.
const AstIfaceRefDType* const asamep = VN_DBG_AS(samep, IfaceRefDType);
return ifaceViaCellp() && ifaceViaCellp() == asamep->ifaceViaCellp()
&& modportName() == asamep->modportName() && isVirtual() == asamep->isVirtual();
}
int widthAlignBytes() const override { return 0; }
int widthTotalBytes() const override { return 0; }
bool isVirtual() const { return m_virtual; }
@@ -0,0 +1,65 @@
%Error-PROTOTYPEMIS: t/t_class_extern_vif_mismatch_bad.v:21:50: In prototype for 'drive_modport_bad', argument 'bus' data-type does not match out-of-block declaration's data-type (IEEE 1800-2023 8.24)
: ... note: In instance 't'
: ... Prototype data type: 'IFACEREFDTYPE'
: ... Declaration data type: 'IFACEREFDTYPE'
21 | extern function void drive_modport_bad(virtual Bus.Source bus);
| ^~~
t/t_class_extern_vif_mismatch_bad.v:30:49: ... Location of out-of-block declaration
30 | function void Driver::drive_modport_bad(virtual Bus.Sink bus);
| ^~~
... For error description see https://verilator.org/warn/PROTOTYPEMIS?v=latest
%Error-PROTOTYPEMIS: t/t_class_extern_vif_mismatch_bad.v:22:48: In prototype for 'drive_iface_bad', argument 'bus' data-type does not match out-of-block declaration's data-type (IEEE 1800-2023 8.24)
: ... note: In instance 't'
: ... Prototype data type: 'IFACEREFDTYPE'
: ... Declaration data type: 'IFACEREFDTYPE'
22 | extern function void drive_iface_bad(virtual Bus bus);
| ^~~
t/t_class_extern_vif_mismatch_bad.v:33:47: ... Location of out-of-block declaration
33 | function void Driver::drive_iface_bad(virtual OtherBus bus);
| ^~~~~~~~
%Error-PROTOTYPEMIS: t/t_class_extern_vif_mismatch_bad.v:23:48: In prototype for 'drive_param_bad', argument 'bus' data-type does not match out-of-block declaration's data-type (IEEE 1800-2023 8.24)
: ... note: In instance 't'
: ... Prototype data type: 'IFACEREFDTYPE'
: ... Declaration data type: 'IFACEREFDTYPE'
23 | extern function void drive_param_bad(virtual Bus #(7) bus);
| ^~~
t/t_class_extern_vif_mismatch_bad.v:36:47: ... Location of out-of-block declaration
36 | function void Driver::drive_param_bad(virtual Bus #(8) bus);
| ^~~
%Error-PROTOTYPEMIS: t/t_class_extern_vif_mismatch_bad.v:24:64: In prototype for 'drive_queue_bad', argument 'buses' data-type does not match out-of-block declaration's data-type (IEEE 1800-2023 8.24)
: ... note: In instance 't'
: ... Prototype data type: 'IFACEREFDTYPE$[$]'
: ... Declaration data type: 'IFACEREFDTYPE$[$]'
24 | extern function void drive_queue_bad(virtual Bus.Source buses[$]);
| ^
t/t_class_extern_vif_mismatch_bad.v:39:61: ... Location of out-of-block declaration
39 | function void Driver::drive_queue_bad(virtual Bus.Sink buses[$]);
| ^
%Error-PROTOTYPEMIS: t/t_class_extern_vif_mismatch_bad.v:25:55: In prototype for 'drive_dyn_bad', argument 'buses' data-type does not match out-of-block declaration's data-type (IEEE 1800-2023 8.24)
: ... note: In instance 't'
: ... Prototype data type: 'IFACEREFDTYPE$[]'
: ... Declaration data type: 'IFACEREFDTYPE$[]'
25 | extern function void drive_dyn_bad(virtual Bus buses[]);
| ^
t/t_class_extern_vif_mismatch_bad.v:42:59: ... Location of out-of-block declaration
42 | function void Driver::drive_dyn_bad(virtual OtherBus buses[]);
| ^
%Error-PROTOTYPEMIS: t/t_class_extern_vif_mismatch_bad.v:26:69: In prototype for 'drive_assoc_bad', argument 'buses' data-type does not match out-of-block declaration's data-type (IEEE 1800-2023 8.24)
: ... note: In instance 't'
: ... Prototype data type: 'IFACEREFDTYPE$[int]'
: ... Declaration data type: 'IFACEREFDTYPE$[int]'
26 | extern function void drive_assoc_bad(virtual Bus #(7).Source buses[int]);
| ^
t/t_class_extern_vif_mismatch_bad.v:45:68: ... Location of out-of-block declaration
45 | function void Driver::drive_assoc_bad(virtual Bus #(8).Source buses[int]);
| ^
%Error-PROTOTYPEMIS: t/t_class_extern_vif_mismatch_bad.v:27:27: In prototype for 'get_bus_bad', return data type does not match out-of-block declaration data-type (IEEE 1800-2023 8.24)
: ... note: In instance 't'
: ... Prototype data type: 'IFACEREFDTYPE'
: ... Declaration data type: 'IFACEREFDTYPE'
27 | extern function virtual Bus.Source get_bus_bad();
| ^~~
t/t_class_extern_vif_mismatch_bad.v:48:18: ... Location of out-of-block declaration
48 | function virtual Bus.Sink Driver::get_bus_bad();
| ^~~
%Error: Exiting due to
+16
View File
@@ -0,0 +1,16 @@
#!/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('linter')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()
@@ -0,0 +1,52 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
interface Bus #(
parameter int WIDTH = 1
);
logic [WIDTH-1:0] value;
modport Source(output value);
modport Sink(input value);
endinterface
interface OtherBus;
logic value;
endinterface
class Driver;
extern function void drive_modport_bad(virtual Bus.Source bus); // <--- Error (modport)
extern function void drive_iface_bad(virtual Bus bus); // <--- Error (interface)
extern function void drive_param_bad(virtual Bus #(7) bus); // <--- Error (parameter)
extern function void drive_queue_bad(virtual Bus.Source buses[$]); // <--- Error (modport)
extern function void drive_dyn_bad(virtual Bus buses[]); // <--- Error (interface)
extern function void drive_assoc_bad(virtual Bus #(7).Source buses[int]); // <--- Error (parameter)
extern function virtual Bus.Source get_bus_bad(); // <--- Error (return modport)
endclass
function void Driver::drive_modport_bad(virtual Bus.Sink bus);
endfunction
function void Driver::drive_iface_bad(virtual OtherBus bus);
endfunction
function void Driver::drive_param_bad(virtual Bus #(8) bus);
endfunction
function void Driver::drive_queue_bad(virtual Bus.Sink buses[$]);
endfunction
function void Driver::drive_dyn_bad(virtual OtherBus buses[]);
endfunction
function void Driver::drive_assoc_bad(virtual Bus #(8).Source buses[int]);
endfunction
function virtual Bus.Sink Driver::get_bus_bad();
endfunction
module t;
endmodule
+16
View File
@@ -0,0 +1,16 @@
#!/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()
@@ -0,0 +1,119 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// 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
interface Bus #(
parameter int WIDTH = 1
);
logic [WIDTH-1:0] value;
modport Source(output value);
endinterface
typedef virtual Bus #(7).Source SourceBus;
class Driver;
extern function void drive_external(virtual Bus bus, logic value);
extern function void drive_parameter(virtual Bus #(7) bus, logic [6:0] value);
extern function void drive_modport(virtual Bus #(7).Source bus, logic [6:0] value);
extern function void drive_array(virtual Bus #(7).Source buses[2], logic [6:0] value);
extern function void drive_queue(virtual Bus #(7).Source buses[$], logic [6:0] value);
extern function void drive_dyn(virtual Bus #(7).Source buses[], logic [6:0] value);
extern function void drive_assoc(virtual Bus #(7).Source buses[int], logic [6:0] value);
extern function SourceBus get_bus(SourceBus bus);
function void drive_inline(virtual Bus bus, logic value);
bus.value = value;
endfunction
endclass
function void Driver::drive_external(virtual Bus bus, logic value);
bus.value = value;
endfunction
function void Driver::drive_parameter(virtual Bus #(7) bus, logic [6:0] value);
bus.value = value;
endfunction
function void Driver::drive_modport(virtual Bus #(7).Source bus, logic [6:0] value);
bus.value = value;
endfunction
function void Driver::drive_array(virtual Bus #(7).Source buses[2], logic [6:0] value);
buses[1].value = value;
endfunction
function void Driver::drive_queue(virtual Bus #(7).Source buses[$], logic [6:0] value);
buses[1].value = value;
endfunction
function void Driver::drive_dyn(virtual Bus #(7).Source buses[], logic [6:0] value);
buses[1].value = value;
endfunction
function void Driver::drive_assoc(virtual Bus #(7).Source buses[int], logic [6:0] value);
buses[7].value = value;
endfunction
function SourceBus Driver::get_bus(SourceBus bus);
return bus;
endfunction
module t;
Bus bus();
Bus #(7) parameter_bus();
Bus #(7) bus_array[2]();
Driver driver = new;
initial begin
automatic SourceBus returned_bus;
automatic virtual Bus #(7).Source queue_buses[$];
automatic virtual Bus #(7).Source dyn_buses[];
automatic virtual Bus #(7).Source assoc_buses[int];
bus.value = 1'b0;
driver.drive_inline(bus, 1'b1);
`checkd(bus.value, 1)
driver.drive_external(bus, 1'b0);
`checkd(bus.value, 0)
driver.drive_parameter(parameter_bus, 7'd31);
`checkd(parameter_bus.value, 31)
driver.drive_modport(parameter_bus.Source, 7'd47);
`checkd(parameter_bus.value, 47)
driver.drive_array(bus_array, 7'd63);
`checkd(bus_array[1].value, 63)
queue_buses.push_back(parameter_bus.Source);
queue_buses.push_back(bus_array[0].Source);
driver.drive_queue(queue_buses, 7'd15);
`checkd(bus_array[0].value, 15)
dyn_buses = new[2];
dyn_buses[0] = parameter_bus.Source;
dyn_buses[1] = bus_array[1].Source;
driver.drive_dyn(dyn_buses, 7'd23);
`checkd(bus_array[1].value, 23)
assoc_buses[7] = parameter_bus.Source;
driver.drive_assoc(assoc_buses, 7'd39);
`checkd(parameter_bus.value, 39)
returned_bus = driver.get_bus(parameter_bus.Source);
returned_bus.value = 7'd79;
`checkd(parameter_bus.value, 79)
$write("*-* All Finished *-*\n");
$finish;
end
endmodule