Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -953,6 +953,9 @@ /// Whether this variable is (C++0x) constexpr. unsigned IsConstexpr : 1; + /// Whether this variable is a suspension point for a resumable expression. + unsigned IsResumable : 1; + /// Whether this variable is the implicit variable for a lambda /// init-capture. unsigned IsInitCapture : 1; @@ -1386,6 +1389,15 @@ NonParmVarDeclBits.IsConstexpr = IC; } + /// Wheither this variable is specified with the 'resumable' keyword. + bool isResumableSpecified() const { + return isa(this) ? false : NonParmVarDeclBits.IsResumable; + } + void setResumableSpecified(bool IR) { + assert(!isa(this)); + NonParmVarDeclBits.IsResumable = IR; + } + /// Whether this variable is the implicit variable for a lambda init-capture. bool isInitCapture() const { return isa(this) ? false : NonParmVarDeclBits.IsInitCapture; @@ -1760,6 +1772,8 @@ unsigned HasImplicitReturnZero : 1; unsigned IsLateTemplateParsed : 1; unsigned IsConstexpr : 1; + unsigned IsResumableSpecified : 1; + unsigned IsImplicitlyResumable : 1; unsigned InstantiationIsPending : 1; /// Indicates if the function uses __try. @@ -1862,7 +1876,7 @@ FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified, - bool isConstexprSpecified) + bool isConstexprSpecified, bool isResumableSpecified) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), DeclContext(DK), redeclarable_base(C), SClass(S), @@ -1870,13 +1884,15 @@ IsExplicitSpecified(false), IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), IsTrivialForCall(false), - IsDefaulted(false), - IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), - IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), - InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false), - WillHaveBody(false), IsMultiVersion(false), - IsCopyDeductionCandidate(false), HasODRHash(false), ODRHash(0), - EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) {} + IsDefaulted(false), IsExplicitlyDefaulted(false), + HasImplicitReturnZero(false), IsLateTemplateParsed(false), + IsConstexpr(isConstexprSpecified), + IsResumableSpecified(isResumableSpecified), + IsImplicitlyResumable(false), InstantiationIsPending(false), + UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false), + IsMultiVersion(false), IsCopyDeductionCandidate(false), + HasODRHash(false), ODRHash(0), EndRangeLoc(NameInfo.getEndLoc()), + DNLoc(NameInfo.getInfo()) {} using redeclarable_base = Redeclarable; @@ -1906,29 +1922,23 @@ using redeclarable_base::getMostRecentDecl; using redeclarable_base::isFirstDecl; - static FunctionDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, SourceLocation NLoc, - DeclarationName N, QualType T, - TypeSourceInfo *TInfo, - StorageClass SC, - bool isInlineSpecified = false, - bool hasWrittenPrototype = true, - bool isConstexprSpecified = false) { + static FunctionDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation NLoc, DeclarationName N, QualType T, + TypeSourceInfo *TInfo, StorageClass SC, bool isInlineSpecified = false, + bool hasWrittenPrototype = true, bool isConstexprSpecified = false, + bool isResumableSpecified = false) { DeclarationNameInfo NameInfo(N, NLoc); - return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, - SC, + return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC, isInlineSpecified, hasWrittenPrototype, - isConstexprSpecified); + isConstexprSpecified, isResumableSpecified); } - static FunctionDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass SC, - bool isInlineSpecified, - bool hasWrittenPrototype, - bool isConstexprSpecified = false); + static FunctionDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype, + bool isConstexprSpecified = false, bool isResumableSpecified = false); static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2088,6 +2098,16 @@ bool isConstexpr() const { return IsConstexpr; } void setConstexpr(bool IC) { IsConstexpr = IC; } + bool isResumable() const { + return IsResumableSpecified || IsImplicitlyResumable; + } + + bool isResumableSpecified() const { return IsResumableSpecified; } + void setResumableSpecified(bool IR) { IsResumableSpecified = IR; } + + bool isImplicitlyResumable() const { return IsImplicitlyResumable; } + void setImplicitlyResumable(bool IR) { IsImplicitlyResumable = IR; } + /// Whether the instantiation of this function is pending. /// This bit is set when the decision to instantiate this function is made /// and unset if and when the function body is created. That leaves out Index: include/clang/AST/DeclCXX.h =================================================================== --- include/clang/AST/DeclCXX.h +++ include/clang/AST/DeclCXX.h @@ -1984,7 +1984,7 @@ QualType T, TypeSourceInfo *TInfo, SourceLocation EndLocation) : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo, - SC_None, false, false) { + SC_None, false, false, false) { if (EndLocation.isValid()) setRangeEnd(EndLocation); IsExplicitSpecified = IsExplicit; @@ -2034,11 +2034,11 @@ protected: CXXMethodDecl(Kind DK, ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass SC, bool isInline, - bool isConstexpr, SourceLocation EndLocation) - : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, - SC, isInline, isConstexpr) { + QualType T, TypeSourceInfo *TInfo, StorageClass SC, + bool isInline, bool isConstexpr, bool isResumable, + SourceLocation EndLocation) + : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, isInline, + isConstexpr, isResumable) { if (EndLocation.isValid()) setRangeEnd(EndLocation); } @@ -2046,12 +2046,10 @@ public: static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass SC, - bool isInline, - bool isConstexpr, - SourceLocation EndLocation); + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, StorageClass SC, + bool isInline, bool isConstexpr, + bool isResumable, SourceLocation EndLocation); static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2475,14 +2473,14 @@ unsigned IsInheritingConstructor : 1; CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isExplicitSpecified, bool isInline, - bool isImplicitlyDeclared, bool isConstexpr, + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, bool isExplicitSpecified, + bool isInline, bool isImplicitlyDeclared, bool isConstexpr, InheritedConstructor Inherited) - : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, isConstexpr, SourceLocation()), - NumCtorInitializers(0), IsInheritingConstructor((bool)Inherited) { + : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, + SC_None, isInline, isConstexpr, /*isResumable=*/false, + SourceLocation()), + NumCtorInitializers(0), IsInheritingConstructor((bool)Inherited) { setImplicit(isImplicitlyDeclared); if (Inherited) *getTrailingObjects() = Inherited; @@ -2693,12 +2691,12 @@ Expr *OperatorDeleteThisArg = nullptr; CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isImplicitlyDeclared) - : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, /*isConstexpr=*/false, SourceLocation()) - { + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, bool isInline, + bool isImplicitlyDeclared) + : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo, + SC_None, isInline, /*isConstexpr=*/false, + /*isResumable=*/false, SourceLocation()) { setImplicit(isImplicitlyDeclared); } @@ -2750,9 +2748,10 @@ const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicitSpecified, bool isConstexpr, - SourceLocation EndLocation) + bool isResumable, SourceLocation EndLocation) : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, isConstexpr, EndLocation) { + SC_None, isInline, isConstexpr, isResumable, + EndLocation) { IsExplicitSpecified = isExplicitSpecified; } @@ -2762,13 +2761,11 @@ friend class ASTDeclReader; friend class ASTDeclWriter; - static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit, - bool isConstexpr, - SourceLocation EndLocation); + static CXXConversionDecl * + Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isExplicit, bool isConstexpr, bool isResumable, + SourceLocation EndLocation); static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID); /// Whether this function is marked as explicit explicitly. Index: include/clang/AST/Stmt.h =================================================================== --- include/clang/AST/Stmt.h +++ include/clang/AST/Stmt.h @@ -113,6 +113,14 @@ unsigned IsConstexpr : 1; }; + class BreakStmtBitfields { + friend class BreakStmt; + + unsigned : NumStmtBits; + + unsigned IsResumable : 1; + }; + class ExprBitfields { friend class ASTStmtReader; // deserialization friend class AtomicExpr; // ctor @@ -295,6 +303,7 @@ StmtBitfields StmtBits; CompoundStmtBitfields CompoundStmtBits; IfStmtBitfields IfStmtBits; + BreakStmtBitfields BreakStmtBits; ExprBitfields ExprBits; CharacterLiteralBitfields CharacterLiteralBits; FloatingLiteralBitfields FloatingLiteralBits; @@ -1396,21 +1405,36 @@ /// BreakStmt - This represents a break. class BreakStmt : public Stmt { SourceLocation BreakLoc; + SourceLocation ResumableLoc; public: - BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) { - static_assert(sizeof(BreakStmt) == 2 * sizeof(SourceLocation), + BreakStmt(SourceLocation BL, bool IsResumable = false, + SourceLocation ResumableLoc = SourceLocation()) + : Stmt(BreakStmtClass), BreakLoc(BL), ResumableLoc(ResumableLoc) { + assert(IsResumable == ResumableLoc.isValid()); + BreakStmtBits.IsResumable = IsResumable; + // FIXME(EricWF): Figure out why this assert was here, and specified + // sizeof(BreakStmt) == 2 * sizeof(SourceLocation) + static_assert(sizeof(BreakStmt) == 4 * sizeof(SourceLocation), "BreakStmt too large"); } /// Build an empty break statement. explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) {} + bool isResumableSpecified() const { return BreakStmtBits.IsResumable; } + void setResumableSpecified() { BreakStmtBits.IsResumable = true; } + SourceLocation getBreakLoc() const { return BreakLoc; } void setBreakLoc(SourceLocation L) { BreakLoc = L; } + SourceLocation getResumableLoc() const { return ResumableLoc; } + void setResumableLoc(SourceLocation L) { ResumableLoc = L; } + SourceLocation getLocStart() const LLVM_READONLY { return BreakLoc; } - SourceLocation getLocEnd() const LLVM_READONLY { return BreakLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return isResumableSpecified() ? ResumableLoc : BreakLoc; + } static bool classof(const Stmt *T) { return T->getStmtClass() == BreakStmtClass; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -686,6 +686,8 @@ def note_main_remove_noreturn : Note<"remove '_Noreturn'">; def err_constexpr_main : Error< "'main' is not allowed to be declared constexpr">; +def err_resumable_main : Error< + "'main' is not allowed to be declared resumable">; def err_deleted_main : Error<"'main' is not allowed to be deleted">; def err_mainlike_template_decl : Error<"%0 cannot be a template">; def err_main_returns_nonint : Error<"'main' must return 'int'">; @@ -2394,6 +2396,48 @@ def note_private_extern : Note< "use __attribute__((visibility(\"hidden\"))) attribute instead">; +// C++ Resumable functions +def err_resumable_ctor_dtor : Error< + "%select{constructor|destructor}0 cannot be marked resumable">; +def err_invalid_resumable : Error< + "%select{function parameter|typedef|non-static data member|global variable}0 " + "cannot be resumable">; +def err_resumable_tag : Error< + "%select{class|struct|interface|union|enum}0 cannot be marked resumable">; +def err_resumable_no_declarators : Error< + "resumable can only be used in variable and function declarations">; +def err_invalid_resumable_var_decl : Error< + "resumable variable declaration must be a definition">; +def err_resumable_redecl_mismatch : Error< + "%select{non-resumable declaration of %0 follows resumable declaration" + "|resumable declaration of %0 follows non-resumable declaration}1">; +def err_resumable_virtual : Error<"virtual function cannot be resumable">; +def err_resumable_local_var_static : Error< + "%select{static|thread_local}1 variable not permitted in a resumable " + "%select{function|constructor}0">; +def err_resumable_var_decl_type : Error< + "resumable variable cannot be declared with type %0; " + "declared type must be 'auto'">; +def err_resumable_var_decl_constexpr : Error< + "resumable variable declaration %0 cannot be constexpr">; +def err_resumable_var_decl_requires_init : Error< + "resumable variable declaration %0 requires an initializer">; +def err_resumable_func_is_coroutine : Error< + "resumable function %0 cannot be a coroutine">; +def err_resumable_var_decl_init_not_call_expr : Error< + "initializer for the resumable variable declaration %0 must be a call to a " + "resumable function">; +def err_resumable_var_decl_init_not_resumable_expr : Error< + "initializer for resumable variable declaration %0 calls a non-resumable " + "function">; +def note_function_declared_here : Note< + "function declared here">; +def err_addrof_resumable_fn : Error< + "cannot take address of resumable function %0">; +def note_addrof_ovl_candidate_resumable_fn : Note< + "candidate function address cannot be taken because the function is resumable">; + + // C++ Concepts TS def err_concept_wrong_decl_kind : Error< "'concept' can only appear on the definition of a function template or variable template">; @@ -7922,6 +7966,8 @@ "'continue' statement not in loop statement">; def err_break_not_in_loop_or_switch : Error< "'break' statement not in loop or switch statement">; +def err_break_resumable_not_in_resumable_function : Error< + "'break resumable' statement not in a resumable function">; def warn_loop_ctrl_binds_to_inner : Warning< "'%0' is bound to current loop, GCC binds it to the enclosing loop">, InGroup; @@ -9287,8 +9333,8 @@ "attributes">; def err_multiversion_diff : Error< "multiversioned function declaration has a different %select{calling convention" - "|return type|constexpr specification|inline specification|storage class|" - "linkage}0">; + "|return type|constexpr specification|inline specification" + "|resumable specification|storage class|linkage}0">; def err_multiversion_doesnt_support : Error< "multiversioned functions do not yet support %select{function templates|" "virtual functions|deduced return types|constructors|destructors|" Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -140,6 +140,7 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly") LANGOPT(CoroutinesTS , 1, 0, "C++ coroutines TS") LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments") +LANGOPT(ResumableFunctions, 1, 0, "C++ Resumable Functions (N4453)") LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -379,6 +379,9 @@ KEYWORD(co_return , KEYCOROUTINES) KEYWORD(co_yield , KEYCOROUTINES) +// C++ resumable function proposal keywords (N4453) +KEYWORD(resumable, KEYRESUMABLEFUNCS) + // C++ modules TS keywords MODULES_KEYWORD(module) MODULES_KEYWORD(import) Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -670,6 +670,11 @@ def fno_coroutines_ts : Flag <["-"], "fno-coroutines-ts">, Group, Flags<[DriverOption]>; +// C++ Resumable Functions (N4453) +def fresumable_functions : Flag<["-"], "fresumable-functions">, Group, + Flags<[DriverOption, CC1Option]>, + HelpText<"Enable support for C++ resumable functions">; + def fembed_bitcode_EQ : Joined<["-"], "fembed-bitcode=">, Group, Flags<[DriverOption, CC1Option]>, MetaVarName<"