Skip to content

Commit 60aa76d

Browse files
authored
Merge pull request #73216 from gottesmm/release/6.0-region-iso
[6.0][region-isolation] Fix import pre concurrency support for region isolation
2 parents 1580719 + 3312aa3 commit 60aa76d

16 files changed

+544
-24
lines changed

include/swift/SIL/SILFunction.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ class SILFunction
269269
/// @_dynamicReplacement(for:) function.
270270
SILFunction *ReplacedFunction = nullptr;
271271

272+
/// The SILDeclRef that this function was created for by SILGen if one exists.
273+
SILDeclRef DeclRef = SILDeclRef();
274+
272275
/// This SILFunction REFerences an ad-hoc protocol requirement witness in
273276
/// order to keep it alive, such that it main be obtained in IRGen. Without
274277
/// this explicit reference, the witness would seem not-used, and not be
@@ -1114,6 +1117,12 @@ class SILFunction
11141117
/// Get the source location of the function.
11151118
const SILDebugScope *getDebugScope() const { return DebugScope; }
11161119

1120+
/// Return the SILDeclRef for this SILFunction if one was assigned by SILGen.
1121+
SILDeclRef getDeclRef() const { return DeclRef; }
1122+
1123+
/// Set the SILDeclRef for this SILFunction. Used mainly by SILGen.
1124+
void setDeclRef(SILDeclRef declRef) { DeclRef = declRef; }
1125+
11171126
/// Get this function's bare attribute.
11181127
IsBare_t isBare() const { return IsBare_t(Bare); }
11191128
void setBare(IsBare_t isB) { Bare = isB; }
@@ -1376,6 +1385,9 @@ class SILFunction
13761385

13771386
ActorIsolation getActorIsolation() const { return actorIsolation; }
13781387

1388+
/// Return the source file that this SILFunction belongs to if it exists.
1389+
SourceFile *getSourceFile() const;
1390+
13791391
//===--------------------------------------------------------------------===//
13801392
// Block List Access
13811393
//===--------------------------------------------------------------------===//

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,8 @@ PASS(ReferenceBindingTransform, "sil-reference-binding-transform",
501501
"Check/transform reference bindings")
502502
PASS(DiagnosticDeadFunctionElimination, "sil-diagnostic-dead-function-elim",
503503
"Eliminate dead functions from early specialization optimizations before we run later diagnostics")
504+
PASS(DiagnoseUnnecessaryPreconcurrencyImports, "sil-diagnose-unnecessary-preconcurrency-imports",
505+
"Diagnose any preconcurrency imports that Sema and TransferNonSendable did not use")
504506
PASS(PruneVTables, "prune-vtables",
505507
"Mark class methods that do not require vtable dispatch")
506508
PASS_RANGE(AllPasses, AADumper, PruneVTables)

include/swift/Sema/Concurrency.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===--- Concurrency.h ----------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
///
15+
/// This file defines concurrency utility routines from Sema that are used by
16+
/// later parts of the compiler like the pass pipeline.
17+
///
18+
//===----------------------------------------------------------------------===//
19+
20+
#ifndef SWIFT_SEMA_CONCURRENCY_H
21+
#define SWIFT_SEMA_CONCURRENCY_H
22+
23+
namespace swift {
24+
25+
class SourceFile;
26+
class NominalTypeDecl;
27+
28+
/// If any of the imports in this source file was @preconcurrency but there were
29+
/// no diagnostics downgraded or suppressed due to that @preconcurrency, suggest
30+
/// that the attribute be removed.
31+
void diagnoseUnnecessaryPreconcurrencyImports(SourceFile &sf);
32+
33+
/// Determine whether the given nominal type has an explicit Sendable
34+
/// conformance (regardless of its availability).
35+
bool hasExplicitSendableConformance(NominalTypeDecl *nominal,
36+
bool applyModuleDefault = true);
37+
38+
} // namespace swift
39+
40+
#endif

lib/SIL/IR/SILFunction.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,3 +1189,11 @@ bool SILFunction::argumentMayRead(Operand *argOp, SILValue addr) {
11891189

11901190
return argumentMayReadFunction({this}, {argOp}, {addr});
11911191
}
1192+
1193+
SourceFile *SILFunction::getSourceFile() const {
1194+
auto declRef = getDeclRef();
1195+
if (!declRef)
1196+
return nullptr;
1197+
1198+
return declRef.getInnermostDeclContext()->getParentSourceFile();
1199+
}

lib/SILGen/SILGen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,9 @@ void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F,
12361236
// Create a debug scope for the function using astNode as source location.
12371237
F->setDebugScope(new (M) SILDebugScope(Loc, F));
12381238

1239+
// Initialize F with the constant we created for it.
1240+
F->setDeclRef(constant);
1241+
12391242
LLVM_DEBUG(llvm::dbgs() << "lowering ";
12401243
F->printName(llvm::dbgs());
12411244
llvm::dbgs() << " : ";

lib/SILOptimizer/Mandatory/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ target_sources(swiftSILOptimizer PRIVATE
99
ConsumeOperatorCopyableValuesChecker.cpp
1010
PhiStorageOptimizer.cpp
1111
ConstantPropagation.cpp
12+
DiagnoseUnnecessaryPreconcurrencyImports.cpp
1213
DebugInfoCanonicalizer.cpp
1314
DefiniteInitialization.cpp
1415
DIMemoryUseCollector.cpp
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===--- DiagnoseUnnecessaryPreconcurrencyImports.cpp ---------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
///
15+
/// This is run after TransferNonSendable and uses Sema infrastructure to
16+
/// determine if in Sema or TransferNonSendable any of the preconcurrency import
17+
/// statements were not used.
18+
///
19+
/// This only runs when RegionIsolation is enabled. If RegionIsolation is
20+
/// disabled, we emit the unnecessary preconcurrency imports earlier during Sema
21+
/// since no later diagnostics will be emitted.
22+
///
23+
/// NOTE: This needs to be a module pass and run after TransferNonSendable so we
24+
/// can guarantee that we have run TransferNonSendable on all functions in our
25+
/// module before this runs.
26+
///
27+
//===----------------------------------------------------------------------===//
28+
29+
#include "swift/AST/SourceFile.h"
30+
#include "swift/SILOptimizer/PassManager/Transforms.h"
31+
#include "swift/Sema/Concurrency.h"
32+
33+
using namespace swift;
34+
35+
//===----------------------------------------------------------------------===//
36+
// MARK: Top Level Entrypoint
37+
//===----------------------------------------------------------------------===//
38+
39+
namespace {
40+
41+
class DiagnoseUnnecessaryPreconcurrencyImports : public SILModuleTransform {
42+
void run() override {
43+
// If region isolation is not enabled... return early.
44+
if (!getModule()->getASTContext().LangOpts.hasFeature(
45+
Feature::RegionBasedIsolation))
46+
return;
47+
48+
std::vector<SourceFile *> data;
49+
for (auto &fn : *getModule()) {
50+
auto *sf = fn.getSourceFile();
51+
if (!sf) {
52+
continue;
53+
}
54+
55+
data.push_back(sf);
56+
assert(sf->getBufferID() != -1 && "Must have a buffer id");
57+
}
58+
59+
// Sort unique by filename so our diagnostics are deterministic.
60+
//
61+
// TODO: If we cannot rely upon this, just sort by pointer address. Non
62+
// determinism emission of diagnostics isn't great but it isn't fatal.
63+
sortUnique(data, [](SourceFile *lhs, SourceFile *rhs) -> bool {
64+
return lhs->getBufferID() < rhs->getBufferID();
65+
});
66+
67+
// At this point, we know that we have our sorted unique list of source
68+
// files.
69+
for (auto *sf : data) {
70+
diagnoseUnnecessaryPreconcurrencyImports(*sf);
71+
}
72+
}
73+
};
74+
75+
} // namespace
76+
77+
SILTransform *swift::createDiagnoseUnnecessaryPreconcurrencyImports() {
78+
return new DiagnoseUnnecessaryPreconcurrencyImports();
79+
}

lib/SILOptimizer/Mandatory/TransferNonSendable.cpp

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "swift/AST/ASTWalker.h"
1616
#include "swift/AST/DiagnosticsSIL.h"
1717
#include "swift/AST/Expr.h"
18+
#include "swift/AST/ProtocolConformance.h"
19+
#include "swift/AST/SourceFile.h"
1820
#include "swift/AST/Type.h"
1921
#include "swift/Basic/FrozenMultiMap.h"
2022
#include "swift/Basic/ImmutablePointerSet.h"
@@ -35,6 +37,7 @@
3537
#include "swift/SILOptimizer/PassManager/Transforms.h"
3638
#include "swift/SILOptimizer/Utils/PartitionUtils.h"
3739
#include "swift/SILOptimizer/Utils/VariableNameUtils.h"
40+
#include "swift/Sema/Concurrency.h"
3841
#include "llvm/ADT/DenseMap.h"
3942
#include "llvm/Support/Debug.h"
4043

@@ -55,6 +58,33 @@ using Region = PartitionPrimitives::Region;
5558
// MARK: Utilities
5659
//===----------------------------------------------------------------------===//
5760

61+
static std::optional<DiagnosticBehavior>
62+
getDiagnosticBehaviorLimitForValue(SILValue value) {
63+
auto *nom = value->getType().getNominalOrBoundGenericNominal();
64+
if (!nom)
65+
return {};
66+
67+
auto declRef = value->getFunction()->getDeclRef();
68+
if (!declRef)
69+
return {};
70+
71+
auto *fromDC = declRef.getInnermostDeclContext();
72+
auto attributedImport = nom->findImport(fromDC);
73+
if (!attributedImport ||
74+
!attributedImport->options.contains(ImportFlags::Preconcurrency))
75+
return {};
76+
77+
if (auto *sourceFile = fromDC->getParentSourceFile())
78+
sourceFile->setImportUsedPreconcurrency(*attributedImport);
79+
80+
if (hasExplicitSendableConformance(nom))
81+
return DiagnosticBehavior::Warning;
82+
83+
return attributedImport->module.importedModule->isConcurrencyChecked()
84+
? DiagnosticBehavior::Warning
85+
: DiagnosticBehavior::Ignore;
86+
}
87+
5888
static Expr *inferArgumentExprFromApplyExpr(ApplyExpr *sourceApply,
5989
FullApplySite fai,
6090
const Operand *op) {
@@ -438,14 +468,19 @@ class UseAfterTransferDiagnosticEmitter {
438468
emitUnknownPatternError();
439469
}
440470

471+
std::optional<DiagnosticBehavior> getBehaviorLimit() const {
472+
return getDiagnosticBehaviorLimitForValue(transferOp->get());
473+
}
474+
441475
void
442476
emitNamedIsolationCrossingError(SILLocation loc, Identifier name,
443477
SILIsolationInfo namedValuesIsolationInfo,
444478
ApplyIsolationCrossing isolationCrossing) {
445479
// Emit the short error.
446480
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
447481
name)
448-
.highlight(loc.getSourceRange());
482+
.highlight(loc.getSourceRange())
483+
.limitBehaviorIf(getBehaviorLimit());
449484

450485
// Then emit the note with greater context.
451486
SmallString<64> descriptiveKindStr;
@@ -466,7 +501,8 @@ class UseAfterTransferDiagnosticEmitter {
466501
loc, diag::regionbasedisolation_transfer_yields_race_with_isolation,
467502
inferredType, isolationCrossing.getCallerIsolation(),
468503
isolationCrossing.getCalleeIsolation())
469-
.highlight(loc.getSourceRange());
504+
.highlight(loc.getSourceRange())
505+
.limitBehaviorIf(getBehaviorLimit());
470506
emitRequireInstDiagnostics();
471507
}
472508

@@ -475,7 +511,8 @@ class UseAfterTransferDiagnosticEmitter {
475511
// Emit the short error.
476512
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
477513
name)
478-
.highlight(loc.getSourceRange());
514+
.highlight(loc.getSourceRange())
515+
.limitBehaviorIf(getBehaviorLimit());
479516

480517
// Then emit the note with greater context.
481518
diagnoseNote(
@@ -493,7 +530,8 @@ class UseAfterTransferDiagnosticEmitter {
493530
diag::
494531
regionbasedisolation_transfer_yields_race_stronglytransferred_binding,
495532
inferredType)
496-
.highlight(loc.getSourceRange());
533+
.highlight(loc.getSourceRange())
534+
.limitBehaviorIf(getBehaviorLimit());
497535
emitRequireInstDiagnostics();
498536
}
499537

@@ -502,7 +540,8 @@ class UseAfterTransferDiagnosticEmitter {
502540
diagnoseError(loc,
503541
diag::regionbasedisolation_transfer_yields_race_no_isolation,
504542
inferredType)
505-
.highlight(loc.getSourceRange());
543+
.highlight(loc.getSourceRange())
544+
.limitBehaviorIf(getBehaviorLimit());
506545
emitRequireInstDiagnostics();
507546
}
508547

@@ -513,7 +552,8 @@ class UseAfterTransferDiagnosticEmitter {
513552
// Emit the short error.
514553
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
515554
name)
516-
.highlight(loc.getSourceRange());
555+
.highlight(loc.getSourceRange())
556+
.limitBehaviorIf(getBehaviorLimit());
517557

518558
SmallString<64> descriptiveKindStr;
519559
{
@@ -535,13 +575,15 @@ class UseAfterTransferDiagnosticEmitter {
535575
diagnoseError(loc, diag::regionbasedisolation_isolated_capture_yields_race,
536576
inferredType, isolationCrossing.getCalleeIsolation(),
537577
isolationCrossing.getCallerIsolation())
538-
.highlight(loc.getSourceRange());
578+
.highlight(loc.getSourceRange())
579+
.limitBehaviorIf(getBehaviorLimit());
539580
emitRequireInstDiagnostics();
540581
}
541582

542583
void emitUnknownPatternError() {
543584
diagnoseError(transferOp->getUser(),
544-
diag::regionbasedisolation_unknown_pattern);
585+
diag::regionbasedisolation_unknown_pattern)
586+
.limitBehaviorIf(getBehaviorLimit());
545587
}
546588

547589
private:
@@ -941,20 +983,26 @@ class TransferNonTransferrableDiagnosticEmitter {
941983
return info.nonTransferrable.dyn_cast<SILInstruction *>();
942984
}
943985

986+
std::optional<DiagnosticBehavior> getBehaviorLimit() const {
987+
return getDiagnosticBehaviorLimitForValue(info.transferredOperand->get());
988+
}
989+
944990
/// Return the isolation region info for \p getNonTransferrableValue().
945991
SILIsolationInfo getIsolationRegionInfo() const {
946992
return info.isolationRegionInfo;
947993
}
948994

949995
void emitUnknownPatternError() {
950996
diagnoseError(getOperand()->getUser(),
951-
diag::regionbasedisolation_unknown_pattern);
997+
diag::regionbasedisolation_unknown_pattern)
998+
.limitBehaviorIf(getBehaviorLimit());
952999
}
9531000

9541001
void emitUnknownUse(SILLocation loc) {
9551002
// TODO: This will eventually be an unknown pattern error.
956-
diagnoseError(
957-
loc, diag::regionbasedisolation_task_or_actor_isolated_transferred);
1003+
diagnoseError(loc,
1004+
diag::regionbasedisolation_task_or_actor_isolated_transferred)
1005+
.limitBehaviorIf(getBehaviorLimit());
9581006
}
9591007

9601008
void emitFunctionArgumentApply(SILLocation loc, Type type,
@@ -967,7 +1015,8 @@ class TransferNonTransferrableDiagnosticEmitter {
9671015
diagnoseError(loc, diag::regionbasedisolation_arg_transferred,
9681016
StringRef(descriptiveKindStr), type,
9691017
crossing.getCalleeIsolation())
970-
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
1018+
.highlight(getOperand()->getUser()->getLoc().getSourceRange())
1019+
.limitBehaviorIf(getBehaviorLimit());
9711020
}
9721021

9731022
void emitNamedFunctionArgumentClosure(SILLocation loc, Identifier name,
@@ -995,13 +1044,15 @@ class TransferNonTransferrableDiagnosticEmitter {
9951044
auto diag =
9961045
diag::regionbasedisolation_arg_passed_to_strongly_transferred_param;
9971046
diagnoseError(loc, diag, descriptiveKindStr, type)
998-
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
1047+
.highlight(getOperand()->getUser()->getLoc().getSourceRange())
1048+
.limitBehaviorIf(getBehaviorLimit());
9991049
}
10001050

10011051
void emitNamedOnlyError(SILLocation loc, Identifier name) {
10021052
diagnoseError(loc, diag::regionbasedisolation_named_transfer_yields_race,
10031053
name)
1004-
.highlight(getOperand()->getUser()->getLoc().getSourceRange());
1054+
.highlight(getOperand()->getUser()->getLoc().getSourceRange())
1055+
.limitBehaviorIf(getBehaviorLimit());
10051056
}
10061057

10071058
void emitNamedIsolation(SILLocation loc, Identifier name,
@@ -1176,7 +1227,7 @@ bool TransferNonTransferrableDiagnosticInferrer::run() {
11761227
if (!isolation) {
11771228
// Otherwise, emit a "we don't know error" that tells the user to file a
11781229
// bug.
1179-
diagnoseError(op->getUser(), diag::regionbasedisolation_unknown_pattern);
1230+
diagnosticEmitter.emitUnknownPatternError();
11801231
return false;
11811232
}
11821233
assert(isolation && "Expected non-null");

0 commit comments

Comments
 (0)