Fix crash on overlapping priority case
This commit is contained in:
parent
279b425a57
commit
e0c4c995b9
|
|
@ -290,9 +290,9 @@ class CaseVisitor final : public VNVisitor {
|
|||
const uint32_t mask = nummask.toUInt();
|
||||
const uint32_t val = numval.toUInt();
|
||||
|
||||
uint32_t firstOverlap = 0;
|
||||
const AstConst* overlappedCondp = nullptr;
|
||||
bool foundHit = false;
|
||||
bool foundNewCase = false;
|
||||
const AstConst* firstOverlapConstp = nullptr;
|
||||
uint32_t firstOverlapValue = 0;
|
||||
for (uint32_t i = 0; i < numCases; ++i) {
|
||||
if ((i & mask) != val) continue;
|
||||
|
||||
|
|
@ -303,51 +303,53 @@ class CaseVisitor final : public VNVisitor {
|
|||
caseRecord.itemp = itemp;
|
||||
caseRecord.constp = iconstp;
|
||||
caseRecord.stmtsp = itemp->stmtsp();
|
||||
foundHit = true;
|
||||
foundNewCase = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise record the first overlapping case,
|
||||
// but overlap within the same CaseItem is legal
|
||||
if (!overlappedCondp && caseRecord.itemp != itemp) {
|
||||
firstOverlap = i;
|
||||
overlappedCondp = caseRecord.constp;
|
||||
// There is an overlap. If it's within the same CaseItem, it is legal
|
||||
if (caseRecord.itemp == itemp) continue;
|
||||
|
||||
// Otherwise record the first overlapping case
|
||||
if (!firstOverlapConstp) {
|
||||
firstOverlapConstp = caseRecord.constp;
|
||||
firstOverlapValue = i;
|
||||
m_caseNoOverlaps = false;
|
||||
}
|
||||
}
|
||||
if (!nodep->priorityPragma()) {
|
||||
// If this case statement doesn't have the priority
|
||||
// keyword, we want to warn on any overlap.
|
||||
if (!reportedOverlap && overlappedCondp) {
|
||||
if (nodep->priorityPragma()) {
|
||||
// If this is a priority case, we only want to complain if every possible value
|
||||
// for this item is already hit by some other item. This is true if
|
||||
// 'foundNewCase' is false. 'firstOverlapConstp' is null when the only covering
|
||||
// item is this item itself, which is legal overlap within one item.
|
||||
if (!reportedSubcase && !foundNewCase && firstOverlapConstp) {
|
||||
iconstp->v3warn(CASEOVERLAP,
|
||||
"Case item ignored: every matching value is covered "
|
||||
"by an earlier condition\n"
|
||||
<< iconstp->warnContextPrimary() << '\n'
|
||||
<< firstOverlapConstp->warnOther()
|
||||
<< "... Location of previous condition\n"
|
||||
<< firstOverlapConstp->warnContextPrimary());
|
||||
reportedSubcase = true;
|
||||
}
|
||||
} else {
|
||||
// If this case statement doesn't have the priority keyword,
|
||||
// we want to warn on any overlap.
|
||||
if (!reportedOverlap && firstOverlapConstp) {
|
||||
std::ostringstream examplePattern;
|
||||
if (iconstp->num().isAnyXZ()) {
|
||||
examplePattern << " (example pattern 0x" << std::hex << firstOverlap
|
||||
<< ")";
|
||||
examplePattern << " (example pattern 0x" << std::hex
|
||||
<< firstOverlapValue << ")";
|
||||
}
|
||||
iconstp->v3warn(CASEOVERLAP,
|
||||
"Case conditions overlap"
|
||||
<< examplePattern.str() << "\n"
|
||||
<< iconstp->warnContextPrimary() << '\n'
|
||||
<< overlappedCondp->warnOther()
|
||||
<< firstOverlapConstp->warnOther()
|
||||
<< "... Location of overlapping condition\n"
|
||||
<< overlappedCondp->warnContextSecondary());
|
||||
<< firstOverlapConstp->warnContextSecondary());
|
||||
reportedOverlap = true;
|
||||
}
|
||||
} else {
|
||||
// If this is a priority case, we only want to complain
|
||||
// if every possible value for this item is already hit
|
||||
// by some other item. This is true if foundHit is
|
||||
// false.
|
||||
if (!reportedSubcase && !foundHit) {
|
||||
iconstp->v3warn(CASEOVERLAP,
|
||||
"Case item ignored: every matching value is covered "
|
||||
"by an earlier condition\n"
|
||||
<< iconstp->warnContextPrimary() << '\n'
|
||||
<< overlappedCondp->warnOther()
|
||||
<< "... Location of previous condition\n"
|
||||
<< overlappedCondp->warnContextPrimary());
|
||||
reportedSubcase = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/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(verilator_flags2=['--binary'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
// 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
|
||||
|
||||
// Regression: a `priority` case item whose later condition (INST_B) is fully
|
||||
// subsumed by an earlier condition (INST_A) of the *same* item. Overlap within
|
||||
// a single case item is legal, but this previously crashed V3Case with a null
|
||||
// pointer dereference: the priority "case item ignored" CASEOVERLAP diagnostic
|
||||
// dereferenced 'overlappedCondp', which is null when the only covering item is
|
||||
// the item itself. Must compile cleanly and simulate correctly.
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
|
||||
logic clk = 1'b0;
|
||||
always #5 clk = ~clk;
|
||||
|
||||
logic [1:0] in;
|
||||
logic [1:0] out;
|
||||
|
||||
always_comb begin
|
||||
priority casez (in)
|
||||
2'b1?, // fully subsumes 2'b11 below on the same case clause
|
||||
2'b11: out = 2'b10;
|
||||
2'b0?: out = 2'b01;
|
||||
endcase
|
||||
end
|
||||
|
||||
initial begin
|
||||
in = 2'b00;
|
||||
@(posedge clk);
|
||||
`checkh(out, 2'b01);
|
||||
|
||||
in = 2'b01;
|
||||
@(posedge clk);
|
||||
`checkh(out, 2'b01);
|
||||
|
||||
in = 2'b10;
|
||||
@(posedge clk);
|
||||
`checkh(out, 2'b10);
|
||||
|
||||
in = 2'b11;
|
||||
@(posedge clk);
|
||||
`checkh(out, 2'b10);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue