Fix pattern type matching against nested aggregates (#7304).

Fixes #7304.
This commit is contained in:
Wilson Snyder
2026-09-13 14:48:07 -04:00
parent e871c3657e
commit e172e94b30
4 changed files with 82 additions and 123 deletions
+1
View File
@@ -39,6 +39,7 @@ Verilator 5.053 devel
* Optimize unnecessary per-vertex allocations in NFA lowering (#8319). [Artur Bieniek, Antmicro Ltd.]
* Optimize duplicate lookup in NFA property recursion guard (#8321). [Artur Bieniek, Antmicro Ltd.]
* Fix array slice crash when used as a bare value (#5132) (#8262). [Marco Frank]
* Fix pattern type matching against nested aggregates (#7304).
* Fix covergroup-internal references multi-threaded ordering (#7779) (#8255). [Matthew Ballance]
* Fix detecting non-inlined awaits in V3Delayed.cpp (#7982). [Igor Zaworski, Antmicro Ltd.]
* Fix phased `solve...before` diversity (#8189) (#8194). [Aditya Shevade]
+5 -2
View File
@@ -5790,7 +5790,7 @@ class WidthVisitor final : public VNVisitor {
if (it == patmap.end()) { // Default or default_type assignment
patp = defaultPatp_patternUOrStruct(nodep, memp, vdtypep, defaultp, dtypemap);
pushDeletep(patp);
patp = defaultPatp_forDType(patp, memp->virtRefDTypep());
patp = defaultPatp_forDType(patp, memp->virtRefDTypep(), dtypemap);
pushDeletep(patp);
} else {
patp = it->second; // Member assignment
@@ -5877,7 +5877,8 @@ class WidthVisitor final : public VNVisitor {
return newp;
}
AstPatMember* defaultPatp_forDType(AstPatMember* defaultp, AstNodeDType* elemDTypep) {
AstPatMember* defaultPatp_forDType(AstPatMember* defaultp, AstNodeDType* elemDTypep,
const DTypeMap& dtypemap = DTypeMap{}) {
AstNodeExpr* const valuep = defaultp->lhssp()->cloneTree(false);
AstNodeDType* const elemDTypeSkipRefp = elemDTypep->skipRefp();
const AstStructDType* const structp = VN_CAST(elemDTypeSkipRefp, StructDType);
@@ -5907,6 +5908,8 @@ class WidthVisitor final : public VNVisitor {
AstPatMember* const nestedDefaultp
= new AstPatMember{defaultp->fileline(), valuep, nullptr, nullptr};
nestedDefaultp->isDefault(true);
// Propagate the outer 'data_type: value' entries into the nested aggregate
for (const auto& entry : dtypemap) nestedDefaultp->addNext(entry.second->cloneTree(false));
AstPattern* const recursivePatternp = new AstPattern{defaultp->fileline(), nestedDefaultp};
return new AstPatMember{defaultp->fileline(), recursivePatternp, nullptr, nullptr};
}
@@ -11,7 +11,7 @@ import vltest_bootstrap
test.scenarios('simulator_st')
test.compile(verilator_flags2=['-Wno-DEPRECATED', '--structs-packed'])
test.compile()
test.execute()
+75 -120
View File
@@ -4,37 +4,30 @@
// SPDX-FileCopyrightText: 2022 Mostafa Gamal
// SPDX-License-Identifier: CC0-1.0
/* verilator lint_off UNPACKED */
// verilog_format: off
`define stop $stop
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
// verilog_format: on
module top();
module t;
typedef struct { // IEEE 1800-2023 5.10
typedef struct { // IEEE 1800-2023 5.10
int a;
shortint b;
} ab_struct;
typedef struct { // IEEE 1800-2023 10.9.2
int x;
int y;
typedef struct { // IEEE 1800-2023 10.9.2
int x;
int y;
} st_struct;
typedef struct { // IEEE 1800-2023 10.9.2
logic [7:0] a;
bit b;
bit signed [31:0] c;
int s;
} sa_struct;
typedef struct { // IEEE 1800-2023 10.9.2
typedef struct { // IEEE 1800-2023 10.9.2
int A;
struct {
int B, C;
} BC1, BC2;
struct {int B, C;} BC1, BC2;
} DEF_struct;
typedef struct { // IEEE 1800-2023 10.9.2
typedef struct { // IEEE 1800-2023 10.9.2
int A;
struct {
int B, C;
@@ -48,137 +41,99 @@ module top();
} BC1;
} HIJ_struct;
// struct ab
ab_struct ab;
ab_struct abkey[1:0];
// struct st
st_struct st;
int k = 1;
// struct sa
sa_struct sa;
// struct DEF
DEF_struct DEF;
// struct HIJ
HIJ_struct HIJ;
initial begin
// struct ab
ab = '{0, 0}; //constant member by position
if (ab.a != 0) $stop;
if (ab.b != 0) $stop;
ab = '{0, 0}; //constant member by position
`checkd(ab.a, 0);
`checkd(ab.b, 0);
ab = '{default: 0}; //default value
if (ab.a != 0) $stop;
if (ab.b != 0) $stop;
ab = '{default: 0}; //default value
`checkd(ab.a, 0);
`checkd(ab.b, 0);
ab = '{int: 1, shortint: 0}; //data type and default value
if (ab.a != 1) $stop;
if (ab.b != 0) $stop;
ab = '{int : 1, shortint : 0}; //data type and default value
`checkd(ab.a, 1);
`checkd(ab.b, 0);
abkey[1:0] = '{'{a:1, b:2}, '{int:2, shortint:3}}; // member: value & data_type: value
if (abkey[1].a != 1) $stop;
if (abkey[1].b != 2) $stop;
if (abkey[0].a != 2) $stop;
if (abkey[0].b != 3) $stop;
abkey[1:0] = '{'{a: 1, b: 2}, '{int : 2, shortint : 3}}; // member: value & data_type: value
`checkd(abkey[1].a, 1);
`checkd(abkey[1].b, 2);
`checkd(abkey[0].a, 2);
`checkd(abkey[0].b, 3);
// struct st
st = '{1, 2+k}; //constant member by position
if (st.x != 1) $stop;
if (st.y != 2+k) $stop;
st = '{1, 2 + k}; //constant member by position
`checkd(st.x, 1);
`checkd(st.y, 2 + k);
st = '{x:2, y:3+k}; //member: value
if (st.x != 2) $stop;
if (st.y != 3+k) $stop;
st = '{x: 2, y: 3 + k}; //member: value
`checkd(st.x, 2);
`checkd(st.y, 3 + k);
st = '{int:2, int:3+k}; //data_type: value override
if (st.x != 3+k) $stop;
if (st.y != 3+k) $stop;
// struct sa
sa = '{default:'1};
if (sa.a != '1) $stop;
if (sa.b != '1) $stop;
if (sa.c != '1) $stop;
if (sa.s != '1) $stop;
sa = '{default:'1, int: 5};
if (sa.a != '1) $stop;
if (sa.b != '1) $stop;
if (sa.c != '1) $stop;
if (sa.s != 5) $stop;
sa = '{default:'1, int: 5, b: 0};
if (sa.a != '1) $stop;
if (sa.b != 0) $stop;
if (sa.c != '1) $stop;
if (sa.s != 5) $stop;
st = '{int : 2, int : 3 + k}; //data_type: value override
`checkd(st.x, 3 + k);
`checkd(st.y, 3 + k);
// struct DEF
DEF = '{A:1, BC1:'{B:2, C:3}, BC2:'{B:4,C:5}};
if (DEF.A != 1) $stop;
if (DEF.BC1.B != 2) $stop;
if (DEF.BC1.C != 3) $stop;
if (DEF.BC2.B != 4) $stop;
if (DEF.BC2.C != 5) $stop;
DEF = '{A: 1, BC1: '{B: 2, C: 3}, BC2: '{B: 4, C: 5}};
`checkd(DEF.A, 1);
`checkd(DEF.BC1.B, 2);
`checkd(DEF.BC1.C, 3);
`checkd(DEF.BC2.B, 4);
`checkd(DEF.BC2.C, 5);
DEF = '{int:0, BC1:'{int:10}, BC2:'{default:5}};
if (DEF.A != 0) $stop;
if (DEF.BC1.B != 10) $stop;
if (DEF.BC1.C != 10) $stop;
if (DEF.BC2.B != 5) $stop;
if (DEF.BC2.C != 5) $stop;
DEF = '{int : 0, BC1: '{int : 10}, BC2: '{default: 5}};
`checkd(DEF.A, 0);
`checkd(DEF.BC1.B, 10);
`checkd(DEF.BC1.C, 10);
`checkd(DEF.BC2.B, 5);
`checkd(DEF.BC2.C, 5);
DEF = '{default:1, BC1:'{int:10}, BC2:'{default:5}};
if (DEF.A != 1) $stop;
if (DEF.BC1.B != 10) $stop;
if (DEF.BC1.C != 10) $stop;
if (DEF.BC2.B != 5) $stop;
if (DEF.BC2.C != 5) $stop;
DEF = '{default: 1, BC1: '{int : 10}, BC2: '{default: 5}};
`checkd(DEF.A, 1);
`checkd(DEF.BC1.B, 10);
`checkd(DEF.BC1.C, 10);
`checkd(DEF.BC2.B, 5);
`checkd(DEF.BC2.C, 5);
DEF = '{default:10};
if (DEF.A != 10) $stop;
if (DEF.BC1.B != 10) $stop;
if (DEF.BC1.C != 10) $stop;
if (DEF.BC2.B != 10) $stop;
if (DEF.BC2.C != 10) $stop;
DEF = '{int:10};
if (DEF.A != 10) $stop;
if (DEF.BC1.B != 10) $stop;
if (DEF.BC1.C != 10) $stop;
if (DEF.BC2.B != 10) $stop;
if (DEF.BC2.C != 10) $stop;
DEF = '{default: 10};
`checkd(DEF.A, 10);
`checkd(DEF.BC1.B, 10);
`checkd(DEF.BC1.C, 10);
`checkd(DEF.BC2.B, 10);
`checkd(DEF.BC2.C, 10);
// struct HIJ
HIJ = '{int:10, default: 5};
if (HIJ.A != 10) $stop;
if (HIJ.BC1.B != 10) $stop;
if (HIJ.BC1.C != 10) $stop;
if (HIJ.BC1.DE1.D != 10) $stop;
if (HIJ.BC1.DE1.E != 10) $stop;
if (HIJ.BC1.DE1.FG1.F != 10) $stop;
if (HIJ.BC1.DE1.FG1.G != 5) $stop;
HIJ = '{int : 10, default: 5};
`checkd(HIJ.A, 10);
`checkd(HIJ.BC1.B, 10);
`checkd(HIJ.BC1.C, 10);
`checkd(HIJ.BC1.DE1.D, 10);
`checkd(HIJ.BC1.DE1.E, 10);
`checkd(HIJ.BC1.DE1.FG1.F, 10);
`checkd(HIJ.BC1.DE1.FG1.G, 5);
HIJ = '{shortint:10, default: 5};
if (HIJ.A != 5) $stop;
if (HIJ.BC1.B != 5) $stop;
if (HIJ.BC1.C != 5) $stop;
if (HIJ.BC1.DE1.D != 5) $stop;
if (HIJ.BC1.DE1.E != 5) $stop;
if (HIJ.BC1.DE1.FG1.F != 5) $stop;
if (HIJ.BC1.DE1.FG1.G != 10) $stop;
HIJ = '{shortint : 10, default: 5};
`checkd(HIJ.A, 5);
`checkd(HIJ.BC1.B, 5);
`checkd(HIJ.BC1.C, 5);
`checkd(HIJ.BC1.DE1.D, 5);
`checkd(HIJ.BC1.DE1.E, 5);
`checkd(HIJ.BC1.DE1.FG1.F, 5);
`checkd(HIJ.BC1.DE1.FG1.G, 10);
$write("*-* All Finished *-*\n");
$finish;