summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-stmt.cpp
diff options
context:
space:
mode:
authorsriramm-nv <85252063+sriramm-nv@users.noreply.github.com>2024-04-03 15:10:16 -0700
committerGitHub <noreply@github.com>2024-04-03 15:10:16 -0700
commitf6c49fdb2cc7ead1943d944097220cedd142792f (patch)
tree86f8a09544d89cab007f3168f10396bcee73d12e /source/slang/slang-check-stmt.cpp
parent2768e429e556f3978825beaf71cf361626057135 (diff)
Fix assertions due to malformed switch statements (#3858)
* Fix assertions due to malformed switch statements Fixes the issue #2955 * Checks for multiple case statements with same values * Checks for multiple default cases * Constant-folds case exprs into an Integer value * fix the comments, and updated error code * one-line comment on diagnostic code
Diffstat (limited to 'source/slang/slang-check-stmt.cpp')
-rw-r--r--source/slang/slang-check-stmt.cpp54
1 files changed, 49 insertions, 5 deletions
diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp
index b68465087..729b24d35 100644
--- a/source/slang/slang-check-stmt.cpp
+++ b/source/slang/slang-check-stmt.cpp
@@ -239,6 +239,47 @@ namespace Slang
subContext.checkStmt(stmt->body);
}
+ void SemanticsStmtVisitor::validateCaseStmts(SwitchStmt* stmt, DiagnosticSink* sink)
+ {
+ auto blockStmt = as<BlockStmt>(stmt->body);
+ if (!blockStmt)
+ return;
+
+ auto seqStmt = as<SeqStmt>(blockStmt->body);
+ if (!seqStmt)
+ return;
+
+ bool hasDefaultStmt = false;
+ HashSet<Val*> caseStmtVals;
+ for (auto& sStmt : seqStmt->stmts)
+ {
+ if (auto caseStmt = as<CaseStmt>(sStmt))
+ {
+ // check that all case tags are unique
+ if (caseStmt->exprVal)
+ {
+ // exprVal contains the constant folded expr, that is checked for
+ // uniqueness within the scope of the switch statement.
+ if (!caseStmtVals.add(caseStmt->exprVal))
+ {
+ sink->diagnose(sStmt, Diagnostics::switchDuplicateCases);
+ return;
+ }
+ }
+ }
+ else if (auto defaultStmt = as<DefaultStmt>(sStmt))
+ {
+ // check that there is at most one `default` clause
+ if (hasDefaultStmt)
+ {
+ sink->diagnose(sStmt, Diagnostics::switchMultipleDefault);
+ return;
+ }
+ hasDefaultStmt = true;
+ }
+ }
+ }
+
void SemanticsStmtVisitor::visitSwitchStmt(SwitchStmt* stmt)
{
WithOuterStmt subContext(this, stmt);
@@ -247,16 +288,18 @@ namespace Slang
stmt->condition = CheckExpr(stmt->condition);
subContext.checkStmt(stmt->body);
- // TODO(tfoley): need to check that all case tags are unique
-
- // TODO(tfoley): check that there is at most one `default` clause
+ // check the case value exits within the switch
+ validateCaseStmts(stmt, getSink());
}
void SemanticsStmtVisitor::visitCaseStmt(CaseStmt* stmt)
{
- // TODO(tfoley): Need to coerce to type being switch on,
- // and ensure that value is a compile-time constant
auto expr = CheckExpr(stmt->expr);
+
+ // coerce to type being switch on, and ensure that value is a compile-time constant
+ // The Vals in the AST are pointer-unique, making them easy to check for duplicates
+ // by addeing them to a HashSet.
+ auto exprVal = tryConstantFoldExpr(expr, ConstantFoldingKind::CompileTime, nullptr);
auto switchStmt = FindOuterStmt<SwitchStmt>();
if (!switchStmt)
@@ -270,6 +313,7 @@ namespace Slang
}
stmt->expr = expr;
+ stmt->exprVal = exprVal;
stmt->parentStmt = switchStmt;
}