diff --git a/include/swift/Basic/BlockListAction.def b/include/swift/Basic/BlockListAction.def index e825306545516..1f6ca8cf61345 100644 --- a/include/swift/Basic/BlockListAction.def +++ b/include/swift/Basic/BlockListAction.def @@ -23,5 +23,6 @@ BLOCKLIST_ACTION(ShouldUseBinaryModule) BLOCKLIST_ACTION(ShouldUseTextualModule) BLOCKLIST_ACTION(DowngradeInterfaceVerificationFailure) BLOCKLIST_ACTION(ShouldUseLayoutStringValueWitnesses) +BLOCKLIST_ACTION(ShouldDisableOwnershipVerification) #undef BLOCKLIST_ACTION diff --git a/lib/SIL/Verifier/SILOwnershipVerifier.cpp b/lib/SIL/Verifier/SILOwnershipVerifier.cpp index 85025cfe91ef8..68fd925af65b7 100644 --- a/lib/SIL/Verifier/SILOwnershipVerifier.cpp +++ b/lib/SIL/Verifier/SILOwnershipVerifier.cpp @@ -802,15 +802,24 @@ bool SILValueOwnershipChecker::checkUses() { return true; } +bool disableOwnershipVerification(const SILModule &mod) { + if (DisableOwnershipVerification) + return true; + if (mod.getASTContext().blockListConfig.hasBlockListAction( + mod.getSwiftModule()->getRealName().str(), + BlockListKeyKind::ModuleName, + BlockListAction::ShouldDisableOwnershipVerification)) { + return true; + } + return false; +} + //===----------------------------------------------------------------------===// // Top Level Entrypoints //===----------------------------------------------------------------------===// void SILInstruction::verifyOperandOwnership( SILModuleConventions *silConv) const { - if (DisableOwnershipVerification) - return; - if (isStaticInitializerInst()) return; @@ -831,11 +840,13 @@ void SILInstruction::verifyOperandOwnership( !getFunction()->shouldVerifyOwnership()) return; + if (disableOwnershipVerification(getModule())) + return; + // If we are testing the verifier, bail so we only print errors once when // performing a full verification, instead of additionally in the SILBuilder. if (IsSILOwnershipVerifierTestingEnabled) return; - // If this is a terminator instruction, do not verify in SILBuilder. This is // because when building a new function, one must create the destination block // first which is an unnatural pattern and pretty brittle. @@ -903,9 +914,6 @@ verifySILValueHelper(const SILFunction *f, SILValue value, } void SILValue::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { - if (DisableOwnershipVerification) - return; - // Do not validate SILUndef values. if (isa(*this)) return; @@ -931,6 +939,14 @@ void SILValue::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { } } + // Since we do not have SILUndef, we now know that getFunction() should return + // a real function. Assert in case this assumption is no longer true. + auto *f = (*this)->getFunction(); + assert(f && "Instructions and arguments should have a function"); + + if (disableOwnershipVerification(f->getModule())) + return; + // If we are testing the verifier, bail so we only print errors once when // performing a full verification a function at a time by the // OwnershipVerifierStateDumper pass, instead of additionally in the @@ -938,11 +954,6 @@ void SILValue::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { if (IsSILOwnershipVerifierTestingEnabled) return; - // Since we do not have SILUndef, we now know that getFunction() should return - // a real function. Assert in case this assumption is no longer true. - auto *f = (*this)->getFunction(); - assert(f && "Instructions and arguments should have a function"); - using BehaviorKind = LinearLifetimeChecker::ErrorBehaviorKind; LinearLifetimeChecker::ErrorBuilder errorBuilder( *f, BehaviorKind::PrintMessageAndAssert); @@ -952,7 +963,7 @@ void SILValue::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { } void SILModule::verifyOwnership() const { - if (DisableOwnershipVerification) + if (disableOwnershipVerification(*this)) return; #ifdef NDEBUG @@ -973,8 +984,6 @@ void SILModule::verifyOwnership() const { } void SILFunction::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { - if (DisableOwnershipVerification) - return; if (!getModule().getOptions().VerifySILOwnership) return; @@ -996,6 +1005,9 @@ void SILFunction::verifyOwnership(DeadEndBlocks *deadEndBlocks) const { if (!hasOwnership() || !shouldVerifyOwnership()) return; + if (disableOwnershipVerification(getModule())) + return; + using BehaviorKind = LinearLifetimeChecker::ErrorBehaviorKind; unsigned errorCounter = 0; std::optional errorBuilder; diff --git a/test/SIL/disable_ossa_verification_blocklist.sil b/test/SIL/disable_ossa_verification_blocklist.sil new file mode 100644 index 0000000000000..ebd5280a387da --- /dev/null +++ b/test/SIL/disable_ossa_verification_blocklist.sil @@ -0,0 +1,20 @@ +// RUN: %empty-directory(%t) + +// RUN: echo "---" > %t/blocklist.yml +// RUN: echo "ShouldDisableOwnershipVerification:" >> %t/blocklist.yml +// RUN: echo " ModuleName:" >> %t/blocklist.yml +// RUN: echo " - Foo" >> %t/blocklist.yml + +// RUN: %target-swift-frontend -emit-sil -module-name Foo -blocklist-file %t/blocklist.yml %s | %FileCheck %s + +class Klass {} + +// CHECK-LABEL: sil @invalid_destroy +// CHECK: strong_release +sil [ossa] @invalid_destroy : $@convention(thin) (@guaranteed Klass) -> () { +bb0(%0 : @guaranteed $Klass): + destroy_value %0 : $Klass + %t = tuple () + return %t : $() +} +