From 73a1afbde511843a1ba50c1540f820737ce6e09e Mon Sep 17 00:00:00 2001 From: zhaoxuhui Date: Fri, 15 Nov 2024 16:16:53 +0800 Subject: [PATCH 1/5] [bugfix] Trait definition can contain its own type Eg. trait Continuation { trait Continuation* resume(This* this); void setResult(T* arg); }; --- clang/include/clang/Sema/Sema.h | 1 + .../lib/Headers/bsc_include/continuation.hbs | 14 ++ clang/lib/Parse/BSC/ParseDeclBSC.cpp | 43 ++--- clang/lib/Sema/BSC/SemaBSCTrait.cpp | 150 ++++++++++++------ 4 files changed, 140 insertions(+), 68 deletions(-) create mode 100644 clang/lib/Headers/bsc_include/continuation.hbs diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9b81a134c800..bef5c870d472 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7679,6 +7679,7 @@ public: void ActOnFinishTraitMemberSpecification(Decl *TagDecl); RecordDecl *ActOnDesugarVtableRecord(TraitDecl *TD); RecordDecl *ActOnDesugarTraitRecord(TraitDecl *TD, RecordDecl *TraitVtableRD, bool addOwned = false, bool addBorrow = false); + void ActOnVtableRecordFields(TraitDecl *TD); bool IsTraitExpr(Expr *Expr); ExprResult ActOnTraitReassignNull(Scope *S, SourceLocation TokLoc, BinaryOperatorKind Opc, Expr *LHSExpr, diff --git a/clang/lib/Headers/bsc_include/continuation.hbs b/clang/lib/Headers/bsc_include/continuation.hbs new file mode 100644 index 000000000000..524abaa056af --- /dev/null +++ b/clang/lib/Headers/bsc_include/continuation.hbs @@ -0,0 +1,14 @@ +#ifndef _BSCCONTINUATION_HBS +#define _BSCCONTINUATION_HBS 1 + +trait Continuation { + trait Continuation* resume(This* this); + void setResult(T* arg); +}; + +trait Awaitable { + trait Continuation* await(This* this); + void setParent(trait Continuation* k); + void free(This *this); +}; +#endif /* continuation.hbs */ \ No newline at end of file diff --git a/clang/lib/Parse/BSC/ParseDeclBSC.cpp b/clang/lib/Parse/BSC/ParseDeclBSC.cpp index 89c82fcc5ebe..808ee169269b 100644 --- a/clang/lib/Parse/BSC/ParseDeclBSC.cpp +++ b/clang/lib/Parse/BSC/ParseDeclBSC.cpp @@ -436,6 +436,27 @@ void Parser::ParseTraitSpecifier(SourceLocation StartLoc, DeclSpec &DS, } } + // desugar + Decl *D = TagOrTempResult.get(); + TraitDecl *TD = nullptr; + if (TUK == Sema::TUK_Definition && D != nullptr && !D->isInvalidDecl()) { + if (auto *TTD = dyn_cast_or_null(D)) { + TD = TTD->getTemplatedDecl(); + } else if (auto *TraitD = dyn_cast_or_null(D)) { + TD = TraitD; + } + assert(TD && "No corresponding trait"); + + RecordDecl *TraitVtableRD = Actions.ActOnDesugarVtableRecord(TD); + RecordDecl *TraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD); + TD->setTrait(TraitRD); + RecordDecl *OwnedTraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, true, false); + TD->setOwnedTrait(OwnedTraitRD); + RecordDecl *BorrowTraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, false, true); + TD->setBorrowTrait(BorrowTraitRD); + TD->setVtable(TraitVtableRD); + } + if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace)); ParseTraitBody(StartLoc, AttrFixitLoc, TagOrTempResult.get()); @@ -480,26 +501,8 @@ void Parser::ParseTraitSpecifier(SourceLocation StartLoc, DeclSpec &DS, Tok.setKind(tok::semi); } } - - // desugar - Decl *D = TagOrTempResult.get(); - if (TUK == Sema::TUK_Definition && D != nullptr && !D->isInvalidDecl()) { - TraitDecl *TD = nullptr; - if (auto *TTD = dyn_cast_or_null(D)) { - TD = TTD->getTemplatedDecl(); - } else if (auto *TraitD = dyn_cast_or_null(D)) { - TD = TraitD; - } - assert(TD && "No corresponding trait"); - - RecordDecl *TraitVtableRD = Actions.ActOnDesugarVtableRecord(TD); - RecordDecl *TraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD); - TD->setTrait(TraitRD); - RecordDecl *OwnedTraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, true, false); - TD->setOwnedTrait(OwnedTraitRD); - RecordDecl *BorrowTraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, false, true); - TD->setBorrowTrait(BorrowTraitRD); - TD->setVtable(TraitVtableRD); + if (TUK == Sema::TUK_Definition && TD) { + Actions.ActOnVtableRecordFields(TD); } } diff --git a/clang/lib/Sema/BSC/SemaBSCTrait.cpp b/clang/lib/Sema/BSC/SemaBSCTrait.cpp index 31210494b9c4..0d510c0e86d1 100644 --- a/clang/lib/Sema/BSC/SemaBSCTrait.cpp +++ b/clang/lib/Sema/BSC/SemaBSCTrait.cpp @@ -74,54 +74,54 @@ RecordDecl *Sema::ActOnDesugarVtableRecord(TraitDecl *TD) { // todo: error report? } - TraitVtableRD->startDefinition(); - for (TraitDecl::field_iterator FieldIt = TD->field_begin(); - FieldIt != TD->field_end(); ++FieldIt) { - QualType FT = FieldIt->getType(); - if (auto *FPT = FT->getAs()) { - SmallVector Args; - for (unsigned i = 0; i < FPT->getNumParams(); i++) { - QualType T = FPT->getParamType(i); - if (T->isPointerType() && - T->getPointeeType().getCanonicalType().getTypePtr() == - Context.ThisTy.getTypePtr()) { - QualType ThisPT = Context.getQualifiedType( - Context.VoidTy, T->getPointeeType().getLocalQualifiers()); - ThisPT = Context.getPointerType(ThisPT); - ThisPT = Context.getQualifiedType(ThisPT, T.getLocalQualifiers()); - Args.push_back(ThisPT); - } else { - Args.push_back(T); - } - } - SourceLocation BL = FieldIt->getBeginLoc(); - SourceLocation EL = FieldIt->getEndLoc(); - IdentifierInfo *Name = TD->getIdentifier(); - QualType FunctionTy = BuildFunctionType(FPT->getReturnType(), Args, BL, - Name, FPT->getExtProtoInfo()); - QualType PT = BuildPointerType(FunctionTy, BL, Name); - - // Set SourceLocation and Param information for TypeSourceInfo to use - // during serialization - TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(PT); - UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); - CurrTL.getAs().setStarLoc(BL); - CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); - FunctionTypeLoc FTL = CurrTL.getAs(); - FTL.setLocalRangeBegin(BL); - FTL.setLocalRangeEnd(EL); - FTL.setLParenLoc(BL); - FTL.setRParenLoc(EL); - - FieldDecl *NewFD = FieldDecl::Create(Context, TraitVtableRD, BL, EL, - FieldIt->getIdentifier(), PT, TInfo, - nullptr, false, ICIS_NoInit); - NewFD->setAccess(AS_public); - TraitVtableRD->addDecl(NewFD); - } - } - TraitVtableRD->completeDefinition(); - Context.BSCDesugaredMap[TD].push_back(TraitVtableRD); + // TraitVtableRD->startDefinition(); + // for (TraitDecl::field_iterator FieldIt = TD->field_begin(); + // FieldIt != TD->field_end(); ++FieldIt) { + // QualType FT = FieldIt->getType(); + // if (auto *FPT = FT->getAs()) { + // SmallVector Args; + // for (unsigned i = 0; i < FPT->getNumParams(); i++) { + // QualType T = FPT->getParamType(i); + // if (T->isPointerType() && + // T->getPointeeType().getCanonicalType().getTypePtr() == + // Context.ThisTy.getTypePtr()) { + // QualType ThisPT = Context.getQualifiedType( + // Context.VoidTy, T->getPointeeType().getLocalQualifiers()); + // ThisPT = Context.getPointerType(ThisPT); + // ThisPT = Context.getQualifiedType(ThisPT, T.getLocalQualifiers()); + // Args.push_back(ThisPT); + // } else { + // Args.push_back(T); + // } + // } + // SourceLocation BL = FieldIt->getBeginLoc(); + // SourceLocation EL = FieldIt->getEndLoc(); + // IdentifierInfo *Name = TD->getIdentifier(); + // QualType FunctionTy = BuildFunctionType(FPT->getReturnType(), Args, BL, + // Name, FPT->getExtProtoInfo()); + // QualType PT = BuildPointerType(FunctionTy, BL, Name); + + // // Set SourceLocation and Param information for TypeSourceInfo to use + // // during serialization + // TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(PT); + // UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); + // CurrTL.getAs().setStarLoc(BL); + // CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); + // FunctionTypeLoc FTL = CurrTL.getAs(); + // FTL.setLocalRangeBegin(BL); + // FTL.setLocalRangeEnd(EL); + // FTL.setLParenLoc(BL); + // FTL.setRParenLoc(EL); + + // FieldDecl *NewFD = FieldDecl::Create(Context, TraitVtableRD, BL, EL, + // FieldIt->getIdentifier(), PT, TInfo, + // nullptr, false, ICIS_NoInit); + // NewFD->setAccess(AS_public); + // TraitVtableRD->addDecl(NewFD); + // } + // } + // TraitVtableRD->completeDefinition(); + // Context.BSCDesugaredMap[TD].push_back(TraitVtableRD); return TraitVtableRD; } @@ -206,6 +206,60 @@ RecordDecl *Sema::ActOnDesugarTraitRecord(TraitDecl *TD, return TraitRD; } +void Sema::ActOnVtableRecordFields(TraitDecl *TD) { + RecordDecl *TraitVtableRD = TD->getVtable(); + TraitVtableRD->startDefinition(); + for (TraitDecl::field_iterator FieldIt = TD->field_begin(); + FieldIt != TD->field_end(); ++FieldIt) { + QualType FT = FieldIt->getType(); + if (auto *FPT = FT->getAs()) { + SmallVector Args; + for (unsigned i = 0; i < FPT->getNumParams(); i++) { + QualType T = FPT->getParamType(i); + if (T->isPointerType() && + T->getPointeeType().getCanonicalType().getTypePtr() == + Context.ThisTy.getTypePtr()) { + QualType ThisPT = Context.getQualifiedType( + Context.VoidTy, T->getPointeeType().getLocalQualifiers()); + ThisPT = Context.getPointerType(ThisPT); + ThisPT = Context.getQualifiedType(ThisPT, T.getLocalQualifiers()); + Args.push_back(ThisPT); + } else { + Args.push_back(T); + } + } + SourceLocation BL = FieldIt->getBeginLoc(); + SourceLocation EL = FieldIt->getEndLoc(); + IdentifierInfo *Name = TD->getIdentifier(); + QualType FunctionTy = BuildFunctionType(FPT->getReturnType(), Args, BL, + Name, FPT->getExtProtoInfo()); + QualType PT = BuildPointerType(FunctionTy, BL, Name); + + // Set SourceLocation and Param information for TypeSourceInfo to use + // during serialization + TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(PT); + UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); + CurrTL.getAs().setStarLoc(BL); + CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); + FunctionTypeLoc FTL = CurrTL.getAs(); + FTL.setLocalRangeBegin(BL); + FTL.setLocalRangeEnd(EL); + FTL.setLParenLoc(BL); + FTL.setRParenLoc(EL); + + FieldDecl *NewFD = FieldDecl::Create(Context, TraitVtableRD, BL, EL, + FieldIt->getIdentifier(), PT, TInfo, + nullptr, false, ICIS_NoInit); + NewFD->setAccess(AS_public); + TraitVtableRD->addDecl(NewFD); + } + } + TraitVtableRD->completeDefinition(); + Context.BSCDesugaredMap[TD].push_back(TraitVtableRD); + TD->setVtable(TraitVtableRD); +} + + static std::string TypeAsString(QualType T) { PrintingPolicy PrintPolicy = LangOptions(); SplitQualType T_split = T.split(); -- Gitee From da0fb79a8a3796008795580b3498fd93a88cc22c Mon Sep 17 00:00:00 2001 From: zhaoxuhui Date: Mon, 18 Nov 2024 17:09:54 +0800 Subject: [PATCH 2/5] [Coroutine] the state machine transition is based on CPS --- clang/include/clang/AST/Type.h | 4 +- clang/include/clang/Sema/Sema.h | 12 +- clang/lib/AST/BSC/TypeBSC.cpp | 10 + clang/lib/Headers/CMakeLists.txt | 3 +- .../lib/Headers/bsc_include/continuation.hbs | 10 +- clang/lib/Sema/BSC/SemaBSCContinuation.cpp | 3326 +++++++++++++++++ clang/lib/Sema/BSC/SemaBSCTrait.cpp | 55 +- clang/lib/Sema/CMakeLists.txt | 2 +- clang/lib/Sema/SemaCast.cpp | 30 +- 9 files changed, 3383 insertions(+), 69 deletions(-) create mode 100644 clang/lib/Sema/BSC/SemaBSCContinuation.cpp diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index ccf49eac7dd9..3bc282c52d58 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2383,7 +2383,9 @@ public: #if ENABLE_BSC /// Check if the type is the BSC future type. bool isBSCFutureType() const; - #endif + /// Check if the type is the BSC Awaitable type. + bool isBSCAwaitableType() const; +#endif /// Return the implicit lifetime for this type, which must not be dependent. Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index bef5c870d472..9a18ce83a382 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3223,6 +3223,7 @@ public: SmallVector ActOnAsyncFunctionDefinition(FunctionDecl *FD); bool IsBSCCompatibleFutureType(QualType Ty); + bool IsBSCCompatibleAwaitableType(QualType Ty); // BSC Destructor related. BSCMethodDecl *getOrInsertBSCDestructor(RecordDecl *RD); @@ -5951,10 +5952,13 @@ public: ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *CastExpr); - ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, - TypeSourceInfo *Ty, - SourceLocation RParenLoc, - Expr *Op); + ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, + SourceLocation RParenLoc, Expr *Op +#if ENABLE_BSC + , + bool ShouldDesugared = true +#endif + ); CastKind PrepareScalarCast(ExprResult &src, QualType destType); /// Build an altivec or OpenCL literal. diff --git a/clang/lib/AST/BSC/TypeBSC.cpp b/clang/lib/AST/BSC/TypeBSC.cpp index a4c393f37b09..dfa9680cacfc 100644 --- a/clang/lib/AST/BSC/TypeBSC.cpp +++ b/clang/lib/AST/BSC/TypeBSC.cpp @@ -293,6 +293,16 @@ bool Type::isBSCFutureType() const { return false; } +bool Type::isBSCAwaitableType() const { + if (const auto *RT = getAs()) { + RecordDecl *RD = RT->getAsRecordDecl(); + if (isa(RD)) { + return RD->getNameAsString() == "__Trait_Awaitable"; + } + } + return false; +} + ConditionalType::ConditionalType(llvm::Optional CondRes, Expr *CondE, QualType T1, QualType T2, QualType can) : Type(Conditional, can, diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 158dfb759f75..149be9d5e380 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -267,6 +267,7 @@ if (ENABLE_BSC) set(bsc_include_files bsc_include/bsc_type_traits.hbs bsc_include/bsc_conditional.hbs + bsc_include/continuation.hbs bsc_include/future.hbs ) endif() @@ -684,5 +685,5 @@ if (NOT LLVM_ENABLE_IDE) add_llvm_install_targets(install-bsc-resource-headers DEPENDS bsc-resource-headers COMPONENT bsc-resource-headers) - endif() + endif() endif() diff --git a/clang/lib/Headers/bsc_include/continuation.hbs b/clang/lib/Headers/bsc_include/continuation.hbs index 524abaa056af..46cb8c51e2db 100644 --- a/clang/lib/Headers/bsc_include/continuation.hbs +++ b/clang/lib/Headers/bsc_include/continuation.hbs @@ -1,14 +1,16 @@ #ifndef _BSCCONTINUATION_HBS #define _BSCCONTINUATION_HBS 1 +struct Void{}; + trait Continuation { - trait Continuation* resume(This* this); - void setResult(T* arg); + trait Continuation* resume(This* this, T* arg); + // void setResult(This* this, T* arg); }; trait Awaitable { - trait Continuation* await(This* this); - void setParent(trait Continuation* k); + trait Continuation* awaitable(This* this, trait Continuation* k); + // void setParent(This* this, trait Continuation* k); void free(This *this); }; #endif /* continuation.hbs */ \ No newline at end of file diff --git a/clang/lib/Sema/BSC/SemaBSCContinuation.cpp b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp new file mode 100644 index 000000000000..128a24cd8835 --- /dev/null +++ b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp @@ -0,0 +1,3326 @@ +//===--- 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. +// +//===----------------------------------------------------------------------===// + +#if ENABLE_BSC + +#include +#include +#include + +#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" + +using namespace clang; +using namespace sema; + +static RecordDecl *buildAsyncDataRecord(ASTContext &C, StringRef Name, + SourceLocation StartLoc, + SourceLocation EndLoc, + RecordDecl::TagKind TK) { + RecordDecl *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, SourceLocation EndLoc, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, + StorageClass SC, QualType ET) { + // TODO: inline should be passed. + BSCMethodDecl *NewDecl = BSCMethodDecl::Create( + C, DC, StartLoc, DeclarationNameInfo(N, NLoc), T, TInfo, SC, false, false, + ConstexprSpecKind::Unspecified, EndLoc); + if (auto RD = dyn_cast_or_null(DC)) { + C.BSCDeclContextMap[RD->getTypeForDecl()] = DC; + NewDecl->setHasThisParam(true); // bug + NewDecl->setExtendedType(ET); + } + return NewDecl; +} + +std::string GetPrefix(QualType T) { + std::string ExtendedTypeStr = T.getCanonicalType().getAsString(); + for (int i = ExtendedTypeStr.length() - 1; i >= 0; i--) { + if (ExtendedTypeStr[i] == ' ') { + ExtendedTypeStr.replace(i, 1, "_"); + } + } + return ExtendedTypeStr; +} + +static BSCMethodDecl *lookupBSCMethodInRecord(Sema &S, std::string FuncName, + DeclContext *RecordDecl) { + LookupResult Result( + S, + DeclarationNameInfo(&(S.Context.Idents).get(FuncName), SourceLocation()), + S.LookupOrdinaryName); + S.LookupQualifiedName(Result, RecordDecl); + BSCMethodDecl *BSCMethod = nullptr; + if (!Result.empty()) + BSCMethod = dyn_cast_or_null(Result.getFoundDecl()); + return BSCMethod; +} + +static bool implementedAwaitableType(Sema &S, QualType Ty) { + RecordDecl *FutureRD = nullptr; + if (const auto *RT = Ty->getAs()) { + FutureRD = RT->getAsRecordDecl(); + } + + if (!FutureRD) + return false; + BSCMethodDecl *PollFD = lookupBSCMethodInRecord(S, "awaitable", FutureRD); + if (PollFD == nullptr) + return false; + + BSCMethodDecl *FreeFD = lookupBSCMethodInRecord(S, "free", FutureRD); + if (FreeFD == nullptr) + return false; + + return true; +} + +// Logic for generating the procedure to free a future object: +// @code +// if (FutureObj != 0) { +// FreeFuncExpr(FutureObj); +// FutureObj = (void*)0; +// } +// @endcode +static Stmt * +buildIfStmtForFreeFutureObj(Sema &S, Expr *PtrExpr, Expr *FreeFuncExpr, + SourceLocation Loc = SourceLocation()) { + llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), 0); + Expr *IntegerExpr = IntegerLiteral::Create(S.Context, ResultVal, + S.Context.IntTy, SourceLocation()); + // generating condition + Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_NE, + /*LHSExpr=*/PtrExpr, /*RHSExpr=*/IntegerExpr) + .get(); + Sema::ConditionResult IfCond = S.ActOnCondition( + nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); + + // generating free call + QualType Ty = S.Context.VoidPtrTy; + Expr *FreeArg = PtrExpr; + if (PtrExpr->getType() != Ty) { + FreeArg = CStyleCastExpr::Create( + S.Context, Ty, VK_PRValue, CK_BitCast, FreeArg, nullptr, + FPOptionsOverride(), + S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), + SourceLocation(), SourceLocation()); + } + std::vector FreeArgs{FreeArg}; + Expr *FreeFuncCall = S.BuildCallExpr(nullptr, FreeFuncExpr, SourceLocation(), + FreeArgs, SourceLocation()) + .get(); + // generating null assignment + Expr *RAssignExpr = CStyleCastExpr::Create( + S.Context, Ty, VK_PRValue, CK_NullToPointer, IntegerExpr, nullptr, + FPOptionsOverride(), + S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), + SourceLocation(), SourceLocation()); + if (PtrExpr->getType() != Ty) { + RAssignExpr = CStyleCastExpr::Create( + S.Context, PtrExpr->getType(), VK_PRValue, CK_BitCast, RAssignExpr, + nullptr, FPOptionsOverride(), + S.Context.getTrivialTypeSourceInfo(PtrExpr->getType(), + SourceLocation()), + SourceLocation(), SourceLocation()); + } + Expr *NullptrAssign = + S.BuildBinOp(nullptr, SourceLocation(), BO_Assign, + /*LHSExpr=*/PtrExpr, /*RHSExpr=*/RAssignExpr) + .get(); + + SmallVector BodyStmts = {FreeFuncCall, NullptrAssign}; + Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), + SourceLocation(), SourceLocation()); + + Stmt *If = S.BuildIfStmt(Loc, IfStatementKind::Ordinary, + /*LPL=*/Loc, /*Init=*/nullptr, IfCond, + /*RPL=*/Loc, Body, Loc, nullptr) + .get(); + return If; +} + +bool Sema::IsBSCCompatibleFutureType(QualType Ty) { + return implementedAwaitableType(*this, Ty) || + Ty.getTypePtr()->isBSCFutureType(); +} + +// TODO: leaf +bool Sema::IsBSCCompatibleAwaitableType(QualType Ty) { + return implementedAwaitableType(*this, Ty) || + Ty.getTypePtr()->isBSCAwaitableType(); +} + +namespace { +class LocalVarFinder : public StmtVisitor { + ASTContext &Context; + std::vector> LocalVarList; + std::map IdentifierNumber; + +public: + LocalVarFinder(ASTContext &Context) : Context(Context) {} + + 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)) { + if (VD->isExternallyVisible() || VD->isConstexpr() || + VD->isStaticLocal()) + continue; + + QualType QT = VD->getType(); + if (QT->hasTraitType()) + continue; + + Expr *Init = VD->getInit(); + // Do not need to transform constant variable with compile-time + // constant initializier. + const Expr *Culprit; + if (QT.isConstQualified() && Init && !Init->isValueDependent() && + Init->isConstantInitializer(Context, false, &Culprit)) + continue; + + std::string VDName = VD->getName().str(); + // May have several local variables which has same name, eg. + // @code + // async void f() { + // int c = 1; + // { + // int c = 2; + // } + // } + // @endcode + std::map::iterator I = + IdentifierNumber.find(VDName); + int VDNameNum = I != IdentifierNumber.end() ? I->second : 0; + IdentifierNumber[VDName] = VDNameNum + 1; + if (VDNameNum > 0) { + VDName = VDName + "_" + std::to_string(VDNameNum); + VD->setDeclName(&(Context.Idents).get(VDName)); + } + + LocalVarList.push_back(std::make_pair( + VD->getDeclName(), VD->getType())); + } + } + } + Visit(C); + } + } + } + std::vector> GetLocalVarList() const { + return LocalVarList; + } +}; + +class AwaitExprFinder : public StmtVisitor { + int AwaitCount = 0; + std::vector Args; + +public: + AwaitExprFinder() {} + + void VisitAwaitExpr(AwaitExpr *E) { + Visit(E->getSubExpr()); + Args.push_back(E); + AwaitCount++; + } + + void VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + Visit(C); + } + } + } + + int GetAwaitExprNum() const { return AwaitCount; } + + std::vector GetAwaitExpr() const { return Args; } +}; + +static 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; +} + +/// Look for Illegal AwaitExpr +class IllegalAEFinder : public StmtVisitor { + Sema &SemaRef; + bool IsIllegal; + +public: + IllegalAEFinder(Sema &SemaRef) : SemaRef(SemaRef) { IsIllegal = 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 && !IsIllegal) + IsIllegal = CHasIllegalAwait; + + return CHasIllegalAwait; + } + + bool CheckAsyncFuncIllegalStmt(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"; + } 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 (!IsIllegal) + IsIllegal = true; + } + return IsContinue; + } else if (DeclStmt *DS = dyn_cast(S)) { + bool HasVar = false; + for (auto *D : DS->decls()) { + if (VarDecl *VD = dyn_cast(D)) { + if (isa(VD->getType())) { + HasVar = true; + break; + } + } + } + if (HasVar) { + ArgString = "VariableArrayType"; + SemaRef.Diag(S->getBeginLoc(), diag::err_async_func_unsupported) + << ArgString; + if (!IsIllegal) + IsIllegal = true; + return IsContinue; + } + return false; + } + + bool CHasIllegalAwait = hasAwaitExpr(S); + if (CHasIllegalAwait && !IsIllegal) + IsIllegal = 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) || + isa(C) || isa(C)) { + bool IsContinue = CheckAsyncFuncIllegalStmt(C); + if (IsContinue) + continue; + } + + Visit(C); + } + } + } + + 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 IsIllegal; } +}; + +static 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; +} + +static bool isRefactorStmt(Stmt *S) { + if (isa(S) || isa(S) || isa(S) || + isa(S) || isa(S) || isa(S)) + return true; + + return false; +} + +static QualType lookupGenericType(Sema &S, SourceLocation SLoc, QualType T, + std::string GenericDeclName) { + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(GenericDeclName))); + 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) + << GenericDeclName << "\"continuation.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, QualType ContType, 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(); + CallExpr *CE = dyn_cast(AE); + QualType AEType; + // TODO + if (CE) { + FunctionDecl *AwaitFD = + dyn_cast_or_null(CE->getCalleeDecl()); + AEType = + AwaitFD == nullptr + ? AE->getType() + : S.Context.getQualifiedType( + AE->getType(), AwaitFD->getReturnType().getQualifiers()); + } else + AEType = AE->getType(); + + if (!S.IsBSCCompatibleAwaitableType(AEType)) { + QualType AwaitableType = + lookupGenericType(S, FD->getBeginLoc(), AEType, "__Trait_Awaitable"); + if (AwaitableType.isNull()) { + return nullptr; + } + + RecordDecl *AwaitableStruct = AwaitableType->getAsRecordDecl(); + assert(AwaitableStruct != nullptr); + + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getRecordType(AwaitableStruct))); + } else if (implementedAwaitableType(S, AEType)) { + const RecordType *FutureType = + dyn_cast(AEType.getDesugaredType(S.Context)); + RecordDecl *FutureDecl = FutureType->getDecl(); + assert(FutureDecl != nullptr && + "struct future of async function is null"); + + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getRecordType(FutureDecl))); + } 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; + if (VarType.isConstQualified()) { + VarType.removeLocalConst(); + } + addAsyncRecordDecl(S.Context, VarName, VarType, SLoc, ELoc, RD); + } + + const std::string FutureStateName = "__future_state"; + addAsyncRecordDecl(S.Context, FutureStateName, S.Context.IntTy, SLoc, ELoc, + RD); + const std::string ContinuationName = "__cont"; + addAsyncRecordDecl(S.Context, ContinuationName, ContType, SLoc, ELoc, RD); + RD->completeDefinition(); + S.PushOnScopeChains(RD, S.getCurScope(), true); + return RD; +} + +static std::pair +generateVoidStruct(Sema &S, SourceLocation BLoc, SourceLocation ELoc) { + std::string Recordname = "Void"; + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(Recordname))); + RecordDecl *VoidRD = nullptr; + bool IsExisted = false; + + 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; + } + } + IsExisted = true; + } else if (Decls.empty()) { + VoidRD = buildAsyncDataRecord(S.Context, Recordname, BLoc, ELoc, + clang::TagDecl::TagKind::TTK_Struct); + VoidRD->startDefinition(); + VoidRD->completeDefinition(); + S.PushOnScopeChains(VoidRD, S.getCurScope(), true); + } + return std::make_pair(VoidRD, IsExisted); +} + +static std::string getBSCTypeName(QualType QT) { + std::string ExtendedTypeStr = QT.getAsString(); + int len = ExtendedTypeStr.length() - 1; + for (int i = len; i >= 0; i--) { + if (ExtendedTypeStr[i] == ' ') { + if (i == 0) { + ExtendedTypeStr.replace(i, 1, ""); + continue; + } + ExtendedTypeStr.replace(i, 1, "_"); + } else if (ExtendedTypeStr[i] == '*') { + // Since '*' is not allowed to appear in identifier, + // we replace it with 'P'. + // FIXME: it may conflict with user defined type Char_P. + ExtendedTypeStr.replace(i, 1, "P"); + } else if (ExtendedTypeStr[i] == '(') { + // Since '(' is not allowed to appear in identifier, + // we replace it with 'LP'. + ExtendedTypeStr.replace(i, 1, "LP"); + } else if (ExtendedTypeStr[i] == ')') { + // Since ')' is not allowed to appear in identifier, + // we replace it with 'RP'. + ExtendedTypeStr.replace(i, 1, "RP"); + } else if (ExtendedTypeStr[i] == '[') { + // Since '[' is not allowed to appear in identifier, + // we replace it with 'LB'. + ExtendedTypeStr.replace(i, 1, "LB"); + } else if (ExtendedTypeStr[i] == ']') { + // Since ']' is not allowed to appear in identifier, + // we replace it with 'RB'. + ExtendedTypeStr.replace(i, 1, "RB"); + } else if (ExtendedTypeStr[i] == ',') { + // Since ',' is not allowed to appear in identifier, + // we replace it with 'COMMA'. + ExtendedTypeStr.replace(i, 1, "COMMA"); + } + } + return ExtendedTypeStr; +} + +// TODO: Can we first desugar to "impl trait Future<> for type", +// then call the trait interface to desugar again. +static VarDecl *buildContVtableInitDecl(Sema &S, FunctionDecl *FD, + BSCMethodDecl *ResumeFunc, + QualType QT) { + std::string IName = "__Trait_Continuation_Vtable_" + getBSCTypeName(QT) + + "_" + FD->getDeclName().getAsString(); + DeclContext::lookup_result Res = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(IName))); + VarDecl *CVD = nullptr; + if (Res.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Res.begin(), E = Res.end(); + I != E; ++I) { + if (isa(*I)) { + CVD = dyn_cast(*I); + break; + } + } + } + if (CVD) + return CVD; + + QualType ContinuationVtableType = lookupGenericType( + S, FD->getBeginLoc(), QT, "__Trait_Continuation_Vtable"); + VarDecl *VD = VarDecl::Create(S.Context, S.Context.getTranslationUnitDecl(), + FD->getBeginLoc(), FD->getEndLoc(), + &(S.Context.Idents).get(IName), + ContinuationVtableType, nullptr, SC_None); + DeclGroupRef DG(VD); + S.PushOnScopeChains(VD, S.getCurScope(), true); + + SmallVector InitExprs; + QualType ResumeFuncType = S.Context.getPointerType(ResumeFunc->getType()); + Expr *AwaitInit = S.BuildDeclRefExpr(ResumeFunc, ResumeFunc->getType(), + VK_LValue, SourceLocation()); + AwaitInit->HasBSCScopeSpec = true; + AwaitInit = S.ImpCastExprToType( + AwaitInit, S.Context.getPointerType(AwaitInit->getType()), + CK_FunctionToPointerDecay) + .get(); + SmallVector Args; + Args.push_back(S.Context.VoidPtrTy); + Args.push_back(S.Context.getPointerType(QT)); + ResumeFuncType = S.Context.getPointerType( + S.Context.getFunctionType(ResumeFunc->getReturnType(), Args, {})); + AwaitInit = + S.BuildCStyleCastExpr(SourceLocation(), + S.Context.getTrivialTypeSourceInfo(ResumeFuncType), + SourceLocation(), AwaitInit) + .get(); + InitExprs.push_back(AwaitInit); + + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(ContinuationVtableType); + VD->setInit(ILE); + return VD; +} + +static VarDecl *buildAwaitVtableInitDecl(Sema &S, FunctionDecl *FD, + RecordDecl *AwaitVtableRD, + BSCMethodDecl *AwaitFunc, + BSCMethodDecl *FreeFunc) { + std::string IName = AwaitVtableRD->getDeclName().getAsString() + + FD->getDeclName().getAsString(); + VarDecl *VD = VarDecl::Create( + S.Context, S.Context.getTranslationUnitDecl(), FD->getBeginLoc(), + FD->getEndLoc(), &(S.Context.Idents).get(IName), + S.Context.getRecordType(AwaitVtableRD), nullptr, SC_None); + DeclGroupRef DG(VD); + S.PushOnScopeChains(VD, S.getCurScope(), true); + + SmallVector InitExprs; + SmallVector AwaitArgs; + const FunctionProtoType *FPT = + dyn_cast(AwaitFunc->getType()); + AwaitArgs.push_back(S.Context.VoidPtrTy); + AwaitArgs.push_back(FPT->getParamType(1)); + QualType AwaitFuncType = S.Context.getPointerType( + S.Context.getFunctionType(FPT->getReturnType(), AwaitArgs, {})); + // QualType AwaitFuncType = S.Context.getPointerType(AwaitFunc->getType()); + Expr *AwaitInit = S.BuildDeclRefExpr(AwaitFunc, AwaitFunc->getType(), + VK_LValue, SourceLocation()); + AwaitInit->HasBSCScopeSpec = true; + AwaitInit = S.ImpCastExprToType( + AwaitInit, S.Context.getPointerType(AwaitInit->getType()), + CK_FunctionToPointerDecay) + .get(); + AwaitInit = + S.BuildCStyleCastExpr(SourceLocation(), + S.Context.getTrivialTypeSourceInfo(AwaitFuncType), + SourceLocation(), AwaitInit) + .get(); + InitExprs.push_back(AwaitInit); + + SmallVector FreeArgs; + FPT = dyn_cast(FreeFunc->getType()); + FreeArgs.push_back(S.Context.VoidPtrTy); + QualType FreeFuncType = S.Context.getPointerType( + S.Context.getFunctionType(FPT->getReturnType(), FreeArgs, {})); + // QualType FreeFuncType = S.Context.getPointerType(FreeFunc->getType()); + Expr *FreeInit = S.BuildDeclRefExpr(FreeFunc, FreeFunc->getType(), VK_LValue, + SourceLocation()); + FreeInit->HasBSCScopeSpec = true; + FreeInit = S.ImpCastExprToType(FreeInit, + S.Context.getPointerType(FreeInit->getType()), + CK_FunctionToPointerDecay) + .get(); + FreeInit = + S.BuildCStyleCastExpr(SourceLocation(), + S.Context.getTrivialTypeSourceInfo(FreeFuncType), + SourceLocation(), FreeInit) + .get(); + InitExprs.push_back(FreeInit); + + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(S.Context.getRecordType(AwaitVtableRD)); + VD->setInit(ILE); + return VD; +} + +static FunctionDecl *buildFutureInitFunctionDefinition(Sema &S, RecordDecl *RD, + FunctionDecl *FD, + RecordDecl *AwaitableRD, + VarDecl *AwaitVtableInit, + FunctionDecl *FDecl) { + FunctionDecl *NewFD = nullptr; + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + FunctionDecl::param_const_iterator pi; + + if (isa(FD)) { + BSCMethodDecl *BMD = cast(FD); + NewFD = buildAsyncBSCMethodDecl( + S.Context, FDecl->getDeclContext(), SLoc, NLoc, ELoc, + &(S.Context.Idents).get(FDecl->getName().str()), FDecl->getType(), + FDecl->getTypeSourceInfo(), SC_None, BMD->getExtendedType()); + } else { + NewFD = buildAsyncFuncDecl(S.Context, FDecl->getDeclContext(), SLoc, NLoc, + &(S.Context.Idents).get(FDecl->getName().str()), + FDecl->getType(), FDecl->getTypeSourceInfo()); + } + + 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); + 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, SLoc, ELoc); + std::vector Stmts; + Stmts.push_back(DataDS); + + std::string CallocName = "calloc"; + + DeclContext::lookup_result CallocDecls = + S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(CallocName))); + FunctionDecl *CallocFunc = nullptr; + if (CallocDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = CallocDecls.begin(), + E = CallocDecls.end(); + I != E; ++I) { + if (isa(*I)) { + CallocFunc = dyn_cast(*I); + break; + } + } + } else { + S.Diag(FD->getBeginLoc(), diag::err_function_not_found) + << CallocName << ""; + return nullptr; + } + + llvm::APInt OneResultVal(S.Context.getTargetInfo().getIntWidth(), 1); + Expr *One = IntegerLiteral::Create(S.Context, OneResultVal, S.Context.IntTy, + SourceLocation()); + + Expr *CallocRef = + S.BuildDeclRefExpr(CallocFunc, CallocFunc->getType(), VK_LValue, NLoc); + CallocRef = S.ImpCastExprToType( + CallocRef, S.Context.getPointerType(CallocRef->getType()), + CK_FunctionToPointerDecay) + .get(); + // bsc: sizeof(struct __Futurex) + Expr *SizeOfExpr = + S.CreateUnaryExprOrTypeTraitExpr( + S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(RD)), + NLoc, UETT_SizeOf, SourceRange()) + .get(); + SmallVector Args; + Args.push_back(One); + Args.push_back(SizeOfExpr); + + // bsc: calloc(1, sizeof(struct __Futurex)) + Expr *CE = S.BuildCallExpr(nullptr, CallocRef, 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); + + // bsc: if (data == 0) + llvm::APInt ZeroResultVal(S.Context.getTargetInfo().getIntWidth(), 0); + Expr *Zero = IntegerLiteral::Create(S.Context, ZeroResultVal, S.Context.IntTy, + SourceLocation()); + Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_EQ, + /*LHSExpr=*/DataRef, /*RHSExpr=*/Zero) + .get(); + + Sema::ConditionResult IfCond = S.ActOnCondition( + nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); + + // bsc: exit(1); + std::string ExitName = "exit"; + + DeclContext::lookup_result ExitDecls = + S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(ExitName))); + FunctionDecl *ExitFunc = nullptr; + if (ExitDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = ExitDecls.begin(), + E = ExitDecls.end(); + I != E; ++I) { + if (isa(*I)) { + ExitFunc = dyn_cast(*I); + break; + } + } + } else { + S.Diag(FD->getBeginLoc(), diag::err_function_not_found) + << ExitName << ""; + return nullptr; + } + + Expr *ExitRef = + S.BuildDeclRefExpr(ExitFunc, ExitFunc->getType(), VK_LValue, NLoc); + ExitRef = + S.ImpCastExprToType(ExitRef, S.Context.getPointerType(ExitRef->getType()), + CK_FunctionToPointerDecay) + .get(); + + SmallVector ExitArgs = {One}; + Expr *ExitCE = S.BuildCallExpr(nullptr, ExitRef, SourceLocation(), ExitArgs, + SourceLocation()) + .get(); + // Current code: if (data == 0) exit(1); + // TODO: before exit(1) function, hope there is printf("calloc failed\n") + // function to prompt for calloc failure. and it need to import header file + // "stdio.h". + SmallVector BodyStmts = {ExitCE}; + Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), + SourceLocation(), SourceLocation()); + Stmt *If = S.BuildIfStmt(SourceLocation(), IfStatementKind::Ordinary, + /*LPL=*/SourceLocation(), /*Init=*/nullptr, IfCond, + /*RPL=*/SourceLocation(), /*Body=*/Body, + SourceLocation(), nullptr) + .get(); + Stmts.push_back(If); + + 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()); + + 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; + break; + } + } + + 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(AwaitableRD), + S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(AwaitableRD), + SLoc), + SC_None); + + DeclGroupRef FatPointerDG(FatPointerVD); + DeclStmt *FatPointerDS = new (S.Context) DeclStmt(FatPointerDG, SLoc, ELoc); + Stmts.push_back(FatPointerDS); + + SmallVector InitExprs; + Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); + FutureRefExpr = + S.BuildCStyleCastExpr( + NLoc, S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), NLoc, + FutureRefExpr) + .get(); + + Expr *VtableRefExpr = S.BuildDeclRefExpr( + AwaitVtableInit, AwaitVtableInit->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(AwaitableRD)); + FatPointerVD->setInit(ILE); + + Expr *FatPointerRef = S.BuildDeclRefExpr( + FatPointerVD, FatPointerVD->getType(), VK_LValue, NLoc); + // No need for ImplicitCastExpr since BuildReturnStmt will generate for us. + Stmt *RS = S.BuildReturnStmt(NLoc, FatPointerRef).get(); + Stmts.push_back(RS); + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + S.PopDeclContext(); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + return NewFD; +} + +static FunctionDecl * +buildFutureInitFunctionDeclaration(Sema &S, FunctionDecl *FD, RecordDecl *RD) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + DeclarationName funcName = FD->getDeclName(); + QualType FuncRetType = S.Context.getRecordType(RD); + 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(); + + FunctionDecl *NewFD = nullptr; + if (isa(FD)) { + BSCMethodDecl *BMD = cast(FD); + NewFD = + buildAsyncBSCMethodDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, + ELoc, &(S.Context.Idents).get(FName), FuncType, + Tinfo, SC_None, BMD->getExtendedType()); + } 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; +} + +// build function struct Future for async function +static FunctionDecl * +buildFutureStructInitFunctionDefinition(Sema &S, RecordDecl *RD, + FunctionDecl *OriginFD) { + SourceLocation SLoc = OriginFD->getBeginLoc(); + SourceLocation NLoc = OriginFD->getNameInfo().getLoc(); + SourceLocation ELoc = OriginFD->getEndLoc(); + QualType FuncRetType = S.Context.getRecordType(RD); + SmallVector ParamTys; + FunctionDecl::param_const_iterator pi; + for (pi = OriginFD->param_begin(); pi != OriginFD->param_end(); pi++) { + ParamTys.push_back((*pi)->getType()); + } + + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + FunctionDecl *NewFD = nullptr; + + std::string FuncName = "__" + OriginFD->getName().str(); + if (isa(OriginFD)) { + BSCMethodDecl *BMD = cast(OriginFD); + NewFD = buildAsyncBSCMethodDecl( + S.Context, OriginFD->getDeclContext(), SLoc, NLoc, ELoc, + &(S.Context.Idents).get(FuncName), FuncType, + OriginFD->getTypeSourceInfo(), SC_None, BMD->getExtendedType()); + } else { + NewFD = buildAsyncFuncDecl(S.Context, OriginFD->getDeclContext(), SLoc, + NLoc, &(S.Context.Idents).get(FuncName), + FuncType, OriginFD->getTypeSourceInfo()); + } + + SmallVector ParmVarDecls; + for (const auto &I : OriginFD->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.PushFunctionScope(); + S.PushDeclContext(S.getCurScope(), NewFD); + + // Instantiate the struct object and assign values to it + std::string IName = "fi"; + VarDecl *VD = VarDecl::Create(S.Context, NewFD, SLoc, SLoc, + &(S.Context.Idents).get(IName), FuncRetType, + nullptr, SC_None); + InitListExpr *ILE = new (S.Context) + InitListExpr(S.Context, SourceLocation(), {}, SourceLocation()); + ILE->setType(FuncRetType); + S.AddInitializerToDecl(VD, ILE, /*DirectInit=*/false); + DeclGroupRef FutureDG(VD); + DeclStmt *FutureDS = new (S.Context) DeclStmt(FutureDG, SLoc, ELoc); + std::vector Stmts; + Stmts.push_back(FutureDS); + + Expr *StructFutureRef = + S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); + + RecordDecl::field_iterator FieldIt = RD->field_begin(), + Field_end = RD->field_end(); + llvm::SmallVector InitExprs; + for (pi = NewFD->param_begin(); + pi != NewFD->param_end() && FieldIt != Field_end; ++pi, ++FieldIt) { + DeclarationName Name = FieldIt->getDeclName(); + DeclarationNameInfo MemberNameInfo(Name, FieldIt->getLocation()); + Expr *LHSExpr = S.BuildMemberExpr( + StructFutureRef, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FieldIt, + DeclAccessPair::make(*FieldIt, FieldIt->getAccess()), false, + MemberNameInfo, FieldIt->getType().getNonReferenceType(), VK_LValue, + OK_Ordinary); + ExprResult RHSER = + S.BuildDeclRefExpr(*pi, FieldIt->getType().getNonReferenceType(), + VK_LValue, SourceLocation()); + if (RHSER.isInvalid()) + return nullptr; + Expr *RHSExpr = RHSER.get(); + + 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; + break; + } + } + DeclarationName Name = FutureStateField->getDeclName(); + DeclarationNameInfo MemberNameInfo(Name, FutureStateField->getLocation()); + Expr *LHSExpr = S.BuildMemberExpr( + StructFutureRef, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FutureStateField, + DeclAccessPair::make(*FutureStateField, FutureStateField->getAccess()), + false, MemberNameInfo, 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); + + // Generating: + // @code + // return fi; + // @endcode + // No need for ImplicitCastExpr since BuildReturnStmt will generate for us. + Stmt *RS = S.BuildReturnStmt(NLoc, StructFutureRef).get(); + Stmts.push_back(RS); + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + S.PopDeclContext(); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +namespace { +/** + * Visit a Stmt and return true if there's a recursive call to the provided Decl + */ +class RecursiveCallVisitor + : public ConstStmtVisitor { +public: + RecursiveCallVisitor(const Decl *FD) : FD(FD) {} + bool VisitCallExpr(const CallExpr *E) { + if (E->getCalleeDecl() == FD) + return true; + + return this->VisitStmt(static_cast(E)); + } + bool VisitStmt(const Stmt *S) { + for (auto *C : S->children()) { + if (C) { + if (Visit(C)) { + return true; + } + } + } + return false; + } + +private: + const Decl *FD; +}; +} // namespace + +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; } + + FunctionDecl *TransformFunctionDecl(FunctionDecl *D) { + FunctionDecl *NewFD = 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, {}); + + SourceLocation SLoc = D->getBeginLoc(); + SourceLocation NLoc = D->getNameInfo().getLoc(); + SourceLocation ELoc = D->getEndLoc(); + TypeSourceInfo *Tinfo = D->getTypeSourceInfo(); + std::string FName = std::string(D->getIdentifier()->getName()); + + if (isa(D)) { + BSCMethodDecl *BMD = cast(D); + NewFD = buildAsyncBSCMethodDecl( + SemaRef.Context, D->getDeclContext(), SLoc, NLoc, ELoc, + &(SemaRef.Context.Idents).get(FName), FuncType, Tinfo, SC_None, + BMD->getExtendedType()); + } else { + NewFD = buildAsyncFuncDecl(SemaRef.Context, D->getDeclContext(), SLoc, + NLoc, &(SemaRef.Context.Idents).get(FName), + FuncType, Tinfo); + } + SmallVector ParmVarDecls; + for (const auto &I : D->parameters()) { + ParmVarDecl *PVD = ParmVarDecl::Create( + SemaRef.Context, NewFD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(I->getName()), I->getType(), nullptr, + SC_None, nullptr); + ParmVarDecls.push_back(PVD); + } + NewFD->setParams(ParmVarDecls); + NewFD->setLexicalDeclContext(SemaRef.Context.getTranslationUnitDecl()); + + 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); + body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + } + + Stmt *FuncBody = BaseTransform::TransformStmt(body).getAs(); + NewFD->setBody(FuncBody); + } + return NewFD; + } + + 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 { + typedef TreeTransform BaseTransform; + Expr *PDRE; + RecordDecl *FutureRD; + FunctionDecl *FD; + std::vector DeclStmts; + int DIndex; + llvm::DenseMap> DMap; + std::map ArrayPointerMap; + std::map ArrayAssignedPointerMap; + +public: + TransformToAP(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, + FunctionDecl *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 = VD->getInit(); + Expr *LE = nullptr; + Expr *RE = nullptr; + QualType QT = VD->getType(); + + if (VD->isExternallyVisible() || VD->isConstexpr() || + VD->isStaticLocal()) + return S; + + // Do not need to transform constant variable with compile-time constant + // initializier. + const Expr *Culprit; + if (QT.isConstQualified() && Init && !Init->isValueDependent() && + Init->isConstantInitializer(SemaRef.Context, false, &Culprit)) + return S; + + 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 (Init && (QT->isArrayType() || QT->isRecordType())) { + Expr *CInit = BaseTransform::TransformExpr(Init).get(); + + 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); + + SemaRef.AddInitializerToDecl(ArgVDNew, CInit, /*DirectInit=*/false); + DeclStmt *DSNew = + SemaRef + .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(DSNew); + + RE = SemaRef.BuildDeclRefExpr(ArgVDNew, + VD->getType().getNonReferenceType(), + VK_LValue, SourceLocation()); + // No need for ImplicitCastExpr which will be generated + // by RebuildBinaryOperator in future. + DIndex++; + CIndex++; + + if (const ConstantArrayType *CA = dyn_cast(QT)) { + int Elements = SemaRef.Context.getConstantArrayElementCount(CA); + QualType SubQT = SemaRef.Context.getBaseElementType(QT); + + QualType Pty = SemaRef.Context.getPointerType(SubQT); + Expr *AssignedRVExpr = SemaRef.BuildDeclRefExpr( + ArgVDNew, ArgVDNew->getType(), VK_LValue, SourceLocation()); + TypeSourceInfo *AssignedType = + SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *AssignedCCE = BaseTransform::RebuildCStyleCastExpr( + SourceLocation(), AssignedType, + SourceLocation(), AssignedRVExpr) + .get(); + + std::string AssignedPtrName = + "__ASSIGNED_ARRAY_PTR_" + GetPrefix(SubQT); + VarDecl *AssignedPtrVar = + GetArrayAssignedPointerMap(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=*/false); + + DeclStmt *AssignedDS = + SemaRef + .ActOnDeclStmt( + SemaRef.ConvertDeclToDeclGroup(AssignedPtrVar), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(AssignedDS); + SetArrayAssignedPointerMap(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++; + + TypeSourceInfo *ArrayType = + SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *ArrayCCE = + BaseTransform::RebuildCStyleCastExpr( + SourceLocation(), ArrayType, SourceLocation(), LE) + .get(); + + std::string ArrayPtrName = "__ARRAY_PTR_" + GetPrefix(SubQT); + VarDecl *ArrayPtrVar = GetArrayPointerMap(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=*/false); + DeclStmt *ArrayDS = + SemaRef + .ActOnDeclStmt( + SemaRef.ConvertDeclToDeclGroup(ArrayPtrVar), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(ArrayDS); + SetArrayPointerMap(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 *FInit = new (SemaRef.Context) + DeclStmt(IDG, SourceLocation(), SourceLocation()); + + Expr *IDRE = + SemaRef.BuildDeclRefExpr(IArgVDNew, SemaRef.Context.IntTy, + VK_LValue, SourceLocation()); + 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, IDRE, 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(); + 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, FInit, 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 (Init == nullptr) { + 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); + SemaRef.ActOnUninitializedDecl(ArgVDNew); + DeclStmt *DSNew = + SemaRef + .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(DSNew); + DIndex++; + CIndex++; + } + + 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); + } + } + } + + int BOSize = BOStmts.size(); + if (BOSize == 0) { + Result = DeclStmts[DeclStmts.size() - 1]; + DeclStmts.erase(DeclStmts.end() - 1); + DIndex--; + CIndex--; + } 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); + } + if (CIndex > 0) + 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 SetArrayPointerMap(std::string APName, VarDecl *VD) { + assert(VD && "Passed null array pointers variable"); + ArrayPointerMap[APName] = VD; + } + + VarDecl *GetArrayPointerMap(std::string APName) { + std::map::iterator I = ArrayPointerMap.find(APName); + if (I != ArrayPointerMap.end()) + return I->second; + return nullptr; + } + + void SetArrayAssignedPointerMap(std::string AAPName, VarDecl *VD) { + assert(VD && "Passed null array pointers variable"); + ArrayAssignedPointerMap[AAPName] = VD; + } + + VarDecl *GetArrayAssignedPointerMap(std::string AAPName) { + std::map::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(If->getBeginLoc(), Stmts, + If->getEndLoc(), false) + .getAs(); + If->setElse(ES); + } + + if (HasStatement && !isRefactorStmt(TS)) { + std::vector Stmts; + Stmts.push_back(TS); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + TS = BaseTransform::RebuildCompoundStmt(If->getBeginLoc(), Stmts, + If->getEndLoc(), 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(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), false) + .getAs(); + WS->setBody(Body); + } + 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(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), false) + .getAs(); + DS->setBody(Body); + } + return BaseTransform::TransformDoStmt(DS); + } + + 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(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), 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(SS->getBeginLoc(), Stmts, + SS->getEndLoc(), 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(SS->getBeginLoc(), Stmts, + SS->getEndLoc(), 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( + S->getBeginLoc(), Statements, S->getEndLoc(), false) + .getAs(); + return CS; + } + + StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { + return S; + } +}; +} // namespace + +namespace { +class TransformARToCS : public TreeTransform { + typedef TreeTransform BaseTransform; + Expr *PDRE; + RecordDecl *FutureRD; + FunctionDecl *FD; + std::map IdentifierNumber; + +public: + TransformARToCS(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, + FunctionDecl *FD) + : BaseTransform(SemaRef), PDRE(PDRE), FutureRD(FutureRD), FD(FD) {} + + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } + + StmtResult TransformReturnStmt(ReturnStmt *S) { + std::vector ReturnStmts; + Expr *RHSExpr = S->getRetValue(); + SourceLocation BLoc = FD->getBeginLoc(); + SourceLocation ELoc = FD->getEndLoc(); + + RecordDecl::field_iterator FutureStateField, ContField, TheFieldIt; + for (TheFieldIt = FutureRD->field_begin(); + TheFieldIt != FutureRD->field_end(); ++TheFieldIt) { + if (TheFieldIt->getDeclName().getAsString() == "__future_state") { + FutureStateField = TheFieldIt; + } + if (TheFieldIt->getDeclName().getAsString() == "__cont") { + ContField = TheFieldIt; + } + } + + 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"; + // May have several return stmts in the same scope, eg. + // @code + // async f() { + // goto ERR; + // return 0; + // ERR: + // return 0; + // } + // @endcode + std::map::iterator I = + IdentifierNumber.find(ResReturnName); + int ResReturnNum = I != IdentifierNumber.end() ? I->second : 0; + IdentifierNumber[ResReturnName] = ResReturnNum + 1; + if (ResReturnNum > 0) { + ResReturnName = ResReturnName + "_" + std::to_string(ResReturnNum); + } + 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); + + // @code + // this->cont.data + // @endcode + Expr *ContExpr = SemaRef.BuildMemberExpr( + PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *ContField, + DeclAccessPair::make(*ContField, ContField->getAccess()), false, + DeclarationNameInfo(), ContField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + RecordDecl *ContRD = + (*ContField)->getType().getTypePtr()->getAsRecordDecl(); + RecordDecl::field_iterator DataField, VtableField; + for (TheFieldIt = ContRD->field_begin(); TheFieldIt != ContRD->field_end(); + ++TheFieldIt) { + if (TheFieldIt->getDeclName().getAsString() == "data") { + DataField = TheFieldIt; + } + if (TheFieldIt->getDeclName().getAsString() == "vtable") { + VtableField = TheFieldIt; + } + } + Expr *DataExpr = SemaRef.BuildMemberExpr( + ContExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *DataField, + DeclAccessPair::make(*DataField, DataField->getAccess()), false, + DeclarationNameInfo(), DataField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + // @code + // (void *)&__RES_RETURN + // @endcode + Expr *ResExpr = SemaRef.BuildDeclRefExpr( + ResReturnVD, ResReturnVD->getType(), VK_LValue, SourceLocation()); + ResExpr = UnaryOperator::Create( + SemaRef.Context, ResExpr, UO_AddrOf, + SemaRef.Context.getPointerType(ResExpr->getType()), VK_PRValue, + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); + ResExpr = SemaRef + .BuildCStyleCastExpr(SourceLocation(), + SemaRef.Context.getTrivialTypeSourceInfo( + SemaRef.Context.VoidPtrTy), + SourceLocation(), ResExpr) + .get(); + // ResExpr = ImplicitCastExpr::Create(SemaRef.Context, + // ResReturnVD->getType(), + // CK_LValueToRValue, ResExpr, nullptr, + // VK_PRValue, FPOptionsOverride()); + SmallVector Args; + Args.push_back(DataExpr); + Args.push_back(ResExpr); + + // @code + // this->cont.vtable->resume() + // @endcode + Expr *VtableExpr = SemaRef.BuildMemberExpr( + ContExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *VtableField, + DeclAccessPair::make(*VtableField, VtableField->getAccess()), false, + DeclarationNameInfo(), VtableField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + VtableExpr = ImplicitCastExpr::Create( + SemaRef.Context, VtableExpr->getType(), CK_LValueToRValue, VtableExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + RecordDecl *ContVtableRD = (*VtableField) + ->getType() + ->getPointeeType() + .getTypePtr() + ->getAsRecordDecl(); + RecordDecl::field_iterator ResumeField; + for (TheFieldIt = ContVtableRD->field_begin(); + TheFieldIt != ContVtableRD->field_end(); ++TheFieldIt) { + if (TheFieldIt->getDeclName().getAsString() == "resume") { + ResumeField = TheFieldIt; + break; + } + } + Expr *ResumeExpr = SemaRef.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *ResumeField, + DeclAccessPair::make(*ResumeField, ResumeField->getAccess()), false, + DeclarationNameInfo(), ResumeField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + ResumeExpr = ImplicitCastExpr::Create( + SemaRef.Context, ResumeField->getType(), CK_LValueToRValue, ResumeExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + Expr *CE = + SemaRef.BuildCallExpr(nullptr, ResumeExpr, BLoc, Args, ELoc).get(); + Stmt *RS = SemaRef.BuildReturnStmt(BLoc, CE).get(); + ReturnStmts.push_back(RS); + CompoundStmt *CS = CompoundStmt::Create(SemaRef.Context, ReturnStmts, + FPOptionsOverride(), BLoc, ELoc); + + return CS; + } +}; +} // namespace + +namespace { +class TransformAEToCS : public TreeTransform { + typedef TreeTransform BaseTransform; + int AwaitIndex; + std::vector AEStmts; + std::vector &LabelDecls; + int AwaitCount = 0; + + ParmVarDecl *PVD1, *PVD2; + Expr *PDRE; + RecordDecl *FutureRD; + std::vector AwaitStmts; + FunctionDecl *FD; + std::vector ContVtableDecls; + +public: + TransformAEToCS(Sema &SemaRef, std::vector &LabelDecls, + Expr *PDRE, RecordDecl *FutureRD, FunctionDecl *FD, + std::vector &ContVtableDecls) + : BaseTransform(SemaRef), LabelDecls(LabelDecls), PDRE(PDRE), + FutureRD(FutureRD), FD(FD), ContVtableDecls(ContVtableDecls) { + PVD1 = FD->getParamDecl(0); + PVD2 = FD->getParamDecl(1); + AwaitIndex = 1; + } + + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } + + ExprResult TransformAwaitExpr(AwaitExpr *E) { + auto TransformedSE = BaseTransform::TransformExpr(E->getSubExpr()); + AwaitCount++; + auto *AE = TransformedSE.get(); + 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 *FtExpr = SemaRef.BuildMemberExpr( + PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FtField, + DeclAccessPair::make(PVD1, FtField->getAccess()), false, + DeclarationNameInfo(), FtField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + Expr *RHSExpr = AE; + + bool IsOptimization = false; + // Handle nested call + if (CallExpr *CE = dyn_cast(AE)) { + FunctionDecl *FutureInitFunc = CE->getDirectCallee(); + if (FutureInitFunc) { + IsOptimization = !(CE->getType().getTypePtr()->isBSCAwaitableType()) && + implementedAwaitableType(SemaRef, CE->getType()); + // CHECK: Do I need all of this? + std::vector CallArgs; + for (unsigned I = 0; I < CE->getNumArgs(); ++I) { + CallArgs.push_back(CE->getArg(I)); + } + + Expr *FDRef = SemaRef.BuildDeclRefExpr( + FutureInitFunc, FutureInitFunc->getType().getNonReferenceType(), + VK_LValue, SourceLocation()); + FDRef->HasBSCScopeSpec = true; + FDRef = SemaRef + .ImpCastExprToType(FDRef, + SemaRef.Context.getPointerType( + FutureInitFunc->getType()), + CK_FunctionToPointerDecay) + .get(); + FDRef->HasBSCScopeSpec = true; + + RHSExpr = SemaRef + .BuildCallExpr(nullptr, FDRef, SourceLocation(), CallArgs, + SourceLocation()) + .get(); + } + } + + Expr *ResultStmt = SemaRef + .CreateBuiltinBinOp((*FtField)->getLocation(), + BO_Assign, FtExpr, RHSExpr) + .get(); + AwaitStmts.push_back(ResultStmt); + + RecordDecl::field_iterator FutureStateField; + for (RecordDecl::field_iterator FieldIt = FutureRD->field_begin(); + FieldIt != FutureRD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "__future_state") { + FutureStateField = FieldIt; + break; + } + } + + Expr *FSExpr = SemaRef.BuildMemberExpr( + PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FutureStateField, + DeclAccessPair::make(*FutureStateField, FutureStateField->getAccess()), + false, DeclarationNameInfo(), + FutureStateField->getType().getNonReferenceType(), VK_LValue, + OK_Ordinary); + + llvm::APInt ResultVal(SemaRef.Context.getTargetInfo().getIntWidth(), + AwaitIndex); + Expr *IntExpr = IntegerLiteral::Create( + SemaRef.Context, ResultVal, SemaRef.Context.IntTy, SourceLocation()); + Expr *BO = SemaRef + .CreateBuiltinBinOp((*FutureStateField)->getLocation(), + BO_Assign, FSExpr, IntExpr) + .get(); + AwaitStmts.push_back(BO); + + // @code + // this->Ft_1.data + // @endcode + RecordDecl *AwaitRD = (*FtField)->getType().getTypePtr()->getAsRecordDecl(); + RecordDecl::field_iterator DataField, VtableField, TheFieldIt; + for (TheFieldIt = AwaitRD->field_begin(); + TheFieldIt != AwaitRD->field_end(); ++TheFieldIt) { + if (TheFieldIt->getDeclName().getAsString() == "data") { + DataField = TheFieldIt; + } + if (TheFieldIt->getDeclName().getAsString() == "vtable") { + VtableField = TheFieldIt; + } + } + Expr *DataExpr = SemaRef.BuildMemberExpr( + FtExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *DataField, + DeclAccessPair::make(*DataField, DataField->getAccess()), false, + DeclarationNameInfo(), DataField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + + // @code + // (struct __Trait_Continuation_char){.data = this, .vtable = + // &__Trait_Continuation_Vtablefoo} + // @endcode + Expr *ParamExpr1 = ImplicitCastExpr::Create( + SemaRef.Context, SemaRef.Context.VoidPtrTy, CK_BitCast, PDRE, nullptr, + VK_PRValue, FPOptionsOverride()); + VarDecl *ContVtableDecl = ContVtableDecls[AwaitIndex - 1]; + Expr *ParamExpr2 = SemaRef.BuildDeclRefExpr( + ContVtableDecl, ContVtableDecl->getType(), VK_LValue, SourceLocation()); + ParamExpr2 = UnaryOperator::Create( + SemaRef.Context, ParamExpr2, UO_AddrOf, + SemaRef.Context.getPointerType(ParamExpr2->getType()), VK_PRValue, + OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); + InitListExpr *ILE = new (SemaRef.Context) + InitListExpr(SemaRef.Context, SourceLocation(), + {ParamExpr1, ParamExpr2}, SourceLocation()); + QualType Ty = lookupGenericType(SemaRef, SourceLocation(), E->getType(), + "__Trait_Continuation"); + ILE->setType(Ty); + TypeSourceInfo *superTInfo = SemaRef.Context.getTrivialTypeSourceInfo(Ty); + CompoundLiteralExpr *CLE = new (SemaRef.Context) CompoundLiteralExpr( + SourceLocation(), superTInfo, Ty, VK_LValue, ILE, false); + SmallVector Args; + Args.push_back(DataExpr); + Args.push_back(CLE); + + // @code + // this->Ft_1.vtable->await() + // @endcode + Expr *VtableExpr = SemaRef.BuildMemberExpr( + FtExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *VtableField, + DeclAccessPair::make(*VtableField, VtableField->getAccess()), false, + DeclarationNameInfo(), VtableField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + VtableExpr = ImplicitCastExpr::Create( + SemaRef.Context, VtableExpr->getType(), CK_LValueToRValue, VtableExpr, + nullptr, VK_PRValue, FPOptionsOverride()); + RecordDecl *ContVtableRD = (*VtableField) + ->getType() + ->getPointeeType() + .getTypePtr() + ->getAsRecordDecl(); + RecordDecl::field_iterator AwaitField, FreeFuncField; + for (TheFieldIt = ContVtableRD->field_begin(); + TheFieldIt != ContVtableRD->field_end(); ++TheFieldIt) { + if (TheFieldIt->getDeclName().getAsString() == "awaitable") { + AwaitField = TheFieldIt; + } + if (TheFieldIt->getDeclName().getAsString() == "free") { + FreeFuncField = TheFieldIt; + } + } + Expr *AwaitExpr = SemaRef.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *AwaitField, + DeclAccessPair::make(*AwaitField, AwaitField->getAccess()), false, + DeclarationNameInfo(), AwaitField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + AwaitExpr = ImplicitCastExpr::Create(SemaRef.Context, AwaitField->getType(), + CK_LValueToRValue, AwaitExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + Expr *CE = SemaRef + .BuildCallExpr(nullptr, AwaitExpr, SourceLocation(), Args, + SourceLocation()) + .get(); + Stmt *RS = SemaRef.BuildReturnStmt(SourceLocation(), CE).get(); + AwaitStmts.push_back(RS); + + Stmt::EmptyShell Empty; + Stmt *Null = new (SemaRef.Context) NullStmt(Empty); + LabelStmt *LS = + BaseTransform::RebuildLabelStmt( + SourceLocation(), cast(LabelDecls[AwaitIndex++]), + SourceLocation(), Null) + .getAs(); + AwaitStmts.push_back(LS); + + // @code + // char Res_1 = *(char*)extra + // @endcode + Expr *RESExpr = SemaRef.BuildDeclRefExpr(PVD2, PVD2->getType(), VK_LValue, + SourceLocation()); + ImplicitCastExpr *ICE = ImplicitCastExpr::Create( + SemaRef.Context, PVD2->getType(), CK_LValueToRValue, RESExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + ICE->setIsPartOfExplicitCast(true); + RESExpr = SemaRef + .BuildCStyleCastExpr( + SourceLocation(), + SemaRef.Context.getTrivialTypeSourceInfo( + SemaRef.Context.getPointerType(E->getType())), + SourceLocation(), ICE) + .get(); + RESExpr = + SemaRef.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, RESExpr).get(); + std::string AwaitResultVDName = "Res_" + std::to_string(AwaitCount); + VarDecl *AwaitResultVD = + VarDecl::Create(SemaRef.Context, FD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(AwaitResultVDName), + E->getType(), nullptr, SC_None); + AwaitResultVD->setInit(RESExpr); + DeclGroupRef AwaitResultDG(AwaitResultVD); + DeclStmt *AwaitResultDS = new (SemaRef.Context) + DeclStmt(AwaitResultDG, SourceLocation(), SourceLocation()); + AwaitStmts.push_back(AwaitResultDS); + + // @code + // this->Ft_1.vtable->free(this->Ft_1.data); + // @endcode + Expr *FreeFuncExpr = SemaRef.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FreeFuncField, + DeclAccessPair::make(*FreeFuncField, FreeFuncField->getAccess()), false, + DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, + OK_Ordinary); + SmallVector FreeArgs; + FreeArgs.push_back(DataExpr); + FreeFuncExpr = SemaRef + .BuildCallExpr(nullptr, FreeFuncExpr, SourceLocation(), + FreeArgs, SourceLocation()) + .get(); + AwaitStmts.push_back(FreeFuncExpr); + + // @code + // this->Ft_1.data = 0; + // @endcode + llvm::APInt ZeroVal(SemaRef.Context.getTargetInfo().getIntWidth(), 0); + Expr *IntegerExpr = IntegerLiteral::Create( + SemaRef.Context, ZeroVal, SemaRef.Context.IntTy, SourceLocation()); + Expr *FreeDataBO = BinaryOperator::Create( + SemaRef.Context, DataExpr, IntegerExpr, BO_Assign, DataExpr->getType(), + VK_PRValue, OK_Ordinary, SourceLocation(), FPOptionsOverride()); + AwaitStmts.push_back(FreeDataBO); + Expr *AwaitResultRef = SemaRef.BuildDeclRefExpr( + AwaitResultVD, AwaitResultVD->getType(), VK_LValue, SourceLocation()); + AwaitResultRef = ImplicitCastExpr::Create( + SemaRef.Context, AwaitResultVD->getType(), CK_LValueToRValue, + AwaitResultRef, nullptr, VK_PRValue, FPOptionsOverride()); + return AwaitResultRef; + } + + Decl *TransformDefinition(SourceLocation Loc, Decl *D) { + 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(); + + VarDecl *NewVD = VarDecl::Create( + SemaRef.Context, VD->getDeclContext(), VD->getBeginLoc(), + VD->getEndLoc(), VD->getIdentifier(), VD->getType(), + VD->getTypeSourceInfo(), VD->getStorageClass()); + + SemaRef.AddInitializerToDecl(NewVD, Init, /*DirectInit=*/false); + transformedLocalDecl(VD, NewVD); + return NewVD; + } + } + + return BaseTransform::TransformDefinition(Loc, D); + } + + StmtResult TransformCompoundStmt(CompoundStmt *S) { + return this->TransformCompoundStmt(S, false); + } + + StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { + if (S == nullptr) + return S; + + std::vector Statements; + for (auto *SS : S->children()) { + auto prevSize = AwaitStmts.size(); + SS = BaseTransform::TransformStmt(SS).getAs(); + for (size_t i = prevSize; i < AwaitStmts.size(); ++i) { + Statements.push_back(AwaitStmts[i]); + } + AwaitStmts.resize(prevSize); + Statements.push_back(SS); + } + Sema::CompoundScopeRAII CompoundScope(SemaRef); + CompoundStmt *CS = + BaseTransform::RebuildCompoundStmt(S->getBeginLoc(), Statements, + S->getEndLoc(), IsStmtExpr) + .getAs(); + return CS; + } +}; +} // namespace + +static BSCMethodDecl *buildResumeFunction(Sema &S, RecordDecl *RD, + FunctionDecl *FD, + FunctionDecl *PollFD, + QualType FuncRetType) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + + std::string FName = "resume"; + QualType ParamType1 = S.Context.getPointerType(S.Context.getRecordType(RD)); + QualType ParamType2 = S.Context.VoidPtrTy; + SmallVector ParamTys; + ParamTys.push_back(ParamType1); + ParamTys.push_back(ParamType2); + + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + + BSCMethodDecl *NewFD = buildAsyncBSCMethodDecl( + S.Context, RD, SLoc, NLoc, ELoc, &(S.Context.Idents).get(FName), FuncType, + nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; + + SmallVector ParmVarDecls; + ParmVarDecl *PVD1 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("this"), ParamType1, nullptr, SC_None, nullptr); + ParmVarDecl *PVD2 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("arg"), ParamType2, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD1); + ParmVarDecls.push_back(PVD2); + NewFD->setParams(ParmVarDecls); + S.PushFunctionScope(); + S.PushDeclContext(S.getCurScope(), NewFD); + + std::vector ReturnStmts; + Expr *ThisExpr = + S.BuildDeclRefExpr(PVD1, ParamType1, VK_LValue, SourceLocation()); + ThisExpr = ImplicitCastExpr::Create(S.Context, ThisExpr->getType(), + CK_LValueToRValue, ThisExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + Expr *ArgExpr = + S.BuildDeclRefExpr(PVD2, ParamType2, VK_LValue, SourceLocation()); + ArgExpr = S.BuildCStyleCastExpr( + SourceLocation(), + S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), + SourceLocation(), ArgExpr, false) + .get(); + SmallVector Args; + Args.push_back(ThisExpr); + Args.push_back(ArgExpr); + Expr *PollExpr = S.BuildDeclRefExpr(PollFD, PollFD->getType(), VK_LValue, + SourceLocation()); + Expr *CE = S.BuildCallExpr(nullptr, PollExpr, SLoc, Args, ELoc).get(); + Stmt *RS = S.BuildReturnStmt(SLoc, CE).get(); + ReturnStmts.push_back(RS); + CompoundStmt *CS = CompoundStmt::Create(S.Context, ReturnStmts, + FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopDeclContext(); + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +static BSCMethodDecl *buildAwaitFunction(Sema &S, RecordDecl *RD, + FunctionDecl *FD, FunctionDecl *PollFD, + QualType FuncRetType, + QualType ParamType2) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + + std::string FName = "awaitable"; + QualType ParamType1 = S.Context.getPointerType(S.Context.getRecordType(RD)); + SmallVector ParamTys; + ParamTys.push_back(ParamType1); + ParamTys.push_back(ParamType2); + + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + + BSCMethodDecl *NewFD = buildAsyncBSCMethodDecl( + S.Context, RD, SLoc, NLoc, ELoc, &(S.Context.Idents).get(FName), FuncType, + nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; + + SmallVector ParmVarDecls; + ParmVarDecl *PVD1 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("this"), ParamType1, nullptr, SC_None, nullptr); + ParmVarDecl *PVD2 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("arg"), ParamType2, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD1); + ParmVarDecls.push_back(PVD2); + NewFD->setParams(ParmVarDecls); + S.PushFunctionScope(); + S.PushDeclContext(S.getCurScope(), NewFD); + + std::vector ReturnStmts; + Expr *ThisExpr = + S.BuildDeclRefExpr(PVD1, ParamType1, VK_LValue, SourceLocation()); + ThisExpr = ImplicitCastExpr::Create(S.Context, ThisExpr->getType(), + CK_LValueToRValue, ThisExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + Expr *ArgExpr = + S.BuildDeclRefExpr(PVD2, ParamType2, VK_LValue, SourceLocation()); + ArgExpr = UnaryOperator::Create( + S.Context, ArgExpr, UO_AddrOf, S.Context.getPointerType(ParamType2), + VK_PRValue, OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); + ArgExpr = S.BuildCStyleCastExpr( + SourceLocation(), + S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), + SourceLocation(), ArgExpr, false) + .get(); + SmallVector Args; + Args.push_back(ThisExpr); + Args.push_back(ArgExpr); + Expr *PollExpr = S.BuildDeclRefExpr(PollFD, PollFD->getType(), VK_LValue, + SourceLocation()); + Expr *CE = S.BuildCallExpr(nullptr, PollExpr, SLoc, Args, ELoc).get(); + Stmt *RS = S.BuildReturnStmt(SLoc, CE).get(); + ReturnStmts.push_back(RS); + CompoundStmt *CS = CompoundStmt::Create(S.Context, ReturnStmts, + FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopDeclContext(); + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, + FunctionDecl *FD, bool IsOptimization) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + + 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, ELoc, &(S.Context.Idents).get(FName), FuncType, + nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); + 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; + + auto StartsWith = [](const std::string &str, const std::string &prefix) { + if (str.length() >= prefix.length()) { + return 0 == str.compare(0, prefix.length(), prefix); + } + return false; + }; + + std::stack Futures; + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + FieldIt != RD->field_end(); ++FieldIt) { + if (FieldIt->getType().getTypePtr()->isBSCAwaitableType() && + StartsWith(FieldIt->getDeclName().getAsString(), "Ft_")) { + 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()); + + // Generating `FutureExpr` as followed: + // @code + // this.Ft_ + // @endcode + 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; + } + } + + // Generating `VtableExpr` as followed: + // @code + // this.Ft_.vtable + // @endcode + 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_NoOp, 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; + } + } + + Expr *DataExpr = S.BuildMemberExpr( + FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PtrField, + DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, + DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); + + Expr *FreeFuncExpr = S.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FreeFuncField, + DeclAccessPair::make(FatPointerRD, FreeFuncField->getAccess()), false, + DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, + OK_Ordinary); + Stmt *If = buildIfStmtForFreeFutureObj(S, DataExpr, FreeFuncExpr); + Stmts.push_back(If); + } + + if (!IsOptimization) { + 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); + Expr *FutureObj = + S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); + Stmt *If = buildIfStmtForFreeFutureObj(S, FutureObj, FreeFuncRef); + Stmts.push_back(If); + } + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +static FunctionDecl *buildPollFunctionDeclaration(Sema &S, FunctionDecl *FD, + RecordDecl *RD, + QualType FuncRetType) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + + QualType ParamType1 = S.Context.getPointerType(S.Context.getRecordType(RD)); + QualType ParamType2 = S.Context.VoidPtrTy; + SmallVector ParamTys; + ParamTys.push_back(ParamType1); + ParamTys.push_back(ParamType2); + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + TypeSourceInfo *Tinfo = FD->getTypeSourceInfo(); + std::string FName = + "_" + FD->getDeclName().getAsString() + "_state_transiton"; + + FunctionDecl *NewFD = nullptr; + if (isa(FD)) { + BSCMethodDecl *BMD = cast(FD); + NewFD = + buildAsyncBSCMethodDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, + ELoc, &(S.Context.Idents).get(FName), FuncType, + Tinfo, SC_None, BMD->getExtendedType()); + } else { + NewFD = buildAsyncFuncDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, + &(S.Context.Idents).get(FName), FuncType, Tinfo); + } + SmallVector ParmVarDecls; + ParmVarDecl *PVD1 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("this"), ParamType1, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD1); + ParmVarDecl *PVD2 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("extra"), ParamType2, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD2); + NewFD->setParams(ParmVarDecls); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +static FunctionDecl *buildPollFunction(Sema &S, RecordDecl *RD, + FunctionDecl *FD, + RecordDecl *FatPointerRD, + std::vector ContVtableDecls, + QualType FuncRetType, + int FutureStateNumber) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + // QualType Ty = FD->getDeclaredReturnType(); + + S.PushFunctionScope(); + S.PushDeclContext(S.getCurScope(), FD); + FunctionDecl *TransformedFD = + TransformToReturnVoid(S).TransformFunctionDecl(FD); + S.PopDeclContext(); + S.PopFunctionScopeInfo(); + + std::string FName = + "_" + FD->getDeclName().getAsString() + "_state_transiton"; + + QualType ParamType1 = S.Context.getPointerType(S.Context.getRecordType(RD)); + QualType ParamType2 = S.Context.VoidPtrTy; + SmallVector ParamTys; + ParamTys.push_back(ParamType1); + ParamTys.push_back(ParamType2); + + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + // QualType OriginType = S.Context.getFunctionType(Ty, ParamTys, {}); + + FunctionDecl *NewFD = buildAsyncFuncDecl(S.Context, RD, SLoc, NLoc, + &(S.Context.Idents).get(FName), + FuncType, FD->getTypeSourceInfo()); + NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; + S.PushFunctionScope(); + + SmallVector ParmVarDecls; + ParmVarDecl *PVD1 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("this"), ParamType1, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD1); + ParmVarDecl *PVD2 = ParmVarDecl::Create( + S.Context, NewFD, SourceLocation(), SourceLocation(), + &(S.Context.Idents).get("extra"), ParamType2, nullptr, SC_None, nullptr); + ParmVarDecls.push_back(PVD2); + NewFD->setParams(ParmVarDecls); + + std::vector Stmts; + + RecordDecl::field_iterator FutureStateField; + RecordDecl::field_iterator ContField; + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + FieldIt != RD->field_end(); ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "__future_state") { + FutureStateField = FieldIt; + } + if (FieldIt->getDeclName().getAsString() == "__cont") { + ContField = FieldIt; + } + } + + Expr *FutureObj = + S.BuildDeclRefExpr(PVD1, ParamType1, VK_LValue, SourceLocation()); + FutureObj = ImplicitCastExpr::Create(S.Context, ParamType1, CK_LValueToRValue, + FutureObj, nullptr, VK_PRValue, + FPOptionsOverride()); + // Creating Switch Stmt + DeclarationName FutureName = FutureStateField->getDeclName(); + DeclarationNameInfo MemberNameInfo(FutureName, + FutureStateField->getLocation()); + + // @code + // this.__future_state + // @endcode + 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, ELoc); + + SS->setBody(SSBody); + Stmts.push_back(SS); + int StmtSize = Stmts.size(); + + // eg. this->cont = *(struct __Trait_Continuation_type*)extra + Expr *LHSExpr = + S.BuildDeclRefExpr(PVD1, ParamType1, VK_LValue, SourceLocation()); + LHSExpr = ImplicitCastExpr::Create(S.Context, LHSExpr->getType(), + CK_LValueToRValue, LHSExpr, nullptr, + VK_PRValue, FPOptionsOverride()); + LHSExpr = S.BuildMemberExpr( + LHSExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *ContField, + DeclAccessPair::make(*ContField, ContField->getAccess()), false, + DeclarationNameInfo(), ContField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + + Expr *RHSExpr = + S.BuildDeclRefExpr(PVD2, ParamType2, VK_LValue, SourceLocation()); + ImplicitCastExpr *ICE = ImplicitCastExpr::Create( + S.Context, ParamType2, CK_LValueToRValue, RHSExpr, nullptr, VK_PRValue, + FPOptionsOverride()); + ICE->setIsPartOfExplicitCast(true); + RHSExpr = + S.BuildCStyleCastExpr(SourceLocation(), + S.Context.getTrivialTypeSourceInfo( + S.Context.getPointerType(LHSExpr->getType())), + SourceLocation(), ICE) + .get(); + RHSExpr = S.CreateBuiltinUnaryOp(SourceLocation(), UO_Deref, RHSExpr).get(); + Expr *BO = BinaryOperator::Create(S.Context, LHSExpr, RHSExpr, BO_Assign, + LHSExpr->getType(), VK_PRValue, OK_Ordinary, + SourceLocation(), FPOptionsOverride()); + Stmts.push_back(BO); + + NewFD->setType( + S.Context.getFunctionType(TransformedFD->getReturnType(), ParamTys, {})); + S.PushDeclContext(S.getCurScope(), NewFD); + + TransformToAP DT = TransformToAP(S, FutureObj, RD, NewFD); + StmtResult MemberChangeRes = DT.TransformStmt(TransformedFD->getBody()); + Stmt *FuncBody = MemberChangeRes.get(); + + StmtResult SingleStateRes = + TransformToHasSingleState(S, DT).TransformStmt(FuncBody); + FuncBody = SingleStateRes.get(); + + NewFD->setType(FuncType); + + StmtResult ARToCSRes = + TransformARToCS(S, FutureObj, RD, NewFD).TransformStmt(FuncBody); + FuncBody = ARToCSRes.get(); + + StmtResult AEToCSRes = + TransformAEToCS(S, LabelDecls, FutureObj, RD, NewFD, ContVtableDecls) + .TransformStmt(FuncBody); + S.PopDeclContext(); + + for (auto *C : AEToCSRes.get()->children()) { + Stmts.push_back(C); + } + Stmt::EmptyShell Empty; + Stmt *Null = new (S.Context) NullStmt(Empty); + int CurStmtSize = Stmts.size(); + if (CurStmtSize > StmtSize) { + LabelStmt *LS = + new (S.Context) LabelStmt(SourceLocation(), LabelDecls[0], Null); + Stmts.insert(Stmts.begin() + StmtSize, LS); + } else { + LabelStmt *LS = + new (S.Context) LabelStmt(SourceLocation(), LabelDecls[0], Null); + Stmts.push_back(LS); + } + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + 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; + } + + QualType AwaitReturnTy = E->getType(); + + bool IsCall = isa(E); + if (IsCall) { + Decl *AwaitDecl = (dyn_cast(E))->getCalleeDecl(); + FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); + if (FDecl) { + if (!FDecl->isAsyncSpecified() && + !IsBSCCompatibleAwaitableType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); + } + } else { + if (!IsBSCCompatibleAwaitableType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); + } + } + } else { + if (!IsBSCCompatibleAwaitableType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); + } + } + + if (AwaitReturnTy.getTypePtr()->isBSCAwaitableType()) { + const RecordType *AwaitableType = + dyn_cast(AwaitReturnTy.getDesugaredType(Context)); + RecordDecl *AwaitDecl = AwaitableType->getDecl(); + assert(isa(AwaitDecl)); + ClassTemplateSpecializationDecl *CTSD = + cast(AwaitDecl); + const TemplateArgumentList &args = CTSD->getTemplateArgs(); + assert(args.size() == 1); + AwaitReturnTy = args[0].getAsType(); + } else if (implementedAwaitableType(*this, AwaitReturnTy)) { + const RecordType *FutureType = + dyn_cast(AwaitReturnTy.getDesugaredType(Context)); + RecordDecl *FutureRD = FutureType->getDecl(); + + BSCMethodDecl *PollFD = + lookupBSCMethodInRecord(*this, "awaitable", FutureRD); + if (PollFD != nullptr) { + const RecordType *PollResultType = dyn_cast( + PollFD->getReturnType().getDesugaredType(Context)); + 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(); + } + } + } + } + + // build AwaitExpr + AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, E, 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(); + } + + // Correct typos for await expr. + ExprResult CorrectVal = + CorrectDelayedTyposInExpr(E, nullptr, /*RecoverUncorrectedTypos=*/true); + if (CorrectVal.isInvalid()) + return ExprError(); + E = CorrectVal.get(); + return BuildAwaitExpr(AwaitLoc, E); +} + +SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { + SmallVector Decls; + if (!IsBSCCompatibleAwaitableType(FD->getReturnType())) { + QualType ReturnTy = FD->getReturnType(); + ReturnTy.removeLocalConst(); // TODO: need to reconsider. + if (ReturnTy->isVoidType()) { + std::pair VoidRD = + generateVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); + if (!std::get<1>(VoidRD)) { + Decls.push_back(std::get<0>(VoidRD)); + Context.BSCDesugaredMap[FD].push_back(std::get<0>(VoidRD)); + } + ReturnTy = Context.getRecordType(std::get<0>(VoidRD)); + } + + // Continuation + QualType ContinuationVtableType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation_Vtable"); + if (ContinuationVtableType.isNull()) { + return Decls; + } + QualType ContinuationType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation"); + if (ContinuationType.isNull()) { + return Decls; + } + + // Awaitable + QualType AwaitableVtableType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Awaitable_Vtable"); + if (AwaitableVtableType.isNull()) { + return Decls; + } + QualType AwaitableType = lookupGenericType(*this, FD->getBeginLoc(), + ReturnTy, "__Trait_Awaitable"); + if (AwaitableType.isNull()) { + return Decls; + } + RecordDecl *AwaitableRD = AwaitableType->getAsRecordDecl(); + + if (!FD->isStatic()) { + FunctionDecl *FutureInitDef = + buildFutureInitFunctionDeclaration(*this, FD, AwaitableRD); + if (FutureInitDef) { + Decls.push_back(FutureInitDef); + Context.BSCDesugaredMap[FD].push_back(FutureInitDef); + } + } + } + return Decls; +} + +SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { + SmallVector Decls; + Decls.push_back(FD); + + AwaitExprFinder AwaitFinder = AwaitExprFinder(); + AwaitFinder.Visit(FD->getBody()); + + // Report if await expression appear in non-async functions. + if (!FD->isAsyncSpecified()) { + if (AwaitFinder.GetAwaitExprNum() != 0) { + Diag(FD->getBeginLoc(), diag::err_await_invalid_scope) + << "non-async function."; + } + return Decls; + } + + // For leaf nodes, should not be modified async. + // if (IsBSCCompatibleAwaitableType(FD->getReturnType())) { + // Diag(FD->getBeginLoc(), diag::err_invalid_async_function); + // return Decls; + // } + + // Do not process desugar if we already met errors. + if (Diags.hasErrorOccurred()) { + return Decls; + } + + IllegalAEFinder IAEFinder = IllegalAEFinder(*this); + IAEFinder.Visit(FD->getBody()); + if (IAEFinder.HasIllegalAwaitExpr()) + return Decls; + + QualType ReturnTy = FD->getReturnType(); + ReturnTy.removeLocalConst(); + std::pair VoidRD = + generateVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); + if (!std::get<1>(VoidRD)) { + Decls.push_back(std::get<0>(VoidRD)); + Context.BSCDesugaredMap[FD].push_back(std::get<0>(VoidRD)); + } + QualType VoidRDTy = Context.getRecordType(std::get<0>(VoidRD)); + if (ReturnTy->isVoidType()) { + ReturnTy = VoidRDTy; + } + // Continuation + QualType ContinuationVtableType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation_Vtable"); + if (ContinuationVtableType.isNull()) { + return Decls; + } + RecordDecl *ContinuationVtableRD = ContinuationVtableType->getAsRecordDecl(); + QualType ContinuationType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation"); + if (ContinuationType.isNull()) { + return Decls; + } + RecordDecl *ContinuationRD = ContinuationType->getAsRecordDecl(); + + // Awaitable + QualType AwaitableVtableType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Awaitable_Vtable"); + if (AwaitableVtableType.isNull()) { + return Decls; + } + RecordDecl *AwaitableVtableRD = AwaitableVtableType->getAsRecordDecl(); + QualType AwaitableType = lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Awaitable"); + if (AwaitableType.isNull()) { + return Decls; + } + RecordDecl *AwaitableRD = AwaitableType->getAsRecordDecl(); + + // Continuation + QualType ContVoidRDType = lookupGenericType(*this, FD->getBeginLoc(), + VoidRDTy, "__Trait_Continuation"); + if (ContinuationType.isNull()) { + return Decls; + } + + // state machine struct + LocalVarFinder VarFinder = LocalVarFinder(Context); + VarFinder.Visit(FD->getBody()); + RecordDecl *RD = buildFutureRecordDecl(*this, FD, ContinuationType, + AwaitFinder.GetAwaitExpr(), + VarFinder.GetLocalVarList()); + if (!RD) { + return Decls; + } + Decls.push_back(RD); + Context.BSCDesugaredMap[FD].push_back(RD); + + // Handle declaration first. + bool IsRecursiveCall = RecursiveCallVisitor(FD).VisitStmt(FD->getBody()); + bool IsOptimization = FD->isStatic() && !IsRecursiveCall; + // init declaration + FunctionDecl *FutureInitDef = + buildFutureInitFunctionDeclaration(*this, FD, AwaitableRD); + if (!FutureInitDef) { + return Decls; + } + Decls.push_back(FutureInitDef); + Context.BSCDesugaredMap[FD].push_back(FutureInitDef); + + // poll declaration + FunctionDecl *PollDef = + buildPollFunctionDeclaration(*this, FD, RD, ContVoidRDType); + if (!PollDef) { + return Decls; + } + Decls.push_back(PollDef); + Context.BSCDesugaredMap[FD].push_back(PollDef); + + // resume + std::vector ContVtableDecls; + if (AwaitFinder.GetAwaitExprNum() > 0) { + BSCMethodDecl *ResumeDecl = + buildResumeFunction(*this, RD, FD, PollDef, ContVoidRDType); + if (!ResumeDecl) { + return Decls; + } + Decls.push_back(ResumeDecl); + Context.BSCDesugaredMap[FD].push_back(ResumeDecl); + + std::vector Args = AwaitFinder.GetAwaitExpr(); + for (unsigned int i = 0; i < AwaitFinder.GetAwaitExprNum(); i++) { + QualType QT = Args[i]->getType(); + VarDecl *CVD = buildContVtableInitDecl(*this, FD, ResumeDecl, QT); + if (!CVD) { + return Decls; + } + ContVtableDecls.push_back(CVD); + Decls.push_back(CVD); + Context.BSCDesugaredMap[FD].push_back(CVD); + } + } + + // awaitable + BSCMethodDecl *AwaitDecl = buildAwaitFunction( + *this, RD, FD, PollDef, ContVoidRDType, ContinuationType); + if (!AwaitDecl) { + return Decls; + } + Decls.push_back(AwaitDecl); + Context.BSCDesugaredMap[FD].push_back(AwaitDecl); + + // free + BSCMethodDecl *FreeDecl = buildFreeFunction(*this, RD, FD, IsOptimization); + if (!FreeDecl) { + return Decls; + } + Decls.push_back(FreeDecl); + Context.BSCDesugaredMap[FD].push_back(FreeDecl); + + // Awaitable Vtable VarDecl + VarDecl *AwaitVtableDecl = buildAwaitVtableInitDecl( + *this, FD, AwaitableVtableRD, AwaitDecl, FreeDecl); + if (!AwaitVtableDecl) { + return Decls; + } + Decls.push_back(AwaitVtableDecl); + Context.BSCDesugaredMap[FD].push_back(AwaitVtableDecl); + + // poll define + const int FutureStateNumber = AwaitFinder.GetAwaitExprNum() + 1; + FunctionDecl *PollDecl = + buildPollFunction(*this, RD, FD, AwaitableRD, ContVtableDecls, + ContVoidRDType, FutureStateNumber); + if (!PollDecl) { + return Decls; + } + Decls.push_back(PollDecl); + Context.BSCDesugaredMap[FD].push_back(PollDecl); + + FunctionDecl *FutureInit = nullptr; + // if (IsOptimization) { + // FutureInit = + // buildFutureStructInitFunctionDefinition(*this, RD, FD); + // } else { + FutureInit = buildFutureInitFunctionDefinition( + *this, RD, FD, AwaitableRD, AwaitVtableDecl, FutureInitDef); + // } + + if (!FutureInit) { + return Decls; + } + Decls.push_back(FutureInit); + Context.BSCDesugaredMap[FD].push_back(FutureInit); + + return Decls; +} + +#endif // ENABLE_BSC \ No newline at end of file diff --git a/clang/lib/Sema/BSC/SemaBSCTrait.cpp b/clang/lib/Sema/BSC/SemaBSCTrait.cpp index 0d510c0e86d1..b1508bd79b6d 100644 --- a/clang/lib/Sema/BSC/SemaBSCTrait.cpp +++ b/clang/lib/Sema/BSC/SemaBSCTrait.cpp @@ -73,55 +73,6 @@ RecordDecl *Sema::ActOnDesugarVtableRecord(TraitDecl *TD) { } else { // todo: error report? } - - // TraitVtableRD->startDefinition(); - // for (TraitDecl::field_iterator FieldIt = TD->field_begin(); - // FieldIt != TD->field_end(); ++FieldIt) { - // QualType FT = FieldIt->getType(); - // if (auto *FPT = FT->getAs()) { - // SmallVector Args; - // for (unsigned i = 0; i < FPT->getNumParams(); i++) { - // QualType T = FPT->getParamType(i); - // if (T->isPointerType() && - // T->getPointeeType().getCanonicalType().getTypePtr() == - // Context.ThisTy.getTypePtr()) { - // QualType ThisPT = Context.getQualifiedType( - // Context.VoidTy, T->getPointeeType().getLocalQualifiers()); - // ThisPT = Context.getPointerType(ThisPT); - // ThisPT = Context.getQualifiedType(ThisPT, T.getLocalQualifiers()); - // Args.push_back(ThisPT); - // } else { - // Args.push_back(T); - // } - // } - // SourceLocation BL = FieldIt->getBeginLoc(); - // SourceLocation EL = FieldIt->getEndLoc(); - // IdentifierInfo *Name = TD->getIdentifier(); - // QualType FunctionTy = BuildFunctionType(FPT->getReturnType(), Args, BL, - // Name, FPT->getExtProtoInfo()); - // QualType PT = BuildPointerType(FunctionTy, BL, Name); - - // // Set SourceLocation and Param information for TypeSourceInfo to use - // // during serialization - // TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(PT); - // UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); - // CurrTL.getAs().setStarLoc(BL); - // CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); - // FunctionTypeLoc FTL = CurrTL.getAs(); - // FTL.setLocalRangeBegin(BL); - // FTL.setLocalRangeEnd(EL); - // FTL.setLParenLoc(BL); - // FTL.setRParenLoc(EL); - - // FieldDecl *NewFD = FieldDecl::Create(Context, TraitVtableRD, BL, EL, - // FieldIt->getIdentifier(), PT, TInfo, - // nullptr, false, ICIS_NoInit); - // NewFD->setAccess(AS_public); - // TraitVtableRD->addDecl(NewFD); - // } - // } - // TraitVtableRD->completeDefinition(); - // Context.BSCDesugaredMap[TD].push_back(TraitVtableRD); return TraitVtableRD; } @@ -1090,8 +1041,10 @@ ExprResult Sema::ActOnTraitReassignNull(Scope *S, SourceLocation TokLoc, // void *p = (void *)f; // @endcode ExprResult Sema::ActOnTraitPointerCast(Expr *RHSExpr) { - RecordDecl *RD = - dyn_cast(RHSExpr->getType().getCanonicalType())->getDecl(); + QualType T = RHSExpr->getType().getCanonicalType(); + while (T->isPointerType()) + T = T->getPointeeType(); + RecordDecl *RD = dyn_cast(T)->getDecl(); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I) { if (I->getNameAsString() == "data") { diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index a665edbb358a..80f6131e1718 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -15,7 +15,7 @@ add_clang_library(clangSema BSC/SemaBSCDestructor.cpp BSC/SemaBSCOverload.cpp BSC/SemaBSCOwnedStruct.cpp - BSC/SemaBSCCoroutine.cpp + BSC/SemaBSCContinuation.cpp BSC/SemaBSCOwnership.cpp BSC/SemaBSCSafeZone.cpp BSC/SemaBSCTrait.cpp diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index b174416b2a54..9452a13e3afe 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -97,7 +97,11 @@ namespace { void CheckStaticCast(); void CheckDynamicCast(); void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); - void CheckCStyleCast(); + void CheckCStyleCast( +#if ENABLE_BSC + bool ShouldDesugared = true +#endif + ); void CheckBuiltinBitCast(); void CheckAddrspaceCast(); @@ -2845,7 +2849,11 @@ static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, } /// Check the semantics of a C-style cast operation, in C. -void CastOperation::CheckCStyleCast() { +void CastOperation::CheckCStyleCast( +#if ENABLE_BSC + bool ShouldDesugared +#endif +) { assert(!Self.getLangOpts().CPlusPlus); // C-style casts can resolve __unknown_any types. @@ -2906,8 +2914,8 @@ void CastOperation::CheckCStyleCast() { } } } - if (Self.getLangOpts().BSC && Self.IsTraitExpr(SrcExpr.get()) && - DestType->isPointerType()) { + if (Self.getLangOpts().BSC && ShouldDesugared && + Self.IsTraitExpr(SrcExpr.get()) && DestType->isPointerType()) { if (!DestType->hasTraitType()) SrcExpr = Self.ActOnTraitPointerCast(SrcExpr.get()); if (DestType->isVoidPointerType()) { @@ -3295,8 +3303,12 @@ static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, TypeSourceInfo *CastTypeInfo, - SourceLocation RPLoc, - Expr *CastExpr) { + SourceLocation RPLoc, Expr *CastExpr +#if ENABLE_BSC + , + bool ShouldDesugared +#endif +) { CastOperation Op(*this, CastTypeInfo->getType(), CastExpr); Op.DestRange = CastTypeInfo->getTypeLoc().getSourceRange(); Op.OpRange = SourceRange(LPLoc, CastExpr->getEndLoc()); @@ -3305,7 +3317,11 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, Op.CheckCXXCStyleCast(/*FunctionalCast=*/ false, isa(CastExpr)); } else { - Op.CheckCStyleCast(); + Op.CheckCStyleCast( +#if ENABLE_BSC + ShouldDesugared +#endif + ); } if (Op.SrcExpr.isInvalid()) -- Gitee From dd16b88120f7df0b58ddfe7b8ac7eb6f5ffe2017 Mon Sep 17 00:00:00 2001 From: zhaoxuhui Date: Sat, 30 Nov 2024 15:42:58 +0800 Subject: [PATCH 3/5] [Coroutine][Driver] add -CPS option 1.add -CPS compilation option to indicate that the coroutine transformation on continuation passing style 2.move the common method of coroutine transformation to AsyncBSC.h --- clang/include/clang/AST/BSC/AsyncBSC.h | 1754 ++++++++++++ clang/include/clang/AST/Type.h | 4 +- clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/BSC/BSCOptions.td | 2 + clang/include/clang/Sema/Sema.h | 5 +- clang/lib/AST/BSC/TypeBSC.cpp | 20 +- clang/lib/Driver/ToolChains/Clang.cpp | 2 + .../lib/Headers/bsc_include/continuation.hbs | 2 - clang/lib/Parse/BSC/ParseDeclBSC.cpp | 6 +- clang/lib/Parse/ParseDecl.cpp | 13 +- clang/lib/Sema/BSC/SemaBSCContinuation.cpp | 2546 ++--------------- clang/lib/Sema/BSC/SemaBSCCoroutine.cpp | 1131 ++------ clang/lib/Sema/BSC/SemaBSCTrait.cpp | 1 - clang/lib/Sema/CMakeLists.txt | 1 + clang/lib/Sema/SemaExpr.cpp | 4 +- 15 files changed, 2220 insertions(+), 3272 deletions(-) create mode 100644 clang/include/clang/AST/BSC/AsyncBSC.h diff --git a/clang/include/clang/AST/BSC/AsyncBSC.h b/clang/include/clang/AST/BSC/AsyncBSC.h new file mode 100644 index 000000000000..4478f5d75235 --- /dev/null +++ b/clang/include/clang/AST/BSC/AsyncBSC.h @@ -0,0 +1,1754 @@ +//===- WalkerBSC.h - Classes for traversing BSC ASTs --*- BSC -*-=====// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the BSC Walker utilities. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_WALKERBSC_H +#define LLVM_CLANG_AST_WALKERBSC_H + +#if ENABLE_BSC +#include "clang/AST/ASTContext.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/TargetInfo.h" + +namespace clang { +class ASTContext; + +static RecordDecl *buildAsyncDataRecord(ASTContext &C, StringRef Name, + SourceLocation StartLoc, + SourceLocation EndLoc, + RecordDecl::TagKind TK) { + RecordDecl *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, SourceLocation EndLoc, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, + StorageClass SC, QualType ET) { + // TODO: inline should be passed. + BSCMethodDecl *NewDecl = BSCMethodDecl::Create( + C, DC, StartLoc, DeclarationNameInfo(N, NLoc), T, TInfo, SC, false, false, + ConstexprSpecKind::Unspecified, EndLoc); + if (auto RD = dyn_cast_or_null(DC)) { + C.BSCDeclContextMap[RD->getTypeForDecl()] = DC; + NewDecl->setHasThisParam(true); // bug + NewDecl->setExtendedType(ET); + } + return NewDecl; +} + +static std::string GetPrefix(QualType T) { + std::string ExtendedTypeStr = T.getCanonicalType().getAsString(); + for (int i = ExtendedTypeStr.length() - 1; i >= 0; i--) { + if (ExtendedTypeStr[i] == ' ') { + ExtendedTypeStr.replace(i, 1, "_"); + } + } + return ExtendedTypeStr; +} + +static BSCMethodDecl *lookupBSCMethodInRecord(Sema &S, std::string FuncName, + DeclContext *RecordDecl) { + LookupResult Result( + S, + DeclarationNameInfo(&(S.Context.Idents).get(FuncName), SourceLocation()), + S.LookupOrdinaryName); + S.LookupQualifiedName(Result, RecordDecl, false, true); + BSCMethodDecl *BSCMethod = nullptr; + if (!Result.empty()) + BSCMethod = dyn_cast_or_null(Result.getRepresentativeDecl()); + return BSCMethod; +} + +static QualType lookupGenericType(Sema &S, SourceLocation SLoc, QualType T, + std::string GenericDeclName, + std::string FileName) { + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(GenericDeclName))); + 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) + << GenericDeclName << "\"" + FileName + "\""; + 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; +} + +static bool implementedAsyncType(Sema &S, QualType Ty) { + RecordDecl *AsyncRD = nullptr; + if (const auto *RT = Ty->getAs()) { + AsyncRD = RT->getAsRecordDecl(); + } + + if (!AsyncRD) + return false; + BSCMethodDecl *FreeFD = lookupBSCMethodInRecord(S, "free", AsyncRD); + if (FreeFD == nullptr) + return false; + + bool IsCPS = S.Context.getLangOpts().ContinuationPassingStyle; + BSCMethodDecl *FD = NULL; + if (IsCPS) { + FD = lookupBSCMethodInRecord(S, "awaitable", AsyncRD); + } else { + FD = lookupBSCMethodInRecord(S, "poll", AsyncRD); + } + if (FD == nullptr) + return false; + + return true; +} + +static 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; +} + +static 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; +} + +static bool isRefactorStmt(Stmt *S) { + if (isa(S) || isa(S) || isa(S) || + isa(S) || isa(S) || isa(S)) + return true; + + return false; +} + +class LocalVarFinder : public StmtVisitor { + ASTContext &Context; + std::vector> LocalVarList; + std::map IdentifierNumber; + +public: + LocalVarFinder(ASTContext &Context) : Context(Context) {} + + 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)) { + if (VD->isExternallyVisible() || VD->isConstexpr() || + VD->isStaticLocal()) + continue; + + QualType QT = VD->getType(); + if (QT->hasTraitType()) + continue; + + Expr *Init = VD->getInit(); + // Do not need to transform constant variable with compile-time + // constant initializier. + const Expr *Culprit; + if (QT.isConstQualified() && Init && !Init->isValueDependent() && + Init->isConstantInitializer(Context, false, &Culprit)) + continue; + + std::string VDName = VD->getName().str(); + // May have several local variables which has same name, eg. + // @code + // async void f() { + // int c = 1; + // { + // int c = 2; + // } + // } + // @endcode + std::map::iterator I = + IdentifierNumber.find(VDName); + int VDNameNum = I != IdentifierNumber.end() ? I->second : 0; + IdentifierNumber[VDName] = VDNameNum + 1; + if (VDNameNum > 0) { + VDName = VDName + "_" + std::to_string(VDNameNum); + VD->setDeclName(&(Context.Idents).get(VDName)); + } + + LocalVarList.push_back(std::make_pair( + VD->getDeclName(), VD->getType())); + } + } + } + Visit(C); + } + } + } + std::vector> GetLocalVarList() const { + return LocalVarList; + } +}; + +class AwaitExprFinder : public StmtVisitor { + int AwaitCount = 0; + std::vector Args; + +public: + AwaitExprFinder() {} + + void VisitAwaitExpr(AwaitExpr *E) { + Visit(E->getSubExpr()); + Args.push_back(E); + AwaitCount++; + } + + void VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + Visit(C); + } + } + } + + int GetAwaitExprNum() const { return AwaitCount; } + + std::vector GetAwaitExpr() const { return Args; } +}; + +/// Look for Illegal AwaitExpr +class IllegalAEFinder : public StmtVisitor { + Sema &SemaRef; + bool IsIllegal; + +public: + IllegalAEFinder(Sema &SemaRef) : SemaRef(SemaRef) { IsIllegal = 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 && !IsIllegal) + IsIllegal = CHasIllegalAwait; + + return CHasIllegalAwait; + } + + bool CheckAsyncFuncIllegalStmt(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"; + } 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 (!IsIllegal) + IsIllegal = true; + } + return IsContinue; + } else if (DeclStmt *DS = dyn_cast(S)) { + bool HasVar = false; + for (auto *D : DS->decls()) { + if (VarDecl *VD = dyn_cast(D)) { + if (isa(VD->getType())) { + HasVar = true; + break; + } + } + } + if (HasVar) { + ArgString = "VariableArrayType"; + SemaRef.Diag(S->getBeginLoc(), diag::err_async_func_unsupported) + << ArgString; + if (!IsIllegal) + IsIllegal = true; + return IsContinue; + } + return false; + } + + bool CHasIllegalAwait = hasAwaitExpr(S); + if (CHasIllegalAwait && !IsIllegal) + IsIllegal = 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) || + isa(C) || isa(C)) { + bool IsContinue = CheckAsyncFuncIllegalStmt(C); + if (IsContinue) + continue; + } + + Visit(C); + } + } + } + + 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 IsIllegal; } +}; + +class TransformToAP : public TreeTransform { + typedef TreeTransform BaseTransform; + Expr *PDRE; + RecordDecl *FutureRD; + FunctionDecl *FD; + std::vector DeclStmts; + int DIndex; + llvm::DenseMap> DMap; + std::map ArrayPointerMap; + std::map ArrayAssignedPointerMap; + +public: + TransformToAP(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, + FunctionDecl *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 = VD->getInit(); + Expr *LE = nullptr; + Expr *RE = nullptr; + QualType QT = VD->getType(); + + if (VD->isExternallyVisible() || VD->isConstexpr() || + VD->isStaticLocal()) + return S; + + // Do not need to transform constant variable with compile-time constant + // initializier. + const Expr *Culprit; + if (QT.isConstQualified() && Init && !Init->isValueDependent() && + Init->isConstantInitializer(SemaRef.Context, false, &Culprit)) + return S; + + 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 (Init && (QT->isArrayType() || QT->isRecordType())) { + Expr *CInit = BaseTransform::TransformExpr(Init).get(); + + 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); + + SemaRef.AddInitializerToDecl(ArgVDNew, CInit, /*DirectInit=*/false); + DeclStmt *DSNew = + SemaRef + .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(DSNew); + + RE = SemaRef.BuildDeclRefExpr(ArgVDNew, + VD->getType().getNonReferenceType(), + VK_LValue, SourceLocation()); + // No need for ImplicitCastExpr which will be generated + // by RebuildBinaryOperator in future. + DIndex++; + CIndex++; + + if (const ConstantArrayType *CA = dyn_cast(QT)) { + int Elements = SemaRef.Context.getConstantArrayElementCount(CA); + QualType SubQT = SemaRef.Context.getBaseElementType(QT); + + QualType Pty = SemaRef.Context.getPointerType(SubQT); + Expr *AssignedRVExpr = SemaRef.BuildDeclRefExpr( + ArgVDNew, ArgVDNew->getType(), VK_LValue, SourceLocation()); + TypeSourceInfo *AssignedType = + SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *AssignedCCE = BaseTransform::RebuildCStyleCastExpr( + SourceLocation(), AssignedType, + SourceLocation(), AssignedRVExpr) + .get(); + + std::string AssignedPtrName = + "__ASSIGNED_ARRAY_PTR_" + GetPrefix(SubQT); + VarDecl *AssignedPtrVar = + GetArrayAssignedPointerMap(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=*/false); + + DeclStmt *AssignedDS = + SemaRef + .ActOnDeclStmt( + SemaRef.ConvertDeclToDeclGroup(AssignedPtrVar), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(AssignedDS); + SetArrayAssignedPointerMap(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++; + + TypeSourceInfo *ArrayType = + SemaRef.Context.getTrivialTypeSourceInfo(Pty); + Expr *ArrayCCE = + BaseTransform::RebuildCStyleCastExpr( + SourceLocation(), ArrayType, SourceLocation(), LE) + .get(); + + std::string ArrayPtrName = "__ARRAY_PTR_" + GetPrefix(SubQT); + VarDecl *ArrayPtrVar = GetArrayPointerMap(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=*/false); + DeclStmt *ArrayDS = + SemaRef + .ActOnDeclStmt( + SemaRef.ConvertDeclToDeclGroup(ArrayPtrVar), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(ArrayDS); + SetArrayPointerMap(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 *FInit = new (SemaRef.Context) + DeclStmt(IDG, SourceLocation(), SourceLocation()); + + Expr *IDRE = + SemaRef.BuildDeclRefExpr(IArgVDNew, SemaRef.Context.IntTy, + VK_LValue, SourceLocation()); + 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, IDRE, 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(); + 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, FInit, 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 (Init == nullptr) { + 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); + SemaRef.ActOnUninitializedDecl(ArgVDNew); + DeclStmt *DSNew = + SemaRef + .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), + SourceLocation(), SourceLocation()) + .getAs(); + + DeclStmts.push_back(DSNew); + DIndex++; + CIndex++; + } + + 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); + } + } + } + + int BOSize = BOStmts.size(); + if (BOSize == 0) { + Result = DeclStmts[DeclStmts.size() - 1]; + DeclStmts.erase(DeclStmts.end() - 1); + DIndex--; + CIndex--; + } 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); + } + if (CIndex > 0) + 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 SetArrayPointerMap(std::string APName, VarDecl *VD) { + assert(VD && "Passed null array pointers variable"); + ArrayPointerMap[APName] = VD; + } + + VarDecl *GetArrayPointerMap(std::string APName) { + std::map::iterator I = ArrayPointerMap.find(APName); + if (I != ArrayPointerMap.end()) + return I->second; + return nullptr; + } + + void SetArrayAssignedPointerMap(std::string AAPName, VarDecl *VD) { + assert(VD && "Passed null array pointers variable"); + ArrayAssignedPointerMap[AAPName] = VD; + } + + VarDecl *GetArrayAssignedPointerMap(std::string AAPName) { + std::map::iterator I = + ArrayAssignedPointerMap.find(AAPName); + if (I != ArrayAssignedPointerMap.end()) + return I->second; + return nullptr; + } +}; + +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(If->getBeginLoc(), Stmts, + If->getEndLoc(), false) + .getAs(); + If->setElse(ES); + } + + if (HasStatement && !isRefactorStmt(TS)) { + std::vector Stmts; + Stmts.push_back(TS); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + TS = BaseTransform::RebuildCompoundStmt(If->getBeginLoc(), Stmts, + If->getEndLoc(), 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(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), false) + .getAs(); + WS->setBody(Body); + } + 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(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), false) + .getAs(); + DS->setBody(Body); + } + return BaseTransform::TransformDoStmt(DS); + } + + 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(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), 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(SS->getBeginLoc(), Stmts, + SS->getEndLoc(), 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(SS->getBeginLoc(), Stmts, + SS->getEndLoc(), 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( + S->getBeginLoc(), Statements, S->getEndLoc(), false) + .getAs(); + return CS; + } + + StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { + return S; + } +}; + +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; } + + FunctionDecl *TransformFunctionDecl(FunctionDecl *D) { + FunctionDecl *NewFD = 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, {}); + + SourceLocation SLoc = D->getBeginLoc(); + SourceLocation NLoc = D->getNameInfo().getLoc(); + SourceLocation ELoc = D->getEndLoc(); + TypeSourceInfo *Tinfo = D->getTypeSourceInfo(); + std::string FName = std::string(D->getIdentifier()->getName()); + + if (isa(D)) { + BSCMethodDecl *BMD = cast(D); + NewFD = buildAsyncBSCMethodDecl( + SemaRef.Context, D->getDeclContext(), SLoc, NLoc, ELoc, + &(SemaRef.Context.Idents).get(FName), FuncType, Tinfo, SC_None, + BMD->getExtendedType()); + } else { + NewFD = buildAsyncFuncDecl(SemaRef.Context, D->getDeclContext(), SLoc, + NLoc, &(SemaRef.Context.Idents).get(FName), + FuncType, Tinfo); + } + SmallVector ParmVarDecls; + for (const auto &I : D->parameters()) { + ParmVarDecl *PVD = ParmVarDecl::Create( + SemaRef.Context, NewFD, SourceLocation(), SourceLocation(), + &(SemaRef.Context.Idents).get(I->getName()), I->getType(), nullptr, + SC_None, nullptr); + ParmVarDecls.push_back(PVD); + } + NewFD->setParams(ParmVarDecls); + NewFD->setLexicalDeclContext(SemaRef.Context.getTranslationUnitDecl()); + + 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); + body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); + } + + Stmt *FuncBody = BaseTransform::TransformStmt(body).getAs(); + NewFD->setBody(FuncBody); + } + return NewFD; + } + + 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; + } +}; + +/** + * Build the Future init declaration + */ +static FunctionDecl *buildFutureInitFunctionDeclaration(Sema &S, + FunctionDecl *FD, + QualType FuncRetType) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + DeclarationName funcName = FD->getDeclName(); + + 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(); + + FunctionDecl *NewFD = nullptr; + if (isa(FD)) { + BSCMethodDecl *BMD = cast(FD); + NewFD = + buildAsyncBSCMethodDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, + ELoc, &(S.Context.Idents).get(FName), FuncType, + Tinfo, SC_None, BMD->getExtendedType()); + } 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; +} + +// build struct Future for async function +static RecordDecl *buildFutureRecordDecl( + Sema &S, FunctionDecl *FD, ArrayRef Args, + std::vector> LocalVarList, + QualType ContType) { + 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())); + } + + bool IsCPS = S.Context.getLangOpts().ContinuationPassingStyle; + for (unsigned I = 0; I != Args.size(); ++I) { + auto *AE = cast(Args[I])->getSubExpr(); + CallExpr *CE = dyn_cast(AE); + QualType AEType; + if (CE) { + FunctionDecl *AwaitFD = + dyn_cast_or_null(CE->getCalleeDecl()); + AEType = + AwaitFD == nullptr + ? AE->getType() + : S.Context.getQualifiedType( + AE->getType(), AwaitFD->getReturnType().getQualifiers()); + } else + AEType = AE->getType(); + + if (!S.IsBSCCompatibleAsyncType(AEType)) { + QualType AwaitableType; + if (IsCPS) { + AwaitableType = + lookupGenericType(S, FD->getBeginLoc(), AEType, "__Trait_Awaitable", + "continuation.hbs"); + } else { + AwaitableType = lookupGenericType(S, FD->getBeginLoc(), AEType, + "__Trait_Future", "future.hbs"); + } + if (AwaitableType.isNull()) { + return nullptr; + } + + RecordDecl *AwaitableStruct = AwaitableType->getAsRecordDecl(); + assert(AwaitableStruct != nullptr); + + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getRecordType(AwaitableStruct))); + } else if (implementedAsyncType(S, AEType)) { + const RecordType *FutureType = + dyn_cast(AEType.getDesugaredType(S.Context)); + RecordDecl *FutureDecl = FutureType->getDecl(); + assert(FutureDecl != nullptr && + "struct future of async function is null"); + + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getRecordType(FutureDecl))); + } 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; + if (VarType.isConstQualified()) { + VarType.removeLocalConst(); + } + addAsyncRecordDecl(S.Context, VarName, VarType, SLoc, ELoc, RD); + } + + const std::string FutureStateName = "__future_state"; + addAsyncRecordDecl(S.Context, FutureStateName, S.Context.IntTy, SLoc, ELoc, + RD); + if (IsCPS) { + const std::string ContinuationName = "__cont"; + addAsyncRecordDecl(S.Context, ContinuationName, ContType, SLoc, ELoc, RD); + } + RD->completeDefinition(); + S.PushOnScopeChains(RD, S.getCurScope(), true); + return RD; +} + +static FunctionDecl *buildFutureInitFunctionDefinition(Sema &S, RecordDecl *RD, + FunctionDecl *FD, + // RecordDecl *FatPointerRD, + // VarDecl *VtableInit, + FunctionDecl *FDecl) { + FunctionDecl *NewFD = nullptr; + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + FunctionDecl::param_const_iterator pi; + + if (isa(FD)) { + BSCMethodDecl *BMD = cast(FD); + NewFD = buildAsyncBSCMethodDecl( + S.Context, FDecl->getDeclContext(), SLoc, NLoc, ELoc, + &(S.Context.Idents).get(FDecl->getName().str()), FDecl->getType(), + FDecl->getTypeSourceInfo(), SC_None, BMD->getExtendedType()); + } else { + NewFD = buildAsyncFuncDecl(S.Context, FDecl->getDeclContext(), SLoc, NLoc, + &(S.Context.Idents).get(FDecl->getName().str()), + FDecl->getType(), FDecl->getTypeSourceInfo()); + } + + 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); + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + Sema::ContextRAII savedContext(S, NewFD); + LocalInstantiationScope Scope(S); + 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, SLoc, ELoc); + std::vector Stmts; + Stmts.push_back(DataDS); + + std::string CallocName = "calloc"; + + DeclContext::lookup_result CallocDecls = + S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(CallocName))); + FunctionDecl *CallocFunc = nullptr; + if (CallocDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = CallocDecls.begin(), + E = CallocDecls.end(); + I != E; ++I) { + if (isa(*I)) { + CallocFunc = dyn_cast(*I); + break; + } + } + } else { + S.Diag(FD->getBeginLoc(), diag::err_function_not_found) + << CallocName << ""; + return nullptr; + } + + llvm::APInt OneResultVal(S.Context.getTargetInfo().getIntWidth(), 1); + Expr *One = IntegerLiteral::Create(S.Context, OneResultVal, S.Context.IntTy, + SourceLocation()); + + Expr *CallocRef = + S.BuildDeclRefExpr(CallocFunc, CallocFunc->getType(), VK_LValue, NLoc); + CallocRef = S.ImpCastExprToType( + CallocRef, S.Context.getPointerType(CallocRef->getType()), + CK_FunctionToPointerDecay) + .get(); + // bsc: sizeof(struct __Futurex) + Expr *SizeOfExpr = + S.CreateUnaryExprOrTypeTraitExpr( + S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(RD)), + NLoc, UETT_SizeOf, SourceRange()) + .get(); + SmallVector Args; + Args.push_back(One); + Args.push_back(SizeOfExpr); + + // bsc: calloc(1, sizeof(struct __Futurex)) + Expr *CE = S.BuildCallExpr(nullptr, CallocRef, 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); + + // bsc: if (data == 0) + llvm::APInt ZeroResultVal(S.Context.getTargetInfo().getIntWidth(), 0); + Expr *Zero = IntegerLiteral::Create(S.Context, ZeroResultVal, S.Context.IntTy, + SourceLocation()); + Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_EQ, + /*LHSExpr=*/DataRef, /*RHSExpr=*/Zero) + .get(); + + Sema::ConditionResult IfCond = S.ActOnCondition( + nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); + + // bsc: exit(1); + std::string ExitName = "exit"; + + DeclContext::lookup_result ExitDecls = + S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(ExitName))); + FunctionDecl *ExitFunc = nullptr; + if (ExitDecls.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = ExitDecls.begin(), + E = ExitDecls.end(); + I != E; ++I) { + if (isa(*I)) { + ExitFunc = dyn_cast(*I); + break; + } + } + } else { + S.Diag(FD->getBeginLoc(), diag::err_function_not_found) + << ExitName << ""; + return nullptr; + } + + Expr *ExitRef = + S.BuildDeclRefExpr(ExitFunc, ExitFunc->getType(), VK_LValue, NLoc); + ExitRef = + S.ImpCastExprToType(ExitRef, S.Context.getPointerType(ExitRef->getType()), + CK_FunctionToPointerDecay) + .get(); + + SmallVector ExitArgs = {One}; + Expr *ExitCE = S.BuildCallExpr(nullptr, ExitRef, SourceLocation(), ExitArgs, + SourceLocation()) + .get(); + // Current code: if (data == 0) exit(1); + // TODO: before exit(1) function, hope there is printf("calloc failed\n") + // function to prompt for calloc failure. and it need to import header file + // "stdio.h". + SmallVector BodyStmts = {ExitCE}; + Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), + SourceLocation(), SourceLocation()); + Stmt *If = S.BuildIfStmt(SourceLocation(), IfStatementKind::Ordinary, + /*LPL=*/SourceLocation(), /*Init=*/nullptr, IfCond, + /*RPL=*/SourceLocation(), /*Body=*/Body, + SourceLocation(), nullptr) + .get(); + Stmts.push_back(If); + + 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()); + + 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; + break; + } + } + + 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, SLoc, ELoc); + // Stmts.push_back(FatPointerDS); + + // SmallVector InitExprs; + Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); + // 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); + // No need for ImplicitCastExpr since BuildReturnStmt will generate for us. + Stmt *RS = S.BuildReturnStmt(NLoc, FutureRefExpr).get(); + Stmts.push_back(RS); + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + // S.PopDeclContext(); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + return NewFD; +} + +// Logic for generating the procedure to free a future object: +// @code +// if (FutureObj != 0) { +// FreeFuncExpr(FutureObj); +// FutureObj = (void*)0; +// } +// @endcode +static Stmt * +buildIfStmtForFreeFutureObj(Sema &S, Expr *PtrExpr, Expr *FreeFuncExpr, + SourceLocation Loc = SourceLocation()) { + llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), 0); + Expr *IntegerExpr = IntegerLiteral::Create(S.Context, ResultVal, + S.Context.IntTy, SourceLocation()); + // generating condition + Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_NE, + /*LHSExpr=*/PtrExpr, /*RHSExpr=*/IntegerExpr) + .get(); + Sema::ConditionResult IfCond = S.ActOnCondition( + nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); + + // generating free call + QualType Ty = S.Context.VoidPtrTy; + Expr *FreeArg = PtrExpr; + if (PtrExpr->getType() != Ty) { + FreeArg = CStyleCastExpr::Create( + S.Context, Ty, VK_PRValue, CK_BitCast, FreeArg, nullptr, + FPOptionsOverride(), + S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), + SourceLocation(), SourceLocation()); + } + std::vector FreeArgs{FreeArg}; + Expr *FreeFuncCall = S.BuildCallExpr(nullptr, FreeFuncExpr, SourceLocation(), + FreeArgs, SourceLocation()) + .get(); + // generating null assignment + Expr *RAssignExpr = CStyleCastExpr::Create( + S.Context, Ty, VK_PRValue, CK_NullToPointer, IntegerExpr, nullptr, + FPOptionsOverride(), + S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), + SourceLocation(), SourceLocation()); + if (PtrExpr->getType() != Ty) { + RAssignExpr = CStyleCastExpr::Create( + S.Context, PtrExpr->getType(), VK_PRValue, CK_BitCast, RAssignExpr, + nullptr, FPOptionsOverride(), + S.Context.getTrivialTypeSourceInfo(PtrExpr->getType(), + SourceLocation()), + SourceLocation(), SourceLocation()); + } + Expr *NullptrAssign = + S.BuildBinOp(nullptr, SourceLocation(), BO_Assign, + /*LHSExpr=*/PtrExpr, /*RHSExpr=*/RAssignExpr) + .get(); + + SmallVector BodyStmts = {FreeFuncCall, NullptrAssign}; + Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), + SourceLocation(), SourceLocation()); + + Stmt *If = S.BuildIfStmt(Loc, IfStatementKind::Ordinary, + /*LPL=*/Loc, /*Init=*/nullptr, IfCond, + /*RPL=*/Loc, Body, Loc, nullptr) + .get(); + return If; +} + +static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, + FunctionDecl *FD, bool IsOptimization) { + SourceLocation SLoc = FD->getBeginLoc(); + SourceLocation NLoc = FD->getNameInfo().getLoc(); + SourceLocation ELoc = FD->getEndLoc(); + + 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, ELoc, &(S.Context.Idents).get(FName), FuncType, + nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); + 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; + + auto StartsWith = [](const std::string &str, const std::string &prefix) { + if (str.length() >= prefix.length()) { + return 0 == str.compare(0, prefix.length(), prefix); + } + return false; + }; + + std::stack Futures; + for (RecordDecl::field_iterator FieldIt = RD->field_begin(); + FieldIt != RD->field_end(); ++FieldIt) { + if (FieldIt->getType().getTypePtr()->isBSCAsyncType(S.Context) && + StartsWith(FieldIt->getDeclName().getAsString(), "Ft_")) { + 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()); + + // Generating `FutureExpr` as followed: + // @code + // this.Ft_ + // @endcode + 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; + } + } + + // Generating `VtableExpr` as followed: + // @code + // this.Ft_.vtable + // @endcode + 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_NoOp, 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; + break; + } + } + + Expr *DataExpr = S.BuildMemberExpr( + FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PtrField, + DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, + DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); + + Expr *FreeFuncExpr = S.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FreeFuncField, + DeclAccessPair::make(FatPointerRD, FreeFuncField->getAccess()), false, + DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, + OK_Ordinary); + Stmt *If = buildIfStmtForFreeFutureObj(S, DataExpr, FreeFuncExpr); + Stmts.push_back(If); + } + + if (!IsOptimization) { + 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); + Expr *FutureObj = + S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); + Stmt *If = buildIfStmtForFreeFutureObj(S, FutureObj, FreeFuncRef); + Stmts.push_back(If); + } + + CompoundStmt *CS = + CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); + NewFD->setBody(CS); + sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; + S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; +} + +} // namespace clang + +#endif // ENABLE_BSC + +#endif // LLVM_CLANG_AST_WALKERBSC_H \ No newline at end of file diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 3bc282c52d58..5d71e6bbcb7c 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2382,9 +2382,7 @@ public: #if ENABLE_BSC /// Check if the type is the BSC future type. - bool isBSCFutureType() const; - /// Check if the type is the BSC Awaitable type. - bool isBSCAwaitableType() const; + bool isBSCAsyncType(const ASTContext &Context) const; #endif /// Return the implicit lifetime for this type, which must not be dependent. diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 6530a91d7f78..0fe0e1085dd5 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -260,6 +260,7 @@ LANGOPT(RenderScript , 1, 0, "RenderScript") LANGOPT(HLSL, 1, 0, "HLSL") #if ENABLE_BSC LANGOPT(BSC, 1, 0, "BSC") +LANGOPT(ContinuationPassingStyle, 1, 0, "continuation passing style") LANGOPT(DisableOwnershipCheck, 1, 0, "disable ownership check") ENUM_LANGOPT(NullabilityCheck, NullCheckZone, 2, NC_SAFE, "nullability check") #endif diff --git a/clang/include/clang/Driver/BSC/BSCOptions.td b/clang/include/clang/Driver/BSC/BSCOptions.td index f07573965822..0a1b352f52a7 100644 --- a/clang/include/clang/Driver/BSC/BSCOptions.td +++ b/clang/include/clang/Driver/BSC/BSCOptions.td @@ -4,6 +4,8 @@ def rewrite_bsc : Flag<["-"], "rewrite-bsc">, Flags<[CC1Option]>, Group; def rewrite_bsc_line : Flag<["-"], "line">, Flags<[CC1Option]>, HelpText<"Insert line info when rewrite BSC">; +def continuation_passing_style : Flag<["-"], "CPS">, Flags<[CC1Option]>, + HelpText<"Coroutine transformation on continuation passing style">, MarshallingInfoFlag>; def disable_ownership_check : Flag<["-"], "disable-ownership-check">, Flags<[CC1Option]>, HelpText<"Disable ownership check">, MarshallingInfoFlag>; def nullability_check : Joined<["-"], "nullability-check=">, Flags<[CC1Option]>, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9a18ce83a382..012f923a21ec 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3221,9 +3221,10 @@ public: /// Entry functions for desugaring async functions. SmallVector ActOnAsyncFunctionDeclaration(FunctionDecl *FD); SmallVector ActOnAsyncFunctionDefinition(FunctionDecl *FD); + SmallVector ActOnAsyncCPSFunctionDeclaration(FunctionDecl *FD); + SmallVector ActOnAsyncCPSFunctionDefinition(FunctionDecl *FD); - bool IsBSCCompatibleFutureType(QualType Ty); - bool IsBSCCompatibleAwaitableType(QualType Ty); + bool IsBSCCompatibleAsyncType(QualType Ty); // BSC Destructor related. BSCMethodDecl *getOrInsertBSCDestructor(RecordDecl *RD); diff --git a/clang/lib/AST/BSC/TypeBSC.cpp b/clang/lib/AST/BSC/TypeBSC.cpp index dfa9680cacfc..b73cfdf574f5 100644 --- a/clang/lib/AST/BSC/TypeBSC.cpp +++ b/clang/lib/AST/BSC/TypeBSC.cpp @@ -283,21 +283,17 @@ bool RecordType::withBorrowFields() const { return false; } -bool Type::isBSCFutureType() const { +bool Type::isBSCAsyncType(const ASTContext &Context) const { + bool IsCPS = Context.getLangOpts().ContinuationPassingStyle; + std::string PrefixName = ""; + if (IsCPS) + PrefixName = "__Trait_Awaitable"; + else + PrefixName = "__Trait_Future"; if (const auto *RT = getAs()) { RecordDecl *RD = RT->getAsRecordDecl(); if (isa(RD)) { - return RD->getNameAsString() == "__Trait_Future"; - } - } - return false; -} - -bool Type::isBSCAwaitableType() const { - if (const auto *RT = getAs()) { - RecordDecl *RD = RT->getAsRecordDecl(); - if (isa(RD)) { - return RD->getNameAsString() == "__Trait_Awaitable"; + return RD->getNameAsString() == PrefixName; } } return false; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 8bca3ce34aae..e6277b154e5c 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4818,6 +4818,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, #if ENABLE_BSC if (Args.getLastArg(options::OPT_opt_string)) Args.AddLastArg(CmdArgs, options::OPT_opt_string); + if (Args.hasArg(options::OPT_continuation_passing_style)) + CmdArgs.push_back("-CPS"); if (Args.hasArg(options::OPT_disable_ownership_check)) CmdArgs.push_back("-disable-ownership-check"); if (Args.hasArg(options::OPT_nullability_check)) { diff --git a/clang/lib/Headers/bsc_include/continuation.hbs b/clang/lib/Headers/bsc_include/continuation.hbs index 46cb8c51e2db..afbfdf21ed8a 100644 --- a/clang/lib/Headers/bsc_include/continuation.hbs +++ b/clang/lib/Headers/bsc_include/continuation.hbs @@ -5,12 +5,10 @@ struct Void{}; trait Continuation { trait Continuation* resume(This* this, T* arg); - // void setResult(This* this, T* arg); }; trait Awaitable { trait Continuation* awaitable(This* this, trait Continuation* k); - // void setParent(This* this, trait Continuation* k); void free(This *this); }; #endif /* continuation.hbs */ \ No newline at end of file diff --git a/clang/lib/Parse/BSC/ParseDeclBSC.cpp b/clang/lib/Parse/BSC/ParseDeclBSC.cpp index 808ee169269b..16ce5c91399d 100644 --- a/clang/lib/Parse/BSC/ParseDeclBSC.cpp +++ b/clang/lib/Parse/BSC/ParseDeclBSC.cpp @@ -450,9 +450,11 @@ void Parser::ParseTraitSpecifier(SourceLocation StartLoc, DeclSpec &DS, RecordDecl *TraitVtableRD = Actions.ActOnDesugarVtableRecord(TD); RecordDecl *TraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD); TD->setTrait(TraitRD); - RecordDecl *OwnedTraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, true, false); + RecordDecl *OwnedTraitRD = + Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, true, false); TD->setOwnedTrait(OwnedTraitRD); - RecordDecl *BorrowTraitRD = Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, false, true); + RecordDecl *BorrowTraitRD = + Actions.ActOnDesugarTraitRecord(TD, TraitVtableRD, false, true); TD->setBorrowTrait(BorrowTraitRD); TD->setVtable(TraitVtableRD); } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 3faa4ceba9ca..3ce02f67da84 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2158,8 +2158,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, #if ENABLE_BSC FunctionDecl *FD = dyn_cast_or_null(TheDecl); if (getLangOpts().BSC && FD) { - SmallVector Decls = - Actions.ActOnAsyncFunctionDefinition(FD); + SmallVector Decls; + if (getLangOpts().ContinuationPassingStyle) + Decls = Actions.ActOnAsyncCPSFunctionDefinition(FD); + else + Decls = Actions.ActOnAsyncFunctionDefinition(FD); return Actions.BuildDeclaratorGroup(Decls); } #endif @@ -2236,7 +2239,11 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, if (FirstDecl) { FunctionDecl *FD = dyn_cast_or_null(FirstDecl); if (getLangOpts().BSC && FD && FD->isAsyncSpecified()) { - SmallVector Decls = Actions.ActOnAsyncFunctionDeclaration(FD); + SmallVector Decls; + if (getLangOpts().ContinuationPassingStyle) + Decls = Actions.ActOnAsyncCPSFunctionDeclaration(FD); + else + Decls = Actions.ActOnAsyncFunctionDeclaration(FD); for (auto &D : Decls) { DeclsInGroup.push_back(D); } diff --git a/clang/lib/Sema/BSC/SemaBSCContinuation.cpp b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp index 128a24cd8835..5ba081e138ea 100644 --- a/clang/lib/Sema/BSC/SemaBSCContinuation.cpp +++ b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp @@ -13,642 +13,18 @@ #if ENABLE_BSC -#include -#include -#include - #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 "clang/AST/BSC/AsyncBSC.h" using namespace clang; using namespace sema; -static RecordDecl *buildAsyncDataRecord(ASTContext &C, StringRef Name, - SourceLocation StartLoc, - SourceLocation EndLoc, - RecordDecl::TagKind TK) { - RecordDecl *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, SourceLocation EndLoc, - DeclarationName N, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, QualType ET) { - // TODO: inline should be passed. - BSCMethodDecl *NewDecl = BSCMethodDecl::Create( - C, DC, StartLoc, DeclarationNameInfo(N, NLoc), T, TInfo, SC, false, false, - ConstexprSpecKind::Unspecified, EndLoc); - if (auto RD = dyn_cast_or_null(DC)) { - C.BSCDeclContextMap[RD->getTypeForDecl()] = DC; - NewDecl->setHasThisParam(true); // bug - NewDecl->setExtendedType(ET); - } - return NewDecl; -} - -std::string GetPrefix(QualType T) { - std::string ExtendedTypeStr = T.getCanonicalType().getAsString(); - for (int i = ExtendedTypeStr.length() - 1; i >= 0; i--) { - if (ExtendedTypeStr[i] == ' ') { - ExtendedTypeStr.replace(i, 1, "_"); - } - } - return ExtendedTypeStr; -} - -static BSCMethodDecl *lookupBSCMethodInRecord(Sema &S, std::string FuncName, - DeclContext *RecordDecl) { - LookupResult Result( - S, - DeclarationNameInfo(&(S.Context.Idents).get(FuncName), SourceLocation()), - S.LookupOrdinaryName); - S.LookupQualifiedName(Result, RecordDecl); - BSCMethodDecl *BSCMethod = nullptr; - if (!Result.empty()) - BSCMethod = dyn_cast_or_null(Result.getFoundDecl()); - return BSCMethod; -} - -static bool implementedAwaitableType(Sema &S, QualType Ty) { - RecordDecl *FutureRD = nullptr; - if (const auto *RT = Ty->getAs()) { - FutureRD = RT->getAsRecordDecl(); - } - - if (!FutureRD) - return false; - BSCMethodDecl *PollFD = lookupBSCMethodInRecord(S, "awaitable", FutureRD); - if (PollFD == nullptr) - return false; - - BSCMethodDecl *FreeFD = lookupBSCMethodInRecord(S, "free", FutureRD); - if (FreeFD == nullptr) - return false; - - return true; -} - -// Logic for generating the procedure to free a future object: -// @code -// if (FutureObj != 0) { -// FreeFuncExpr(FutureObj); -// FutureObj = (void*)0; -// } -// @endcode -static Stmt * -buildIfStmtForFreeFutureObj(Sema &S, Expr *PtrExpr, Expr *FreeFuncExpr, - SourceLocation Loc = SourceLocation()) { - llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), 0); - Expr *IntegerExpr = IntegerLiteral::Create(S.Context, ResultVal, - S.Context.IntTy, SourceLocation()); - // generating condition - Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_NE, - /*LHSExpr=*/PtrExpr, /*RHSExpr=*/IntegerExpr) - .get(); - Sema::ConditionResult IfCond = S.ActOnCondition( - nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); - - // generating free call - QualType Ty = S.Context.VoidPtrTy; - Expr *FreeArg = PtrExpr; - if (PtrExpr->getType() != Ty) { - FreeArg = CStyleCastExpr::Create( - S.Context, Ty, VK_PRValue, CK_BitCast, FreeArg, nullptr, - FPOptionsOverride(), - S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), - SourceLocation(), SourceLocation()); - } - std::vector FreeArgs{FreeArg}; - Expr *FreeFuncCall = S.BuildCallExpr(nullptr, FreeFuncExpr, SourceLocation(), - FreeArgs, SourceLocation()) - .get(); - // generating null assignment - Expr *RAssignExpr = CStyleCastExpr::Create( - S.Context, Ty, VK_PRValue, CK_NullToPointer, IntegerExpr, nullptr, - FPOptionsOverride(), - S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), - SourceLocation(), SourceLocation()); - if (PtrExpr->getType() != Ty) { - RAssignExpr = CStyleCastExpr::Create( - S.Context, PtrExpr->getType(), VK_PRValue, CK_BitCast, RAssignExpr, - nullptr, FPOptionsOverride(), - S.Context.getTrivialTypeSourceInfo(PtrExpr->getType(), - SourceLocation()), - SourceLocation(), SourceLocation()); - } - Expr *NullptrAssign = - S.BuildBinOp(nullptr, SourceLocation(), BO_Assign, - /*LHSExpr=*/PtrExpr, /*RHSExpr=*/RAssignExpr) - .get(); - - SmallVector BodyStmts = {FreeFuncCall, NullptrAssign}; - Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), - SourceLocation(), SourceLocation()); - - Stmt *If = S.BuildIfStmt(Loc, IfStatementKind::Ordinary, - /*LPL=*/Loc, /*Init=*/nullptr, IfCond, - /*RPL=*/Loc, Body, Loc, nullptr) - .get(); - return If; -} - -bool Sema::IsBSCCompatibleFutureType(QualType Ty) { - return implementedAwaitableType(*this, Ty) || - Ty.getTypePtr()->isBSCFutureType(); -} - -// TODO: leaf -bool Sema::IsBSCCompatibleAwaitableType(QualType Ty) { - return implementedAwaitableType(*this, Ty) || - Ty.getTypePtr()->isBSCAwaitableType(); -} - -namespace { -class LocalVarFinder : public StmtVisitor { - ASTContext &Context; - std::vector> LocalVarList; - std::map IdentifierNumber; - -public: - LocalVarFinder(ASTContext &Context) : Context(Context) {} - - 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)) { - if (VD->isExternallyVisible() || VD->isConstexpr() || - VD->isStaticLocal()) - continue; - - QualType QT = VD->getType(); - if (QT->hasTraitType()) - continue; - - Expr *Init = VD->getInit(); - // Do not need to transform constant variable with compile-time - // constant initializier. - const Expr *Culprit; - if (QT.isConstQualified() && Init && !Init->isValueDependent() && - Init->isConstantInitializer(Context, false, &Culprit)) - continue; - - std::string VDName = VD->getName().str(); - // May have several local variables which has same name, eg. - // @code - // async void f() { - // int c = 1; - // { - // int c = 2; - // } - // } - // @endcode - std::map::iterator I = - IdentifierNumber.find(VDName); - int VDNameNum = I != IdentifierNumber.end() ? I->second : 0; - IdentifierNumber[VDName] = VDNameNum + 1; - if (VDNameNum > 0) { - VDName = VDName + "_" + std::to_string(VDNameNum); - VD->setDeclName(&(Context.Idents).get(VDName)); - } - - LocalVarList.push_back(std::make_pair( - VD->getDeclName(), VD->getType())); - } - } - } - Visit(C); - } - } - } - std::vector> GetLocalVarList() const { - return LocalVarList; - } -}; - -class AwaitExprFinder : public StmtVisitor { - int AwaitCount = 0; - std::vector Args; - -public: - AwaitExprFinder() {} - - void VisitAwaitExpr(AwaitExpr *E) { - Visit(E->getSubExpr()); - Args.push_back(E); - AwaitCount++; - } - - void VisitStmt(Stmt *S) { - for (auto *C : S->children()) { - if (C) { - Visit(C); - } - } - } - - int GetAwaitExprNum() const { return AwaitCount; } - - std::vector GetAwaitExpr() const { return Args; } -}; - -static 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; -} - -/// Look for Illegal AwaitExpr -class IllegalAEFinder : public StmtVisitor { - Sema &SemaRef; - bool IsIllegal; - -public: - IllegalAEFinder(Sema &SemaRef) : SemaRef(SemaRef) { IsIllegal = 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 && !IsIllegal) - IsIllegal = CHasIllegalAwait; - - return CHasIllegalAwait; - } - - bool CheckAsyncFuncIllegalStmt(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"; - } 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 (!IsIllegal) - IsIllegal = true; - } - return IsContinue; - } else if (DeclStmt *DS = dyn_cast(S)) { - bool HasVar = false; - for (auto *D : DS->decls()) { - if (VarDecl *VD = dyn_cast(D)) { - if (isa(VD->getType())) { - HasVar = true; - break; - } - } - } - if (HasVar) { - ArgString = "VariableArrayType"; - SemaRef.Diag(S->getBeginLoc(), diag::err_async_func_unsupported) - << ArgString; - if (!IsIllegal) - IsIllegal = true; - return IsContinue; - } - return false; - } - - bool CHasIllegalAwait = hasAwaitExpr(S); - if (CHasIllegalAwait && !IsIllegal) - IsIllegal = 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) || - isa(C) || isa(C)) { - bool IsContinue = CheckAsyncFuncIllegalStmt(C); - if (IsContinue) - continue; - } - - Visit(C); - } - } - } - - 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 IsIllegal; } -}; - -static 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; -} - -static bool isRefactorStmt(Stmt *S) { - if (isa(S) || isa(S) || isa(S) || - isa(S) || isa(S) || isa(S)) - return true; - - return false; -} - -static QualType lookupGenericType(Sema &S, SourceLocation SLoc, QualType T, - std::string GenericDeclName) { - DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( - DeclarationName(&(S.Context.Idents).get(GenericDeclName))); - 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) - << GenericDeclName << "\"continuation.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, QualType ContType, 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(); - CallExpr *CE = dyn_cast(AE); - QualType AEType; - // TODO - if (CE) { - FunctionDecl *AwaitFD = - dyn_cast_or_null(CE->getCalleeDecl()); - AEType = - AwaitFD == nullptr - ? AE->getType() - : S.Context.getQualifiedType( - AE->getType(), AwaitFD->getReturnType().getQualifiers()); - } else - AEType = AE->getType(); - - if (!S.IsBSCCompatibleAwaitableType(AEType)) { - QualType AwaitableType = - lookupGenericType(S, FD->getBeginLoc(), AEType, "__Trait_Awaitable"); - if (AwaitableType.isNull()) { - return nullptr; - } - - RecordDecl *AwaitableStruct = AwaitableType->getAsRecordDecl(); - assert(AwaitableStruct != nullptr); - - LocalVarList.push_back(std::make_pair( - &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), - S.Context.getRecordType(AwaitableStruct))); - } else if (implementedAwaitableType(S, AEType)) { - const RecordType *FutureType = - dyn_cast(AEType.getDesugaredType(S.Context)); - RecordDecl *FutureDecl = FutureType->getDecl(); - assert(FutureDecl != nullptr && - "struct future of async function is null"); - - LocalVarList.push_back(std::make_pair( - &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), - S.Context.getRecordType(FutureDecl))); - } 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; - if (VarType.isConstQualified()) { - VarType.removeLocalConst(); - } - addAsyncRecordDecl(S.Context, VarName, VarType, SLoc, ELoc, RD); - } - - const std::string FutureStateName = "__future_state"; - addAsyncRecordDecl(S.Context, FutureStateName, S.Context.IntTy, SLoc, ELoc, - RD); - const std::string ContinuationName = "__cont"; - addAsyncRecordDecl(S.Context, ContinuationName, ContType, SLoc, ELoc, RD); - RD->completeDefinition(); - S.PushOnScopeChains(RD, S.getCurScope(), true); - return RD; -} - -static std::pair -generateVoidStruct(Sema &S, SourceLocation BLoc, SourceLocation ELoc) { +static RecordDecl *lookupVoidStruct(Sema &S, SourceLocation BLoc, + SourceLocation ELoc) { std::string Recordname = "Void"; DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( DeclarationName(&(S.Context.Idents).get(Recordname))); RecordDecl *VoidRD = nullptr; - bool IsExisted = false; if (Decls.isSingleResult()) { for (DeclContext::lookup_result::iterator I = Decls.begin(), @@ -659,87 +35,50 @@ generateVoidStruct(Sema &S, SourceLocation BLoc, SourceLocation ELoc) { break; } } - IsExisted = true; - } else if (Decls.empty()) { - VoidRD = buildAsyncDataRecord(S.Context, Recordname, BLoc, ELoc, - clang::TagDecl::TagKind::TTK_Struct); - VoidRD->startDefinition(); - VoidRD->completeDefinition(); - S.PushOnScopeChains(VoidRD, S.getCurScope(), true); - } - return std::make_pair(VoidRD, IsExisted); -} - -static std::string getBSCTypeName(QualType QT) { - std::string ExtendedTypeStr = QT.getAsString(); - int len = ExtendedTypeStr.length() - 1; - for (int i = len; i >= 0; i--) { - if (ExtendedTypeStr[i] == ' ') { - if (i == 0) { - ExtendedTypeStr.replace(i, 1, ""); - continue; - } - ExtendedTypeStr.replace(i, 1, "_"); - } else if (ExtendedTypeStr[i] == '*') { - // Since '*' is not allowed to appear in identifier, - // we replace it with 'P'. - // FIXME: it may conflict with user defined type Char_P. - ExtendedTypeStr.replace(i, 1, "P"); - } else if (ExtendedTypeStr[i] == '(') { - // Since '(' is not allowed to appear in identifier, - // we replace it with 'LP'. - ExtendedTypeStr.replace(i, 1, "LP"); - } else if (ExtendedTypeStr[i] == ')') { - // Since ')' is not allowed to appear in identifier, - // we replace it with 'RP'. - ExtendedTypeStr.replace(i, 1, "RP"); - } else if (ExtendedTypeStr[i] == '[') { - // Since '[' is not allowed to appear in identifier, - // we replace it with 'LB'. - ExtendedTypeStr.replace(i, 1, "LB"); - } else if (ExtendedTypeStr[i] == ']') { - // Since ']' is not allowed to appear in identifier, - // we replace it with 'RB'. - ExtendedTypeStr.replace(i, 1, "RB"); - } else if (ExtendedTypeStr[i] == ',') { - // Since ',' is not allowed to appear in identifier, - // we replace it with 'COMMA'. - ExtendedTypeStr.replace(i, 1, "COMMA"); - } + } else { + S.Diag(BLoc, diag::err_function_not_found) + << Recordname << "\"continuation.hbs\""; } - return ExtendedTypeStr; + return VoidRD; } // TODO: Can we first desugar to "impl trait Future<> for type", // then call the trait interface to desugar again. static VarDecl *buildContVtableInitDecl(Sema &S, FunctionDecl *FD, BSCMethodDecl *ResumeFunc, - QualType QT) { - std::string IName = "__Trait_Continuation_Vtable_" + getBSCTypeName(QT) + + QualType VtableTy) { + std::string IName = "__Trait_Continuation_Vtable_" + GetPrefix(VtableTy) + "_" + FD->getDeclName().getAsString(); DeclContext::lookup_result Res = S.Context.getTranslationUnitDecl()->lookup( DeclarationName(&(S.Context.Idents).get(IName))); - VarDecl *CVD = nullptr; + VarDecl *ContVtableVD = nullptr; if (Res.isSingleResult()) { for (DeclContext::lookup_result::iterator I = Res.begin(), E = Res.end(); I != E; ++I) { if (isa(*I)) { - CVD = dyn_cast(*I); + ContVtableVD = dyn_cast(*I); break; } } } - if (CVD) - return CVD; - - QualType ContinuationVtableType = lookupGenericType( - S, FD->getBeginLoc(), QT, "__Trait_Continuation_Vtable"); - VarDecl *VD = VarDecl::Create(S.Context, S.Context.getTranslationUnitDecl(), - FD->getBeginLoc(), FD->getEndLoc(), - &(S.Context.Idents).get(IName), - ContinuationVtableType, nullptr, SC_None); - DeclGroupRef DG(VD); - S.PushOnScopeChains(VD, S.getCurScope(), true); + if (ContVtableVD) + return ContVtableVD; + + QualType ContinuationVtableType = + lookupGenericType(S, FD->getBeginLoc(), VtableTy, + "__Trait_Continuation_Vtable", "continuation.hbs"); + (void)lookupGenericType(S, FD->getBeginLoc(), VtableTy, + "__Trait_Continuation", "continuation.hbs"); + (void)lookupGenericType(S, FD->getBeginLoc(), VtableTy, + "__Trait_Awaitable_Vtable", "continuation.hbs"); + (void)lookupGenericType(S, FD->getBeginLoc(), VtableTy, + "__Trait_Awaitable", "continuation.hbs"); + ContVtableVD = VarDecl::Create(S.Context, S.Context.getTranslationUnitDecl(), + FD->getBeginLoc(), FD->getEndLoc(), + &(S.Context.Idents).get(IName), + ContinuationVtableType, nullptr, SC_None); + DeclGroupRef DG(ContVtableVD); + S.PushOnScopeChains(ContVtableVD, S.getCurScope(), true); SmallVector InitExprs; QualType ResumeFuncType = S.Context.getPointerType(ResumeFunc->getType()); @@ -747,1209 +86,89 @@ static VarDecl *buildContVtableInitDecl(Sema &S, FunctionDecl *FD, VK_LValue, SourceLocation()); AwaitInit->HasBSCScopeSpec = true; AwaitInit = S.ImpCastExprToType( - AwaitInit, S.Context.getPointerType(AwaitInit->getType()), - CK_FunctionToPointerDecay) - .get(); - SmallVector Args; - Args.push_back(S.Context.VoidPtrTy); - Args.push_back(S.Context.getPointerType(QT)); - ResumeFuncType = S.Context.getPointerType( - S.Context.getFunctionType(ResumeFunc->getReturnType(), Args, {})); - AwaitInit = - S.BuildCStyleCastExpr(SourceLocation(), - S.Context.getTrivialTypeSourceInfo(ResumeFuncType), - SourceLocation(), AwaitInit) - .get(); - InitExprs.push_back(AwaitInit); - - Expr *ILE = - S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); - ILE->setType(ContinuationVtableType); - VD->setInit(ILE); - return VD; -} - -static VarDecl *buildAwaitVtableInitDecl(Sema &S, FunctionDecl *FD, - RecordDecl *AwaitVtableRD, - BSCMethodDecl *AwaitFunc, - BSCMethodDecl *FreeFunc) { - std::string IName = AwaitVtableRD->getDeclName().getAsString() + - FD->getDeclName().getAsString(); - VarDecl *VD = VarDecl::Create( - S.Context, S.Context.getTranslationUnitDecl(), FD->getBeginLoc(), - FD->getEndLoc(), &(S.Context.Idents).get(IName), - S.Context.getRecordType(AwaitVtableRD), nullptr, SC_None); - DeclGroupRef DG(VD); - S.PushOnScopeChains(VD, S.getCurScope(), true); - - SmallVector InitExprs; - SmallVector AwaitArgs; - const FunctionProtoType *FPT = - dyn_cast(AwaitFunc->getType()); - AwaitArgs.push_back(S.Context.VoidPtrTy); - AwaitArgs.push_back(FPT->getParamType(1)); - QualType AwaitFuncType = S.Context.getPointerType( - S.Context.getFunctionType(FPT->getReturnType(), AwaitArgs, {})); - // QualType AwaitFuncType = S.Context.getPointerType(AwaitFunc->getType()); - Expr *AwaitInit = S.BuildDeclRefExpr(AwaitFunc, AwaitFunc->getType(), - VK_LValue, SourceLocation()); - AwaitInit->HasBSCScopeSpec = true; - AwaitInit = S.ImpCastExprToType( - AwaitInit, S.Context.getPointerType(AwaitInit->getType()), - CK_FunctionToPointerDecay) - .get(); - AwaitInit = - S.BuildCStyleCastExpr(SourceLocation(), - S.Context.getTrivialTypeSourceInfo(AwaitFuncType), - SourceLocation(), AwaitInit) - .get(); - InitExprs.push_back(AwaitInit); - - SmallVector FreeArgs; - FPT = dyn_cast(FreeFunc->getType()); - FreeArgs.push_back(S.Context.VoidPtrTy); - QualType FreeFuncType = S.Context.getPointerType( - S.Context.getFunctionType(FPT->getReturnType(), FreeArgs, {})); - // QualType FreeFuncType = S.Context.getPointerType(FreeFunc->getType()); - Expr *FreeInit = S.BuildDeclRefExpr(FreeFunc, FreeFunc->getType(), VK_LValue, - SourceLocation()); - FreeInit->HasBSCScopeSpec = true; - FreeInit = S.ImpCastExprToType(FreeInit, - S.Context.getPointerType(FreeInit->getType()), - CK_FunctionToPointerDecay) - .get(); - FreeInit = - S.BuildCStyleCastExpr(SourceLocation(), - S.Context.getTrivialTypeSourceInfo(FreeFuncType), - SourceLocation(), FreeInit) - .get(); - InitExprs.push_back(FreeInit); - - Expr *ILE = - S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); - ILE->setType(S.Context.getRecordType(AwaitVtableRD)); - VD->setInit(ILE); - return VD; -} - -static FunctionDecl *buildFutureInitFunctionDefinition(Sema &S, RecordDecl *RD, - FunctionDecl *FD, - RecordDecl *AwaitableRD, - VarDecl *AwaitVtableInit, - FunctionDecl *FDecl) { - FunctionDecl *NewFD = nullptr; - SourceLocation SLoc = FD->getBeginLoc(); - SourceLocation NLoc = FD->getNameInfo().getLoc(); - SourceLocation ELoc = FD->getEndLoc(); - FunctionDecl::param_const_iterator pi; - - if (isa(FD)) { - BSCMethodDecl *BMD = cast(FD); - NewFD = buildAsyncBSCMethodDecl( - S.Context, FDecl->getDeclContext(), SLoc, NLoc, ELoc, - &(S.Context.Idents).get(FDecl->getName().str()), FDecl->getType(), - FDecl->getTypeSourceInfo(), SC_None, BMD->getExtendedType()); - } else { - NewFD = buildAsyncFuncDecl(S.Context, FDecl->getDeclContext(), SLoc, NLoc, - &(S.Context.Idents).get(FDecl->getName().str()), - FDecl->getType(), FDecl->getTypeSourceInfo()); - } - - 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); - 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, SLoc, ELoc); - std::vector Stmts; - Stmts.push_back(DataDS); - - std::string CallocName = "calloc"; - - DeclContext::lookup_result CallocDecls = - S.Context.getTranslationUnitDecl()->lookup( - DeclarationName(&(S.Context.Idents).get(CallocName))); - FunctionDecl *CallocFunc = nullptr; - if (CallocDecls.isSingleResult()) { - for (DeclContext::lookup_result::iterator I = CallocDecls.begin(), - E = CallocDecls.end(); - I != E; ++I) { - if (isa(*I)) { - CallocFunc = dyn_cast(*I); - break; - } - } - } else { - S.Diag(FD->getBeginLoc(), diag::err_function_not_found) - << CallocName << ""; - return nullptr; - } - - llvm::APInt OneResultVal(S.Context.getTargetInfo().getIntWidth(), 1); - Expr *One = IntegerLiteral::Create(S.Context, OneResultVal, S.Context.IntTy, - SourceLocation()); - - Expr *CallocRef = - S.BuildDeclRefExpr(CallocFunc, CallocFunc->getType(), VK_LValue, NLoc); - CallocRef = S.ImpCastExprToType( - CallocRef, S.Context.getPointerType(CallocRef->getType()), - CK_FunctionToPointerDecay) - .get(); - // bsc: sizeof(struct __Futurex) - Expr *SizeOfExpr = - S.CreateUnaryExprOrTypeTraitExpr( - S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(RD)), - NLoc, UETT_SizeOf, SourceRange()) - .get(); - SmallVector Args; - Args.push_back(One); - Args.push_back(SizeOfExpr); - - // bsc: calloc(1, sizeof(struct __Futurex)) - Expr *CE = S.BuildCallExpr(nullptr, CallocRef, 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); - - // bsc: if (data == 0) - llvm::APInt ZeroResultVal(S.Context.getTargetInfo().getIntWidth(), 0); - Expr *Zero = IntegerLiteral::Create(S.Context, ZeroResultVal, S.Context.IntTy, - SourceLocation()); - Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_EQ, - /*LHSExpr=*/DataRef, /*RHSExpr=*/Zero) - .get(); - - Sema::ConditionResult IfCond = S.ActOnCondition( - nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); - - // bsc: exit(1); - std::string ExitName = "exit"; - - DeclContext::lookup_result ExitDecls = - S.Context.getTranslationUnitDecl()->lookup( - DeclarationName(&(S.Context.Idents).get(ExitName))); - FunctionDecl *ExitFunc = nullptr; - if (ExitDecls.isSingleResult()) { - for (DeclContext::lookup_result::iterator I = ExitDecls.begin(), - E = ExitDecls.end(); - I != E; ++I) { - if (isa(*I)) { - ExitFunc = dyn_cast(*I); - break; - } - } - } else { - S.Diag(FD->getBeginLoc(), diag::err_function_not_found) - << ExitName << ""; - return nullptr; - } - - Expr *ExitRef = - S.BuildDeclRefExpr(ExitFunc, ExitFunc->getType(), VK_LValue, NLoc); - ExitRef = - S.ImpCastExprToType(ExitRef, S.Context.getPointerType(ExitRef->getType()), - CK_FunctionToPointerDecay) - .get(); - - SmallVector ExitArgs = {One}; - Expr *ExitCE = S.BuildCallExpr(nullptr, ExitRef, SourceLocation(), ExitArgs, - SourceLocation()) - .get(); - // Current code: if (data == 0) exit(1); - // TODO: before exit(1) function, hope there is printf("calloc failed\n") - // function to prompt for calloc failure. and it need to import header file - // "stdio.h". - SmallVector BodyStmts = {ExitCE}; - Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), - SourceLocation(), SourceLocation()); - Stmt *If = S.BuildIfStmt(SourceLocation(), IfStatementKind::Ordinary, - /*LPL=*/SourceLocation(), /*Init=*/nullptr, IfCond, - /*RPL=*/SourceLocation(), /*Body=*/Body, - SourceLocation(), nullptr) - .get(); - Stmts.push_back(If); - - 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()); - - 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; - break; - } - } - - 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(AwaitableRD), - S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(AwaitableRD), - SLoc), - SC_None); - - DeclGroupRef FatPointerDG(FatPointerVD); - DeclStmt *FatPointerDS = new (S.Context) DeclStmt(FatPointerDG, SLoc, ELoc); - Stmts.push_back(FatPointerDS); - - SmallVector InitExprs; - Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); - FutureRefExpr = - S.BuildCStyleCastExpr( - NLoc, S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), NLoc, - FutureRefExpr) - .get(); - - Expr *VtableRefExpr = S.BuildDeclRefExpr( - AwaitVtableInit, AwaitVtableInit->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(AwaitableRD)); - FatPointerVD->setInit(ILE); - - Expr *FatPointerRef = S.BuildDeclRefExpr( - FatPointerVD, FatPointerVD->getType(), VK_LValue, NLoc); - // No need for ImplicitCastExpr since BuildReturnStmt will generate for us. - Stmt *RS = S.BuildReturnStmt(NLoc, FatPointerRef).get(); - Stmts.push_back(RS); - - CompoundStmt *CS = - CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); - NewFD->setBody(CS); - S.PopDeclContext(); - sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); - return NewFD; -} - -static FunctionDecl * -buildFutureInitFunctionDeclaration(Sema &S, FunctionDecl *FD, RecordDecl *RD) { - SourceLocation SLoc = FD->getBeginLoc(); - SourceLocation NLoc = FD->getNameInfo().getLoc(); - SourceLocation ELoc = FD->getEndLoc(); - DeclarationName funcName = FD->getDeclName(); - QualType FuncRetType = S.Context.getRecordType(RD); - 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(); - - FunctionDecl *NewFD = nullptr; - if (isa(FD)) { - BSCMethodDecl *BMD = cast(FD); - NewFD = - buildAsyncBSCMethodDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, - ELoc, &(S.Context.Idents).get(FName), FuncType, - Tinfo, SC_None, BMD->getExtendedType()); - } 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; -} - -// build function struct Future for async function -static FunctionDecl * -buildFutureStructInitFunctionDefinition(Sema &S, RecordDecl *RD, - FunctionDecl *OriginFD) { - SourceLocation SLoc = OriginFD->getBeginLoc(); - SourceLocation NLoc = OriginFD->getNameInfo().getLoc(); - SourceLocation ELoc = OriginFD->getEndLoc(); - QualType FuncRetType = S.Context.getRecordType(RD); - SmallVector ParamTys; - FunctionDecl::param_const_iterator pi; - for (pi = OriginFD->param_begin(); pi != OriginFD->param_end(); pi++) { - ParamTys.push_back((*pi)->getType()); - } - - QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); - FunctionDecl *NewFD = nullptr; - - std::string FuncName = "__" + OriginFD->getName().str(); - if (isa(OriginFD)) { - BSCMethodDecl *BMD = cast(OriginFD); - NewFD = buildAsyncBSCMethodDecl( - S.Context, OriginFD->getDeclContext(), SLoc, NLoc, ELoc, - &(S.Context.Idents).get(FuncName), FuncType, - OriginFD->getTypeSourceInfo(), SC_None, BMD->getExtendedType()); - } else { - NewFD = buildAsyncFuncDecl(S.Context, OriginFD->getDeclContext(), SLoc, - NLoc, &(S.Context.Idents).get(FuncName), - FuncType, OriginFD->getTypeSourceInfo()); - } - - SmallVector ParmVarDecls; - for (const auto &I : OriginFD->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.PushFunctionScope(); - S.PushDeclContext(S.getCurScope(), NewFD); - - // Instantiate the struct object and assign values to it - std::string IName = "fi"; - VarDecl *VD = VarDecl::Create(S.Context, NewFD, SLoc, SLoc, - &(S.Context.Idents).get(IName), FuncRetType, - nullptr, SC_None); - InitListExpr *ILE = new (S.Context) - InitListExpr(S.Context, SourceLocation(), {}, SourceLocation()); - ILE->setType(FuncRetType); - S.AddInitializerToDecl(VD, ILE, /*DirectInit=*/false); - DeclGroupRef FutureDG(VD); - DeclStmt *FutureDS = new (S.Context) DeclStmt(FutureDG, SLoc, ELoc); - std::vector Stmts; - Stmts.push_back(FutureDS); - - Expr *StructFutureRef = - S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); - - RecordDecl::field_iterator FieldIt = RD->field_begin(), - Field_end = RD->field_end(); - llvm::SmallVector InitExprs; - for (pi = NewFD->param_begin(); - pi != NewFD->param_end() && FieldIt != Field_end; ++pi, ++FieldIt) { - DeclarationName Name = FieldIt->getDeclName(); - DeclarationNameInfo MemberNameInfo(Name, FieldIt->getLocation()); - Expr *LHSExpr = S.BuildMemberExpr( - StructFutureRef, false, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *FieldIt, - DeclAccessPair::make(*FieldIt, FieldIt->getAccess()), false, - MemberNameInfo, FieldIt->getType().getNonReferenceType(), VK_LValue, - OK_Ordinary); - ExprResult RHSER = - S.BuildDeclRefExpr(*pi, FieldIt->getType().getNonReferenceType(), - VK_LValue, SourceLocation()); - if (RHSER.isInvalid()) - return nullptr; - Expr *RHSExpr = RHSER.get(); - - 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; - break; - } - } - DeclarationName Name = FutureStateField->getDeclName(); - DeclarationNameInfo MemberNameInfo(Name, FutureStateField->getLocation()); - Expr *LHSExpr = S.BuildMemberExpr( - StructFutureRef, false, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *FutureStateField, - DeclAccessPair::make(*FutureStateField, FutureStateField->getAccess()), - false, MemberNameInfo, 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); - - // Generating: - // @code - // return fi; - // @endcode - // No need for ImplicitCastExpr since BuildReturnStmt will generate for us. - Stmt *RS = S.BuildReturnStmt(NLoc, StructFutureRef).get(); - Stmts.push_back(RS); - - CompoundStmt *CS = - CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); - NewFD->setBody(CS); - S.PopDeclContext(); - sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); - S.PushOnScopeChains(NewFD, S.getCurScope(), true); - return NewFD; -} - -namespace { -/** - * Visit a Stmt and return true if there's a recursive call to the provided Decl - */ -class RecursiveCallVisitor - : public ConstStmtVisitor { -public: - RecursiveCallVisitor(const Decl *FD) : FD(FD) {} - bool VisitCallExpr(const CallExpr *E) { - if (E->getCalleeDecl() == FD) - return true; - - return this->VisitStmt(static_cast(E)); - } - bool VisitStmt(const Stmt *S) { - for (auto *C : S->children()) { - if (C) { - if (Visit(C)) { - return true; - } - } - } - return false; - } - -private: - const Decl *FD; -}; -} // namespace - -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; } - - FunctionDecl *TransformFunctionDecl(FunctionDecl *D) { - FunctionDecl *NewFD = 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, {}); - - SourceLocation SLoc = D->getBeginLoc(); - SourceLocation NLoc = D->getNameInfo().getLoc(); - SourceLocation ELoc = D->getEndLoc(); - TypeSourceInfo *Tinfo = D->getTypeSourceInfo(); - std::string FName = std::string(D->getIdentifier()->getName()); - - if (isa(D)) { - BSCMethodDecl *BMD = cast(D); - NewFD = buildAsyncBSCMethodDecl( - SemaRef.Context, D->getDeclContext(), SLoc, NLoc, ELoc, - &(SemaRef.Context.Idents).get(FName), FuncType, Tinfo, SC_None, - BMD->getExtendedType()); - } else { - NewFD = buildAsyncFuncDecl(SemaRef.Context, D->getDeclContext(), SLoc, - NLoc, &(SemaRef.Context.Idents).get(FName), - FuncType, Tinfo); - } - SmallVector ParmVarDecls; - for (const auto &I : D->parameters()) { - ParmVarDecl *PVD = ParmVarDecl::Create( - SemaRef.Context, NewFD, SourceLocation(), SourceLocation(), - &(SemaRef.Context.Idents).get(I->getName()), I->getType(), nullptr, - SC_None, nullptr); - ParmVarDecls.push_back(PVD); - } - NewFD->setParams(ParmVarDecls); - NewFD->setLexicalDeclContext(SemaRef.Context.getTranslationUnitDecl()); - - 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); - body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, - SourceLocation(), false) - .getAs(); - } - - Stmt *FuncBody = BaseTransform::TransformStmt(body).getAs(); - NewFD->setBody(FuncBody); - } - return NewFD; - } - - 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 { - typedef TreeTransform BaseTransform; - Expr *PDRE; - RecordDecl *FutureRD; - FunctionDecl *FD; - std::vector DeclStmts; - int DIndex; - llvm::DenseMap> DMap; - std::map ArrayPointerMap; - std::map ArrayAssignedPointerMap; - -public: - TransformToAP(Sema &SemaRef, Expr *PDRE, RecordDecl *FutureRD, - FunctionDecl *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 = VD->getInit(); - Expr *LE = nullptr; - Expr *RE = nullptr; - QualType QT = VD->getType(); - - if (VD->isExternallyVisible() || VD->isConstexpr() || - VD->isStaticLocal()) - return S; - - // Do not need to transform constant variable with compile-time constant - // initializier. - const Expr *Culprit; - if (QT.isConstQualified() && Init && !Init->isValueDependent() && - Init->isConstantInitializer(SemaRef.Context, false, &Culprit)) - return S; - - 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 (Init && (QT->isArrayType() || QT->isRecordType())) { - Expr *CInit = BaseTransform::TransformExpr(Init).get(); - - 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); - - SemaRef.AddInitializerToDecl(ArgVDNew, CInit, /*DirectInit=*/false); - DeclStmt *DSNew = - SemaRef - .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(DSNew); - - RE = SemaRef.BuildDeclRefExpr(ArgVDNew, - VD->getType().getNonReferenceType(), - VK_LValue, SourceLocation()); - // No need for ImplicitCastExpr which will be generated - // by RebuildBinaryOperator in future. - DIndex++; - CIndex++; - - if (const ConstantArrayType *CA = dyn_cast(QT)) { - int Elements = SemaRef.Context.getConstantArrayElementCount(CA); - QualType SubQT = SemaRef.Context.getBaseElementType(QT); - - QualType Pty = SemaRef.Context.getPointerType(SubQT); - Expr *AssignedRVExpr = SemaRef.BuildDeclRefExpr( - ArgVDNew, ArgVDNew->getType(), VK_LValue, SourceLocation()); - TypeSourceInfo *AssignedType = - SemaRef.Context.getTrivialTypeSourceInfo(Pty); - Expr *AssignedCCE = BaseTransform::RebuildCStyleCastExpr( - SourceLocation(), AssignedType, - SourceLocation(), AssignedRVExpr) - .get(); - - std::string AssignedPtrName = - "__ASSIGNED_ARRAY_PTR_" + GetPrefix(SubQT); - VarDecl *AssignedPtrVar = - GetArrayAssignedPointerMap(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=*/false); - - DeclStmt *AssignedDS = - SemaRef - .ActOnDeclStmt( - SemaRef.ConvertDeclToDeclGroup(AssignedPtrVar), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(AssignedDS); - SetArrayAssignedPointerMap(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++; - - TypeSourceInfo *ArrayType = - SemaRef.Context.getTrivialTypeSourceInfo(Pty); - Expr *ArrayCCE = - BaseTransform::RebuildCStyleCastExpr( - SourceLocation(), ArrayType, SourceLocation(), LE) - .get(); - - std::string ArrayPtrName = "__ARRAY_PTR_" + GetPrefix(SubQT); - VarDecl *ArrayPtrVar = GetArrayPointerMap(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=*/false); - DeclStmt *ArrayDS = - SemaRef - .ActOnDeclStmt( - SemaRef.ConvertDeclToDeclGroup(ArrayPtrVar), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(ArrayDS); - SetArrayPointerMap(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 *FInit = new (SemaRef.Context) - DeclStmt(IDG, SourceLocation(), SourceLocation()); - - Expr *IDRE = - SemaRef.BuildDeclRefExpr(IArgVDNew, SemaRef.Context.IntTy, - VK_LValue, SourceLocation()); - 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, IDRE, 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(); - 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, FInit, 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 (Init == nullptr) { - 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); - SemaRef.ActOnUninitializedDecl(ArgVDNew); - DeclStmt *DSNew = - SemaRef - .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(DSNew); - DIndex++; - CIndex++; - } - - 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); - } - } - } - - int BOSize = BOStmts.size(); - if (BOSize == 0) { - Result = DeclStmts[DeclStmts.size() - 1]; - DeclStmts.erase(DeclStmts.end() - 1); - DIndex--; - CIndex--; - } 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); - } - if (CIndex > 0) - 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 SetArrayPointerMap(std::string APName, VarDecl *VD) { - assert(VD && "Passed null array pointers variable"); - ArrayPointerMap[APName] = VD; - } - - VarDecl *GetArrayPointerMap(std::string APName) { - std::map::iterator I = ArrayPointerMap.find(APName); - if (I != ArrayPointerMap.end()) - return I->second; - return nullptr; - } - - void SetArrayAssignedPointerMap(std::string AAPName, VarDecl *VD) { - assert(VD && "Passed null array pointers variable"); - ArrayAssignedPointerMap[AAPName] = VD; - } - - VarDecl *GetArrayAssignedPointerMap(std::string AAPName) { - std::map::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(If->getBeginLoc(), Stmts, - If->getEndLoc(), false) - .getAs(); - If->setElse(ES); - } - - if (HasStatement && !isRefactorStmt(TS)) { - std::vector Stmts; - Stmts.push_back(TS); - Sema::CompoundScopeRAII CompoundScope(SemaRef); - TS = BaseTransform::RebuildCompoundStmt(If->getBeginLoc(), Stmts, - If->getEndLoc(), 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(Body->getBeginLoc(), Stmts, - Body->getEndLoc(), false) - .getAs(); - WS->setBody(Body); - } - 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(Body->getBeginLoc(), Stmts, - Body->getEndLoc(), false) - .getAs(); - DS->setBody(Body); - } - return BaseTransform::TransformDoStmt(DS); - } - - 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(Body->getBeginLoc(), Stmts, - Body->getEndLoc(), false) - .getAs(); - FS->setBody(Body); - } - return BaseTransform::TransformForStmt(FS); - } + AwaitInit, S.Context.getPointerType(AwaitInit->getType()), + CK_FunctionToPointerDecay) + .get(); + SmallVector Args; + Args.push_back(S.Context.VoidPtrTy); + Args.push_back(S.Context.getPointerType(VtableTy)); + ResumeFuncType = S.Context.getPointerType( + S.Context.getFunctionType(ResumeFunc->getReturnType(), Args, {})); + AwaitInit = + S.BuildCStyleCastExpr(SourceLocation(), + S.Context.getTrivialTypeSourceInfo(ResumeFuncType), + SourceLocation(), AwaitInit) + .get(); + InitExprs.push_back(AwaitInit); - 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(SS->getBeginLoc(), Stmts, - SS->getEndLoc(), false) - .getAs(); - CS->setSubStmt(SS); - } - return BaseTransform::TransformCaseStmt(CS); - } + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(ContinuationVtableType); + ContVtableVD->setInit(ILE); + return ContVtableVD; +} - 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(SS->getBeginLoc(), Stmts, - SS->getEndLoc(), false) - .getAs(); - DS->setSubStmt(SS); - } - return BaseTransform::TransformDefaultStmt(DS); - } +static VarDecl *buildAwaitVtableInitDecl(Sema &S, FunctionDecl *FD, + RecordDecl *AwaitVtableRD, + BSCMethodDecl *AwaitFunc, + BSCMethodDecl *FreeFunc) { + std::string IName = AwaitVtableRD->getDeclName().getAsString() + "_" + + FD->getDeclName().getAsString(); + QualType AwaitVtableTy = S.Context.getRecordType(AwaitVtableRD); + VarDecl *VD = VarDecl::Create(S.Context, S.Context.getTranslationUnitDecl(), + FD->getBeginLoc(), FD->getEndLoc(), + &(S.Context.Idents).get(IName), AwaitVtableTy, + nullptr, SC_None); + DeclGroupRef DG(VD); + S.PushOnScopeChains(VD, S.getCurScope(), true); - StmtResult TransformCompoundStmt(CompoundStmt *S) { - if (S == nullptr) - return S; + SmallVector InitExprs; + SmallVector AwaitArgs; + const FunctionProtoType *FPT = + dyn_cast(AwaitFunc->getType()); + AwaitArgs.push_back(S.Context.VoidPtrTy); + AwaitArgs.push_back(FPT->getParamType(1)); + QualType AwaitFuncType = S.Context.getPointerType( + S.Context.getFunctionType(FPT->getReturnType(), AwaitArgs, {})); + Expr *AwaitInit = S.BuildDeclRefExpr(AwaitFunc, AwaitFunc->getType(), + VK_LValue, SourceLocation()); + AwaitInit->HasBSCScopeSpec = true; + AwaitInit = S.ImpCastExprToType( + AwaitInit, S.Context.getPointerType(AwaitInit->getType()), + CK_FunctionToPointerDecay) + .get(); + AwaitInit = + S.BuildCStyleCastExpr(SourceLocation(), + S.Context.getTrivialTypeSourceInfo(AwaitFuncType), + SourceLocation(), AwaitInit) + .get(); + InitExprs.push_back(AwaitInit); - 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( - S->getBeginLoc(), Statements, S->getEndLoc(), false) - .getAs(); - return CS; - } + SmallVector FreeArgs; + FPT = dyn_cast(FreeFunc->getType()); + FreeArgs.push_back(S.Context.VoidPtrTy); + QualType FreeFuncType = S.Context.getPointerType( + S.Context.getFunctionType(FPT->getReturnType(), FreeArgs, {})); + Expr *FreeInit = S.BuildDeclRefExpr(FreeFunc, FreeFunc->getType(), VK_LValue, + SourceLocation()); + FreeInit->HasBSCScopeSpec = true; + FreeInit = S.ImpCastExprToType(FreeInit, + S.Context.getPointerType(FreeInit->getType()), + CK_FunctionToPointerDecay) + .get(); + FreeInit = + S.BuildCStyleCastExpr(SourceLocation(), + S.Context.getTrivialTypeSourceInfo(FreeFuncType), + SourceLocation(), FreeInit) + .get(); + InitExprs.push_back(FreeInit); - StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { - return S; - } -}; -} // namespace + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(AwaitVtableTy); + VD->setInit(ILE); + return VD; +} namespace { class TransformARToCS : public TreeTransform { @@ -2186,8 +405,9 @@ public: if (CallExpr *CE = dyn_cast(AE)) { FunctionDecl *FutureInitFunc = CE->getDirectCallee(); if (FutureInitFunc) { - IsOptimization = !(CE->getType().getTypePtr()->isBSCAwaitableType()) && - implementedAwaitableType(SemaRef, CE->getType()); + IsOptimization = + !(CE->getType().getTypePtr()->isBSCAsyncType(SemaRef.Context)) && + implementedAsyncType(SemaRef, CE->getType()); // CHECK: Do I need all of this? std::vector CallArgs; for (unsigned I = 0; I < CE->getNumArgs(); ++I) { @@ -2285,7 +505,7 @@ public: InitListExpr(SemaRef.Context, SourceLocation(), {ParamExpr1, ParamExpr2}, SourceLocation()); QualType Ty = lookupGenericType(SemaRef, SourceLocation(), E->getType(), - "__Trait_Continuation"); + "__Trait_Continuation", "continuation.hbs"); ILE->setType(Ty); TypeSourceInfo *superTInfo = SemaRef.Context.getTrivialTypeSourceInfo(Ty); CompoundLiteralExpr *CLE = new (SemaRef.Context) CompoundLiteralExpr( @@ -2398,6 +618,10 @@ public: llvm::APInt ZeroVal(SemaRef.Context.getTargetInfo().getIntWidth(), 0); Expr *IntegerExpr = IntegerLiteral::Create( SemaRef.Context, ZeroVal, SemaRef.Context.IntTy, SourceLocation()); + IntegerExpr = ImplicitCastExpr::Create( + SemaRef.Context, SemaRef.Context.getPointerType(IntegerExpr->getType()), + CK_NullToPointer, IntegerExpr, nullptr, VK_PRValue, + FPOptionsOverride()); Expr *FreeDataBO = BinaryOperator::Create( SemaRef.Context, DataExpr, IntegerExpr, BO_Assign, DataExpr->getType(), VK_PRValue, OK_Ordinary, SourceLocation(), FPOptionsOverride()); @@ -2459,82 +683,14 @@ public: }; } // namespace -static BSCMethodDecl *buildResumeFunction(Sema &S, RecordDecl *RD, - FunctionDecl *FD, - FunctionDecl *PollFD, - QualType FuncRetType) { - SourceLocation SLoc = FD->getBeginLoc(); - SourceLocation NLoc = FD->getNameInfo().getLoc(); - SourceLocation ELoc = FD->getEndLoc(); - - std::string FName = "resume"; - QualType ParamType1 = S.Context.getPointerType(S.Context.getRecordType(RD)); - QualType ParamType2 = S.Context.VoidPtrTy; - SmallVector ParamTys; - ParamTys.push_back(ParamType1); - ParamTys.push_back(ParamType2); - - QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); - - BSCMethodDecl *NewFD = buildAsyncBSCMethodDecl( - S.Context, RD, SLoc, NLoc, ELoc, &(S.Context.Idents).get(FName), FuncType, - nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); - NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); - S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; - - SmallVector ParmVarDecls; - ParmVarDecl *PVD1 = ParmVarDecl::Create( - S.Context, NewFD, SourceLocation(), SourceLocation(), - &(S.Context.Idents).get("this"), ParamType1, nullptr, SC_None, nullptr); - ParmVarDecl *PVD2 = ParmVarDecl::Create( - S.Context, NewFD, SourceLocation(), SourceLocation(), - &(S.Context.Idents).get("arg"), ParamType2, nullptr, SC_None, nullptr); - ParmVarDecls.push_back(PVD1); - ParmVarDecls.push_back(PVD2); - NewFD->setParams(ParmVarDecls); - S.PushFunctionScope(); - S.PushDeclContext(S.getCurScope(), NewFD); - - std::vector ReturnStmts; - Expr *ThisExpr = - S.BuildDeclRefExpr(PVD1, ParamType1, VK_LValue, SourceLocation()); - ThisExpr = ImplicitCastExpr::Create(S.Context, ThisExpr->getType(), - CK_LValueToRValue, ThisExpr, nullptr, - VK_PRValue, FPOptionsOverride()); - Expr *ArgExpr = - S.BuildDeclRefExpr(PVD2, ParamType2, VK_LValue, SourceLocation()); - ArgExpr = S.BuildCStyleCastExpr( - SourceLocation(), - S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), - SourceLocation(), ArgExpr, false) - .get(); - SmallVector Args; - Args.push_back(ThisExpr); - Args.push_back(ArgExpr); - Expr *PollExpr = S.BuildDeclRefExpr(PollFD, PollFD->getType(), VK_LValue, - SourceLocation()); - Expr *CE = S.BuildCallExpr(nullptr, PollExpr, SLoc, Args, ELoc).get(); - Stmt *RS = S.BuildReturnStmt(SLoc, CE).get(); - ReturnStmts.push_back(RS); - CompoundStmt *CS = CompoundStmt::Create(S.Context, ReturnStmts, - FPOptionsOverride(), SLoc, ELoc); - NewFD->setBody(CS); - sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - S.PopDeclContext(); - S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); - S.PushOnScopeChains(NewFD, S.getCurScope(), true); - return NewFD; -} - -static BSCMethodDecl *buildAwaitFunction(Sema &S, RecordDecl *RD, - FunctionDecl *FD, FunctionDecl *PollFD, - QualType FuncRetType, - QualType ParamType2) { +static BSCMethodDecl * +buildAwaitFunction(Sema &S, RecordDecl *RD, FunctionDecl *FD, + FunctionDecl *StateTransDef, QualType FuncRetType, + QualType ParamType2, std::string FName) { SourceLocation SLoc = FD->getBeginLoc(); SourceLocation NLoc = FD->getNameInfo().getLoc(); SourceLocation ELoc = FD->getEndLoc(); - std::string FName = "awaitable"; QualType ParamType1 = S.Context.getPointerType(S.Context.getRecordType(RD)); SmallVector ParamTys; ParamTys.push_back(ParamType1); @@ -2569,9 +725,11 @@ static BSCMethodDecl *buildAwaitFunction(Sema &S, RecordDecl *RD, VK_PRValue, FPOptionsOverride()); Expr *ArgExpr = S.BuildDeclRefExpr(PVD2, ParamType2, VK_LValue, SourceLocation()); - ArgExpr = UnaryOperator::Create( - S.Context, ArgExpr, UO_AddrOf, S.Context.getPointerType(ParamType2), - VK_PRValue, OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); + if (!(ParamType2->isPointerType() && + ParamType2->getPointeeType()->isVoidType())) + ArgExpr = UnaryOperator::Create( + S.Context, ArgExpr, UO_AddrOf, S.Context.getPointerType(ParamType2), + VK_PRValue, OK_Ordinary, SourceLocation(), false, FPOptionsOverride()); ArgExpr = S.BuildCStyleCastExpr( SourceLocation(), S.Context.getTrivialTypeSourceInfo(S.Context.VoidPtrTy), @@ -2580,9 +738,10 @@ static BSCMethodDecl *buildAwaitFunction(Sema &S, RecordDecl *RD, SmallVector Args; Args.push_back(ThisExpr); Args.push_back(ArgExpr); - Expr *PollExpr = S.BuildDeclRefExpr(PollFD, PollFD->getType(), VK_LValue, - SourceLocation()); - Expr *CE = S.BuildCallExpr(nullptr, PollExpr, SLoc, Args, ELoc).get(); + Expr *StateTransExpr = S.BuildDeclRefExpr( + StateTransDef, StateTransDef->getType(), VK_LValue, SourceLocation()); + StateTransExpr->HasBSCScopeSpec = true; + Expr *CE = S.BuildCallExpr(nullptr, StateTransExpr, SLoc, Args, ELoc).get(); Stmt *RS = S.BuildReturnStmt(SLoc, CE).get(); ReturnStmts.push_back(RS); CompoundStmt *CS = CompoundStmt::Create(S.Context, ReturnStmts, @@ -2595,166 +754,8 @@ static BSCMethodDecl *buildAwaitFunction(Sema &S, RecordDecl *RD, return NewFD; } -static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, - FunctionDecl *FD, bool IsOptimization) { - SourceLocation SLoc = FD->getBeginLoc(); - SourceLocation NLoc = FD->getNameInfo().getLoc(); - SourceLocation ELoc = FD->getEndLoc(); - - 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, ELoc, &(S.Context.Idents).get(FName), FuncType, - nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); - 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; - - auto StartsWith = [](const std::string &str, const std::string &prefix) { - if (str.length() >= prefix.length()) { - return 0 == str.compare(0, prefix.length(), prefix); - } - return false; - }; - - std::stack Futures; - for (RecordDecl::field_iterator FieldIt = RD->field_begin(); - FieldIt != RD->field_end(); ++FieldIt) { - if (FieldIt->getType().getTypePtr()->isBSCAwaitableType() && - StartsWith(FieldIt->getDeclName().getAsString(), "Ft_")) { - 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()); - - // Generating `FutureExpr` as followed: - // @code - // this.Ft_ - // @endcode - 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; - } - } - - // Generating `VtableExpr` as followed: - // @code - // this.Ft_.vtable - // @endcode - 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_NoOp, 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; - } - } - - Expr *DataExpr = S.BuildMemberExpr( - FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *PtrField, - DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, - DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); - - Expr *FreeFuncExpr = S.BuildMemberExpr( - VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *FreeFuncField, - DeclAccessPair::make(FatPointerRD, FreeFuncField->getAccess()), false, - DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, - OK_Ordinary); - Stmt *If = buildIfStmtForFreeFutureObj(S, DataExpr, FreeFuncExpr); - Stmts.push_back(If); - } - - if (!IsOptimization) { - 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); - Expr *FutureObj = - S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); - Stmt *If = buildIfStmtForFreeFutureObj(S, FutureObj, FreeFuncRef); - Stmts.push_back(If); - } - - CompoundStmt *CS = - CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); - NewFD->setBody(CS); - sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); - S.PushOnScopeChains(NewFD, S.getCurScope(), true); - return NewFD; -} - -static FunctionDecl *buildPollFunctionDeclaration(Sema &S, FunctionDecl *FD, - RecordDecl *RD, - QualType FuncRetType) { +static FunctionDecl *buildStateTransDecl(Sema &S, FunctionDecl *FD, + RecordDecl *RD, QualType FuncRetType) { SourceLocation SLoc = FD->getBeginLoc(); SourceLocation NLoc = FD->getNameInfo().getLoc(); SourceLocation ELoc = FD->getEndLoc(); @@ -2795,16 +796,13 @@ static FunctionDecl *buildPollFunctionDeclaration(Sema &S, FunctionDecl *FD, return NewFD; } -static FunctionDecl *buildPollFunction(Sema &S, RecordDecl *RD, - FunctionDecl *FD, - RecordDecl *FatPointerRD, - std::vector ContVtableDecls, - QualType FuncRetType, - int FutureStateNumber) { +static FunctionDecl * +buildStateTransFunction(Sema &S, RecordDecl *RD, FunctionDecl *FD, + std::vector ContVtableDecls, + QualType FuncRetType, int FutureStateNumber) { SourceLocation SLoc = FD->getBeginLoc(); SourceLocation NLoc = FD->getNameInfo().getLoc(); SourceLocation ELoc = FD->getEndLoc(); - // QualType Ty = FD->getDeclaredReturnType(); S.PushFunctionScope(); S.PushDeclContext(S.getCurScope(), FD); @@ -2821,15 +819,20 @@ static FunctionDecl *buildPollFunction(Sema &S, RecordDecl *RD, SmallVector ParamTys; ParamTys.push_back(ParamType1); ParamTys.push_back(ParamType2); - + TypeSourceInfo *Tinfo = FD->getTypeSourceInfo(); QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); - // QualType OriginType = S.Context.getFunctionType(Ty, ParamTys, {}); - FunctionDecl *NewFD = buildAsyncFuncDecl(S.Context, RD, SLoc, NLoc, - &(S.Context.Idents).get(FName), - FuncType, FD->getTypeSourceInfo()); + FunctionDecl *NewFD = nullptr; + if (isa(FD)) { + BSCMethodDecl *BMD = cast(FD); + NewFD = buildAsyncBSCMethodDecl(S.Context, RD, SLoc, NLoc, ELoc, + &(S.Context.Idents).get(FName), FuncType, + Tinfo, SC_None, BMD->getExtendedType()); + } else { + NewFD = buildAsyncFuncDecl(S.Context, RD, SLoc, NLoc, + &(S.Context.Idents).get(FName), FuncType, Tinfo); + } NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); - S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; S.PushFunctionScope(); SmallVector ParmVarDecls; @@ -2990,139 +993,53 @@ static FunctionDecl *buildPollFunction(Sema &S, RecordDecl *RD, 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; - } - - QualType AwaitReturnTy = E->getType(); - - bool IsCall = isa(E); - if (IsCall) { - Decl *AwaitDecl = (dyn_cast(E))->getCalleeDecl(); - FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); - if (FDecl) { - if (!FDecl->isAsyncSpecified() && - !IsBSCCompatibleAwaitableType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } else { - if (!IsBSCCompatibleAwaitableType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } - } else { - if (!IsBSCCompatibleAwaitableType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } - - if (AwaitReturnTy.getTypePtr()->isBSCAwaitableType()) { - const RecordType *AwaitableType = - dyn_cast(AwaitReturnTy.getDesugaredType(Context)); - RecordDecl *AwaitDecl = AwaitableType->getDecl(); - assert(isa(AwaitDecl)); - ClassTemplateSpecializationDecl *CTSD = - cast(AwaitDecl); - const TemplateArgumentList &args = CTSD->getTemplateArgs(); - assert(args.size() == 1); - AwaitReturnTy = args[0].getAsType(); - } else if (implementedAwaitableType(*this, AwaitReturnTy)) { - const RecordType *FutureType = - dyn_cast(AwaitReturnTy.getDesugaredType(Context)); - RecordDecl *FutureRD = FutureType->getDecl(); - - BSCMethodDecl *PollFD = - lookupBSCMethodInRecord(*this, "awaitable", FutureRD); - if (PollFD != nullptr) { - const RecordType *PollResultType = dyn_cast( - PollFD->getReturnType().getDesugaredType(Context)); - 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(); - } - } - } - } - - // build AwaitExpr - AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, E, 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(); - } - - // Correct typos for await expr. - ExprResult CorrectVal = - CorrectDelayedTyposInExpr(E, nullptr, /*RecoverUncorrectedTypos=*/true); - if (CorrectVal.isInvalid()) - return ExprError(); - E = CorrectVal.get(); - return BuildAwaitExpr(AwaitLoc, E); -} - -SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { +SmallVector +Sema::ActOnAsyncCPSFunctionDeclaration(FunctionDecl *FD) { SmallVector Decls; - if (!IsBSCCompatibleAwaitableType(FD->getReturnType())) { + if (!IsBSCCompatibleAsyncType(FD->getReturnType())) { QualType ReturnTy = FD->getReturnType(); ReturnTy.removeLocalConst(); // TODO: need to reconsider. if (ReturnTy->isVoidType()) { - std::pair VoidRD = - generateVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); - if (!std::get<1>(VoidRD)) { - Decls.push_back(std::get<0>(VoidRD)); - Context.BSCDesugaredMap[FD].push_back(std::get<0>(VoidRD)); + RecordDecl *VoidRD = + lookupVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); + if (!VoidRD) { + return Decls; } - ReturnTy = Context.getRecordType(std::get<0>(VoidRD)); + ReturnTy = Context.getRecordType(VoidRD); } // Continuation - QualType ContinuationVtableType = lookupGenericType( - *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation_Vtable"); + QualType ContinuationVtableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Continuation_Vtable", "continuation.hbs"); if (ContinuationVtableType.isNull()) { return Decls; } - QualType ContinuationType = lookupGenericType( - *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation"); + QualType ContinuationType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Continuation", "continuation.hbs"); if (ContinuationType.isNull()) { return Decls; } // Awaitable - QualType AwaitableVtableType = lookupGenericType( - *this, FD->getBeginLoc(), ReturnTy, "__Trait_Awaitable_Vtable"); + QualType AwaitableVtableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Awaitable_Vtable", "continuation.hbs"); if (AwaitableVtableType.isNull()) { return Decls; } - QualType AwaitableType = lookupGenericType(*this, FD->getBeginLoc(), - ReturnTy, "__Trait_Awaitable"); + QualType AwaitableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Awaitable", "continuation.hbs"); if (AwaitableType.isNull()) { return Decls; } - RecordDecl *AwaitableRD = AwaitableType->getAsRecordDecl(); if (!FD->isStatic()) { - FunctionDecl *FutureInitDef = - buildFutureInitFunctionDeclaration(*this, FD, AwaitableRD); + FunctionDecl *FutureInitDef = buildFutureInitFunctionDeclaration( + *this, FD, + Context.getElaboratedType(ETK_Struct, nullptr, AwaitableType)); if (FutureInitDef) { Decls.push_back(FutureInitDef); Context.BSCDesugaredMap[FD].push_back(FutureInitDef); @@ -3132,7 +1049,7 @@ SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { return Decls; } -SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { +SmallVector Sema::ActOnAsyncCPSFunctionDefinition(FunctionDecl *FD) { SmallVector Decls; Decls.push_back(FD); @@ -3149,10 +1066,10 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { } // For leaf nodes, should not be modified async. - // if (IsBSCCompatibleAwaitableType(FD->getReturnType())) { - // Diag(FD->getBeginLoc(), diag::err_invalid_async_function); - // return Decls; - // } + if (IsBSCCompatibleAsyncType(FD->getReturnType())) { + Diag(FD->getBeginLoc(), diag::err_invalid_async_function); + return Decls; + } // Do not process desugar if we already met errors. if (Diags.hasErrorOccurred()) { @@ -3164,59 +1081,63 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { if (IAEFinder.HasIllegalAwaitExpr()) return Decls; + // Function Return Type QualType ReturnTy = FD->getReturnType(); ReturnTy.removeLocalConst(); - std::pair VoidRD = - generateVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); - if (!std::get<1>(VoidRD)) { - Decls.push_back(std::get<0>(VoidRD)); - Context.BSCDesugaredMap[FD].push_back(std::get<0>(VoidRD)); + RecordDecl *VoidRD = + lookupVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); + if (!VoidRD) { + return Decls; } - QualType VoidRDTy = Context.getRecordType(std::get<0>(VoidRD)); + QualType VoidRDTy = Context.getRecordType(VoidRD); if (ReturnTy->isVoidType()) { ReturnTy = VoidRDTy; } + // Continuation - QualType ContinuationVtableType = lookupGenericType( - *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation_Vtable"); + QualType ContinuationVtableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Continuation_Vtable", "continuation.hbs"); if (ContinuationVtableType.isNull()) { return Decls; } - RecordDecl *ContinuationVtableRD = ContinuationVtableType->getAsRecordDecl(); - QualType ContinuationType = lookupGenericType( - *this, FD->getBeginLoc(), ReturnTy, "__Trait_Continuation"); + QualType ContinuationType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Continuation", "continuation.hbs"); if (ContinuationType.isNull()) { return Decls; } - RecordDecl *ContinuationRD = ContinuationType->getAsRecordDecl(); // Awaitable - QualType AwaitableVtableType = lookupGenericType( - *this, FD->getBeginLoc(), ReturnTy, "__Trait_Awaitable_Vtable"); + QualType AwaitableVtableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Awaitable_Vtable", "continuation.hbs"); if (AwaitableVtableType.isNull()) { return Decls; } RecordDecl *AwaitableVtableRD = AwaitableVtableType->getAsRecordDecl(); - QualType AwaitableType = lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, - "__Trait_Awaitable"); + QualType AwaitableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, "__Trait_Awaitable", + "continuation.hbs"); if (AwaitableType.isNull()) { return Decls; } RecordDecl *AwaitableRD = AwaitableType->getAsRecordDecl(); // Continuation - QualType ContVoidRDType = lookupGenericType(*this, FD->getBeginLoc(), - VoidRDTy, "__Trait_Continuation"); - if (ContinuationType.isNull()) { + QualType ContVoidRDType = + lookupGenericType(*this, FD->getBeginLoc(), VoidRDTy, + "__Trait_Continuation", "continuation.hbs"); + if (ContVoidRDType.isNull()) { return Decls; } // state machine struct LocalVarFinder VarFinder = LocalVarFinder(Context); VarFinder.Visit(FD->getBody()); - RecordDecl *RD = buildFutureRecordDecl(*this, FD, ContinuationType, - AwaitFinder.GetAwaitExpr(), - VarFinder.GetLocalVarList()); + RecordDecl *RD = + buildFutureRecordDecl(*this, FD, AwaitFinder.GetAwaitExpr(), + VarFinder.GetLocalVarList(), ContinuationType); if (!RD) { return Decls; } @@ -3224,31 +1145,32 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { Context.BSCDesugaredMap[FD].push_back(RD); // Handle declaration first. - bool IsRecursiveCall = RecursiveCallVisitor(FD).VisitStmt(FD->getBody()); - bool IsOptimization = FD->isStatic() && !IsRecursiveCall; + // bool IsRecursiveCall = RecursiveCallVisitor(FD).VisitStmt(FD->getBody()); + bool IsOptimization = FD->isStatic(); //&& !IsRecursiveCall; // init declaration - FunctionDecl *FutureInitDef = - buildFutureInitFunctionDeclaration(*this, FD, AwaitableRD); + FunctionDecl *FutureInitDef = buildFutureInitFunctionDeclaration( + *this, FD, Context.getElaboratedType(ETK_Struct, nullptr, AwaitableType)); if (!FutureInitDef) { return Decls; } Decls.push_back(FutureInitDef); Context.BSCDesugaredMap[FD].push_back(FutureInitDef); - // poll declaration - FunctionDecl *PollDef = - buildPollFunctionDeclaration(*this, FD, RD, ContVoidRDType); - if (!PollDef) { + // state transform declaration + FunctionDecl *StateTransDef = + buildStateTransDecl(*this, FD, RD, ContVoidRDType); + if (!StateTransDef) { return Decls; } - Decls.push_back(PollDef); - Context.BSCDesugaredMap[FD].push_back(PollDef); + Decls.push_back(StateTransDef); + Context.BSCDesugaredMap[FD].push_back(StateTransDef); // resume std::vector ContVtableDecls; if (AwaitFinder.GetAwaitExprNum() > 0) { BSCMethodDecl *ResumeDecl = - buildResumeFunction(*this, RD, FD, PollDef, ContVoidRDType); + buildAwaitFunction(*this, RD, FD, StateTransDef, ContVoidRDType, + Context.VoidPtrTy, "resume"); if (!ResumeDecl) { return Decls; } @@ -3256,21 +1178,23 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { Context.BSCDesugaredMap[FD].push_back(ResumeDecl); std::vector Args = AwaitFinder.GetAwaitExpr(); - for (unsigned int i = 0; i < AwaitFinder.GetAwaitExprNum(); i++) { - QualType QT = Args[i]->getType(); - VarDecl *CVD = buildContVtableInitDecl(*this, FD, ResumeDecl, QT); - if (!CVD) { + for (int i = 0; i < AwaitFinder.GetAwaitExprNum(); i++) { + QualType VtableTy = Args[i]->getType(); + VarDecl *ContVtableVD = + buildContVtableInitDecl(*this, FD, ResumeDecl, VtableTy); + if (!ContVtableVD) { return Decls; } - ContVtableDecls.push_back(CVD); - Decls.push_back(CVD); - Context.BSCDesugaredMap[FD].push_back(CVD); + ContVtableDecls.push_back(ContVtableVD); + Decls.push_back(ContVtableVD); + Context.BSCDesugaredMap[FD].push_back(ContVtableVD); } } // awaitable - BSCMethodDecl *AwaitDecl = buildAwaitFunction( - *this, RD, FD, PollDef, ContVoidRDType, ContinuationType); + BSCMethodDecl *AwaitDecl = + buildAwaitFunction(*this, RD, FD, StateTransDef, ContVoidRDType, + ContinuationType, "awaitable"); if (!AwaitDecl) { return Decls; } @@ -3286,32 +1210,32 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { Context.BSCDesugaredMap[FD].push_back(FreeDecl); // Awaitable Vtable VarDecl - VarDecl *AwaitVtableDecl = buildAwaitVtableInitDecl( + VarDecl *AwaitVtableVD = buildAwaitVtableInitDecl( *this, FD, AwaitableVtableRD, AwaitDecl, FreeDecl); - if (!AwaitVtableDecl) { + if (!AwaitVtableVD) { return Decls; } - Decls.push_back(AwaitVtableDecl); - Context.BSCDesugaredMap[FD].push_back(AwaitVtableDecl); + Decls.push_back(AwaitVtableVD); + Context.BSCDesugaredMap[FD].push_back(AwaitVtableVD); - // poll define + // state transform define const int FutureStateNumber = AwaitFinder.GetAwaitExprNum() + 1; - FunctionDecl *PollDecl = - buildPollFunction(*this, RD, FD, AwaitableRD, ContVtableDecls, - ContVoidRDType, FutureStateNumber); - if (!PollDecl) { + FunctionDecl *StateTransDecl = buildStateTransFunction( + *this, RD, FD, ContVtableDecls, ContVoidRDType, FutureStateNumber); + if (!StateTransDecl) { return Decls; } - Decls.push_back(PollDecl); - Context.BSCDesugaredMap[FD].push_back(PollDecl); + Decls.push_back(StateTransDecl); + Context.BSCDesugaredMap[FD].push_back(StateTransDecl); FunctionDecl *FutureInit = nullptr; + // TODO: // if (IsOptimization) { // FutureInit = // buildFutureStructInitFunctionDefinition(*this, RD, FD); // } else { - FutureInit = buildFutureInitFunctionDefinition( - *this, RD, FD, AwaitableRD, AwaitVtableDecl, FutureInitDef); + FutureInit = buildFutureInitFunctionDefinition(*this, RD, FD, AwaitableRD, + AwaitVtableVD, FutureInitDef); // } if (!FutureInit) { diff --git a/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp index a67c1c8dfea5..0c301846aba6 100644 --- a/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp @@ -13,537 +13,119 @@ #if ENABLE_BSC -#include -#include -#include - #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 "clang/AST/BSC/AsyncBSC.h" using namespace clang; using namespace sema; -static RecordDecl *buildAsyncDataRecord(ASTContext &C, StringRef Name, - SourceLocation StartLoc, - SourceLocation EndLoc, - RecordDecl::TagKind TK) { - RecordDecl *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, SourceLocation EndLoc, - DeclarationName N, QualType T, TypeSourceInfo *TInfo, - StorageClass SC, QualType ET) { - // TODO: inline should be passed. - BSCMethodDecl *NewDecl = BSCMethodDecl::Create( - C, DC, StartLoc, DeclarationNameInfo(N, NLoc), T, TInfo, SC, false, false, - ConstexprSpecKind::Unspecified, EndLoc); - if (auto RD = dyn_cast_or_null(DC)) { - C.BSCDeclContextMap[RD->getTypeForDecl()] = DC; - NewDecl->setHasThisParam(true); // bug - NewDecl->setExtendedType(ET); - } - return NewDecl; +bool Sema::IsBSCCompatibleAsyncType(QualType Ty) { + return implementedAsyncType(*this, Ty) || + Ty.getTypePtr()->isBSCAsyncType(Context); } -std::string GetPrefix(QualType T) { - std::string ExtendedTypeStr = T.getCanonicalType().getAsString(); - for (int i = ExtendedTypeStr.length() - 1; i >= 0; i--) { - if (ExtendedTypeStr[i] == ' ') { - ExtendedTypeStr.replace(i, 1, "_"); - } - } - return ExtendedTypeStr; -} - -static BSCMethodDecl *lookupBSCMethodInRecord(Sema &S, std::string FuncName, - DeclContext *RecordDecl) { - LookupResult Result( - S, - DeclarationNameInfo(&(S.Context.Idents).get(FuncName), SourceLocation()), - S.LookupOrdinaryName); - S.LookupQualifiedName(Result, RecordDecl, false, true); - BSCMethodDecl *BSCMethod = nullptr; - if (!Result.empty()) - BSCMethod = dyn_cast_or_null(Result.getRepresentativeDecl()); - return BSCMethod; -} +// BSC extensions for await keyword +ExprResult Sema::BuildAwaitExpr(SourceLocation AwaitLoc, Expr *E) { + assert(E && "null expression"); -static bool implementedFutureType(Sema &S, QualType Ty) { - RecordDecl *FutureRD = nullptr; - if (const auto *RT = Ty->getAs()) { - FutureRD = RT->getAsRecordDecl(); + if (E->getType()->isDependentType()) { + Expr *Res = new (Context) AwaitExpr(AwaitLoc, E, Context.DependentTy); + return Res; } - if (!FutureRD) - return false; - BSCMethodDecl *PollFD = lookupBSCMethodInRecord(S, "poll", FutureRD); - if (PollFD == nullptr) - return false; - - BSCMethodDecl *FreeFD = lookupBSCMethodInRecord(S, "free", FutureRD); - if (FreeFD == nullptr) - return false; - - return true; -} - -// Logic for generating the procedure to free a future object: -// @code -// if (FutureObj != 0) { -// FreeFuncExpr(FutureObj); -// FutureObj = (void*)0; -// } -// @endcode -static Stmt * -buildIfStmtForFreeFutureObj(Sema &S, Expr *PtrExpr, Expr *FreeFuncExpr, - SourceLocation Loc = SourceLocation()) { - llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), 0); - Expr *IntegerExpr = IntegerLiteral::Create(S.Context, ResultVal, - S.Context.IntTy, SourceLocation()); - // generating condition - Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_NE, - /*LHSExpr=*/PtrExpr, /*RHSExpr=*/IntegerExpr) - .get(); - Sema::ConditionResult IfCond = S.ActOnCondition( - nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); - - // generating free call - QualType Ty = S.Context.getPointerType(S.Context.VoidTy); - Expr *FreeArg = PtrExpr; - if (PtrExpr->getType() != Ty) { - FreeArg = CStyleCastExpr::Create( - S.Context, Ty, VK_PRValue, CK_BitCast, FreeArg, nullptr, - FPOptionsOverride(), - S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), - SourceLocation(), SourceLocation()); - } - std::vector FreeArgs{FreeArg}; - Expr *FreeFuncCall = S.BuildCallExpr(nullptr, FreeFuncExpr, SourceLocation(), - FreeArgs, SourceLocation()) - .get(); - // generating null assignment - Expr *RAssignExpr = CStyleCastExpr::Create( - S.Context, Ty, VK_PRValue, CK_NullToPointer, IntegerExpr, nullptr, - FPOptionsOverride(), - S.Context.getTrivialTypeSourceInfo(Ty, SourceLocation()), - SourceLocation(), SourceLocation()); - if (PtrExpr->getType() != Ty) { - RAssignExpr = CStyleCastExpr::Create( - S.Context, PtrExpr->getType(), VK_PRValue, CK_BitCast, RAssignExpr, - nullptr, FPOptionsOverride(), - S.Context.getTrivialTypeSourceInfo(PtrExpr->getType(), - SourceLocation()), - SourceLocation(), SourceLocation()); - } - Expr *NullptrAssign = - S.BuildBinOp(nullptr, SourceLocation(), BO_Assign, - /*LHSExpr=*/PtrExpr, /*RHSExpr=*/RAssignExpr) - .get(); - - SmallVector BodyStmts = {FreeFuncCall, NullptrAssign}; - Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), - SourceLocation(), SourceLocation()); - - Stmt *If = S.BuildIfStmt(Loc, IfStatementKind::Ordinary, - /*LPL=*/Loc, /*Init=*/nullptr, IfCond, - /*RPL=*/Loc, Body, Loc, nullptr) - .get(); - return If; -} - -/** - * Is a BSC compatible future if and only if: - * - Implements the Future trait - * - is of the form *T, and T implements the Future trait - * - is of the form trait Future* - */ -bool Sema::IsBSCCompatibleFutureType(QualType Ty) { - return implementedFutureType(*this, Ty) || - (isa(Ty.getTypePtr()) && - implementedFutureType( - *this, cast(Ty.getTypePtr())->getPointeeType())) || - Ty.getTypePtr()->isBSCFutureType(); -} - -namespace { -class LocalVarFinder : public StmtVisitor { - ASTContext &Context; - std::vector> LocalVarList; - std::map IdentifierNumber; - -public: - LocalVarFinder(ASTContext &Context) : Context(Context) {} + QualType AwaitReturnTy = E->getType(); - 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)) { - if (VD->isExternallyVisible() || VD->isConstexpr() || - VD->isStaticLocal()) - continue; - - QualType QT = VD->getType(); - if (QT->hasTraitType()) - continue; - - Expr *Init = VD->getInit(); - // Do not need to transform constant variable with compile-time - // constant initializier. - const Expr *Culprit; - if (QT.isConstQualified() && Init && !Init->isValueDependent() && - Init->isConstantInitializer(Context, false, &Culprit)) - continue; - - std::string VDName = VD->getName().str(); - // May have several local variables which has same name, eg. - // @code - // async void f() { - // int c = 1; - // { - // int c = 2; - // } - // } - // @endcode - std::map::iterator I = - IdentifierNumber.find(VDName); - int VDNameNum = I != IdentifierNumber.end() ? I->second : 0; - IdentifierNumber[VDName] = VDNameNum + 1; - if (VDNameNum > 0) { - VDName = VDName + "_" + std::to_string(VDNameNum); - VD->setDeclName(&(Context.Idents).get(VDName)); - } - - LocalVarList.push_back(std::make_pair( - VD->getDeclName(), VD->getType())); - } - } - } - Visit(C); + bool IsCall = isa(E); + if (IsCall) { + Decl *AwaitDecl = (dyn_cast(E))->getCalleeDecl(); + FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); + if (FDecl) { + if (!FDecl->isAsyncSpecified() && + !IsBSCCompatibleAsyncType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); } - } - } - std::vector> GetLocalVarList() const { - return LocalVarList; - } -}; - -class AwaitExprFinder : public StmtVisitor { - int AwaitCount = 0; - std::vector Args; - -public: - AwaitExprFinder() {} - - void VisitAwaitExpr(AwaitExpr *E) { - Visit(E->getSubExpr()); - Args.push_back(E); - AwaitCount++; - } - - void VisitStmt(Stmt *S) { - for (auto *C : S->children()) { - if (C) { - Visit(C); + } else { + if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); } } - } - - int GetAwaitExprNum() const { return AwaitCount; } - - std::vector GetAwaitExpr() const { return Args; } -}; - -static 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; -} - -/// Look for Illegal AwaitExpr -class IllegalAEFinder : public StmtVisitor { - Sema &SemaRef; - bool IsIllegal; - -public: - IllegalAEFinder(Sema &SemaRef) : SemaRef(SemaRef) { IsIllegal = 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; + } else { + if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); } - - if (CHasIllegalAwait && !IsIllegal) - IsIllegal = CHasIllegalAwait; - - return CHasIllegalAwait; } - bool CheckAsyncFuncIllegalStmt(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"; - } 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 (AwaitReturnTy.getTypePtr()->isBSCAsyncType(Context)) { + const RecordType *AwaitableType = + dyn_cast(AwaitReturnTy.getDesugaredType(Context)); + RecordDecl *AwaitDecl = AwaitableType->getDecl(); + assert(isa(AwaitDecl)); + ClassTemplateSpecializationDecl *CTSD = + cast(AwaitDecl); + const TemplateArgumentList &args = CTSD->getTemplateArgs(); + assert(args.size() == 1); + AwaitReturnTy = args[0].getAsType(); + } else if (implementedAsyncType(*this, AwaitReturnTy)) { + const RecordType *FutureType = + dyn_cast(AwaitReturnTy.getDesugaredType(Context)); + RecordDecl *FutureRD = FutureType->getDecl(); - if (!IsIllegal) IsIllegal = true; - } - return IsContinue; - } else if (DeclStmt *DS = dyn_cast(S)) { - bool HasVar = false; - for (auto *D : DS->decls()) { - if (VarDecl *VD = dyn_cast(D)) { - if (isa(VD->getType())) { - HasVar = true; - break; - } + BSCMethodDecl *FD = NULL; + if (Context.getLangOpts().ContinuationPassingStyle) + FD = lookupBSCMethodInRecord(*this, "awaitable", FutureRD); + else + FD = lookupBSCMethodInRecord(*this, "poll", FutureRD); + + if (FD != nullptr) { + const RecordType *ResultType = dyn_cast( + FD->getReturnType().getDesugaredType(Context)); + RecordDecl *Result = ResultType->getDecl(); + for (RecordDecl::field_iterator FieldIt = Result->field_begin(), + Field_end = Result->field_end(); + FieldIt != Field_end; ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "res") { + AwaitReturnTy = FieldIt->getType(); } } - if (HasVar) { - ArgString = "VariableArrayType"; - SemaRef.Diag(S->getBeginLoc(), diag::err_async_func_unsupported) - << ArgString; - if (!IsIllegal) - IsIllegal = true; - return IsContinue; - } - return false; } - - bool CHasIllegalAwait = hasAwaitExpr(S); - if (CHasIllegalAwait && !IsIllegal) - IsIllegal = 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) || - isa(C) || isa(C)) { - bool IsContinue = CheckAsyncFuncIllegalStmt(C); - if (IsContinue) continue; + } else if ((isa(AwaitReturnTy.getTypePtr()) && + implementedFutureType( + *this, cast(AwaitReturnTy.getTypePtr()) + ->getPointeeType()))) { + auto AwaitReturnTy2 = + cast(AwaitReturnTy.getTypePtr())->getPointeeType(); + const RecordType *FutureType = + dyn_cast(AwaitReturnTy2.getDesugaredType(Context)); + RecordDecl *FutureRD = FutureType->getDecl(); + if (Context.getLangOpts().ContinuationPassingStyle) + FD = lookupBSCMethodInRecord(*this, "awaitable", FutureRD); + else + FD = lookupBSCMethodInRecord(*this, "poll", FutureRD); + if (FD != nullptr) { + const RecordType *ResultType = dyn_cast( + FD->getReturnType().getDesugaredType(Context)); + RecordDecl *Result = ResultType->getDecl(); + for (RecordDecl::field_iterator FieldIt = Result->field_begin(), + Field_end = Result->field_end(); + FieldIt != Field_end; ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "res") { + AwaitReturnTy = FieldIt->getType(); } - - Visit(C); - } - } - } - - 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 IsIllegal; } -}; - -static 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; -} - -static bool isRefactorStmt(Stmt *S) { - if (isa(S) || isa(S) || isa(S) || - isa(S) || isa(S) || isa(S)) - return true; - - return false; -} - -static QualType lookupGenericType(Sema &S, SourceLocation SLoc, QualType T, - std::string GenericDeclName) { - DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( - DeclarationName(&(S.Context.Idents).get(GenericDeclName))); - 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) - << GenericDeclName << "\"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; + // build AwaitExpr + AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, E, AwaitReturnTy); + return Res; } -} // namespace - // build struct Future declaration for async function static RecordDecl *buildOpaqueFutureRecordDecl(Sema &S, FunctionDecl *FD) { DeclarationName funcName = FD->getDeclName(); @@ -628,12 +210,13 @@ static RecordDecl *buildFutureRecordDecl( 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; + // Correct typos for await expr. + ExprResult CorrectVal = + CorrectDelayedTyposInExpr(E, nullptr, /*RecoverUncorrectedTypos=*/true); + if (CorrectVal.isInvalid()) + return ExprError(); + E = CorrectVal.get(); + return BuildAwaitExpr(AwaitLoc, E); } static std::pair @@ -700,271 +283,6 @@ static VarDecl *buildVtableInitDecl(Sema &S, FunctionDecl *FD, return x; } -static FunctionDecl *buildFutureInitFunctionDefinition(Sema &S, RecordDecl *RD, - FunctionDecl *FD, - FunctionDecl *FDecl) { - FunctionDecl *NewFD = nullptr; - SourceLocation SLoc = FD->getBeginLoc(); - SourceLocation NLoc = FD->getNameInfo().getLoc(); - SourceLocation ELoc = FD->getEndLoc(); - FunctionDecl::param_const_iterator pi; - - if (isa(FD)) { - BSCMethodDecl *BMD = cast(FD); - NewFD = buildAsyncBSCMethodDecl( - S.Context, FDecl->getDeclContext(), SLoc, NLoc, ELoc, - &(S.Context.Idents).get(FDecl->getName().str()), FDecl->getType(), - FDecl->getTypeSourceInfo(), SC_None, BMD->getExtendedType()); - } else { - NewFD = buildAsyncFuncDecl(S.Context, FDecl->getDeclContext(), SLoc, NLoc, - &(S.Context.Idents).get(FDecl->getName().str()), - FDecl->getType(), FDecl->getTypeSourceInfo()); - } - - 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); - // Enter the scope of this instantiation. We don't use - // PushDeclContext because we don't have a scope. - Sema::ContextRAII savedContext(S, NewFD); - LocalInstantiationScope Scope(S); - - S.PushFunctionScope(); - - 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, SLoc, ELoc); - std::vector Stmts; - Stmts.push_back(DataDS); - - std::string CallocName = "calloc"; - - DeclContext::lookup_result CallocDecls = - S.Context.getTranslationUnitDecl()->lookup( - DeclarationName(&(S.Context.Idents).get(CallocName))); - FunctionDecl *CallocFunc = nullptr; - if (CallocDecls.isSingleResult()) { - for (DeclContext::lookup_result::iterator I = CallocDecls.begin(), - E = CallocDecls.end(); - I != E; ++I) { - if (isa(*I)) { - CallocFunc = dyn_cast(*I); - break; - } - } - } else { - S.Diag(FD->getBeginLoc(), diag::err_function_not_found) - << CallocName << ""; - return nullptr; - } - - llvm::APInt OneResultVal(S.Context.getTargetInfo().getIntWidth(), 1); - Expr *One = IntegerLiteral::Create(S.Context, OneResultVal, S.Context.IntTy, - SourceLocation()); - - Expr *CallocRef = - S.BuildDeclRefExpr(CallocFunc, CallocFunc->getType(), VK_LValue, NLoc); - CallocRef = S.ImpCastExprToType( - CallocRef, S.Context.getPointerType(CallocRef->getType()), - CK_FunctionToPointerDecay) - .get(); - // bsc: sizeof(struct __Futurex) - Expr *SizeOfExpr = - S.CreateUnaryExprOrTypeTraitExpr( - S.Context.getTrivialTypeSourceInfo(S.Context.getRecordType(RD)), - NLoc, UETT_SizeOf, SourceRange()) - .get(); - SmallVector Args; - Args.push_back(One); - Args.push_back(SizeOfExpr); - - // bsc: calloc(1, sizeof(struct __Futurex)) - Expr *CE = S.BuildCallExpr(nullptr, CallocRef, 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); - - // bsc: if (data == 0) - llvm::APInt ZeroResultVal(S.Context.getTargetInfo().getIntWidth(), 0); - Expr *Zero = IntegerLiteral::Create(S.Context, ZeroResultVal, S.Context.IntTy, - SourceLocation()); - Expr *Comp = S.BuildBinOp(nullptr, SourceLocation(), BO_EQ, - /*LHSExpr=*/DataRef, /*RHSExpr=*/Zero) - .get(); - - Sema::ConditionResult IfCond = S.ActOnCondition( - nullptr, SourceLocation(), Comp, Sema::ConditionKind::Boolean); - - // bsc: exit(1); - std::string ExitName = "exit"; - - DeclContext::lookup_result ExitDecls = - S.Context.getTranslationUnitDecl()->lookup( - DeclarationName(&(S.Context.Idents).get(ExitName))); - FunctionDecl *ExitFunc = nullptr; - if (ExitDecls.isSingleResult()) { - for (DeclContext::lookup_result::iterator I = ExitDecls.begin(), - E = ExitDecls.end(); - I != E; ++I) { - if (isa(*I)) { - ExitFunc = dyn_cast(*I); - break; - } - } - } else { - S.Diag(FD->getBeginLoc(), diag::err_function_not_found) - << ExitName << ""; - return nullptr; - } - - Expr *ExitRef = - S.BuildDeclRefExpr(ExitFunc, ExitFunc->getType(), VK_LValue, NLoc); - ExitRef = - S.ImpCastExprToType(ExitRef, S.Context.getPointerType(ExitRef->getType()), - CK_FunctionToPointerDecay) - .get(); - - SmallVector ExitArgs = {One}; - Expr *ExitCE = S.BuildCallExpr(nullptr, ExitRef, SourceLocation(), ExitArgs, - SourceLocation()) - .get(); - // Current code: if (data == 0) exit(1); - // TODO: before exit(1) function, hope there is printf("calloc failed\n") - // function to prompt for calloc failure. and it need to import header file - // "stdio.h". - SmallVector BodyStmts = {ExitCE}; - Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), - SourceLocation(), SourceLocation()); - Stmt *If = S.BuildIfStmt(SourceLocation(), IfStatementKind::Ordinary, - /*LPL=*/SourceLocation(), /*Init=*/nullptr, IfCond, - /*RPL=*/SourceLocation(), /*Body=*/Body, - SourceLocation(), nullptr) - .get(); - Stmts.push_back(If); - - 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()); - - 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); - - Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); - Stmt *RS = S.BuildReturnStmt(NLoc, FutureRefExpr).get(); - Stmts.push_back(RS); - - CompoundStmt *CS = - CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); - NewFD->setBody(CS); - sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); - return NewFD; -} - -/** - * Build the Future init declaration - */ -static FunctionDecl *buildFutureInitFunctionDeclaration(Sema &S, - FunctionDecl *FD, - QualType FuncRetType) { - SourceLocation SLoc = FD->getBeginLoc(); - SourceLocation NLoc = FD->getNameInfo().getLoc(); - SourceLocation ELoc = FD->getEndLoc(); - DeclarationName funcName = FD->getDeclName(); - 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(); - - FunctionDecl *NewFD = nullptr; - if (isa(FD)) { - BSCMethodDecl *BMD = cast(FD); - NewFD = - buildAsyncBSCMethodDecl(S.Context, FD->getDeclContext(), SLoc, NLoc, - ELoc, &(S.Context.Idents).get(FName), FuncType, - Tinfo, SC_None, BMD->getExtendedType()); - } 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; -} - // build function struct Future for async function static FunctionDecl * buildFutureStructInitFunctionDefinition(Sema &S, RecordDecl *RD, @@ -1743,159 +1061,104 @@ public: : BaseTransform(SemaRef), DT(DT), PDRE(PDRE), FutureRD(FutureRD), FD(FD) { } - // 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(If->getBeginLoc(), Stmts, - If->getEndLoc(), false) - .getAs(); - If->setElse(ES); - } - - if (HasStatement && !isRefactorStmt(TS)) { - std::vector Stmts; - Stmts.push_back(TS); - Sema::CompoundScopeRAII CompoundScope(SemaRef); - TS = BaseTransform::RebuildCompoundStmt(If->getBeginLoc(), Stmts, - If->getEndLoc(), false) - .getAs(); - If->setThen(TS); - } + llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), AwaitCount); + Expr *RHSExpr = IntegerLiteral::Create(S.Context, ResultVal, + S.Context.IntTy, SourceLocation()); - return BaseTransform::TransformIfStmt(If); + Expr *BO = S.CreateBuiltinBinOp((*TheField)->getLocation(), BO_Assign, + LHSExpr, RHSExpr) + .get(); + ElseStmts.push_back(BO); } - StmtResult TransformWhileStmt(WhileStmt *S) { - bool HasStatement = false; - WhileStmt *WS = S; - Stmt *Body = WS->getBody(); + RecordDecl *PollResultRD = PollResultVar->getType()->getAsRecordDecl(); + BSCMethodDecl *IsCompletedFD = + lookupBSCMethodInRecord(S, "is_completed", PollResultRD); + if (IsCompletedFD) { + Expr *IsCompletedFDRef = S.BuildDeclRefExpr( + IsCompletedFD, IsCompletedFD->getType(), VK_LValue, BLoc); + IsCompletedFDRef->HasBSCScopeSpec = true; + IsCompletedFDRef = S.ImpCastExprToType(IsCompletedFDRef, + S.Context.getPointerType( + IsCompletedFDRef->getType()), + CK_FunctionToPointerDecay) + .get(); - if (Body != nullptr) - HasStatement = (hasAwaitExpr(Body) || hasReturnStmt(Body)); + if (PollResultRD) { + Expr *PollResultVarRef = S.BuildDeclRefExpr( + PollResultVar, PollResultVar->getType(), VK_LValue, BLoc); + PollResultVarRef = + S.CreateBuiltinUnaryOp(BLoc, UO_AddrOf, PollResultVarRef).get(); + Expr *AwaitResultRef = S.BuildDeclRefExpr( + AwaitResult, AwaitResult->getType(), VK_LValue, BLoc); + AwaitResultRef = + S.CreateBuiltinUnaryOp(BLoc, UO_AddrOf, AwaitResultRef).get(); - if (HasStatement && !isRefactorStmt(Body)) { - std::vector Stmts; - Stmts.push_back(Body); - Sema::CompoundScopeRAII CompoundScope(SemaRef); - Body = BaseTransform::RebuildCompoundStmt(Body->getBeginLoc(), Stmts, - Body->getEndLoc(), false) - .getAs(); - WS->setBody(Body); + SmallVector Args; + Args.push_back(PollResultVarRef); + Args.push_back(AwaitResultRef); + IfCond = + S.BuildCallExpr(nullptr, IsCompletedFDRef, BLoc, Args, BLoc).get(); } - 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)); + RecordDecl *PollResultRDForPending = + NewFD->getReturnType()->getAsRecordDecl(); + BSCMethodDecl *PendingFD = + lookupBSCMethodInRecord(S, "pending", PollResultRDForPending); - if (HasStatement && !isRefactorStmt(Body)) { - std::vector Stmts; - Stmts.push_back(Body); - Sema::CompoundScopeRAII CompoundScope(SemaRef); - Body = BaseTransform::RebuildCompoundStmt(Body->getBeginLoc(), Stmts, - Body->getEndLoc(), false) - .getAs(); - DS->setBody(Body); - } - return BaseTransform::TransformDoStmt(DS); - } - - 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(Body->getBeginLoc(), Stmts, - Body->getEndLoc(), 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(SS->getBeginLoc(), Stmts, - SS->getEndLoc(), 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(SS->getBeginLoc(), Stmts, - SS->getEndLoc(), false) - .getAs(); - DS->setSubStmt(SS); - } - return BaseTransform::TransformDefaultStmt(DS); + if (PendingFD) { + Expr *PendingFDRef = + S.BuildDeclRefExpr(PendingFD, PendingFD->getType(), VK_LValue, BLoc); + PendingFDRef->HasBSCScopeSpec = true; + PendingFDRef = + S.ImpCastExprToType(PendingFDRef, + S.Context.getPointerType(PendingFDRef->getType()), + CK_FunctionToPointerDecay) + .get(); + Expr *PendingCall = + S.BuildCallExpr(nullptr, PendingFDRef, BLoc, {}, BLoc).get(); + Stmt *RS = S.BuildReturnStmt(BLoc, PendingCall).get(); + ElseStmts.push_back(RS); } - StmtResult TransformCompoundStmt(CompoundStmt *S) { - if (S == nullptr) return S; + std::vector BodyStmts{ThenBodyStmt}; - std::vector Statements; + Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), + BLoc, BLoc); + Stmt *Else = CompoundStmt::Create(S.Context, ElseStmts, FPOptionsOverride(), + BLoc, BLoc); + IfStmt *If = IfStmt::Create(S.Context, BLoc, IfStatementKind::Ordinary, + /*Init=*/nullptr, + /*Var=*/nullptr, IfCond, + /*LPL=*/BLoc, + /*RPL=*/BLoc, Body, BLoc, Else); + return If; +} + +namespace { +/** + * Visit a Stmt and return true if there's a recursive call to the provided Decl + */ +class RecursiveCallVisitor + : public ConstStmtVisitor { +public: + RecursiveCallVisitor(const Decl *FD) : FD(FD) {} + bool VisitCallExpr(const CallExpr *E) { + if (E->getCalleeDecl() == FD) + return true; + + return this->VisitStmt(static_cast(E)); + } + bool VisitStmt(const Stmt *S) { 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]); + if (C) { + if (Visit(C)) { + return true; } } - SS = BaseTransform::TransformStmt(SS).getAs(); - Statements.push_back(SS); } - Sema::CompoundScopeRAII CompoundScope(SemaRef); - CompoundStmt *CS = BaseTransform::RebuildCompoundStmt( - S->getBeginLoc(), Statements, S->getEndLoc(), false) - .getAs(); - return CS; + return false; } StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { @@ -2203,11 +1466,11 @@ public: assert(args.size() == 1); // Make sure these three generic types are fully instantiated. (void)lookupGenericType(SemaRef, FD->getBeginLoc(), args[0].getAsType(), - "PollResult"); + "PollResult", "future.hbs"); (void)lookupGenericType(SemaRef, FD->getBeginLoc(), args[0].getAsType(), - "__Trait_Future_Vtable"); + "__Trait_Future_Vtable", "future.hbs"); (void)lookupGenericType(SemaRef, FD->getBeginLoc(), args[0].getAsType(), - "__Trait_Future"); + "__Trait_Future", "future.hbs"); RecordDecl::field_iterator PtrField, VtableField, FPFieldIt; for (FPFieldIt = FatPointerRD->field_begin(); FPFieldIt != FatPointerRD->field_end(); ++FPFieldIt) { @@ -2987,7 +2250,7 @@ ExprResult Sema::ActOnAwaitExpr(SourceLocation AwaitLoc, Expr *E) { SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { SmallVector Decls; - if (!IsBSCCompatibleFutureType(FD->getReturnType())) { + if (!IsBSCCompatibleAsyncType(FD->getReturnType())) { QualType ReturnTy = FD->getReturnType(); ReturnTy.removeLocalConst(); // TODO: need to reconsider. if (ReturnTy->isVoidType()) { @@ -2999,18 +2262,19 @@ SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { } ReturnTy = Context.getRecordType(std::get<0>(VoidRD)); } - QualType PollResultType = - lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, "PollResult"); + QualType PollResultType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "PollResult", "future.hbs"); if (PollResultType.isNull()) { return Decls; } - QualType VtableType = lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, - "__Trait_Future_Vtable"); + QualType VtableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Future_Vtable", "future.hbs"); if (VtableType.isNull()) { return Decls; } - QualType FatPointerType = - lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, "__Trait_Future"); + QualType FatPointerType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Future", "future.hbs"); if (FatPointerType.isNull()) { return Decls; } @@ -3064,7 +2328,7 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { } // For leaf nodes, should not be modified async. - if (IsBSCCompatibleFutureType(FD->getReturnType())) { + if (IsBSCCompatibleAsyncType(FD->getReturnType())) { Diag(FD->getBeginLoc(), diag::err_invalid_async_function); return Decls; } @@ -3089,20 +2353,21 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { } ReturnTy = Context.getRecordType(std::get<0>(VoidRD)); } - QualType PollResultType = - lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, "PollResult"); + QualType PollResultType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "PollResult", "future.hbs"); if (PollResultType.isNull()) { return Decls; } RecordDecl *PollResultRD = PollResultType->getAsRecordDecl(); - QualType VtableType = lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, - "__Trait_Future_Vtable"); + QualType VtableType = + lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, + "__Trait_Future_Vtable", "future.hbs"); if (VtableType.isNull()) { return Decls; } - - QualType FatPointerType = - lookupGenericType(*this, FD->getBeginLoc(), ReturnTy, "__Trait_Future"); + RecordDecl *VtableRD = VtableType->getAsRecordDecl(); + QualType FatPointerType = lookupGenericType( + *this, FD->getBeginLoc(), ReturnTy, "__Trait_Future", "future.hbs"); if (FatPointerType.isNull()) { return Decls; } @@ -3114,11 +2379,9 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { bool IsRecursiveCall = RecursiveCallVisitor(FD).VisitStmt(FD->getBody()); bool IsOptimization = FD->isStatic() && !IsRecursiveCall; - RecordDecl *RD = buildFutureRecordDecl(*this, FD, AwaitFinder.GetAwaitExpr(), - VarFinder.GetLocalVarList()); - auto RDType = Context.getRecordType(RD); - QualType PointerStructTy = Context.getPointerType(RDType); - + RecordDecl *RD = + buildFutureRecordDecl(*this, FD, AwaitFinder.GetAwaitExpr(), + VarFinder.GetLocalVarList(), QualType()); if (!RD) { return Decls; } diff --git a/clang/lib/Sema/BSC/SemaBSCTrait.cpp b/clang/lib/Sema/BSC/SemaBSCTrait.cpp index b1508bd79b6d..c76509d82c91 100644 --- a/clang/lib/Sema/BSC/SemaBSCTrait.cpp +++ b/clang/lib/Sema/BSC/SemaBSCTrait.cpp @@ -210,7 +210,6 @@ void Sema::ActOnVtableRecordFields(TraitDecl *TD) { TD->setVtable(TraitVtableRD); } - static std::string TypeAsString(QualType T) { PrintingPolicy PrintPolicy = LangOptions(); SplitQualType T_split = T.split(); diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 80f6131e1718..68a19731bdf8 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -15,6 +15,7 @@ add_clang_library(clangSema BSC/SemaBSCDestructor.cpp BSC/SemaBSCOverload.cpp BSC/SemaBSCOwnedStruct.cpp + BSC/SemaBSCCoroutine.cpp BSC/SemaBSCContinuation.cpp BSC/SemaBSCOwnership.cpp BSC/SemaBSCSafeZone.cpp diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 246582275fef..21601d552ae9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2111,7 +2111,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, if (FunctionDecl *FD = dyn_cast_or_null(D)) { if (FD->isAsyncSpecified()) { QualType AwaitReturnTy = FD->getReturnType(); - if (!IsBSCCompatibleFutureType(AwaitReturnTy)) { + if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { FunctionDecl *DesugaredFD = nullptr; if (Context.BSCDesugaredMap.find(FD) != Context.BSCDesugaredMap.end()) { for (auto &DesugaredDecl : Context.BSCDesugaredMap[FD]) { @@ -7210,7 +7210,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, // Desugar for BSC async function call if (FD->isAsyncSpecified()) { QualType AwaitReturnTy = FD->getReturnType(); - if (!IsBSCCompatibleFutureType(AwaitReturnTy)) { + if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { FunctionDecl *DesugaredFD = nullptr; if (Context.BSCDesugaredMap.find(FD) != Context.BSCDesugaredMap.end()) { for (auto &DesugaredDecl : Context.BSCDesugaredMap[FD]) { -- Gitee From eb3170350bb4be616e946750be0b2947cbe0bcd7 Mon Sep 17 00:00:00 2001 From: zhaoxuhui Date: Tue, 10 Dec 2024 19:19:00 +0800 Subject: [PATCH 4/5] [testcase] add test cases for CPS transformation --- clang/include/clang/AST/BSC/AsyncBSC.h | 32 +++- clang/lib/Sema/BSC/SemaBSCContinuation.cpp | 39 +---- clang/lib/Sema/BSC/SemaBSCCoroutine.cpp | 31 +--- .../await-expr-call-absent.cbs | 2 +- .../await-expr-call-absent.cbs | 16 ++ .../await-expr-compound-expression.cbs | 14 ++ .../await-expr-for-cond.cbs | 17 +++ .../await-expr-if-cond/await-expr-if-cond.cbs | 18 +++ .../await-expr-of-func-params.cbs | 28 ++++ .../await-expr-switch-cond.cbs | 21 +++ .../await-expr-while-cond.cbs | 16 ++ .../async_constexpr_declaration.cbs | 17 +++ .../async_static_declaration.cbs | 24 +++ .../await-non-async-call.cbs | 17 +++ .../invalid-async-function.cbs | 13 ++ .../invalid-await-expression.cbs | 13 ++ .../variable_undeclared.cbs | 15 ++ .../variable-array-decl.cbs | 16 ++ .../async-func-read-opposite-cps.hbs | 36 +++++ .../await-expr-nest-await.cbs | 39 +++++ .../await-expr-num/await-expr-num.cbs | 68 +++++++++ .../await-expr-of-return.cbs | 49 +++++++ .../await-expr-single-judgement.cbs | 58 ++++++++ .../async_definition_1/async_definition_1.cbs | 46 ++++++ .../async-different-return-type2.cbs | 48 ++++++ .../async-type-with-pointer.cbs | 48 ++++++ .../await-different-return-type.cbs | 46 ++++++ .../typealias-return-type.cbs | 59 ++++++++ .../Coroutine/CPS/Other/Extern/Extern.cbs | 26 ++++ .../CPS/Other/Extern/Inputs/extern-file.cbs | 6 + .../async-bscmethod-as-func-pointer.cbs | 31 ++++ .../async-func-as-func-pointer.cbs | 24 +++ .../async-instance-member-function.cbs | 48 ++++++ .../async-member-function.cbs | 46 ++++++ .../static-async-for-trait-multi-pointer.cbs | 46 ++++++ .../static-async-member-function.cbs | 79 ++++++++++ .../await-non-call/await-non-call.cbs | 47 ++++++ .../recursive-async-call.cbs | 59 ++++++++ .../static-recursive-async-call-2.cbs | 104 +++++++++++++ .../static-recursive-async-call.cbs | 99 +++++++++++++ .../async-func-pointer-2.cbs | 22 +++ .../async-func-pointer/async-func-pointer.cbs | 26 ++++ .../async-func-volatile.cbs | 44 ++++++ .../async-func-with-owned.cbs | 43 ++++++ ...sync-function-without-await-expression.cbs | 38 +++++ .../leaf-node-async-function.cbs | 45 ++++++ .../malloc-free-call/malloc-free-call.cbs | 69 +++++++++ .../static-async-function-opt.cbs | 45 ++++++ .../trait-inside-async/trait-inside-async.cbs | 32 ++++ .../unused-await-expression.cbs | 39 +++++ .../volatile-async-function1.cbs | 43 ++++++ .../volatile-async-function2.cbs | 38 +++++ .../auto-storage-class/auto-storage-class.cbs | 46 ++++++ .../Common/await-expr-for/await-expr-for.cbs | 42 ++++++ .../Common/func-invoke/func-invoke.cbs | 44 ++++++ .../register-storage-class.cbs | 42 ++++++ .../static-storage-class.cbs | 45 ++++++ .../DeclStmt/Enum/enum1/enum1.cbs | 43 ++++++ .../MultiDecl/array-decl/array-decl.cbs | 49 +++++++ .../MultiDecl/array-decl1/array-decl1.cbs | 41 ++++++ .../base-type-decl/base-type-decl.cbs | 55 +++++++ .../MultiDecl/const-decl/const-decl.cbs | 86 +++++++++++ .../constexpr-decl/constexpr-decl.cbs | 89 ++++++++++++ .../MultiDecl/extern-decl/extern-decl.cbs | 46 ++++++ .../MultiDecl/global-decl/global-decl.cbs | 42 ++++++ .../literal-quantity-decl.cbs | 43 ++++++ .../MultiDecl/multi-decl/multi-decl.cbs | 44 ++++++ .../multi-dimension-array-decl.cbs | 43 ++++++ .../MultiDecl/pointer-decl/pointer-decl.cbs | 50 +++++++ .../MultiDecl/static-decl/static-decl.cbs | 97 +++++++++++++ .../MultiDecl/string-decl/string-decl.cbs | 42 ++++++ .../MultiDecl/struct-decl/struct-decl.cbs | 49 +++++++ .../MultiDecl/typedef-decl/typedef-decl.cbs | 48 ++++++ .../uninit-array-decl/uninit-array-decl.cbs | 52 +++++++ .../uninit-array-decl1/uninit-array-decl1.cbs | 116 +++++++++++++++ .../var-decl-multi-same-local-name.cbs | 137 ++++++++++++++++++ .../arithmetic-op-of-c-pointer.cbs | 50 +++++++ .../c-pointer-to-pointer.cbs | 45 ++++++ .../Pointer/func-pointer/func-pointer.cbs | 49 +++++++ .../Struct/struct-init/struct-init.cbs | 50 +++++++ .../DeclStmt/Union/union-init/union-init.cbs | 49 +++++++ .../Judgement/await-expr-if/await-expr-if.cbs | 49 +++++++ .../if-else-statement/if-else-statement.cbs | 43 ++++++ .../if-nested-if-statement.cbs | 44 ++++++ .../if-statement-uninitialized-static.cbs | 55 +++++++ .../if-statement-uninitialized.cbs | 55 +++++++ .../Judgement/if-statement/if-statement.cbs | 43 ++++++ .../switch-nested-switch-statement.cbs | 61 ++++++++ .../switch-statement/switch-statement.cbs | 55 +++++++ .../Other/LabelStmt/label-stmt/label-stmt.cbs | 94 ++++++++++++ .../Loop/do-while-loop/do-while-loop.cbs | 44 ++++++ .../Other/Loop/for-loop/for-loop.cbs | 42 ++++++ .../Other/Loop/loop-nested/loop-nested.cbs | 46 ++++++ .../Other/Loop/while-loop/while-loop.cbs | 45 ++++++ .../Operators/arithmetic-op/arithmetic-op.cbs | 49 +++++++ .../Other/Operators/assign-op/assign-op.cbs | 53 +++++++ .../Other/Operators/bit-op/bit-op.cbs | 49 +++++++ .../Other/Operators/logocal-op/logocal-op.cbs | 46 ++++++ .../Other/Operators/other-op/other-op.cbs | 45 ++++++ .../Operators/relational-op/relational-op.cbs | 49 +++++++ .../async-func-return-const-int.cbs | 48 ++++++ .../async-func-return-type.cbs | 111 ++++++++++++++ .../async-func-return-void.cbs | 41 ++++++ .../await-expr-return-type.cbs | 40 +++++ .../await-expr-return-type1.cbs | 29 ++++ .../Coroutine/Other/Extern/Extern.cbs | 0 .../Other/Extern/Inputs/extern-file.cbs | 0 .../MultiDecl/const-decl/const-decl.cbs | 9 +- .../var-decl-multi-same-local-name.cbs | 33 ++++- .../Other/LabelStmt/label-stmt/label-stmt.cbs | 27 ++-- .../rewrite-bsc}/Atmoic/rewrite_atmoic.cbs | 0 111 files changed, 4801 insertions(+), 83 deletions(-) create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-compound-expression/await-expr-compound-expression.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-for-cond/await-expr-for-cond.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-if-cond/await-expr-if-cond.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-of-func-params/await-expr-of-func-params.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-switch-cond/await-expr-switch-cond.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-while-cond/await-expr-while-cond.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/Other/Definition/async_constexpr_declaration/async_constexpr_declaration.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/Other/Definition/async_static_declaration/async_static_declaration.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/Other/await-non-async-call/await-non-async-call.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/Other/invalid-async-function/invalid-async-function.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/Other/invalid-await-expression/invalid-await-expression.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/Common/variable_undeclared/variable_undeclared.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/variable-array-decl/variable-array-decl.cbs create mode 100644 clang/test/BSC/Negative/Coroutine/async-func-read-opposite-cps.hbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-nest-await/await-expr-nest-await.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-num/await-expr-num.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-of-return/await-expr-of-return.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-single-judgement/await-expr-single-judgement.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/Definition/async_definition_1/async_definition_1.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-different-return-type2/async-different-return-type2.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-type-with-pointer/async-type-with-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/await-different-return-type/await-different-return-type.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/typealias-return-type/typealias-return-type.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Extern.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Inputs/extern-file.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-bscmethod-as-func-pointer/async-bscmethod-as-func-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-func-as-func-pointer/async-func-as-func-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-instance-member-function/async-instance-member-function.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-member-function/async-member-function.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-for-trait-multi-pointer/static-async-for-trait-multi-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-member-function/static-async-member-function.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/NonCallAwaitExpr/await-non-call/await-non-call.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/recursive-async-call/recursive-async-call.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call-2/static-recursive-async-call-2.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call/static-recursive-async-call.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer-2/async-func-pointer-2.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer/async-func-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-volatile/async-func-volatile.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-with-owned/async-func-with-owned.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/async-function-without-await-expression/async-function-without-await-expression.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/leaf-node-async-function/leaf-node-async-function.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/malloc-free-call/malloc-free-call.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/static-async-function-opt/static-async-function-opt.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/trait-inside-async/trait-inside-async.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/unused-await-expression/unused-await-expression.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function1/volatile-async-function1.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function2/volatile-async-function2.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/auto-storage-class/auto-storage-class.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/await-expr-for/await-expr-for.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/func-invoke/func-invoke.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/register-storage-class/register-storage-class.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/static-storage-class/static-storage-class.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Enum/enum1/enum1.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl/array-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl1/array-decl1.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/base-type-decl/base-type-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/constexpr-decl/constexpr-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/extern-decl/extern-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/global-decl/global-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl/literal-quantity-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-decl/multi-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl/multi-dimension-array-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/pointer-decl/pointer-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/static-decl/static-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/string-decl/string-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/struct-decl/struct-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/typedef-decl/typedef-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl/uninit-array-decl.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl1/uninit-array-decl1.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer/arithmetic-op-of-c-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer/c-pointer-to-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/func-pointer/func-pointer.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Struct/struct-init/struct-init.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Union/union-init/union-init.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/await-expr-if/await-expr-if.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-else-statement/if-else-statement.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-nested-if-statement/if-nested-if-statement.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized-static/if-statement-uninitialized-static.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized/if-statement-uninitialized.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement/if-statement.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-nested-switch-statement/switch-nested-switch-statement.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-statement/switch-statement.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/do-while-loop/do-while-loop.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/for-loop/for-loop.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/loop-nested/loop-nested.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/while-loop/while-loop.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/arithmetic-op/arithmetic-op.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/assign-op/assign-op.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/bit-op/bit-op.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/logocal-op/logocal-op.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/other-op/other-op.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/relational-op/relational-op.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-const-int/async-func-return-const-int.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-type/async-func-return-type.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-void/async-func-return-void.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type/await-expr-return-type.cbs create mode 100644 clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type1/await-expr-return-type1.cbs rename clang/test/BSC/{Negative => Positive}/Coroutine/Other/Extern/Extern.cbs (100%) rename clang/test/BSC/{Negative => Positive}/Coroutine/Other/Extern/Inputs/extern-file.cbs (100%) rename clang/test/BSC/Positive/{Coroutine => Driver/rewrite-bsc}/Atmoic/rewrite_atmoic.cbs (100%) diff --git a/clang/include/clang/AST/BSC/AsyncBSC.h b/clang/include/clang/AST/BSC/AsyncBSC.h index 4478f5d75235..c075d173e86f 100644 --- a/clang/include/clang/AST/BSC/AsyncBSC.h +++ b/clang/include/clang/AST/BSC/AsyncBSC.h @@ -1,4 +1,4 @@ -//===- WalkerBSC.h - Classes for traversing BSC ASTs --*- BSC -*-=====// +//===- AsyncBSC.h - Classes for Coroutine transformation --*- BSC -*-=====// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // /// \file -/// Defines the BSC Walker utilities. +/// Defines the BSC Coroutine utilities. // //===----------------------------------------------------------------------===// @@ -125,6 +125,34 @@ static QualType lookupGenericType(Sema &S, SourceLocation SLoc, QualType T, return PollResultRecord; } +static std::pair +generateVoidStruct(Sema &S, SourceLocation BLoc, SourceLocation ELoc) { + std::string Recordname = "Void"; + DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( + DeclarationName(&(S.Context.Idents).get(Recordname))); + RecordDecl *VoidRD = nullptr; + bool IsExisted = false; + + 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; + } + } + IsExisted = true; + } else if (Decls.empty()) { + VoidRD = buildAsyncDataRecord(S.Context, Recordname, BLoc, ELoc, + clang::TagDecl::TagKind::TTK_Struct); + VoidRD->startDefinition(); + VoidRD->completeDefinition(); + S.PushOnScopeChains(VoidRD, S.getCurScope(), true); + } + return std::make_pair(VoidRD, IsExisted); +} + static bool implementedAsyncType(Sema &S, QualType Ty) { RecordDecl *AsyncRD = nullptr; if (const auto *RT = Ty->getAs()) { diff --git a/clang/lib/Sema/BSC/SemaBSCContinuation.cpp b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp index 5ba081e138ea..a9aae8289f41 100644 --- a/clang/lib/Sema/BSC/SemaBSCContinuation.cpp +++ b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp @@ -19,29 +19,6 @@ using namespace clang; using namespace sema; -static RecordDecl *lookupVoidStruct(Sema &S, SourceLocation BLoc, - SourceLocation ELoc) { - 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 { - S.Diag(BLoc, diag::err_function_not_found) - << Recordname << "\"continuation.hbs\""; - } - return VoidRD; -} - // TODO: Can we first desugar to "impl trait Future<> for type", // then call the trait interface to desugar again. static VarDecl *buildContVtableInitDecl(Sema &S, FunctionDecl *FD, @@ -1000,12 +977,12 @@ Sema::ActOnAsyncCPSFunctionDeclaration(FunctionDecl *FD) { QualType ReturnTy = FD->getReturnType(); ReturnTy.removeLocalConst(); // TODO: need to reconsider. if (ReturnTy->isVoidType()) { - RecordDecl *VoidRD = - lookupVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); - if (!VoidRD) { + std::pair VoidRD = + generateVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); + if (!std::get<1>(VoidRD)) { return Decls; } - ReturnTy = Context.getRecordType(VoidRD); + ReturnTy = Context.getRecordType(std::get<0>(VoidRD)); } // Continuation @@ -1084,12 +1061,12 @@ SmallVector Sema::ActOnAsyncCPSFunctionDefinition(FunctionDecl *FD) { // Function Return Type QualType ReturnTy = FD->getReturnType(); ReturnTy.removeLocalConst(); - RecordDecl *VoidRD = - lookupVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); - if (!VoidRD) { + std::pair VoidRD = + generateVoidStruct(*this, FD->getBeginLoc(), FD->getEndLoc()); + if (!std::get<1>(VoidRD)) { return Decls; } - QualType VoidRDTy = Context.getRecordType(VoidRD); + QualType VoidRDTy = Context.getRecordType(std::get<0>(VoidRD)); if (ReturnTy->isVoidType()) { ReturnTy = VoidRDTy; } diff --git a/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp index 0c301846aba6..80ba564ba232 100644 --- a/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp @@ -219,35 +219,8 @@ static RecordDecl *buildFutureRecordDecl( return BuildAwaitExpr(AwaitLoc, E); } -static std::pair -generateVoidStruct(Sema &S, SourceLocation BLoc, SourceLocation ELoc) { - std::string Recordname = "Void"; - DeclContext::lookup_result Decls = S.Context.getTranslationUnitDecl()->lookup( - DeclarationName(&(S.Context.Idents).get(Recordname))); - RecordDecl *VoidRD = nullptr; - bool IsExisted = false; - - 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; - } - } - IsExisted = true; - } else if (Decls.empty()) { - VoidRD = buildAsyncDataRecord(S.Context, Recordname, BLoc, ELoc, - clang::TagDecl::TagKind::TTK_Struct); - VoidRD->startDefinition(); - VoidRD->completeDefinition(); - S.PushOnScopeChains(VoidRD, S.getCurScope(), true); - } - return std::make_pair(VoidRD, IsExisted); -} - -// Future trait implementation +// TODO: Can we first desugar to "impl trait Future<> for type", +// then call the trait interface to desugar again. static VarDecl *buildVtableInitDecl(Sema &S, FunctionDecl *FD, QualType RecordType, QualType ReturnType, bool Initialize) { diff --git a/clang/test/BSC/Negative/Coroutine/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs b/clang/test/BSC/Negative/Coroutine/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs index 12f124d2e180..d5e72ba54936 100644 --- a/clang/test/BSC/Negative/Coroutine/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs +++ b/clang/test/BSC/Negative/Coroutine/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs @@ -2,7 +2,7 @@ #include "../../async-func-read-opposite.hbs" -async int f(int start) { +async int f(int start) { await g(); // #1 int result = await read(1); return result; diff --git a/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs new file mode 100644 index 000000000000..188bd018541a --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-call-absent/await-expr-call-absent.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.hbs" + +async int f(int start) { + await g(); // #1 + int result = await read(1); + return result; +} + +// expected-warning@#1 {{call to undeclared function 'g'; ISO C99 and later do not support implicit function declarations}} +// expected-error@#1 {{the await expression's external function declaration must be modified by async or return 'Future' type}} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-compound-expression/await-expr-compound-expression.cbs b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-compound-expression/await-expr-compound-expression.cbs new file mode 100644 index 000000000000..755d3afa4548 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-compound-expression/await-expr-compound-expression.cbs @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.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/Negative/Coroutine/CPS/AwaitExpr/await-expr-for-cond/await-expr-for-cond.cbs b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-for-cond/await-expr-for-cond.cbs new file mode 100644 index 000000000000..e6d451ed8115 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-for-cond/await-expr-for-cond.cbs @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.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/Negative/Coroutine/CPS/AwaitExpr/await-expr-if-cond/await-expr-if-cond.cbs b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-if-cond/await-expr-if-cond.cbs new file mode 100644 index 000000000000..ddc8c020937c --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-if-cond/await-expr-if-cond.cbs @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.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/Negative/Coroutine/CPS/AwaitExpr/await-expr-of-func-params/await-expr-of-func-params.cbs b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-of-func-params/await-expr-of-func-params.cbs new file mode 100644 index 000000000000..4c2bc28935c2 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-of-func-params/await-expr-of-func-params.cbs @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.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/Negative/Coroutine/CPS/AwaitExpr/await-expr-switch-cond/await-expr-switch-cond.cbs b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-switch-cond/await-expr-switch-cond.cbs new file mode 100644 index 000000000000..8d1638dfe075 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-switch-cond/await-expr-switch-cond.cbs @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.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/Negative/Coroutine/CPS/AwaitExpr/await-expr-while-cond/await-expr-while-cond.cbs b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-while-cond/await-expr-while-cond.cbs new file mode 100644 index 000000000000..b21b95d4a8be --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/AwaitExpr/await-expr-while-cond/await-expr-while-cond.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.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/Negative/Coroutine/CPS/Other/Definition/async_constexpr_declaration/async_constexpr_declaration.cbs b/clang/test/BSC/Negative/Coroutine/CPS/Other/Definition/async_constexpr_declaration/async_constexpr_declaration.cbs new file mode 100644 index 000000000000..77e62553e375 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/Other/Definition/async_constexpr_declaration/async_constexpr_declaration.cbs @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../../lib/Headers/bsc_include -verify %s + +#include "continuation.hbs" + +constexpr async int test(); // expected-error {{async function does not support constexpr}} +constexpr async int test() { // expected-error {{async function does not support constexpr}} + return 42; +} + +async int f(int start) { + int a = await test(); + return a; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Negative/Coroutine/CPS/Other/Definition/async_static_declaration/async_static_declaration.cbs b/clang/test/BSC/Negative/Coroutine/CPS/Other/Definition/async_static_declaration/async_static_declaration.cbs new file mode 100644 index 000000000000..ae35e36de3c4 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/Other/Definition/async_static_declaration/async_static_declaration.cbs @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../../async-func-read-opposite-cps.hbs" + +static async int f(int start); // expected-error {{async function does not support static declaration}} + +async int test() { + return 42; +} + +async int g() { + int tmp = await f(3); + return 42; +} + +static async int f(int start) { + start = 3; + int a = await test(); + return a + start; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Negative/Coroutine/CPS/Other/await-non-async-call/await-non-async-call.cbs b/clang/test/BSC/Negative/Coroutine/CPS/Other/await-non-async-call/await-non-async-call.cbs new file mode 100644 index 000000000000..22dafed6f1fa --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/Other/await-non-async-call/await-non-async-call.cbs @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.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/Negative/Coroutine/CPS/Other/invalid-async-function/invalid-async-function.cbs b/clang/test/BSC/Negative/Coroutine/CPS/Other/invalid-async-function/invalid-async-function.cbs new file mode 100644 index 000000000000..55d418168fde --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/Other/invalid-async-function/invalid-async-function.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.hbs" + +async trait Awaitable* f1() { // expected-error {{function which returns 'Future' type should not be modified by 'async'}} + trait Awaitable* f; + int a = await read(1); + return f; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Negative/Coroutine/CPS/Other/invalid-await-expression/invalid-await-expression.cbs b/clang/test/BSC/Negative/Coroutine/CPS/Other/invalid-await-expression/invalid-await-expression.cbs new file mode 100644 index 000000000000..96e43af739bf --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/Other/invalid-await-expression/invalid-await-expression.cbs @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../async-func-read-opposite-cps.hbs" + +trait Awaitable* f() { // expected-error {{await expression is not allowed to appear in non-async function.}} + trait Awaitable*f; + int a = await read(1); + return f; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/Common/variable_undeclared/variable_undeclared.cbs b/clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/Common/variable_undeclared/variable_undeclared.cbs new file mode 100644 index 000000000000..e4c213946934 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/Common/variable_undeclared/variable_undeclared.cbs @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../../../async-func-read-opposite-cps.hbs" + +async int f(int start) { + int result = await read(r1); // #1 + return result; +} + +// expected-error@#1 {{use of undeclared identifier 'r1'}} +// expected-error@#1 {{initializing 'int' with an expression of incompatible type ''}} + +int main() { + return 0; +} diff --git a/clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/variable-array-decl/variable-array-decl.cbs b/clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/variable-array-decl/variable-array-decl.cbs new file mode 100644 index 000000000000..8e5a579b8af0 --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/variable-array-decl/variable-array-decl.cbs @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -CPS -internal-isystem %S/../../../../../../../../../lib/Headers/bsc_include -verify %s + +#include "../../../../../async-func-read-opposite-cps.hbs" + +async int f() { + int n = 3; + int *a[n]; // #1 + int x = await read(2); + return 42; +} + +// expected-error@#1 {{async function does not support VariableArrayType}} + +int main() { + return 0; +} diff --git a/clang/test/BSC/Negative/Coroutine/async-func-read-opposite-cps.hbs b/clang/test/BSC/Negative/Coroutine/async-func-read-opposite-cps.hbs new file mode 100644 index 000000000000..7735a135c9ad --- /dev/null +++ b/clang/test/BSC/Negative/Coroutine/async-func-read-opposite-cps.hbs @@ -0,0 +1,36 @@ +#ifndef READ_H +#define READ_H + +#include "continuation.hbs" + +struct _Futureread { + int a; + int res; + int __future_state; + trait Continuation *cont; +}; +typedef struct _Futureread __Futureread; + +trait Continuation *struct _Futureread::awaitable(__Futureread *this, trait Continuation *extra) { + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->res = this->a; + this->__future_state = -1; + return this->cont->resume((void *)0); +} + +void struct _Futureread::free(struct _Futureread *this) {} + +impl trait Awaitable for struct _Futureread; + +trait Awaitable* read(int a) { + struct _Futureread* ptr; + ptr->a = a; + ptr->__future_state = 0; + return ptr; +} + +#endif \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-nest-await/await-expr-nest-await.cbs b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-nest-await/await-expr-nest-await.cbs new file mode 100644 index 000000000000..315ece2244a0 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-nest-await/await-expr-nest-await.cbs @@ -0,0 +1,39 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int result = await read(await read(start)); + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-num/await-expr-num.cbs b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-num/await-expr-num.cbs new file mode 100644 index 000000000000..b977781e3be4 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-num/await-expr-num.cbs @@ -0,0 +1,68 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +struct _Futuretest2 { + int a; + int res; + int __future_state; + trait Continuation *cont; +}; +typedef struct _Futuretest2 __Futuretest2; + +trait Continuation *struct _Futuretest2::awaitable(__Futuretest2 *this, trait Continuation *extra) { + this->cont = extra; + this->res = this->a; + this->__future_state = -1; + int _RES_RETURN = this->res; + return this->cont->resume(&_RES_RETURN); +} + +void struct _Futuretest2::free(struct _Futuretest2 *this) {} + +impl trait Awaitable for struct _Futuretest2; + +trait Awaitable* test2(int a) { + struct _Futuretest2* ptr = malloc(sizeof(struct _Futuretest2)); + ptr->a = a; + ptr->__future_state = 0; + return ptr; +} + +async int f(int start) { + int result = await read(2); + if (start < 20) + start = await test2(1); + return result + start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-of-return/await-expr-of-return.cbs b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-of-return/await-expr-of-return.cbs new file mode 100644 index 000000000000..9dd62ea07415 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-of-return/await-expr-of-return.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-single-judgement/await-expr-single-judgement.cbs b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-single-judgement/await-expr-single-judgement.cbs new file mode 100644 index 000000000000..41a0095a14d8 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/AwaitExpr/await-expr-single-judgement/await-expr-single-judgement.cbs @@ -0,0 +1,58 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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); + + int b = 0; + a = await read(2); + while (b != a) + b = await read(2); + + a = await read(3); + do + b = await read(3); + while (b != a); + + return start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/Definition/async_definition_1/async_definition_1.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/Definition/async_definition_1/async_definition_1.cbs new file mode 100644 index 000000000000..a6c29dc84822 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/Definition/async_definition_1/async_definition_1.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int g(); + +async int f() { + int a = await g(); + return a; +} + +async int g() { + int a = await read(1); + return 0; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-different-return-type2/async-different-return-type2.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-different-return-type2/async-different-return-type2.cbs new file mode 100644 index 000000000000..2b808aa98553 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-different-return-type2/async-different-return-type2.cbs @@ -0,0 +1,48 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include +#include + +async int read(int a) { + return 0; +} + +async bool int::g(); + +async int int::f() { + await int::g(); + return 0; +} + +async bool int::g() { + trait Awaitable* a = read(1); + await a; + return false; +} + +typedef struct Identity_bool { + bool result; +}Identity_bool; + +trait Continuation *Identity_bool::resume(This *this, bool* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_bool; + +int main() { + trait Awaitable* this = int::f(); + struct Identity_bool result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-type-with-pointer/async-type-with-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-type-with-pointer/async-type-with-pointer.cbs new file mode 100644 index 000000000000..0661e77c343b --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/async-type-with-pointer/async-type-with-pointer.cbs @@ -0,0 +1,48 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int* f() { + int a = 1; + int* b = &a; + int c; + if(a == 1) { + if (*b == 3) + int c = await read(3); + int c = await read(2); + } + int* d = &c; + return d; +} + +typedef struct Identity_int_pointer { + int* result; +}Identity_int_pointer; + + +trait Continuation *Identity_int_pointer::resume(This *this, int** arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int_pointer; + +int main() { + trait Awaitable* this = f(); + struct Identity_int_pointer result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/await-different-return-type/await-different-return-type.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/await-different-return-type/await-different-return-type.cbs new file mode 100644 index 000000000000..2146cb82f8f0 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/await-different-return-type/await-different-return-type.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async void g(); + +async int f() { + await g(); + return 0; +} + +async void g() { + trait Awaitable* a = read(1); + await a; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/typealias-return-type/typealias-return-type.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/typealias-return-type/typealias-return-type.cbs new file mode 100644 index 000000000000..db42545b6576 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/DifferenctReturnType/typealias-return-type/typealias-return-type.cbs @@ -0,0 +1,59 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +typedef unsigned int UINT32; +async UINT32 f() { + await read(1); + return 0; +} + +trait Awaitable* (*CallBack)() = f; +async UINT32 g() { + UINT32 i = 0; + i = await CallBack(); + return i; +} + +async unsigned int q() { + unsigned int i = 0; + i = await CallBack(); + return i; +} + +async UINT32 h() { + UINT32 i = 0; + i = await q(); + return i; +} + +typedef struct Identity_uint { + unsigned int result; +}Identity_uint; + +trait Continuation *Identity_uint::resume(This *this, unsigned int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_uint; + +int main() { + trait Awaitable* this = g(); + struct Identity_uint result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Extern.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Extern.cbs new file mode 100644 index 000000000000..e1836e3a2de2 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Extern.cbs @@ -0,0 +1,26 @@ +// RUN: %clang -CPS %s %S/Inputs/extern-file.cbs -o %test.output + + +#include "continuation.hbs" + +extern async int f(int n); + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = (void *)0; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(5); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Inputs/extern-file.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Inputs/extern-file.cbs new file mode 100644 index 000000000000..ad45745624f5 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/Extern/Inputs/extern-file.cbs @@ -0,0 +1,6 @@ +#include "continuation.hbs" +#include "stdlib.h" + +async int f(int n) { + return 42 + n; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-bscmethod-as-func-pointer/async-bscmethod-as-func-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-bscmethod-as-func-pointer/async-bscmethod-as-func-pointer.cbs new file mode 100644 index 000000000000..77b1639d0aa0 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-bscmethod-as-func-pointer/async-bscmethod-as-func-pointer.cbs @@ -0,0 +1,31 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int int::g(int start) { + return 0; +} + +async int int::q(int* this) { + return 0; +} + +trait Awaitable* (*CallBack)(int) = int::g; +trait Awaitable* (*CallBack2)(int*) = int::q; + +async int f(int start) { + int result = await CallBack(1); + result = await CallBack2(&result); + return result; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-func-as-func-pointer/async-func-as-func-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-func-as-func-pointer/async-func-as-func-pointer.cbs new file mode 100644 index 000000000000..3def1220fd68 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/FuncPointer/async-func-as-func-pointer/async-func-as-func-pointer.cbs @@ -0,0 +1,24 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int g(int start) { + return 0; +} + +trait Awaitable* (*CallBack)(int) = g; +async int f(int start) { + int result = await CallBack(1); + return result; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-instance-member-function/async-instance-member-function.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-instance-member-function/async-instance-member-function.cbs new file mode 100644 index 000000000000..566e37f1a2a5 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-instance-member-function/async-instance-member-function.cbs @@ -0,0 +1,48 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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) { + trait Awaitable* a = read(1); + await a; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = int::f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-member-function/async-member-function.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-member-function/async-member-function.cbs new file mode 100644 index 000000000000..fa09361f3976 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/async-member-function/async-member-function.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async void int::g(); + +async int int::f() { + await int::g(); + return 0; +} + +async void int::g() { + trait Awaitable* a = read(1); + await a; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = int::f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-for-trait-multi-pointer/static-async-for-trait-multi-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-for-trait-multi-pointer/static-async-for-trait-multi-pointer.cbs new file mode 100644 index 000000000000..bb029e9f22b9 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-for-trait-multi-pointer/static-async-for-trait-multi-pointer.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int int::g() { + trait Awaitable* a = read(1); + trait Awaitable** b = &a; + int tmp = await *b; + return tmp; +} + +async int int::f() { + await int::g(); + return 0; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = int::f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-member-function/static-async-member-function.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-member-function/static-async-member-function.cbs new file mode 100644 index 000000000000..de8609dfd8be --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/MemberFunc/static-async-member-function/static-async-member-function.cbs @@ -0,0 +1,79 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +static async int int::g() { + trait Awaitable* a = read(1); + int tmp = await a; + return tmp; +} + +async int int::f() { + await int::g(); + return 0; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = int::f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +//CHECK: void struct__Futureg_free(struct _Futureg *this) { +//CHECK-NEXT: if (this->Ft_1.data != 0) { +//CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +//CHECK-NEXT: this->Ft_1.data = (void *)0; +//CHECK-NEXT: } +//CHECK-NEXT: } + +//CHECK: struct __Trait_Continuation_struct_Void int__f_state_transiton(struct _Futuref *this, void *extra) { +//CHECK-NEXT: switch (this->__future_state) { +//CHECK-NEXT: case 0: +//CHECK-NEXT: goto __L0; +//CHECK-NEXT: case 1: +//CHECK-NEXT: goto __L1; +//CHECK-NEXT: } +//CHECK-NEXT: __L0: +//CHECK-NEXT: ; +//CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +//CHECK-NEXT: this->Ft_1 = int___g(); +//CHECK-NEXT: this->__future_state = 1; +//CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +//CHECK-NEXT: __L1: +//CHECK-NEXT: ; +//CHECK-NEXT: int Res_1 = *(int *)extra; +//CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +//CHECK-NEXT: this->Ft_1.data = 0; +//CHECK-NEXT: Res_1; +//CHECK-NEXT: { +//CHECK-NEXT: this->__future_state = -1; +//CHECK-NEXT: int __RES_RETURN = 0; +//CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +//CHECK-NEXT: } +//CHECK-NEXT:} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/NonCallAwaitExpr/await-non-call/await-non-call.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/NonCallAwaitExpr/await-non-call/await-non-call.cbs new file mode 100644 index 000000000000..63340fc38320 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/NonCallAwaitExpr/await-non-call/await-non-call.cbs @@ -0,0 +1,47 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int g(); + +async int f() { + int a = await g(); + return a; +} + +async int g() { + trait Awaitable* a = read(1); + await a; + return 0; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/recursive-async-call/recursive-async-call.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/recursive-async-call/recursive-async-call.cbs new file mode 100644 index 000000000000..376197398bbc --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/recursive-async-call/recursive-async-call.cbs @@ -0,0 +1,59 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// expected-no-diagnostics + +// since it's a recursive call, we will get a segv if we run it. + +// Test without serialization: +// RUN: %clang_cc1 -CPS -triple x86_64-unknown-unknown \ +// RUN: -internal-isystem %S/../../../../../../../../lib/Headers/bsc_include \ +// RUN: -internal-externc-isystem /usr/include/x86_64-linux-gnu \ +// RUN: -internal-externc-isystem /include -internal-externc-isystem /usr/include -ast-dump %s \ +// RUN: | FileCheck --strict-whitespace %s +// +// Test with serialization: +// RUN: %clang_cc1 -CPS -triple x86_64-unknown-unknown \ +// RUN: -internal-isystem %S/../../../../../../../../lib/Headers/bsc_include \ +// RUN: -internal-externc-isystem /usr/include/x86_64-linux-gnu \ +// RUN: -internal-externc-isystem /include -internal-externc-isystem /usr/include -emit-pch -o %t %s +// RUN: %clang_cc1 -CPS -x bsc -triple x86_64-unknown-unknown \ +// RUN: -internal-externc-isystem /usr/include/x86_64-linux-gnu \ +// RUN: -internal-externc-isystem /include -internal-externc-isystem /usr/include -include-pch %t -ast-dump-all /dev/null \ +// RUN: | sed -e "s/ //" -e "s/ imported//" \ +// RUN: | FileCheck --strict-whitespace %s + +#include "continuation.hbs" +#include + +async int f() { + int a = await f(); + return a; +} + +// CHECK: |-FunctionDecl {{.*}} col:11 used __f 'struct __Trait_Awaitable (void)' + +// CHECK: |-FunctionDecl {{.*}} line:30:11 used __f 'struct __Trait_Awaitable (void)' +// CHECK-NEXT: | `-CompoundStmt {{.*}} +// CHECK-NEXT: | |-DeclStmt {{.*}} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call-2/static-recursive-async-call-2.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call-2/static-recursive-async-call-2.cbs new file mode 100644 index 000000000000..c7f8d0ee7209 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call-2/static-recursive-async-call-2.cbs @@ -0,0 +1,104 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + + +int g(int x) { + return x; +} + +static async int f(int n) { + if (n == 0 || n == 1) + return 1; + int tmp = g(await f(n-1)); + return n * tmp; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(3); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK:struct _Futuref { +// CHECK-NEXT: int n; +// CHECK-NEXT: int tmp; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_1; +// CHECK-NEXT: int __future_state; +// CHECK-NEXT: struct __Trait_Continuation_int __cont; +// CHECK-NEXT: }; + +// CHECK:void struct__Futuref_free(struct _Futuref *this) { +// CHECK-NEXT: if (this->Ft_1.data != 0) { +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = (void *)0; +// CHECK-NEXT: } +// CHECK-NEXT:} +// CHECK-EMPTY: +// CHECK-NEXT:struct __Trait_Awaitable_Vtable_int __Trait_Awaitable_Vtable_f = {(struct __Trait_Continuation_struct_Void (*)(void *, struct __Trait_Continuation_int))struct__Futuref_awaitable, (void (*)(void *))struct__Futuref_free}; +// CHECK-EMPTY: +// CHECK-NEXT:struct __Trait_Continuation_struct_Void _f_state_transiton(struct _Futuref *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: if (this->n == 0 || this->n == 1) { +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = 1; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: this->Ft_1 = __f(this->n - 1); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->tmp = g(Res_1); +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN_1 = this->n * this->tmp; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN_1); +// CHECK-NEXT: } +// CHECK-NEXT:} +// CHECK-EMPTY: +// CHECK:struct __Trait_Awaitable_int __f(int n) { +// CHECK-NEXT: struct _Futuref *data = calloc(1, sizeof(struct _Futuref)); +// CHECK-NEXT: if (data == 0) { +// CHECK-NEXT: exit(1); +// CHECK-NEXT: } +// CHECK-NEXT: data->n = n; +// CHECK-NEXT: data->__future_state = 0; +// CHECK-NEXT: struct __Trait_Awaitable_int fp = {(void *)data, &__Trait_Awaitable_Vtable_f}; +// CHECK-NEXT: return fp; +// CHECK-NEXT: } \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call/static-recursive-async-call.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call/static-recursive-async-call.cbs new file mode 100644 index 000000000000..d07a3c26ee46 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/RecursiveCall/static-recursive-async-call/static-recursive-async-call.cbs @@ -0,0 +1,99 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +static async int f(int n) { + if (n == 0 || n == 1) + return 1; + int tmp = await f(n-1); + return n * tmp; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(3); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK:struct _Futuref { +// CHECK-NEXT: int n; +// CHECK-NEXT: int tmp; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_1; +// CHECK-NEXT: int __future_state; +// CHECK-NEXT: struct __Trait_Continuation_int __cont; +// CHECK-NEXT: }; + +// CHECK:void struct__Futuref_free(struct _Futuref *this) { +// CHECK-NEXT: if (this->Ft_1.data != 0) { +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = (void *)0; +// CHECK-NEXT: } +// CHECK-NEXT:} +// CHECK-EMPTY: +// CHECK-NEXT:struct __Trait_Awaitable_Vtable_int __Trait_Awaitable_Vtable_f = {(struct __Trait_Continuation_struct_Void (*)(void *, struct __Trait_Continuation_int))struct__Futuref_awaitable, (void (*)(void *))struct__Futuref_free}; +// CHECK-EMPTY: +// CHECK-NEXT:struct __Trait_Continuation_struct_Void _f_state_transiton(struct _Futuref *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: if (this->n == 0 || this->n == 1) { +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = 1; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: this->Ft_1 = __f(this->n - 1); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->tmp = Res_1; +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN_1 = this->n * this->tmp; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN_1); +// CHECK-NEXT: } +// CHECK-NEXT:} +// CHECK-EMPTY: +// CHECK-NEXT:struct __Trait_Awaitable_int __f(int n) { +// CHECK-NEXT: struct _Futuref *data = calloc(1, sizeof(struct _Futuref)); +// CHECK-NEXT: if (data == 0) { +// CHECK-NEXT: exit(1); +// CHECK-NEXT: } +// CHECK-NEXT: data->n = n; +// CHECK-NEXT: data->__future_state = 0; +// CHECK-NEXT: struct __Trait_Awaitable_int fp = {(void *)data, &__Trait_Awaitable_Vtable_f}; +// CHECK-NEXT: return fp; +// CHECK-NEXT:} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer-2/async-func-pointer-2.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer-2/async-func-pointer-2.cbs new file mode 100644 index 000000000000..98711007357b --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer-2/async-func-pointer-2.cbs @@ -0,0 +1,22 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int f() { return 0; } + +trait Awaitable* (*pollFunc) () = f; + +async void g() { + await pollFunc(); +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer/async-func-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer/async-func-pointer.cbs new file mode 100644 index 000000000000..6e5ed8c3e6a2 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-pointer/async-func-pointer.cbs @@ -0,0 +1,26 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +typedef trait Awaitable* (*pollFunc) (); // triger point 1, do not change + +typedef struct EQueueFunc { + pollFunc func; +} EQueueFunc; + + +async void f() { // triger point 2, do not change + EQueueFunc f; + await f.func(); +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-volatile/async-func-volatile.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-volatile/async-func-volatile.cbs new file mode 100644 index 000000000000..43bea61a07c7 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-volatile/async-func-volatile.cbs @@ -0,0 +1,44 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async volatile int f() { + int a = 1; + int b = a - 1; + int n[10]; + for (int i=0; i<10; i++) { + n[i] = i + 100; + } + return 0; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-with-owned/async-func-with-owned.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-with-owned/async-func-with-owned.cbs new file mode 100644 index 000000000000..12e5a081d70d --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-func-with-owned/async-func-with-owned.cbs @@ -0,0 +1,43 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include +T* owned malloc_owned(T value) { + T * p = (T *) malloc( sizeof(T) ); + *p = value; + return (T* owned)p; +} + +void free_owned(T* owned p) { + free( (T*)p ); +} + +struct Owned { + T* owned p; +}; + +struct Owned make_owned(T value) { + struct Owned ret= {.p = malloc_owned(value)}; + return ret; +} + +async int f() { + return 0; +} + +async int foo() { + struct Owned q = make_owned(2); + int a = await f(); + int * p = (int *) q.p; + return a; +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/async-function-without-await-expression/async-function-without-await-expression.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-function-without-await-expression/async-function-without-await-expression.cbs new file mode 100644 index 000000000000..5bfe8cea6220 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/async-function-without-await-expression/async-function-without-await-expression.cbs @@ -0,0 +1,38 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int f() { + return 0; +} + +async int g() { + return await f(); +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = g(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/leaf-node-async-function/leaf-node-async-function.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/leaf-node-async-function/leaf-node-async-function.cbs new file mode 100644 index 000000000000..72f92719ce60 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/leaf-node-async-function/leaf-node-async-function.cbs @@ -0,0 +1,45 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +static async int test() { + return 42; +} + +async int f(int start) { + start = 3; + int a = await test(); + return a + start; +} + +async int g() { + int tmp = await f(3); + return 42; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = g(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/malloc-free-call/malloc-free-call.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/malloc-free-call/malloc-free-call.cbs new file mode 100644 index 000000000000..303fb297c7a7 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/malloc-free-call/malloc-free-call.cbs @@ -0,0 +1,69 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int n) { + int tmp1 = await read(n-1); + int tmp2 = await read(n); + return tmp2 + tmp1 + 42; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(3); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK:void struct__Futuref_free(struct _Futuref *this) { +// CHECK-NEXT: if (this->Ft_2.data != 0) { +// CHECK-NEXT: this->Ft_2.vtable->free(this->Ft_2.data); +// CHECK-NEXT: this->Ft_2.data = (void *)0; +// CHECK-NEXT: } +// CHECK-NEXT: if (this->Ft_1.data != 0) { +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = (void *)0; +// CHECK-NEXT: } +// CHECK-NEXT: if (this != 0) { +// CHECK-NEXT: free((void *)this); +// CHECK-NEXT: this = (struct _Futuref *)(void *)0; +// CHECK-NEXT: } +// CHECK-NEXT: } + +// CHECK: struct __Trait_Awaitable_Vtable_int __Trait_Awaitable_Vtable_f = {(struct __Trait_Continuation_struct_Void (*)(void *, struct __Trait_Continuation_int))struct__Futuref_awaitable, (void (*)(void *))struct__Futuref_free}; + +// CHECK:struct __Trait_Awaitable_int __f(int n) { +// CHECK-NEXT: struct _Futuref *data = calloc(1, sizeof(struct _Futuref)); +// CHECK-NEXT: if (data == 0) { +// CHECK-NEXT: exit(1); +// CHECK-NEXT: } +// CHECK-NEXT: data->n = n; +// CHECK-NEXT: data->__future_state = 0; +// CHECK-NEXT: struct __Trait_Awaitable_int fp = {(void *)data, &__Trait_Awaitable_Vtable_f}; +// CHECK-NEXT: return fp; +// CHECK-NEXT: } \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/static-async-function-opt/static-async-function-opt.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/static-async-function-opt/static-async-function-opt.cbs new file mode 100644 index 000000000000..6106b5324dc6 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/static-async-function-opt/static-async-function-opt.cbs @@ -0,0 +1,45 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int test() { + return 42; +} + +static async int f(int start) { + start = 3; + int a = await test(); + return a + start; +} + +async int g() { + int tmp = await f(3); + return 42; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = g(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/trait-inside-async/trait-inside-async.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/trait-inside-async/trait-inside-async.cbs new file mode 100644 index 000000000000..4665632c11d2 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/trait-inside-async/trait-inside-async.cbs @@ -0,0 +1,32 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics +#include "continuation.hbs" +#include + +struct A {}; + +trait B {}; + +impl trait B for struct A; + +struct A* foo() { + return 0; +} + +void bar(trait B* x) { + return; +} + + +async void f() { + bar(foo()); +} + +int main() { + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/unused-await-expression/unused-await-expression.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/unused-await-expression/unused-await-expression.cbs new file mode 100644 index 000000000000..42eccb0ea502 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/unused-await-expression/unused-await-expression.cbs @@ -0,0 +1,39 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + await read(await read(1)); + return start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function1/volatile-async-function1.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function1/volatile-async-function1.cbs new file mode 100644 index 000000000000..d4e8d2a17673 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function1/volatile-async-function1.cbs @@ -0,0 +1,43 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async volatile char g(char x) { + char a = await g(1); + switch (1) { + case 1: + return await g(2); + break; + case 2: + return await g(3); + break; + default: + return await g(4); + } + return 0; +} + +typedef struct Identity_char { + char result; +}Identity_char; + +trait Continuation *Identity_char::resume(This *this, char* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_char; + +int main() { + trait Awaitable* this = g(1); + struct Identity_char result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function2/volatile-async-function2.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function2/volatile-async-function2.cbs new file mode 100644 index 000000000000..50295cca15d4 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Other/volatile-async-function2/volatile-async-function2.cbs @@ -0,0 +1,38 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async volatile int g(int x) { + int a = await g(1); + return 0; + if(1) { + if (3) + return await g(3); + return await g(2); + } +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = g(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/auto-storage-class/auto-storage-class.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/auto-storage-class/auto-storage-class.cbs new file mode 100644 index 000000000000..b56948a3674f --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/auto-storage-class/auto-storage-class.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + auto int j = 1; + { + auto int j= 2; + { + auto int j = 3; + } + } + int result = await read(1); + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/await-expr-for/await-expr-for.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/await-expr-for/await-expr-for.cbs new file mode 100644 index 000000000000..99069e4b8d68 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/await-expr-for/await-expr-for.cbs @@ -0,0 +1,42 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int result = start; + for (int i = 0; i < start; i++) { + int a = await read(1); + } + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/func-invoke/func-invoke.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/func-invoke/func-invoke.cbs new file mode 100644 index 000000000000..bf92b6d369df --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/func-invoke/func-invoke.cbs @@ -0,0 +1,44 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +int test() { + return 5; +} + +async int f(int start) { + start = test(); + int result = await read(1); + return result + start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/register-storage-class/register-storage-class.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/register-storage-class/register-storage-class.cbs new file mode 100644 index 000000000000..8a3165ec07d9 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/register-storage-class/register-storage-class.cbs @@ -0,0 +1,42 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + register char a = 'S'; + register double b = 10; + register int c = 8; + int result = await read(1); + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/static-storage-class/static-storage-class.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/static-storage-class/static-storage-class.cbs new file mode 100644 index 000000000000..b44227475f4d --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Common/static-storage-class/static-storage-class.cbs @@ -0,0 +1,45 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +static int count = 10; + +async int f(int start) { + while (count--) + { + start ++; + } + int result = await read(2); + return result + 5 + start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Enum/enum1/enum1.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Enum/enum1/enum1.cbs new file mode 100644 index 000000000000..f67405c48a87 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Enum/enum1/enum1.cbs @@ -0,0 +1,43 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun }; +enum week a = Mon, b = Wed, c = Sat; + +async int f(int start) { + start = Mon; + int result = await read(1); + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl/array-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl/array-decl.cbs new file mode 100644 index 000000000000..727d59074ae3 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl/array-decl.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl1/array-decl1.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl1/array-decl1.cbs new file mode 100644 index 000000000000..7913907e7a2e --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/array-decl1/array-decl1.cbs @@ -0,0 +1,41 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/base-type-decl/base-type-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/base-type-decl/base-type-decl.cbs new file mode 100644 index 000000000000..c17b864cab0b --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/base-type-decl/base-type-decl.cbs @@ -0,0 +1,55 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs new file mode 100644 index 000000000000..0fb0256fe536 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs @@ -0,0 +1,86 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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"}; + const int newStart = start; + + int result = await read(newStart); + return result + 5 + start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + + +// CHECK: struct __Trait_Continuation_struct_Void _f_state_transiton(struct _Futuref *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: const long myLong = 100000L; +// CHECK-NEXT: const unsigned int myUnsignedInt = 10U; +// CHECK-NEXT: const float myFloat = 3.1400001F; +// CHECK-NEXT: const double myDouble = 3.1415899999999999; +// CHECK-NEXT: const struct Addr addr = {1, "hello"}; +// CHECK-NEXT: this->newStart = this->start; +// CHECK-NEXT: this->Ft_1 = __read(this->newStart); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->result = Res_1; +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->result + 5 + this->start; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT:} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/constexpr-decl/constexpr-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/constexpr-decl/constexpr-decl.cbs new file mode 100644 index 000000000000..87afec99340d --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/constexpr-decl/constexpr-decl.cbs @@ -0,0 +1,89 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +struct Addr +{ + int a; + char str[10]; +}; + +async int f(int start) { + constexpr long myLong = 100000L; + constexpr unsigned int myUnsignedInt = 10U; + constexpr int myInt = 2; + static struct Addr addr = {myInt, "hello"}; + + int result = await read(myInt); + return result + 5 + start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK: struct _Futuref { +// CHECK-NEXT: int start; +// CHECK-NEXT: int result; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_1; +// CHECK-NEXT: int __future_state; +// CHECK-NEXT: struct __Trait_Continuation_int __cont; +// CHECK-NEXT: }; + +// CHECK: struct __Trait_Continuation_struct_Void _f_state_transiton(struct _Futuref *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: long myLong = 100000L; +// CHECK-NEXT: unsigned int myUnsignedInt = 10U; +// CHECK-NEXT: int myInt = 2; +// CHECK-NEXT: static struct Addr addr = {2, "hello"}; +// CHECK-NEXT: this->Ft_1 = __read(2); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->result = Res_1; +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->result + 5 + this->start; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT:} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/extern-decl/extern-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/extern-decl/extern-decl.cbs new file mode 100644 index 000000000000..bd320d445577 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/extern-decl/extern-decl.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/global-decl/global-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/global-decl/global-decl.cbs new file mode 100644 index 000000000000..f8bf6b92939c --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/global-decl/global-decl.cbs @@ -0,0 +1,42 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +int g = 5; + +async int f(int start) { + g = 6; + int result = await read(1); + return result + g; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl/literal-quantity-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl/literal-quantity-decl.cbs new file mode 100644 index 000000000000..9b3e257da576 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/literal-quantity-decl/literal-quantity-decl.cbs @@ -0,0 +1,43 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-decl/multi-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-decl/multi-decl.cbs new file mode 100644 index 000000000000..80f324040d0a --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-decl/multi-decl.cbs @@ -0,0 +1,44 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl/multi-dimension-array-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl/multi-dimension-array-decl.cbs new file mode 100644 index 000000000000..4d2558a1405b --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/multi-dimension-array-decl/multi-dimension-array-decl.cbs @@ -0,0 +1,43 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/pointer-decl/pointer-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/pointer-decl/pointer-decl.cbs new file mode 100644 index 000000000000..02b798e995ae --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/pointer-decl/pointer-decl.cbs @@ -0,0 +1,50 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/static-decl/static-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/static-decl/static-decl.cbs new file mode 100644 index 000000000000..38b23ab2f393 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/static-decl/static-decl.cbs @@ -0,0 +1,97 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +struct Addr +{ + int a; + char str[10]; +}; + +async int f(int start) { + const int myFirstInt = 1; + const int myFirstInt1 = myFirstInt; + static long myLong = 100000L; + static unsigned int myUnsignedInt = 10U; + static float myFloat = 3.14f; + static double myDouble = 3.14159; + static struct Addr addr = {myFirstInt1, "hello"}; + static int myInt = myFirstInt; + + int result = await read(myInt); + return result + 5 + start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK: struct _Futuref { +// CHECK-NEXT: int start; +// CHECK-NEXT: int result; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_1; +// CHECK-NEXT: int __future_state; +// CHECK-NEXT: struct __Trait_Continuation_int __cont; +// CHECK-NEXT: }; + +// CHECK:struct __Trait_Continuation_struct_Void _f_state_transiton(struct _Futuref *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: const int myFirstInt = 1; +// CHECK-NEXT: const int myFirstInt1 = myFirstInt; +// CHECK-NEXT: static long myLong = 100000L; +// CHECK-NEXT: static unsigned int myUnsignedInt = 10U; +// CHECK-NEXT: static float myFloat = 3.1400001F; +// CHECK-NEXT: static double myDouble = 3.1415899999999999; +// CHECK-NEXT: static struct Addr addr = {myFirstInt1, "hello"}; +// CHECK-NEXT: static int myInt = myFirstInt; +// CHECK-NEXT: this->Ft_1 = __read(myInt); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->result = Res_1; +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->result + 5 + this->start; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT:} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/string-decl/string-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/string-decl/string-decl.cbs new file mode 100644 index 000000000000..f5785a010190 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/string-decl/string-decl.cbs @@ -0,0 +1,42 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/struct-decl/struct-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/struct-decl/struct-decl.cbs new file mode 100644 index 000000000000..651ffe6a724d --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/struct-decl/struct-decl.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/typedef-decl/typedef-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/typedef-decl/typedef-decl.cbs new file mode 100644 index 000000000000..23eba4ba61be --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/typedef-decl/typedef-decl.cbs @@ -0,0 +1,48 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +typedef struct node +{ + int data; + struct node *next; +} *Pnode, Node; + +typedef struct node B; +B node1; + +async int f(int start) { + int a = await read(1); + return a; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl/uninit-array-decl.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl/uninit-array-decl.cbs new file mode 100644 index 000000000000..ab280161d2bc --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl/uninit-array-decl.cbs @@ -0,0 +1,52 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl1/uninit-array-decl1.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl1/uninit-array-decl1.cbs new file mode 100644 index 000000000000..c463c660a4f9 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/uninit-array-decl1/uninit-array-decl1.cbs @@ -0,0 +1,116 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +struct Addr { + int a; +}; + +async int f() { + int a; + float b; + char c; + char *p; + float f[10]; + struct Addr addr[10]; + a = 1; + int cc[10][3] = {0}; + int n[10]; + for (int i=0; i<10; i++) { + n[i] = i + 100; + } + int x = await read(2); + return 42; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK:struct _Futuref { +// CHECK-NEXT: int a; +// CHECK-NEXT: float b; +// CHECK-NEXT: char c; +// CHECK-NEXT: char *p; +// CHECK-NEXT: float f[10]; +// CHECK-NEXT: struct Addr addr[10]; +// CHECK-NEXT: int cc[10][3]; +// CHECK-NEXT: int n[10]; +// CHECK-NEXT: int i; +// CHECK-NEXT: int x; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_1; +// CHECK-NEXT: int __future_state; +// CHECK-NEXT: struct __Trait_Continuation_int __cont; +// CHECK-NEXT: }; + +// CHECK:struct __Trait_Continuation_struct_Void _f_state_transiton(struct _Futuref *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: int a; +// CHECK-NEXT: float b; +// CHECK-NEXT: char c; +// CHECK-NEXT: char *p; +// CHECK-NEXT: float f[10]; +// CHECK-NEXT: struct Addr addr[10]; +// CHECK-NEXT: this->a = 1; +// CHECK-NEXT: int cc[10][3] = {0}; +// CHECK-NEXT: int *__ASSIGNED_ARRAY_PTR_int = (int *)cc; +// CHECK-NEXT: int *__ARRAY_PTR_int = (int *)this->cc; +// CHECK-NEXT: for (int I = 0; I < 30; ++I) { +// CHECK-NEXT: *__ARRAY_PTR_int++ = *__ASSIGNED_ARRAY_PTR_int++; +// CHECK-NEXT: } +// CHECK-NEXT: __ARRAY_PTR_int = /*implicit*/(int *)0; +// CHECK-NEXT: int n[10]; +// CHECK-NEXT: for (this->i = 0; this->i < 10; this->i++) { +// CHECK-NEXT: this->n[this->i] = this->i + 100; +// CHECK-NEXT: } +// CHECK-NEXT: this->Ft_1 = __read(2); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->x = Res_1; +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = 42; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT:} diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs new file mode 100644 index 000000000000..e6cda4699afb --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs @@ -0,0 +1,137 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int getData() { + int res = 0; + if (res == 0) { + int start = await read(2); + int a = 3; + if (a == 3) { + int start = await read(3); + } + } else { + int start = await read(2); + int a = 3; + if (a == 3) { + int start = await read(3); + } + } + return res; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = getData(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK:struct _FuturegetData { +// CHECK-NEXT: int res; +// CHECK-NEXT: int start; +// CHECK-NEXT: int a; +// CHECK-NEXT: int start_1; +// CHECK-NEXT: int start_2; +// CHECK-NEXT: int a_1; +// CHECK-NEXT: int start_3; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_1; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_2; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_3; +// CHECK-NEXT: struct __Trait_Awaitable_int Ft_4; +// CHECK-NEXT: int __future_state; +// CHECK-NEXT: struct __Trait_Continuation_int __cont; +// CHECK-NEXT: }; + +// CHECK:struct __Trait_Continuation_struct_Void _getData_state_transiton(struct _FuturegetData *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: case 2: +// CHECK-NEXT: goto __L2; +// CHECK-NEXT: case 3: +// CHECK-NEXT: goto __L3; +// CHECK-NEXT: case 4: +// CHECK-NEXT: goto __L4; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: this->res = 0; +// CHECK-NEXT: if (this->res == 0) { +// CHECK-NEXT: this->Ft_1 = __read(2); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_getData}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->start = Res_1; +// CHECK-NEXT: this->a = 3; +// CHECK-NEXT: if (this->a == 3) { +// CHECK-NEXT: this->Ft_2 = __read(3); +// CHECK-NEXT: this->__future_state = 2; +// CHECK-NEXT: return this->Ft_2.vtable->awaitable(this->Ft_2.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_getData}); +// CHECK-NEXT: __L2: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_2 = *(int *)extra; +// CHECK-NEXT: this->Ft_2.vtable->free(this->Ft_2.data); +// CHECK-NEXT: this->Ft_2.data = 0; +// CHECK-NEXT: this->start_1 = Res_2; +// CHECK-NEXT: } +// CHECK-NEXT: } else { +// CHECK-NEXT: this->Ft_3 = __read(2); +// CHECK-NEXT: this->__future_state = 3; +// CHECK-NEXT: return this->Ft_3.vtable->awaitable(this->Ft_3.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_getData}); +// CHECK-NEXT: __L3: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_3 = *(int *)extra; +// CHECK-NEXT: this->Ft_3.vtable->free(this->Ft_3.data); +// CHECK-NEXT: this->Ft_3.data = 0; +// CHECK-NEXT: this->start_2 = Res_3; +// CHECK-NEXT: this->a_1 = 3; +// CHECK-NEXT: if (this->a_1 == 3) { +// CHECK-NEXT: this->Ft_4 = __read(3); +// CHECK-NEXT: this->__future_state = 4; +// CHECK-NEXT: return this->Ft_4.vtable->awaitable(this->Ft_4.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_getData}); +// CHECK-NEXT: __L4: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_4 = *(int *)extra; +// CHECK-NEXT: this->Ft_4.vtable->free(this->Ft_4.data); +// CHECK-NEXT: this->Ft_4.data = 0; +// CHECK-NEXT: this->start_3 = Res_4; +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->res; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT:} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer/arithmetic-op-of-c-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer/arithmetic-op-of-c-pointer.cbs new file mode 100644 index 000000000000..a835a8b4ca1c --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/arithmetic-op-of-c-pointer/arithmetic-op-of-c-pointer.cbs @@ -0,0 +1,50 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer/c-pointer-to-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer/c-pointer-to-pointer.cbs new file mode 100644 index 000000000000..38fd40d49c7a --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/c-pointer-to-pointer/c-pointer-to-pointer.cbs @@ -0,0 +1,45 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int V; + int *ptr1; + int **ptr2; + V = 100; + ptr1 = &V; + ptr2 = &ptr1; + int result = await read(1); + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/func-pointer/func-pointer.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/func-pointer/func-pointer.cbs new file mode 100644 index 000000000000..847d1bd777ca --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Pointer/func-pointer/func-pointer.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Struct/struct-init/struct-init.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Struct/struct-init/struct-init.cbs new file mode 100644 index 000000000000..e8933477f6b7 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Struct/struct-init/struct-init.cbs @@ -0,0 +1,50 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Union/union-init/union-init.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Union/union-init/union-init.cbs new file mode 100644 index 000000000000..5b5b49d278d6 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/DeclStmt/Union/union-init/union-init.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/await-expr-if/await-expr-if.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/await-expr-if/await-expr-if.cbs new file mode 100644 index 000000000000..36c9e93fa52b --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/await-expr-if/await-expr-if.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-else-statement/if-else-statement.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-else-statement/if-else-statement.cbs new file mode 100644 index 000000000000..9ce7ad0eaecf --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-else-statement/if-else-statement.cbs @@ -0,0 +1,43 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int x = 3; + int result; + if (x < 20) { + result = await read(1); + } else result = x; + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-nested-if-statement/if-nested-if-statement.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-nested-if-statement/if-nested-if-statement.cbs new file mode 100644 index 000000000000..e6c5717cb774 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-nested-if-statement/if-nested-if-statement.cbs @@ -0,0 +1,44 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized-static/if-statement-uninitialized-static.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized-static/if-statement-uninitialized-static.cbs new file mode 100644 index 000000000000..bde6d7891cb8 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized-static/if-statement-uninitialized-static.cbs @@ -0,0 +1,55 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +static async int f() { + int ret; + if (1) { + ret = await read(0); + } else { + ret = await read(0); + } + return ret; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK: struct __Trait_Awaitable_int __f(void) { +// CHECK-NEXT: struct _Futuref *data = calloc(1, sizeof(struct _Futuref)); +// CHECK-NEXT: if (data == 0) { +// CHECK-NEXT: exit(1); +// CHECK-NEXT: } +// CHECK-NEXT: data->__future_state = 0; +// CHECK-NEXT: struct __Trait_Awaitable_int fp = {(void *)data, &__Trait_Awaitable_Vtable_f}; +// CHECK-NEXT: return fp; +// CHECK-NEXT: } \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized/if-statement-uninitialized.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized/if-statement-uninitialized.cbs new file mode 100644 index 000000000000..e32292bdc88a --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement-uninitialized/if-statement-uninitialized.cbs @@ -0,0 +1,55 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f() { + int ret; + if (1) { + ret = await read(0); + } else { + ret = await read(0); + } + return ret; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK: struct __Trait_Awaitable_int __f(void) { +// CHECK-NEXT: struct _Futuref *data = calloc(1, sizeof(struct _Futuref)); +// CHECK-NEXT: if (data == 0) { +// CHECK-NEXT: exit(1); +// CHECK-NEXT: } +// CHECK-NEXT: data->__future_state = 0; +// CHECK-NEXT: struct __Trait_Awaitable_int fp = {(void *)data, &__Trait_Awaitable_Vtable_f}; +// CHECK-NEXT: return fp; +// CHECK-NEXT: } diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement/if-statement.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement/if-statement.cbs new file mode 100644 index 000000000000..2ba7a7d9f6a6 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/if-statement/if-statement.cbs @@ -0,0 +1,43 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int x = 3; + int result; + if (x < 20) { + result = await read(1); + } + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-nested-switch-statement/switch-nested-switch-statement.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-nested-switch-statement/switch-nested-switch-statement.cbs new file mode 100644 index 000000000000..af2897ac0a09 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-nested-switch-statement/switch-nested-switch-statement.cbs @@ -0,0 +1,61 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-statement/switch-statement.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-statement/switch-statement.cbs new file mode 100644 index 000000000000..e53124d3aa6a --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Judgement/switch-statement/switch-statement.cbs @@ -0,0 +1,55 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs new file mode 100644 index 000000000000..c515556a29d2 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs @@ -0,0 +1,94 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int result = await read(1); + if (result !=0) { + goto ERR; + } else if (result != 1) { + goto ERR2; + } + return result; +ERR: + return result; +ERR2: + result = result + 1; + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + +// CHECK:struct __Trait_Continuation_struct_Void _f_state_transiton(struct _Futuref *this, void *extra) { +// CHECK-NEXT: switch (this->__future_state) { +// CHECK-NEXT: case 0: +// CHECK-NEXT: goto __L0; +// CHECK-NEXT: case 1: +// CHECK-NEXT: goto __L1; +// CHECK-NEXT: } +// CHECK-NEXT: __L0: +// CHECK-NEXT: ; +// CHECK-NEXT: this->__cont = *(struct __Trait_Continuation_int *)extra; +// CHECK-NEXT: this->Ft_1 = __read(1); +// CHECK-NEXT: this->__future_state = 1; +// CHECK-NEXT: return this->Ft_1.vtable->awaitable(this->Ft_1.data, (struct __Trait_Continuation_int){this, &__Trait_Continuation_Vtable_int_f}); +// CHECK-NEXT: __L1: +// CHECK-NEXT: ; +// CHECK-NEXT: int Res_1 = *(int *)extra; +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = 0; +// CHECK-NEXT: this->result = Res_1; +// CHECK-NEXT: if (this->result != 0) { +// CHECK-NEXT: goto ERR; +// CHECK-NEXT: } else if (this->result != 1) { +// CHECK-NEXT: goto ERR2; +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->result; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN); +// CHECK-NEXT: } +// CHECK-NEXT: ERR: +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN_1 = this->result; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN_1); +// CHECK-NEXT: } +// CHECK-NEXT: ERR2: +// CHECK-NEXT: this->result = this->result + 1; +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN_2 = this->result; +// CHECK-NEXT: return this->__cont.vtable->resume(this->__cont.data, (void *)&__RES_RETURN_2); +// CHECK-NEXT: } +// CHECK-NEXT:} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/do-while-loop/do-while-loop.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/do-while-loop/do-while-loop.cbs new file mode 100644 index 000000000000..a6175ba46ab8 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/do-while-loop/do-while-loop.cbs @@ -0,0 +1,44 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int i = 0; + do { + start = await read(i); + i++; + } while (i < 3); + int result = start; + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/for-loop/for-loop.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/for-loop/for-loop.cbs new file mode 100644 index 000000000000..dfc1cd3d2c9e --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/for-loop/for-loop.cbs @@ -0,0 +1,42 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + for (int i=0; i<3; i++) { + start = await read(i); + } + int result = start; + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/loop-nested/loop-nested.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/loop-nested/loop-nested.cbs new file mode 100644 index 000000000000..acac91c93770 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/loop-nested/loop-nested.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/while-loop/while-loop.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/while-loop/while-loop.cbs new file mode 100644 index 000000000000..9c989543c24a --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Loop/while-loop/while-loop.cbs @@ -0,0 +1,45 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int i = 0; + while (i < 3) + { + start = await read(i); + i++; + } + int result = start; + return result; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/arithmetic-op/arithmetic-op.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/arithmetic-op/arithmetic-op.cbs new file mode 100644 index 000000000000..08180bddaeae --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/arithmetic-op/arithmetic-op.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/assign-op/assign-op.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/assign-op/assign-op.cbs new file mode 100644 index 000000000000..7690030720d3 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/assign-op/assign-op.cbs @@ -0,0 +1,53 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/bit-op/bit-op.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/bit-op/bit-op.cbs new file mode 100644 index 000000000000..37443f8b6f13 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/bit-op/bit-op.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/logocal-op/logocal-op.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/logocal-op/logocal-op.cbs new file mode 100644 index 000000000000..c01910b29023 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/logocal-op/logocal-op.cbs @@ -0,0 +1,46 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/other-op/other-op.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/other-op/other-op.cbs new file mode 100644 index 000000000000..246a65375cdd --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/other-op/other-op.cbs @@ -0,0 +1,45 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/relational-op/relational-op.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/relational-op/relational-op.cbs new file mode 100644 index 000000000000..3d029c182305 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/Other/Operators/relational-op/relational-op.cbs @@ -0,0 +1,49 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-const-int/async-func-return-const-int.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-const-int/async-func-return-const-int.cbs new file mode 100644 index 000000000000..253d5e8d6d3b --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-const-int/async-func-return-const-int.cbs @@ -0,0 +1,48 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-type/async-func-return-type.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-type/async-func-return-type.cbs new file mode 100644 index 000000000000..e9a963758093 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-type/async-func-return-type.cbs @@ -0,0 +1,111 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +struct _Futuretest1 { + int a; + int res; + int __future_state; + trait Continuation *cont; +}; +typedef struct _Futuretest1 __Futuretest1; + +trait Continuation *struct _Futuretest1::awaitable(__Futuretest1 *this, trait Continuation *extra) { + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->cont = extra; + this->res = this->a; + this->__future_state = -1; + return this->cont->resume(NULL); +} +void struct _Futuretest1::free(__Futuretest1 *this) {} + +impl trait Awaitable for struct _Futuretest1; + +trait Awaitable* test1(int a) { + struct _Futuretest1* ptr = malloc(sizeof(struct _Futuretest1)); + ptr->a = a; + ptr->__future_state = 0; + return ptr; +} + +struct _Futuretest2 { + int a; + int res; + int __future_state; + trait Continuation *cont; +}; +typedef struct _Futuretest2 __Futuretest2; + +trait Continuation *struct _Futuretest2::awaitable(__Futuretest2 *this, trait Continuation *extra) { + switch (this->__future_state) { + case 0: + goto L0; + } + L0: + this->cont = extra; + this->res = this->a; + this->__future_state = -1; + return this->cont->resume(NULL); +} + +void struct _Futuretest2::free(__Futuretest2 *this) {} + +impl trait Awaitable for struct _Futuretest2; + +trait Awaitable* test2(int a) { + struct _Futuretest2* ptr = malloc(sizeof(struct _Futuretest2)); + ptr->a = a; + ptr->__future_state = 0; + return ptr; +} + +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; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} + diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-void/async-func-return-void.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-void/async-func-return-void.cbs new file mode 100644 index 000000000000..16da53787ebc --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/async-func-return-void/async-func-return-void.cbs @@ -0,0 +1,41 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async void f(int start) { + int result = start; + for (int i = 0; i < start; i++) { + int a = await read(1); + } +} + +typedef struct Identity_void { + struct Void result; +}Identity_void; + +trait Continuation *Identity_void::resume(This *this, struct Void* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_void; + +int main() { + trait Awaitable* this = f(1); + struct Identity_void result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type/await-expr-return-type.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type/await-expr-return-type.cbs new file mode 100644 index 000000000000..0cdac3d7a20b --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type/await-expr-return-type.cbs @@ -0,0 +1,40 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +async int f(int start) { + int r1 = await read(1); + int result = await read(1); + return r1 *result + start; +} + +typedef struct Identity_int { + int result; +}Identity_int; + +trait Continuation *Identity_int::resume(This *this, int* arg) { + this->result = *arg; + trait Continuation *res = NULL; + return res; +} + +impl trait Continuation for Identity_int; + +int main() { + trait Awaitable* this = f(1); + struct Identity_int result; + trait Continuation *r = this->awaitable(&result); + this->free(); + return 0; +} \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type1/await-expr-return-type1.cbs b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type1/await-expr-return-type1.cbs new file mode 100644 index 000000000000..52e572bd16b3 --- /dev/null +++ b/clang/test/BSC/Positive/Coroutine/CPS/Treetransform/ReturnStmt/await-expr-return-type1/await-expr-return-type1.cbs @@ -0,0 +1,29 @@ +// RUN: %clang -CPS %s -o %test.output +// RUN: %test.output +// RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/continuation.hbs -o %T/continuation.h +// RUN: %clang -CPS -rewrite-bsc %s -o %t-rw.c +// RUN: %clang %t-rw.c -o %t-rw.output +// RUN: %t-rw.output +// expected-no-diagnostics + +#include "continuation.hbs" +#include + +async int read(int a) { + return 0; +} + +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/Negative/Coroutine/Other/Extern/Extern.cbs b/clang/test/BSC/Positive/Coroutine/Other/Extern/Extern.cbs similarity index 100% rename from clang/test/BSC/Negative/Coroutine/Other/Extern/Extern.cbs rename to clang/test/BSC/Positive/Coroutine/Other/Extern/Extern.cbs diff --git a/clang/test/BSC/Negative/Coroutine/Other/Extern/Inputs/extern-file.cbs b/clang/test/BSC/Positive/Coroutine/Other/Extern/Inputs/extern-file.cbs similarity index 100% rename from clang/test/BSC/Negative/Coroutine/Other/Extern/Inputs/extern-file.cbs rename to clang/test/BSC/Positive/Coroutine/Other/Extern/Inputs/extern-file.cbs diff --git a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs index 072aea9ae03a..64e1951c150e 100644 --- a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs +++ b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs @@ -2,6 +2,7 @@ // RUN: %test.output // RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/future.hbs -o %T/future.h // RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s // RUN: %clang %t-rw.c -o %t-rw.output // RUN: %t-rw.output // expected-no-diagnostics @@ -67,7 +68,9 @@ int main() { // CHECK-NEXT: return struct_PollResult_int_pending(); // CHECK-NEXT: } // CHECK-NEXT: this->result = Res_1; -// CHECK-NEXT: this->__future_state = -1; -// CHECK-NEXT: int __RES_RETURN = this->result + 5 + this->start; -// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN); +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->result + 5 + this->start; +// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN); +// CHECK-NEXT: } // CHECK-NEXT: } \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs index 935864d681fd..7071b5569e29 100644 --- a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs +++ b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs @@ -2,6 +2,7 @@ // RUN: %test.output // RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/future.hbs -o %T/future.h // RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s // RUN: %clang %t-rw.c -o %t-rw.output // RUN: %t-rw.output // expected-no-diagnostics @@ -70,12 +71,16 @@ int main() { // CHECK-NEXT: ; // CHECK-NEXT: this->res = 0; // CHECK-NEXT: if (this->res == 0) { -// CHECK-NEXT: this->Ft_1 = read(2); +// CHECK-NEXT: this->Ft_1 = __read(2); // CHECK-NEXT: __L1: // CHECK-NEXT: ; // CHECK-NEXT: int Res_1; // CHECK-NEXT: struct PollResult_int PR_1 = this->Ft_1.vtable->poll(this->Ft_1.data); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_1, &Res_1)) { +// CHECK-NEXT: if (this->Ft_1.data != 0) { +// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); +// CHECK-NEXT: this->Ft_1.data = (void *)0; +// CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 1; // CHECK-NEXT: return struct_PollResult_int_pending(); @@ -83,12 +88,16 @@ int main() { // CHECK-NEXT: this->start = Res_1; // CHECK-NEXT: this->a = 3; // CHECK-NEXT: if (this->a == 3) { -// CHECK-NEXT: this->Ft_2 = read(3); +// CHECK-NEXT: this->Ft_2 = __read(3); // CHECK-NEXT: __L2: // CHECK-NEXT: ; // CHECK-NEXT: int Res_2; // CHECK-NEXT: struct PollResult_int PR_2 = this->Ft_2.vtable->poll(this->Ft_2.data); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_2, &Res_2)) { +// CHECK-NEXT: if (this->Ft_2.data != 0) { +// CHECK-NEXT: this->Ft_2.vtable->free(this->Ft_2.data); +// CHECK-NEXT: this->Ft_2.data = (void *)0; +// CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 2; // CHECK-NEXT: return struct_PollResult_int_pending(); @@ -96,12 +105,16 @@ int main() { // CHECK-NEXT: this->start_1 = Res_2; // CHECK-NEXT: } // CHECK-NEXT: } else { -// CHECK-NEXT: this->Ft_3 = read(2); +// CHECK-NEXT: this->Ft_3 = __read(2); // CHECK-NEXT: __L3: // CHECK-NEXT: ; // CHECK-NEXT: int Res_3; // CHECK-NEXT: struct PollResult_int PR_3 = this->Ft_3.vtable->poll(this->Ft_3.data); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_3, &Res_3)) { +// CHECK-NEXT: if (this->Ft_3.data != 0) { +// CHECK-NEXT: this->Ft_3.vtable->free(this->Ft_3.data); +// CHECK-NEXT: this->Ft_3.data = (void *)0; +// CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 3; // CHECK-NEXT: return struct_PollResult_int_pending(); @@ -109,12 +122,16 @@ int main() { // CHECK-NEXT: this->start_2 = Res_3; // CHECK-NEXT: this->a_1 = 3; // CHECK-NEXT: if (this->a_1 == 3) { -// CHECK-NEXT: this->Ft_4 = read(3); +// CHECK-NEXT: this->Ft_4 = __read(3); // CHECK-NEXT: __L4: // CHECK-NEXT: ; // CHECK-NEXT: int Res_4; // CHECK-NEXT: struct PollResult_int PR_4 = this->Ft_4.vtable->poll(this->Ft_4.data); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_4, &Res_4)) { +// CHECK-NEXT: if (this->Ft_4.data != 0) { +// CHECK-NEXT: this->Ft_4.vtable->free(this->Ft_4.data); +// CHECK-NEXT: this->Ft_4.data = (void *)0; +// CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 4; // CHECK-NEXT: return struct_PollResult_int_pending(); @@ -122,7 +139,9 @@ int main() { // CHECK-NEXT: this->start_3 = Res_4; // CHECK-NEXT: } // CHECK-NEXT: } -// CHECK-NEXT: this->__future_state = -1; -// CHECK-NEXT: int __RES_RETURN = this->res; -// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN); +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->res; +// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN); +// CHECK-NEXT: } // CHECK-NEXT: } \ No newline at end of file diff --git a/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs b/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs index 6cbec0afbf9b..6b732e971e69 100644 --- a/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs +++ b/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs @@ -2,6 +2,7 @@ // RUN: %test.output // RUN: %clang -rewrite-bsc %S/../../../../../../../../lib/Headers/bsc_include/future.hbs -o %T/future.h // RUN: %clang -rewrite-bsc %s -o %t-rw.c +// RUN: FileCheck --input-file=%t-rw.c %s // RUN: %clang %t-rw.c -o %t-rw.output // RUN: %t-rw.output // expected-no-diagnostics @@ -25,7 +26,7 @@ ERR: return result; ERR2: result = result + 1; - return result; + return result; } int main() { @@ -63,16 +64,22 @@ int main() { // CHECK-NEXT: } else if (this->result != 1) { // CHECK-NEXT: goto ERR2; // CHECK-NEXT: } -// CHECK-NEXT: this->__future_state = -1; -// CHECK-NEXT: int __RES_RETURN = this->result; -// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN); +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN = this->result; +// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN); +// CHECK-NEXT: } // CHECK-NEXT: ERR: -// CHECK-NEXT: this->__future_state = -1; -// CHECK-NEXT: int __RES_RETURN_1 = this->result; -// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN_1); +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN_1 = this->result; +// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN_1); +// CHECK-NEXT: } // CHECK-NEXT: ERR2: // CHECK-NEXT: this->result = this->result + 1; -// CHECK-NEXT: this->__future_state = -1; -// CHECK-NEXT: int __RES_RETURN_2 = this->result; -// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN_2); +// CHECK-NEXT: { +// CHECK-NEXT: this->__future_state = -1; +// CHECK-NEXT: int __RES_RETURN_2 = this->result; +// CHECK-NEXT: return struct_PollResult_int_completed(__RES_RETURN_2); +// CHECK-NEXT: } // CHECK-NEXT: } diff --git a/clang/test/BSC/Positive/Coroutine/Atmoic/rewrite_atmoic.cbs b/clang/test/BSC/Positive/Driver/rewrite-bsc/Atmoic/rewrite_atmoic.cbs similarity index 100% rename from clang/test/BSC/Positive/Coroutine/Atmoic/rewrite_atmoic.cbs rename to clang/test/BSC/Positive/Driver/rewrite-bsc/Atmoic/rewrite_atmoic.cbs -- Gitee From 16a26a0736fa7d5682cb3184aeb6370505f5ace7 Mon Sep 17 00:00:00 2001 From: zhaoxuhui Date: Tue, 17 Dec 2024 10:01:23 +0800 Subject: [PATCH 5/5] [bugfix] fixed tests after rebase --- clang/include/clang/AST/BSC/AsyncBSC.h | 429 +++--- clang/lib/Sema/BSC/SemaBSCContinuation.cpp | 14 +- clang/lib/Sema/BSC/SemaBSCCoroutine.cpp | 1257 ++--------------- clang/lib/Sema/BSC/SemaExprBSC.cpp | 148 ++ clang/lib/Sema/CMakeLists.txt | 3 +- .../MultiDecl/const-decl/const-decl.cbs | 8 +- .../var-decl-multi-same-local-name.cbs | 40 +- .../Other/LabelStmt/label-stmt/label-stmt.cbs | 8 +- 8 files changed, 598 insertions(+), 1309 deletions(-) create mode 100644 clang/lib/Sema/BSC/SemaExprBSC.cpp diff --git a/clang/include/clang/AST/BSC/AsyncBSC.h b/clang/include/clang/AST/BSC/AsyncBSC.h index c075d173e86f..4a247561cf6e 100644 --- a/clang/include/clang/AST/BSC/AsyncBSC.h +++ b/clang/include/clang/AST/BSC/AsyncBSC.h @@ -11,13 +11,15 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_WALKERBSC_H -#define LLVM_CLANG_AST_WALKERBSC_H +#ifndef LLVM_CLANG_AST_ASYNCBSC_H +#define LLVM_CLANG_AST_ASYNCBSC_H #if ENABLE_BSC #include "clang/AST/ASTContext.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/Template.h" +#include "TreeTransform.h" namespace clang { class ASTContext; @@ -1106,20 +1108,27 @@ public: NewFD->setParams(ParmVarDecls); NewFD->setLexicalDeclContext(SemaRef.Context.getTranslationUnitDecl()); - 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); + CompoundStmt *body = + llvm::dyn_cast_if_present(D->getBody()); + // If transforming a declaration without body this may not be present + if (body) { + 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); + body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, + SourceLocation(), false) + .getAs(); } - ReturnStmt *RS = ReturnStmt::Create(SemaRef.Context, SourceLocation(), - nullptr, nullptr); - Stmts.push_back(RS); - Sema::CompoundScopeRAII CompoundScope(SemaRef); - body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, - SourceLocation(), false) - .getAs(); + + Stmt *FuncBody = BaseTransform::TransformStmt(body).getAs(); + NewFD->setBody(FuncBody); } Stmt *FuncBody = BaseTransform::TransformStmt(body).getAs(); @@ -1201,6 +1210,13 @@ static RecordDecl *buildFutureRecordDecl( DeclarationName funcName = FD->getDeclName(); SourceLocation SLoc = FD->getBeginLoc(); SourceLocation ELoc = FD->getEndLoc(); + // Create Record declaration + const std::string Recordname = "_Future" + funcName.getAsString(); + RecordDecl *RD = buildAsyncDataRecord(S.Context, Recordname, SLoc, ELoc, + clang::TagDecl::TagKind::TTK_Struct); + RD->startDefinition(); + + // Gather Function parameters for (FunctionDecl::param_const_iterator pi = FD->param_begin(); pi != FD->param_end(); pi++) { paramList.push_back(std::make_pair( @@ -1208,62 +1224,71 @@ static RecordDecl *buildFutureRecordDecl( } bool IsCPS = S.Context.getLangOpts().ContinuationPassingStyle; + // Gather all awaited expressions for (unsigned I = 0; I != Args.size(); ++I) { auto *AE = cast(Args[I])->getSubExpr(); CallExpr *CE = dyn_cast(AE); QualType AEType; + FunctionDecl *AwaitFD = nullptr; if (CE) { - FunctionDecl *AwaitFD = - dyn_cast_or_null(CE->getCalleeDecl()); + AwaitFD = dyn_cast_or_null(CE->getCalleeDecl()); AEType = AwaitFD == nullptr ? AE->getType() : S.Context.getQualifiedType( AE->getType(), AwaitFD->getReturnType().getQualifiers()); - } else - AEType = AE->getType(); + } else AEType = AE->getType(); - if (!S.IsBSCCompatibleAsyncType(AEType)) { + if (IsCPS) { + if (!S.IsBSCCompatibleAsyncType(AEType)) { QualType AwaitableType; - if (IsCPS) { - AwaitableType = - lookupGenericType(S, FD->getBeginLoc(), AEType, "__Trait_Awaitable", - "continuation.hbs"); + AwaitableType = + lookupGenericType(S, FD->getBeginLoc(), AEType, "__Trait_Awaitable", + "continuation.hbs"); + if (AwaitableType.isNull()) { + return nullptr; + } + + RecordDecl *AwaitableStruct = AwaitableType->getAsRecordDecl(); + assert(AwaitableStruct != nullptr); + + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getRecordType(AwaitableStruct))); + } else if (implementedAsyncType(S, AEType)) { + const RecordType *FutureType = + dyn_cast(AEType.getDesugaredType(S.Context)); + RecordDecl *FutureDecl = FutureType->getDecl(); + assert(FutureDecl != nullptr && + "struct future of async function is null"); + + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getRecordType(FutureDecl))); } else { - AwaitableType = lookupGenericType(S, FD->getBeginLoc(), AEType, - "__Trait_Future", "future.hbs"); + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + AE->getType())); } - if (AwaitableType.isNull()) { - return nullptr; - } - - RecordDecl *AwaitableStruct = AwaitableType->getAsRecordDecl(); - assert(AwaitableStruct != nullptr); - - LocalVarList.push_back(std::make_pair( - &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), - S.Context.getRecordType(AwaitableStruct))); - } else if (implementedAsyncType(S, AEType)) { - const RecordType *FutureType = - dyn_cast(AEType.getDesugaredType(S.Context)); - RecordDecl *FutureDecl = FutureType->getDecl(); - assert(FutureDecl != nullptr && - "struct future of async function is null"); - - LocalVarList.push_back(std::make_pair( - &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), - S.Context.getRecordType(FutureDecl))); } else { - LocalVarList.push_back(std::make_pair( - &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), - AE->getType())); + if (AwaitFD && AwaitFD == FD) { + // A recursive await + assert(CE); + // This only happen in the recursive case, and I'm building the thing + // exactly now + assert(AwaitFD->isAsyncSpecified()); + + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + S.Context.getPointerType(S.Context.getRecordType(RD)))); + } 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++) { @@ -1296,9 +1321,9 @@ static RecordDecl *buildFutureRecordDecl( static FunctionDecl *buildFutureInitFunctionDefinition(Sema &S, RecordDecl *RD, FunctionDecl *FD, - // RecordDecl *FatPointerRD, - // VarDecl *VtableInit, - FunctionDecl *FDecl) { + FunctionDecl *FDecl, + RecordDecl *FatPointerRD, + VarDecl *VtableInit) { FunctionDecl *NewFD = nullptr; SourceLocation SLoc = FD->getBeginLoc(); SourceLocation NLoc = FD->getNameInfo().getLoc(); @@ -1506,42 +1531,49 @@ static FunctionDecl *buildFutureInitFunctionDefinition(Sema &S, RecordDecl *RD, .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, SLoc, ELoc); - // Stmts.push_back(FatPointerDS); - - // SmallVector InitExprs; - Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); - // 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); - // No need for ImplicitCastExpr since BuildReturnStmt will generate for us. - Stmt *RS = S.BuildReturnStmt(NLoc, FutureRefExpr).get(); + Stmt *RS = NULL; + bool IsCPS = S.Context.getLangOpts().ContinuationPassingStyle; + if (IsCPS) { + 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, SLoc, ELoc); + Stmts.push_back(FatPointerDS); + + SmallVector InitExprs; + Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); + 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); + // No need for ImplicitCastExpr since BuildReturnStmt will generate for us. + RS = S.BuildReturnStmt(NLoc, FatPointerRef).get(); + } else { + Expr *FutureRefExpr = S.BuildDeclRefExpr(VD, VD->getType(), VK_LValue, NLoc); + RS = S.BuildReturnStmt(NLoc, FutureRefExpr).get(); + } Stmts.push_back(RS); CompoundStmt *CS = @@ -1617,8 +1649,9 @@ buildIfStmtForFreeFutureObj(Sema &S, Expr *PtrExpr, Expr *FreeFuncExpr, return If; } -static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, - FunctionDecl *FD, bool IsOptimization) { +static BSCMethodDecl *buildFreeFunctionDefinition(Sema &S, RecordDecl *RD, + FunctionDecl *FD, + bool IsOptimization) { SourceLocation SLoc = FD->getBeginLoc(); SourceLocation NLoc = FD->getNameInfo().getLoc(); SourceLocation ELoc = FD->getEndLoc(); @@ -1635,6 +1668,8 @@ static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, S.Context, RD, SLoc, NLoc, ELoc, &(S.Context.Idents).get(FName), FuncType, nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); + S.PushOnScopeChains(NewFD, S.getCurScope(), true); + S.Context.BSCDeclContextMap[RD->getTypeForDecl()] = RD; SmallVector ParmVarDecls; @@ -1657,82 +1692,156 @@ static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, std::stack Futures; for (RecordDecl::field_iterator FieldIt = RD->field_begin(); FieldIt != RD->field_end(); ++FieldIt) { - if (FieldIt->getType().getTypePtr()->isBSCAsyncType(S.Context) && - StartsWith(FieldIt->getDeclName().getAsString(), "Ft_")) { - Futures.push(FieldIt); + if (StartsWith(FieldIt->getDeclName().getAsString(), "Ft_")) { + auto FieldTy = FieldIt->getType(); + auto maybePtrTy = dyn_cast(FieldTy.getTypePtr()); + // Free trait pointer or known pointers + if (FieldTy.getTypePtr()->isBSCAsyncType(S.Context) || + (maybePtrTy && + implementedAsyncType( + S, maybePtrTy->getPointeeType())) || + (maybePtrTy && + isa(maybePtrTy->getPointeeType()) && + cast(maybePtrTy->getPointeeType())->getDecl() == RD)) { + 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 *DataExpr = nullptr; + Expr *FreeFuncExpr = nullptr; + if (FtField->getType().getTypePtr()->isBSCAsyncType(S.Context)) { + // If its BSCFutureType (the trait) call the free function from the vtable + RecordDecl *FatPointerRD = + dyn_cast(FtField->getType().getDesugaredType(S.Context)) + ->getDecl(); + + assert(isa(FatPointerRD)); + ClassTemplateSpecializationDecl *CTSD = + cast(FatPointerRD); + const TemplateArgumentList &args = CTSD->getTemplateArgs(); + assert(args.size() == 1); + + // Make sure these three generic types are fully instantiated. + bool IsCPS = S.Context.getLangOpts().ContinuationPassingStyle; + if (!IsCPS) { + (void)lookupGenericType(S, FD->getBeginLoc(), args[0].getAsType(), + "PollResult", "future.hbs"); + (void)lookupGenericType(S, FD->getBeginLoc(), args[0].getAsType(), + "__Trait_Future_Vtable", "future.hbs"); + (void)lookupGenericType(S, FD->getBeginLoc(), args[0].getAsType(), + "__Trait_Future", "future.hbs"); + } - Expr *DRE = S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); - Expr *PDRE = - ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); - - // Generating `FutureExpr` as followed: - // @code - // this.Ft_ - // @endcode - Expr *FutureExpr = S.BuildMemberExpr( - PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *FtField, - DeclAccessPair::make(PVD, FtField->getAccess()), false, - DeclarationNameInfo(), FtField->getType().getNonReferenceType(), - VK_LValue, OK_Ordinary); + Expr *DRE = + S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); + Expr *PDRE = + ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, DRE, + nullptr, VK_PRValue, FPOptionsOverride()); + + // Generating `FutureExpr` as followed: + // @code + // this.Ft_ + // @endcode + 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; + } + } - 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; + // Generating `VtableExpr` as followed: + // @code + // this.Ft_.vtable + // @endcode + 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_NoOp, 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; + } } - } - // Generating `VtableExpr` as followed: - // @code - // this.Ft_.vtable - // @endcode - 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_NoOp, 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; - break; + DataExpr = S.BuildMemberExpr( + FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *PtrField, + DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, + DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); + + FreeFuncExpr = S.BuildMemberExpr( + VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FreeFuncField, + DeclAccessPair::make(FatPointerRD, FreeFuncField->getAccess()), false, + DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, + OK_Ordinary); + } else { + // If not, the free function can be obtained directly + auto AEType = FtField->getType(); + + // Remove all pointers from type + while (AEType->isPointerType()) { + AEType = AEType->getPointeeType(); } - } - Expr *DataExpr = S.BuildMemberExpr( - FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *PtrField, - DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, - DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); - - Expr *FreeFuncExpr = S.BuildMemberExpr( - VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *FreeFuncField, - DeclAccessPair::make(FatPointerRD, FreeFuncField->getAccess()), false, - DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, - OK_Ordinary); + const RecordType *FutureType = + dyn_cast(AEType.getDesugaredType(S.Context)); + assert(FutureType != nullptr && + "struct future of async function is null"); + + RecordDecl *FutureStructRD = FutureType->getDecl(); + assert(FutureStructRD != nullptr && + "struct future of async function is null"); + + BSCMethodDecl *FreeFD = + lookupBSCMethodInRecord(S, "free", FutureStructRD); + assert(FreeFD != nullptr && "free function of async function is null"); + + FreeFuncExpr = S.BuildDeclRefExpr( + FreeFD, FreeFD->getType().getNonReferenceType(), VK_LValue, SLoc); + + FreeFuncExpr->HasBSCScopeSpec = true; + + Expr *DRE = + S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); + Expr *PDRE = + ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, DRE, + nullptr, VK_PRValue, FPOptionsOverride()); + + DataExpr = S.BuildMemberExpr( + PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), + SourceLocation(), *FtField, + DeclAccessPair::make(PVD, FtField->getAccess()), false, + DeclarationNameInfo(), FtField->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary); + } + assert(DataExpr); + assert(FreeFuncExpr); Stmt *If = buildIfStmtForFreeFutureObj(S, DataExpr, FreeFuncExpr); Stmts.push_back(If); } @@ -1771,7 +1880,7 @@ static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, NewFD->setBody(CS); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); - S.PushOnScopeChains(NewFD, S.getCurScope(), true); + return NewFD; } @@ -1779,4 +1888,4 @@ static BSCMethodDecl *buildFreeFunction(Sema &S, RecordDecl *RD, #endif // ENABLE_BSC -#endif // LLVM_CLANG_AST_WALKERBSC_H \ No newline at end of file +#endif // LLVM_CLANG_AST_ASYNCBSC_H \ No newline at end of file diff --git a/clang/lib/Sema/BSC/SemaBSCContinuation.cpp b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp index a9aae8289f41..7488087a7f32 100644 --- a/clang/lib/Sema/BSC/SemaBSCContinuation.cpp +++ b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp @@ -13,7 +13,6 @@ #if ENABLE_BSC -#include "TreeTransform.h" #include "clang/AST/BSC/AsyncBSC.h" using namespace clang; @@ -377,14 +376,14 @@ public: VK_LValue, OK_Ordinary); Expr *RHSExpr = AE; - bool IsOptimization = false; + // bool IsOptimization = false; // Handle nested call if (CallExpr *CE = dyn_cast(AE)) { FunctionDecl *FutureInitFunc = CE->getDirectCallee(); if (FutureInitFunc) { - IsOptimization = - !(CE->getType().getTypePtr()->isBSCAsyncType(SemaRef.Context)) && - implementedAsyncType(SemaRef, CE->getType()); + // IsOptimization = + // !(CE->getType().getTypePtr()->isBSCAsyncType(SemaRef.Context)) && + // implementedAsyncType(SemaRef, CE->getType()); // CHECK: Do I need all of this? std::vector CallArgs; for (unsigned I = 0; I < CE->getNumArgs(); ++I) { @@ -1179,7 +1178,7 @@ SmallVector Sema::ActOnAsyncCPSFunctionDefinition(FunctionDecl *FD) { Context.BSCDesugaredMap[FD].push_back(AwaitDecl); // free - BSCMethodDecl *FreeDecl = buildFreeFunction(*this, RD, FD, IsOptimization); + BSCMethodDecl *FreeDecl = buildFreeFunctionDefinition(*this, RD, FD, IsOptimization); if (!FreeDecl) { return Decls; } @@ -1211,8 +1210,7 @@ SmallVector Sema::ActOnAsyncCPSFunctionDefinition(FunctionDecl *FD) { // FutureInit = // buildFutureStructInitFunctionDefinition(*this, RD, FD); // } else { - FutureInit = buildFutureInitFunctionDefinition(*this, RD, FD, AwaitableRD, - AwaitVtableVD, FutureInitDef); + FutureInit = buildFutureInitFunctionDefinition(*this, RD, FD, FutureInitDef, AwaitableRD, AwaitVtableVD); // } if (!FutureInit) { diff --git a/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp index 80ba564ba232..c269ff10cc5a 100644 --- a/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp @@ -13,119 +13,11 @@ #if ENABLE_BSC -#include "TreeTransform.h" #include "clang/AST/BSC/AsyncBSC.h" using namespace clang; using namespace sema; -bool Sema::IsBSCCompatibleAsyncType(QualType Ty) { - return implementedAsyncType(*this, Ty) || - Ty.getTypePtr()->isBSCAsyncType(Context); -} - -// 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; - } - - QualType AwaitReturnTy = E->getType(); - - bool IsCall = isa(E); - if (IsCall) { - Decl *AwaitDecl = (dyn_cast(E))->getCalleeDecl(); - FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); - if (FDecl) { - if (!FDecl->isAsyncSpecified() && - !IsBSCCompatibleAsyncType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } else { - if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } - } else { - if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } - - if (AwaitReturnTy.getTypePtr()->isBSCAsyncType(Context)) { - const RecordType *AwaitableType = - dyn_cast(AwaitReturnTy.getDesugaredType(Context)); - RecordDecl *AwaitDecl = AwaitableType->getDecl(); - assert(isa(AwaitDecl)); - ClassTemplateSpecializationDecl *CTSD = - cast(AwaitDecl); - const TemplateArgumentList &args = CTSD->getTemplateArgs(); - assert(args.size() == 1); - AwaitReturnTy = args[0].getAsType(); - } else if (implementedAsyncType(*this, AwaitReturnTy)) { - const RecordType *FutureType = - dyn_cast(AwaitReturnTy.getDesugaredType(Context)); - RecordDecl *FutureRD = FutureType->getDecl(); - - BSCMethodDecl *FD = NULL; - if (Context.getLangOpts().ContinuationPassingStyle) - FD = lookupBSCMethodInRecord(*this, "awaitable", FutureRD); - else - FD = lookupBSCMethodInRecord(*this, "poll", FutureRD); - - if (FD != nullptr) { - const RecordType *ResultType = dyn_cast( - FD->getReturnType().getDesugaredType(Context)); - RecordDecl *Result = ResultType->getDecl(); - for (RecordDecl::field_iterator FieldIt = Result->field_begin(), - Field_end = Result->field_end(); - FieldIt != Field_end; ++FieldIt) { - if (FieldIt->getDeclName().getAsString() == "res") { - AwaitReturnTy = FieldIt->getType(); - } - } - } - } else if ((isa(AwaitReturnTy.getTypePtr()) && - implementedFutureType( - *this, cast(AwaitReturnTy.getTypePtr()) - ->getPointeeType()))) { - auto AwaitReturnTy2 = - cast(AwaitReturnTy.getTypePtr())->getPointeeType(); - const RecordType *FutureType = - dyn_cast(AwaitReturnTy2.getDesugaredType(Context)); - RecordDecl *FutureRD = FutureType->getDecl(); - if (Context.getLangOpts().ContinuationPassingStyle) - FD = lookupBSCMethodInRecord(*this, "awaitable", FutureRD); - else - FD = lookupBSCMethodInRecord(*this, "poll", FutureRD); - if (FD != nullptr) { - const RecordType *ResultType = dyn_cast( - FD->getReturnType().getDesugaredType(Context)); - RecordDecl *Result = ResultType->getDecl(); - for (RecordDecl::field_iterator FieldIt = Result->field_begin(), - Field_end = Result->field_end(); - FieldIt != Field_end; ++FieldIt) { - if (FieldIt->getDeclName().getAsString() == "res") { - AwaitReturnTy = FieldIt->getType(); - } - } - } - } - - // build AwaitExpr - AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, E, AwaitReturnTy); - return Res; -} - // build struct Future declaration for async function static RecordDecl *buildOpaqueFutureRecordDecl(Sema &S, FunctionDecl *FD) { DeclarationName funcName = FD->getDeclName(); @@ -139,88 +31,7 @@ static RecordDecl *buildOpaqueFutureRecordDecl(Sema &S, FunctionDecl *FD) { return RD; } -// 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(); - // Create Record declaration - const std::string Recordname = "_Future" + funcName.getAsString(); - RecordDecl *RD = buildAsyncDataRecord(S.Context, Recordname, SLoc, ELoc, - clang::TagDecl::TagKind::TTK_Struct); - RD->startDefinition(); - - // Gather Function parameters - for (FunctionDecl::param_const_iterator pi = FD->param_begin(); - pi != FD->param_end(); pi++) { - paramList.push_back(std::make_pair( - (*pi)->getDeclName(), (*pi)->getType())); - } - - // Gather all awaited expressions - for (unsigned I = 0; I != Args.size(); ++I) { - auto *AE = cast(Args[I])->getSubExpr(); - CallExpr *CE = dyn_cast(AE); - QualType AEType; - FunctionDecl *AwaitFD = nullptr; - if (CE) { - AwaitFD = dyn_cast_or_null(CE->getCalleeDecl()); - AEType = - AwaitFD == nullptr - ? AE->getType() - : S.Context.getQualifiedType( - AE->getType(), AwaitFD->getReturnType().getQualifiers()); - } else AEType = AE->getType(); - - if (AwaitFD && AwaitFD == FD) { - // A recursive await - assert(CE); - // This only happen in the recursive case, and I'm building the thing - // exactly now - assert(AwaitFD->isAsyncSpecified()); - - LocalVarList.push_back(std::make_pair( - &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), - S.Context.getPointerType(S.Context.getRecordType(RD)))); - } else { - LocalVarList.push_back(std::make_pair( - &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), - AE->getType())); - } - } - - 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; - if (VarType.isConstQualified()) { - VarType.removeLocalConst(); - } - addAsyncRecordDecl(S.Context, VarName, VarType, SLoc, ELoc, RD); - } - - // Correct typos for await expr. - ExprResult CorrectVal = - CorrectDelayedTyposInExpr(E, nullptr, /*RecoverUncorrectedTypos=*/true); - if (CorrectVal.isInvalid()) - return ExprError(); - E = CorrectVal.get(); - return BuildAwaitExpr(AwaitLoc, E); -} - -// TODO: Can we first desugar to "impl trait Future<> for type", -// then call the trait interface to desugar again. +// Future trait implementation static VarDecl *buildVtableInitDecl(Sema &S, FunctionDecl *FD, QualType RecordType, QualType ReturnType, bool Initialize) { @@ -521,497 +332,6 @@ private: }; } // namespace -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; } - - FunctionDecl *TransformFunctionDecl(FunctionDecl *D) { - FunctionDecl *NewFD = 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, {}); - - SourceLocation SLoc = D->getBeginLoc(); - SourceLocation NLoc = D->getNameInfo().getLoc(); - SourceLocation ELoc = D->getEndLoc(); - TypeSourceInfo *Tinfo = D->getTypeSourceInfo(); - std::string FName = std::string(D->getIdentifier()->getName()); - - if (isa(D)) { - BSCMethodDecl *BMD = cast(D); - NewFD = buildAsyncBSCMethodDecl( - SemaRef.Context, D->getDeclContext(), SLoc, NLoc, ELoc, - &(SemaRef.Context.Idents).get(FName), FuncType, Tinfo, SC_None, - BMD->getExtendedType()); - } else { - NewFD = buildAsyncFuncDecl(SemaRef.Context, D->getDeclContext(), SLoc, - NLoc, &(SemaRef.Context.Idents).get(FName), - FuncType, Tinfo); - } - SmallVector ParmVarDecls; - for (const auto &I : D->parameters()) { - ParmVarDecl *PVD = ParmVarDecl::Create( - SemaRef.Context, NewFD, SourceLocation(), SourceLocation(), - &(SemaRef.Context.Idents).get(I->getName()), I->getType(), nullptr, - SC_None, nullptr); - ParmVarDecls.push_back(PVD); - } - NewFD->setParams(ParmVarDecls); - NewFD->setLexicalDeclContext(SemaRef.Context.getTranslationUnitDecl()); - - CompoundStmt *body = - llvm::dyn_cast_if_present(D->getBody()); - // If transforming a declaration without body this may not be present - if (body) { - 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); - body = BaseTransform::RebuildCompoundStmt(SourceLocation(), Stmts, - SourceLocation(), false) - .getAs(); - } - - Stmt *FuncBody = BaseTransform::TransformStmt(body).getAs(); - NewFD->setBody(FuncBody); - } - } - return NewFD; - } - - 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 { - typedef TreeTransform BaseTransform; - Expr *PDRE; - RecordDecl *FutureRD; - BSCMethodDecl *FD; - std::vector DeclStmts; - int DIndex; - llvm::DenseMap> DMap; - std::map ArrayPointerMap; - std::map 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 = VD->getInit(); - Expr *LE = nullptr; - Expr *RE = nullptr; - QualType QT = VD->getType(); - - if (VD->isExternallyVisible() || VD->isConstexpr() || - VD->isStaticLocal()) - return S; - - // Do not need to transform constant variable with compile-time constant - // initializier. - const Expr *Culprit; - if (QT.isConstQualified() && Init && !Init->isValueDependent() && - Init->isConstantInitializer(SemaRef.Context, false, &Culprit)) - return S; - - 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 (Init && (QT->isArrayType() || QT->isRecordType())) { - Expr *CInit = BaseTransform::TransformExpr(Init).get(); - - 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); - - SemaRef.AddInitializerToDecl(ArgVDNew, CInit, /*DirectInit=*/false); - DeclStmt *DSNew = - SemaRef - .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(DSNew); - - RE = SemaRef.BuildDeclRefExpr(ArgVDNew, - VD->getType().getNonReferenceType(), - VK_LValue, SourceLocation()); - // No need for ImplicitCastExpr which will be generated - // by RebuildBinaryOperator in future. - DIndex++; - CIndex++; - - if (const ConstantArrayType *CA = dyn_cast(QT)) { - int Elements = SemaRef.Context.getConstantArrayElementCount(CA); - QualType SubQT = SemaRef.Context.getBaseElementType(QT); - - QualType Pty = SemaRef.Context.getPointerType(SubQT); - Expr *AssignedRVExpr = SemaRef.BuildDeclRefExpr( - ArgVDNew, ArgVDNew->getType(), VK_LValue, SourceLocation()); - TypeSourceInfo *AssignedType = - SemaRef.Context.getTrivialTypeSourceInfo(Pty); - Expr *AssignedCCE = BaseTransform::RebuildCStyleCastExpr( - SourceLocation(), AssignedType, - SourceLocation(), AssignedRVExpr) - .get(); - - std::string AssignedPtrName = - "__ASSIGNED_ARRAY_PTR_" + GetPrefix(SubQT); - VarDecl *AssignedPtrVar = - GetArrayAssignedPointerMap(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=*/false); - - DeclStmt *AssignedDS = - SemaRef - .ActOnDeclStmt( - SemaRef.ConvertDeclToDeclGroup(AssignedPtrVar), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(AssignedDS); - SetArrayAssignedPointerMap(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++; - - TypeSourceInfo *ArrayType = - SemaRef.Context.getTrivialTypeSourceInfo(Pty); - Expr *ArrayCCE = - BaseTransform::RebuildCStyleCastExpr( - SourceLocation(), ArrayType, SourceLocation(), LE) - .get(); - - std::string ArrayPtrName = "__ARRAY_PTR_" + GetPrefix(SubQT); - VarDecl *ArrayPtrVar = GetArrayPointerMap(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=*/false); - DeclStmt *ArrayDS = - SemaRef - .ActOnDeclStmt( - SemaRef.ConvertDeclToDeclGroup(ArrayPtrVar), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(ArrayDS); - SetArrayPointerMap(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 *FInit = new (SemaRef.Context) - DeclStmt(IDG, SourceLocation(), SourceLocation()); - - Expr *IDRE = - SemaRef.BuildDeclRefExpr(IArgVDNew, SemaRef.Context.IntTy, - VK_LValue, SourceLocation()); - 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, IDRE, 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(); - 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, FInit, 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 (Init == nullptr) { - 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); - SemaRef.ActOnUninitializedDecl(ArgVDNew); - DeclStmt *DSNew = - SemaRef - .ActOnDeclStmt(SemaRef.ConvertDeclToDeclGroup(ArgVDNew), - SourceLocation(), SourceLocation()) - .getAs(); - - DeclStmts.push_back(DSNew); - DIndex++; - CIndex++; - } - - 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); - } - } - } - - int BOSize = BOStmts.size(); - if (BOSize == 0) { - Result = DeclStmts[DeclStmts.size() - 1]; - DeclStmts.erase(DeclStmts.end() - 1); - DIndex--; - CIndex--; - } 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); - } - if (CIndex > 0) - 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 SetArrayPointerMap(std::string APName, VarDecl *VD) { - assert(VD && "Passed null array pointers variable"); - ArrayPointerMap[APName] = VD; - } - - VarDecl *GetArrayPointerMap(std::string APName) { - std::map::iterator I = ArrayPointerMap.find(APName); - if (I != ArrayPointerMap.end()) - return I->second; - return nullptr; - } - - void SetArrayAssignedPointerMap(std::string AAPName, VarDecl *VD) { - assert(VD && "Passed null array pointers variable"); - ArrayAssignedPointerMap[AAPName] = VD; - } - - VarDecl *GetArrayAssignedPointerMap(std::string AAPName) { - std::map::iterator I = - ArrayAssignedPointerMap.find(AAPName); - if (I != ArrayAssignedPointerMap.end()) - return I->second; - return nullptr; - } -}; -} // namespace - namespace { /** * Transform the function body so it manages a single state and the return @@ -1034,104 +354,159 @@ public: : BaseTransform(SemaRef), DT(DT), PDRE(PDRE), FutureRD(FutureRD), FD(FD) { } - llvm::APInt ResultVal(S.Context.getTargetInfo().getIntWidth(), AwaitCount); - Expr *RHSExpr = IntegerLiteral::Create(S.Context, ResultVal, - S.Context.IntTy, SourceLocation()); + // make sure redo semantic analysis + bool AlwaysRebuild() { return true; } - Expr *BO = S.CreateBuiltinBinOp((*TheField)->getLocation(), BO_Assign, - LHSExpr, RHSExpr) - .get(); - ElseStmts.push_back(BO); + 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(If->getBeginLoc(), Stmts, + If->getEndLoc(), false) + .getAs(); + If->setElse(ES); + } + + if (HasStatement && !isRefactorStmt(TS)) { + std::vector Stmts; + Stmts.push_back(TS); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + TS = BaseTransform::RebuildCompoundStmt(If->getBeginLoc(), Stmts, + If->getEndLoc(), false) + .getAs(); + If->setThen(TS); + } + + return BaseTransform::TransformIfStmt(If); } - RecordDecl *PollResultRD = PollResultVar->getType()->getAsRecordDecl(); - BSCMethodDecl *IsCompletedFD = - lookupBSCMethodInRecord(S, "is_completed", PollResultRD); - if (IsCompletedFD) { - Expr *IsCompletedFDRef = S.BuildDeclRefExpr( - IsCompletedFD, IsCompletedFD->getType(), VK_LValue, BLoc); - IsCompletedFDRef->HasBSCScopeSpec = true; - IsCompletedFDRef = S.ImpCastExprToType(IsCompletedFDRef, - S.Context.getPointerType( - IsCompletedFDRef->getType()), - CK_FunctionToPointerDecay) - .get(); + StmtResult TransformWhileStmt(WhileStmt *S) { + bool HasStatement = false; + WhileStmt *WS = S; + Stmt *Body = WS->getBody(); - if (PollResultRD) { - Expr *PollResultVarRef = S.BuildDeclRefExpr( - PollResultVar, PollResultVar->getType(), VK_LValue, BLoc); - PollResultVarRef = - S.CreateBuiltinUnaryOp(BLoc, UO_AddrOf, PollResultVarRef).get(); - Expr *AwaitResultRef = S.BuildDeclRefExpr( - AwaitResult, AwaitResult->getType(), VK_LValue, BLoc); - AwaitResultRef = - S.CreateBuiltinUnaryOp(BLoc, UO_AddrOf, AwaitResultRef).get(); + if (Body != nullptr) + HasStatement = (hasAwaitExpr(Body) || hasReturnStmt(Body)); - SmallVector Args; - Args.push_back(PollResultVarRef); - Args.push_back(AwaitResultRef); - IfCond = - S.BuildCallExpr(nullptr, IsCompletedFDRef, BLoc, Args, BLoc).get(); + if (HasStatement && !isRefactorStmt(Body)) { + std::vector Stmts; + Stmts.push_back(Body); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + Body = BaseTransform::RebuildCompoundStmt(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), false) + .getAs(); + WS->setBody(Body); } + return BaseTransform::TransformWhileStmt(WS); } - RecordDecl *PollResultRDForPending = - NewFD->getReturnType()->getAsRecordDecl(); - BSCMethodDecl *PendingFD = - lookupBSCMethodInRecord(S, "pending", PollResultRDForPending); - - if (PendingFD) { - Expr *PendingFDRef = - S.BuildDeclRefExpr(PendingFD, PendingFD->getType(), VK_LValue, BLoc); - PendingFDRef->HasBSCScopeSpec = true; - PendingFDRef = - S.ImpCastExprToType(PendingFDRef, - S.Context.getPointerType(PendingFDRef->getType()), - CK_FunctionToPointerDecay) - .get(); - Expr *PendingCall = - S.BuildCallExpr(nullptr, PendingFDRef, BLoc, {}, BLoc).get(); - Stmt *RS = S.BuildReturnStmt(BLoc, PendingCall).get(); - ElseStmts.push_back(RS); - } + StmtResult TransformDoStmt(DoStmt *S) { + bool HasStatement = false; + DoStmt *DS = S; + Stmt *Body = DS->getBody(); - std::vector BodyStmts{ThenBodyStmt}; + if (Body != nullptr) + HasStatement = (hasAwaitExpr(Body) || hasReturnStmt(Body)); - Stmt *Body = CompoundStmt::Create(S.Context, BodyStmts, FPOptionsOverride(), - BLoc, BLoc); - Stmt *Else = CompoundStmt::Create(S.Context, ElseStmts, FPOptionsOverride(), - BLoc, BLoc); - IfStmt *If = IfStmt::Create(S.Context, BLoc, IfStatementKind::Ordinary, - /*Init=*/nullptr, - /*Var=*/nullptr, IfCond, - /*LPL=*/BLoc, - /*RPL=*/BLoc, Body, BLoc, Else); - return If; -} + if (HasStatement && !isRefactorStmt(Body)) { + std::vector Stmts; + Stmts.push_back(Body); + Sema::CompoundScopeRAII CompoundScope(SemaRef); + Body = BaseTransform::RebuildCompoundStmt(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), false) + .getAs(); + DS->setBody(Body); + } + return BaseTransform::TransformDoStmt(DS); + } + + 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(Body->getBeginLoc(), Stmts, + Body->getEndLoc(), 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(SS->getBeginLoc(), Stmts, + SS->getEndLoc(), 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(SS->getBeginLoc(), Stmts, + SS->getEndLoc(), false) + .getAs(); + DS->setSubStmt(SS); + } + return BaseTransform::TransformDefaultStmt(DS); + } -namespace { -/** - * Visit a Stmt and return true if there's a recursive call to the provided Decl - */ -class RecursiveCallVisitor - : public ConstStmtVisitor { -public: - RecursiveCallVisitor(const Decl *FD) : FD(FD) {} - bool VisitCallExpr(const CallExpr *E) { - if (E->getCalleeDecl() == FD) - return true; + StmtResult TransformCompoundStmt(CompoundStmt *S) { + if (S == nullptr) return S; - return this->VisitStmt(static_cast(E)); - } - bool VisitStmt(const Stmt *S) { + std::vector Statements; for (auto *C : S->children()) { - if (C) { - if (Visit(C)) { - return true; + 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); } - return false; + Sema::CompoundScopeRAII CompoundScope(SemaRef); + CompoundStmt *CS = BaseTransform::RebuildCompoundStmt( + S->getBeginLoc(), Statements, S->getEndLoc(), false) + .getAs(); + return CS; } StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr) { @@ -1299,10 +674,10 @@ public: FunctionDecl *FutureInitFunc = CE->getDirectCallee(); if (FutureInitFunc) { IsOptimization = - !(CE->getType().getTypePtr()->isBSCFutureType()) && - (implementedFutureType(SemaRef, CE->getType()) || + !(CE->getType().getTypePtr()->isBSCAsyncType(SemaRef.Context)) && + (implementedAsyncType(SemaRef, CE->getType()) || (isa(CE->getType().getTypePtr()) && - implementedFutureType( + implementedAsyncType( SemaRef, cast(CE->getType().getTypePtr()) ->getPointeeType()))); } @@ -1654,238 +1029,6 @@ static BSCMethodDecl *buildFreeFunctionDeclaration(Sema &S, RecordDecl *RD, return NewFD; } -static BSCMethodDecl *buildFreeFunctionDefinition(Sema &S, RecordDecl *RD, - FunctionDecl *FD, - bool IsOptimization) { - SourceLocation SLoc = FD->getBeginLoc(); - SourceLocation NLoc = FD->getNameInfo().getLoc(); - SourceLocation ELoc = FD->getEndLoc(); - - 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, ELoc, &(S.Context.Idents).get(FName), FuncType, - nullptr, SC_None, RD->getTypeForDecl()->getCanonicalTypeInternal()); - NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); - S.PushOnScopeChains(NewFD, S.getCurScope(), true); - - 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; - - auto StartsWith = [](const std::string &str, const std::string &prefix) { - if (str.length() >= prefix.length()) { - return 0 == str.compare(0, prefix.length(), prefix); - } - return false; - }; - - std::stack Futures; - for (RecordDecl::field_iterator FieldIt = RD->field_begin(); - FieldIt != RD->field_end(); ++FieldIt) { - if (StartsWith(FieldIt->getDeclName().getAsString(), "Ft_")) { - auto FieldTy = FieldIt->getType(); - auto maybePtrTy = dyn_cast(FieldTy.getTypePtr()); - // Free trait pointer or known pointers - if (FieldTy.getTypePtr()->isBSCFutureType() || - (maybePtrTy && - implementedFutureType( - S, maybePtrTy->getPointeeType())) || - (maybePtrTy && - isa(maybePtrTy->getPointeeType()) && - cast(maybePtrTy->getPointeeType())->getDecl() == RD)) { - Futures.push(FieldIt); - } - } - } - - while (!Futures.empty()) { - RecordDecl::field_iterator FtField = Futures.top(); - Futures.pop(); - Expr *DataExpr = nullptr; - Expr *FreeFuncExpr = nullptr; - if (FtField->getType().getTypePtr()->isBSCFutureType()) { - // If its BSCFutureType (the trait) call the free function from the vtable - RecordDecl *FatPointerRD = - dyn_cast(FtField->getType().getDesugaredType(S.Context)) - ->getDecl(); - - assert(isa(FatPointerRD)); - ClassTemplateSpecializationDecl *CTSD = - cast(FatPointerRD); - const TemplateArgumentList &args = CTSD->getTemplateArgs(); - assert(args.size() == 1); - - // Make sure these three generic types are fully instantiated. - (void)lookupGenericType(S, FD->getBeginLoc(), args[0].getAsType(), - "PollResult"); - (void)lookupGenericType(S, FD->getBeginLoc(), args[0].getAsType(), - "__Trait_Future_Vtable"); - (void)lookupGenericType(S, FD->getBeginLoc(), args[0].getAsType(), - "__Trait_Future"); - - Expr *DRE = - S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); - Expr *PDRE = - ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); - - // Generating `FutureExpr` as followed: - // @code - // this.Ft_ - // @endcode - 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; - } - } - - // Generating `VtableExpr` as followed: - // @code - // this.Ft_.vtable - // @endcode - 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_NoOp, 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; - } - } - - DataExpr = S.BuildMemberExpr( - FutureExpr, false, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *PtrField, - DeclAccessPair::make(FatPointerRD, PtrField->getAccess()), false, - DeclarationNameInfo(), PtrField->getType(), VK_LValue, OK_Ordinary); - - FreeFuncExpr = S.BuildMemberExpr( - VtableExpr, true, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *FreeFuncField, - DeclAccessPair::make(FatPointerRD, FreeFuncField->getAccess()), false, - DeclarationNameInfo(), FreeFuncField->getType(), VK_LValue, - OK_Ordinary); - } else { - // If not, the free function can be obtained directly - auto AEType = FtField->getType(); - - // Remove all pointers from type - while (AEType->isPointerType()) { - AEType = AEType->getPointeeType(); - } - - const RecordType *FutureType = - dyn_cast(AEType.getDesugaredType(S.Context)); - assert(FutureType != nullptr && - "struct future of async function is null"); - - RecordDecl *FutureStructRD = FutureType->getDecl(); - assert(FutureStructRD != nullptr && - "struct future of async function is null"); - - BSCMethodDecl *FreeFD = - lookupBSCMethodInRecord(S, "free", FutureStructRD); - assert(FreeFD != nullptr && "free function of async function is null"); - - FreeFuncExpr = S.BuildDeclRefExpr( - FreeFD, FreeFD->getType().getNonReferenceType(), VK_LValue, SLoc); - - FreeFuncExpr->HasBSCScopeSpec = true; - - Expr *DRE = - S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); - Expr *PDRE = - ImplicitCastExpr::Create(S.Context, ParamType, CK_LValueToRValue, DRE, - nullptr, VK_PRValue, FPOptionsOverride()); - - DataExpr = S.BuildMemberExpr( - PDRE, true, SourceLocation(), NestedNameSpecifierLoc(), - SourceLocation(), *FtField, - DeclAccessPair::make(PVD, FtField->getAccess()), false, - DeclarationNameInfo(), FtField->getType().getNonReferenceType(), - VK_LValue, OK_Ordinary); - } - assert(DataExpr); - assert(FreeFuncExpr); - Stmt *If = buildIfStmtForFreeFutureObj(S, DataExpr, FreeFuncExpr); - Stmts.push_back(If); - } - - if (!IsOptimization) { - 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); - Expr *FutureObj = - S.BuildDeclRefExpr(PVD, ParamType, VK_LValue, SourceLocation()); - Stmt *If = buildIfStmtForFreeFutureObj(S, FutureObj, FreeFuncRef); - Stmts.push_back(If); - } - - CompoundStmt *CS = - CompoundStmt::Create(S.Context, Stmts, FPOptionsOverride(), SLoc, ELoc); - NewFD->setBody(CS); - sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - S.PopFunctionScopeInfo(ActivePolicy, NewFD, QualType(), true); - - return NewFD; -} - static BSCMethodDecl *buildPollFunctionDeclaration(Sema &S, RecordDecl *RD, RecordDecl *PollResultRD, FunctionDecl *FD) { @@ -2109,118 +1252,6 @@ static BSCMethodDecl *buildPollFunctionDefinition(Sema &S, RecordDecl *RD, 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; - } - - QualType AwaitReturnTy = E->getType(); - - bool IsCall = isa(E); - if (IsCall) { - Decl *AwaitDecl = (dyn_cast(E))->getCalleeDecl(); - FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); - if (FDecl) { - if (!FDecl->isAsyncSpecified() && - !IsBSCCompatibleFutureType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } else { - if (!IsBSCCompatibleFutureType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } - } else { - if (!IsBSCCompatibleFutureType(AwaitReturnTy)) { - Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) - << getExprRange(E)); - return ExprError(); - } - } - - if (AwaitReturnTy.getTypePtr()->isBSCFutureType()) { - const RecordType *FatPointerType = - dyn_cast(AwaitReturnTy.getDesugaredType(Context)); - RecordDecl *FatPointer = FatPointerType->getDecl(); - assert(isa(FatPointer)); - ClassTemplateSpecializationDecl *CTSD = - cast(FatPointer); - const TemplateArgumentList &args = CTSD->getTemplateArgs(); - assert(args.size() == 1); - AwaitReturnTy = args[0].getAsType(); - } else if (implementedFutureType(*this, AwaitReturnTy)) { - const RecordType *FutureType = - dyn_cast(AwaitReturnTy.getDesugaredType(Context)); - RecordDecl *FutureRD = FutureType->getDecl(); - - BSCMethodDecl *PollFD = lookupBSCMethodInRecord(*this, "poll", FutureRD); - if (PollFD != nullptr) { - const RecordType *PollResultType = dyn_cast( - PollFD->getReturnType().getDesugaredType(Context)); - 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(); - } - } - } - } else if ((isa(AwaitReturnTy.getTypePtr()) && - implementedFutureType( - *this, cast(AwaitReturnTy.getTypePtr()) - ->getPointeeType()))) { - auto AwaitReturnTy2 = - cast(AwaitReturnTy.getTypePtr())->getPointeeType(); - const RecordType *FutureType = - dyn_cast(AwaitReturnTy2.getDesugaredType(Context)); - RecordDecl *FutureRD = FutureType->getDecl(); - - BSCMethodDecl *PollFD = lookupBSCMethodInRecord(*this, "poll", FutureRD); - if (PollFD != nullptr) { - const RecordType *PollResultType = dyn_cast( - PollFD->getReturnType().getDesugaredType(Context)); - 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(); - } - } - } - } - - // build AwaitExpr - AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, E, 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(); - } - - // Correct typos for await expr. - ExprResult CorrectVal = - CorrectDelayedTyposInExpr(E, nullptr, /*RecoverUncorrectedTypos=*/true); - if (CorrectVal.isInvalid()) - return ExprError(); - E = CorrectVal.get(); - return BuildAwaitExpr(AwaitLoc, E); -} - SmallVector Sema::ActOnAsyncFunctionDeclaration(FunctionDecl *FD) { SmallVector Decls; if (!IsBSCCompatibleAsyncType(FD->getReturnType())) { @@ -2338,7 +1369,7 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { if (VtableType.isNull()) { return Decls; } - RecordDecl *VtableRD = VtableType->getAsRecordDecl(); + // RecordDecl *VtableRD = VtableType->getAsRecordDecl(); QualType FatPointerType = lookupGenericType( *this, FD->getBeginLoc(), ReturnTy, "__Trait_Future", "future.hbs"); if (FatPointerType.isNull()) { @@ -2355,6 +1386,8 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { RecordDecl *RD = buildFutureRecordDecl(*this, FD, AwaitFinder.GetAwaitExpr(), VarFinder.GetLocalVarList(), QualType()); + auto RDType = Context.getRecordType(RD); + QualType PointerStructTy = Context.getPointerType(RDType); if (!RD) { return Decls; } @@ -2378,7 +1411,7 @@ SmallVector Sema::ActOnAsyncFunctionDefinition(FunctionDecl *FD) { FutureInit = buildFutureStructInitFunctionDefinition(*this, RD, FD); } else { FutureInit = - buildFutureInitFunctionDefinition(*this, RD, FD, FutureInitDef); + buildFutureInitFunctionDefinition(*this, RD, FD, FutureInitDef, NULL, NULL); } if (!FutureInit) { diff --git a/clang/lib/Sema/BSC/SemaExprBSC.cpp b/clang/lib/Sema/BSC/SemaExprBSC.cpp new file mode 100644 index 000000000000..304959f9439e --- /dev/null +++ b/clang/lib/Sema/BSC/SemaExprBSC.cpp @@ -0,0 +1,148 @@ +//===--- SemaExprBSC.cpp - Semantic Analysis for Expressions +//------------------===// +// +// 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 expressions. +// +//===----------------------------------------------------------------------===// + +#if ENABLE_BSC + +#include "TreeTransform.h" +#include "clang/AST/BSC/AsyncBSC.h" + +using namespace clang; +using namespace sema; + +bool Sema::IsBSCCompatibleAsyncType(QualType Ty) { + return implementedAsyncType(*this, Ty) || + (isa(Ty.getTypePtr()) && + implementedAsyncType( + *this, cast(Ty.getTypePtr())->getPointeeType())) || + Ty.getTypePtr()->isBSCAsyncType(Context); +} + +// 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; + } + + QualType AwaitReturnTy = E->getType(); + + bool IsCall = isa(E); + if (IsCall) { + Decl *AwaitDecl = (dyn_cast(E))->getCalleeDecl(); + FunctionDecl *FDecl = dyn_cast_or_null(AwaitDecl); + if (FDecl) { + if (!FDecl->isAsyncSpecified() && + !IsBSCCompatibleAsyncType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); + } + } else { + if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); + } + } + } else { + if (!IsBSCCompatibleAsyncType(AwaitReturnTy)) { + Diag(E->getExprLoc(), PDiag(diag::err_not_a_async_call) + << getExprRange(E)); + return ExprError(); + } + } + + BSCMethodDecl *FD = NULL; + if (AwaitReturnTy.getTypePtr()->isBSCAsyncType(Context)) { + const RecordType *AwaitableType = + dyn_cast(AwaitReturnTy.getDesugaredType(Context)); + RecordDecl *AwaitDecl = AwaitableType->getDecl(); + assert(isa(AwaitDecl)); + ClassTemplateSpecializationDecl *CTSD = + cast(AwaitDecl); + const TemplateArgumentList &args = CTSD->getTemplateArgs(); + assert(args.size() == 1); + AwaitReturnTy = args[0].getAsType(); + } else if (implementedAsyncType(*this, AwaitReturnTy)) { + const RecordType *FutureType = + dyn_cast(AwaitReturnTy.getDesugaredType(Context)); + RecordDecl *FutureRD = FutureType->getDecl(); + + if (Context.getLangOpts().ContinuationPassingStyle) + FD = lookupBSCMethodInRecord(*this, "awaitable", FutureRD); + else + FD = lookupBSCMethodInRecord(*this, "poll", FutureRD); + + if (FD != nullptr) { + const RecordType *ResultType = dyn_cast( + FD->getReturnType().getDesugaredType(Context)); + RecordDecl *Result = ResultType->getDecl(); + for (RecordDecl::field_iterator FieldIt = Result->field_begin(), + Field_end = Result->field_end(); + FieldIt != Field_end; ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "res") { + AwaitReturnTy = FieldIt->getType(); + } + } + } + } else if ((isa(AwaitReturnTy.getTypePtr()) && + implementedAsyncType( + *this, cast(AwaitReturnTy.getTypePtr()) + ->getPointeeType()))) { + auto AwaitReturnTy2 = + cast(AwaitReturnTy.getTypePtr())->getPointeeType(); + const RecordType *FutureType = + dyn_cast(AwaitReturnTy2.getDesugaredType(Context)); + RecordDecl *FutureRD = FutureType->getDecl(); + if (Context.getLangOpts().ContinuationPassingStyle) + FD = lookupBSCMethodInRecord(*this, "awaitable", FutureRD); + else + FD = lookupBSCMethodInRecord(*this, "poll", FutureRD); + if (FD != nullptr) { + const RecordType *ResultType = dyn_cast( + FD->getReturnType().getDesugaredType(Context)); + RecordDecl *Result = ResultType->getDecl(); + for (RecordDecl::field_iterator FieldIt = Result->field_begin(), + Field_end = Result->field_end(); + FieldIt != Field_end; ++FieldIt) { + if (FieldIt->getDeclName().getAsString() == "res") { + AwaitReturnTy = FieldIt->getType(); + } + } + } + } + + // build AwaitExpr + AwaitExpr *Res = new (Context) AwaitExpr(AwaitLoc, E, 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(); + } + + // Correct typos for await expr. + ExprResult CorrectVal = + CorrectDelayedTyposInExpr(E, nullptr, /*RecoverUncorrectedTypos=*/true); + if (CorrectVal.isInvalid()) + return ExprError(); + E = CorrectVal.get(); + return BuildAwaitExpr(AwaitLoc, E); +} +#endif \ No newline at end of file diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index 68a19731bdf8..7326b4b71e94 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -20,8 +20,9 @@ add_clang_library(clangSema BSC/SemaBSCOwnership.cpp BSC/SemaBSCSafeZone.cpp BSC/SemaBSCTrait.cpp - BSC/SemaStmtBSC.cpp BSC/SemaDeclBSC.cpp + BSC/SemaExprBSC.cpp + BSC/SemaStmtBSC.cpp BSC/SemaTemplateInstantiateDeclBSC.cpp BSC/DeclSpecBSC.cpp CodeCompleteConsumer.cpp diff --git a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs index 64e1951c150e..3d99648bfee9 100644 --- a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs +++ b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/const-decl/const-decl.cbs @@ -57,11 +57,11 @@ int main() { // CHECK-NEXT: __L1: // CHECK-NEXT: ; // CHECK-NEXT: int Res_1; -// CHECK-NEXT: struct PollResult_int PR_1 = this->Ft_1.vtable->poll(this->Ft_1.data); +// CHECK-NEXT: struct PollResult_int PR_1 = struct__Futureread_poll(this->Ft_1); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_1, &Res_1)) { -// CHECK-NEXT: if (this->Ft_1.data != 0) { -// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); -// CHECK-NEXT: this->Ft_1.data = (void *)0; +// CHECK-NEXT: { +// CHECK-NEXT: struct__Futureread_free(this->Ft_1); +// CHECK-NEXT: this->Ft_1 = (struct _Futureread *)0; // CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 1; diff --git a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs index 7071b5569e29..6b94c61c9222 100644 --- a/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs +++ b/clang/test/BSC/Positive/Coroutine/Treetransform/DeclStmt/MultiDecl/var-decl-multi-same-local-name/var-decl-multi-same-local-name.cbs @@ -47,10 +47,10 @@ int main() { // CHECK-NEXT: int start_2; // CHECK-NEXT: int a_1; // CHECK-NEXT: int start_3; -// CHECK-NEXT: struct __Trait_Future_int Ft_1; -// CHECK-NEXT: struct __Trait_Future_int Ft_2; -// CHECK-NEXT: struct __Trait_Future_int Ft_3; -// CHECK-NEXT: struct __Trait_Future_int Ft_4; +// CHECK-NEXT: struct _Futureread *Ft_1; +// CHECK-NEXT: struct _Futureread *Ft_2; +// CHECK-NEXT: struct _Futureread *Ft_3; +// CHECK-NEXT: struct _Futureread *Ft_4; // CHECK-NEXT: int __future_state; // CHECK-NEXT: }; @@ -75,11 +75,11 @@ int main() { // CHECK-NEXT: __L1: // CHECK-NEXT: ; // CHECK-NEXT: int Res_1; -// CHECK-NEXT: struct PollResult_int PR_1 = this->Ft_1.vtable->poll(this->Ft_1.data); +// CHECK-NEXT: struct PollResult_int PR_1 = struct__Futureread_poll(this->Ft_1); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_1, &Res_1)) { -// CHECK-NEXT: if (this->Ft_1.data != 0) { -// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); -// CHECK-NEXT: this->Ft_1.data = (void *)0; +// CHECK-NEXT: { +// CHECK-NEXT: struct__Futureread_free(this->Ft_1); +// CHECK-NEXT: this->Ft_1 = (struct _Futureread *)0; // CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 1; @@ -92,11 +92,11 @@ int main() { // CHECK-NEXT: __L2: // CHECK-NEXT: ; // CHECK-NEXT: int Res_2; -// CHECK-NEXT: struct PollResult_int PR_2 = this->Ft_2.vtable->poll(this->Ft_2.data); +// CHECK-NEXT: struct PollResult_int PR_2 = struct__Futureread_poll(this->Ft_2); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_2, &Res_2)) { -// CHECK-NEXT: if (this->Ft_2.data != 0) { -// CHECK-NEXT: this->Ft_2.vtable->free(this->Ft_2.data); -// CHECK-NEXT: this->Ft_2.data = (void *)0; +// CHECK-NEXT: { +// CHECK-NEXT: struct__Futureread_free(this->Ft_2); +// CHECK-NEXT: this->Ft_2 = (struct _Futureread *)0; // CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 2; @@ -109,11 +109,11 @@ int main() { // CHECK-NEXT: __L3: // CHECK-NEXT: ; // CHECK-NEXT: int Res_3; -// CHECK-NEXT: struct PollResult_int PR_3 = this->Ft_3.vtable->poll(this->Ft_3.data); +// CHECK-NEXT: struct PollResult_int PR_3 = struct__Futureread_poll(this->Ft_3); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_3, &Res_3)) { -// CHECK-NEXT: if (this->Ft_3.data != 0) { -// CHECK-NEXT: this->Ft_3.vtable->free(this->Ft_3.data); -// CHECK-NEXT: this->Ft_3.data = (void *)0; +// CHECK-NEXT: { +// CHECK-NEXT: struct__Futureread_free(this->Ft_3); +// CHECK-NEXT: this->Ft_3 = (struct _Futureread *)0; // CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 3; @@ -126,11 +126,11 @@ int main() { // CHECK-NEXT: __L4: // CHECK-NEXT: ; // CHECK-NEXT: int Res_4; -// CHECK-NEXT: struct PollResult_int PR_4 = this->Ft_4.vtable->poll(this->Ft_4.data); +// CHECK-NEXT: struct PollResult_int PR_4 = struct__Futureread_poll(this->Ft_4); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_4, &Res_4)) { -// CHECK-NEXT: if (this->Ft_4.data != 0) { -// CHECK-NEXT: this->Ft_4.vtable->free(this->Ft_4.data); -// CHECK-NEXT: this->Ft_4.data = (void *)0; +// CHECK-NEXT: { +// CHECK-NEXT: struct__Futureread_free(this->Ft_4); +// CHECK-NEXT: this->Ft_4 = (struct _Futureread *)0; // CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 4; diff --git a/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs b/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs index 6b732e971e69..a6246df31c18 100644 --- a/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs +++ b/clang/test/BSC/Positive/Coroutine/Treetransform/Other/LabelStmt/label-stmt/label-stmt.cbs @@ -48,11 +48,11 @@ int main() { // CHECK-NEXT: __L1: // CHECK-NEXT: ; // CHECK-NEXT: int Res_1; -// CHECK-NEXT: struct PollResult_int PR_1 = this->Ft_1.vtable->poll(this->Ft_1.data); +// CHECK-NEXT: struct PollResult_int PR_1 = struct__Futureread_poll(this->Ft_1); // CHECK-NEXT: if (struct_PollResult_int_is_completed(&PR_1, &Res_1)) { -// CHECK-NEXT: if (this->Ft_1.data != 0) { -// CHECK-NEXT: this->Ft_1.vtable->free(this->Ft_1.data); -// CHECK-NEXT: this->Ft_1.data = (void *)0; +// CHECK-NEXT: { +// CHECK-NEXT: struct__Futureread_free(this->Ft_1); +// CHECK-NEXT: this->Ft_1 = (struct _Futureread *)0; // CHECK-NEXT: } // CHECK-NEXT: } else { // CHECK-NEXT: this->__future_state = 1; -- Gitee