Skip to content

[region-isolation] When RegionIsolation is enabled, delay the preconcurrency import not used diagnostic to the SIL pipeline. #73202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/swift/SIL/SILFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ class SILFunction
/// @_dynamicReplacement(for:) function.
SILFunction *ReplacedFunction = nullptr;

/// The SILDeclRef that this function was created for by SILGen if one exists.
SILDeclRef DeclRef = SILDeclRef();

/// This SILFunction REFerences an ad-hoc protocol requirement witness in
/// order to keep it alive, such that it main be obtained in IRGen. Without
/// this explicit reference, the witness would seem not-used, and not be
Expand Down Expand Up @@ -1114,6 +1117,12 @@ class SILFunction
/// Get the source location of the function.
const SILDebugScope *getDebugScope() const { return DebugScope; }

/// Return the SILDeclRef for this SILFunction if one was assigned by SILGen.
SILDeclRef getDeclRef() const { return DeclRef; }

/// Set the SILDeclRef for this SILFunction. Used mainly by SILGen.
void setDeclRef(SILDeclRef declRef) { DeclRef = declRef; }

/// Get this function's bare attribute.
IsBare_t isBare() const { return IsBare_t(Bare); }
void setBare(IsBare_t isB) { Bare = isB; }
Expand Down Expand Up @@ -1390,6 +1399,9 @@ class SILFunction

ActorIsolation getActorIsolation() const { return actorIsolation; }

/// Return the source file that this SILFunction belongs to if it exists.
SourceFile *getSourceFile() const;

//===--------------------------------------------------------------------===//
// Block List Access
//===--------------------------------------------------------------------===//
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ PASS(DiagnosticDeadFunctionElimination, "sil-diagnostic-dead-function-elim",
"Eliminate dead functions from early specialization optimizations before we run later diagnostics")
SWIFT_FUNCTION_PASS(UpdateBorrowedFrom, "update-borrowed-from",
"Test pass for update borrowed-from instructions")
PASS(DiagnoseUnnecessaryPreconcurrencyImports, "sil-diagnose-unnecessary-preconcurrency-imports",
"Diagnose any preconcurrency imports that Sema and TransferNonSendable did not use")
PASS(PruneVTables, "prune-vtables",
"Mark class methods that do not require vtable dispatch")
PASS_RANGE(AllPasses, AADumper, PruneVTables)
Expand Down
34 changes: 34 additions & 0 deletions include/swift/Sema/Concurrency.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===--- Concurrency.h ----------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// This file defines concurrency utility routines from Sema that are used by
/// later parts of the compiler like the pass pipeline.
///
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SEMA_CONCURRENCY_H
#define SWIFT_SEMA_CONCURRENCY_H

namespace swift {

class SourceFile;

/// If any of the imports in this source file was @preconcurrency but there were
/// no diagnostics downgraded or suppressed due to that @preconcurrency, suggest
/// that the attribute be removed.
void diagnoseUnnecessaryPreconcurrencyImports(SourceFile &sf);

} // namespace swift

#endif
8 changes: 8 additions & 0 deletions lib/SIL/IR/SILFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1189,3 +1189,11 @@ bool SILFunction::argumentMayRead(Operand *argOp, SILValue addr) {

return argumentMayReadFunction({this}, {argOp}, {addr});
}

SourceFile *SILFunction::getSourceFile() const {
auto declRef = getDeclRef();
if (!declRef)
return nullptr;

return declRef.getInnermostDeclContext()->getParentSourceFile();
}
3 changes: 3 additions & 0 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,9 @@ void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F,
// Create a debug scope for the function using astNode as source location.
F->setDebugScope(new (M) SILDebugScope(Loc, F));

// Initialize F with the constant we created for it.
F->setDeclRef(constant);

LLVM_DEBUG(llvm::dbgs() << "lowering ";
F->printName(llvm::dbgs());
llvm::dbgs() << " : ";
Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/Mandatory/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ target_sources(swiftSILOptimizer PRIVATE
ConsumeOperatorCopyableValuesChecker.cpp
PhiStorageOptimizer.cpp
ConstantPropagation.cpp
DiagnoseUnnecessaryPreconcurrencyImports.cpp
DebugInfoCanonicalizer.cpp
DefiniteInitialization.cpp
DIMemoryUseCollector.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===--- DiagnoseUnnecessaryPreconcurrencyImports.cpp ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// This is run after TransferNonSendable and uses Sema infrastructure to
/// determine if in Sema or TransferNonSendable any of the preconcurrency import
/// statements were not used.
///
/// This only runs when RegionIsolation is enabled. If RegionIsolation is
/// disabled, we emit the unnecessary preconcurrency imports earlier during Sema
/// since no later diagnostics will be emitted.
///
/// NOTE: This needs to be a module pass and run after TransferNonSendable so we
/// can guarantee that we have run TransferNonSendable on all functions in our
/// module before this runs.
///
//===----------------------------------------------------------------------===//

#include "swift/AST/SourceFile.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/Sema/Concurrency.h"

using namespace swift;

//===----------------------------------------------------------------------===//
// MARK: Top Level Entrypoint
//===----------------------------------------------------------------------===//

namespace {

class DiagnoseUnnecessaryPreconcurrencyImports : public SILModuleTransform {
void run() override {
// If region isolation is not enabled... return early.
if (!getModule()->getASTContext().LangOpts.hasFeature(
Feature::RegionBasedIsolation))
return;

std::vector<SourceFile *> data;
for (auto &fn : *getModule()) {
auto *sf = fn.getSourceFile();
if (!sf) {
continue;
}

data.push_back(sf);
assert(sf->getBufferID() != -1 && "Must have a buffer id");
}

// Sort unique by filename so our diagnostics are deterministic.
//
// TODO: If we cannot rely upon this, just sort by pointer address. Non
// determinism emission of diagnostics isn't great but it isn't fatal.
sortUnique(data, [](SourceFile *lhs, SourceFile *rhs) -> bool {
return lhs->getBufferID() < rhs->getBufferID();
});

// At this point, we know that we have our sorted unique list of source
// files.
for (auto *sf : data) {
diagnoseUnnecessaryPreconcurrencyImports(*sf);
}
}
};

} // namespace

SILTransform *swift::createDiagnoseUnnecessaryPreconcurrencyImports() {
return new DiagnoseUnnecessaryPreconcurrencyImports();
}
5 changes: 4 additions & 1 deletion lib/SILOptimizer/PassManager/PassPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,11 @@ static void addMandatoryDiagnosticOptPipeline(SILPassPipelinePlan &P) {
P.addTransferNonSendable();

// Now that we have completed running passes that use region analysis, clear
// region analysis.
// region analysis and emit diagnostics for unnecessary preconcurrency
// imports.
P.addRegionAnalysisInvalidationTransform();
P.addDiagnoseUnnecessaryPreconcurrencyImports();

// Lower tuple addr constructor. Eventually this can be merged into later
// passes. This ensures we do not need to update later passes for something
// that is only needed by TransferNonSendable().
Expand Down
7 changes: 2 additions & 5 deletions lib/Sema/TypeCheckConcurrency.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "swift/AST/Expr.h"
#include "swift/AST/Module.h"
#include "swift/AST/Type.h"
#include "swift/Sema/Concurrency.h"

#include <cassert>

namespace swift {
Expand Down Expand Up @@ -487,11 +489,6 @@ bool diagnoseSendabilityErrorBasedOn(
NominalTypeDecl *nominal, SendableCheckContext fromContext,
llvm::function_ref<bool(DiagnosticBehavior)> diagnose);

/// If any of the imports in this source file was @preconcurrency but
/// there were no diagnostics downgraded or suppressed due to that
/// @preconcurrency, suggest that the attribute be removed.
void diagnoseUnnecessaryPreconcurrencyImports(SourceFile &sf);

/// Given a set of custom attributes, pick out the global actor attributes
/// and perform any necessary resolution and diagnostics, returning the
/// global actor attribute and type it refers to (or \c std::nullopt).
Expand Down
6 changes: 5 additions & 1 deletion lib/Sema/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,11 @@ TypeCheckSourceFileRequest::evaluate(Evaluator &eval, SourceFile *SF) const {
SF->typeCheckDelayedFunctions();
}

diagnoseUnnecessaryPreconcurrencyImports(*SF);
// If region based isolation is enabled, we diagnose unnecessary
// preconcurrency imports in the SIL pipeline in the
// DiagnoseUnnecessaryPreconcurrencyImports pass.
if (!Ctx.LangOpts.hasFeature(Feature::RegionBasedIsolation))
diagnoseUnnecessaryPreconcurrencyImports(*SF);
diagnoseUnnecessaryPublicImports(*SF);

// Check to see if there are any inconsistent imports.
Expand Down