-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[ast]/[silgen] If a case stmt is a fallthrough source, tail allocate a pointer in the case stmt to the fallthrough case. #23284
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,16 +26,18 @@ | |
#include "llvm/Support/TrailingObjects.h" | ||
|
||
namespace swift { | ||
class AnyPattern; | ||
class ASTContext; | ||
class ASTWalker; | ||
class Decl; | ||
class Expr; | ||
class FuncDecl; | ||
class Pattern; | ||
class PatternBindingDecl; | ||
class VarDecl; | ||
|
||
|
||
class AnyPattern; | ||
class ASTContext; | ||
class ASTWalker; | ||
class Decl; | ||
class Expr; | ||
class FuncDecl; | ||
class Pattern; | ||
class PatternBindingDecl; | ||
class VarDecl; | ||
class CaseStmt; | ||
|
||
enum class StmtKind { | ||
#define STMT(ID, PARENT) ID, | ||
#define LAST_STMT(ID) Last_Stmt = ID, | ||
|
@@ -920,6 +922,45 @@ class CaseLabelItem { | |
} | ||
}; | ||
|
||
/// FallthroughStmt - The keyword "fallthrough". | ||
class FallthroughStmt : public Stmt { | ||
SourceLoc Loc; | ||
CaseStmt *FallthroughSource; | ||
CaseStmt *FallthroughDest; | ||
|
||
public: | ||
FallthroughStmt(SourceLoc Loc, Optional<bool> implicit = None) | ||
: Stmt(StmtKind::Fallthrough, getDefaultImplicitFlag(implicit, Loc)), | ||
Loc(Loc), FallthroughSource(nullptr), FallthroughDest(nullptr) {} | ||
|
||
SourceLoc getLoc() const { return Loc; } | ||
|
||
SourceRange getSourceRange() const { return Loc; } | ||
|
||
/// Get the CaseStmt block from which the fallthrough transfers control. | ||
/// Set during Sema. (May stay null if fallthrough is invalid.) | ||
CaseStmt *getFallthroughSource() const { return FallthroughSource; } | ||
void setFallthroughSource(CaseStmt *C) { | ||
assert(!FallthroughSource && "fallthrough source already set?!"); | ||
FallthroughSource = C; | ||
} | ||
|
||
/// Get the CaseStmt block to which the fallthrough transfers control. | ||
/// Set during Sema. | ||
CaseStmt *getFallthroughDest() const { | ||
assert(FallthroughDest && "fallthrough dest is not set until Sema"); | ||
return FallthroughDest; | ||
} | ||
void setFallthroughDest(CaseStmt *C) { | ||
assert(!FallthroughDest && "fallthrough dest already set?!"); | ||
FallthroughDest = C; | ||
} | ||
|
||
static bool classof(const Stmt *S) { | ||
return S->getKind() == StmtKind::Fallthrough; | ||
} | ||
}; | ||
|
||
/// A 'case' or 'default' block of a switch statement. Only valid as the | ||
/// substatement of a SwitchStmt. A case block begins either with one or more | ||
/// CaseLabelItems or a single 'default' label. | ||
|
@@ -933,8 +974,10 @@ class CaseLabelItem { | |
/// default: | ||
/// \endcode | ||
/// | ||
class CaseStmt final : public Stmt, | ||
private llvm::TrailingObjects<CaseStmt, CaseLabelItem> { | ||
class CaseStmt final | ||
: public Stmt, | ||
private llvm::TrailingObjects<CaseStmt, FallthroughStmt *, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to store the entire FallthroughStmt * rather than a pointer to the CaseStmt* returned from FallthroughStmt::getFallthroughDest(). This seems more flexible. That being said, I did not want to add it to the API surface, so I did not expose it directly. |
||
CaseLabelItem> { | ||
friend TrailingObjects; | ||
|
||
SourceLoc UnknownAttrLoc; | ||
|
@@ -943,24 +986,47 @@ class CaseStmt final : public Stmt, | |
|
||
llvm::PointerIntPair<Stmt *, 1, bool> BodyAndHasBoundDecls; | ||
|
||
/// Set to true if we have a fallthrough. | ||
/// | ||
/// TODO: Once we have CaseBodyVarDecls, use the bit in BodyAndHasBoundDecls | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be clear here: HasBoundDecls is true iff we have CaseBodyVarDecls to my commit adding those will fix that. I just did not want to create a field called |
||
/// for this instead. This is separate now for staging reasons. | ||
bool hasFallthrough; | ||
|
||
CaseStmt(SourceLoc CaseLoc, ArrayRef<CaseLabelItem> CaseLabelItems, | ||
bool HasBoundDecls, SourceLoc UnknownAttrLoc, SourceLoc ColonLoc, | ||
Stmt *Body, Optional<bool> Implicit); | ||
Stmt *Body, Optional<bool> Implicit, | ||
NullablePtr<FallthroughStmt> fallthroughStmt); | ||
|
||
public: | ||
static CaseStmt *create(ASTContext &C, SourceLoc CaseLoc, | ||
ArrayRef<CaseLabelItem> CaseLabelItems, | ||
bool HasBoundDecls, SourceLoc UnknownAttrLoc, | ||
SourceLoc ColonLoc, Stmt *Body, | ||
Optional<bool> Implicit = None); | ||
static CaseStmt * | ||
create(ASTContext &C, SourceLoc CaseLoc, | ||
ArrayRef<CaseLabelItem> CaseLabelItems, bool HasBoundDecls, | ||
SourceLoc UnknownAttrLoc, SourceLoc ColonLoc, Stmt *Body, | ||
Optional<bool> Implicit = None, | ||
NullablePtr<FallthroughStmt> fallthroughStmt = nullptr); | ||
|
||
ArrayRef<CaseLabelItem> getCaseLabelItems() const { | ||
return {getTrailingObjects<CaseLabelItem>(), Bits.CaseStmt.NumPatterns}; | ||
} | ||
|
||
MutableArrayRef<CaseLabelItem> getMutableCaseLabelItems() { | ||
return {getTrailingObjects<CaseLabelItem>(), Bits.CaseStmt.NumPatterns}; | ||
} | ||
|
||
unsigned getNumCaseLabelItems() const { return Bits.CaseStmt.NumPatterns; } | ||
|
||
NullablePtr<CaseStmt> getFallthroughDest() const { | ||
return const_cast<CaseStmt &>(*this).getFallthroughDest(); | ||
} | ||
|
||
NullablePtr<CaseStmt> getFallthroughDest() { | ||
if (!hasFallthrough) | ||
return nullptr; | ||
return (*getTrailingObjects<FallthroughStmt *>())->getFallthroughDest(); | ||
} | ||
|
||
bool hasFallthroughDest() const { return hasFallthrough; } | ||
|
||
Stmt *getBody() const { return BodyAndHasBoundDecls.getPointer(); } | ||
void setBody(Stmt *body) { BodyAndHasBoundDecls.setPointer(body); } | ||
|
||
|
@@ -991,6 +1057,14 @@ class CaseStmt final : public Stmt, | |
} | ||
|
||
static bool classof(const Stmt *S) { return S->getKind() == StmtKind::Case; } | ||
|
||
size_t numTrailingObjects(OverloadToken<CaseLabelItem>) const { | ||
return getNumCaseLabelItems(); | ||
} | ||
|
||
size_t numTrailingObjects(OverloadToken<FallthroughStmt *>) const { | ||
return hasFallthrough ? 1 : 0; | ||
} | ||
}; | ||
|
||
/// Switch statement. | ||
|
@@ -1135,48 +1209,6 @@ class ContinueStmt : public Stmt { | |
} | ||
}; | ||
|
||
/// FallthroughStmt - The keyword "fallthrough". | ||
class FallthroughStmt : public Stmt { | ||
SourceLoc Loc; | ||
CaseStmt *FallthroughSource; | ||
CaseStmt *FallthroughDest; | ||
|
||
public: | ||
FallthroughStmt(SourceLoc Loc, Optional<bool> implicit = None) | ||
: Stmt(StmtKind::Fallthrough, getDefaultImplicitFlag(implicit, Loc)), | ||
Loc(Loc), FallthroughSource(nullptr), FallthroughDest(nullptr) | ||
{} | ||
|
||
SourceLoc getLoc() const { return Loc; } | ||
|
||
SourceRange getSourceRange() const { return Loc; } | ||
|
||
/// Get the CaseStmt block from which the fallthrough transfers control. | ||
/// Set during Sema. (May stay null if fallthrough is invalid.) | ||
CaseStmt *getFallthroughSource() const { | ||
return FallthroughSource; | ||
} | ||
void setFallthroughSource(CaseStmt *C) { | ||
assert(!FallthroughSource && "fallthrough source already set?!"); | ||
FallthroughSource = C; | ||
} | ||
|
||
/// Get the CaseStmt block to which the fallthrough transfers control. | ||
/// Set during Sema. | ||
CaseStmt *getFallthroughDest() const { | ||
assert(FallthroughDest && "fallthrough dest is not set until Sema"); | ||
return FallthroughDest; | ||
} | ||
void setFallthroughDest(CaseStmt *C) { | ||
assert(!FallthroughDest && "fallthrough dest already set?!"); | ||
FallthroughDest = C; | ||
} | ||
|
||
static bool classof(const Stmt *S) { | ||
return S->getKind() == StmtKind::Fallthrough; | ||
} | ||
}; | ||
|
||
/// FailStmt - A statement that indicates a failable, which is currently | ||
/// spelled as "return nil" and can only be used within failable initializers. | ||
class FailStmt : public Stmt { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no changes here to FallthroughStmt. I just ran into issues with my uses for it in CaseStmt and then discovered that I couldn't just use a forward declaration of it = /.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*So I moved it above CaseStmt.