Files
swift-mirror/include/swift/SIL/SILLocation.h
Adrian Prantl 310b0433a9 Reapply "Serialize debug scope and location info in the SIL assembler language.""
This ireapplies commit 255c52de9f.

Original commit message:

Serialize debug scope and location info in the SIL assembler language.
At the moment it is only possible to test the effects that SIL
optimization passes have on debug information by observing the
effects of a full .swift -> LLVM IR compilation. This change enable us
to write targeted testcases for single SIL optimization passes.

The new syntax is as follows:

 sil-scope-ref ::= 'scope' [0-9]+
 sil-scope ::= 'sil_scope' [0-9]+ '{'
                 sil-loc
                 'parent' scope-parent
                 ('inlined_at' sil-scope-ref )?
               '}'
 scope-parent ::= sil-function-name ':' sil-type
 scope-parent ::= sil-scope-ref
 sil-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+

Each instruction may have a debug location and a SIL scope reference
at the end.  Debug locations consist of a filename, a line number, and
a column number.  If the debug location is omitted, it defaults to the
location in the SIL source file.  SIL scopes describe the position
inside the lexical scope structure that the Swift expression a SIL
instruction was generated from had originally. SIL scopes also hold
inlining information.

<rdar://problem/22706994>
2016-02-26 13:28:57 -08:00

714 lines
23 KiB
C++

//===--- SILLocation.h - Location information for SIL nodes -----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SIL_LOCATION_H
#define SWIFT_SIL_LOCATION_H
#include "llvm/ADT/PointerUnion.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/Stmt.h"
#include <cstddef>
#include <type_traits>
namespace swift {
class SourceLoc;
/// This is a pointer to the AST node that a SIL instruction was
/// derived from. This may be null if AST information is unavailable or
/// stripped.
///
/// FIXME: This should eventually include inlining history, generics
/// instantiation info, etc (when we get to it).
///
class SILLocation {
private:
template <class T, class Enable = void>
struct base_type;
template <class T>
struct base_type<T,
typename std::enable_if<std::is_base_of<Decl, T>::value>::type> {
using type = Decl;
};
template <class T>
struct base_type<T,
typename std::enable_if<std::is_base_of<Expr, T>::value>::type> {
using type = Expr;
};
template <class T>
struct base_type<T,
typename std::enable_if<std::is_base_of<Stmt, T>::value>::type> {
using type = Stmt;
};
template <class T>
struct base_type<T,
typename std::enable_if<std::is_base_of<Pattern, T>::value>::type> {
using type = Pattern;
};
typedef llvm::PointerUnion4<Stmt*, Expr*, Decl*, Pattern*> ASTNodeTy;
public:
enum LocationKind : unsigned {
// FIXME: NoneKind is to be removed.
NoneKind = 0,
RegularKind = 1,
ReturnKind = 2,
ImplicitReturnKind = 3,
InlinedKind = 4,
MandatoryInlinedKind = 5,
CleanupKind = 6,
ArtificialUnreachableKind = 7
};
enum StorageKind : unsigned {
UnknownKind = 0,
ASTNodeKind = 1 << 3,
SILFileKind = 1 << 4,
DebugInfoKind = 1 << 3 | 1 << 4
};
typedef struct {
unsigned Line = 0, Column = 0;
const char *Filename = nullptr;
} DebugLoc;
protected:
union UnderlyingLocation {
UnderlyingLocation() : DebugInfoLoc({}) {}
UnderlyingLocation(ASTNodeTy N) : ASTNode(N) {}
UnderlyingLocation(SourceLoc L) : SILFileLoc(L) {}
UnderlyingLocation(DebugLoc D) : DebugInfoLoc(D) {}
struct ASTNodeLoc {
ASTNodeLoc(ASTNodeTy N) : Primary(N) {}
/// Primary AST location, always used for diagnostics.
ASTNodeTy Primary;
/// Sometimes the location for diagnostics needs to be
/// different than the one used to emit the line table. If
/// HasDebugLoc is set, this is used for the debug info.
ASTNodeTy ForDebugger;
} ASTNode;
/// A location inside a textual .sil file.
SourceLoc SILFileLoc;
/// A deserialized source location.
DebugLoc DebugInfoLoc;
} Loc;
/// The kind of this SIL location.
unsigned KindData;
enum {
LocationKindBits = 3,
LocationKindMask = 7,
StorageKindBits = 2,
StorageKindMask = (1 << 3) | (1 << 4),
SpecialFlagsMask = ~ (LocationKindMask | StorageKindMask),
/// Used to mark this instruction as part of auto-generated
/// code block.
AutoGeneratedBit = 5,
/// Used to redefine the default source location used to
/// represent this SILLocation. For example, when the host instruction
/// is known to correspond to the beginning or the end of the source
/// range of the ASTNode.
PointsToStartBit = 6,
PointsToEndBit = 7,
/// Used to notify that this instruction belongs to the top-
/// level (module) scope.
///
/// FIXME: If Module becomes a Decl, this could be removed.
IsInTopLevel = 8,
/// Marks this instruction as belonging to the function prologue.
IsInPrologue = 9
};
template <typename T>
T *getNodeAs(ASTNodeTy Node) const {
using base = typename base_type<T>::type*;
return dyn_cast_or_null<T>(Node.dyn_cast<base>());
}
template <typename T>
bool isNode(ASTNodeTy Node) const {
assert(isASTNode());
if (Loc.ASTNode.Primary.is<typename base_type<T>::type*>())
return isa<T>(Node.get<typename base_type<T>::type*>());
return false;
}
template <typename T>
T *castNodeTo(ASTNodeTy Node) const {
return cast<T>(Node.get<typename base_type<T>::type*>());
}
/// \defgroup SILLocation constructors.
/// @{
/// This constructor is used to support getAs operation.
SILLocation() { assert(Loc.DebugInfoLoc.Line == 0); }
SILLocation(LocationKind K, unsigned Flags = 0) : KindData(K | Flags) {
assert(Loc.DebugInfoLoc.Line == 0);
}
SILLocation(Stmt *S, LocationKind K, unsigned Flags = 0)
: Loc(S), KindData(K | Flags) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
SILLocation(Expr *E, LocationKind K, unsigned Flags = 0)
: Loc(E), KindData(K | Flags) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
SILLocation(Decl *D, LocationKind K, unsigned Flags = 0)
: Loc(D), KindData(K | Flags) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
SILLocation(Pattern *P, LocationKind K, unsigned Flags = 0)
: Loc(P), KindData(K | Flags) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
SILLocation(SourceLoc L, LocationKind K, unsigned Flags = 0)
: Loc(L), KindData(K | Flags) {
setStorageKind(SILFileKind);
assert(isSILFile());
}
SILLocation(DebugLoc L, LocationKind K, unsigned Flags = 0)
: Loc(L), KindData(K | Flags) {
setStorageKind(DebugInfoKind);
assert(isDebugInfoLoc());
}
/// @}
private:
friend class ImplicitReturnLocation;
friend class MandatoryInlinedLocation;
friend class InlinedLocation;
friend class CleanupLocation;
void setLocationKind(LocationKind K) { KindData |= (K & LocationKindMask); }
void setStorageKind(StorageKind K) { KindData |= (K & StorageKindMask); }
unsigned getSpecialFlags() const { return KindData & SpecialFlagsMask; }
void setSpecialFlags(unsigned Flags) {
KindData |= (Flags & SpecialFlagsMask);
}
SourceLoc getSourceLoc(ASTNodeTy N) const;
SourceLoc getStartSourceLoc(ASTNodeTy N) const;
SourceLoc getEndSourceLoc(ASTNodeTy N) const;
public:
/// When an ASTNode gets implicitly converted into a SILLocation we
/// construct a RegularLocation. Since RegularLocations represent the majority
/// of locations, this greatly simplifies the user code.
SILLocation(Stmt *S) : Loc(S), KindData(RegularKind) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
SILLocation(Expr *E) : Loc(E), KindData(RegularKind) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
SILLocation(Decl *D) : Loc(D), KindData(RegularKind) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
SILLocation(Pattern *P) : Loc(P), KindData(RegularKind) {
setStorageKind(ASTNodeKind);
assert(isASTNode());
}
/// Check if the location wraps an AST node or a valid SIL file
/// location.
///
/// Artificial locations and the top-level module locations will be null.
bool isNull() const {
switch (getStorageKind()) {
case ASTNodeKind: return Loc.ASTNode.Primary.isNull();
case DebugInfoKind: return Loc.DebugInfoLoc.Filename;
case SILFileKind: return Loc.SILFileLoc.isInvalid();
default: return true;
}
}
explicit operator bool() const { return !isNull(); }
/// Return whether this location is backed by an AST node.
bool isASTNode() const { return getStorageKind() == ASTNodeKind; }
/// Return whether this location came from a SIL file.
bool isSILFile() const { return getStorageKind() == SILFileKind; }
/// Return whether this location came from a textual SIL file.
bool isDebugInfoLoc() const { return getStorageKind() == DebugInfoKind; }
/// Marks the location as coming from auto-generated body.
void markAutoGenerated() { KindData |= (1 << AutoGeneratedBit); }
/// Returns true if the location represents an artificially generated
/// body, such as thunks or default destructors.
///
/// These locations should not be included in the debug line table.
/// These might also need special handling by the debugger since they might
/// contain calls, which the debugger could be able to step into.
bool isAutoGenerated() const { return KindData & (1 << AutoGeneratedBit); }
/// Changes the default source location position to point to start of
/// the AST node.
void pointToStart() { KindData |= (1 << PointsToStartBit); }
/// Changes the default source location position to point to the end of
/// the AST node.
void pointToEnd() { KindData |= (1 << PointsToEndBit); }
/// Mark this location as the location corresponding to the top-level
/// (module-level) code.
void markAsInTopLevel() { KindData |= (1 << IsInTopLevel); }
/// Check is this location is associated with the top level/module.
bool isInTopLevel() const { return KindData & (1 << IsInTopLevel); }
/// Mark this location as being part of the function
/// prologue, which means that it deals with setting up the stack
/// frame. The first breakpoint location in a function is at the end
/// of the prologue.
void markAsPrologue() { KindData |= (1 << IsInPrologue); }
/// Check is this location is part of a function's implicit prologue.
bool isInPrologue() const { return KindData & (1 << IsInPrologue); }
/// Add an ASTNode to use as the location for debugging
/// purposes if this location is different from the location used
/// for diagnostics.
template <typename T>
void setDebugLoc(T *ASTNodeForDebugging) {
assert(!hasDebugLoc() && "DebugLoc already present");
assert(isASTNode() && "not an AST location");
Loc.ASTNode.ForDebugger = ASTNodeForDebugging;
}
bool hasDebugLoc() const {
return isASTNode() && !Loc.ASTNode.ForDebugger.isNull();
}
/// Populate this empty SILLocation with a DebugLoc.
void setDebugInfoLoc(DebugLoc L) {
Loc.DebugInfoLoc = L;
setStorageKind(DebugInfoKind);
}
/// Check if the corresponding source code location definitely points
/// to the start of the AST node.
bool alwaysPointsToStart() const { return KindData & (1 << PointsToStartBit);}
/// Check if the corresponding source code location definitely points
/// to the end of the AST node.
bool alwaysPointsToEnd() const { return KindData & (1 << PointsToEndBit); }
LocationKind getKind() const {
return LocationKind(KindData & LocationKindMask);
}
StorageKind getStorageKind() const {
return StorageKind(KindData & StorageKindMask);
}
template <typename T>
bool is() const {
return T::isKind(*this);
}
template <typename T>
T castTo() const {
assert(T::isKind(*this));
T t;
SILLocation& tr = t;
tr = *this;
return t;
}
template <typename T>
Optional<T> getAs() const {
if (!T::isKind(*this))
return Optional<T>();
T t;
SILLocation& tr = t;
tr = *this;
return t;
}
/// If the current value is of the specified AST unit type T,
/// return it, otherwise return null.
template <typename T> T *getAsASTNode() const {
return isASTNode() ? getNodeAs<T>(Loc.ASTNode.Primary) : nullptr;
}
/// Returns true if the Location currently points to the AST node
/// matching type T.
template <typename T> bool isASTNode() const {
return isASTNode() && isNode<T>(Loc.ASTNode.Primary);
}
/// Returns the primary value as the specified AST node type. If the
/// specified type is incorrect, asserts.
template <typename T> T *castToASTNode() const {
assert(isASTNode());
return castNodeTo<T>(Loc.ASTNode.Primary);
}
/// If the DebugLoc is of the specified AST unit type T,
/// return it, otherwise return null.
template <typename T> T *getDebugLocAsASTNode() const {
assert(hasDebugLoc() && "no debug location");
return getNodeAs<T>(Loc.ASTNode.ForDebugger);
}
SourceLoc getDebugSourceLoc() const;
SourceLoc getSourceLoc() const;
SourceLoc getStartSourceLoc() const;
SourceLoc getEndSourceLoc() const;
SourceRange getSourceRange() const {
return { getStartSourceLoc(), getEndSourceLoc() };
}
/// Fingerprint a DebugLoc for use in a DenseMap.
typedef std::pair<std::pair<unsigned, unsigned>, const void *> DebugLocKey;
struct DebugLocHash : public DebugLocKey {
DebugLocHash(DebugLoc L) : DebugLocKey({{L.Line, L.Column}, L.Filename}) {}
};
/// Extract the line, column, and filename.
static DebugLoc decode(SourceLoc Loc, const SourceManager &SM);
/// Return the decoded debug location.
DebugLoc decodeDebugLoc(const SourceManager &SM) const {
return isDebugInfoLoc() ? Loc.DebugInfoLoc
: decode(getDebugSourceLoc(), SM);
}
/// Pretty-print the value.
void dump(const SourceManager &SM) const;
void print(raw_ostream &OS, const SourceManager &SM) const;
/// Returns an opaque pointer value for the debug location that may
/// be used to unique debug locations.
const void *getOpaquePointerValue() const {
if (isSILFile())
return Loc.SILFileLoc.getOpaquePointerValue();
if (isASTNode())
return Loc.ASTNode.Primary.getOpaqueValue();
else
return 0;
}
unsigned getOpaqueKind() const { return KindData; }
inline bool operator==(const SILLocation& R) const {
return KindData == R.KindData &&
Loc.ASTNode.Primary.getOpaqueValue() ==
R.Loc.ASTNode.Primary.getOpaqueValue() &&
Loc.ASTNode.ForDebugger.getOpaqueValue() ==
R.Loc.ASTNode.ForDebugger.getOpaqueValue();
}
};
/// Allowed on any instruction.
class RegularLocation : public SILLocation {
public:
RegularLocation(Stmt *S) : SILLocation(S, RegularKind) {}
RegularLocation(Expr *E) : SILLocation(E, RegularKind) {}
RegularLocation(Decl *D) : SILLocation(D, RegularKind) {}
RegularLocation(Pattern *P) : SILLocation(P, RegularKind) {}
RegularLocation(SourceLoc L) : SILLocation(L, RegularKind) {}
RegularLocation(DebugLoc L) : SILLocation(L, RegularKind) {}
/// Returns a location representing the module.
static RegularLocation getModuleLocation() {
RegularLocation Loc;
Loc.markAsInTopLevel();
return Loc;
}
/// If the current value is of the specified AST unit type T,
/// return it, otherwise return null.
template <typename T> T *getAs() const { return getNodeAs<T>(Loc.ASTNode); }
/// Returns true if the Location currently points to the AST node
/// matching type T.
template <typename T> bool is() const { return isNode<T>(Loc.ASTNode); }
/// Returns the primary value as the specified AST node type. If the
/// specified type is incorrect, asserts.
template <typename T> T *castTo() const { return castNodeTo<T>(Loc.ASTNode); }
static RegularLocation getAutoGeneratedLocation() {
RegularLocation AL;
AL.markAutoGenerated();
return AL;
}
private:
RegularLocation() : SILLocation(RegularKind) {}
friend class SILLocation;
static bool isKind(const SILLocation& L) {
return L.getKind() == RegularKind;
}
};
/// Used to represent a return instruction in user code.
///
/// Allowed on an BranchInst, ReturnInst.
class ReturnLocation : public SILLocation {
public:
ReturnLocation(ReturnStmt *RS) : SILLocation(RS, ReturnKind) {}
/// Construct the return location for a constructor or a destructor.
ReturnLocation(BraceStmt *BS)
: SILLocation(BS, ReturnKind) {}
ReturnStmt *get() {
return castToASTNode<ReturnStmt>();
}
private:
friend class SILLocation;
static bool isKind(const SILLocation& L) {
return L.getKind() == ReturnKind;
}
};
/// Used on the instruction that was generated to represent an implicit
/// return from a function.
///
/// Allowed on an BranchInst, ReturnInst.
class ImplicitReturnLocation : public SILLocation {
public:
ImplicitReturnLocation(AbstractClosureExpr *E)
: SILLocation(E, ImplicitReturnKind) { }
ImplicitReturnLocation(ReturnStmt *S)
: SILLocation(S, ImplicitReturnKind) { }
ImplicitReturnLocation(AbstractFunctionDecl *AFD)
: SILLocation(AFD, ImplicitReturnKind) { }
/// Construct from a RegularLocation; preserve all special bits.
///
/// Note, this can construct an implicit return for an arbitrary expression
/// (specifically, in case of auto-generated bodies).
static SILLocation getImplicitReturnLoc(SILLocation L) {
assert(L.isASTNode<Expr>() ||
L.isASTNode<ValueDecl>() ||
L.isASTNode<PatternBindingDecl>() ||
(L.isNull() && L.isInTopLevel()));
L.setLocationKind(ImplicitReturnKind);
return L;
}
AbstractClosureExpr *get() {
return castToASTNode<AbstractClosureExpr>();
}
private:
friend class SILLocation;
static bool isKind(const SILLocation& L) {
return L.getKind() == ImplicitReturnKind;
}
ImplicitReturnLocation() : SILLocation(ImplicitReturnKind) {}
};
/// Marks instructions that correspond to inlined function body and
/// setup code. This location should not be used for inlined transparent
/// bodies, see MandatoryInlinedLocation.
///
/// This location wraps the call site ASTNode.
///
/// Allowed on any instruction except for ReturnInst.
class InlinedLocation : public SILLocation {
public:
InlinedLocation(Expr *CallSite) : SILLocation(CallSite, InlinedKind) {}
InlinedLocation(Stmt *S) : SILLocation(S, InlinedKind) {}
InlinedLocation(Pattern *P) : SILLocation(P, InlinedKind) {}
InlinedLocation(Decl *D) : SILLocation(D, InlinedKind) {}
/// Constructs an inlined location when the call site is represented by a
/// SILFile location.
InlinedLocation(SourceLoc L) : SILLocation(InlinedKind) {
setStorageKind(SILFileKind);
Loc.SILFileLoc = L;
}
static InlinedLocation getInlinedLocation(SILLocation L);
private:
friend class SILLocation;
static bool isKind(const SILLocation& L) {
return L.getKind() == InlinedKind;
}
InlinedLocation() : SILLocation(InlinedKind) {}
InlinedLocation(Expr *E, unsigned F) : SILLocation(E, InlinedKind, F) {}
InlinedLocation(Stmt *S, unsigned F) : SILLocation(S, InlinedKind, F) {}
InlinedLocation(Pattern *P, unsigned F) : SILLocation(P, InlinedKind, F) {}
InlinedLocation(Decl *D, unsigned F) : SILLocation(D, InlinedKind, F) {}
InlinedLocation(SourceLoc L, unsigned F) : SILLocation(L, InlinedKind, F) {}
static InlinedLocation getModuleLocation(unsigned Flags) {
auto L = InlinedLocation();
L.setSpecialFlags(Flags);
return L;
}
};
/// Marks instructions that correspond to inlined function body and
/// setup code for transparent functions, inlined as part of mandatory inlining
/// pass.
///
/// This location wraps the call site ASTNode.
///
/// Allowed on any instruction except for ReturnInst.
class MandatoryInlinedLocation : public SILLocation {
public:
MandatoryInlinedLocation(Expr *CallSite) :
SILLocation(CallSite, MandatoryInlinedKind) {}
MandatoryInlinedLocation(Stmt *S) : SILLocation(S, MandatoryInlinedKind) {}
MandatoryInlinedLocation(Pattern *P) : SILLocation(P, MandatoryInlinedKind) {}
MandatoryInlinedLocation(Decl *D) : SILLocation(D, MandatoryInlinedKind) {}
/// Constructs an inlined location when the call site is represented by a
/// SILFile location.
MandatoryInlinedLocation(SourceLoc L)
: SILLocation(L, MandatoryInlinedKind) {}
static MandatoryInlinedLocation getMandatoryInlinedLocation(SILLocation L);
static MandatoryInlinedLocation getModuleLocation(unsigned Flags) {
auto L = MandatoryInlinedLocation();
L.setSpecialFlags(Flags);
return L;
}
private:
friend class SILLocation;
static bool isKind(const SILLocation& L) {
return L.getKind() == MandatoryInlinedKind;
}
MandatoryInlinedLocation() : SILLocation(MandatoryInlinedKind) {}
MandatoryInlinedLocation(Expr *E, unsigned F)
: SILLocation(E, MandatoryInlinedKind, F) {}
MandatoryInlinedLocation(Stmt *S, unsigned F)
: SILLocation(S, MandatoryInlinedKind, F) {}
MandatoryInlinedLocation(Pattern *P, unsigned F)
: SILLocation(P, MandatoryInlinedKind, F) {}
MandatoryInlinedLocation(Decl *D, unsigned F)
: SILLocation(D, MandatoryInlinedKind, F) {}
MandatoryInlinedLocation(SourceLoc L, unsigned F)
: SILLocation(L, MandatoryInlinedKind, F) {}
};
/// Used on the instruction performing auto-generated cleanup such as
/// deallocs, destructor calls.
///
/// The cleanups are performed after completing the evaluation of the AST Node
/// wrapped inside the SILLocation. This location wraps the statement
/// representing the enclosing scope, for example, FuncDecl, ParenExpr. The
/// scope's end location points to the SourceLoc that shows when the operation
/// is performed at runtime.
///
/// Allowed on any instruction except for ReturnInst.
/// Locations of an inlined destructor should also be represented by this.
class CleanupLocation : public SILLocation {
public:
CleanupLocation(Expr *E) : SILLocation(E, CleanupKind) {}
CleanupLocation(Stmt *S) : SILLocation(S, CleanupKind) {}
CleanupLocation(Pattern *P) : SILLocation(P, CleanupKind) {}
CleanupLocation(Decl *D) : SILLocation(D, CleanupKind) {}
static CleanupLocation get(SILLocation L);
/// Returns a location representing a cleanup on the module level.
static CleanupLocation getModuleCleanupLocation() {
CleanupLocation Loc;
Loc.markAsInTopLevel();
return Loc;
}
private:
friend class SILLocation;
static bool isKind(const SILLocation& L) {
return L.getKind() == CleanupKind;
}
CleanupLocation() : SILLocation(CleanupKind) {}
CleanupLocation(Expr *E, unsigned F) : SILLocation(E, CleanupKind, F) {}
CleanupLocation(Stmt *S, unsigned F) : SILLocation(S, CleanupKind, F) {}
CleanupLocation(Pattern *P, unsigned F) : SILLocation(P, CleanupKind, F) {}
CleanupLocation(Decl *D, unsigned F) : SILLocation(D, CleanupKind, F) {}
};
/// Used to represent an unreachable location that was
/// auto-generated and has no correspondence to user code. It should
/// not be used in diagnostics or for debugging.
///
/// Differentiates an unreachable instruction, which is generated by
/// DCE, from an unreachable instruction in user code (output of SILGen).
/// Allowed on an unreachable instruction.
class ArtificialUnreachableLocation : public SILLocation {
public:
ArtificialUnreachableLocation() : SILLocation(ArtificialUnreachableKind) {}
private:
friend class SILLocation;
static bool isKind(const SILLocation& L) {
return (L.getKind() == ArtificialUnreachableKind);
}
};
class SILDebugScope;
/// A SILLocation paired with a SILDebugScope.
class SILDebugLocation {
const SILDebugScope *Scope = nullptr;
SILLocation Location;
public:
SILDebugLocation() : Scope(nullptr), Location(RegularLocation(SourceLoc())) {}
SILDebugLocation(SILLocation Loc, const SILDebugScope *DS)
: Scope(DS), Location(Loc) {}
SILLocation getLocation() const { return Location; }
const SILDebugScope *getScope() const { return Scope; }
};
} // end swift namespace
#endif