diff --git a/lib/Dialect/FIRRTL/FIRRTLOps.cpp b/lib/Dialect/FIRRTL/FIRRTLOps.cpp index 05148af52b33..3f585c1c9f0d 100644 --- a/lib/Dialect/FIRRTL/FIRRTLOps.cpp +++ b/lib/Dialect/FIRRTL/FIRRTLOps.cpp @@ -318,7 +318,9 @@ bool firrtl::hasDontTouch(Value value) { if (auto *op = value.getDefiningOp()) return hasDontTouch(op); auto arg = dyn_cast(value); - auto module = cast(arg.getOwner()->getParentOp()); + auto module = dyn_cast(arg.getOwner()->getParentOp()); + if (!module) + return false; return (module.getPortSymbolAttr(arg.getArgNumber())) || AnnotationSet::forPort(module, arg.getArgNumber()).hasDontTouch(); } diff --git a/test/Dialect/FIRRTL/imdce.mlir b/test/Dialect/FIRRTL/imdce.mlir index 934769d4ea00..02811d5efb3c 100644 --- a/test/Dialect/FIRRTL/imdce.mlir +++ b/test/Dialect/FIRRTL/imdce.mlir @@ -606,3 +606,17 @@ firrtl.circuit "FormalMarkerIsUse" { firrtl.formal @Test, @Foo {} "some_unknown_dialect.op"() { magic = @Bar, other = @Uninstantiated } : () -> () } + +// ----- + +// Block arguments on operations that aren't modules, e.g. contracts, must not +// crash the `firrtl::hasDontTouch` query. +// CHECK-LABEL: firrtl.circuit "NonModuleBlockArgsMustNotCrash" +firrtl.circuit "NonModuleBlockArgsMustNotCrash" { + firrtl.module @NonModuleBlockArgsMustNotCrash(in %a: !firrtl.uint<42>, out %b: !firrtl.uint<42>) { + %0 = firrtl.contract %a : !firrtl.uint<42> { + ^bb0(%arg0: !firrtl.uint<42>): + } + firrtl.matchingconnect %b, %0 : !firrtl.uint<42> + } +}