aboutsummaryrefslogtreecommitdiff
path: root/include/clang/Sema/ScopeInfo.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Sema/ScopeInfo.h')
-rw-r--r--include/clang/Sema/ScopeInfo.h81
1 files changed, 73 insertions, 8 deletions
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 4b54807ab660..4487c7c2ccb6 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -24,6 +24,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSwitch.h"
#include <algorithm>
namespace clang {
@@ -135,6 +136,18 @@ public:
/// false if there is an invocation of an initializer on 'self'.
bool ObjCWarnForNoInitDelegation : 1;
+ /// \brief True only when this function has not already built, or attempted
+ /// to build, the initial and final coroutine suspend points
+ bool NeedsCoroutineSuspends : 1;
+
+ /// \brief An enumeration represeting the kind of the first coroutine statement
+ /// in the function. One of co_return, co_await, or co_yield.
+ unsigned char FirstCoroutineStmtKind : 2;
+
+ /// First coroutine statement in the current function.
+ /// (ex co_return, co_await, co_yield)
+ SourceLocation FirstCoroutineStmtLoc;
+
/// First 'return' statement in the current function.
SourceLocation FirstReturnLoc;
@@ -157,12 +170,10 @@ public:
SmallVector<ReturnStmt*, 4> Returns;
/// \brief The promise object for this coroutine, if any.
- VarDecl *CoroutinePromise;
+ VarDecl *CoroutinePromise = nullptr;
- /// \brief The list of coroutine control flow constructs (co_await, co_yield,
- /// co_return) that occur within the function or block. Empty if and only if
- /// this function or block is not (yet known to be) a coroutine.
- SmallVector<Stmt*, 4> CoroutineStmts;
+ /// \brief The initial and final coroutine suspend points.
+ std::pair<Stmt *, Stmt *> CoroutineSuspends;
/// \brief The stack of currently active compound stamement scopes in the
/// function.
@@ -376,7 +387,47 @@ public:
(HasIndirectGoto ||
(HasBranchProtectedScope && HasBranchIntoScope));
}
-
+
+ void setFirstCoroutineStmt(SourceLocation Loc, StringRef Keyword) {
+ assert(FirstCoroutineStmtLoc.isInvalid() &&
+ "first coroutine statement location already set");
+ FirstCoroutineStmtLoc = Loc;
+ FirstCoroutineStmtKind = llvm::StringSwitch<unsigned char>(Keyword)
+ .Case("co_return", 0)
+ .Case("co_await", 1)
+ .Case("co_yield", 2);
+ }
+
+ StringRef getFirstCoroutineStmtKeyword() const {
+ assert(FirstCoroutineStmtLoc.isValid()
+ && "no coroutine statement available");
+ switch (FirstCoroutineStmtKind) {
+ case 0: return "co_return";
+ case 1: return "co_await";
+ case 2: return "co_yield";
+ default:
+ llvm_unreachable("FirstCoroutineStmtKind has an invalid value");
+ };
+ }
+
+ void setNeedsCoroutineSuspends(bool value = true) {
+ assert((!value || CoroutineSuspends.first == nullptr) &&
+ "we already have valid suspend points");
+ NeedsCoroutineSuspends = value;
+ }
+
+ bool hasInvalidCoroutineSuspends() const {
+ return !NeedsCoroutineSuspends && CoroutineSuspends.first == nullptr;
+ }
+
+ void setCoroutineSuspends(Stmt *Initial, Stmt *Final) {
+ assert(Initial && Final && "suspend points cannot be null");
+ assert(CoroutineSuspends.first == nullptr && "suspend points already set");
+ NeedsCoroutineSuspends = false;
+ CoroutineSuspends.first = Initial;
+ CoroutineSuspends.second = Final;
+ }
+
FunctionScopeInfo(DiagnosticsEngine &Diag)
: Kind(SK_Function),
HasBranchProtectedScope(false),
@@ -391,6 +442,7 @@ public:
ObjCWarnForNoDesignatedInitChain(false),
ObjCIsSecondaryInit(false),
ObjCWarnForNoInitDelegation(false),
+ NeedsCoroutineSuspends(true),
ErrorTrap(Diag) { }
virtual ~FunctionScopeInfo();
@@ -452,6 +504,14 @@ public:
/// non-static data member that would hold the capture.
QualType CaptureType;
+ /// \brief Whether an explicit capture has been odr-used in the body of the
+ /// lambda.
+ bool ODRUsed;
+
+ /// \brief Whether an explicit capture has been non-odr-used in the body of
+ /// the lambda.
+ bool NonODRUsed;
+
public:
Capture(VarDecl *Var, bool Block, bool ByRef, bool IsNested,
SourceLocation Loc, SourceLocation EllipsisLoc,
@@ -460,7 +520,8 @@ public:
InitExprAndCaptureKind(
Cpy, !Var ? Cap_VLA : Block ? Cap_Block : ByRef ? Cap_ByRef
: Cap_ByCopy),
- Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(EllipsisLoc), CaptureType(CaptureType),
+ ODRUsed(false), NonODRUsed(false) {}
enum IsThisCapture { ThisCapture };
Capture(IsThisCapture, bool IsNested, SourceLocation Loc,
@@ -468,7 +529,8 @@ public:
: VarAndNestedAndThis(
nullptr, (IsThisCaptured | (IsNested ? IsNestedCapture : 0))),
InitExprAndCaptureKind(Cpy, ByCopy ? Cap_ByCopy : Cap_ByRef),
- Loc(Loc), EllipsisLoc(), CaptureType(CaptureType) {}
+ Loc(Loc), EllipsisLoc(), CaptureType(CaptureType), ODRUsed(false),
+ NonODRUsed(false) {}
bool isThisCapture() const {
return VarAndNestedAndThis.getInt() & IsThisCaptured;
@@ -491,6 +553,9 @@ public:
bool isNested() const {
return VarAndNestedAndThis.getInt() & IsNestedCapture;
}
+ bool isODRUsed() const { return ODRUsed; }
+ bool isNonODRUsed() const { return NonODRUsed; }
+ void markUsed(bool IsODRUse) { (IsODRUse ? ODRUsed : NonODRUsed) = true; }
VarDecl *getVariable() const {
return VarAndNestedAndThis.getPointer();