From 131300b30f4e79ed7371175208c13a940d951ba1 Mon Sep 17 00:00:00 2001 From: jeanniely Date: Mon, 3 Jul 2023 11:26:19 +0800 Subject: [PATCH 1/8] [BSC] Coroutine: async/await keyword init --- clang/include/clang/AST/Decl.h | 17 +++- clang/include/clang/AST/DeclBase.h | 1 + clang/include/clang/AST/DeclCXX.h | 23 +++-- clang/include/clang/AST/Expr.h | 34 ++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 1 + clang/include/clang/ASTMatchers/ASTMatchers.h | 11 +++ clang/include/clang/Basic/Attr.td | 3 + .../clang/Basic/DiagnosticSemaKinds.td | 6 ++ clang/include/clang/Basic/StmtNodes.td | 3 + clang/include/clang/Basic/TokenKinds.def | 6 ++ clang/include/clang/Sema/DeclSpec.h | 20 +++-- .../include/clang/Serialization/ASTBitCodes.h | 1 + clang/lib/AST/ASTImporter.cpp | 11 +-- clang/lib/AST/Decl.cpp | 12 +-- clang/lib/AST/DeclCXX.cpp | 11 +-- clang/lib/AST/DeclPrinter.cpp | 2 + clang/lib/AST/Expr.cpp | 1 + clang/lib/AST/ExprClassification.cpp | 1 + clang/lib/AST/ExprConstant.cpp | 1 + clang/lib/AST/JSONNodeDumper.cpp | 1 + clang/lib/AST/ODRHash.cpp | 1 + clang/lib/AST/StmtPrinter.cpp | 6 ++ clang/lib/AST/StmtProfile.cpp | 2 + clang/lib/AST/TextNodeDumper.cpp | 2 + clang/lib/Basic/IdentifierTable.cpp | 83 ++++++++++--------- clang/lib/CodeGen/CGExprScalar.cpp | 1 + clang/lib/Parse/ParseDecl.cpp | 7 ++ clang/lib/Parse/ParseExpr.cpp | 10 +++ clang/lib/Parse/ParseObjc.cpp | 1 + clang/lib/Parse/ParseTentative.cpp | 2 + clang/lib/Sema/DeclSpec.cpp | 15 +++- clang/lib/Sema/SemaDecl.cpp | 12 ++- clang/lib/Sema/SemaExceptionSpec.cpp | 1 + clang/lib/Sema/TreeTransform.h | 24 ++++++ clang/lib/Serialization/ASTReaderDecl.cpp | 1 + clang/lib/Serialization/ASTReaderStmt.cpp | 13 +++ clang/lib/Serialization/ASTWriterDecl.cpp | 2 + clang/lib/Serialization/ASTWriterStmt.cpp | 11 +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + clang/tools/libclang/CXCursor.cpp | 1 + .../Clang/NameSearchContext.cpp | 7 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 3 +- .../TypeSystem/Clang/TypeSystemClang.h | 2 +- 43 files changed, 290 insertions(+), 84 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 84f7feb57567..334d5363297f 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2017,7 +2017,8 @@ protected: const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin, bool isInlineSpecified, ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause = nullptr); + Expr *TrailingRequiresClause = nullptr, + bool isAsyncSpecified = false); using redeclarable_base = Redeclarable; @@ -2053,12 +2054,13 @@ public: TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin = false, bool isInlineSpecified = false, bool hasWrittenPrototype = true, ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified, - Expr *TrailingRequiresClause = nullptr) { + Expr *TrailingRequiresClause = nullptr, + bool isAsyncSpecified = false) { DeclarationNameInfo NameInfo(N, NLoc); return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, isInlineSpecified, hasWrittenPrototype, ConstexprKind, - TrailingRequiresClause); + TrailingRequiresClause, isAsyncSpecified); } static FunctionDecl * @@ -2066,7 +2068,7 @@ public: const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified, bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause); + Expr *TrailingRequiresClause, bool isAsyncSpecified = false); static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2629,6 +2631,13 @@ public: FunctionDeclBits.SClass = SClass; } + /// Determine whether the "async" keyword was specified for this + /// function. + bool isAsyncSpecified() const { return FunctionDeclBits.IsAsyncSpecified; } + + /// Set whether the "async" keyword was specified for this function. + void setAsyncSpecified(bool I) { FunctionDeclBits.IsAsyncSpecified = I; } + /// Determine whether the "inline" keyword was specified for this /// function. bool isInlineSpecified() const { return FunctionDeclBits.IsInlineSpecified; } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index dabd3bedc71a..ba69ba2132e4 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1601,6 +1601,7 @@ class DeclContext { uint64_t SClass : 3; uint64_t IsInline : 1; uint64_t IsInlineSpecified : 1; + uint64_t IsAsyncSpecified : 1; uint64_t IsVirtualAsWritten : 1; uint64_t IsPure : 1; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 02eb280aad24..ae934d25f37c 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1902,14 +1902,12 @@ class BSCMethodDecl : public FunctionDecl { protected: BSCMethodDecl(Kind DK, ASTContext &C, DeclContext *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, - bool isInline, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, - Expr *TrailingRequiresClause = nullptr) - : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, isInline, - ConstexprKind, TrailingRequiresClause) { - //: FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, - // isInline, ConstexprKind, TrailingRequiresClause) { + QualType T, TypeSourceInfo *TInfo, StorageClass SC, + bool UsesFPIntrin, bool isInline, + ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, + Expr *TrailingRequiresClause = nullptr, bool isAsync = false) + : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, + isInline, ConstexprKind, TrailingRequiresClause, isAsync) { if (EndLocation.isValid()) setRangeEnd(EndLocation); } @@ -1918,8 +1916,9 @@ public: static BSCMethodDecl * Create(ASTContext &C, DeclContext *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, bool UsesFPIntrin, bool isInline, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, Expr *TrailingRequiresClause = nullptr); + StorageClass SC, bool UsesFPIntrin, bool isInline, + ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, + Expr *TrailingRequiresClause = nullptr, bool isAsync = false); static BSCMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); bool getHasThisParam() const { return HasThisParam; } @@ -1956,9 +1955,9 @@ protected: QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, bool isInline, ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, - Expr *TrailingRequiresClause = nullptr) + Expr *TrailingRequiresClause = nullptr, bool isAsync = false) : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, - isInline, ConstexprKind, TrailingRequiresClause) { + isInline, ConstexprKind, TrailingRequiresClause, isAsync) { if (EndLocation.isValid()) setRangeEnd(EndLocation); } diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 8602ee27b4f4..aa582da91605 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6471,6 +6471,40 @@ private: friend class ASTStmtWriter; }; +class AwaitExpr final : public Expr { +protected: + Stmt *SubExpr; + +public: + explicit AwaitExpr(SourceLocation AwaitLoc, Expr *Se, QualType Ty) + : Expr(AwaitExprClass, Ty, VK_PRValue, OK_Ordinary), AwaitLoc(AwaitLoc) { + SubExpr = Se; + } + + explicit AwaitExpr(EmptyShell Empty) : Expr(AwaitExprClass, Empty) {} + + SourceLocation getBeginLoc() const { return AwaitLoc; } + SourceLocation getEndLoc() const { return SubExpr->getEndLoc(); } + + const Expr *getSubExpr() const { return cast(SubExpr); } + Expr *getSubExpr() { return cast(SubExpr); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AwaitExprClass; + } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } + const_child_range children() const { + return const_child_range(&SubExpr, &SubExpr + 1); + } + +private: + SourceLocation AwaitLoc; + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + } // end namespace clang #endif // LLVM_CLANG_AST_EXPR_H diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 38cdabec99cf..4038030fbe06 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2412,6 +2412,7 @@ DEF_TRAVERSE_STMT(ObjCAtThrowStmt, {}) DEF_TRAVERSE_STMT(ObjCAtTryStmt, {}) DEF_TRAVERSE_STMT(ObjCForCollectionStmt, {}) DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {}) +DEF_TRAVERSE_STMT(AwaitExpr, {}) DEF_TRAVERSE_STMT(CXXForRangeStmt, { if (!getDerived().shouldVisitImplicitCode()) { diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 9f4d807c232d..2570eccf891a 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -7748,6 +7748,17 @@ AST_MATCHER_P(FunctionDecl, hasExplicitSpecifier, internal::Matcher, return InnerMatcher.matches(*ES.getExpr(), Finder, Builder); } +/// Matches function that are marked with the async keyword. +/// +/// Given +/// \code +/// async void g(); +/// \endcode +/// functionDecl(isAsyncSpecified()) will match ::g(). +AST_MATCHER(FunctionDecl, isAsyncSpecified) { + return (dyn_cast(&Node))->isAsyncSpecified(); +} + /// Matches functions, variables and namespace declarations that are marked with /// the inline keyword. /// diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index f9faec770851..a0a87b0fe161 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -136,6 +136,9 @@ def GlobalVar : SubsetSubjectisInlineSpecified()}], "inline functions">; +def AsyncFunction : SubsetSubjectisAsyncSpecified()}], "async functions">; + def FunctionTmpl : SubsetSubjectgetTemplatedKind() == FunctionDecl::TK_FunctionTemplate}], diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index af888b93a732..5b1657241e0b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -109,6 +109,9 @@ def err_ice_too_large : Error< "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; +// BSC warnings and errors +def err_await_invalid_scope : Error< + "await expression is not allowed to appear in %0">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< "predefined identifier is only valid inside function">, @@ -438,6 +441,8 @@ def err_inline_non_function : Error< "'inline' can only appear on functions%select{| and non-local variables}0">; def err_noreturn_non_function : Error< "'_Noreturn' can only appear on functions">; +def err_async_non_function : Error< + "'async' can only appear on functions">; def warn_qual_return_type : Warning< "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, InGroup, DefaultIgnore; @@ -858,6 +863,7 @@ def warn_static_main : Warning<"'main' should not be declared static">, InGroup
; def err_static_main : Error<"'main' is not allowed to be declared static">; def err_inline_main : Error<"'main' is not allowed to be declared inline">; +def err_async_main : Error<"'main' is not allowed to be declared async">; def ext_variadic_main : ExtWarn< "'main' is not allowed to be declared variadic">, InGroup
; def ext_noreturn_main : ExtWarn< diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index ebbd8db31342..73d02a22d106 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -203,6 +203,9 @@ def TypoExpr : StmtNode; def RecoveryExpr : StmtNode; def BuiltinBitCastExpr : StmtNode; +// BSC Extensions +def AwaitExpr : StmtNode; + // Microsoft Extensions. def MSPropertyRefExpr : StmtNode; def MSPropertySubscriptExpr : StmtNode; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 077ceb41e715..7fb354506c55 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -450,6 +450,12 @@ KEYWORD(__FUNCTION__ , KEYALL) KEYWORD(__PRETTY_FUNCTION__ , KEYALL) KEYWORD(__auto_type , KEYALL) +// BSC Extensions +KEYWORD(__await , KEYBSC) +ALIAS("await", __await, KEYBSC) +KEYWORD(__async , KEYBSC) +ALIAS("async", __async, KEYBSC) + // GNU Extensions (outside impl-reserved namespace) KEYWORD(typeof , KEYGNU) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 2b35dd0e9937..159d70d96134 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -377,6 +377,7 @@ private: unsigned FS_forceinline_specified: 1; unsigned FS_virtual_specified : 1; unsigned FS_noreturn_specified : 1; + unsigned FS_async_specified : 1; // friend-specifier unsigned Friend_specified : 1; @@ -419,7 +420,8 @@ private: SourceRange TypeofParensRange; SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc; - SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc, + FS_asyncLoc; SourceLocation FS_explicitCloseParenLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; @@ -462,11 +464,10 @@ public: TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false), TypeQualifiers(TQ_unspecified), FS_inline_specified(false), FS_forceinline_specified(false), FS_virtual_specified(false), - FS_noreturn_specified(false), Friend_specified(false), - ConstexprSpecifier( - static_cast(ConstexprSpecKind::Unspecified)), - FS_explicit_specifier(), - FS_safe_specified(SS_None), FS_safe_loc(), + FS_noreturn_specified(false), FS_async_specified(false), + Friend_specified(false), ConstexprSpecifier(static_cast( + ConstexprSpecKind::Unspecified)), + FS_explicit_specifier(), FS_safe_specified(SS_None), FS_safe_loc(), Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {} // storage-class-specifier @@ -605,6 +606,9 @@ public: return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc; } + bool isAsyncSpecified() const { return FS_async_specified; } + SourceLocation getAsyncSpecLoc() const { return FS_asyncLoc; } + ExplicitSpecifier getExplicitSpecifier() const { return FS_explicit_specifier; } @@ -638,6 +642,8 @@ public: FS_inlineLoc = SourceLocation(); FS_forceinline_specified = false; FS_forceinlineLoc = SourceLocation(); + FS_async_specified = false; + FS_asyncLoc = SourceLocation(); FS_virtual_specified = false; FS_virtualLoc = SourceLocation(); FS_explicit_specifier = ExplicitSpecifier(); @@ -774,6 +780,8 @@ public: unsigned &DiagID); bool setFunctionSpecForceInline(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); + bool setFunctionSpecAsync(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 089550c517e5..31924d0772a3 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1994,6 +1994,7 @@ enum StmtCode { EXPR_COAWAIT, EXPR_COYIELD, EXPR_DEPENDENT_COAWAIT, + EXPR_BSC_AWAIT, // FixedPointLiteral EXPR_FIXEDPOINT_LITERAL, diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 6ba8f8ca5483..8bb28d0eaef5 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3564,11 +3564,12 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { cast(ToFunction) ->setIsCopyDeductionCandidate(Guide->isCopyDeductionCandidate()); } else { - if (GetImportedOrCreateDecl( - ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, - NameInfo, T, TInfo, D->getStorageClass(), D->UsesFPIntrin(), - D->isInlineSpecified(), D->hasWrittenPrototype(), - D->getConstexprKind(), TrailingRequiresClause)) + if (GetImportedOrCreateDecl(ToFunction, D, Importer.getToContext(), DC, + ToInnerLocStart, NameInfo, T, TInfo, + D->getStorageClass(), D->UsesFPIntrin(), + D->isInlineSpecified(), + D->hasWrittenPrototype(), D->getConstexprKind(), + TrailingRequiresClause, D->isAsyncSpecified())) return ToFunction; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index fc94e6b273c4..26b1c3273cf1 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2941,7 +2941,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin, bool isInlineSpecified, ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause) + Expr *TrailingRequiresClause, bool isAsyncSpecified) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0), @@ -2950,6 +2950,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.SClass = S; FunctionDeclBits.IsInline = isInlineSpecified; FunctionDeclBits.IsInlineSpecified = isInlineSpecified; + FunctionDeclBits.IsAsyncSpecified = isAsyncSpecified; FunctionDeclBits.IsVirtualAsWritten = false; FunctionDeclBits.IsPure = false; FunctionDeclBits.HasInheritedPrototype = false; @@ -5103,10 +5104,11 @@ FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified, bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause) { - FunctionDecl *New = new (C, DC) FunctionDecl( - Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, - isInlineSpecified, ConstexprKind, TrailingRequiresClause); + Expr *TrailingRequiresClause, bool isAsyncSpecified) { + FunctionDecl *New = new (C, DC) + FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, + UsesFPIntrin, isInlineSpecified, ConstexprKind, + TrailingRequiresClause, isAsyncSpecified); New->setHasWrittenPrototype(hasWrittenPrototype); return New; } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 07e15f50bb4b..25220ee84abb 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2113,11 +2113,12 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, BSCMethodDecl *BSCMethodDecl::Create( ASTContext &C, DeclContext *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, bool UsesFPIntrinbool, bool isInline, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, Expr *TrailingRequiresClause) { - return new (C, RD) BSCMethodDecl(BSCMethod, C, RD, StartLoc, NameInfo, T, - TInfo, SC, UsesFPIntrinbool, isInline, ConstexprKind, - EndLocation, TrailingRequiresClause); + StorageClass SC, bool UsesFPIntrinbool, bool isInline, + ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, + Expr *TrailingRequiresClause, bool isAsync) { + return new (C, RD) BSCMethodDecl( + BSCMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrinbool, + isInline, ConstexprKind, EndLocation, TrailingRequiresClause, isAsync); } BSCMethodDecl *BSCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 2c5b47342cef..9c13184cce56 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -637,6 +637,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { } if (D->isInlineSpecified()) Out << "inline "; + if (D->isAsyncSpecified()) + Out << "async "; if (D->isVirtualAsWritten()) Out << "virtual "; if (D->isModulePrivate()) Out << "__module_private__ "; if (D->isConstexprSpecified() && !D->isExplicitlyDefaulted()) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 5b9b844dd072..86c211e9f83c 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3523,6 +3523,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case CoawaitExprClass: case DependentCoawaitExprClass: case CoyieldExprClass: + case AwaitExprClass: // These always have a side-effect. return true; diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 6c122cac2c60..dd41506b48f6 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -136,6 +136,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: case Expr::TypoExprClass: + case Expr::AwaitExprClass: case Expr::DependentCoawaitExprClass: case Expr::CXXDependentScopeMemberExprClass: case Expr::DependentScopeDeclRefExprClass: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index cd852a076d81..35d7bdb2a976 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -15425,6 +15425,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::AtomicExprClass: case Expr::LambdaExprClass: case Expr::CXXFoldExprClass: + case Expr::AwaitExprClass: case Expr::CoawaitExprClass: case Expr::DependentCoawaitExprClass: case Expr::CoyieldExprClass: diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 87e4255c2b93..c80bce38dab0 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -848,6 +848,7 @@ void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) { if (SC != SC_None) JOS.attribute("storageClass", VarDecl::getStorageClassSpecifierString(SC)); attributeOnlyIfTrue("inline", FD->isInlineSpecified()); + attributeOnlyIfTrue("async", FD->isAsyncSpecified()); attributeOnlyIfTrue("virtual", FD->isVirtualAsWritten()); attributeOnlyIfTrue("pure", FD->isPure()); attributeOnlyIfTrue("explicitlyDeleted", FD->isDeletedAsWritten()); diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 4c09029b64e1..8348d369e3fd 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -560,6 +560,7 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function, ID.AddInteger(Function->getStorageClass()); AddBoolean(Function->isInlineSpecified()); + AddBoolean(Function->isAsyncSpecified()); AddBoolean(Function->isVirtualAsWritten()); AddBoolean(Function->isPure()); AddBoolean(Function->isDeletedAsWritten()); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 332026f6081d..7448ba31a992 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2573,6 +2573,12 @@ void StmtPrinter::VisitCoyieldExpr(CoyieldExpr *S) { PrintExpr(S->getOperand()); } +// BSC +void StmtPrinter::VisitAwaitExpr(AwaitExpr *S) { + OS << "await "; + PrintExpr(S->getSubExpr()); +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 92a8b18cf68a..33eda729ca38 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2197,6 +2197,8 @@ void StmtProfiler::VisitDependentCoawaitExpr(const DependentCoawaitExpr *S) { VisitExpr(S); } +void StmtProfiler::VisitAwaitExpr(const AwaitExpr *S) { VisitExpr(S); } + void StmtProfiler::VisitCoyieldExpr(const CoyieldExpr *S) { VisitExpr(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 853a678545ef..0933af6f15ab 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1664,6 +1664,8 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { OS << ' ' << VarDecl::getStorageClassSpecifierString(SC); if (D->isInlineSpecified()) OS << " inline"; + if (D->isAsyncSpecified()) + OS << " async"; if (D->isVirtualAsWritten()) OS << " virtual"; if (D->isModulePrivate()) diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 82cee4aa052d..8dffb5ad016c 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -82,46 +82,47 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, // Constants for TokenKinds.def namespace { - enum { - KEYC99 = 0x1, - KEYCXX = 0x2, - KEYCXX11 = 0x4, - KEYGNU = 0x8, - KEYMS = 0x10, - BOOLSUPPORT = 0x20, - KEYALTIVEC = 0x40, - KEYNOCXX = 0x80, - KEYBORLAND = 0x100, - KEYOPENCLC = 0x200, - KEYC11 = 0x400, - KEYNOMS18 = 0x800, - KEYNOOPENCL = 0x1000, - WCHARSUPPORT = 0x2000, - HALFSUPPORT = 0x4000, - CHAR8SUPPORT = 0x8000, - KEYCONCEPTS = 0x10000, - KEYOBJC = 0x20000, - KEYZVECTOR = 0x40000, - KEYCOROUTINES = 0x80000, - KEYMODULES = 0x100000, - KEYCXX20 = 0x200000, - KEYOPENCLCXX = 0x400000, - KEYMSCOMPAT = 0x800000, - KEYSYCL = 0x1000000, - KEYCUDA = 0x2000000, - KEYMAX = KEYCUDA, // The maximum key - KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20, - KEYALL = (KEYMAX | (KEYMAX-1)) & ~KEYNOMS18 & - ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude. - }; - - /// How a keyword is treated in the selected standard. - enum KeywordStatus { - KS_Disabled, // Disabled - KS_Extension, // Is an extension - KS_Enabled, // Enabled - KS_Future // Is a keyword in future standard - }; +enum { + KEYC99 = 0x1, + KEYCXX = 0x2, + KEYCXX11 = 0x4, + KEYGNU = 0x8, + KEYMS = 0x10, + BOOLSUPPORT = 0x20, + KEYALTIVEC = 0x40, + KEYNOCXX = 0x80, + KEYBORLAND = 0x100, + KEYOPENCLC = 0x200, + KEYC11 = 0x400, + KEYNOMS18 = 0x800, + KEYNOOPENCL = 0x1000, + WCHARSUPPORT = 0x2000, + HALFSUPPORT = 0x4000, + CHAR8SUPPORT = 0x8000, + KEYCONCEPTS = 0x10000, + KEYOBJC = 0x20000, + KEYZVECTOR = 0x40000, + KEYCOROUTINES = 0x80000, + KEYMODULES = 0x100000, + KEYCXX20 = 0x200000, + KEYOPENCLCXX = 0x400000, + KEYMSCOMPAT = 0x800000, + KEYSYCL = 0x1000000, + KEYCUDA = 0x2000000, + KEYBSC = 0x3000000, + KEYMAX = KEYCUDA, // The maximum key + KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20, + KEYALL = (KEYMAX | (KEYMAX - 1)) & ~KEYNOMS18 & + ~KEYNOOPENCL // KEYNOMS18 and KEYNOOPENCL are used to exclude. +}; + +/// How a keyword is treated in the selected standard. +enum KeywordStatus { + KS_Disabled, // Disabled + KS_Extension, // Is an extension + KS_Enabled, // Enabled + KS_Future // Is a keyword in future standard +}; } // namespace @@ -134,6 +135,8 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled; if (LangOpts.CPlusPlus20 && (Flags & KEYCXX20)) return KS_Enabled; if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled; + if (LangOpts.BSC && (Flags & KEYBSC)) + return KS_Enabled; if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension; if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension; if (LangOpts.MSVCCompat && (Flags & KEYMSCOMPAT)) return KS_Enabled; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index b150aaa376eb..b3b9dd88f928 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -447,6 +447,7 @@ public: Value *VisitUnaryCoawait(const UnaryOperator *E) { return Visit(E->getSubExpr()); } + Value *VisitAwaitExpr(AwaitExpr *E) { return Visit(E->getSubExpr()); } // Leaves. Value *VisitIntegerLiteral(const IntegerLiteral *E) { diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 542febb095d8..f5203be739b5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2195,6 +2195,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, if (FirstDecl) DeclsInGroup.push_back(FirstDecl); + bool ExpectSemi = Context != DeclaratorContext::ForInit; // If we don't have a comma, it is either the end of the list (a ';') or an @@ -2604,6 +2605,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS, if (Specs & DeclSpec::PQ_FunctionSpecifier) { if (DS.isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec); + if (DS.isAsyncSpecified()) + Diag(DS.getAsyncSpecLoc(), diag::err_typename_invalid_functionspec); if (DS.isVirtualSpecified()) Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec); if (DS.hasExplicitSpecifier()) @@ -3873,6 +3876,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw_inline: isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID); break; + case tok::kw___async: + isInvalid = DS.setFunctionSpecAsync(Loc, PrevSpec, DiagID); + break; case tok::kw_virtual: // C++ for OpenCL does not allow virtual function qualifier, to avoid // function pointers restricted in OpenCL v2.0 s6.9.a. @@ -5453,6 +5459,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // function-specifier case tok::kw_inline: + case tok::kw___async: case tok::kw_virtual: case tok::kw_explicit: case tok::kw__Noreturn: diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 29a9cfa7d1be..9c98d5e7b2f6 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1453,6 +1453,16 @@ ExprResult Parser::ParseCastExpression( return Res; } + case tok::kw___await: { // unary-expression: 'await' cast-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; + SourceLocation AwaitLoc = ConsumeToken(); + Res = ParseCastExpression(AnyCastExpr); + if (!Res.isInvalid()) + Res = Actions.ActOnAwaitExpr(AwaitLoc, Res.get()); + return Res; + } + case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] // __extension__ silences extension warnings in the subexpression. if (NotPrimaryExpression) diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 734c66f65dc2..dfe83914827e 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -1070,6 +1070,7 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) { case tok::kw_goto: case tok::kw_if: case tok::kw_inline: + case tok::kw___async: case tok::kw_int: case tok::kw_long: case tok::kw_mutable: diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 4c9dcdc629a8..418663de690e 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1232,6 +1232,7 @@ public: /// /// function-specifier: /// 'inline' +/// 'async' /// 'virtual' /// 'explicit' /// @@ -1428,6 +1429,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw__Thread_local: // function-specifier case tok::kw_inline: + case tok::kw___async: case tok::kw_virtual: case tok::kw_explicit: diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index a4d864950771..c9c25d7331c7 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -462,7 +462,8 @@ unsigned DeclSpec::getParsedSpecifiers() const { Res |= PQ_TypeSpecifier; if (FS_inline_specified || FS_virtual_specified || hasExplicitSpecifier() || - FS_noreturn_specified || FS_forceinline_specified || FS_safe_specified) + FS_noreturn_specified || FS_forceinline_specified || FS_safe_specified || + FS_async_specified) Res |= PQ_FunctionSpecifier; return Res; } @@ -1010,6 +1011,18 @@ bool DeclSpec::setFunctionSpecForceInline(SourceLocation Loc, const char *&PrevS return false; } +bool DeclSpec::setFunctionSpecAsync(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + if (FS_async_specified) { + DiagID = diag::warn_duplicate_declspec; + PrevSpec = "async"; + return true; + } + FS_async_specified = true; + FS_asyncLoc = Loc; + return false; +} + bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ab704fe54b8f..7b5435f2b4bd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6578,6 +6578,9 @@ void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) { if (DS.isNoreturnSpecified()) Diag(DS.getNoreturnSpecLoc(), diag::err_noreturn_non_function); + + if (DS.isAsyncSpecified()) + Diag(DS.getAsyncSpecLoc(), diag::err_async_non_function); } NamedDecl* @@ -8945,6 +8948,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, FunctionDecl *NewFD = nullptr; bool isInline = D.getDeclSpec().isInlineSpecified(); + bool isAsync = D.getDeclSpec().isAsyncSpecified(); if (!SemaRef.getLangOpts().CPlusPlus) { // Determine whether the function was written with a prototype. This is @@ -8973,7 +8977,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, // FIXME: check whether UsesFPIntrin(before arg "isInline") is false? BSCMethodDecl *Ret = BSCMethodDecl::Create( SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, - false, isInline, ConstexprKind, SourceLocation(), TrailingRequiresClause); + SemaRef.getCurFPFeatures().isFPConstrained(), isInline, ConstexprKind, + SourceLocation(), TrailingRequiresClause, isAsync); Ret->setHasThisParam(D.getBSCScopeSpec().HasThisParam); Ret->setExtendedType(D.getBSCScopeSpec().getExtendedType()); Ret->setExtentedTypeBeginLoc(D.getBSCScopeSpec().getBeginLoc()); @@ -8993,7 +8998,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, SemaRef.getCurFPFeatures().isFPConstrained(), isInline, HasPrototype, ConstexprSpecKind::Unspecified, - /*TrailingRequiresClause=*/nullptr); + /*TrailingRequiresClause=*/nullptr, isAsync); if (D.isInvalidType()) NewFD->setInvalidDecl(); @@ -11717,6 +11722,9 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { if (FD->isInlineSpecified()) Diag(DS.getInlineSpecLoc(), diag::err_inline_main) << FixItHint::CreateRemoval(DS.getInlineSpecLoc()); + if (FD->isAsyncSpecified()) + Diag(DS.getAsyncSpecLoc(), diag::err_async_main) + << FixItHint::CreateRemoval(DS.getAsyncSpecLoc()); if (DS.isNoreturnSpecified()) { SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc(); SourceRange NoreturnRange(NoreturnLoc, getLocForEndOfToken(NoreturnLoc)); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index d8344cfd01f9..7098d2ca00fb 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1308,6 +1308,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: case Expr::BinaryOperatorClass: + case Expr::AwaitExprClass: case Expr::DependentCoawaitExprClass: case Expr::CompoundAssignOperatorClass: case Expr::CStyleCastExprClass: diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 23aebf064cc7..a2f85342920b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3795,6 +3795,14 @@ public: Sema::AtomicArgumentOrder::AST); } + /// Build a new await operation expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildAwaitExpr(SourceLocation BuiltinLoc, Expr *SubExprs) { + return getSema().BuildAwaitExpr(BuiltinLoc, SubExprs); + } + ExprResult RebuildRecoveryExpr(SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef SubExprs, QualType Type) { return getSema().CreateRecoveryExpr(BeginLoc, EndLoc, SubExprs, Type); @@ -14450,6 +14458,22 @@ TreeTransform::TransformAtomicExpr(AtomicExpr *E) { E->getOp(), E->getRParenLoc()); } +//===----------------------------------------------------------------------===// +// BSC await expression transform +//===----------------------------------------------------------------------===// +template +ExprResult TreeTransform::TransformAwaitExpr(AwaitExpr *E) { + ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + if (SubExpr.isInvalid()) + return ExprError(); + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getSubExpr()) + return E; + + return getDerived().RebuildAwaitExpr(E->getBeginLoc(), SubExpr.get()); +} + //===----------------------------------------------------------------------===// // Type reconstruction //===----------------------------------------------------------------------===// diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 998314108984..478269b9ff8d 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -913,6 +913,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setSafeSpecifier(static_cast(Record.readInt())); FD->setInlineSpecified(Record.readInt()); FD->setImplicitlyInline(Record.readInt()); + FD->setAsyncSpecified(Record.readInt()); FD->setVirtualAsWritten(Record.readInt()); // We defer calling `FunctionDecl::setPure()` here as for methods of // `CXXTemplateSpecializationDecl`s, we may not have connected up the diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 08d592d1b9b0..8f08c5994d7e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -497,6 +497,15 @@ void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { SubExpr = Record.readSubStmt(); } +//===----------------------------------------------------------------------===// +// BSC Expressions +//===----------------------------------------------------------------------===// +void ASTStmtReader::VisitAwaitExpr(AwaitExpr *E) { + VisitExpr(E); + E->AwaitLoc = readSourceLocation(); + E->SubExpr = Record.readSubStmt(); +} + void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); Record.skipInts(1); @@ -3999,6 +4008,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) DependentCoawaitExpr(Empty); break; + case EXPR_BSC_AWAIT: + S = new (Context) AwaitExpr(Empty); + break; + case EXPR_CONCEPT_SPECIALIZATION: { unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields]; S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 84479ed6b1bc..4b8f64b2c830 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -551,6 +551,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->getSafeSpecifier()); Record.push_back(D->isInlineSpecified()); Record.push_back(D->isInlined()); + Record.push_back(D->isAsyncSpecified()); Record.push_back(D->isVirtualAsWritten()); Record.push_back(D->isPure()); Record.push_back(D->hasInheritedPrototype()); @@ -2278,6 +2279,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AsyncSpecified Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index ce622a1991da..e47ce0c26373 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1519,6 +1519,17 @@ void ASTStmtWriter::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) Code = serialization::EXPR_OBJC_AVAILABILITY_CHECK; } +//===----------------------------------------------------------------------===// +// BSC Expressions. +//===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitAwaitExpr(AwaitExpr *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getBeginLoc()); + for (Stmt *S : E->children()) + Record.AddStmt(S); + Code = serialization::EXPR_BSC_AWAIT; +} + //===----------------------------------------------------------------------===// // C++ Expressions and Statements. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 19149d079822..14fb5afdc3e3 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1403,6 +1403,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::DependentCoawaitExprClass: case Stmt::CoreturnStmtClass: case Stmt::CoyieldExprClass: + case Stmt::AwaitExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::SEHLeaveStmtClass: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index 15294dac0977..a535639f91fa 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -299,6 +299,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::BinaryConditionalOperatorClass: case Stmt::TypeTraitExprClass: case Stmt::CoawaitExprClass: + case Stmt::AwaitExprClass: case Stmt::DependentCoawaitExprClass: case Stmt::CoyieldExprClass: case Stmt::CXXBindTemporaryExprClass: diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp index a672045dfe31..34c38fcd5fa7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -58,6 +58,7 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, clang::ASTContext &ast = lldb_ast->getASTContext(); const bool isInlineSpecified = false; + const bool isAsyncSpecified = false; const bool hasWrittenPrototype = true; const bool isConstexprSpecified = false; @@ -79,9 +80,11 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, clang::FunctionDecl *func_decl = FunctionDecl::Create( ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, - nullptr, SC_Extern, /*UsesFPIntrin=*/false, isInlineSpecified, hasWrittenPrototype, + nullptr, SC_Extern, /*UsesFPIntrin=*/false, isInlineSpecified, + hasWrittenPrototype, isConstexprSpecified ? ConstexprSpecKind::Constexpr - : ConstexprSpecKind::Unspecified); + : ConstexprSpecKind::Unspecified, + isAsyncSpecified); // We have to do more than just synthesize the FunctionDecl. We have to // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index a1ebe5830bb9..8876a0dd2864 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2139,7 +2139,7 @@ std::string TypeSystemClang::GetTypeNameForDecl(const NamedDecl *named_decl) { FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, llvm::StringRef name, const CompilerType &function_clang_type, - clang::StorageClass storage, bool is_inline) { + clang::StorageClass storage, bool is_inline, bool is_async) { FunctionDecl *func_decl = nullptr; ASTContext &ast = getASTContext(); if (!decl_ctx) @@ -2156,6 +2156,7 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( func_decl->setType(ClangUtil::GetQualType(function_clang_type)); func_decl->setStorageClass(storage); func_decl->setInlineSpecified(is_inline); + func_decl->setAsyncSpecified(is_async); func_decl->setHasWrittenPrototype(hasWrittenPrototype); func_decl->setConstexprKind(isConstexprSpecified ? ConstexprSpecKind::Constexpr diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 7f25a6df548f..88298ad9bf94 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -396,7 +396,7 @@ public: clang::FunctionDecl *CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, llvm::StringRef name, const CompilerType &function_Type, - clang::StorageClass storage, bool is_inline); + clang::StorageClass storage, bool is_inline, bool is_async = false); CompilerType CreateFunctionType(const CompilerType &result_type, const CompilerType *args, unsigned num_args, -- Gitee From b4f394d30f292d555157baf4ae7d7b8758967c40 Mon Sep 17 00:00:00 2001 From: yangdian Date: Mon, 3 Jul 2023 11:37:40 +0800 Subject: [PATCH 2/8] [BSC] Coroutine: desugar for async/await expr --- .../clang/Basic/DiagnosticSemaKinds.td | 5 + clang/include/clang/Sema/Sema.h | 11 + clang/lib/AST/Decl.cpp | 3 + clang/lib/Parse/ParseDecl.cpp | 13 + clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaBSCCoroutine.cpp | 1264 +++++++++++++++++ clang/lib/Sema/SemaExpr.cpp | 61 +- 7 files changed, 1357 insertions(+), 1 deletion(-) create mode 100644 clang/lib/Sema/SemaBSCCoroutine.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5b1657241e0b..294909abad29 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -112,6 +112,11 @@ def err_expr_not_string_literal : Error<"expression is not a string literal">; // BSC warnings and errors def err_await_invalid_scope : Error< "await expression is not allowed to appear in %0">; +def err_not_a_async_call : Error< + "the await expression's external function declaration must be modified by async">; +def err_function_not_found : Error < + "'%0' was not found, you need to include %1 before using the 'async' keyword">; + // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< "predefined identifier is only valid inside function">, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e00dd6f6b042..f889a9a8c3d6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3175,6 +3175,17 @@ public: Decl *ActOnFinishExportDecl(Scope *S, Decl *ExportDecl, SourceLocation RBraceLoc); + /// The parser has processed a await declaration. + /// \param AwaitLoc The location of the await token in the declaration. + /// \param E await expression + ExprResult BuildAwaitExpr(SourceLocation AwaitLoc, Expr *E); + ExprResult ActOnAwaitExpr(SourceLocation AwaitLoc, Expr *E); + + // Entry + void ActOnAsyncFunctionDefinition(FunctionDecl *FD, + SmallVector DeclsInGroup); + SmallVector ActOnAsyncFunctionDeclaration(FunctionDecl *FD); + /// We've found a use of a templated declaration that would trigger an /// implicit instantiation. Check that any relevant explicit specializations /// and partial specializations are visible/reachable, and diagnose if not. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 26b1c3273cf1..8749b02c8dfa 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3303,6 +3303,9 @@ bool FunctionDecl::isGlobal() const { if (const auto *Method = dyn_cast(this)) return Method->isStatic(); + if (const auto *Method = dyn_cast(this)) + return Method->isStatic(); + if (getCanonicalDecl()->getStorageClass() == SC_Static) return false; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f5203be739b5..f2edd1891652 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2126,6 +2126,13 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, Decl *TheDecl = ParseFunctionDefinition(D, ParsedTemplateInfo(), &LateParsedAttrs); + + FunctionDecl *FD = dyn_cast_or_null(TheDecl); + if (getLangOpts().BSC && FD && FD->isAsyncSpecified()) { + SmallVector decls = + Actions.ActOnAsyncFunctionDeclaration(FD); + return Actions.BuildDeclaratorGroup(decls); + } return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -2195,6 +2202,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, if (FirstDecl) DeclsInGroup.push_back(FirstDecl); + if (FirstDecl) { + FunctionDecl *FD = dyn_cast_or_null(FirstDecl); + if (getLangOpts().BSC && FD && FD->isAsyncSpecified()) { + Actions.ActOnAsyncFunctionDefinition(FD, DeclsInGroup); + } + } bool ExpectSemi = Context != DeclaratorContext::ForInit; diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index ffe3e1bb9e2e..c5fa314ff824 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(clangSema SemaAccess.cpp SemaAttr.cpp SemaAvailability.cpp + SemaBSCCoroutine.cpp SemaCXXScopeSpec.cpp SemaCast.cpp SemaChecking.cpp diff --git a/clang/lib/Sema/SemaBSCCoroutine.cpp b/clang/lib/Sema/SemaBSCCoroutine.cpp new file mode 100644 index 000000000000..af0a36d0bd25 --- /dev/null +++ b/clang/lib/Sema/SemaBSCCoroutine.cpp @@ -0,0 +1,1264 @@ +//===--- SemaBSCCoroutine.cpp - Semantic Analysis for BSC Coroutines +//----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for BSC Coroutines. +// +//===----------------------------------------------------------------------===// + +#include "TreeTransform.h" +#include "TypeLocBuilder.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/NonTrivialTypeVisitor.h" +#include "clang/AST/Randstruct.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Template.h" +#include "llvm/ADT/SmallString.h" +#include +#include +#include + +using namespace clang; +using namespace sema; + + +namespace { +class AwaitExprFinder : public StmtVisitor { + int AwaitCount = 0; + std::vector Args; + std::vector> LocalVarList; + +public: + void VisitAwaitExpr(AwaitExpr *E) { + Visit(E->getSubExpr()); + Args.push_back(E); + AwaitCount++; + } + + void VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + if (auto DeclS = dyn_cast_or_null(C)) { + for (const auto &DI : DeclS->decls()) { + if (auto VD = dyn_cast_or_null(DI)) { + QualType QT = VD->getType(); + if (QT.isConstQualified()) { + QT.removeLocalConst(); + VD->setType(QT); + } + LocalVarList.push_back(std::make_pair( + VD->getDeclName(), VD->getType())); + } + } + } + Visit(C); + } + } + } + + int GetAwaitExprNum() const { return AwaitCount; } + + std::vector GetAwaitExpr() const { return Args; } + + std::vector> GetLocalVarList() const { + return LocalVarList; + } +}; + +bool HasAwaitExpr(Stmt *S) { + if (S == nullptr) + return false; + + if (isa(S)) + return true; + + for (auto *C : S->children()) { + if (HasAwaitExpr(C)) { + return true; + } + } + + return false; +} + + +std::string GetPrefix(QualType T) { + std::string ExtendedTypeStr = T.getAsString(); + for (int i = ExtendedTypeStr.length() - 1; i >= 0; i--) { + if (ExtendedTypeStr[i] == ' ') { + ExtendedTypeStr.replace(i, 1, "_"); + } + } + return ExtendedTypeStr; +} + +bool IsFutureType(QualType T) { + std::string prefix = "struct __FatPointer_"; + std::string string = T.getAsString(); + bool isPrefix = + prefix.size() <= string.size() && + std::mismatch(prefix.begin(), prefix.end(), string.begin(), string.end()) + .first == prefix.end(); + return isPrefix; +} + +static QualType lookupPollResultType(Sema &S, SourceLocation SLoc, QualType T) { + std::string PollResultName = "PollResult"; + + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(PollResultName))); + ClassTemplateDecl *CTD = nullptr; + if (Decls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) { + if (isa(*I)) { + CTD = dyn_cast(*I); + break; + } + } + } else { + S.Diag(SLoc, diag::err_function_not_found) + << PollResultName << "\"future.hbs\""; + return QualType(); + } + + TemplateArgumentListInfo Args(SLoc, SLoc); + Args.addArgument(TemplateArgumentLoc( + TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, SLoc))); + QualType PollResultRecord = + S.CheckTemplateIdType(TemplateName(CTD), SourceLocation(), Args); + + if (PollResultRecord.isNull()) + return QualType(); + if (S.RequireCompleteType(SLoc, PollResultRecord, + diag::err_coroutine_type_missing_specialization)) + return QualType(); + return PollResultRecord; +} +} // namespace + +// build struct Future for async function +static RecordDecl *buildFutureRecordDecl( + Sema &S, FunctionDecl *FD, ArrayRef Args, + std::vector> LocalVarList) { + std::vector> paramList; + DeclarationName funcName = FD->getDeclName(); + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation ELoc = FD->getEndLoc(); + for (FunctionDecl::param_const_iterator pi = FD->param_begin(); + pi != FD->param_end(); pi++) { + paramList.push_back(std::make_pair( + (*pi)->getDeclName(), (*pi)->getType())); + } + + for (unsigned I = 0; I != Args.size(); ++I) { + auto *AE = cast(Args[I])->getSubExpr(); + if (!IsFutureType(AE->getType())) { + RecordDecl *FatPointerStruct; + const std::string FatPointerName = + "__FatPointer_" + GetPrefix(AE->getType()); + DeclContext::lookup_result FatPointerDecls = + S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(FatPointerName))); + + if (FatPointerDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = FatPointerDecls.begin(), + E = FatPointerDecls.end(); + I != E; ++I) { + if (isa(*I)) { + FatPointerStruct = dyn_cast(*I); + break; + } + } + } else { + abort(); + } + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getRecordType(FatPointerStruct))); + } else { + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + AE->getType())); + } + } + + const std::string Recordname = "_Future" + funcName.getAsString(); + RecordDecl *RD = buildAsyncDataRecord(S.Context, Recordname, SLoc, ELoc, + clang::TagDecl::TagKind::TTK_Struct); + RD->startDefinition(); + for (std::vector>::iterator it = + paramList.begin(); + it != paramList.end(); it++) { + std::string VarName = it->first.getAsString(); + QualType VarType = it->second; + addAsyncRecordDecl(S.Context, VarName, VarType, SLoc, ELoc, RD); + } + for (std::vector>::iterator it = + LocalVarList.begin(); + it != LocalVarList.end(); it++) { + const std::string VarName = it->first.getAsString(); + QualType VarType = it->second; + addAsyncRecordDecl(S.Context, VarName, VarType, SLoc, ELoc, RD); + } + + const std::string FutureStateName = "__future_state"; + addAsyncRecordDecl(S.Context, FutureStateName, S.Context.IntTy, SLoc, ELoc, + RD); + RD->completeDefinition(); + S.PushOnScopeChains(RD, S.getCurScope(), true); + return RD; +} + + +/// TODO: will be removed after using Future in stdlib +static std::tuple, std::pair> +generateVtableAndFatPointerStruct(Sema &S, QualType T, + RecordDecl *PollResultRD) { + RecordDecl *VtableStruct = nullptr; + QualType ReturnTy = T; + std::string VtableStructName = "__Vtable_" + GetPrefix(ReturnTy); + bool IsVtableExisted = false; + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(VtableStructName))); + + if (Decls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) { + if (isa(*I)) { + VtableStruct = dyn_cast(*I); + break; + } + } + IsVtableExisted = true; + VtableStruct->addAttr(WeakAttr::CreateImplicit(S.Context)); + } else if (Decls.empty()) { + VtableStruct = buildAsyncDataRecord(S.Context, VtableStructName, + SourceLocation(), SourceLocation(), + clang::TagDecl::TagKind::TTK_Struct); + VtableStruct->startDefinition(); + SmallVector Args; + Args.push_back(S.Context.VoidPtrTy); + QualType PollFuncType = S.Context.getPointerType(S.Context.getFunctionType( + S.Context.getRecordType(PollResultRD), Args, {})); + QualType FreeFuncType = S.Context.getPointerType( + S.Context.getFunctionType(S.Context.VoidTy, Args, {})); + addAsyncRecordDecl(S.Context, "poll", PollFuncType, SourceLocation(), + SourceLocation(), VtableStruct); + addAsyncRecordDecl(S.Context, "free", FreeFuncType, SourceLocation(), + SourceLocation(), VtableStruct); + VtableStruct->completeDefinition(); + VtableStruct->addAttr(WeakAttr::CreateImplicit(S.Context)); + S.PushOnScopeChains(VtableStruct, S.getCurScope(), true); + } else { + // should not reach here. todo: change to assert + abort(); + } + RecordDecl *FatPointerStruct = nullptr; + std::string FatPointerName = "__FatPointer_" + GetPrefix(ReturnTy); + bool IsFatPointerExisted = false; + DeclContext::lookup_result FatPointerDecls = + S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(FatPointerName))); + + if (FatPointerDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = FatPointerDecls.begin(), + E = FatPointerDecls.end(); + I != E; ++I) { + if (isa(*I)) { + FatPointerStruct = dyn_cast(*I); + break; + } + } + IsFatPointerExisted = true; + FatPointerStruct->addAttr(WeakAttr::CreateImplicit(S.Context)); + } else if (FatPointerDecls.empty()) { + FatPointerStruct = buildAsyncDataRecord( + S.Context, FatPointerName, SourceLocation(), SourceLocation(), + clang::TagDecl::TagKind::TTK_Struct); + FatPointerStruct->startDefinition(); + addAsyncRecordDecl(S.Context, "data", S.Context.VoidPtrTy, SourceLocation(), + SourceLocation(), FatPointerStruct); + addAsyncRecordDecl( + S.Context, "vtable", + S.Context.getPointerType(S.Context.getRecordType(VtableStruct)), + SourceLocation(), SourceLocation(), FatPointerStruct); + FatPointerStruct->completeDefinition(); + FatPointerStruct->addAttr(WeakAttr::CreateImplicit(S.Context)); + S.PushOnScopeChains(FatPointerStruct, S.getCurScope(), true); + } else { + // should not reach here. todo: change to assert + abort(); + } + return std::make_tuple(std::make_pair(VtableStruct, IsVtableExisted), + std::make_pair(FatPointerStruct, IsFatPointerExisted)); +} + +static VarDecl *buildVtableInitDecl(Sema &S, FunctionDecl *FD, + RecordDecl *VtableRD, + RecordDecl *PollResultRD, + BSCMethodDecl *PollFunc, + BSCMethodDecl *FreeFunc) { + std::string IName = + VtableRD->getDeclName().getAsString() + FD->getDeclName().getAsString(); + VarDecl *VD = VarDecl::Create( + S.Context, S.Context.getTranslationUnitDecl(), SourceLocation(), + SourceLocation(), &(S.Context.Idents).get(IName), + S.Context.getRecordType(VtableRD), nullptr, SC_None); + DeclGroupRef DG(VD); + S.PushOnScopeChains(VD, S.getCurScope(), false); + SmallVector InitExprs; + + SmallVector Args; + Args.push_back(S.Context.VoidPtrTy); + + QualType PollFuncType = S.Context.getPointerType(S.Context.getFunctionType( + S.Context.getRecordType(PollResultRD), Args, {})); + Expr *PollInit = S.BuildDeclRefExpr(PollFunc, PollFunc->getType(), VK_LValue, + SourceLocation()); + PollInit = S.ImpCastExprToType(PollInit, + S.Context.getPointerType(PollInit->getType()), + CK_FunctionToPointerDecay) + .get(); + PollInit = S.ImpCastExprToType(PollInit, PollFuncType, CK_BitCast).get(); + InitExprs.push_back(PollInit); + + QualType FreeFuncType = S.Context.getPointerType( + S.Context.getFunctionType(S.Context.VoidTy, Args, {})); + Expr *FreeInit = S.BuildDeclRefExpr(FreeFunc, FreeFunc->getType(), VK_LValue, + SourceLocation()); + FreeInit = S.ImpCastExprToType(FreeInit, + S.Context.getPointerType(FreeInit->getType()), + CK_FunctionToPointerDecay) + .get(); + FreeInit = S.ImpCastExprToType(FreeInit, FreeFuncType, CK_BitCast).get(); + InitExprs.push_back(FreeInit); + + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(S.Context.getRecordType(VtableRD)); + VD->setInit(ILE); + return VD; +} + +FunctionDecl *buildFutureInitFunctionDeclaraion(Sema &S, RecordDecl *RD, + FunctionDecl *FD, + RecordDecl *FatPointerRD, + VarDecl *VtableInit) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + DeclarationName funcName = FD->getDeclName(); + QualType FuncRetType = S.Context.getRecordType(FatPointerRD); + SmallVector ParamTys; + FunctionDecl::param_const_iterator pi; + for (pi = FD->param_begin(); pi != FD->param_end(); pi++) { + ParamTys.push_back((*pi)->getType()); + } + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + TypeSourceInfo *Tinfo = FD->getTypeSourceInfo(); + std::string FName = "__" + funcName.getAsString(); + + DeclContext::lookup_result Decls = FD->getDeclContext()->lookup( + DeclarationName(&(S.Context.Idents).get(FName))); + FunctionDecl *NewFD = nullptr; + if (Decls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) { + if (isa(*I)) { + NewFD = dyn_cast(*I); + break; + } + } + } else if (Decls.empty()) { + if (dyn_cast(FD)) { + NewFD = buildAsyncBSCMethodDecl(S.Context, FD->getDeclContext(), SLoc, + NLoc, &(S.Context.Idents).get(FName), + FuncType, Tinfo, SC_None); + } else { + NewFD = + buildAsyncFuncDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, + &(S.Context.Idents).get(FName), FuncType, Tinfo); + } + SmallVector ParmVarDecls; + for (const auto &I : FD->parameters()) { + ParmVarDecl *PVD = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get(I->getName()), I->getType(), nullptr, SC_None, + nullptr); + ParmVarDecls.push_back(PVD); + } + NewFD->setParams(ParmVarDecls); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + } else { + abort(); + } + S.PushFunctionScope(); + S.PushDeclContext(S.getCurScope(), NewFD); + + std::string IName = "data"; + VarDecl *VD = VarDecl::Create( + S.Context, NewFD, SLoc, SLoc, &(S.Context.Idents).get(IName), + S.Context.getPointerType(S.Context.getRecordType(RD)), + S.Context.getTrivialTypeSourceInfo( + S.Context.getPointerType(S.Context.getRecordType(RD)), SLoc), + SC_None); + + DeclGroupRef DataDG(VD); + DeclStmt *DataDS = new (S.Context) DeclStmt(DataDG, NLoc, NLoc); + std::vector Stmts; + Stmts.push_back(DataDS); + + std::string MallocName = "malloc"; + + DeclContext::lookup_result MallocDecls = + S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(MallocName))); + FunctionDecl *MallocFunc = nullptr; + if (MallocDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = MallocDecls.begin(), + E = MallocDecls.end(); + I != E; ++I) { + if (isa(*I)) { + MallocFunc = dyn_cast(*I); + break; + } + } + } else { + S.Diag(FD->getBeginLoc(), diag::err_function_not_found) + << MallocName << ""; + return nullptr; + } + + Expr *MallocRef = + S.BuildDeclRefExpr(MallocFunc, MallocFunc->getType(), VK_LValue, NLoc); + MallocRef = S.ImpCastExprToType( + MallocRef, S.Context.getPointerType(MallocRef->getType()), + CK_FunctionToPointerDecay) + .get(); + // sizeof(struct __Futurex) + Expr *SizeOfExpr = + S.CreateUnaryExprOrTypeTraitExpr( + S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(RD)), + NLoc, UETT_SizeOf, SourceRange()) + .get(); + SmallVector Args; + Args.push_back(SizeOfExpr); + + // malloc(sizeof(struct __Futurex)) + Expr *CE = S.BuildCallExpr(nullptr, MallocRef, SourceLocation(), Args, + SourceLocation()) + .get(); + CE = S.ImpCastExprToType( + CE, S.Context.getPointerType(S.Context.getRecordType(RD)), + CK_BitCast) + .get(); + VD->setInit(CE); + + Expr *DataRef = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); + DataRef = ImplicitCastExpr::Create(S.Context, DataRef->getType(), + CK_LValueToRValue, DataRef, nullptr, + VK_PRValue, FPOptionsOverride()); + pi = NewFD->param_begin(); + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + pi != NewFD->param_end(); ++pi, ++FieldIt) { + + Expr *LHSExpr = S.BuildMemberExpr( + DataRef, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FieldIt, + DeclAccessPair::make(*pi, FieldIt->getAccess()), false, + DeclarationNameInfo(), FieldIt->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + + Expr *RHSExpr = + S.BuildDeclRefExpr(*pi, FieldIt->getType().getNonReferenceType(), + VK_LValue, (*pi)->getLocation()); + RHSExpr = ImplicitCastExpr::Create(S.Context, (*pi)->getType(), + CK_LValueToRValue, RHSExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + + Expr *BO = + S.CreateBuiltinBinOp((*pi)->getLocation(), BO_Assign, LHSExpr, RHSExpr) + .get(); + Stmts.push_back(BO); + } + + RecordDecl::field_iterator FutureStateField; + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + FieldIt != RD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "__future_state") { + FutureStateField = FieldIt; + } + } + + Expr *LHSExpr = S.BuildMemberExpr( + DataRef, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FutureStateField, + DeclAccessPair::make(VD, FutureStateField->getAccess()), false, + DeclarationNameInfo(), FutureStateField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + + llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), 0); + Expr *RHSExpr = IntegerLiteral::Create(S.Context, ResultVal, S.Context.IntTy, + SourceLocation()); + + Expr *BO = S.CreateBuiltinBinOp((*FutureStateField)->getLocation(), BO_Assign, + LHSExpr, RHSExpr) + .get(); + Stmts.push_back(BO); + + std::string FatPointerVDName = "fp"; + VarDecl *FatPointerVD = VarDecl::Create( + S.Context, NewFD, SLoc, SLoc, &(S.Context.Idents).get(FatPointerVDName), + S.Context.getRecordType(FatPointerRD), + S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(FatPointerRD), + SLoc), + SC_None); + + DeclGroupRef FatPointerDG(FatPointerVD); + DeclStmt *FatPointerDS = new (S.Context) DeclStmt(FatPointerDG, NLoc, NLoc); + Stmts.push_back(FatPointerDS); + + SmallVector InitExprs; + Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); + FutureRefExpr = ImplicitCastExpr::Create( + S.Context, VD->getType(), CK_LValueToRValue, FutureRefExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + FutureRefExpr = + S.BuildCStyleCastExpr( + NLoc, S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), NLoc, + FutureRefExpr) + .get(); + + Expr *VtableRefExpr = + S.BuildDeclRefExpr(VtableInit, VtableInit->getType(), VK_LValue, NLoc); + + Expr *Unop = + S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, VtableRefExpr).get(); + InitExprs.push_back(FutureRefExpr); + InitExprs.push_back(Unop); + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(S.Context.getRecordType(FatPointerRD)); + FatPointerVD->setInit(ILE); + + Expr *FatPointerRef = S.BuildDeclRefExpr( + FatPointerVD, FatPointerVD->getType(), VK_LValue, NLoc); + FatPointerRef = ImplicitCastExpr::Create( + S.Context, FatPointerRef->getType(), CK_LValueToRValue, FatPointerRef, + nullptr, VK_PRValue, FPOptionsOverride()); + Stmt *RS = S.BuildReturnStmt(NLoc, FatPointerRef).get(); + Stmts.push_back(RS); + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, NLoc); + NewFD->setBody(CS); + S.PopDeclContext(); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD); + return NewFD; +} + +FunctionDecl *buildFutureInitFunctionDefinition(Sema &S, FunctionDecl *FD, + RecordDecl *FatPointerRD) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + DeclarationName funcName = FD->getDeclName(); + QualType FuncRetType = S.Context.getRecordType(FatPointerRD); + SmallVector ParamTys; + FunctionDecl::param_const_iterator pi; + for (pi = FD->param_begin(); pi != FD->param_end(); pi++) { + ParamTys.push_back((*pi)->getType()); + } + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + TypeSourceInfo *Tinfo = FD->getTypeSourceInfo(); + std::string FName = "__" + funcName.getAsString(); + + DeclContext::lookup_result Decls = FD->getDeclContext()->lookup( + DeclarationName(&(S.Context.Idents).get(FName))); + + if (Decls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) { + if (isa(*I)) { + return dyn_cast(*I); + break; + } + } + } + + FunctionDecl *NewFD; + if (dyn_cast(FD)) { + NewFD = buildAsyncBSCMethodDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, + &(S.Context.Idents).get(FName), FuncType, + Tinfo, SC_None); + } else { + NewFD = buildAsyncFuncDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, + &(S.Context.Idents).get(FName), FuncType, Tinfo); + } + SmallVector ParmVarDecls; + for (const auto &I : FD->parameters()) { + ParmVarDecl *PVD = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get(I->getName()), I->getType(), nullptr, SC_None, + nullptr); + ParmVarDecls.push_back(PVD); + } + NewFD->setParams(ParmVarDecls); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +Stmt *ProcessAwaitExprStatus(Sema &S, int AwaitCount, RecordDecl *RD, Expr *ICE, + ParmVarDecl *PVD, VarDecl *PollResultVar, + VarDecl *AwaitResult, BSCMethodDecl *NewFD) { + std::vector BodyStmts; + std::vector ElseStmts; + Expr *IfCond = nullptr; + + RecordDecl::field_iterator TheField; + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + FieldIt != RD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "__future_state") { + TheField = FieldIt; + break; + } + } + + if (*TheField) { + DeclarationName Name = TheField->getDeclName(); + DeclarationNameInfo MemberNameInfo(Name, TheField->getLocation()); + Expr *LHSExpr = S.BuildMemberExpr( + ICE, true, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), + *TheField, DeclAccessPair::make(*TheField, TheField->getAccess()), + false, MemberNameInfo, TheField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + + llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), AwaitCount); + Expr *RHSExpr = IntegerLiteral::Create(S.Context, ResultVal, + S.Context.IntTy, SourceLocation()); + + Expr *BO = S.CreateBuiltinBinOp((*TheField)->getLocation(), BO_Assign, + LHSExpr, RHSExpr) + .get(); + ElseStmts.push_back(BO); + } + + RecordDecl *PollResultRD = PollResultVar->getType()->getAsRecordDecl(); + + BSCMethodDecl *IsCompletedFD = nullptr; + std::string IsCompletedFDName = "is_completed"; + LookupResult IsCompletedFDResult( + S, + DeclarationNameInfo(&(S.Context.Idents).get(IsCompletedFDName), + SourceLocation()), + S.LookupOrdinaryName); + S.LookupQualifiedName(IsCompletedFDResult, PollResultRD); + if (!IsCompletedFDResult.empty()) + IsCompletedFD = + dyn_cast_or_null(IsCompletedFDResult.getFoundDecl()); + + if (IsCompletedFD) { + Expr *IsCompletedFDRef = S.BuildDeclRefExpr( + IsCompletedFD, IsCompletedFD->getType(), VK_LValue, SourceLocation()); + IsCompletedFDRef = S.ImpCastExprToType(IsCompletedFDRef, + S.Context.getPointerType( + IsCompletedFDRef->getType()), + CK_FunctionToPointerDecay) + .get(); + + if (PollResultRD) { + Expr *PollResultVarRef = S.BuildDeclRefExpr( + PollResultVar, PollResultVar->getType(), VK_LValue, SourceLocation()); + PollResultVarRef = + S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, PollResultVarRef) + .get(); + Expr *AwaitResultRef = S.BuildDeclRefExpr( + AwaitResult, AwaitResult->getType(), VK_LValue, SourceLocation()); + AwaitResultRef = + S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, AwaitResultRef) + .get(); + + SmallVector Args; + Args.push_back(PollResultVarRef); + Args.push_back(AwaitResultRef); + IfCond = S.BuildCallExpr(nullptr, IsCompletedFDRef, SourceLocation(), + Args, SourceLocation()) + .get(); + } + } + + RecordDecl *PollResultRDForPending = + NewFD->getReturnType()->getAsRecordDecl(); + std::string PendingFDName = "pending"; + LookupResult PendingFDResult( + S, + DeclarationNameInfo(&(S.Context.Idents).get(PendingFDName), + SourceLocation()), + S.LookupOrdinaryName); + S.LookupQualifiedName(PendingFDResult, PollResultRDForPending); + BSCMethodDecl *PendingFD = nullptr; + if (!PendingFDResult.empty()) + PendingFD = dyn_cast_or_null(PendingFDResult.getFoundDecl()); + + if (PendingFD) { + Expr *PendingFDRef = S.BuildDeclRefExpr(PendingFD, PendingFD->getType(), + VK_LValue, SourceLocation()); + PendingFDRef = + S.ImpCastExprToType(PendingFDRef, + S.Context.getPointerType(PendingFDRef->getType()), + CK_FunctionToPointerDecay) + .get(); + Expr *PendingCall = S.BuildCallExpr(nullptr, PendingFDRef, SourceLocation(), + {}, SourceLocation()) + .get(); + Stmt *RS = S.BuildReturnStmt(SourceLocation(), PendingCall).get(); + ElseStmts.push_back(RS); + } + + Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), + SourceLocation(), SourceLocation()); + Stmt *Else = CompoundStmt::Create(S.Context, ElseStmts, FPOptionsOverride(), + SourceLocation(), SourceLocation()); + auto *If = + IfStmt::Create(S.Context, SourceLocation(), IfStatementKind::Ordinary, + /* Init=*/nullptr, + /* Var=*/nullptr, IfCond, + /* LPL=*/SourceLocation(), + /* RPL=*/SourceLocation(), Body, SourceLocation(), Else); + return If; +} + + + +static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, + FunctionDecl *FD) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + + std::string FName = "free"; + QualType FuncRetType = S.Context.VoidTy; + QualType ParamType = S.Context.getPointerType(S.Context.getRecordType(RD)); + SmallVector ParamTys; + ParamTys.push_back(ParamType); + + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + + BSCMethodDecl *NewFD = buildAsyncBSCMethodDecl(S.Context, RD, SLoc, NLoc, + &(S.Context.Idents).get(FName), + FuncType, nullptr, SC_None); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; + + SmallVector ParmVarDecls; + ParmVarDecl *PVD = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("this"), ParamType, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD); + NewFD->setParams(ParmVarDecls); + S.PushFunctionScope(); + + std::vector Stmts; + + std::stack Futures; + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + FieldIt != RD->field_end(); ++FieldIt) { + if (IsFutureType(FieldIt->getType())) { + Futures.push(FieldIt); + } + } + + while (!Futures.empty()) { + RecordDecl::field_iterator FtField = Futures.top(); + RecordDecl *FatPointerRD = + dyn_cast(FtField->getType().getDesugaredType(S.Context)) + ->getDecl(); + Futures.pop(); + + Expr *DRE = S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); + Expr *PDRE = + ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, DRE, + nullptr, VK_PRValue, FPOptionsOverride()); + // this.Ft_ + Expr *FutureExpr = S.BuildMemberExpr( + PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FtField, + DeclAccessPair::make(PVD, FtField->getAccess()), false, + DeclarationNameInfo(), FtField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + + RecordDecl::field_iterator PtrField, VtableField, FPFieldIt; + for (FPFieldIt = FatPointerRD->field_begin(); + FPFieldIt != FatPointerRD->field_end(); ++FPFieldIt) { + if (FPFieldIt->getDeclName().getAsString() == "data") { + PtrField = FPFieldIt; + } else if (FPFieldIt->getDeclName().getAsString() == "vtable") { + VtableField = FPFieldIt; + } + } + + // this.Ft_.vtable + Expr *VtableExpr = S.BuildMemberExpr( + FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *VtableField, + DeclAccessPair::make(FatPointerRD, VtableField->getAccess()), false, + DeclarationNameInfo(), VtableField->getType(), VK_LValue, OK_Ordinary); + VtableExpr = ImplicitCastExpr::Create( + S.Context, VtableExpr->getType(), CK_LValueToRValue, VtableExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + + RecordDecl::field_iterator FreeFuncField, FreeFuncFieldIt; + const RecordType *RT = dyn_cast( + VtableField->getType()->getPointeeType().getDesugaredType(S.Context)); + RecordDecl *VtableRD = RT->getDecl(); + for (FreeFuncFieldIt = VtableRD->field_begin(); + FreeFuncFieldIt != VtableRD->field_end(); ++FreeFuncFieldIt) { + if (FreeFuncFieldIt->getDeclName().getAsString() == "free") { + FreeFuncField = FreeFuncFieldIt; + } + } + + // this.Ft_.vtable->free + Expr *FreeFuncExpr = S.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FreeFuncField, + DeclAccessPair::make(VtableRD, FreeFuncField->getAccess()), false, + DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, + OK_Ordinary); + FreeFuncExpr = ImplicitCastExpr::Create( + S.Context, FreeFuncExpr->getType(), CK_LValueToRValue, FreeFuncExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + + std::vector FreeArgs; + // this.Ft_.data + Expr *DataExpr = S.BuildMemberExpr( + FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PtrField, + DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, + DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); + DataExpr = ImplicitCastExpr::Create(S.Context, DataExpr->getType(), + CK_LValueToRValue, DataExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + FreeArgs.push_back(DataExpr); + + // this.Ft_.vtable->free(this.Ft_.data) + Expr *RHSExpr = S.BuildCallExpr(nullptr, FreeFuncExpr, SourceLocation(), + FreeArgs, SourceLocation()) + .get(); + Stmts.push_back(RHSExpr); + } + + // TODO: if future is not malloced, do not need to free it. + std::string FreeName = "free"; + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(FreeName))); + FunctionDecl *FreeFunc = nullptr; + if (Decls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) { + if (isa(*I)) { + FreeFunc = dyn_cast(*I); + break; + } + } + } else { + S.Diag(FD->getBeginLoc(), diag::err_function_not_found) + << FreeName << ""; + return nullptr; + } + + Expr *FreeFuncRef = + S.BuildDeclRefExpr(FreeFunc, FreeFunc->getType(), VK_LValue, NLoc); + FreeFuncRef = + S.ImpCastExprToType(FreeFuncRef, + S.Context.getPointerType(FreeFuncRef->getType()), + CK_FunctionToPointerDecay) + .get(); + Expr *FutureObj = + S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); + FutureObj = ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, + FutureObj, nullptr, VK_PRValue, + FPOptionsOverride()); + + FutureObj = S.BuildCStyleCastExpr( + SourceLocation(), + S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), + SourceLocation(), FutureObj) + .get(); + + SmallVector Args; + Args.push_back(FutureObj); + // free(this) + Expr *CE = S.BuildCallExpr(nullptr, FreeFuncRef, SourceLocation(), Args, + SourceLocation()) + .get(); + Stmts.push_back(CE); + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, NLoc); + NewFD->setBody(CS); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +static BSCMethodDecl *buildPollFunction(Sema &S, RecordDecl *RD, + RecordDecl *PollResultRD, + FunctionDecl *FD, + RecordDecl *FatPointerRD, + int FutureStateNumber) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + QualType Ty = FD->getDeclaredReturnType(); + + std::string FName = "poll"; + + QualType FuncRetType = S.Context.getRecordType(PollResultRD); + QualType ParamType = S.Context.getPointerType(S.Context.getRecordType(RD)); + SmallVector ParamTys; + ParamTys.push_back(ParamType); + + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + QualType OriginType = S.Context.getFunctionType(Ty, ParamTys, {}); + + BSCMethodDecl *NewFD = buildAsyncBSCMethodDecl(S.Context, RD, SLoc, NLoc, + &(S.Context.Idents).get(FName), + OriginType, nullptr, SC_None); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; + S.PushFunctionScope(); + + SmallVector ParmVarDecls; + ParmVarDecl *PVD = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("this"), ParamType, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD); + NewFD->setParams(ParmVarDecls); + + std::vector Stmts; + + RecordDecl::field_iterator FutureStateField; + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + FieldIt != RD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "__future_state") { + FutureStateField = FieldIt; + } + } + + Expr *FutureObj = + S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); + FutureObj = ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, + FutureObj, nullptr, VK_PRValue, + FPOptionsOverride()); + // Creating Switch Stmt + DeclarationName FutureName = FutureStateField->getDeclName(); + DeclarationNameInfo MemberNameInfo(FutureName, + FutureStateField->getLocation()); + // this.__future_state + Expr *ConditionVariable = S.BuildMemberExpr( + FutureObj, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FutureStateField, + DeclAccessPair::make(*FutureStateField, FutureStateField->getAccess()), + false, MemberNameInfo, FutureStateField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + S.setFunctionHasBranchIntoScope(); + SwitchStmt *SS = + SwitchStmt::Create(S.Context, nullptr, nullptr, ConditionVariable, + SourceLocation(), SourceLocation()); + + S.getCurFunction()->SwitchStack.push_back( + FunctionScopeInfo::SwitchInfo(SS, false)); + + std::vector CaseStmts; + std::vector LabelDecls; + for (int i = 0; i < FutureStateNumber; i++) { + llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), i); + Expr *LHSExpr = IntegerLiteral::Create(S.Context, ResultVal, + S.Context.IntTy, SourceLocation()); + CaseStmt *CS = + CaseStmt::Create(S.Context, LHSExpr, nullptr, SourceLocation(), + SourceLocation(), SourceLocation()); + LabelDecl *LD = + LabelDecl::Create(S.Context, NewFD, SourceLocation(), + &(S.Context.Idents).get("__L" + std::to_string(i))); + LabelDecls.push_back(LD); + Stmt *RHSExpr = + new (S.Context) GotoStmt(LD, SourceLocation(), SourceLocation()); + CS->setSubStmt(RHSExpr); + CaseStmts.push_back(CS); + SS->addSwitchCase(CS); + } + + CompoundStmt *SSBody = CompoundStmt::Create(S.Context, CaseStmts, + FPOptionsOverride(), SLoc, NLoc); + + SS->setBody(SSBody); + Stmts.push_back(SS); + + int StmtSize = Stmts.size(); + + TransformToReturnVoid(S).TransformFunctionDecl(FD); + + NewFD->setType(S.Context.getFunctionType(FD->getReturnType(), ParamTys, {})); + S.PushDeclContext(S.getCurScope(), NewFD); + + TransformToAP DT = TransformToAP(S, FutureObj, RD, NewFD); + StmtResult MemberChangeRes = DT.TransformStmt(FD->getBody()); + Stmt *FuncBody = MemberChangeRes.get(); + + StmtResult SingleStateRes = + TransformToHasSingleState(S, DT).TransformStmt(FuncBody); + FuncBody = SingleStateRes.get(); + + NewFD->setType(FuncType); + ARFinder ARInitlizer = ARFinder(S, FutureObj, RD, NewFD, Ty); + ARInitlizer.Visit(FuncBody); + + StmtResult ARToCSRes = + TransformARToCS(S, ARInitlizer).TransformStmt(FuncBody); + FuncBody = ARToCSRes.get(); + + AEFinder AEInitlizer = + AEFinder(S, NewFD->getParamDecl(0), FutureObj, RD, NewFD); + AEInitlizer.Visit(FuncBody); + + StmtResult AEToCSRes = + TransformAEToCS(S, AEInitlizer, LabelDecls).TransformStmt(FuncBody); + S.PopDeclContext(); + + for (auto *C : AEToCSRes.get()->children()) { + Stmts.push_back(C); + } + + int CurStmtSize = Stmts.size(); + if (CurStmtSize > StmtSize) { + Stmt *FirstStmt = Stmts[StmtSize]; + LabelStmt *LS = + new (S.Context) LabelStmt(SourceLocation(), LabelDecls[0], FirstStmt); + Stmts.erase(Stmts.begin() + StmtSize); + Stmts.insert(Stmts.begin() + StmtSize, LS); + } else { + llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), 0); + Stmt *IL = IntegerLiteral::Create(S.Context, ResultVal, S.Context.IntTy, + SourceLocation()); + LabelStmt *LS = + new (S.Context) LabelStmt(SourceLocation(), LabelDecls[0], IL); + Stmts.push_back(LS); + } + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, NLoc); + NewFD->setBody(CS); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD); + return NewFD->isInvalidDecl() ? nullptr : NewFD; +} + +// BSC extensions for await keyword +ExprResult Sema::BuildAwaitExpr(SourceLocation AwaitLoc, Expr *E) { + assert(E && "null expression"); + + if (E->getType()->isDependentType()) { + Expr *Res = new (Context) AwaitExpr(AwaitLoc, E, Context.DependentTy); + return Res; + } + + Expr *InnerE = E; + QualType AwaitReturnTy = InnerE->getType(); + bool IsCall = isa(InnerE); + if (IsCall) { + Decl *AwaitDecl = (dyn_cast(InnerE))->getCalleeDecl(); + FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); + if (!FDecl) { + return ExprError(); + } + if (!FDecl->isAsyncSpecified() && !IsFutureType(AwaitReturnTy)) { + // TODO: modify error message + Diag(InnerE->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(InnerE)); + return ExprError(); + } + } else { + if (!IsFutureType(AwaitReturnTy)) { + Diag(InnerE->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(InnerE)); + return ExprError(); + } + } + + if (IsFutureType(AwaitReturnTy)) { + const RecordType *FPRD = + dyn_cast(AwaitReturnTy.getDesugaredType(Context)); + RecordDecl *RD = FPRD->getDecl(); + for (RecordDecl::field_iterator FieldIt = RD->field_begin(), + Field_end = RD->field_end(); + FieldIt != Field_end; ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "vtable") { + const RecordType *VTRD = dyn_cast( + FieldIt->getType()->getPointeeType().getDesugaredType(Context)); + RecordDecl *NewRD = VTRD->getDecl(); + for (RecordDecl::field_iterator FieldIt = NewRD->field_begin(), + Field_end = NewRD->field_end(); + FieldIt != Field_end; ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "poll") { + const RecordType *VTRD1 = dyn_cast( + dyn_cast( + FieldIt->getType()->getPointeeType().getDesugaredType( + Context)) + ->getReturnType() + .getDesugaredType(Context)); + RecordDecl *NewRD1 = VTRD1->getDecl(); + for (RecordDecl::field_iterator FieldIt = NewRD1->field_begin(), + Field_end = NewRD1->field_end(); + FieldIt != Field_end; ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "res") { + AwaitReturnTy = FieldIt->getType(); + } + } + } + } + } + } + } + + // build AwaitExpr + AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, InnerE, AwaitReturnTy); + return Res; +} + +ExprResult Sema::ActOnAwaitExpr(SourceLocation AwaitLoc, Expr *E) { + assert(FunctionScopes.size() > 0 && "FunctionScopes missing"); + if (FunctionScopes.size() < 1 || + getCurFunction()->CompoundScopes.size() < 1) { + Diag(AwaitLoc, diag::err_await_invalid_scope) << "this scope."; + return ExprError(); + } + return BuildAwaitExpr(AwaitLoc, E); +} + +void Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD, + SmallVector DeclsInGroup) { + if (!IsFutureType(FD->getReturnType())) { + QualType ReturnTy = FD->getReturnType(); + ReturnTy.removeLocalConst(); + if (ReturnTy->isVoidType()) { + RecordDecl *VoidRD = generateVoidStruct(*this); + ReturnTy = Context.getRecordType(VoidRD); + } + QualType PollResultType = + lookupPollResultType(*this, FD->getBeginLoc(), ReturnTy); + if (PollResultType.isNull()) { + return; + } + RecordDecl *PollResultRD = PollResultType->getAsRecordDecl(); + std::tuple, std::pair> + NewRDs = + generateVtableAndFatPointerStruct(*this, ReturnTy, PollResultRD); + + if (!std::get<1>(std::get<0>(NewRDs))) + DeclsInGroup.push_back(std::get<0>(std::get<0>(NewRDs))); + if (!std::get<1>(std::get<1>(NewRDs))) + DeclsInGroup.push_back(std::get<0>(std::get<1>(NewRDs))); + + FunctionDecl *FutureInitDef = buildFutureInitFunctionDefinition( + *this, FD, std::get<0>(std::get<1>(NewRDs))); + DeclsInGroup.push_back(FutureInitDef); + } +} + +SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { + SmallVector decls; + + if (IsFutureType(FD->getReturnType())) { + decls.push_back(FD); + return decls; + } + AwaitExprFinder finder = AwaitExprFinder(); + finder.Visit(FD->getBody()); + + if (finder.GetAwaitExprNum() == 0) { + // TODO: return type check. + decls.push_back(FD); + return decls; + } + + IllegalAEFinder IAEFinder = IllegalAEFinder(*this); + IAEFinder.Visit(FD->getBody()); + if (IAEFinder.hasIllegalAwaitExpr()) + return decls; + + QualType ReturnTy = FD->getReturnType(); + ReturnTy.removeLocalConst(); + if (ReturnTy->isVoidType()) { + RecordDecl *VoidRD = generateVoidStruct(*this); + ReturnTy = Context.getRecordType(VoidRD); + } + QualType PollResultType = + lookupPollResultType(*this, FD->getBeginLoc(), ReturnTy); + if (PollResultType.isNull()) { + return decls; + } + RecordDecl *PollResultRD = PollResultType->getAsRecordDecl(); + + std::tuple, std::pair> + NewRDs = generateVtableAndFatPointerStruct(*this, ReturnTy, PollResultRD); + + if (!std::get<1>(std::get<0>(NewRDs))) + decls.push_back(std::get<0>(std::get<0>(NewRDs))); + if (!std::get<1>(std::get<1>(NewRDs))) + decls.push_back(std::get<0>(std::get<1>(NewRDs))); + + FunctionDecl *FutureInitDef = buildFutureInitFunctionDefinition( + *this, FD, std::get<0>(std::get<1>(NewRDs))); + + const int FutureStateNumber = finder.GetAwaitExprNum() + 1; + RecordDecl *RD = buildFutureRecordDecl(*this, FD, finder.GetAwaitExpr(), + finder.GetLocalVarList()); + + BSCMethodDecl *PollDecl = + buildPollFunction(*this, RD, PollResultRD, FD, + std::get<0>(std::get<1>(NewRDs)), FutureStateNumber); + + BSCMethodDecl *FreeDecl = buildFreeFunction(*this, RD, FD); + if (!FreeDecl) { + return decls; + } + + VarDecl *VtableDecl = + buildVtableInitDecl(*this, FD, std::get<0>(std::get<0>(NewRDs)), + PollResultRD, PollDecl, FreeDecl); + + FunctionDecl *FutureInit = buildFutureInitFunctionDeclaraion( + *this, RD, FD, std::get<0>(std::get<1>(NewRDs)), VtableDecl); + + decls.push_back(RD); + decls.push_back(PollDecl); + decls.push_back(FreeDecl); + decls.push_back(VtableDecl); + decls.push_back(FutureInit); + return decls; +} \ No newline at end of file diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 651d7167b86b..d6c20ea63183 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4680,6 +4680,18 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, ExprKind, TInfo, Context.getSizeType(), OpLoc, R.getEnd()); } +namespace { +bool IsFutureType(QualType T) { // TODO: change after get + std::string prefix = "struct __FatPointer_"; + std::string string = T.getAsString(); + bool isPrefix = + prefix.size() <= string.size() && + std::mismatch(prefix.begin(), prefix.end(), string.begin(), string.end()) + .first == prefix.end(); + return isPrefix; +} +} // namespace + /// Build a sizeof or alignof expression given an expression /// operand. ExprResult @@ -6081,7 +6093,6 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // Flag IsDesugaredBSCMethodCall is to jugde if this func call has already desugared. if (!Call->getCallee()->IsDesugaredBSCMethodCall) NumParams = NumParams - 1; - // } } } @@ -6890,6 +6901,54 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, } else if (isa(NakedFn)) NDecl = cast(NakedFn)->getMemberDecl(); + if (FunctionDecl *FDecl = dyn_cast_or_null(NDecl)) { + if (FDecl->isAsyncSpecified()) { + QualType AwaitReturnTy = FDecl->getReturnType(); + if (!IsFutureType(AwaitReturnTy)) { + FunctionDecl *TempCFD = nullptr; + std::string TempName = + "__" + FDecl->getDeclName().getAsString(); // TODO + DeclContext::lookup_result Decls = FDecl->getDeclContext()->lookup( + DeclarationName(&(getASTContext().Idents).get(TempName))); + + if (Decls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) { + if (isa(*I)) { + TempCFD = dyn_cast(*I); + break; + } + } + } else { + // todo: error report? + } + if (TempCFD) { + if (dyn_cast(NakedFn)) { + ExprResult RHSER1 = BuildDeclRefExpr( + TempCFD, TempCFD->getType().getNonReferenceType(), VK_LValue, + TempCFD->getLocation()); + Expr *RHSExpr1 = RHSER1.get(); + Fn = ImpCastExprToType(RHSExpr1, + Context.getPointerType(TempCFD->getType()), + CK_FunctionToPointerDecay) + .get(); + } else if (isa(NakedFn)) { + MemberExpr *ME = dyn_cast(NakedFn); + Fn = MemberExpr::Create( + Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(), + ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), TempCFD, + DeclAccessPair::make(TempCFD, TempCFD->getAccess()), + DeclarationNameInfo(), nullptr, TempCFD->getType(), + ME->getValueKind(), ME->getObjectKind(), ME->isNonOdrUse()); + } + Fn->IsDesugaredBSCMethodCall = NakedFn->IsDesugaredBSCMethodCall; + Fn->HasBSCScopeSpec = NakedFn->HasBSCScopeSpec; + } + } + } + } + if (FunctionDecl *FD = dyn_cast_or_null(NDecl)) { if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable( FD, /*Complain=*/true, Fn->getBeginLoc())) -- Gitee From 4eef0206f47e7f3a1382b615051a7313bec6f996 Mon Sep 17 00:00:00 2001 From: jeanniely Date: Mon, 3 Jul 2023 11:39:42 +0800 Subject: [PATCH 3/8] [BSC] Coroutine: tree transforms for poll function --- clang/lib/Sema/SemaBSCCoroutine.cpp | 1248 +++++++++++++++++++++++++++ 1 file changed, 1248 insertions(+) diff --git a/clang/lib/Sema/SemaBSCCoroutine.cpp b/clang/lib/Sema/SemaBSCCoroutine.cpp index af0a36d0bd25..dae84853e220 100644 --- a/clang/lib/Sema/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/SemaBSCCoroutine.cpp @@ -37,6 +37,52 @@ using namespace clang; using namespace sema; +static RecordDecl *buildAsyncDataRecord(ASTContext &C, StringRef Name, + SourceLocation StartLoc, + SourceLocation EndLoc, + RecordDecl::TagKind TK) { + + RecordDecl *NewDecl; + NewDecl = RecordDecl::Create(C, TK, C.getTranslationUnitDecl(), StartLoc, + EndLoc, &C.Idents.get(Name)); + return NewDecl; +} + +static void addAsyncRecordDecl(ASTContext &C, StringRef Name, QualType Type, + SourceLocation StartLoc, SourceLocation EndLoc, + RecordDecl *RD) { + FieldDecl *Field = FieldDecl::Create( + C, RD, StartLoc, EndLoc, &C.Idents.get(Name), Type, + C.getTrivialTypeSourceInfo(Type, SourceLocation()), + /*BW=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit); + Field->setAccess(AS_public); + RD->addDecl(Field); +} + +static FunctionDecl *buildAsyncFuncDecl(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation NLoc, DeclarationName N, + QualType T, TypeSourceInfo *TInfo) { + FunctionDecl *NewDecl = + FunctionDecl::Create(C, DC, StartLoc, NLoc, N, T, TInfo, SC_None); + return NewDecl; +} + +static BSCMethodDecl * +buildAsyncBSCMethodDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation NLoc, DeclarationName N, QualType T, + TypeSourceInfo *TInfo, StorageClass SC) { + BSCMethodDecl *NewDecl = + BSCMethodDecl::Create( // TODO: inline should be passed. + C, DC, StartLoc, DeclarationNameInfo(N, NLoc), T, TInfo, SC, false, + false, ConstexprSpecKind::Unspecified, NLoc); + if (auto RD = dyn_cast_or_null(DC)) { + C.BSCDeclContextMap[RD->getTypeForDecl()] = DC; + NewDecl->setHasThisParam(true); + NewDecl->setExtendedType(RD->getTypeForDecl()->getCanonicalTypeInternal()); + } + return NewDecl; +} namespace { class AwaitExprFinder : public StmtVisitor { @@ -97,6 +143,154 @@ bool HasAwaitExpr(Stmt *S) { return false; } +/// Look for Illegal AwaitExpr +class IllegalAEFinder : public StmtVisitor { + Sema &SemaRef; + bool HasIllegalAwait; + +public: + IllegalAEFinder(Sema &SemaRef) + : SemaRef(SemaRef) { + HasIllegalAwait = false; + } + + bool CheckCondHasAwaitExpr(Stmt *S) { + Expr *condE = nullptr; + bool CHasIllegalAwait = false; + std::string ArgString; + + switch (S->getStmtClass()) { + case Stmt::IfStmtClass: { + ArgString = "condition statement of if statement"; + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; + } + + case Stmt::WhileStmtClass: { + ArgString = "condition statement of while loop"; + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; + } + + case Stmt::DoStmtClass: { + ArgString = "condition statement of do/while loop"; + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; + } + + case Stmt::ForStmtClass: { + ArgString = "condition statement of for loop"; + Stmt *Init = cast(S)->getInit(); + if (Init != nullptr) + CHasIllegalAwait = HasAwaitExpr(Init); + + if (!CHasIllegalAwait) { + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + } + + break; + } + + case Stmt::SwitchStmtClass: { + ArgString = "condition statement of switch statement"; + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; + } + + default: + break; + } + + if (CHasIllegalAwait) { + SemaRef.Diag(S->getBeginLoc(), diag::err_await_invalid_scope) << ArgString; + } + + if (CHasIllegalAwait && !HasIllegalAwait) + HasIllegalAwait = CHasIllegalAwait; + + return CHasIllegalAwait; + } + + bool CheckExprHasAwaitExpr(Stmt *S) { + bool IsContinue = true; + std::string ArgString; + + if (isa(S)) { + ArgString = "binary operator expression"; + BinaryOperator *BO = cast(S); + switch (BO->getOpcode()) + { + case BO_Comma: + case BO_Assign: + return false; + + default: + break; + } + } else if (isa(S)) + ArgString = "condition operator expression"; + + bool CHasIllegalAwait = HasAwaitExpr(S); + + if (CHasIllegalAwait && !HasIllegalAwait) + HasIllegalAwait = CHasIllegalAwait; + + if (CHasIllegalAwait) { + SemaRef.Diag(S->getBeginLoc(), diag::err_await_invalid_scope) << ArgString; + } + return IsContinue; + } + + void VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + if (isa(C) || isa(C) || isa(C) || + isa(C) || isa(C)) { + CheckCondHasAwaitExpr(C); + } else if (isa(C) || isa(C)) { + bool IsContinue = CheckExprHasAwaitExpr(C); + if (IsContinue) + continue; + } + + Visit(C); + } + } + } + + bool hasIllegalAwaitExpr() { + return HasIllegalAwait; + } +}; + +bool HasReturnStmt(Stmt *S) { + if (S == nullptr) + return false; + + if (isa(S)) + return true; + + for (auto *C : S->children()) { + if (HasReturnStmt(C)) { + return true; + } + } + + return false; +} + +bool IsRefactorStmt(Stmt *S) { + if (isa(S) || isa(S) || isa(S) || + isa(S) || isa(S) || isa(S)) + return true; + + return false; +} std::string GetPrefix(QualType T) { std::string ExtendedTypeStr = T.getAsString(); @@ -751,6 +945,1060 @@ Stmt *ProcessAwaitExprStatus(Sema &S, int AwaitCount, RecordDecl *RD, Expr *ICE, } +namespace { +class TransformToAP : public TreeTransform { + typedef TreeTransform BaseTransform; + Expr *PDRE; + RecordDecl *FutureRD; + BSCMethodDecl *FD; + std::vector DeclStmts; + int DIndex; + llvm::DenseMap> DMap; + llvm::DenseMap ArrayPointersMap; + llvm::DenseMap ArrayAssignedPointerMap; + +public: + TransformToAP(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, + BSCMethodDecl *FD) + : BaseTransform(SemaRef), PDRE(PDRE), FutureRD(FutureRD), FD(FD) { + DIndex = 0; + } + + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } + + ExprResult TransformDeclRefExpr(DeclRefExpr *E) { + Expr *RE = E; + RecordDecl::field_iterator TheField, FieldIt; + for (FieldIt = FutureRD->field_begin(); FieldIt != FutureRD->field_end(); + ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == + cast(RE)->getDecl()->getName()) { + TheField = FieldIt; + break; + } + } + + if (FieldIt != FutureRD->field_end()) { + DeclarationName Name = TheField->getDeclName(); + DeclarationNameInfo MemberNameInfo(Name, TheField->getLocation()); + RE = BaseTransform::RebuildMemberExpr( + PDRE, SourceLocation(), true, NestedNameSpecifierLoc(), + SourceLocation(), MemberNameInfo, *TheField, + DeclAccessPair::make(*TheField, TheField->getAccess()).getDecl(), + nullptr, nullptr) + .getAs(); + } + + return RE; + } + + StmtResult TransformDeclStmt(DeclStmt *S) { + Stmt *Result = nullptr; + DeclStmt *StmDecl = S; + int CIndex = 0; + + std::vector BOStmts; + std::vector NullStmts; + for (auto *SD : StmDecl->decls()) { + if (VarDecl *VD = dyn_cast(SD)) { + Expr *Init = const_cast(VD->getInit()); + Expr *LE = nullptr; + Expr *RE = nullptr; + QualType QT = VD->getType(); + + RecordDecl::field_iterator LField, FieldIt; + for (FieldIt = FutureRD->field_begin(); + FieldIt != FutureRD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == VD->getName()) { + LField = FieldIt; + break; + } + } + + if (FieldIt != FutureRD->field_end()) { + DeclarationName Name = LField->getDeclName(); + DeclarationNameInfo MemberNameInfo(Name, LField->getLocation()); + LE = BaseTransform::RebuildMemberExpr( + PDRE, SourceLocation(), true, NestedNameSpecifierLoc(), + SourceLocation(), MemberNameInfo, *LField, + DeclAccessPair::make(*LField, LField->getAccess()).getDecl(), + nullptr, nullptr) + .getAs(); + } + + if (QT->isArrayType() || + QT->isRecordType() || + QT->isRValueReferenceType()) { + + std::string ArgName = VD->getName().str(); + VarDecl *ArgVDNew = VarDecl::Create( + SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(ArgName), + VD->getType().getNonReferenceType(), nullptr, SC_None); + + Expr *CInit = nullptr; + if (Init != nullptr) { + CInit = BaseTransform::TransformExpr(Init).get(); + } else { + if (VD->getType()->isArrayType()) { + auto *CAT = cast(VD->getType()->castAsArrayTypeUnsafe()); + InitListExpr *ILE = new (SemaRef.Context) + InitListExpr(SemaRef.Context, SourceLocation(), None, SourceLocation()); + ILE->setType(VD->getType()); + Expr *Filler = new (SemaRef.Context) ImplicitValueInitExpr(CAT->getElementType()); + ILE->setArrayFiller(Filler); + Init = CInit = ILE; + } else { + Expr *CE = new (SemaRef.Context) ImplicitValueInitExpr(LE->getType()); + Init = CInit = CE; + } + } + + SemaRef.AddInitializerToDecl(ArgVDNew, CInit, /*DirectInit=*/true); + DeclStmt *DSNew = + SemaRef + .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(DSNew); + + RE = SemaRef.BuildDeclRefExpr(ArgVDNew, + VD->getType().getNonReferenceType(), + VK_LValue, SourceLocation()); + RE = ImplicitCastExpr::Create( + SemaRef.Context, VD->getType().getNonReferenceType(), + CK_LValueToRValue, RE, nullptr, VK_PRValue, FPOptionsOverride()); + DIndex++; + CIndex++; + + if (QT->isArrayType()) { + + int Elements = 1; + + QualType SubQT = QT; + while (const ConstantArrayType *AT = SemaRef.Context.getAsConstantArrayType(SubQT)) { + Elements *= AT->getSize().getZExtValue(); + if (AT->getSize() == 0) + return true; + SubQT = AT->getElementType(); + } + + QualType Pty = SemaRef.Context.getPointerType(SubQT); + Expr *AssignedRVExpr = SemaRef.BuildDeclRefExpr(ArgVDNew, ArgVDNew->getType(), VK_LValue, + SourceLocation()); + AssignedRVExpr = SemaRef.ImpCastExprToType(AssignedRVExpr, SemaRef.Context.getArrayDecayedType(QT), + CK_ArrayToPointerDecay).get(); + TypeSourceInfo *AssignedType = SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *AssignedCCE = BaseTransform::RebuildCStyleCastExpr(SourceLocation(), + AssignedType, + SourceLocation(), + AssignedRVExpr).get(); + + std::string AssignedPtrName = "__ASSIGNED_ARRAY_PTR_" + SubQT.getAsString(); + VarDecl *AssignedPtrVar = GetArrayAssignedPointerMap(StringRef(AssignedPtrName)); + if (AssignedPtrVar == nullptr) { + AssignedPtrVar = VarDecl::Create( + SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(AssignedPtrName), + Pty.getNonReferenceType(), nullptr, SC_None); + + SemaRef.AddInitializerToDecl(AssignedPtrVar, AssignedCCE, /*DirectInit=*/true); + + DeclStmt *AssignedDS = + SemaRef + .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(AssignedPtrVar), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(AssignedDS); + SetArrayAssignedPointerMap(StringRef(AssignedPtrName), AssignedPtrVar); + } else { + Expr *AssignedDRE = SemaRef.BuildDeclRefExpr(AssignedPtrVar, AssignedPtrVar->getType(), VK_LValue, + SourceLocation()); + Stmt *AssignedBO = BaseTransform::RebuildBinaryOperator( + SourceLocation(), BO_Assign, AssignedDRE, AssignedCCE) + .getAs(); + DeclStmts.push_back(AssignedBO); + } + DIndex++; + CIndex++; + + Expr *ArrayRVExpr = SemaRef.ImpCastExprToType(LE, SemaRef.Context.getArrayDecayedType(QT), + CK_ArrayToPointerDecay).get(); + TypeSourceInfo *ArrayType = SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *ArrayCCE = BaseTransform::RebuildCStyleCastExpr(SourceLocation(), + ArrayType, + SourceLocation(), + ArrayRVExpr).get(); + + std::string ArrayPtrName = "__ARRAY_PTR_" + SubQT.getAsString(); + VarDecl *ArrayPtrVar = GetArrayPointersMap(StringRef(ArrayPtrName)); + if (ArrayPtrVar == nullptr) { + ArrayPtrVar = VarDecl::Create( + SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(ArrayPtrName), + Pty.getNonReferenceType(), nullptr, SC_None); + + SemaRef.AddInitializerToDecl(ArrayPtrVar, ArrayCCE, /*DirectInit=*/true); + DeclStmt *ArrayDS = + SemaRef + .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArrayPtrVar), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(ArrayDS); + SetArrayPointersMap(StringRef(ArrayPtrName), ArrayPtrVar); + } else { + Expr *ArrayDRE = SemaRef.BuildDeclRefExpr(ArrayPtrVar, ArrayPtrVar->getType(), VK_LValue, + SourceLocation()); + Stmt *ArrayBO = BaseTransform::RebuildBinaryOperator( + SourceLocation(), BO_Assign, ArrayDRE, ArrayCCE) + .getAs(); + DeclStmts.push_back(ArrayBO); + } + DIndex++; + CIndex++; + + if (Elements > 1) { + VarDecl *IArgVDNew = VarDecl::Create( + SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get("I"), SemaRef.Context.IntTy, + nullptr, SC_None); + llvm::APInt Zero( + SemaRef.Context.getTypeSize(SemaRef.Context.IntTy), 0); + Expr *IInit = IntegerLiteral::Create(SemaRef.Context, Zero, + SemaRef.Context.IntTy, + SourceLocation()); + IArgVDNew->setInit(IInit); + DeclGroupRef IDG(IArgVDNew); + Stmt *Init = new (SemaRef.Context) + DeclStmt(IDG, SourceLocation(), SourceLocation()); + + Expr *IDRE = + SemaRef.BuildDeclRefExpr(IArgVDNew, SemaRef.Context.IntTy, + VK_LValue, SourceLocation()); + Expr *ILE = ImplicitCastExpr::Create( + SemaRef.Context, SemaRef.Context.IntTy, CK_LValueToRValue, + IDRE, nullptr, VK_PRValue, FPOptionsOverride()); + + llvm::APInt ISize( + SemaRef.Context.getTypeSize(SemaRef.Context.IntTy), Elements); + Expr *IRE = IntegerLiteral::Create(SemaRef.Context, ISize, + SemaRef.Context.IntTy, + SourceLocation()); + + Expr *Cond = BaseTransform::RebuildBinaryOperator( + SourceLocation(), BO_LT, ILE, IRE) + .getAs(); + + Expr *Inc = BaseTransform::RebuildUnaryOperator(SourceLocation(), + UO_PreInc, IDRE) + .getAs(); + + llvm::SmallVector Stmts; + + Expr *LHS = SemaRef.BuildDeclRefExpr( + ArrayPtrVar, ArrayPtrVar->getType(), VK_LValue, SourceLocation()); + LHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_PostInc, LHS).get(); + LHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, LHS).get(); + + Expr *RHS = SemaRef.BuildDeclRefExpr( + AssignedPtrVar, AssignedPtrVar->getType(), VK_LValue, SourceLocation()); + RHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_PostInc, RHS).get(); + RHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, RHS).get(); + RHS = SemaRef.ImpCastExprToType(RHS, LHS->getType(), CK_LValueToRValue).get(); + + Expr *BO = BaseTransform::RebuildBinaryOperator( + SourceLocation(), BO_Assign, LHS, RHS) + .getAs(); + + Stmts.push_back(BO); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + Stmt *Body = BaseTransform::RebuildCompoundStmt( + SourceLocation(), Stmts, SourceLocation(), false) + .getAs(); + ForStmt *For = new (SemaRef.Context) + ForStmt(SemaRef.Context, Init, Cond, nullptr, Inc, Body, + SourceLocation(), SourceLocation(), SourceLocation()); + + DeclStmts.push_back(For); + DIndex++; + CIndex++; + + LE = SemaRef.BuildDeclRefExpr( + ArrayPtrVar, ArrayPtrVar->getType(), VK_LValue, SourceLocation()); + RE = new (SemaRef.Context) ImplicitValueInitExpr(LE->getType()); + } + } + } + + if (LE && Init) { + if (RE == nullptr) + RE = BaseTransform::TransformExpr(const_cast(Init)) + .getAs(); + BinaryOperator *BO = BaseTransform::RebuildBinaryOperator( + LField->getLocation(), BO_Assign, LE, RE) + .getAs(); + BOStmts.push_back(BO); + } else if (LE && Init == nullptr) { + RE = new (SemaRef.Context) ImplicitValueInitExpr(LE->getType()); + Stmt *NoInit = BaseTransform::RebuildBinaryOperator( + LField->getLocation(), BO_Assign, LE, RE) + .getAs(); + NullStmts.push_back(NoInit); + } + } + } + + int BOSize = BOStmts.size(); + if (BOSize == 0) { + if (NullStmts.size() != 0) + Result = NullStmts.front(); + else + Result = StmDecl; + } else if (BOSize == 1) { + Result = cast(BOStmts.front()); + } else { + BinaryOperator *PreBO = BOStmts.front(); + for (int I = 1; I < BOSize; I++) { + BinaryOperator *BO = BaseTransform::RebuildBinaryOperator( + SourceLocation(), BO_Comma, PreBO, BOStmts[I]) + .getAs(); + PreBO = BO; + } + Result = cast(PreBO); + } + + SetDMap(Result, std::make_tuple(DIndex - CIndex, CIndex)); + return Result; + } + + void SetDMap(Stmt *S, std::tuple val) { + assert(S && "Passed null DeclStmt"); + DMap[S] = val; + } + + std::tuple GetDMap(Stmt *S) { + llvm::DenseMap>::iterator I = DMap.find(S); + if (I != DMap.end()) + return I->second; + return {-1, -1}; + } + + std::vector GetDeclStmts() { return DeclStmts; } + + void SetArrayPointersMap(StringRef APName, VarDecl *VD) { + assert(VD && "Passed null array pointers variable"); + ArrayPointersMap[APName] = VD; + } + + VarDecl *GetArrayPointersMap(StringRef APName) { + llvm::DenseMap::iterator I = ArrayPointersMap.find(APName); + if (I != ArrayPointersMap.end()) + return I->second; + return nullptr; + } + + void SetArrayAssignedPointerMap(StringRef AAPName, VarDecl *VD) { + assert(VD && "Passed null array pointers variable"); + ArrayAssignedPointerMap[AAPName] = VD; + } + + VarDecl *GetArrayAssignedPointerMap(StringRef AAPName) { + llvm::DenseMap::iterator I = ArrayAssignedPointerMap.find(AAPName); + if (I != ArrayAssignedPointerMap.end()) + return I->second; + return nullptr; + } +}; +} // namespace + +namespace { +class TransformToHasSingleState + : public TreeTransform { + typedef TreeTransform BaseTransform; + TransformToAP DT; + +public: + TransformToHasSingleState(Sema &SemaRef, TransformToAP DT) + : BaseTransform(SemaRef), DT(DT) {} + + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } + + StmtResult TransformIfStmt(IfStmt *S) { + bool HasStatement = false; + bool HasStatementElse = false; + IfStmt *If = S; + Stmt *TS = If->getThen(); + Stmt *ES = If->getElse(); + if (TS != nullptr) + HasStatement = (HasAwaitExpr(TS) || HasReturnStmt(TS)); + if (ES != nullptr) + HasStatementElse = (HasAwaitExpr(ES) || HasReturnStmt(ES)); + + if (HasStatementElse && !IsRefactorStmt(ES)) { + std::vector Stmts; + Stmts.push_back(ES); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + ES = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + If->setElse(ES); + } + + if (HasStatement && !IsRefactorStmt(TS)) { + std::vector Stmts; + Stmts.push_back(TS); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + TS = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + If->setThen(TS); + } + + return BaseTransform::TransformIfStmt(If); + } + + StmtResult TransformWhileStmt(WhileStmt *S) { + bool HasStatement = false; + WhileStmt *WS = S; + Stmt *Body = WS->getBody(); + + if (Body != nullptr) + HasStatement = (HasAwaitExpr(Body) || HasReturnStmt(Body)); + + if (HasStatement && !IsRefactorStmt(Body)) { + std::vector Stmts; + Stmts.push_back(Body); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + Body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + WS->setBody(Body); + } + return BaseTransform::TransformWhileStmt(WS); + } + + StmtResult TransformForStmt(ForStmt *S) { + bool HasStatement = false; + ForStmt *FS = S; + Stmt *Body = FS->getBody(); + + if (Body != nullptr) + HasStatement = (HasAwaitExpr(Body) || HasReturnStmt(Body)); + if (HasStatement && !IsRefactorStmt(Body)) { + std::vector Stmts; + Stmts.push_back(Body); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + Body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + FS->setBody(Body); + } + return BaseTransform::TransformForStmt(FS); + } + + StmtResult TransformCaseStmt(CaseStmt *S) { + bool HasStatement = false; + CaseStmt *CS = S; + Stmt *SS = CS->getSubStmt(); + if (SS != nullptr) + HasStatement = (HasAwaitExpr(SS) || HasReturnStmt(SS)); + if (HasStatement && !IsRefactorStmt(SS)) { + std::vector Stmts; + Stmts.push_back(SS); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + SS = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + CS->setSubStmt(SS); + } + return BaseTransform::TransformCaseStmt(CS); + } + + StmtResult TransformDefaultStmt(DefaultStmt *S) { + bool HasStatement = false; + DefaultStmt *DS = S; + Stmt *SS = DS->getSubStmt(); + if (SS != nullptr) + HasStatement = (HasAwaitExpr(SS) || HasReturnStmt(SS)); + if (HasStatement && !IsRefactorStmt(SS)) { + std::vector Stmts; + Stmts.push_back(SS); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + SS = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + DS->setSubStmt(SS); + } + return BaseTransform::TransformDefaultStmt(DS); + } + + StmtResult TransformCompoundStmt(CompoundStmt *S) { + if (S == nullptr) + return S; + + std::vector Statements; + for (auto *C : S->children()) { + Stmt *SS = const_cast(C); + std::tuple DRes = DT.GetDMap(SS); + int DIndex = std::get<0>(DRes); + if (DIndex != -1) { + int DNum = std::get<1>(DRes); + std::vector DeclStmts = DT.GetDeclStmts(); + int size = DeclStmts.size(); + for (int i = DIndex; i < DIndex + DNum; i++) { + if (i < size) + Statements.push_back(DeclStmts[i]); + } + } + SS = BaseTransform::TransformStmt(SS).getAs(); + Statements.push_back(SS); + } + Sema::CompoundScopeRAII CompoundScope(SemaRef); + CompoundStmt *CS = + BaseTransform::RebuildCompoundStmt(SourceLocation(), Statements, + SourceLocation(), false) + .getAs(); + return CS; + } + + StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { + return S; + } +}; +} // namespace + +namespace { +/// Look for Return Stmt +class ARFinder : public StmtVisitor { + Sema &SemaRef; + Expr *PDRE; + RecordDecl *FutureRD; + BSCMethodDecl *FD; + QualType ReturnTy; + std::vector ReturnStmts; + const int UnitNum = 3; + int ReturnNum; + llvm::DenseMap ARMap; + +public: + ARFinder(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, BSCMethodDecl *FD, + QualType ReturnTy) + : SemaRef(SemaRef), PDRE(PDRE), FutureRD(FutureRD), FD(FD), + ReturnTy(ReturnTy) { + ReturnNum = 0; + } + + void VisitReturnStmt(ReturnStmt *S) { + int ARSecond = ReturnStmts.size(); + SetARMap(S, ARSecond); + ReturnNum++; + ReturnStmt *RSS = + ReturnStmt::Create(SemaRef.Context, SourceLocation(), + cast(S)->getRetValue(), nullptr); + const Expr *RetVal = RSS->getRetValue(); + Expr *RHSExpr = const_cast(RetVal); + + RecordDecl::field_iterator FutureStateField, TheFieldIt; + for (TheFieldIt = FutureRD->field_begin(); + TheFieldIt != FutureRD->field_end(); ++TheFieldIt) { + if (TheFieldIt->getDeclName().getAsString() == "__future_state") { + FutureStateField = TheFieldIt; + break; + } + } + if (TheFieldIt != FutureRD->field_end()) { + DeclarationName Name = FutureStateField->getDeclName(); + DeclarationNameInfo MemberNameInfo(Name, FutureStateField->getLocation()); + Expr *LHSExpr = SemaRef.BuildMemberExpr( + PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FutureStateField, + DeclAccessPair::make(*FutureStateField, + FutureStateField->getAccess()), + false, MemberNameInfo, + FutureStateField->getType().getNonReferenceType(), VK_LValue, + OK_Ordinary); + + llvm::APInt ResultVal(SemaRef.Context.getTargetInfo().getIntWidth(), 1); + Expr *FutureStateVal = IntegerLiteral::Create( + SemaRef.Context, ResultVal, SemaRef.Context.IntTy, SourceLocation()); + + Expr *Unop = + SemaRef + .CreateBuiltinUnaryOp(SourceLocation(), UO_Minus, FutureStateVal) + .get(); + Expr *BO = + SemaRef.CreateBuiltinBinOp(SourceLocation(), BO_Assign, LHSExpr, Unop) + .get(); + ReturnStmts.push_back(BO); + } + + std::string ResReturnName = "__RES_RETURN"; + VarDecl *ResReturnVD = + VarDecl::Create(SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(ResReturnName), + RHSExpr->getType(), nullptr, SC_None); + + ResReturnVD->setInit(RHSExpr); + DeclGroupRef ResReturnDG(ResReturnVD); + DeclStmt *ResReturnDS = new (SemaRef.Context) + DeclStmt(ResReturnDG, SourceLocation(), SourceLocation()); + ReturnStmts.push_back(ResReturnDS); + + Expr *ResExpr = SemaRef.BuildDeclRefExpr( + ResReturnVD, ResReturnVD->getType(), VK_LValue, SourceLocation()); + + ResExpr = ImplicitCastExpr::Create(SemaRef.Context, ResReturnVD->getType(), + CK_LValueToRValue, ResExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + + SmallVector Args; + Args.push_back(ResExpr); + + QualType PollResultType = FD->getReturnType(); + RecordDecl *PollResultRD = PollResultType->getAsRecordDecl(); + + std::string CompletedFuncName = "completed"; + LookupResult CompletedFDResult( + SemaRef, + DeclarationNameInfo(&(SemaRef.Context.Idents).get(CompletedFuncName), + SourceLocation()), + SemaRef.LookupOrdinaryName); + SemaRef.LookupQualifiedName(CompletedFDResult, PollResultRD); + BSCMethodDecl *CompletedFD = nullptr; + if (!CompletedFDResult.empty()) + CompletedFD = + dyn_cast_or_null(CompletedFDResult.getFoundDecl()); + + Expr *CompletedRef = SemaRef.BuildDeclRefExpr( + CompletedFD, CompletedFD->getType(), VK_LValue, SourceLocation()); + CompletedRef = SemaRef + .ImpCastExprToType(CompletedRef, + SemaRef.Context.getPointerType( + CompletedRef->getType()), + CK_FunctionToPointerDecay) + .get(); + + Expr *CE = SemaRef + .BuildCallExpr(nullptr, CompletedRef, SourceLocation(), Args, + SourceLocation()) + .get(); + Stmt *RS = SemaRef.BuildReturnStmt(SourceLocation(), CE).get(); + ReturnStmts.push_back(RS); + return; + } + + void VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + Visit(C); + } + } + } + + int GetReturnNum() { return ReturnNum; } + + std::vector GetReturnStmts() { return ReturnStmts; } + + int GetUnitNum() { return UnitNum; } + + void SetARMap(ReturnStmt *RS, int index) { + assert(RS && "Passed null Return"); + ARMap[RS] = index; + } + + int GetARMap(ReturnStmt *RS) { + llvm::DenseMap::iterator I = ARMap.find(RS); + if (I != ARMap.end()) + return I->second; + return -1; + } +}; +} // namespace + +namespace { +class TransformARToCS : public TreeTransform { + typedef TreeTransform BaseTransform; + ARFinder ARInitlizer; + int ReturnNum; + int ReturnIndex; + +public: + TransformARToCS(Sema &SemaRef, ARFinder ARInitlizer) + : BaseTransform(SemaRef), ARInitlizer(ARInitlizer) { + ReturnIndex = 0; + ReturnNum = ARInitlizer.GetReturnNum(); + } + + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } + + StmtResult TransformCompoundStmt(CompoundStmt *S) { + if (S == nullptr) + return S; + + int UnitNum = ARInitlizer.GetUnitNum(); + std::vector ReturnStmts = ARInitlizer.GetReturnStmts(); + int StmtsSize = ReturnStmts.size(); + + std::vector Statements; + for (auto *C : S->children()) { + Stmt *SS = const_cast(C); + if (isa(SS)) { + int index = ARInitlizer.GetARMap(cast(SS)); + for (int i = index; i < index + UnitNum; i++) { + if (i < StmtsSize) + Statements.push_back(ReturnStmts[i]); + } + continue; + } + SS = BaseTransform::TransformStmt(SS).getAs(); + Statements.push_back(SS); + } + Sema::CompoundScopeRAII CompoundScope(SemaRef); + CompoundStmt *CS = + BaseTransform::RebuildCompoundStmt(SourceLocation(), Statements, + SourceLocation(), false) + .getAs(); + return CS; + } + + StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { + return S; + } +}; +} // namespace + +namespace { +class AEFinder : public StmtVisitor { + Sema &SemaRef; + ParmVarDecl *PVD; + Expr *PDRE; + RecordDecl *FutureRD; + BSCMethodDecl *FD; + std::vector AwaitStmts; + const int UnitNum = 5; + int AwaitCount = 0; + llvm::DenseMap AEMap; + llvm::DenseMap AEReplaceMap; + +public: + AEFinder(Sema &SemaRef, ParmVarDecl *PVD, Expr *PDRE, RecordDecl *FutureRD, + BSCMethodDecl *FD) + : SemaRef(SemaRef), PVD(PVD), PDRE(PDRE), FutureRD(FutureRD), FD(FD) { + AwaitCount = 0; + } + + void VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + Visit(C); + } + } + } + + void VisitAwaitExpr(AwaitExpr *E) { + Visit(E->getSubExpr()); + AwaitCount++; + int AESecond = AwaitStmts.size(); + SetAEMap(E, AESecond); + AwaitExpr *AtEr = E; + auto *AE = AtEr->getSubExpr(); + RecordDecl::field_iterator FtField, FtFieldIt; + for (FtFieldIt = FutureRD->field_begin(); + FtFieldIt != FutureRD->field_end(); ++FtFieldIt) { + if (FtFieldIt->getDeclName().getAsString() == + "Ft_" + std::to_string(AwaitCount)) { + FtField = FtFieldIt; + break; + } + } + + Expr *LHSExpr = SemaRef.BuildMemberExpr( + PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FtField, + DeclAccessPair::make(PVD, FtField->getAccess()), false, + DeclarationNameInfo(), FtField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + Expr *RHSExpr = AE; + // Handle nested call + if (isa(AE)) { + CallExpr *CE = const_cast(cast(AE)); + FunctionDecl *CFD = CE->getDirectCallee(); + std::vector CallArgs; + for (unsigned I = 0; I < CE->getNumArgs(); ++I) { + if (auto *KReplaceAE = dyn_cast(CE->getArg(I))) { + Expr *VReplaceAE = GetAEReplaceMap(KReplaceAE); + if (VReplaceAE != nullptr) { + CallArgs.push_back(VReplaceAE); + continue; + } + } + CallArgs.push_back(CE->getArg(I)); + } + Expr *FDRef = + SemaRef.BuildDeclRefExpr(CFD, CFD->getType().getNonReferenceType(), + VK_LValue, CFD->getLocation()); + FDRef = SemaRef + .ImpCastExprToType( + FDRef, SemaRef.Context.getPointerType(CFD->getType()), + CK_FunctionToPointerDecay) + .get(); + + RHSExpr = SemaRef + .BuildCallExpr(nullptr, FDRef, SourceLocation(), CallArgs, + SourceLocation()) + .get(); + } + + Expr *ResultStmt = SemaRef + .CreateBuiltinBinOp((*FtField)->getLocation(), + BO_Assign, LHSExpr, RHSExpr) + .get(); + AwaitStmts.push_back(ResultStmt); + RecordDecl *FatPointerRD = + dyn_cast( + LHSExpr->getType().getDesugaredType(SemaRef.Context)) + ->getDecl(); + RecordDecl::field_iterator PtrField, VtableField, FPFieldIt; + for (FPFieldIt = FatPointerRD->field_begin(); + FPFieldIt != FatPointerRD->field_end(); ++FPFieldIt) { + if (FPFieldIt->getDeclName().getAsString() == "data") { + PtrField = FPFieldIt; + } else if (FPFieldIt->getDeclName().getAsString() == "vtable") { + VtableField = FPFieldIt; + } + } + + // this.Ft_.vtable + Expr *VtableExpr = SemaRef.BuildMemberExpr( + LHSExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *VtableField, + DeclAccessPair::make(FatPointerRD, VtableField->getAccess()), false, + DeclarationNameInfo(), VtableField->getType(), VK_LValue, + OK_Ordinary); + VtableExpr = ImplicitCastExpr::Create( + SemaRef.Context, VtableExpr->getType(), CK_LValueToRValue, VtableExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + + RecordDecl::field_iterator PollFuncField, VtableFieldIt; + const RecordType *RT = dyn_cast( + VtableField->getType()->getPointeeType().getDesugaredType( + SemaRef.Context)); + RecordDecl *VtableRD = RT->getDecl(); + for (VtableFieldIt = VtableRD->field_begin(); + VtableFieldIt != VtableRD->field_end(); ++VtableFieldIt) { + if (VtableFieldIt->getDeclName().getAsString() == "poll") { + PollFuncField = VtableFieldIt; + } + } + const FunctionType *FT = dyn_cast( + PollFuncField->getType()->getPointeeType().getDesugaredType( + SemaRef.Context)); + RecordDecl *PollResultRD = dyn_cast( + dyn_cast( + SemaRef.Context.getCanonicalType(FT->getReturnType())) + ->getDecl()); + + Expr *PollFuncExpr = SemaRef.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PollFuncField, + DeclAccessPair::make(VtableRD, PollFuncField->getAccess()), false, + DeclarationNameInfo(), PollFuncField->getType(), VK_LValue, + OK_Ordinary); + PollFuncExpr = ImplicitCastExpr::Create( + SemaRef.Context, PollFuncExpr->getType(), CK_LValueToRValue, + PollFuncExpr, nullptr, VK_PRValue, FPOptionsOverride()); + std::vector PollArgs; + Expr *PtrExpr = SemaRef.BuildMemberExpr( + LHSExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PtrField, + DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, + DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); + PtrExpr = ImplicitCastExpr::Create(SemaRef.Context, PtrExpr->getType(), + CK_LValueToRValue, PtrExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + PollArgs.push_back(PtrExpr); + Expr *PollFuncCall = + SemaRef + .BuildCallExpr(nullptr, PollFuncExpr, SourceLocation(), PollArgs, + SourceLocation()) + .get(); + + RecordDecl::field_iterator ResField, FieldIt; + for (FieldIt = PollResultRD->field_begin(); + FieldIt != PollResultRD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "res") { + ResField = FieldIt; + break; + } + } + std::string AwaitResultVDName = "Res_" + std::to_string(AwaitCount); + VarDecl *AwaitResultVD = VarDecl::Create( + SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(AwaitResultVDName), ResField->getType(), + nullptr, SC_None); + + DeclGroupRef AwaitResultDG(AwaitResultVD); + DeclStmt *AwaitResultDS = new (SemaRef.Context) + DeclStmt(AwaitResultDG, SourceLocation(), SourceLocation()); + AwaitStmts.push_back(AwaitResultDS); + + std::string PollResultVDName = "PR_" + std::to_string(AwaitCount); + VarDecl *PollResultVD = VarDecl::Create( + SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(PollResultVDName), + PollFuncCall->getType(), nullptr, SC_None); + + PollResultVD->setInit(PollFuncCall); + DeclGroupRef PollResultDG(PollResultVD); + DeclStmt *PollResultDS = new (SemaRef.Context) + DeclStmt(PollResultDG, SourceLocation(), SourceLocation()); + AwaitStmts.push_back(PollResultDS); + + auto *If = ProcessAwaitExprStatus(SemaRef, AwaitCount, FutureRD, PDRE, + PVD, PollResultVD, AwaitResultVD, FD); + if (If != nullptr) + AwaitStmts.push_back(If); + + Expr *AwaitResultRef = SemaRef.BuildDeclRefExpr( + AwaitResultVD, AwaitResultVD->getType(), VK_LValue, SourceLocation()); + AwaitResultRef = ImplicitCastExpr::Create( + SemaRef.Context, AwaitResultVD->getType(), CK_LValueToRValue, + AwaitResultRef, nullptr, VK_PRValue, FPOptionsOverride()); + SetAEReplaceMap(E, AwaitResultRef); + AwaitStmts.push_back(cast(AwaitResultRef)); + } + + int GetAwaitCount() { return AwaitCount; } + + std::vector GetAwaitStmts() { return AwaitStmts; } + + int GetUnitNum() { return UnitNum; } + + void SetAEMap(AwaitExpr *AE, int index) { + assert(AE && "Passed null AwaitExpr"); + AEMap[AE] = index; + } + + int GetAEMap(AwaitExpr *AE) { + llvm::DenseMap::iterator I = AEMap.find(AE); + if (I != AEMap.end()) + return I->second; + return -1; + } + + void SetAEReplaceMap(AwaitExpr *AE, Expr *AEReplace) { + assert(AE && "Passed null AwaitExpr"); + AEReplaceMap[AE] = AEReplace; + } + + Expr *GetAEReplaceMap(AwaitExpr *AE) { + llvm::DenseMap::iterator I = AEReplaceMap.find(AE); + if (I != AEReplaceMap.end()) + return cast(I->second); + return nullptr; + } +}; +} // namespace + +namespace { +class TransformAEToCS : public TreeTransform { + typedef TreeTransform BaseTransform; + AEFinder AEInitlizer; + int AwaitNum; + int AwaitIndex; + std::vector AEStmts; + std::vector &LabelDecls; + +public: + TransformAEToCS(Sema &SemaRef, AEFinder AEInitlizer, + std::vector &LabelDecls) + : BaseTransform(SemaRef), AEInitlizer(AEInitlizer), + LabelDecls(LabelDecls) { + AwaitIndex = 0; + AwaitNum = AEInitlizer.GetAwaitCount(); + } + + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } + + ExprResult TransformAwaitExpr(AwaitExpr *E) { + return AEInitlizer.GetAEReplaceMap(E); + } + + StmtResult TransformReturnStmt(ReturnStmt *S) { return S; } + + StmtResult TransformCompoundStmt(CompoundStmt *S) { + if (S == nullptr) + return S; + + int UnitNum = AEInitlizer.GetUnitNum(); + std::vector AwaitStmts = AEInitlizer.GetAwaitStmts(); + int StmtsSize = AwaitStmts.size(); + + std::vector Statements; + for (auto *C : S->children()) { + Stmt *SS = const_cast(C); + AEStmts.clear(); + GetAwaitExpr(SS); + int AESize = AEStmts.size(); + if (AESize > 0) { + for (int i = 0; i < AESize; i++) { + int index = AEInitlizer.GetAEMap(AEStmts[i]); + for (int j = index; j < index + UnitNum - 1; j++) { + if (j == index + 1) { + LabelStmt *LS = + BaseTransform::RebuildLabelStmt( + SourceLocation(), + cast(LabelDecls[AwaitIndex + i + 1]), + SourceLocation(), AwaitStmts[j]) + .getAs(); + Statements.push_back(LS); + continue; + } + + if (j < StmtsSize) + Statements.push_back(AwaitStmts[j]); + } + } + + AwaitIndex = AwaitIndex + AESize; + } + + SS = BaseTransform::TransformStmt(SS).getAs(); + Statements.push_back(SS); + } + Sema::CompoundScopeRAII CompoundScope(SemaRef); + CompoundStmt *CS = + BaseTransform::RebuildCompoundStmt(SourceLocation(), Statements, + SourceLocation(), false) + .getAs(); + return CS; + } + + StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { + return S; + } + + void GetAwaitExpr(Stmt *S) { + if (S == nullptr || isa(S)) + return; + + for (auto *C : S->children()) { + GetAwaitExpr(C); + } + + if (isa(S)) { + AEStmts.push_back(cast(S)); + } + } +}; +} // namespace static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, FunctionDecl *FD) { -- Gitee From 3bd9905056aeb2c0b2ab4b2164b0a9f23d884c3c Mon Sep 17 00:00:00 2001 From: Healing Date: Mon, 3 Jul 2023 11:40:53 +0800 Subject: [PATCH 4/8] [BSC] Coroutine: handle async functions which return void --- clang/lib/Sema/SemaBSCCoroutine.cpp | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/clang/lib/Sema/SemaBSCCoroutine.cpp b/clang/lib/Sema/SemaBSCCoroutine.cpp index dae84853e220..832271dd689d 100644 --- a/clang/lib/Sema/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/SemaBSCCoroutine.cpp @@ -421,6 +421,34 @@ static RecordDecl *buildFutureRecordDecl( return RD; } +static RecordDecl *generateVoidStruct(Sema &S) { + std::string Recordname = "Void"; + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(Recordname))); + RecordDecl *VoidRD = nullptr; + + if (Decls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Decls.begin(), + E = Decls.end(); + I != E; ++I) { + if (isa(*I)) { + VoidRD = dyn_cast(*I); + break; + } + } + } else if (Decls.empty()) { + VoidRD = buildAsyncDataRecord(S.Context, Recordname, SourceLocation(), + SourceLocation(), + clang::TagDecl::TagKind::TTK_Struct); + VoidRD->startDefinition(); + VoidRD->completeDefinition(); + S.PushOnScopeChains(VoidRD, S.getCurScope(), true); + } else { + // should not reach here. todo: change to assert + abort(); + } + return VoidRD; +} /// TODO: will be removed after using Future in stdlib static std::tuple, std::pair> @@ -944,6 +972,88 @@ Stmt *ProcessAwaitExprStatus(Sema &S, int AwaitCount, RecordDecl *RD, Expr *ICE, return If; } +namespace { +class TransformToReturnVoid : public TreeTransform { + typedef TreeTransform BaseTransform; + QualType ReturnTy = QualType(); + +public: + TransformToReturnVoid(Sema &SemaRef) : BaseTransform(SemaRef) {} + + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } + + Decl *TransformFunctionDecl(FunctionDecl *D) { + if (D->getReturnType()->isVoidType()) { + std::string ReturnStructName = "Void"; + DeclContext::lookup_result ReturnDecls = + SemaRef.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(SemaRef.Context.Idents).get(ReturnStructName))); + RecordDecl *ReturnDecl = nullptr; + if (ReturnDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = ReturnDecls.begin(), + E = ReturnDecls.end(); + I != E; ++I) { + if (isa(*I)) { + ReturnDecl = dyn_cast(*I); + break; + } + } + } + + assert(ReturnDecl && "struct Void not generated"); + ReturnTy = SemaRef.Context.getRecordType(ReturnDecl); + SmallVector ParamTys; + FunctionDecl::param_const_iterator pi; + for (pi = D->param_begin(); pi != D->param_end(); pi++) { + ParamTys.push_back((*pi)->getType()); + } + QualType FuncType = + SemaRef.Context.getFunctionType(ReturnTy, ParamTys, {}); + D->setType(FuncType); + + CompoundStmt *body = dyn_cast(D->getBody()); + Stmt *LastStmt = body->body_back(); + if (!LastStmt || !dyn_cast(LastStmt)) { + std::vector Stmts; + for (auto *C : body->children()) { + Stmts.push_back(C); + } + ReturnStmt *RS = ReturnStmt::Create(SemaRef.Context, SourceLocation(), + nullptr, nullptr); + Stmts.push_back(RS); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + CompoundStmt *CS = BaseTransform::RebuildCompoundStmt( + SourceLocation(), Stmts, SourceLocation(), false) + .getAs(); + D->setBody(CS); + } + + Stmt *FuncBody = BaseTransform::TransformStmt(D->getBody()).getAs(); + D->setBody(FuncBody); + } + return D; + } + + StmtResult TransformReturnStmt(ReturnStmt *S) { + assert(!S->getRetValue() && "void function should not return a value"); + InitListExpr *ILE = new (SemaRef.Context) + InitListExpr(SemaRef.Context, SourceLocation(), {}, SourceLocation()); + QualType Ty = SemaRef.Context.getElaboratedType(ETK_Struct, nullptr, + ReturnTy, nullptr); + ILE->setType(Ty); + TypeSourceInfo *superTInfo = SemaRef.Context.getTrivialTypeSourceInfo(Ty); + CompoundLiteralExpr *CLE = new (SemaRef.Context) CompoundLiteralExpr( + SourceLocation(), superTInfo, Ty, VK_LValue, ILE, false); + ImplicitCastExpr *ICE = + ImplicitCastExpr::Create(SemaRef.Context, Ty, CK_LValueToRValue, CLE, + nullptr, VK_PRValue, FPOptionsOverride()); + ReturnStmt *RS = + ReturnStmt::Create(SemaRef.Context, SourceLocation(), ICE, nullptr); + return RS; + } +}; +} // namespace namespace { class TransformToAP : public TreeTransform { -- Gitee From 2f039ba280155f6fb1a56b6fa7e3fbac33814d2c Mon Sep 17 00:00:00 2001 From: jeanniely Date: Mon, 3 Jul 2023 14:08:22 +0800 Subject: [PATCH 5/8] [BSC] Coroutine: add testcases --- .../await-expr-compound-expression.cbs | 14 +++ .../AwaitExpr/await-expr-for-cond.cbs | 17 ++++ .../AwaitExpr/await-expr-if-cond.cbs | 18 ++++ .../AwaitExpr/await-expr-nest-await.cbs | 17 ++++ .../Coroutine/AwaitExpr/await-expr-num.cbs | 51 ++++++++++ .../AwaitExpr/await-expr-single-judgement.cbs | 29 ++++++ .../AwaitExpr/await-expr-switch-cond.cbs | 21 +++++ .../AwaitExpr/await-expr-while-cond.cbs | 16 ++++ .../Other/Definition/async_definition_1.cbs | 22 +++++ .../async-different-return-type2.cbs | 25 +++++ .../await-different-return-type.cbs | 23 +++++ .../async-instance-member-function.cbs | 25 +++++ .../MemberFunc/async-member-function.cbs | 23 +++++ .../Other/NonCallAwaitExpr/await-non-call.cbs | 24 +++++ .../DeclStmt/Common/auto-storage-class.cbs | 23 +++++ .../DeclStmt/Common/await-expr-for.cbs | 19 ++++ .../DeclStmt/Common/func-invoke.cbs | 21 +++++ .../Common/register-storage-class.cbs | 19 ++++ .../DeclStmt/Common/static-storage-class.cbs | 22 +++++ .../DeclStmt/Common/variable_undeclared.cbs | 13 +++ .../Treetransform/DeclStmt/Enum/enum1.cbs | 22 +++++ .../DeclStmt/MultiDecl/array-decl.cbs | 27 ++++++ .../DeclStmt/MultiDecl/array-decl1.cbs | 18 ++++ .../DeclStmt/MultiDecl/base-type-decl.cbs | 32 +++++++ .../DeclStmt/MultiDecl/const-decl.cbs | 28 ++++++ .../DeclStmt/MultiDecl/global-decl.cbs | 19 ++++ .../MultiDecl/literal-quantity-decl.cbs | 20 ++++ .../DeclStmt/MultiDecl/multi-decl.cbs | 21 +++++ .../MultiDecl/multi-dimension-array-decl.cbs | 22 +++++ .../DeclStmt/MultiDecl/pointer-decl.cbs | 27 ++++++ .../DeclStmt/MultiDecl/static-decl.cbs | 28 ++++++ .../DeclStmt/MultiDecl/string-decl.cbs | 19 ++++ .../DeclStmt/MultiDecl/struct-decl.cbs | 26 ++++++ .../DeclStmt/MultiDecl/uninit-array-decl.cbs | 29 ++++++ .../Pointer/arithmetic-op-of-c-pointer.cbs | 27 ++++++ .../DeclStmt/Pointer/c-pointer-to-pointer.cbs | 22 +++++ .../DeclStmt/Pointer/func-pointer.cbs | 26 ++++++ .../DeclStmt/Struct/struct-init.cbs | 27 ++++++ .../DeclStmt/Union/union-init.cbs | 26 ++++++ .../Other/Judgement/await-expr-if.cbs | 26 ++++++ .../Other/Judgement/if-else-statement.cbs | 20 ++++ .../Judgement/if-nested-if-statement.cbs | 21 +++++ .../Other/Judgement/if-statement.cbs | 20 ++++ .../switch-nested-switch-statement.cbs | 38 ++++++++ .../Other/Judgement/switch-statement.cbs | 32 +++++++ .../Other/Loop/do-while-loop.cbs | 21 +++++ .../Treetransform/Other/Loop/for-loop.cbs | 19 ++++ .../Treetransform/Other/Loop/loop-nested.cbs | 23 +++++ .../Treetransform/Other/Loop/while-loop.cbs | 22 +++++ .../Other/Operators/arithmetic-op.cbs | 26 ++++++ .../Other/Operators/assign-op.cbs | 30 ++++++ .../Treetransform/Other/Operators/bit-op.cbs | 26 ++++++ .../Other/Operators/logocal-op.cbs | 23 +++++ .../Other/Operators/other-op.cbs | 22 +++++ .../Other/Operators/relational-op.cbs | 26 ++++++ .../async-func-return-const-int.cbs | 25 +++++ .../ReturnStmt/async-func-return-type.cbs | 92 +++++++++++++++++++ .../ReturnStmt/async-func-return-void.cbs | 18 ++++ .../ReturnStmt/await-expr-return-type.cbs | 17 ++++ .../ReturnStmt/await-expr-return-type1.cbs | 20 ++++ .../Coroutine/async-func-read-opposite.hbs | 51 ++++++++++ clang/test/BSC/Coroutine/async-func-read.hbs | 50 ++++++++++ clang/test/BSC/Coroutine/future.hbs | 35 +++++++ 63 files changed, 1611 insertions(+) create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-compound-expression.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-for-cond.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-if-cond.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-nest-await.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-num.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-switch-cond.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-while-cond.cbs create mode 100644 clang/test/BSC/Coroutine/Other/Definition/async_definition_1.cbs create mode 100644 clang/test/BSC/Coroutine/Other/DifferenctReturnType/async-different-return-type2.cbs create mode 100644 clang/test/BSC/Coroutine/Other/DifferenctReturnType/await-different-return-type.cbs create mode 100644 clang/test/BSC/Coroutine/Other/MemberFunc/async-instance-member-function.cbs create mode 100644 clang/test/BSC/Coroutine/Other/MemberFunc/async-member-function.cbs create mode 100644 clang/test/BSC/Coroutine/Other/NonCallAwaitExpr/await-non-call.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/auto-storage-class.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/await-expr-for.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/func-invoke.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/register-storage-class.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/static-storage-class.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/variable_undeclared.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Enum/enum1.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl1.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/base-type-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/global-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/pointer-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/static-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/string-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/struct-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/uninit-array-decl.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/func-pointer.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Struct/struct-init.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/Union/union-init.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Judgement/await-expr-if.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-else-statement.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-nested-if-statement.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-statement.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-nested-switch-statement.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-statement.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Loop/do-while-loop.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Loop/for-loop.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Loop/loop-nested.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Loop/while-loop.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Operators/arithmetic-op.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Operators/assign-op.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Operators/bit-op.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Operators/logocal-op.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Operators/other-op.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/Other/Operators/relational-op.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-const-int.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-type.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-void.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type1.cbs create mode 100644 clang/test/BSC/Coroutine/async-func-read-opposite.hbs create mode 100644 clang/test/BSC/Coroutine/async-func-read.hbs create mode 100644 clang/test/BSC/Coroutine/future.hbs diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-compound-expression.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-compound-expression.cbs new file mode 100644 index 000000000000..e07f4dbd8011 --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-compound-expression.cbs @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +async int f(int start) { + int x = await read(2) + 3; // #1 + return 42; +} + +// expected-error@#1 {{await expression is not allowed to appear in binary operator expression}} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-for-cond.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-for-cond.cbs new file mode 100644 index 000000000000..41756a82b10b --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-for-cond.cbs @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +async int f(int start) { + int result = start; + for (int i = await read(1); i < start; i++) { // #1 + int a = await read(1); + } + return result; +} + +// expected-error@#1 {{await expression is not allowed to appear in condition statement of for loop}} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-if-cond.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-if-cond.cbs new file mode 100644 index 000000000000..02c0b4aa4245 --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-if-cond.cbs @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +async int f(int start) { + int result = start; + if (await read(1) == 1) { // #1 + int a = await read(1); + } + return result; +} + +// expected-error@#1 {{await expression is not allowed to appear in condition statement of if statement}} +// expected-error@#1 {{await expression is not allowed to appear in binary operator expression}} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-nest-await.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-nest-await.cbs new file mode 100644 index 000000000000..ab3bbf254357 --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-nest-await.cbs @@ -0,0 +1,17 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../async-func-read.hbs" + +async int f(int start) { + int result = await read(await read(start)); + return result; +} + +int main() { + struct __FatPointer_int this = f(1); + this.vtable->poll(this.data); + this.vtable->free(this.data); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-num.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-num.cbs new file mode 100644 index 000000000000..fa912fc64a66 --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-num.cbs @@ -0,0 +1,51 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../async-func-read.hbs" + +struct _Futuretest2 { + int a; + int res; + int __future_state; +}; +typedef struct _Futuretest2 __Futuretest2; + +struct PollResult struct _Futuretest2::poll(__Futuretest2 *this) { + struct PollResult poll_result; + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->res = this->a; + this->__future_state = -1; + return struct PollResult::completed(this->res); +} + +void struct _Futuretest2::free(struct _Futuretest2 *this) {} + +struct __Vtable_int _Futuretest2_vtable = { + .poll = struct _Futuretest2::poll, + .free = struct _Futuretest2::free +}; + +struct __FatPointer_int test2(int a) { + struct _Futuretest2* ptr = malloc(sizeof(struct _Futuretest2)); + ptr->a = a; + ptr->__future_state = 0; + return (struct __FatPointer_int) { .data = ptr, .vtable = &_Futuretest2_vtable}; +} + +async int f(int start) { + int result = await read(2); + if (start < 20) + start = await test2(1); + return result + start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs new file mode 100644 index 000000000000..38302394a830 --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs @@ -0,0 +1,29 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../async-func-read.hbs" + +async int f(int start) { + int a = 3; + if (a == 3) + for(int i=0;i<1; i++) + a = await read(1); + else if (a == 4) { + if (a == 4) + a = await read(1); + } + else + a = await read(1); + + while (a<3) + a = await read(1); + + return start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-switch-cond.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-switch-cond.cbs new file mode 100644 index 000000000000..75005c7a043c --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-switch-cond.cbs @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +async int f(int start) { + int result = start; + switch (await read(1)) { // #1 + case 0: + return 0; + case 1: + return 1; + default: + return -1; + } +} + +// expected-error@#1 {{await expression is not allowed to appear in condition statement of switch statement}} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-while-cond.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-while-cond.cbs new file mode 100644 index 000000000000..533d3d4b0243 --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-while-cond.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +async int f(int start) { + int result = start; + while (result != await read(1)) { // expected-error {{await expression is not allowed to appear in condition statement of while loop}} + // expected-error@-1 {{await expression is not allowed to appear in binary operator expression}} + result = await read(1); + } + return result; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/Definition/async_definition_1.cbs b/clang/test/BSC/Coroutine/Other/Definition/async_definition_1.cbs new file mode 100644 index 000000000000..451a32f7bccc --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/Definition/async_definition_1.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output + +#include "../../async-func-read.hbs" + +async int g(); + +async int f() { + int a = await g(); + return a; +} + +async int g() { + int a = await read(1); + return 0; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/DifferenctReturnType/async-different-return-type2.cbs b/clang/test/BSC/Coroutine/Other/DifferenctReturnType/async-different-return-type2.cbs new file mode 100644 index 000000000000..464a9a438643 --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/DifferenctReturnType/async-different-return-type2.cbs @@ -0,0 +1,25 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output + +#include "../../async-func-read.hbs" +#include + +async bool int::g(); + +async int int::f() { + await int::g(); + return 0; +} + +async bool int::g() { + struct __FatPointer_int a = read(1); + await a; + return false; +} + +int main() { + struct __FatPointer_int this = int::f(); + this.vtable->poll(this.data); + this.vtable->free(this.data); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/DifferenctReturnType/await-different-return-type.cbs b/clang/test/BSC/Coroutine/Other/DifferenctReturnType/await-different-return-type.cbs new file mode 100644 index 000000000000..007d8602f8d9 --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/DifferenctReturnType/await-different-return-type.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output + +#include "../../async-func-read.hbs" + +async void g(); + +async int f() { + await g(); + return 0; +} + +async void g() { + struct __FatPointer_int a = read(1); + await a; +} + +int main() { + struct __FatPointer_int this = f(); + this.vtable->poll(this.data); + this.vtable->free(this.data); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/MemberFunc/async-instance-member-function.cbs b/clang/test/BSC/Coroutine/Other/MemberFunc/async-instance-member-function.cbs new file mode 100644 index 000000000000..34db06d42fbc --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/MemberFunc/async-instance-member-function.cbs @@ -0,0 +1,25 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output + +#include "../../async-func-read.hbs" + +async void int::g(int* this); + +async int int::f() { + int i = 1; + await int::g(&i); + await i.g(); + return 0; +} + +async void int::g(int* this) { + struct __FatPointer_int a = read(1); + await a; +} + +int main() { + struct __FatPointer_int this = int::f(); + this.vtable->poll(this.data); + this.vtable->free(this.data); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/MemberFunc/async-member-function.cbs b/clang/test/BSC/Coroutine/Other/MemberFunc/async-member-function.cbs new file mode 100644 index 000000000000..e694df48eeb3 --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/MemberFunc/async-member-function.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output + +#include "../../async-func-read.hbs" + +async void int::g(); + +async int int::f() { + await int::g(); + return 0; +} + +async void int::g() { + struct __FatPointer_int a = read(1); + await a; +} + +int main() { + struct __FatPointer_int this = int::f(); + this.vtable->poll(this.data); + this.vtable->free(this.data); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/NonCallAwaitExpr/await-non-call.cbs b/clang/test/BSC/Coroutine/Other/NonCallAwaitExpr/await-non-call.cbs new file mode 100644 index 000000000000..2aa0865d535c --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/NonCallAwaitExpr/await-non-call.cbs @@ -0,0 +1,24 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output + +#include "../../async-func-read.hbs" + +async int g(); + +async int f() { + int a = await g(); + return a; +} + +async int g() { + struct __FatPointer_int a = read(1); + await a; + return 0; +} + +int main() { + struct __FatPointer_int this = f(); + this.vtable->poll(this.data); + this.vtable->free(this.data); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/auto-storage-class.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/auto-storage-class.cbs new file mode 100644 index 000000000000..b1894732ddb0 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/auto-storage-class.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + auto int j = 1; + { + auto int j= 2; + { + auto int j = 3; + } + } + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/await-expr-for.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/await-expr-for.cbs new file mode 100644 index 000000000000..6996ba85987d --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/await-expr-for.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int result = start; + for (int i = 0; i < start; i++) { + int a = await read(1); + } + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/func-invoke.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/func-invoke.cbs new file mode 100644 index 000000000000..9924f1d599b9 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/func-invoke.cbs @@ -0,0 +1,21 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +int test() { + return 5; +} + +async int f(int start) { + start = test(); + int result = await read(1); + return result + start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/register-storage-class.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/register-storage-class.cbs new file mode 100644 index 000000000000..7a0a2b7ba2e1 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/register-storage-class.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + register char a = 'S'; + register double b = 10; + register int c = 8; + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/static-storage-class.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/static-storage-class.cbs new file mode 100644 index 000000000000..c7a5b890a993 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/static-storage-class.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +static int count = 10; + +async int f(int start) { + while (count--) + { + start ++; + } + int result = await read(2); + return result + 5 + start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/variable_undeclared.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/variable_undeclared.cbs new file mode 100644 index 000000000000..09ff8e08fb3b --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Common/variable_undeclared.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -verify %s + +#include "../../../async-func-read-opposite.hbs" + +async int f(int start) { + int result = await read(r1); // expected-error {{use of undeclared identifier 'r1'}} + // expected-error@-1 {{initializing 'int' with an expression of incompatible type ''}} + return result; +} + +int main() { + return 0; +} diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Enum/enum1.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Enum/enum1.cbs new file mode 100644 index 000000000000..9795d87f52a2 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Enum/enum1.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +enum +{ + MON=1, TUE, WED, THU, FRI, SAT, SUN +} day; + +async int f(int start) { + start = WED; + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl.cbs new file mode 100644 index 000000000000..e130b577d257 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl.cbs @@ -0,0 +1,27 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Addr { + int a; + char *addr; +}; + +async int f(int start) { + int result = start; + char str[10] = "hello"; + int ia[10] = {0}; + int ia1[10] = {1,2,3,4,5,6,7,8,9,10}; + int ia2[] = {1,2,3,4,5,6,7,8,9,10}; + struct Addr addr[10] = {}; + int a = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl1.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl1.cbs new file mode 100644 index 000000000000..c174dfb95401 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/array-decl1.cbs @@ -0,0 +1,18 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int array[] = {1,2,3,4,5}; + int length = sizeof(array)/sizeof(array[0]); + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/base-type-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/base-type-decl.cbs new file mode 100644 index 000000000000..1ec6c50c7198 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/base-type-decl.cbs @@ -0,0 +1,32 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int result = start; + + char x = 5; + short s = 6; + int d = 3; + float ff = 4.0; + double dd = 5.0; + int i = (int)dd; + + unsigned char ux = 5; + signed char sx = 5; + unsigned int ud = 5; + unsigned short us = 5; + unsigned long ul = 5; + long double ld = 3.4; + + int a = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl.cbs new file mode 100644 index 000000000000..11cd708f4c97 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl.cbs @@ -0,0 +1,28 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Addr +{ + int a; + char str[10]; +}; + +async int f(int start) { + const long myLong = 100000L; + const unsigned int myUnsignedInt = 10U; + const float myFloat = 3.14f; + const double myDouble = 3.14159; + const struct Addr addr = {1, "hello"}; + + int result = await read(2); + return result + 5 + start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/global-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/global-decl.cbs new file mode 100644 index 000000000000..16de6802e210 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/global-decl.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +int g = 5; + +async int f(int start) { + g = 6; + int result = await read(1); + return result + g; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl.cbs new file mode 100644 index 000000000000..af2710a6870c --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl.cbs @@ -0,0 +1,20 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + long myLong = 100000L; + unsigned int myUnsignedInt = 10U; + float myFloat = 3.14f; + double myDouble = 3.14159; + int result = await read(2); + return result + 5 + start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-decl.cbs new file mode 100644 index 000000000000..24ce1a202ac4 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-decl.cbs @@ -0,0 +1,21 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int result = start, b; + int c = 1, d; + int u = 3, v; + for (int i = 0; i < start; i++) { + int a = await read(i); + } + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl.cbs new file mode 100644 index 000000000000..52f44ffed53a --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Addr { + int a; +}; + +async int f() { + int a[5][3][2] = {0}; + struct Addr addr[2][3][4][5]; + int x = await read(2); + return 42; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/pointer-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/pointer-decl.cbs new file mode 100644 index 000000000000..97c831aacf4d --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/pointer-decl.cbs @@ -0,0 +1,27 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Addr { + int a; + char *addr; +}; + +async int f(int start) { + double dd = 5.0; + int i = (int)dd; + int* p = &i; + int** pp = &p; + + char *cp = (char *)&i; + int a = await read(1); + return a; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/static-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/static-decl.cbs new file mode 100644 index 000000000000..ceb2953bef64 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/static-decl.cbs @@ -0,0 +1,28 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Addr +{ + int a; + char str[10]; +}; + +async int f(int start) { + static long myLong = 100000L; + static unsigned int myUnsignedInt = 10U; + static float myFloat = 3.14f; + static double myDouble = 3.14159; + static struct Addr addr = {1, "hello"}; + + int result = await read(2); + return result + 5 + start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/string-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/string-decl.cbs new file mode 100644 index 000000000000..a5929f3005bd --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/string-decl.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + char str1[14] = "runoob"; + char str2[7] = {'R', 'U', 'N', 'O', 'O', 'B', '\0'}; + char str3[] = "RUNOOB"; + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/struct-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/struct-decl.cbs new file mode 100644 index 000000000000..acb011fe0758 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/struct-decl.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Addr { + int a; + char *addr; +}; + +async int f(int start) { + int result = start; + struct Addr addr = {.a=1,.addr = "hello"}; + char *tt = "hello"; + struct Addr addcp = {.a=1,.addr = tt}; + struct Addr *ptr = &addr; + int a = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/uninit-array-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/uninit-array-decl.cbs new file mode 100644 index 000000000000..49fbc0a68606 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/uninit-array-decl.cbs @@ -0,0 +1,29 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Addr { + int a; +}; + +async int f() { + int a = 1, b = 2; + int c[10]; + float f[10]; + struct Addr addr[10]; + int cc[10] = {0}; + int n[10]; + for (int i=0; i<10; i++) { + n[i] = i + 100; + } + int x = await read(2); + return 42; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer.cbs new file mode 100644 index 000000000000..5f8e30264e77 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer.cbs @@ -0,0 +1,27 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +const int MAX = 3; + +async int f(int start) { + int *nptr = NULL; + int var[] = {10, 100, 200}; + int i, *ptr; + + ptr = &var[MAX-1]; + for ( i = MAX; i > 0; i--) + { + ptr--; + } + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer.cbs new file mode 100644 index 000000000000..f7464514f0be --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int V; + int *ptr1; + int **ptr2; + V = 100; + ptr1 = &V; + ptr2 = &ptr1; + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/func-pointer.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/func-pointer.cbs new file mode 100644 index 000000000000..fc49cbe2649e --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Pointer/func-pointer.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +int max(int x, int y) +{ + return x > y ? x : y; +} + +async int f(int start) { + int (* p)(int, int) = & max; + int a = 1, b = 2, c = 3, d; + + d = p(p(a, b), c); + + int result = await read(1); + return d; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Struct/struct-init.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Struct/struct-init.cbs new file mode 100644 index 000000000000..66001bf0fc4a --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Struct/struct-init.cbs @@ -0,0 +1,27 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +struct Books +{ + char title[50]; + char author[50]; + char subject[100]; + int book_id; +}; + +async int f(int start) { + struct Books book1; + struct Books book = {"C language", "RUNOOB", "programming language", 123456}; + struct Books *pbook; + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Union/union-init.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Union/union-init.cbs new file mode 100644 index 000000000000..550f6464ea50 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/Union/union-init.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +union Data +{ + int i; + float f; + char str[20]; +}; + +async int f(int start) { + union Data data; + data.i = 10; + data.f = 220.5; + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/await-expr-if.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/await-expr-if.cbs new file mode 100644 index 000000000000..293469a138ff --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/await-expr-if.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int result = start; + if (start > 2 && start < 5) { + if (start > -5) { + int a1 = await read(3); + } + } else if (start < 0) { + int a2 = await read(3); + } else { + int a3 = result + 1; + } + result += start; + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-else-statement.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-else-statement.cbs new file mode 100644 index 000000000000..ef79904013fb --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-else-statement.cbs @@ -0,0 +1,20 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int x = 3; + int result; + if (x < 20) { + result = await read(1); + } else result = x; + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-nested-if-statement.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-nested-if-statement.cbs new file mode 100644 index 000000000000..d6b9112ac239 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-nested-if-statement.cbs @@ -0,0 +1,21 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int x = 3; + int result; + if (x < 20) { + if (x > 0) + result = await read(1); + } else result = x; + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-statement.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-statement.cbs new file mode 100644 index 000000000000..07d587bc6340 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/if-statement.cbs @@ -0,0 +1,20 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int x = 3; + int result; + if (x < 20) { + result = await read(1); + } + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-nested-switch-statement.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-nested-switch-statement.cbs new file mode 100644 index 000000000000..d599dba8d7e0 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-nested-switch-statement.cbs @@ -0,0 +1,38 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + char grade = 'B'; + int class = -1; + int result = await read(1); + switch (grade) { + case 'A': + result = 1; + switch (class) + { + case -1: + result = -1; + } + break; + case 'B': + case 'C': + result = 2; + break; + case 'D': + case 'F': + result = 3; + break; + default: + result = -1; + } + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-statement.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-statement.cbs new file mode 100644 index 000000000000..f9a9f457c4d7 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Judgement/switch-statement.cbs @@ -0,0 +1,32 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + char grade = 'B'; + int result = await read(1); + switch (grade) { + case 'A': + result = 1; + break; + case 'B': + case 'C': + result = 2; + break; + case 'D': + case 'F': + result = 3; + break; + default: + result = -1; + } + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Loop/do-while-loop.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/do-while-loop.cbs new file mode 100644 index 000000000000..80e5952ca22f --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/do-while-loop.cbs @@ -0,0 +1,21 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int i = 0; + do { + start = await read(i); + i++; + } while (i < 3); + int result = start; + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Loop/for-loop.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/for-loop.cbs new file mode 100644 index 000000000000..54d88e2615fc --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/for-loop.cbs @@ -0,0 +1,19 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + for (int i=0; i<3; i++) { + start = await read(i); + } + int result = start; + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Loop/loop-nested.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/loop-nested.cbs new file mode 100644 index 000000000000..e0aae2b7738c --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/loop-nested.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int i = 0; + do { + start = await read(i); + i++; + for (int j=0; j<3; j++) + start++; + } while (i < 3); + int result = start; + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Loop/while-loop.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/while-loop.cbs new file mode 100644 index 000000000000..322c01036288 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Loop/while-loop.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int i = 0; + while (i < 3) + { + start = await read(i); + i++; + } + int result = start; + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Operators/arithmetic-op.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/arithmetic-op.cbs new file mode 100644 index 000000000000..8ee43a7343ce --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/arithmetic-op.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int x = 3; + int y = 5; + int c; + c = x + y; + c = x - y; + c = x * y; + c = x / y; + c = x % y; + c = y ++; + c = y --; + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Operators/assign-op.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/assign-op.cbs new file mode 100644 index 000000000000..f30479f9865d --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/assign-op.cbs @@ -0,0 +1,30 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + unsigned int x = 3; + int z; + z = x; + z += x; + z -= x; + z *= x; + z /= x; + z %= x; + z <<= x; + z >>= x; + z &= x; + z ^= x; + z |= x; + int a = await read(1); + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Operators/bit-op.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/bit-op.cbs new file mode 100644 index 000000000000..eac7df0899a7 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/bit-op.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + unsigned int x = 3; + unsigned int y = 4; + int z; + z = x & y; + z = x | y; + z = x ^ y; + z = ~y; + z = x << y; + z = x >> y; + int a = await read(1); + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Operators/logocal-op.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/logocal-op.cbs new file mode 100644 index 000000000000..190e379d3518 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/logocal-op.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int x = 3; + int y = 4; + int z; + z = x && y; + z = x || y; + z = !(x && y); + int a = await read(1); + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Operators/other-op.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/other-op.cbs new file mode 100644 index 000000000000..5604c376946e --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/other-op.cbs @@ -0,0 +1,22 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int x = 3; + int z; + int *ptr; + ptr = &x; + z = (x == 3) ? 20 : 30; + int a = await read(1); + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/Other/Operators/relational-op.cbs b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/relational-op.cbs new file mode 100644 index 000000000000..c83b0e84109b --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/Other/Operators/relational-op.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +async int f(int start) { + int x = 3; + int y = 4; + int z; + z = x == y; + z = x != y; + z = x > y; + z = x < y; + z = x >= y; + z = x <= y; + int a = await read(1); + int result = await read(1); + return result; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-const-int.cbs b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-const-int.cbs new file mode 100644 index 000000000000..393afd0ba954 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-const-int.cbs @@ -0,0 +1,25 @@ +// RUN: %clang %s -o %t.output +// RUN: %t.output +// expected-no-diagnostics + +#include "../../async-func-read.hbs" + +async const int f(int start) { + int a = await read(1); + int b = 2; + + if(a == 1) { + if (b == 3) + return -1; + return 2; + } + + + return -1; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-type.cbs b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-type.cbs new file mode 100644 index 000000000000..f17fa112e158 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-type.cbs @@ -0,0 +1,92 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../async-func-read.hbs" + +struct _Futuretest1 { + int a; + int res; + int __future_state; +}; +typedef struct _Futuretest1 __Futuretest1; + +struct PollResult struct _Futuretest1::poll(__Futuretest1 *this) { + struct PollResult poll_result; + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->res = this->a; + this->__future_state = -1; + return struct PollResult::completed(this->res); +} +void struct _Futuretest1::free(__Futuretest1 *this) {} + +struct __Vtable_int _Futuretest1_vtable = { + .poll = struct _Futuretest1::poll, + .free = struct _Futuretest1::free +}; + +struct __FatPointer_int test1(int a) { + struct _Futuretest1* ptr = malloc(sizeof(struct _Futuretest1)); + ptr->a = a; + ptr->__future_state = 0; + return (struct __FatPointer_int) { .data = ptr, .vtable = &_Futuretest1_vtable}; +} + +struct _Futuretest2 { + int a; + int res; + int __future_state; +}; +typedef struct _Futuretest2 __Futuretest2; + +struct PollResult struct _Futuretest2::poll(__Futuretest2 *this) { + struct PollResult poll_result; + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->res = this->a; + this->__future_state = -1; + return struct PollResult::completed(this->res); +} + +void struct _Futuretest2::free(__Futuretest2 *this) {} + +struct __Vtable_int _Futuretest2_vtable = { + .poll = struct _Futuretest2::poll, + .free = struct _Futuretest2::free +}; + +struct __FatPointer_int test2(int a) { + struct _Futuretest2* ptr = malloc(sizeof(struct _Futuretest2)); + ptr->a = a; + ptr->__future_state = 0; + return (struct __FatPointer_int) { .data = ptr, .vtable = &_Futuretest2_vtable}; +} + +async int f(int start) { + int a = await read(1); + int b = 2; + + if(a == 1) { + b = await test1(2); + if (b == 3) + return 1; + else b = await test2(3); + return 3; + } + + return -1; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} + diff --git a/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-void.cbs b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-void.cbs new file mode 100644 index 000000000000..e4f351e958ae --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/async-func-return-void.cbs @@ -0,0 +1,18 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../async-func-read.hbs" + +async void f(int start) { + int result = start; + for (int i = 0; i < start; i++) { + int a = await read(1); + } +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type.cbs b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type.cbs new file mode 100644 index 000000000000..0ac2af65146a --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type.cbs @@ -0,0 +1,17 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../async-func-read.hbs" + +async int f(int start) { + int r1 = await read(1); + int result = await read(1); + return r1 *result + start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type1.cbs b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type1.cbs new file mode 100644 index 000000000000..80ae70d825c6 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/ReturnStmt/await-expr-return-type1.cbs @@ -0,0 +1,20 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../async-func-read.hbs" + +async int f(int start) { + int result = await read(1); + return start * result; +} + +async int g() { + int result = await f(2); + return result + 5; +} + +int main() { + g(); + return 0; +} diff --git a/clang/test/BSC/Coroutine/async-func-read-opposite.hbs b/clang/test/BSC/Coroutine/async-func-read-opposite.hbs new file mode 100644 index 000000000000..f5a9f1bbfc88 --- /dev/null +++ b/clang/test/BSC/Coroutine/async-func-read-opposite.hbs @@ -0,0 +1,51 @@ +#ifndef READ_H +#define READ_H + +#include "future.hbs" + +typedef struct PollResult (*pollType)(void*); +typedef void (*freeType)(void*); +struct __Vtable_int { + struct PollResult (*poll)(void*); + void (*free)(void*); +}; + +struct __FatPointer_int { + void* data; + struct __Vtable_int* vtable; +}; + +struct _Futureread { + int a; + int res; + int __future_state; +}; +typedef struct _Futureread __Futureread; + +struct PollResult struct _Futureread::poll(__Futureread *this) { + struct PollResult poll_result; + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->res = this->a; + this->__future_state = -1; + return struct PollResult::completed(this->res); +} + +void struct _Futureread::free(struct _Futureread *this) {} + +struct __Vtable_int _Futureread_vtable = { + .poll = (pollType)struct _Futureread::poll, + .free = (freeType)struct _Futureread::free +}; + +struct __FatPointer_int read(int a) { + struct _Futureread* ptr; + ptr->a = a; + ptr->__future_state = 0; + return (struct __FatPointer_int) { .data = ptr, .vtable = &_Futureread_vtable}; +} + +#endif \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/async-func-read.hbs b/clang/test/BSC/Coroutine/async-func-read.hbs new file mode 100644 index 000000000000..efba00da21e9 --- /dev/null +++ b/clang/test/BSC/Coroutine/async-func-read.hbs @@ -0,0 +1,50 @@ +#ifndef READ_H +#define READ_H + +#include "stdlib.h" // TODO: need change to implicit usage +#include "future.hbs" + +struct _Futureread { + int a; + int res; + int __future_state; +}; +typedef struct _Futureread __Futureread; + +struct PollResult struct _Futureread::poll(__Futureread *this) { + struct PollResult poll_result; + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->res = this->a; + this->__future_state = -1; + return struct PollResult::completed(this->res); +} + +struct __Vtable_int { + struct PollResult (*poll)(void*); + void (*free)(void*); +}; + +struct __FatPointer_int { + void* data; + struct __Vtable_int* vtable; +}; + +void struct _Futureread::free(struct _Futureread *this) {} + +struct __Vtable_int _Futureread_vtable = { + .poll = struct _Futureread::poll, + .free = struct _Futureread::free +}; + +struct __FatPointer_int read(int a) { + struct _Futureread* ptr = malloc(sizeof(struct _Futureread)); + ptr->a = a; + ptr->__future_state = 0; + return (struct __FatPointer_int) { .data = ptr, .vtable = &_Futureread_vtable}; +} + +#endif \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/future.hbs b/clang/test/BSC/Coroutine/future.hbs new file mode 100644 index 000000000000..fd0f8c883334 --- /dev/null +++ b/clang/test/BSC/Coroutine/future.hbs @@ -0,0 +1,35 @@ +#ifndef _BSCFUTURE_HBS +#define _BSCFUTURE_HBS 1 + +struct PollResult { + _Bool isPending; + T res; +}; + +T struct PollResult::is_pending(struct PollResult* this) { + return this->isPending; +} + +struct PollResult struct PollResult::pending() { + struct PollResult this; + this.isPending = 1; + return this; +} + +_Bool struct PollResult::is_completed(struct PollResult *this, T *out) { + out = &this->res; + return !this->isPending; +} + +struct PollResult struct PollResult::completed(T result) { + struct PollResult this; + this.isPending = 0; + this.res = result; + return this; +} + +// trait Future { +// struct PollResult poll(This* this); +// void free(This* this); +// }; +#endif /* future.hbs */ \ No newline at end of file -- Gitee From 28f3dff050a9b201a7dcb4b4030930c6f6945610 Mon Sep 17 00:00:00 2001 From: yangdian Date: Mon, 3 Jul 2023 16:12:47 +0800 Subject: [PATCH 6/8] [BSC] Coroutine: bugfix --- .../clang/Basic/DiagnosticSemaKinds.td | 6 +- clang/lib/AST/ItaniumMangle.cpp | 1 + clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Sema/SemaBSCCoroutine.cpp | 116 ++++++++++-------- .../RecursiveCall/recursive-async-call.cbs | 16 +++ .../Coroutine/Other/await-non-async-call.cbs | 17 +++ .../Other/invalid-async-function.cbs | 13 ++ .../Other/invalid-await-expression.cbs | 13 ++ .../Other/missing-await-expression.cbs | 11 ++ 9 files changed, 145 insertions(+), 50 deletions(-) create mode 100644 clang/test/BSC/Coroutine/Other/RecursiveCall/recursive-async-call.cbs create mode 100644 clang/test/BSC/Coroutine/Other/await-non-async-call.cbs create mode 100644 clang/test/BSC/Coroutine/Other/invalid-async-function.cbs create mode 100644 clang/test/BSC/Coroutine/Other/invalid-await-expression.cbs create mode 100644 clang/test/BSC/Coroutine/Other/missing-await-expression.cbs diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 294909abad29..9cfd1de6f017 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -113,9 +113,13 @@ def err_expr_not_string_literal : Error<"expression is not a string literal">; def err_await_invalid_scope : Error< "await expression is not allowed to appear in %0">; def err_not_a_async_call : Error< - "the await expression's external function declaration must be modified by async">; + "the await expression's external function declaration must be modified by async or return 'Future' type">; def err_function_not_found : Error < "'%0' was not found, you need to include %1 before using the 'async' keyword">; +def err_await_expression_not_found: Error < + "await expression was not found in async function">; +def err_invalid_async_function : Error < + "function which returns 'Future' type should not be modified by 'async'">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 91f41778ee68..dae0917b6347 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4247,6 +4247,7 @@ recurse: case Expr::OMPArrayShapingExprClass: case Expr::OMPIteratorExprClass: case Expr::CXXInheritedCtorInitExprClass: + case Expr::AwaitExprClass: llvm_unreachable("unexpected statement kind"); case Expr::ConstantExprClass: diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f2edd1891652..601d8f2293b7 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2128,7 +2128,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, &LateParsedAttrs); FunctionDecl *FD = dyn_cast_or_null(TheDecl); - if (getLangOpts().BSC && FD && FD->isAsyncSpecified()) { + if (getLangOpts().BSC && FD) { SmallVector decls = Actions.ActOnAsyncFunctionDeclaration(FD); return Actions.BuildDeclaratorGroup(decls); diff --git a/clang/lib/Sema/SemaBSCCoroutine.cpp b/clang/lib/Sema/SemaBSCCoroutine.cpp index 832271dd689d..19a3cf9578e3 100644 --- a/clang/lib/Sema/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/SemaBSCCoroutine.cpp @@ -365,7 +365,7 @@ static RecordDecl *buildFutureRecordDecl( for (unsigned I = 0; I != Args.size(); ++I) { auto *AE = cast(Args[I])->getSubExpr(); if (!IsFutureType(AE->getType())) { - RecordDecl *FatPointerStruct; + RecordDecl *FatPointerStruct = nullptr; const std::string FatPointerName = "__FatPointer_" + GetPrefix(AE->getType()); DeclContext::lookup_result FatPointerDecls = @@ -381,9 +381,10 @@ static RecordDecl *buildFutureRecordDecl( break; } } - } else { - abort(); } + + assert(FatPointerStruct != nullptr); + LocalVarList.push_back(std::make_pair( &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), S.Context.getRecordType(FatPointerStruct))); @@ -443,9 +444,6 @@ static RecordDecl *generateVoidStruct(Sema &S) { VoidRD->startDefinition(); VoidRD->completeDefinition(); S.PushOnScopeChains(VoidRD, S.getCurScope(), true); - } else { - // should not reach here. todo: change to assert - abort(); } return VoidRD; } @@ -490,9 +488,6 @@ generateVtableAndFatPointerStruct(Sema &S, QualType T, VtableStruct->completeDefinition(); VtableStruct->addAttr(WeakAttr::CreateImplicit(S.Context)); S.PushOnScopeChains(VtableStruct, S.getCurScope(), true); - } else { - // should not reach here. todo: change to assert - abort(); } RecordDecl *FatPointerStruct = nullptr; std::string FatPointerName = "__FatPointer_" + GetPrefix(ReturnTy); @@ -526,9 +521,6 @@ generateVtableAndFatPointerStruct(Sema &S, QualType T, FatPointerStruct->completeDefinition(); FatPointerStruct->addAttr(WeakAttr::CreateImplicit(S.Context)); S.PushOnScopeChains(FatPointerStruct, S.getCurScope(), true); - } else { - // should not reach here. todo: change to assert - abort(); } return std::make_tuple(std::make_pair(VtableStruct, IsVtableExisted), std::make_pair(FatPointerStruct, IsFatPointerExisted)); @@ -631,9 +623,8 @@ FunctionDecl *buildFutureInitFunctionDeclaraion(Sema &S, RecordDecl *RD, NewFD->setParams(ParmVarDecls); NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); S.PushOnScopeChains(NewFD, S.getCurScope(), true); - } else { - abort(); } + S.PushFunctionScope(); S.PushDeclContext(S.getCurScope(), NewFD); @@ -2445,53 +2436,52 @@ ExprResult Sema::BuildAwaitExpr(SourceLocation AwaitLoc, Expr *E) { return Res; } - Expr *InnerE = E; - QualType AwaitReturnTy = InnerE->getType(); - bool IsCall = isa(InnerE); + QualType AwaitReturnTy = E->getType(); + bool IsCall = isa(E); if (IsCall) { - Decl *AwaitDecl = (dyn_cast(InnerE))->getCalleeDecl(); + Decl *AwaitDecl = (dyn_cast(E))->getCalleeDecl(); FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); if (!FDecl) { return ExprError(); } if (!FDecl->isAsyncSpecified() && !IsFutureType(AwaitReturnTy)) { - // TODO: modify error message - Diag(InnerE->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(InnerE)); + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); return ExprError(); } } else { if (!IsFutureType(AwaitReturnTy)) { - Diag(InnerE->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(InnerE)); + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); return ExprError(); } } + // TODO: After we use future in stdlib, get template argument directly. if (IsFutureType(AwaitReturnTy)) { - const RecordType *FPRD = + const RecordType *FatPointerType = dyn_cast(AwaitReturnTy.getDesugaredType(Context)); - RecordDecl *RD = FPRD->getDecl(); - for (RecordDecl::field_iterator FieldIt = RD->field_begin(), - Field_end = RD->field_end(); + RecordDecl *FatPointer = FatPointerType->getDecl(); + for (RecordDecl::field_iterator FieldIt = FatPointer->field_begin(), + Field_end = FatPointer->field_end(); FieldIt != Field_end; ++FieldIt) { if (FieldIt->getDeclName().getAsString() == "vtable") { - const RecordType *VTRD = dyn_cast( + const RecordType *VtableType = dyn_cast( FieldIt->getType()->getPointeeType().getDesugaredType(Context)); - RecordDecl *NewRD = VTRD->getDecl(); - for (RecordDecl::field_iterator FieldIt = NewRD->field_begin(), - Field_end = NewRD->field_end(); + RecordDecl *Vtable = VtableType->getDecl(); + for (RecordDecl::field_iterator FieldIt = Vtable->field_begin(), + Field_end = Vtable->field_end(); FieldIt != Field_end; ++FieldIt) { if (FieldIt->getDeclName().getAsString() == "poll") { - const RecordType *VTRD1 = dyn_cast( + const RecordType *PollResultType = dyn_cast( dyn_cast( FieldIt->getType()->getPointeeType().getDesugaredType( Context)) ->getReturnType() .getDesugaredType(Context)); - RecordDecl *NewRD1 = VTRD1->getDecl(); - for (RecordDecl::field_iterator FieldIt = NewRD1->field_begin(), - Field_end = NewRD1->field_end(); + RecordDecl *PollResult = PollResultType->getDecl(); + for (RecordDecl::field_iterator FieldIt = PollResult->field_begin(), + Field_end = PollResult->field_end(); FieldIt != Field_end; ++FieldIt) { if (FieldIt->getDeclName().getAsString() == "res") { AwaitReturnTy = FieldIt->getType(); @@ -2504,7 +2494,7 @@ ExprResult Sema::BuildAwaitExpr(SourceLocation AwaitLoc, Expr *E) { } // build AwaitExpr - AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, InnerE, AwaitReturnTy); + AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, E, AwaitReturnTy); return Res; } @@ -2551,16 +2541,32 @@ void Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD, SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { SmallVector decls; - if (IsFutureType(FD->getReturnType())) { + AwaitExprFinder finder = AwaitExprFinder(); + finder.Visit(FD->getBody()); + + // Report if await expression appear in non-async functions. + if (!FD->isAsyncSpecified()) { + if (finder.GetAwaitExprNum() != 0) { + Diag(FD->getBeginLoc(), diag::err_await_invalid_scope) << "non-async function."; + } decls.push_back(FD); return decls; } - AwaitExprFinder finder = AwaitExprFinder(); - finder.Visit(FD->getBody()); + // For leaf nodes, should not be modified async. + if (IsFutureType(FD->getReturnType())) { + Diag(FD->getBeginLoc(), diag::err_invalid_async_function); + return decls; + } + + // Async functions should have await expression. if (finder.GetAwaitExprNum() == 0) { - // TODO: return type check. - decls.push_back(FD); + Diag(FD->getBeginLoc(), diag::err_await_expression_not_found); + return decls; + } + + // Do not process desugar if we already met errors. + if (Diags.hasErrorOccurred()) { return decls; } @@ -2589,34 +2595,48 @@ SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { decls.push_back(std::get<0>(std::get<0>(NewRDs))); if (!std::get<1>(std::get<1>(NewRDs))) decls.push_back(std::get<0>(std::get<1>(NewRDs))); - - FunctionDecl *FutureInitDef = buildFutureInitFunctionDefinition( + + // Handle definition first. + (void)buildFutureInitFunctionDefinition( *this, FD, std::get<0>(std::get<1>(NewRDs))); const int FutureStateNumber = finder.GetAwaitExprNum() + 1; + RecordDecl *RD = buildFutureRecordDecl(*this, FD, finder.GetAwaitExpr(), finder.GetLocalVarList()); + if (!RD) { + return decls; + } + decls.push_back(RD); BSCMethodDecl *PollDecl = buildPollFunction(*this, RD, PollResultRD, FD, std::get<0>(std::get<1>(NewRDs)), FutureStateNumber); + if (!PollDecl) { + return decls; + } + decls.push_back(PollDecl); BSCMethodDecl *FreeDecl = buildFreeFunction(*this, RD, FD); if (!FreeDecl) { return decls; } + decls.push_back(FreeDecl); VarDecl *VtableDecl = buildVtableInitDecl(*this, FD, std::get<0>(std::get<0>(NewRDs)), PollResultRD, PollDecl, FreeDecl); + if (!VtableDecl) { + return decls; + } + decls.push_back(VtableDecl); + FunctionDecl *FutureInit = buildFutureInitFunctionDeclaraion( *this, RD, FD, std::get<0>(std::get<1>(NewRDs)), VtableDecl); - - decls.push_back(RD); - decls.push_back(PollDecl); - decls.push_back(FreeDecl); - decls.push_back(VtableDecl); + if (!FutureInit) { + return decls; + } decls.push_back(FutureInit); return decls; } \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/RecursiveCall/recursive-async-call.cbs b/clang/test/BSC/Coroutine/Other/RecursiveCall/recursive-async-call.cbs new file mode 100644 index 000000000000..86f8f3f5a70c --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/RecursiveCall/recursive-async-call.cbs @@ -0,0 +1,16 @@ +// RUN: %clang %s -o %test.output +// since it's a recursive call, we will get a segv if we run it. + +#include "../../async-func-read.hbs" + +async int f() { + int a = await f(); + return a; +} + +int main() { + struct __FatPointer_int this = f(); + this.vtable->poll(this.data); + this.vtable->free(this.data); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/await-non-async-call.cbs b/clang/test/BSC/Coroutine/Other/await-non-async-call.cbs new file mode 100644 index 000000000000..bcd827557975 --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/await-non-async-call.cbs @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +int p(int i) { + return i; +} + +async int f() { + int a = await p(1); // expected-error {{the await expression's external function declaration must be modified by async or return 'Future' type}} + int b = await read(1); + return b; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/invalid-async-function.cbs b/clang/test/BSC/Coroutine/Other/invalid-async-function.cbs new file mode 100644 index 000000000000..0d9238e5d3b1 --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/invalid-async-function.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +async struct __FatPointer_int f1() { // expected-error {{function which returns 'Future' type should not be modified by 'async'}} + struct __FatPointer_int f; + int a = await read(1); + return f; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/invalid-await-expression.cbs b/clang/test/BSC/Coroutine/Other/invalid-await-expression.cbs new file mode 100644 index 000000000000..c83d4c12506a --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/invalid-await-expression.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +struct __FatPointer_int f() { // expected-error {{await expression is not allowed to appear in non-async function.}} + struct __FatPointer_int f; + int a = await read(1); + return f; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Coroutine/Other/missing-await-expression.cbs b/clang/test/BSC/Coroutine/Other/missing-await-expression.cbs new file mode 100644 index 000000000000..8afc6492f0f6 --- /dev/null +++ b/clang/test/BSC/Coroutine/Other/missing-await-expression.cbs @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +async int f() { // expected-error {{await expression was not found in async function}} + return 0; +} + +int main() { + return 0; +} \ No newline at end of file -- Gitee From de11a67039ca6dd09cb8bafcd7dc04899073ac12 Mon Sep 17 00:00:00 2001 From: jeanniely Date: Wed, 5 Jul 2023 21:56:11 +0800 Subject: [PATCH 7/8] [BSC] fix async func bug --- clang/lib/Sema/SemaBSCCoroutine.cpp | 732 ++++++++++-------- .../AwaitExpr/await-expr-of-func-params.cbs | 28 + .../AwaitExpr/await-expr-of-return.cbs | 26 + .../AwaitExpr/await-expr-single-judgement.cbs | 6 +- .../DeclStmt/MultiDecl/extern-decl.cbs | 23 + 5 files changed, 504 insertions(+), 311 deletions(-) create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-func-params.cbs create mode 100644 clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-return.cbs create mode 100644 clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/extern-decl.cbs diff --git a/clang/lib/Sema/SemaBSCCoroutine.cpp b/clang/lib/Sema/SemaBSCCoroutine.cpp index 19a3cf9578e3..e4166bcbda75 100644 --- a/clang/lib/Sema/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/SemaBSCCoroutine.cpp @@ -11,6 +11,10 @@ // //===----------------------------------------------------------------------===// +#include +#include +#include + #include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" @@ -30,9 +34,6 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" -#include -#include -#include using namespace clang; using namespace sema; @@ -41,7 +42,6 @@ static RecordDecl *buildAsyncDataRecord(ASTContext &C, StringRef Name, SourceLocation StartLoc, SourceLocation EndLoc, RecordDecl::TagKind TK) { - RecordDecl *NewDecl; NewDecl = RecordDecl::Create(C, TK, C.getTranslationUnitDecl(), StartLoc, EndLoc, &C.Idents.get(Name)); @@ -68,12 +68,14 @@ static FunctionDecl *buildAsyncFuncDecl(ASTContext &C, DeclContext *DC, return NewDecl; } -static BSCMethodDecl * -buildAsyncBSCMethodDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation NLoc, DeclarationName N, QualType T, - TypeSourceInfo *TInfo, StorageClass SC) { +static BSCMethodDecl *buildAsyncBSCMethodDecl(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation NLoc, + DeclarationName N, QualType T, + TypeSourceInfo *TInfo, + StorageClass SC) { BSCMethodDecl *NewDecl = - BSCMethodDecl::Create( // TODO: inline should be passed. + BSCMethodDecl::Create( // TODO: inline should be passed. C, DC, StartLoc, DeclarationNameInfo(N, NLoc), T, TInfo, SC, false, false, ConstexprSpecKind::Unspecified, NLoc); if (auto RD = dyn_cast_or_null(DC)) { @@ -90,7 +92,7 @@ class AwaitExprFinder : public StmtVisitor { std::vector Args; std::vector> LocalVarList; -public: + public: void VisitAwaitExpr(AwaitExpr *E) { Visit(E->getSubExpr()); Args.push_back(E); @@ -103,11 +105,14 @@ public: if (auto DeclS = dyn_cast_or_null(C)) { for (const auto &DI : DeclS->decls()) { if (auto VD = dyn_cast_or_null(DI)) { + if (VD->isExternallyVisible()) continue; + QualType QT = VD->getType(); if (QT.isConstQualified()) { QT.removeLocalConst(); VD->setType(QT); } + LocalVarList.push_back(std::make_pair( VD->getDeclName(), VD->getType())); } @@ -128,11 +133,9 @@ public: }; bool HasAwaitExpr(Stmt *S) { - if (S == nullptr) - return false; + if (S == nullptr) return false; - if (isa(S)) - return true; + if (isa(S)) return true; for (auto *C : S->children()) { if (HasAwaitExpr(C)) { @@ -148,66 +151,63 @@ class IllegalAEFinder : public StmtVisitor { Sema &SemaRef; bool HasIllegalAwait; -public: - IllegalAEFinder(Sema &SemaRef) - : SemaRef(SemaRef) { - HasIllegalAwait = false; - } - + public: + IllegalAEFinder(Sema &SemaRef) : SemaRef(SemaRef) { HasIllegalAwait = false; } + bool CheckCondHasAwaitExpr(Stmt *S) { Expr *condE = nullptr; bool CHasIllegalAwait = false; std::string ArgString; switch (S->getStmtClass()) { - case Stmt::IfStmtClass: { - ArgString = "condition statement of if statement"; - condE = cast(S)->getCond(); - CHasIllegalAwait = HasAwaitExpr(cast(condE)); - break; - } - - case Stmt::WhileStmtClass: { - ArgString = "condition statement of while loop"; - condE = cast(S)->getCond(); - CHasIllegalAwait = HasAwaitExpr(cast(condE)); - break; - } - - case Stmt::DoStmtClass: { - ArgString = "condition statement of do/while loop"; - condE = cast(S)->getCond(); - CHasIllegalAwait = HasAwaitExpr(cast(condE)); - break; - } + case Stmt::IfStmtClass: { + ArgString = "condition statement of if statement"; + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; + } - case Stmt::ForStmtClass: { - ArgString = "condition statement of for loop"; - Stmt *Init = cast(S)->getInit(); - if (Init != nullptr) - CHasIllegalAwait = HasAwaitExpr(Init); + case Stmt::WhileStmtClass: { + ArgString = "condition statement of while loop"; + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; + } - if (!CHasIllegalAwait) { - condE = cast(S)->getCond(); + case Stmt::DoStmtClass: { + ArgString = "condition statement of do/while loop"; + condE = cast(S)->getCond(); CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; } - break; - } + case Stmt::ForStmtClass: { + ArgString = "condition statement of for loop"; + Stmt *Init = cast(S)->getInit(); + if (Init != nullptr) CHasIllegalAwait = HasAwaitExpr(Init); - case Stmt::SwitchStmtClass: { - ArgString = "condition statement of switch statement"; - condE = cast(S)->getCond(); - CHasIllegalAwait = HasAwaitExpr(cast(condE)); - break; - } + if (!CHasIllegalAwait) { + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + } - default: - break; + break; + } + + case Stmt::SwitchStmtClass: { + ArgString = "condition statement of switch statement"; + condE = cast(S)->getCond(); + CHasIllegalAwait = HasAwaitExpr(cast(condE)); + break; + } + + default: + break; } if (CHasIllegalAwait) { - SemaRef.Diag(S->getBeginLoc(), diag::err_await_invalid_scope) << ArgString; + SemaRef.Diag(S->getBeginLoc(), diag::err_await_invalid_scope) + << ArgString; } if (CHasIllegalAwait && !HasIllegalAwait) @@ -223,17 +223,34 @@ public: if (isa(S)) { ArgString = "binary operator expression"; BinaryOperator *BO = cast(S); - switch (BO->getOpcode()) - { - case BO_Comma: - case BO_Assign: - return false; - - default: - break; + switch (BO->getOpcode()) { + case BO_Comma: + case BO_Assign: + return false; + + default: + break; } - } else if (isa(S)) + } else if (isa(S)) { ArgString = "condition operator expression"; + } else if (isa(S)) { + ArgString = "function parameters"; + CallExpr *CE = cast(S); + int AwaitNum = 0; + int CallNum = 0; + int Count = CE->getNumArgs(); + for (int i = 0; i < Count; i++) { + CheckAwaitInFuncParams(CE->getArg(i), AwaitNum, CallNum); + } + + if (AwaitNum >= 2 || (AwaitNum >= 1 && CallNum >= 1)) { + SemaRef.Diag(S->getBeginLoc(), diag::err_await_invalid_scope) + << ArgString; + + if (!HasIllegalAwait) HasIllegalAwait = true; + } + return IsContinue; + } bool CHasIllegalAwait = HasAwaitExpr(S); @@ -241,7 +258,8 @@ public: HasIllegalAwait = CHasIllegalAwait; if (CHasIllegalAwait) { - SemaRef.Diag(S->getBeginLoc(), diag::err_await_invalid_scope) << ArgString; + SemaRef.Diag(S->getBeginLoc(), diag::err_await_invalid_scope) + << ArgString; } return IsContinue; } @@ -252,10 +270,10 @@ public: if (isa(C) || isa(C) || isa(C) || isa(C) || isa(C)) { CheckCondHasAwaitExpr(C); - } else if (isa(C) || isa(C)) { + } else if (isa(C) || isa(C) || + isa(C)) { bool IsContinue = CheckExprHasAwaitExpr(C); - if (IsContinue) - continue; + if (IsContinue) continue; } Visit(C); @@ -263,17 +281,35 @@ public: } } - bool hasIllegalAwaitExpr() { - return HasIllegalAwait; + void CheckAwaitInFuncParams(Stmt *S, int &AwaitNum, int &CallNum) { + if (isa(S)) { + AwaitNum++; + return; + } + + if (isa(S)) { + CallNum++; + return; + } + + for (auto *C : S->children()) { + if (C) { + // In function parameters, if the number of await expr is greater than + // or equal 2, or the function parameters have await expr and call expr, + // then report error. + if (AwaitNum >= 2 || (AwaitNum >= 1 && CallNum >= 1)) return; + Visit(C); + } + } } + + bool hasIllegalAwaitExpr() { return HasIllegalAwait; } }; bool HasReturnStmt(Stmt *S) { - if (S == nullptr) - return false; + if (S == nullptr) return false; - if (isa(S)) - return true; + if (isa(S)) return true; for (auto *C : S->children()) { if (HasReturnStmt(C)) { @@ -339,14 +375,13 @@ static QualType lookupPollResultType(Sema &S, SourceLocation SLoc, QualType T) { QualType PollResultRecord = S.CheckTemplateIdType(TemplateName(CTD), SourceLocation(), Args); - if (PollResultRecord.isNull()) - return QualType(); + if (PollResultRecord.isNull()) return QualType(); if (S.RequireCompleteType(SLoc, PollResultRecord, diag::err_coroutine_type_missing_specialization)) return QualType(); return PollResultRecord; } -} // namespace +} // namespace // build struct Future for async function static RecordDecl *buildFutureRecordDecl( @@ -694,7 +729,6 @@ FunctionDecl *buildFutureInitFunctionDeclaraion(Sema &S, RecordDecl *RD, pi = NewFD->param_begin(); for (RecordDecl::field_iterator FieldIt = RD->field_begin(); pi != NewFD->param_end(); ++pi, ++FieldIt) { - Expr *LHSExpr = S.BuildMemberExpr( DataRef, true, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), *FieldIt, @@ -895,11 +929,12 @@ Stmt *ProcessAwaitExprStatus(Sema &S, int AwaitCount, RecordDecl *RD, Expr *ICE, if (IsCompletedFD) { Expr *IsCompletedFDRef = S.BuildDeclRefExpr( IsCompletedFD, IsCompletedFD->getType(), VK_LValue, SourceLocation()); - IsCompletedFDRef = S.ImpCastExprToType(IsCompletedFDRef, - S.Context.getPointerType( - IsCompletedFDRef->getType()), - CK_FunctionToPointerDecay) - .get(); + IsCompletedFDRef = + S.ImpCastExprToType( + IsCompletedFDRef, + S.Context.getPointerType(IsCompletedFDRef->getType()), + CK_FunctionToPointerDecay) + .get(); if (PollResultRD) { Expr *PollResultVarRef = S.BuildDeclRefExpr( @@ -968,7 +1003,7 @@ class TransformToReturnVoid : public TreeTransform { typedef TreeTransform BaseTransform; QualType ReturnTy = QualType(); -public: + public: TransformToReturnVoid(Sema &SemaRef) : BaseTransform(SemaRef) {} // make sure redo semantic analysis @@ -1044,7 +1079,7 @@ public: return RS; } }; -} // namespace +} // namespace namespace { class TransformToAP : public TreeTransform { @@ -1058,7 +1093,7 @@ class TransformToAP : public TreeTransform { llvm::DenseMap ArrayPointersMap; llvm::DenseMap ArrayAssignedPointerMap; -public: + public: TransformToAP(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, BSCMethodDecl *FD) : BaseTransform(SemaRef), PDRE(PDRE), FutureRD(FutureRD), FD(FD) { @@ -1108,6 +1143,8 @@ public: Expr *RE = nullptr; QualType QT = VD->getType(); + if (VD->isExternallyVisible()) return S; + RecordDecl::field_iterator LField, FieldIt; for (FieldIt = FutureRD->field_begin(); FieldIt != FutureRD->field_end(); ++FieldIt) { @@ -1128,10 +1165,8 @@ public: .getAs(); } - if (QT->isArrayType() || - QT->isRecordType() || + if (QT->isArrayType() || QT->isRecordType() || QT->isRValueReferenceType()) { - std::string ArgName = VD->getName().str(); VarDecl *ArgVDNew = VarDecl::Create( SemaRef.Context, FD, SourceLocation(), SourceLocation(), @@ -1140,21 +1175,24 @@ public: Expr *CInit = nullptr; if (Init != nullptr) { - CInit = BaseTransform::TransformExpr(Init).get(); + CInit = BaseTransform::TransformExpr(Init).get(); } else { if (VD->getType()->isArrayType()) { - auto *CAT = cast(VD->getType()->castAsArrayTypeUnsafe()); - InitListExpr *ILE = new (SemaRef.Context) - InitListExpr(SemaRef.Context, SourceLocation(), None, SourceLocation()); + auto *CAT = cast( + VD->getType()->castAsArrayTypeUnsafe()); + InitListExpr *ILE = new (SemaRef.Context) InitListExpr( + SemaRef.Context, SourceLocation(), None, SourceLocation()); ILE->setType(VD->getType()); - Expr *Filler = new (SemaRef.Context) ImplicitValueInitExpr(CAT->getElementType()); + Expr *Filler = new (SemaRef.Context) + ImplicitValueInitExpr(CAT->getElementType()); ILE->setArrayFiller(Filler); Init = CInit = ILE; } else { - Expr *CE = new (SemaRef.Context) ImplicitValueInitExpr(LE->getType()); + Expr *CE = + new (SemaRef.Context) ImplicitValueInitExpr(LE->getType()); Init = CInit = CE; } - } + } SemaRef.AddInitializerToDecl(ArgVDNew, CInit, /*DirectInit=*/true); DeclStmt *DSNew = @@ -1175,64 +1213,80 @@ public: CIndex++; if (QT->isArrayType()) { - int Elements = 1; QualType SubQT = QT; - while (const ConstantArrayType *AT = SemaRef.Context.getAsConstantArrayType(SubQT)) { + while (const ConstantArrayType *AT = + SemaRef.Context.getAsConstantArrayType(SubQT)) { Elements *= AT->getSize().getZExtValue(); - if (AT->getSize() == 0) - return true; + if (AT->getSize() == 0) return true; SubQT = AT->getElementType(); } QualType Pty = SemaRef.Context.getPointerType(SubQT); - Expr *AssignedRVExpr = SemaRef.BuildDeclRefExpr(ArgVDNew, ArgVDNew->getType(), VK_LValue, - SourceLocation()); - AssignedRVExpr = SemaRef.ImpCastExprToType(AssignedRVExpr, SemaRef.Context.getArrayDecayedType(QT), - CK_ArrayToPointerDecay).get(); - TypeSourceInfo *AssignedType = SemaRef.Context.getTrivialTypeSourceInfo(Pty); - Expr *AssignedCCE = BaseTransform::RebuildCStyleCastExpr(SourceLocation(), - AssignedType, - SourceLocation(), - AssignedRVExpr).get(); - - std::string AssignedPtrName = "__ASSIGNED_ARRAY_PTR_" + SubQT.getAsString(); - VarDecl *AssignedPtrVar = GetArrayAssignedPointerMap(StringRef(AssignedPtrName)); + Expr *AssignedRVExpr = SemaRef.BuildDeclRefExpr( + ArgVDNew, ArgVDNew->getType(), VK_LValue, SourceLocation()); + AssignedRVExpr = + SemaRef + .ImpCastExprToType(AssignedRVExpr, + SemaRef.Context.getArrayDecayedType(QT), + CK_ArrayToPointerDecay) + .get(); + TypeSourceInfo *AssignedType = + SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *AssignedCCE = BaseTransform::RebuildCStyleCastExpr( + SourceLocation(), AssignedType, + SourceLocation(), AssignedRVExpr) + .get(); + + std::string AssignedPtrName = + "__ASSIGNED_ARRAY_PTR_" + SubQT.getAsString(); + VarDecl *AssignedPtrVar = + GetArrayAssignedPointerMap(StringRef(AssignedPtrName)); if (AssignedPtrVar == nullptr) { AssignedPtrVar = VarDecl::Create( SemaRef.Context, FD, SourceLocation(), SourceLocation(), &(SemaRef.Context.Idents).get(AssignedPtrName), Pty.getNonReferenceType(), nullptr, SC_None); - SemaRef.AddInitializerToDecl(AssignedPtrVar, AssignedCCE, /*DirectInit=*/true); + SemaRef.AddInitializerToDecl(AssignedPtrVar, AssignedCCE, + /*DirectInit=*/true); DeclStmt *AssignedDS = SemaRef - .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(AssignedPtrVar), - SourceLocation(), SourceLocation()) + .ActOnDeclStmt( + SemaRef.ConvertDeclToDeclGroup(AssignedPtrVar), + SourceLocation(), SourceLocation()) .getAs(); DeclStmts.push_back(AssignedDS); - SetArrayAssignedPointerMap(StringRef(AssignedPtrName), AssignedPtrVar); + SetArrayAssignedPointerMap(StringRef(AssignedPtrName), + AssignedPtrVar); } else { - Expr *AssignedDRE = SemaRef.BuildDeclRefExpr(AssignedPtrVar, AssignedPtrVar->getType(), VK_LValue, - SourceLocation()); - Stmt *AssignedBO = BaseTransform::RebuildBinaryOperator( - SourceLocation(), BO_Assign, AssignedDRE, AssignedCCE) - .getAs(); + Expr *AssignedDRE = SemaRef.BuildDeclRefExpr( + AssignedPtrVar, AssignedPtrVar->getType(), VK_LValue, + SourceLocation()); + Stmt *AssignedBO = + BaseTransform::RebuildBinaryOperator( + SourceLocation(), BO_Assign, AssignedDRE, AssignedCCE) + .getAs(); DeclStmts.push_back(AssignedBO); } DIndex++; CIndex++; - Expr *ArrayRVExpr = SemaRef.ImpCastExprToType(LE, SemaRef.Context.getArrayDecayedType(QT), - CK_ArrayToPointerDecay).get(); - TypeSourceInfo *ArrayType = SemaRef.Context.getTrivialTypeSourceInfo(Pty); - Expr *ArrayCCE = BaseTransform::RebuildCStyleCastExpr(SourceLocation(), - ArrayType, - SourceLocation(), - ArrayRVExpr).get(); + Expr *ArrayRVExpr = + SemaRef + .ImpCastExprToType(LE, + SemaRef.Context.getArrayDecayedType(QT), + CK_ArrayToPointerDecay) + .get(); + TypeSourceInfo *ArrayType = + SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *ArrayCCE = + BaseTransform::RebuildCStyleCastExpr( + SourceLocation(), ArrayType, SourceLocation(), ArrayRVExpr) + .get(); std::string ArrayPtrName = "__ARRAY_PTR_" + SubQT.getAsString(); VarDecl *ArrayPtrVar = GetArrayPointersMap(StringRef(ArrayPtrName)); @@ -1242,21 +1296,25 @@ public: &(SemaRef.Context.Idents).get(ArrayPtrName), Pty.getNonReferenceType(), nullptr, SC_None); - SemaRef.AddInitializerToDecl(ArrayPtrVar, ArrayCCE, /*DirectInit=*/true); + SemaRef.AddInitializerToDecl(ArrayPtrVar, ArrayCCE, + /*DirectInit=*/true); DeclStmt *ArrayDS = SemaRef - .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArrayPtrVar), - SourceLocation(), SourceLocation()) + .ActOnDeclStmt( + SemaRef.ConvertDeclToDeclGroup(ArrayPtrVar), + SourceLocation(), SourceLocation()) .getAs(); DeclStmts.push_back(ArrayDS); SetArrayPointersMap(StringRef(ArrayPtrName), ArrayPtrVar); } else { - Expr *ArrayDRE = SemaRef.BuildDeclRefExpr(ArrayPtrVar, ArrayPtrVar->getType(), VK_LValue, - SourceLocation()); - Stmt *ArrayBO = BaseTransform::RebuildBinaryOperator( - SourceLocation(), BO_Assign, ArrayDRE, ArrayCCE) - .getAs(); + Expr *ArrayDRE = + SemaRef.BuildDeclRefExpr(ArrayPtrVar, ArrayPtrVar->getType(), + VK_LValue, SourceLocation()); + Stmt *ArrayBO = + BaseTransform::RebuildBinaryOperator( + SourceLocation(), BO_Assign, ArrayDRE, ArrayCCE) + .getAs(); DeclStmts.push_back(ArrayBO); } DIndex++; @@ -1300,16 +1358,29 @@ public: llvm::SmallVector Stmts; - Expr *LHS = SemaRef.BuildDeclRefExpr( - ArrayPtrVar, ArrayPtrVar->getType(), VK_LValue, SourceLocation()); - LHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_PostInc, LHS).get(); - LHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, LHS).get(); - - Expr *RHS = SemaRef.BuildDeclRefExpr( - AssignedPtrVar, AssignedPtrVar->getType(), VK_LValue, SourceLocation()); - RHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_PostInc, RHS).get(); - RHS = SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, RHS).get(); - RHS = SemaRef.ImpCastExprToType(RHS, LHS->getType(), CK_LValueToRValue).get(); + Expr *LHS = + SemaRef.BuildDeclRefExpr(ArrayPtrVar, ArrayPtrVar->getType(), + VK_LValue, SourceLocation()); + LHS = SemaRef + .CreateBuiltinUnaryOp(SourceLocation(), UO_PostInc, LHS) + .get(); + LHS = + SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, LHS) + .get(); + + Expr *RHS = SemaRef.BuildDeclRefExpr(AssignedPtrVar, + AssignedPtrVar->getType(), + VK_LValue, SourceLocation()); + RHS = SemaRef + .CreateBuiltinUnaryOp(SourceLocation(), UO_PostInc, RHS) + .get(); + RHS = + SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, RHS) + .get(); + RHS = + SemaRef + .ImpCastExprToType(RHS, LHS->getType(), CK_LValueToRValue) + .get(); Expr *BO = BaseTransform::RebuildBinaryOperator( SourceLocation(), BO_Assign, LHS, RHS) @@ -1328,8 +1399,8 @@ public: DIndex++; CIndex++; - LE = SemaRef.BuildDeclRefExpr( - ArrayPtrVar, ArrayPtrVar->getType(), VK_LValue, SourceLocation()); + LE = SemaRef.BuildDeclRefExpr(ArrayPtrVar, ArrayPtrVar->getType(), + VK_LValue, SourceLocation()); RE = new (SemaRef.Context) ImplicitValueInitExpr(LE->getType()); } } @@ -1383,8 +1454,7 @@ public: std::tuple GetDMap(Stmt *S) { llvm::DenseMap>::iterator I = DMap.find(S); - if (I != DMap.end()) - return I->second; + if (I != DMap.end()) return I->second; return {-1, -1}; } @@ -1396,9 +1466,9 @@ public: } VarDecl *GetArrayPointersMap(StringRef APName) { - llvm::DenseMap::iterator I = ArrayPointersMap.find(APName); - if (I != ArrayPointersMap.end()) - return I->second; + llvm::DenseMap::iterator I = + ArrayPointersMap.find(APName); + if (I != ArrayPointersMap.end()) return I->second; return nullptr; } @@ -1408,13 +1478,13 @@ public: } VarDecl *GetArrayAssignedPointerMap(StringRef AAPName) { - llvm::DenseMap::iterator I = ArrayAssignedPointerMap.find(AAPName); - if (I != ArrayAssignedPointerMap.end()) - return I->second; + llvm::DenseMap::iterator I = + ArrayAssignedPointerMap.find(AAPName); + if (I != ArrayAssignedPointerMap.end()) return I->second; return nullptr; } }; -} // namespace +} // namespace namespace { class TransformToHasSingleState @@ -1422,7 +1492,7 @@ class TransformToHasSingleState typedef TreeTransform BaseTransform; TransformToAP DT; -public: + public: TransformToHasSingleState(Sema &SemaRef, TransformToAP DT) : BaseTransform(SemaRef), DT(DT) {} @@ -1435,8 +1505,7 @@ public: IfStmt *If = S; Stmt *TS = If->getThen(); Stmt *ES = If->getElse(); - if (TS != nullptr) - HasStatement = (HasAwaitExpr(TS) || HasReturnStmt(TS)); + if (TS != nullptr) HasStatement = (HasAwaitExpr(TS) || HasReturnStmt(TS)); if (ES != nullptr) HasStatementElse = (HasAwaitExpr(ES) || HasReturnStmt(ES)); @@ -1483,6 +1552,26 @@ public: return BaseTransform::TransformWhileStmt(WS); } + StmtResult TransformDoStmt(DoStmt *S) { + bool HasStatement = false; + DoStmt *DS = S; + Stmt *Body = DS->getBody(); + + if (Body != nullptr) + HasStatement = (HasAwaitExpr(Body) || HasReturnStmt(Body)); + + if (HasStatement && !IsRefactorStmt(Body)) { + std::vector Stmts; + Stmts.push_back(Body); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + Body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + DS->setBody(Body); + } + return BaseTransform::TransformDoStmt(DS); + } + StmtResult TransformForStmt(ForStmt *S) { bool HasStatement = false; ForStmt *FS = S; @@ -1506,8 +1595,7 @@ public: bool HasStatement = false; CaseStmt *CS = S; Stmt *SS = CS->getSubStmt(); - if (SS != nullptr) - HasStatement = (HasAwaitExpr(SS) || HasReturnStmt(SS)); + if (SS != nullptr) HasStatement = (HasAwaitExpr(SS) || HasReturnStmt(SS)); if (HasStatement && !IsRefactorStmt(SS)) { std::vector Stmts; Stmts.push_back(SS); @@ -1524,8 +1612,7 @@ public: bool HasStatement = false; DefaultStmt *DS = S; Stmt *SS = DS->getSubStmt(); - if (SS != nullptr) - HasStatement = (HasAwaitExpr(SS) || HasReturnStmt(SS)); + if (SS != nullptr) HasStatement = (HasAwaitExpr(SS) || HasReturnStmt(SS)); if (HasStatement && !IsRefactorStmt(SS)) { std::vector Stmts; Stmts.push_back(SS); @@ -1539,8 +1626,7 @@ public: } StmtResult TransformCompoundStmt(CompoundStmt *S) { - if (S == nullptr) - return S; + if (S == nullptr) return S; std::vector Statements; for (auto *C : S->children()) { @@ -1552,8 +1638,7 @@ public: std::vector DeclStmts = DT.GetDeclStmts(); int size = DeclStmts.size(); for (int i = DIndex; i < DIndex + DNum; i++) { - if (i < size) - Statements.push_back(DeclStmts[i]); + if (i < size) Statements.push_back(DeclStmts[i]); } } SS = BaseTransform::TransformStmt(SS).getAs(); @@ -1571,7 +1656,7 @@ public: return S; } }; -} // namespace +} // namespace namespace { /// Look for Return Stmt @@ -1586,10 +1671,13 @@ class ARFinder : public StmtVisitor { int ReturnNum; llvm::DenseMap ARMap; -public: + public: ARFinder(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, BSCMethodDecl *FD, QualType ReturnTy) - : SemaRef(SemaRef), PDRE(PDRE), FutureRD(FutureRD), FD(FD), + : SemaRef(SemaRef), + PDRE(PDRE), + FutureRD(FutureRD), + FD(FD), ReturnTy(ReturnTy) { ReturnNum = 0; } @@ -1677,12 +1765,13 @@ public: Expr *CompletedRef = SemaRef.BuildDeclRefExpr( CompletedFD, CompletedFD->getType(), VK_LValue, SourceLocation()); - CompletedRef = SemaRef - .ImpCastExprToType(CompletedRef, - SemaRef.Context.getPointerType( - CompletedRef->getType()), - CK_FunctionToPointerDecay) - .get(); + CompletedRef = + SemaRef + .ImpCastExprToType( + CompletedRef, + SemaRef.Context.getPointerType(CompletedRef->getType()), + CK_FunctionToPointerDecay) + .get(); Expr *CE = SemaRef .BuildCallExpr(nullptr, CompletedRef, SourceLocation(), Args, @@ -1714,12 +1803,11 @@ public: int GetARMap(ReturnStmt *RS) { llvm::DenseMap::iterator I = ARMap.find(RS); - if (I != ARMap.end()) - return I->second; + if (I != ARMap.end()) return I->second; return -1; } }; -} // namespace +} // namespace namespace { class TransformARToCS : public TreeTransform { @@ -1728,7 +1816,7 @@ class TransformARToCS : public TreeTransform { int ReturnNum; int ReturnIndex; -public: + public: TransformARToCS(Sema &SemaRef, ARFinder ARInitlizer) : BaseTransform(SemaRef), ARInitlizer(ARInitlizer) { ReturnIndex = 0; @@ -1739,8 +1827,7 @@ public: bool AlwaysRebuild() { return true; } StmtResult TransformCompoundStmt(CompoundStmt *S) { - if (S == nullptr) - return S; + if (S == nullptr) return S; int UnitNum = ARInitlizer.GetUnitNum(); std::vector ReturnStmts = ARInitlizer.GetReturnStmts(); @@ -1751,9 +1838,10 @@ public: Stmt *SS = const_cast(C); if (isa(SS)) { int index = ARInitlizer.GetARMap(cast(SS)); - for (int i = index; i < index + UnitNum; i++) { - if (i < StmtsSize) - Statements.push_back(ReturnStmts[i]); + if (index != -1) { + for (int i = index; i < index + UnitNum; i++) { + if (i < StmtsSize) Statements.push_back(ReturnStmts[i]); + } } continue; } @@ -1772,7 +1860,7 @@ public: return S; } }; -} // namespace +} // namespace namespace { class AEFinder : public StmtVisitor { @@ -1787,7 +1875,7 @@ class AEFinder : public StmtVisitor { llvm::DenseMap AEMap; llvm::DenseMap AEReplaceMap; -public: + public: AEFinder(Sema &SemaRef, ParmVarDecl *PVD, Expr *PDRE, RecordDecl *FutureRD, BSCMethodDecl *FD) : SemaRef(SemaRef), PVD(PVD), PDRE(PDRE), FutureRD(FutureRD), FD(FD) { @@ -1875,104 +1963,102 @@ public: } } - // this.Ft_.vtable - Expr *VtableExpr = SemaRef.BuildMemberExpr( - LHSExpr, false, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *VtableField, - DeclAccessPair::make(FatPointerRD, VtableField->getAccess()), false, - DeclarationNameInfo(), VtableField->getType(), VK_LValue, - OK_Ordinary); - VtableExpr = ImplicitCastExpr::Create( - SemaRef.Context, VtableExpr->getType(), CK_LValueToRValue, VtableExpr, - nullptr, VK_PRValue, FPOptionsOverride()); - - RecordDecl::field_iterator PollFuncField, VtableFieldIt; - const RecordType *RT = dyn_cast( - VtableField->getType()->getPointeeType().getDesugaredType( - SemaRef.Context)); - RecordDecl *VtableRD = RT->getDecl(); - for (VtableFieldIt = VtableRD->field_begin(); - VtableFieldIt != VtableRD->field_end(); ++VtableFieldIt) { - if (VtableFieldIt->getDeclName().getAsString() == "poll") { - PollFuncField = VtableFieldIt; - } + // this.Ft_.vtable + Expr *VtableExpr = SemaRef.BuildMemberExpr( + LHSExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *VtableField, + DeclAccessPair::make(FatPointerRD, VtableField->getAccess()), false, + DeclarationNameInfo(), VtableField->getType(), VK_LValue, OK_Ordinary); + VtableExpr = ImplicitCastExpr::Create( + SemaRef.Context, VtableExpr->getType(), CK_LValueToRValue, VtableExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + + RecordDecl::field_iterator PollFuncField, VtableFieldIt; + const RecordType *RT = dyn_cast( + VtableField->getType()->getPointeeType().getDesugaredType( + SemaRef.Context)); + RecordDecl *VtableRD = RT->getDecl(); + for (VtableFieldIt = VtableRD->field_begin(); + VtableFieldIt != VtableRD->field_end(); ++VtableFieldIt) { + if (VtableFieldIt->getDeclName().getAsString() == "poll") { + PollFuncField = VtableFieldIt; } - const FunctionType *FT = dyn_cast( - PollFuncField->getType()->getPointeeType().getDesugaredType( - SemaRef.Context)); - RecordDecl *PollResultRD = dyn_cast( - dyn_cast( - SemaRef.Context.getCanonicalType(FT->getReturnType())) - ->getDecl()); - - Expr *PollFuncExpr = SemaRef.BuildMemberExpr( - VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *PollFuncField, - DeclAccessPair::make(VtableRD, PollFuncField->getAccess()), false, - DeclarationNameInfo(), PollFuncField->getType(), VK_LValue, - OK_Ordinary); - PollFuncExpr = ImplicitCastExpr::Create( - SemaRef.Context, PollFuncExpr->getType(), CK_LValueToRValue, - PollFuncExpr, nullptr, VK_PRValue, FPOptionsOverride()); - std::vector PollArgs; - Expr *PtrExpr = SemaRef.BuildMemberExpr( - LHSExpr, false, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *PtrField, - DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, - DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); - PtrExpr = ImplicitCastExpr::Create(SemaRef.Context, PtrExpr->getType(), - CK_LValueToRValue, PtrExpr, nullptr, - VK_PRValue, FPOptionsOverride()); - PollArgs.push_back(PtrExpr); - Expr *PollFuncCall = - SemaRef - .BuildCallExpr(nullptr, PollFuncExpr, SourceLocation(), PollArgs, - SourceLocation()) - .get(); + } + const FunctionType *FT = dyn_cast( + PollFuncField->getType()->getPointeeType().getDesugaredType( + SemaRef.Context)); + RecordDecl *PollResultRD = dyn_cast( + dyn_cast( + SemaRef.Context.getCanonicalType(FT->getReturnType())) + ->getDecl()); - RecordDecl::field_iterator ResField, FieldIt; - for (FieldIt = PollResultRD->field_begin(); - FieldIt != PollResultRD->field_end(); ++FieldIt) { - if (FieldIt->getDeclName().getAsString() == "res") { - ResField = FieldIt; - break; - } + Expr *PollFuncExpr = SemaRef.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PollFuncField, + DeclAccessPair::make(VtableRD, PollFuncField->getAccess()), false, + DeclarationNameInfo(), PollFuncField->getType(), VK_LValue, + OK_Ordinary); + PollFuncExpr = ImplicitCastExpr::Create( + SemaRef.Context, PollFuncExpr->getType(), CK_LValueToRValue, + PollFuncExpr, nullptr, VK_PRValue, FPOptionsOverride()); + std::vector PollArgs; + Expr *PtrExpr = SemaRef.BuildMemberExpr( + LHSExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PtrField, + DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, + DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); + PtrExpr = ImplicitCastExpr::Create(SemaRef.Context, PtrExpr->getType(), + CK_LValueToRValue, PtrExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + PollArgs.push_back(PtrExpr); + Expr *PollFuncCall = + SemaRef + .BuildCallExpr(nullptr, PollFuncExpr, SourceLocation(), PollArgs, + SourceLocation()) + .get(); + + RecordDecl::field_iterator ResField, FieldIt; + for (FieldIt = PollResultRD->field_begin(); + FieldIt != PollResultRD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "res") { + ResField = FieldIt; + break; } - std::string AwaitResultVDName = "Res_" + std::to_string(AwaitCount); - VarDecl *AwaitResultVD = VarDecl::Create( - SemaRef.Context, FD, SourceLocation(), SourceLocation(), - &(SemaRef.Context.Idents).get(AwaitResultVDName), ResField->getType(), - nullptr, SC_None); - - DeclGroupRef AwaitResultDG(AwaitResultVD); - DeclStmt *AwaitResultDS = new (SemaRef.Context) - DeclStmt(AwaitResultDG, SourceLocation(), SourceLocation()); - AwaitStmts.push_back(AwaitResultDS); - - std::string PollResultVDName = "PR_" + std::to_string(AwaitCount); - VarDecl *PollResultVD = VarDecl::Create( - SemaRef.Context, FD, SourceLocation(), SourceLocation(), - &(SemaRef.Context.Idents).get(PollResultVDName), - PollFuncCall->getType(), nullptr, SC_None); - - PollResultVD->setInit(PollFuncCall); - DeclGroupRef PollResultDG(PollResultVD); - DeclStmt *PollResultDS = new (SemaRef.Context) - DeclStmt(PollResultDG, SourceLocation(), SourceLocation()); - AwaitStmts.push_back(PollResultDS); - - auto *If = ProcessAwaitExprStatus(SemaRef, AwaitCount, FutureRD, PDRE, - PVD, PollResultVD, AwaitResultVD, FD); - if (If != nullptr) - AwaitStmts.push_back(If); - - Expr *AwaitResultRef = SemaRef.BuildDeclRefExpr( - AwaitResultVD, AwaitResultVD->getType(), VK_LValue, SourceLocation()); - AwaitResultRef = ImplicitCastExpr::Create( - SemaRef.Context, AwaitResultVD->getType(), CK_LValueToRValue, - AwaitResultRef, nullptr, VK_PRValue, FPOptionsOverride()); - SetAEReplaceMap(E, AwaitResultRef); - AwaitStmts.push_back(cast(AwaitResultRef)); + } + std::string AwaitResultVDName = "Res_" + std::to_string(AwaitCount); + VarDecl *AwaitResultVD = + VarDecl::Create(SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(AwaitResultVDName), + ResField->getType(), nullptr, SC_None); + + DeclGroupRef AwaitResultDG(AwaitResultVD); + DeclStmt *AwaitResultDS = new (SemaRef.Context) + DeclStmt(AwaitResultDG, SourceLocation(), SourceLocation()); + AwaitStmts.push_back(AwaitResultDS); + + std::string PollResultVDName = "PR_" + std::to_string(AwaitCount); + VarDecl *PollResultVD = + VarDecl::Create(SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(PollResultVDName), + PollFuncCall->getType(), nullptr, SC_None); + + PollResultVD->setInit(PollFuncCall); + DeclGroupRef PollResultDG(PollResultVD); + DeclStmt *PollResultDS = new (SemaRef.Context) + DeclStmt(PollResultDG, SourceLocation(), SourceLocation()); + AwaitStmts.push_back(PollResultDS); + + auto *If = ProcessAwaitExprStatus(SemaRef, AwaitCount, FutureRD, PDRE, PVD, + PollResultVD, AwaitResultVD, FD); + if (If != nullptr) AwaitStmts.push_back(If); + + Expr *AwaitResultRef = SemaRef.BuildDeclRefExpr( + AwaitResultVD, AwaitResultVD->getType(), VK_LValue, SourceLocation()); + AwaitResultRef = ImplicitCastExpr::Create( + SemaRef.Context, AwaitResultVD->getType(), CK_LValueToRValue, + AwaitResultRef, nullptr, VK_PRValue, FPOptionsOverride()); + SetAEReplaceMap(E, AwaitResultRef); + AwaitStmts.push_back(cast(AwaitResultRef)); } int GetAwaitCount() { return AwaitCount; } @@ -1988,8 +2074,7 @@ public: int GetAEMap(AwaitExpr *AE) { llvm::DenseMap::iterator I = AEMap.find(AE); - if (I != AEMap.end()) - return I->second; + if (I != AEMap.end()) return I->second; return -1; } @@ -2000,12 +2085,11 @@ public: Expr *GetAEReplaceMap(AwaitExpr *AE) { llvm::DenseMap::iterator I = AEReplaceMap.find(AE); - if (I != AEReplaceMap.end()) - return cast(I->second); + if (I != AEReplaceMap.end()) return cast(I->second); return nullptr; } }; -} // namespace +} // namespace namespace { class TransformAEToCS : public TreeTransform { @@ -2016,10 +2100,11 @@ class TransformAEToCS : public TreeTransform { std::vector AEStmts; std::vector &LabelDecls; -public: + public: TransformAEToCS(Sema &SemaRef, AEFinder AEInitlizer, std::vector &LabelDecls) - : BaseTransform(SemaRef), AEInitlizer(AEInitlizer), + : BaseTransform(SemaRef), + AEInitlizer(AEInitlizer), LabelDecls(LabelDecls) { AwaitIndex = 0; AwaitNum = AEInitlizer.GetAwaitCount(); @@ -2032,11 +2117,27 @@ public: return AEInitlizer.GetAEReplaceMap(E); } + StmtResult TransformDeclStmt(DeclStmt *S) { + SmallVector Decls; + for (auto *D : S->decls()) { + if (VarDecl *VD = dyn_cast(D)) { + Expr *Init = const_cast(VD->getInit()); + bool HasAwait = HasAwaitExpr(Init); + if (HasAwait && Init != nullptr) { + Init = BaseTransform::TransformExpr(Init).get(); + SemaRef.AddInitializerToDecl(VD, Init, /*DirectInit=*/true); + } + } + Decls.push_back(D); + } + return BaseTransform::RebuildDeclStmt(Decls, S->getBeginLoc(), + S->getEndLoc()); + } + StmtResult TransformReturnStmt(ReturnStmt *S) { return S; } StmtResult TransformCompoundStmt(CompoundStmt *S) { - if (S == nullptr) - return S; + if (S == nullptr) return S; int UnitNum = AEInitlizer.GetUnitNum(); std::vector AwaitStmts = AEInitlizer.GetAwaitStmts(); @@ -2049,8 +2150,12 @@ public: GetAwaitExpr(SS); int AESize = AEStmts.size(); if (AESize > 0) { + int BaseIndex = Statements.size() - 1; for (int i = 0; i < AESize; i++) { int index = AEInitlizer.GetAEMap(AEStmts[i]); + + if (index == -1) continue; + for (int j = index; j < index + UnitNum - 1; j++) { if (j == index + 1) { LabelStmt *LS = @@ -2063,8 +2168,17 @@ public: continue; } - if (j < StmtsSize) - Statements.push_back(AwaitStmts[j]); + if (j < StmtsSize) Statements.push_back(AwaitStmts[j]); + } + } + + if (isa(SS) && cast(SS)->isSingleDecl() && + BaseIndex >= 0) { + VarDecl *VD = cast(cast(SS)->getSingleDecl()); + if (VD->getNameAsString() == "__RES_RETURN") { + Stmt *LastStmt = Statements[BaseIndex]; + Statements.erase(Statements.begin() + BaseIndex); + Statements.push_back(LastStmt); } } @@ -2087,8 +2201,7 @@ public: } void GetAwaitExpr(Stmt *S) { - if (S == nullptr || isa(S)) - return; + if (S == nullptr || isa(S)) return; for (auto *C : S->children()) { GetAwaitExpr(C); @@ -2099,7 +2212,7 @@ public: } } }; -} // namespace +} // namespace static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, FunctionDecl *FD) { @@ -2446,13 +2559,13 @@ ExprResult Sema::BuildAwaitExpr(SourceLocation AwaitLoc, Expr *E) { } if (!FDecl->isAsyncSpecified() && !IsFutureType(AwaitReturnTy)) { Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); + << getExprRange(E)); return ExprError(); } } else { if (!IsFutureType(AwaitReturnTy)) { Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); + << getExprRange(E)); return ExprError(); } } @@ -2547,7 +2660,8 @@ SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { // Report if await expression appear in non-async functions. if (!FD->isAsyncSpecified()) { if (finder.GetAwaitExprNum() != 0) { - Diag(FD->getBeginLoc(), diag::err_await_invalid_scope) << "non-async function."; + Diag(FD->getBeginLoc(), diag::err_await_invalid_scope) + << "non-async function."; } decls.push_back(FD); return decls; @@ -2572,8 +2686,7 @@ SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { IllegalAEFinder IAEFinder = IllegalAEFinder(*this); IAEFinder.Visit(FD->getBody()); - if (IAEFinder.hasIllegalAwaitExpr()) - return decls; + if (IAEFinder.hasIllegalAwaitExpr()) return decls; QualType ReturnTy = FD->getReturnType(); ReturnTy.removeLocalConst(); @@ -2595,13 +2708,13 @@ SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { decls.push_back(std::get<0>(std::get<0>(NewRDs))); if (!std::get<1>(std::get<1>(NewRDs))) decls.push_back(std::get<0>(std::get<1>(NewRDs))); - + // Handle definition first. - (void)buildFutureInitFunctionDefinition( - *this, FD, std::get<0>(std::get<1>(NewRDs))); + (void)buildFutureInitFunctionDefinition(*this, FD, + std::get<0>(std::get<1>(NewRDs))); const int FutureStateNumber = finder.GetAwaitExprNum() + 1; - + RecordDecl *RD = buildFutureRecordDecl(*this, FD, finder.GetAwaitExpr(), finder.GetLocalVarList()); if (!RD) { @@ -2631,7 +2744,6 @@ SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { } decls.push_back(VtableDecl); - FunctionDecl *FutureInit = buildFutureInitFunctionDeclaraion( *this, RD, FD, std::get<0>(std::get<1>(NewRDs)), VtableDecl); if (!FutureInit) { diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-func-params.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-func-params.cbs new file mode 100644 index 000000000000..2a739485fb01 --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-func-params.cbs @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -verify %s + +#include "../async-func-read-opposite.hbs" + +int t() { + return 42; +} + +int test(int a, int b) { + return 42; +} + +async int f(int start) { + t(); + test(await read(2), await read(2)); // #1 + test(2,3); + test(t(), await read(2)); // #2 + + int result = await read(1); + return result; +} + +// expected-error@#1 {{await expression is not allowed to appear in function parameters}} +// expected-error@#2 {{await expression is not allowed to appear in function parameters}} + +int main() { + return 0; +} diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-return.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-return.cbs new file mode 100644 index 000000000000..a7a47febd91e --- /dev/null +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-of-return.cbs @@ -0,0 +1,26 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../async-func-read.hbs" + +async int f(int start) { + + int a = await read(2); + int b = 2; + + if (a == 1) { + if (b == 3) + return await read(3); + + return await read(2); + } + + return start; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} diff --git a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs index 38302394a830..efd013870b88 100644 --- a/clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs +++ b/clang/test/BSC/Coroutine/AwaitExpr/await-expr-single-judgement.cbs @@ -16,9 +16,13 @@ async int f(int start) { else a = await read(1); - while (a<3) + while (a < 3) a = await read(1); + do + a = await read(1); + while (a < 3); + return start; } diff --git a/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/extern-decl.cbs b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/extern-decl.cbs new file mode 100644 index 000000000000..9f1ff1267167 --- /dev/null +++ b/clang/test/BSC/Coroutine/Treetransform/DeclStmt/MultiDecl/extern-decl.cbs @@ -0,0 +1,23 @@ +// RUN: %clang %s -o %test.output +// RUN: %test.output +// expected-no-diagnostics + +#include "../../../async-func-read.hbs" + +int p; +int t; + +async int f(int start) { + extern int p; + extern int t; + p = 3; + t = 4; + int x = await read(2); + return 42; +} + +int main() { + struct _Futuref this = {}; + struct _Futuref::poll(&this); + return 0; +} -- Gitee From da320f7cac9345a83ad138feaf246b64b0e9ca51 Mon Sep 17 00:00:00 2001 From: yangdian Date: Sat, 8 Jul 2023 09:44:56 +0800 Subject: [PATCH 8/8] [BSC] bugfix for changing FunctionDeclBitfields --- clang/include/clang/AST/DeclBase.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index ba69ba2132e4..db6fa49e8f8c 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1662,7 +1662,7 @@ class DeclContext { }; /// Number of non-inherited bits in FunctionDeclBitfields. - enum { NumFunctionDeclBits = 28 }; + enum { NumFunctionDeclBits = 29 }; /// Stores the bits used by CXXConstructorDecl. If modified /// NumCXXConstructorDeclBits and the accessor @@ -1674,12 +1674,12 @@ class DeclContext { /// For the bits in FunctionDeclBitfields. uint64_t : NumFunctionDeclBits; - /// 23 bits to fit in the remaining available space. + /// 22 bits to fit in the remaining available space. /// Note that this makes CXXConstructorDeclBitfields take /// exactly 64 bits and thus the width of NumCtorInitializers /// will need to be shrunk if some bit is added to NumDeclContextBitfields, /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields. - uint64_t NumCtorInitializers : 20; + uint64_t NumCtorInitializers : 19; uint64_t IsInheritingConstructor : 1; /// Whether this constructor has a trail-allocated explicit specifier. -- Gitee