mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #77238 from gottesmm/region_isolation_refactoring
[region-isolation] Refactor code so that I can more easily add additional error kinds
This commit is contained in:
63
include/swift/SILOptimizer/Utils/PartitionOpError.def
Normal file
63
include/swift/SILOptimizer/Utils/PartitionOpError.def
Normal file
@@ -0,0 +1,63 @@
|
||||
//===--- PartitionOpError.def ----------------------------*- C++ -*--------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// This file contains macros for creating PartitionOpErrors for use with
|
||||
/// SendNonSendable. This just makes it easier to add these errors without
|
||||
/// needing to write so much boielr plate.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef PARTITION_OP_ERROR
|
||||
#define PARTITION_OP_ERROR(Name)
|
||||
#endif
|
||||
|
||||
/// An error created if we discover a value was locally used after it
|
||||
/// was already sent.
|
||||
///
|
||||
/// The arguments in the type are:
|
||||
///
|
||||
/// 1. The PartitionOp that required the element to be alive.
|
||||
///
|
||||
/// 2. The element in the PartitionOp that was asked to be alive.
|
||||
///
|
||||
/// 3. The operand of the instruction that originally transferred the
|
||||
/// region. Can be used to get the immediate value transferred or the
|
||||
/// transferring instruction.
|
||||
PARTITION_OP_ERROR(LocalUseAfterSend)
|
||||
|
||||
/// This is called if we detect a never sendable element that was actually sent.
|
||||
///
|
||||
/// E.x.: passing a main actor exposed value to a sending parameter.
|
||||
PARTITION_OP_ERROR(SentNeverSendable)
|
||||
|
||||
/// This is emitted when a never sendable value is passed into a sending
|
||||
/// result. The sending result will be viewed in our caller as disconnected and
|
||||
/// able to be sent.
|
||||
PARTITION_OP_ERROR(AssignNeverSendableIntoSendingResult)
|
||||
|
||||
/// This is emitted when an inout sending parameter has been sent in a function
|
||||
/// body but has not been reinitialized at the end of the function.
|
||||
PARTITION_OP_ERROR(InOutSendingNotInitializedAtExit)
|
||||
|
||||
/// This is emitted when an inout sending parameter has been assigned a
|
||||
/// non-disconnected value (e.x.: a value exposed to main actor isolated code)
|
||||
/// at end of function without being reinitialized with something disconnected.
|
||||
PARTITION_OP_ERROR(InOutSendingNotDisconnectedAtExit)
|
||||
|
||||
/// Used to signify an "unknown code pattern" has occured while performing
|
||||
/// dataflow.
|
||||
///
|
||||
/// DISCUSSION: Our dataflow cannot emit errors itself so this is a callback
|
||||
/// to our user so that we can emit that error as we process.
|
||||
PARTITION_OP_ERROR(UnknownCodePattern)
|
||||
|
||||
#undef PARTITION_OP_ERROR
|
||||
@@ -460,7 +460,7 @@ enum class PartitionOpKind : uint8_t {
|
||||
/// parameter is reinitialized with a disconnected value.
|
||||
///
|
||||
/// Takes one parameter, the inout parameter that we need to check.
|
||||
RequireInOutSendingAtFunctionExit,
|
||||
InOutSendingAtFunctionExit,
|
||||
};
|
||||
|
||||
/// PartitionOp represents a primitive operation that can be performed on
|
||||
@@ -568,9 +568,9 @@ public:
|
||||
return PartitionOp(PartitionOpKind::UnknownPatternError, elt, sourceInst);
|
||||
}
|
||||
|
||||
static PartitionOp
|
||||
RequireInOutSendingAtFunctionExit(Element elt, SILInstruction *sourceInst) {
|
||||
return PartitionOp(PartitionOpKind::RequireInOutSendingAtFunctionExit, elt,
|
||||
static PartitionOp InOutSendingAtFunctionExit(Element elt,
|
||||
SILInstruction *sourceInst) {
|
||||
return PartitionOp(PartitionOpKind::InOutSendingAtFunctionExit, elt,
|
||||
sourceInst);
|
||||
}
|
||||
|
||||
@@ -943,6 +943,143 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
/// Swift style enum we use to decouple and reduce boilerplate in between the
|
||||
/// diagnostic and non-diagnostic part of the infrastructure.
|
||||
class PartitionOpError {
|
||||
public:
|
||||
using Element = PartitionPrimitives::Element;
|
||||
using Region = PartitionPrimitives::Region;
|
||||
|
||||
enum Kind {
|
||||
#define PARTITION_OP_ERROR(NAME) NAME,
|
||||
#include "PartitionOpError.def"
|
||||
};
|
||||
|
||||
struct UnknownCodePatternError {
|
||||
const PartitionOp *op;
|
||||
|
||||
UnknownCodePatternError(const PartitionOp &op) : op(&op) {}
|
||||
};
|
||||
|
||||
struct LocalUseAfterSendError {
|
||||
const PartitionOp *op;
|
||||
Element sentElement;
|
||||
Operand *sendingOp;
|
||||
|
||||
LocalUseAfterSendError(const PartitionOp &op, Element elt,
|
||||
Operand *sendingOp)
|
||||
: op(&op), sentElement(elt), sendingOp(sendingOp) {}
|
||||
};
|
||||
|
||||
struct SentNeverSendableError {
|
||||
const PartitionOp *op;
|
||||
Element sentElement;
|
||||
SILDynamicMergedIsolationInfo isolationRegionInfo;
|
||||
|
||||
SentNeverSendableError(const PartitionOp &op, Element sentElement,
|
||||
SILDynamicMergedIsolationInfo isolationRegionInfo)
|
||||
: op(&op), sentElement(sentElement),
|
||||
isolationRegionInfo(isolationRegionInfo) {}
|
||||
};
|
||||
|
||||
struct AssignNeverSendableIntoSendingResultError {
|
||||
const PartitionOp *op;
|
||||
Element destElement;
|
||||
SILFunctionArgument *destValue;
|
||||
Element srcElement;
|
||||
SILValue srcValue;
|
||||
SILDynamicMergedIsolationInfo srcIsolationRegionInfo;
|
||||
|
||||
AssignNeverSendableIntoSendingResultError(
|
||||
const PartitionOp &op, Element destElement,
|
||||
SILFunctionArgument *destValue, Element srcElement, SILValue srcValue,
|
||||
SILDynamicMergedIsolationInfo srcIsolationRegionInfo)
|
||||
: op(&op), destElement(destElement), destValue(destValue),
|
||||
srcElement(srcElement), srcValue(srcValue),
|
||||
srcIsolationRegionInfo(srcIsolationRegionInfo) {}
|
||||
};
|
||||
|
||||
struct InOutSendingNotInitializedAtExitError {
|
||||
const PartitionOp *op;
|
||||
Element sentElement;
|
||||
Operand *sendingOp;
|
||||
|
||||
InOutSendingNotInitializedAtExitError(const PartitionOp &op, Element elt,
|
||||
Operand *sendingOp)
|
||||
: op(&op), sentElement(elt), sendingOp(sendingOp) {}
|
||||
};
|
||||
|
||||
struct InOutSendingNotDisconnectedAtExitError {
|
||||
const PartitionOp *op;
|
||||
Element inoutSendingElement;
|
||||
SILDynamicMergedIsolationInfo isolationInfo;
|
||||
|
||||
InOutSendingNotDisconnectedAtExitError(
|
||||
const PartitionOp &op, Element elt,
|
||||
SILDynamicMergedIsolationInfo isolation)
|
||||
: op(&op), inoutSendingElement(elt), isolationInfo(isolation) {}
|
||||
};
|
||||
|
||||
#define PARTITION_OP_ERROR(NAME) \
|
||||
static_assert(std::is_copy_constructible_v<NAME##Error>, \
|
||||
#NAME " must be copy constructable");
|
||||
#include "PartitionOpError.def"
|
||||
#define PARTITION_OP_ERROR(NAME) \
|
||||
static_assert(std::is_copy_assignable_v<NAME##Error>, \
|
||||
#NAME " must be copy assignable");
|
||||
#include "PartitionOpError.def"
|
||||
|
||||
private:
|
||||
Kind kind;
|
||||
std::variant<
|
||||
#define PARTITION_OP_ERROR(NAME) NAME##Error,
|
||||
#include "PartitionOpError.def"
|
||||
bool // sentinel value to avoid syntax issues.
|
||||
>
|
||||
data;
|
||||
|
||||
public:
|
||||
#define PARTITION_OP_ERROR(NAME) \
|
||||
PartitionOpError(NAME##Error error) : kind(Kind::NAME), data(error) {}
|
||||
#include "PartitionOpError.def"
|
||||
|
||||
PartitionOpError(const PartitionOpError &error)
|
||||
: kind(error.kind), data(error.data) {
|
||||
switch (getKind()) {
|
||||
#define PARTITION_OP_ERROR(NAME) \
|
||||
case NAME: \
|
||||
assert(std::holds_alternative<NAME##Error>(data) && \
|
||||
"Data has value that does not match kind?!"); \
|
||||
break;
|
||||
#include "PartitionOpError.def"
|
||||
}
|
||||
}
|
||||
|
||||
PartitionOpError &operator=(const PartitionOpError &error) {
|
||||
kind = error.kind;
|
||||
data = error.data;
|
||||
|
||||
switch (getKind()) {
|
||||
#define PARTITION_OP_ERROR(NAME) \
|
||||
case NAME: \
|
||||
assert(std::holds_alternative<NAME##Error>(data) && \
|
||||
"Data has value that does not match kind?!"); \
|
||||
break;
|
||||
#include "PartitionOpError.def"
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
#define PARTITION_OP_ERROR(NAME) \
|
||||
NAME##Error get##NAME##Error() const { \
|
||||
assert(getKind() == Kind::NAME); \
|
||||
return std::get<NAME##Error>(data); \
|
||||
}
|
||||
#include "PartitionOpError.def"
|
||||
};
|
||||
|
||||
/// A data structure that applies a series of PartitionOps to a single Partition
|
||||
/// that it modifies.
|
||||
///
|
||||
@@ -961,6 +1098,10 @@ public:
|
||||
using TransferringOperandSetFactory =
|
||||
Partition::TransferringOperandSetFactory;
|
||||
|
||||
#define PARTITION_OP_ERROR(NAME) \
|
||||
using NAME##Error = PartitionOpError::NAME##Error;
|
||||
#include "PartitionOpError.def"
|
||||
|
||||
protected:
|
||||
TransferringOperandSetFactory &ptrSetFactory;
|
||||
TransferringOperandToStateMap &operandToStateMap;
|
||||
@@ -979,56 +1120,7 @@ public:
|
||||
return asImpl().shouldEmitVerboseLogging();
|
||||
}
|
||||
|
||||
/// Call handleUnknownCodePattern on our CRTP subclass.
|
||||
void handleUnknownCodePattern(const PartitionOp &op) const {
|
||||
return asImpl().handleUnknownCodePattern(op);
|
||||
}
|
||||
|
||||
/// Call handleLocalUseAfterTransfer on our CRTP subclass.
|
||||
void handleLocalUseAfterTransfer(const PartitionOp &op, Element elt,
|
||||
Operand *transferringOp) const {
|
||||
return asImpl().handleLocalUseAfterTransfer(op, elt, transferringOp);
|
||||
}
|
||||
|
||||
/// Call handleTransferNonTransferrable on our CRTP subclass.
|
||||
void handleTransferNonTransferrable(
|
||||
const PartitionOp &op, Element elt,
|
||||
SILDynamicMergedIsolationInfo isolationRegionInfo) const {
|
||||
return asImpl().handleTransferNonTransferrable(op, elt,
|
||||
isolationRegionInfo);
|
||||
}
|
||||
/// Just call our CRTP subclass.
|
||||
void handleTransferNonTransferrable(
|
||||
const PartitionOp &op, Element elt, Element otherElement,
|
||||
SILDynamicMergedIsolationInfo isolationRegionInfo) const {
|
||||
return asImpl().handleTransferNonTransferrable(op, elt, otherElement,
|
||||
isolationRegionInfo);
|
||||
}
|
||||
|
||||
/// Just call our CRTP subclass.
|
||||
void handleAssignTransferNonTransferrableIntoSendingResult(
|
||||
const PartitionOp &op, Element destElement,
|
||||
SILFunctionArgument *destValue, Element srcElement, SILValue srcValue,
|
||||
SILDynamicMergedIsolationInfo srcIsolationRegionInfo) const {
|
||||
return asImpl().handleAssignTransferNonTransferrableIntoSendingResult(
|
||||
op, destElement, destValue, srcElement, srcValue,
|
||||
srcIsolationRegionInfo);
|
||||
}
|
||||
|
||||
/// Call our CRTP subclass.
|
||||
void handleInOutSendingNotInitializedAtExitError(
|
||||
const PartitionOp &op, Element elt, Operand *transferringOp) const {
|
||||
return asImpl().handleInOutSendingNotInitializedAtExitError(op, elt,
|
||||
transferringOp);
|
||||
}
|
||||
|
||||
/// Call our CRTP subclass.
|
||||
void handleInOutSendingNotDisconnectedAtExitError(
|
||||
const PartitionOp &op, Element elt,
|
||||
SILDynamicMergedIsolationInfo isolation) const {
|
||||
return asImpl().handleInOutSendingNotDisconnectedAtExitError(op, elt,
|
||||
isolation);
|
||||
}
|
||||
void handleError(PartitionOpError error) { asImpl().handleError(error); }
|
||||
|
||||
/// Call isActorDerived on our CRTP subclass.
|
||||
bool isActorDerived(Element elt) const {
|
||||
@@ -1117,7 +1209,7 @@ public:
|
||||
}
|
||||
|
||||
/// Apply \p op to the partition op.
|
||||
void apply(const PartitionOp &op) const {
|
||||
void apply(const PartitionOp &op) {
|
||||
if (shouldEmitVerboseLogging()) {
|
||||
REGIONBASEDISOLATION_VERBOSE_LOG(llvm::dbgs() << "Applying: ";
|
||||
op.print(llvm::dbgs()));
|
||||
@@ -1158,9 +1250,9 @@ public:
|
||||
// assign an actor introducing inst.
|
||||
auto rep = getRepresentativeValue(op.getOpArgs()[1]).getValue();
|
||||
if (!dynamicRegionIsolation.isDisconnected()) {
|
||||
handleAssignTransferNonTransferrableIntoSendingResult(
|
||||
handleError(AssignNeverSendableIntoSendingResultError(
|
||||
op, op.getOpArgs()[0], fArg, op.getOpArgs()[1], rep,
|
||||
dynamicRegionIsolation);
|
||||
dynamicRegionIsolation));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1210,8 +1302,7 @@ public:
|
||||
auto pairOpt =
|
||||
getIsolationRegionInfo(transferredRegion, op.getSourceOp());
|
||||
if (!pairOpt) {
|
||||
handleUnknownCodePattern(op);
|
||||
return;
|
||||
return handleError(UnknownCodePatternError(op));
|
||||
}
|
||||
std::tie(transferredRegionIsolation, isClosureCapturedElt) = *pairOpt;
|
||||
|
||||
@@ -1245,7 +1336,7 @@ public:
|
||||
state.isolationInfo.merge(transferredRegionIsolation)) {
|
||||
state.isolationInfo = *newInfo;
|
||||
} else {
|
||||
handleUnknownCodePattern(op);
|
||||
handleError(UnknownCodePatternError(op));
|
||||
}
|
||||
assert(state.isolationInfo && "Cannot have unknown");
|
||||
state.isolationHistory.pushCFGHistoryJoin(p.getIsolationHistory());
|
||||
@@ -1283,9 +1374,9 @@ public:
|
||||
// assign an actor introducing inst.
|
||||
auto rep = getRepresentativeValue(op.getOpArgs()[1]).getValue();
|
||||
if (!dynamicRegionIsolation.isDisconnected()) {
|
||||
handleAssignTransferNonTransferrableIntoSendingResult(
|
||||
handleError(AssignNeverSendableIntoSendingResultError(
|
||||
op, op.getOpArgs()[0], fArg, op.getOpArgs()[1], rep,
|
||||
dynamicRegionIsolation);
|
||||
dynamicRegionIsolation));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1308,7 +1399,7 @@ public:
|
||||
}
|
||||
}
|
||||
return;
|
||||
case PartitionOpKind::RequireInOutSendingAtFunctionExit: {
|
||||
case PartitionOpKind::InOutSendingAtFunctionExit: {
|
||||
assert(op.getOpArgs().size() == 1 &&
|
||||
"Require PartitionOp should be passed 1 argument");
|
||||
assert(p.isTrackingElement(op.getOpArgs()[0]) &&
|
||||
@@ -1318,8 +1409,8 @@ public:
|
||||
// transferred. In that case, we emit a special use after free error.
|
||||
if (auto *transferredOperandSet = p.getTransferred(op.getOpArgs()[0])) {
|
||||
for (auto transferredOperand : transferredOperandSet->data()) {
|
||||
handleInOutSendingNotInitializedAtExitError(op, op.getOpArgs()[0],
|
||||
transferredOperand);
|
||||
handleError(InOutSendingNotInitializedAtExitError(
|
||||
op, op.getOpArgs()[0], transferredOperand));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1331,15 +1422,15 @@ public:
|
||||
|
||||
// If we failed to merge emit an unknown pattern error so we fail.
|
||||
if (!dynamicRegionIsolation) {
|
||||
handleUnknownCodePattern(op);
|
||||
handleError(UnknownCodePatternError(op));
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, emit the error if the dynamic region isolation is not
|
||||
// disconnected.
|
||||
if (!dynamicRegionIsolation.isDisconnected()) {
|
||||
handleInOutSendingNotDisconnectedAtExitError(op, op.getOpArgs()[0],
|
||||
dynamicRegionIsolation);
|
||||
handleError(InOutSendingNotDisconnectedAtExitError(
|
||||
op, op.getOpArgs()[0], dynamicRegionIsolation));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1348,8 +1439,7 @@ public:
|
||||
p.trackNewElement(op.getOpArgs()[0]);
|
||||
|
||||
// Then emit an unknown code pattern error.
|
||||
handleUnknownCodePattern(op);
|
||||
return;
|
||||
return handleError(UnknownCodePatternError(op));
|
||||
}
|
||||
|
||||
llvm_unreachable("Covered switch isn't covered?!");
|
||||
@@ -1394,7 +1484,7 @@ private:
|
||||
// Private helper that squelches the error if our transfer instruction and our
|
||||
// use have the same isolation.
|
||||
void handleLocalUseAfterTransferHelper(const PartitionOp &op, Element elt,
|
||||
Operand *transferringOp) const {
|
||||
Operand *transferringOp) {
|
||||
if (shouldTryToSquelchErrors()) {
|
||||
if (SILValue equivalenceClassRep =
|
||||
getRepresentative(transferringOp->get())) {
|
||||
@@ -1433,14 +1523,14 @@ private:
|
||||
}
|
||||
|
||||
// Ok, we actually need to emit a call to the callback.
|
||||
return handleLocalUseAfterTransfer(op, elt, transferringOp);
|
||||
return handleError(LocalUseAfterSendError(op, elt, transferringOp));
|
||||
}
|
||||
|
||||
// Private helper that squelches the error if our transfer instruction and our
|
||||
// use have the same isolation.
|
||||
void handleTransferNonTransferrableHelper(
|
||||
const PartitionOp &op, Element elt,
|
||||
SILDynamicMergedIsolationInfo dynamicMergedIsolationInfo) const {
|
||||
SILDynamicMergedIsolationInfo dynamicMergedIsolationInfo) {
|
||||
if (shouldTryToSquelchErrors()) {
|
||||
if (SILValue equivalenceClassRep =
|
||||
getRepresentative(op.getSourceOp()->get())) {
|
||||
@@ -1467,7 +1557,8 @@ private:
|
||||
}
|
||||
|
||||
// Ok, we actually need to emit a call to the callback.
|
||||
return handleTransferNonTransferrable(op, elt, dynamicMergedIsolationInfo);
|
||||
return handleError(
|
||||
SentNeverSendableError(op, elt, dynamicMergedIsolationInfo));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1491,57 +1582,6 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
|
||||
/// PartitionOps.
|
||||
bool shouldEmitVerboseLogging() const { return true; }
|
||||
|
||||
/// A function called if we discover a transferred value was used after it
|
||||
/// was transferred.
|
||||
///
|
||||
/// The arguments passed to the closure are:
|
||||
///
|
||||
/// 1. The PartitionOp that required the element to be alive.
|
||||
///
|
||||
/// 2. The element in the PartitionOp that was asked to be alive.
|
||||
///
|
||||
/// 3. The operand of the instruction that originally transferred the
|
||||
/// region. Can be used to get the immediate value transferred or the
|
||||
/// transferring instruction.
|
||||
void handleLocalUseAfterTransfer(const PartitionOp &op, Element elt,
|
||||
Operand *transferringOp) const {}
|
||||
|
||||
/// This is called if we detect a never transferred element that was passed to
|
||||
/// a transfer instruction.
|
||||
void handleTransferNonTransferrable(
|
||||
const PartitionOp &op, Element elt,
|
||||
SILDynamicMergedIsolationInfo regionInfo) const {}
|
||||
|
||||
/// Please see documentation on the CRTP version of this call for information
|
||||
/// about this entrypoint.
|
||||
void handleTransferNonTransferrable(
|
||||
const PartitionOp &op, Element elt, Element otherElement,
|
||||
SILDynamicMergedIsolationInfo isolationRegionInfo) const {}
|
||||
|
||||
/// Please see documentation on the CRTP version of this call for information
|
||||
/// about this entrypoint.
|
||||
void handleAssignTransferNonTransferrableIntoSendingResult(
|
||||
const PartitionOp &partitionOp, Element destElement,
|
||||
SILFunctionArgument *destValue, Element srcElement, SILValue srcValue,
|
||||
SILDynamicMergedIsolationInfo srcIsolationRegionInfo) const {}
|
||||
|
||||
/// Used to signify an "unknown code pattern" has occured while performing
|
||||
/// dataflow.
|
||||
///
|
||||
/// DISCUSSION: Our dataflow cannot emit errors itself so this is a callback
|
||||
/// to our user so that we can emit that error as we process.
|
||||
void handleUnknownCodePattern(const PartitionOp &op) const {}
|
||||
|
||||
/// Called if we find an 'inout sending' parameter that is not live at exit.
|
||||
void handleInOutSendingNotInitializedAtExitError(
|
||||
const PartitionOp &op, Element elt, Operand *transferringOp) const {}
|
||||
|
||||
/// Called if we find an 'inout sending' parameter that is live at excit but
|
||||
/// is actor isolated instead of disconnected.
|
||||
void handleInOutSendingNotDisconnectedAtExitError(
|
||||
const PartitionOp &op, Element elt,
|
||||
SILDynamicMergedIsolationInfo actorIsolation) const {}
|
||||
|
||||
/// This is used to determine if an element is actor derived. If we determine
|
||||
/// that a region containing such an element is transferred, we emit an error
|
||||
/// since actor regions cannot be transferred.
|
||||
@@ -1551,6 +1591,9 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
|
||||
/// isolated value.
|
||||
bool isTaskIsolatedDerived(Element elt) const { return false; }
|
||||
|
||||
/// By default, do nothing upon error.
|
||||
void handleError(PartitionOpError error) {}
|
||||
|
||||
/// Returns the information about \p elt's isolation that we ascertained from
|
||||
/// SIL and the AST.
|
||||
SILIsolationInfo getIsolationRegionInfo(Element elt) const {
|
||||
|
||||
@@ -291,6 +291,13 @@ public:
|
||||
llvm::dbgs() << '\n';
|
||||
}
|
||||
|
||||
/// Prints out the message for a diagnostic that states that the value is
|
||||
/// exposed to a specific code.
|
||||
///
|
||||
/// We do this programatically since task-isolated code needs a very different
|
||||
/// form of diagnostic than other cases.
|
||||
void printForCodeDiagnostic(llvm::raw_ostream &os) const;
|
||||
|
||||
void printForDiagnostics(llvm::raw_ostream &os) const;
|
||||
|
||||
SWIFT_DEBUG_DUMPER(dumpForDiagnostics()) {
|
||||
@@ -525,6 +532,10 @@ public:
|
||||
innerInfo.dumpForDiagnostics();
|
||||
}
|
||||
|
||||
void printForCodeDiagnostic(llvm::raw_ostream &os) const {
|
||||
innerInfo.printForCodeDiagnostic(os);
|
||||
}
|
||||
|
||||
void printForOneLineLogging(llvm::raw_ostream &os) const {
|
||||
innerInfo.printForOneLineLogging(os);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user