diff --git a/clang/include/clang/AST/BSC/AsyncBSC.h b/clang/include/clang/AST/BSC/AsyncBSC.h new file mode 100644 index 0000000000000000000000000000000000000000..4a247561cf6e860051e3863b4380a5c53b615f89 --- /dev/null +++ b/clang/include/clang/AST/BSC/AsyncBSC.h @@ -0,0 +1,1891 @@ +//===- 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. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the BSC Coroutine utilities. +// +//===----------------------------------------------------------------------===// + +#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; + +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 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()) { + 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 = + 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); + } + + 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(); + // 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())); + } + + 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) { + 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 (IsCPS) { + if (!S.IsBSCCompatibleAsyncType(AEType)) { + QualType AwaitableType; + 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 { + LocalVarList.push_back(std::make_pair( + &(S.Context.Idents).get("Ft_" + std::to_string(I + 1)), + AE->getType())); + } + } else { + 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); + } + + 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, + FunctionDecl *FDecl, + RecordDecl *FatPointerRD, + VarDecl *VtableInit) { + 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); + + 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 = + 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 *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()->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(); + 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); + + 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; +} + +} // namespace clang + +#endif // ENABLE_BSC + +#endif // LLVM_CLANG_AST_ASYNCBSC_H \ No newline at end of file diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index ccf49eac7dd94c5c25c3d3ae9ac11fc0bb8f46c5..5d71e6bbcb7c6320220a111fa0e53baf68c4181c 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2382,8 +2382,8 @@ public: #if ENABLE_BSC /// Check if the type is the BSC future type. - bool isBSCFutureType() const; - #endif + bool isBSCAsyncType(const ASTContext &Context) const; +#endif /// Return the implicit lifetime for this type, which must not be dependent. Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 6530a91d7f785238abe87acc4710b389e99104a9..0fe0e1085dd52a838a674cb5c701d042e30ef5c2 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 f07573965822a0f64aee1c40921be25cad5b82f9..0a1b352f52a70f774a2cfbd13a7e59d86d8b0eb5 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 9b81a134c8004faff3a3e71c316dc1593778cea8..012f923a21ecc7b62455e50aeace6e4e125c5561 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3221,8 +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 IsBSCCompatibleAsyncType(QualType Ty); // BSC Destructor related. BSCMethodDecl *getOrInsertBSCDestructor(RecordDecl *RD); @@ -5951,10 +5953,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. @@ -7679,6 +7684,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/AST/BSC/TypeBSC.cpp b/clang/lib/AST/BSC/TypeBSC.cpp index a4c393f37b090b1b6631c4cc4132b13f999ccf7c..b73cfdf574f56341645ae2d37def6413497ecf48 100644 --- a/clang/lib/AST/BSC/TypeBSC.cpp +++ b/clang/lib/AST/BSC/TypeBSC.cpp @@ -283,11 +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 RD->getNameAsString() == PrefixName; } } return false; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 8bca3ce34aae10672ba2a456991668acaf6ef905..e6277b154e5c2d701ea48770d2bfd47572734fe3 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/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 158dfb759f75964c6455f34a819f9c10cfa6d518..149be9d5e3808b76df2462dc07bb044a52cea8ef 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 new file mode 100644 index 0000000000000000000000000000000000000000..afbfdf21ed8a3d67bcd1a0c0dfc57a0b50f132eb --- /dev/null +++ b/clang/lib/Headers/bsc_include/continuation.hbs @@ -0,0 +1,14 @@ +#ifndef _BSCCONTINUATION_HBS +#define _BSCCONTINUATION_HBS 1 + +struct Void{}; + +trait Continuation { + trait Continuation* resume(This* this, T* arg); +}; + +trait Awaitable { + trait Continuation* awaitable(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 89c82fcc5ebe84bab38329b6bf5c34ed781f5765..16ce5c91399d578fcda2c6c397aec34a96cf723c 100644 --- a/clang/lib/Parse/BSC/ParseDeclBSC.cpp +++ b/clang/lib/Parse/BSC/ParseDeclBSC.cpp @@ -436,6 +436,29 @@ 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 +503,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/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 3faa4ceba9ca2408482efd1a7d14c24dbdb63e30..3ce02f67da84d7dfaa6752ab6bc12ea7e56275c3 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 new file mode 100644 index 0000000000000000000000000000000000000000..7488087a7f32c27ca5a96dbb2e13fba99bce774b --- /dev/null +++ b/clang/lib/Sema/BSC/SemaBSCContinuation.cpp @@ -0,0 +1,1225 @@ +//===--- 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 "clang/AST/BSC/AsyncBSC.h" + +using namespace clang; +using namespace sema; + +// 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 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 *ContVtableVD = nullptr; + if (Res.isSingleResult()) { + for (DeclContext::lookup_result::iterator I = Res.begin(), E = Res.end(); + I != E; ++I) { + if (isa(*I)) { + ContVtableVD = dyn_cast(*I); + break; + } + } + } + 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()); + 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(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); + + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(ContinuationVtableType); + ContVtableVD->setInit(ILE); + return ContVtableVD; +} + +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); + + 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); + + 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); + + Expr *ILE = + S.BuildInitList(SourceLocation(), InitExprs, SourceLocation()).get(); + ILE->setType(AwaitVtableTy); + VD->setInit(ILE); + return VD; +} + +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()->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) { + 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", "continuation.hbs"); + 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()); + 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()); + 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 * +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(); + + 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()); + 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), + SourceLocation(), ArgExpr, false) + .get(); + SmallVector Args; + Args.push_back(ThisExpr); + Args.push_back(ArgExpr); + 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, + 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 FunctionDecl *buildStateTransDecl(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 * +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(); + + 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); + TypeSourceInfo *Tinfo = FD->getTypeSourceInfo(); + QualType FuncType = S.Context.getFunctionType(FuncRetType, ParamTys, {}); + + 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.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; +} + +SmallVector +Sema::ActOnAsyncCPSFunctionDeclaration(FunctionDecl *FD) { + SmallVector Decls; + 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)) { + return Decls; + } + ReturnTy = Context.getRecordType(std::get<0>(VoidRD)); + } + + // Continuation + 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", "continuation.hbs"); + if (ContinuationType.isNull()) { + return Decls; + } + + // Awaitable + 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", "continuation.hbs"); + if (AwaitableType.isNull()) { + return Decls; + } + + if (!FD->isStatic()) { + FunctionDecl *FutureInitDef = buildFutureInitFunctionDeclaration( + *this, FD, + Context.getElaboratedType(ETK_Struct, nullptr, AwaitableType)); + if (FutureInitDef) { + Decls.push_back(FutureInitDef); + Context.BSCDesugaredMap[FD].push_back(FutureInitDef); + } + } + } + return Decls; +} + +SmallVector Sema::ActOnAsyncCPSFunctionDefinition(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 (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()) { + return Decls; + } + + IllegalAEFinder IAEFinder = IllegalAEFinder(*this); + IAEFinder.Visit(FD->getBody()); + 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)) { + return Decls; + } + QualType VoidRDTy = Context.getRecordType(std::get<0>(VoidRD)); + if (ReturnTy->isVoidType()) { + ReturnTy = VoidRDTy; + } + + // Continuation + 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", "continuation.hbs"); + if (ContinuationType.isNull()) { + return Decls; + } + + // Awaitable + 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", + "continuation.hbs"); + if (AwaitableType.isNull()) { + return Decls; + } + RecordDecl *AwaitableRD = AwaitableType->getAsRecordDecl(); + + // Continuation + 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, AwaitFinder.GetAwaitExpr(), + VarFinder.GetLocalVarList(), ContinuationType); + 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, Context.getElaboratedType(ETK_Struct, nullptr, AwaitableType)); + if (!FutureInitDef) { + return Decls; + } + Decls.push_back(FutureInitDef); + Context.BSCDesugaredMap[FD].push_back(FutureInitDef); + + // state transform declaration + FunctionDecl *StateTransDef = + buildStateTransDecl(*this, FD, RD, ContVoidRDType); + if (!StateTransDef) { + return Decls; + } + Decls.push_back(StateTransDef); + Context.BSCDesugaredMap[FD].push_back(StateTransDef); + + // resume + std::vector ContVtableDecls; + if (AwaitFinder.GetAwaitExprNum() > 0) { + BSCMethodDecl *ResumeDecl = + buildAwaitFunction(*this, RD, FD, StateTransDef, ContVoidRDType, + Context.VoidPtrTy, "resume"); + if (!ResumeDecl) { + return Decls; + } + Decls.push_back(ResumeDecl); + Context.BSCDesugaredMap[FD].push_back(ResumeDecl); + + std::vector Args = AwaitFinder.GetAwaitExpr(); + 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(ContVtableVD); + Decls.push_back(ContVtableVD); + Context.BSCDesugaredMap[FD].push_back(ContVtableVD); + } + } + + // awaitable + BSCMethodDecl *AwaitDecl = + buildAwaitFunction(*this, RD, FD, StateTransDef, ContVoidRDType, + ContinuationType, "awaitable"); + if (!AwaitDecl) { + return Decls; + } + Decls.push_back(AwaitDecl); + Context.BSCDesugaredMap[FD].push_back(AwaitDecl); + + // free + BSCMethodDecl *FreeDecl = buildFreeFunctionDefinition(*this, RD, FD, IsOptimization); + if (!FreeDecl) { + return Decls; + } + Decls.push_back(FreeDecl); + Context.BSCDesugaredMap[FD].push_back(FreeDecl); + + // Awaitable Vtable VarDecl + VarDecl *AwaitVtableVD = buildAwaitVtableInitDecl( + *this, FD, AwaitableVtableRD, AwaitDecl, FreeDecl); + if (!AwaitVtableVD) { + return Decls; + } + Decls.push_back(AwaitVtableVD); + Context.BSCDesugaredMap[FD].push_back(AwaitVtableVD); + + // state transform define + const int FutureStateNumber = AwaitFinder.GetAwaitExprNum() + 1; + FunctionDecl *StateTransDecl = buildStateTransFunction( + *this, RD, FD, ContVtableDecls, ContVoidRDType, FutureStateNumber); + if (!StateTransDecl) { + return Decls; + } + 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, FutureInitDef, AwaitableRD, AwaitVtableVD); + // } + + 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/SemaBSCCoroutine.cpp b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp index a67c1c8dfea5da0973605bc68831a3551aff9036..c269ff10cc5a10a5ac66e4f012a23c18934c6a54 100644 --- a/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp +++ b/clang/lib/Sema/BSC/SemaBSCCoroutine.cpp @@ -13,537 +13,11 @@ #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, false, true); - BSCMethodDecl *BSCMethod = nullptr; - if (!Result.empty()) - BSCMethod = dyn_cast_or_null(Result.getRepresentativeDecl()); - return BSCMethod; -} - -static bool implementedFutureType(Sema &S, QualType Ty) { - RecordDecl *FutureRD = nullptr; - if (const auto *RT = Ty->getAs()) { - FutureRD = RT->getAsRecordDecl(); - } - - 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) {} - - 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 << "\"future.hbs\""; - return QualType(); - } - - TemplateArgumentListInfo Args(SLoc, SLoc); - Args.addArgument(TemplateArgumentLoc( - TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, SLoc))); - QualType PollResultRecord = - S.CheckTemplateIdType(TemplateName(CTD), SourceLocation(), Args); - if (PollResultRecord.isNull()) return QualType(); - if (S.RequireCompleteType(SLoc, PollResultRecord, - diag::err_coroutine_type_missing_specialization)) - return QualType(); - return PollResultRecord; -} - -} // namespace - // build struct Future declaration for async function static RecordDecl *buildOpaqueFutureRecordDecl(Sema &S, FunctionDecl *FD) { DeclarationName funcName = FD->getDeclName(); @@ -557,113 +31,6 @@ 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); - } - - 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; -} - -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 static VarDecl *buildVtableInitDecl(Sema &S, FunctionDecl *FD, QualType RecordType, QualType ReturnType, @@ -684,285 +51,20 @@ static VarDecl *buildVtableInitDecl(Sema &S, FunctionDecl *FD, Args.addArgument(TemplateArgumentLoc( TemplateArgument(ReturnType), S.Context.getTrivialTypeSourceInfo(ReturnType, SLoc))); - QualType InstantiatedTrait = - S.CheckTemplateIdType(TemplateName(TraitDecl), SourceLocation(), Args); - - if (InstantiatedTrait.isNull()) { - return nullptr; - } - - auto x = S.DesugarImplTrait( - TraitDecl->getTemplatedDecl(), SLoc, SLoc, ELoc, SourceRange(SLoc, ELoc), - RecordType, - S.Context.getElaboratedType(ETK_Trait, nullptr, InstantiatedTrait), SLoc, - Initialize); - - 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(); + QualType InstantiatedTrait = + S.CheckTemplateIdType(TemplateName(TraitDecl), SourceLocation(), Args); - 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); + if (InstantiatedTrait.isNull()) { + return nullptr; } - NewFD->setParams(ParmVarDecls); - NewFD->setLexicalDeclContext(S.Context.getTranslationUnitDecl()); - S.PushOnScopeChains(NewFD, S.getCurScope(), true); - return NewFD; + + auto x = S.DesugarImplTrait( + TraitDecl->getTemplatedDecl(), SLoc, SLoc, ELoc, SourceRange(SLoc, ELoc), + RecordType, + S.Context.getElaboratedType(ETK_Trait, nullptr, InstantiatedTrait), SLoc, + Initialize); + + return x; } // build function struct Future for async function @@ -1230,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 @@ -2063,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()))); } @@ -2203,11 +814,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) { @@ -2418,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) { @@ -2873,121 +1252,9 @@ 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 (!IsBSCCompatibleFutureType(FD->getReturnType())) { + if (!IsBSCCompatibleAsyncType(FD->getReturnType())) { QualType ReturnTy = FD->getReturnType(); ReturnTy.removeLocalConst(); // TODO: need to reconsider. if (ReturnTy->isVoidType()) { @@ -2999,18 +1266,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 +1332,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 +1357,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 +1383,11 @@ 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()); + RecordDecl *RD = + buildFutureRecordDecl(*this, FD, AwaitFinder.GetAwaitExpr(), + VarFinder.GetLocalVarList(), QualType()); auto RDType = Context.getRecordType(RD); QualType PointerStructTy = Context.getPointerType(RDType); - if (!RD) { return Decls; } @@ -3142,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/SemaBSCTrait.cpp b/clang/lib/Sema/BSC/SemaBSCTrait.cpp index 31210494b9c493301fd25c6358daf027be8207e3..c76509d82c9159a9e05385c8bdeefcafb265273a 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; } @@ -206,6 +157,59 @@ 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(); @@ -1036,8 +1040,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/BSC/SemaExprBSC.cpp b/clang/lib/Sema/BSC/SemaExprBSC.cpp new file mode 100644 index 0000000000000000000000000000000000000000..304959f9439e9f3c8881b9a6a6473781b6ef139d --- /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 a665edbb358a22451336d54958a4655682d26714..7326b4b71e94a684e9db8af409706293d7ae3500 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -16,11 +16,13 @@ add_clang_library(clangSema BSC/SemaBSCOverload.cpp BSC/SemaBSCOwnedStruct.cpp BSC/SemaBSCCoroutine.cpp + BSC/SemaBSCContinuation.cpp 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/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index b174416b2a54141d7e60aecb9b218d61a37aebe5..9452a13e3afe21da000aecbd5d6f9ee5f7794a29 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()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 246582275fef89b4bffa58f4ee4dfb061826f363..21601d552ae92c15b08ef2e8b483a5a24918ba1d 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]) { 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 12f124d2e180f8756b9a5b40254a62adcb8eecfe..d5e72ba54936a61f58be5cfac8b2c48de0fc1f0a 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 0000000000000000000000000000000000000000..188bd018541ae37b88c5ee9e7ce9223b71703d86 --- /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 0000000000000000000000000000000000000000..755d3afa45487d000d0543674bf6f139c3345d03 --- /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 0000000000000000000000000000000000000000..e6d451ed8115fd14e464a042337a9ab0507b6c8e --- /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 0000000000000000000000000000000000000000..ddc8c020937c647b06b1edd33e7f999e7f4129d0 --- /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 0000000000000000000000000000000000000000..4c2bc28935c234571f12d5a1186da35beb361e7d --- /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 0000000000000000000000000000000000000000..8d1638dfe075dd27e6f1a343869d2b5bded611b7 --- /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 0000000000000000000000000000000000000000..b21b95d4a8be63f746b4bb005bf3257e8d70a360 --- /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 0000000000000000000000000000000000000000..77e62553e375b8675864ce030e66cab473902ad9 --- /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 0000000000000000000000000000000000000000..ae35e36de3c4b482d1a1963ad516cc0a65f185a9 --- /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 0000000000000000000000000000000000000000..22dafed6f1fac465a38db7c7591fd6f437ec2345 --- /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 0000000000000000000000000000000000000000..55d418168fde0677db0c2fbf9830c7eb4438f34b --- /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 0000000000000000000000000000000000000000..96e43af739bfc4607f4961622ae13e80b342e2bf --- /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 0000000000000000000000000000000000000000..e4c21394693421a852d785146ad1ee8779dd6db5 --- /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 0000000000000000000000000000000000000000..8e5a579b8af0695b964cd4d16f58d637c14f8c2a --- /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 0000000000000000000000000000000000000000..7735a135c9adf4988615124692efb7a535571abb --- /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 0000000000000000000000000000000000000000..315ece2244a0849a0aa62db1fe3747f0ca262cf4 --- /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 0000000000000000000000000000000000000000..b977781e3be4670f8cf636d1afd443fdcf5bf4a6 --- /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 0000000000000000000000000000000000000000..9dd62ea074152d757e8d02351011888042674733 --- /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 0000000000000000000000000000000000000000..41a0095a14d8c3196e8357a4f21c3514aad91cc9 --- /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 0000000000000000000000000000000000000000..a6c29dc84822223cab7317f8ea9d2c36fcb2c79f --- /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 0000000000000000000000000000000000000000..2b808aa985533d9e1ea1ebc0fc0eb33382a9bac2 --- /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 0000000000000000000000000000000000000000..0661e77c343b29e0bc752c64c718ef4a3b7ac9bc --- /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 0000000000000000000000000000000000000000..2146cb82f8f0958af16f0970c4be3764930587e1 --- /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 0000000000000000000000000000000000000000..db42545b657697147a7f93f12b39d5a9d403e4a0 --- /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 0000000000000000000000000000000000000000..e1836e3a2de2f7b6f65fbc597b38af2bdabf43be --- /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 0000000000000000000000000000000000000000..ad45745624f5136da1fdee5cf3791a4e18b2af17 --- /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 0000000000000000000000000000000000000000..77b1639d0aa0ab6b46dcf6689652a73fc6d876c6 --- /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 0000000000000000000000000000000000000000..3def1220fd68e604deeeccf587d149901b62f31f --- /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 0000000000000000000000000000000000000000..566e37f1a2a5b75160582e60503d5ddb1ea68576 --- /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 0000000000000000000000000000000000000000..fa09361f39762963326e8494ce76255c09a41dac --- /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 0000000000000000000000000000000000000000..bb029e9f22b98d7f4ed18b7273d7313aa9c7a424 --- /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 0000000000000000000000000000000000000000..de8609dfd8beb46050518d15acded00bd0205798 --- /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 0000000000000000000000000000000000000000..63340fc38320f5320db40f8cd7a764ac36c878d5 --- /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 0000000000000000000000000000000000000000..376197398bbc103e70859a98741b4a4f4396df87 --- /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 0000000000000000000000000000000000000000..c7f8d0ee7209b06dda3231f19f3676b32fd2cb1f --- /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 0000000000000000000000000000000000000000..d07a3c26ee4643bce0b85a294ef28b35c258a129 --- /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 0000000000000000000000000000000000000000..98711007357b455f6b0e0f34da7638bb1784ba3e --- /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 0000000000000000000000000000000000000000..6e5ed8c3e6a2e1fb8c0592032292584abec5740a --- /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 0000000000000000000000000000000000000000..43bea61a07c71b1c128a393711d64bd4a807841c --- /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 0000000000000000000000000000000000000000..12e5a081d70d1fab8dcdbd83dfa1e69b562b7835 --- /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 0000000000000000000000000000000000000000..5bfe8cea6220a018dcb398a4e59e05f1efc0d956 --- /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 0000000000000000000000000000000000000000..72f92719ce60f5de813039cb892a377c5ecc8990 --- /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 0000000000000000000000000000000000000000..303fb297c7a7f8ab67a4f7c89e005a61e8aad1a5 --- /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 0000000000000000000000000000000000000000..6106b5324dc6eb714dbcb92bb45b020637a81825 --- /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 0000000000000000000000000000000000000000..4665632c11d2649a8d5a4cb185274b6ca7809190 --- /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 0000000000000000000000000000000000000000..42eccb0ea502e12361e35a3cf9058ae8b65dc5e0 --- /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 0000000000000000000000000000000000000000..d4e8d2a17673b66548511636e47df3d14ad661f4 --- /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 0000000000000000000000000000000000000000..50295cca15d4b16aa44cfe477a1f58a6b5f68365 --- /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 0000000000000000000000000000000000000000..b56948a3674f004e37c01f6460577a5712b01579 --- /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 0000000000000000000000000000000000000000..99069e4b8d68b6c2b7e2e35a178c455fa2ee5226 --- /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 0000000000000000000000000000000000000000..bf92b6d369df2200dcf662ab49f6072069741da2 --- /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 0000000000000000000000000000000000000000..8a3165ec07d94eff9e41c93c96c2da2979e8161b --- /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 0000000000000000000000000000000000000000..b44227475f4dcb25784d2dcdad259f6f73602539 --- /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 0000000000000000000000000000000000000000..f67405c48a876abc10b90c33d93e629ffcbd4aa0 --- /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 0000000000000000000000000000000000000000..727d59074ae335a4edfbbdc1d39c4aad34173245 --- /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 0000000000000000000000000000000000000000..7913907e7a2e05a97fc1ef2b6ebbb198e750f8a0 --- /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 0000000000000000000000000000000000000000..c17b864cab0bcfb5e341eb3eb13b42e2a2d8fff4 --- /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 0000000000000000000000000000000000000000..0fb0256fe536073019145797a9d83ee7f3447672 --- /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 0000000000000000000000000000000000000000..87afec99340dd6c2ae61047f1f1e1b880906bbad --- /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 0000000000000000000000000000000000000000..bd320d445577fb7648dee0d2a5102d2e5e34b65b --- /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 0000000000000000000000000000000000000000..f8bf6b92939ce6ce9983070f1db447e4d06c0ddf --- /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 0000000000000000000000000000000000000000..9b3e257da576cf31ddb1b43591c20f651905f907 --- /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 0000000000000000000000000000000000000000..80f324040d0ac1666dab76bc211517dd81046114 --- /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 0000000000000000000000000000000000000000..4d2558a1405bc2bdd9bce76e7e9ff4eebf13887e --- /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 0000000000000000000000000000000000000000..02b798e995ae7a654059372ed739573c9c3efc57 --- /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 0000000000000000000000000000000000000000..38b23ab2f39347778425e38a04efc50b6eaa3b4f --- /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 0000000000000000000000000000000000000000..f5785a0101903b07882f35470b12d9e3209f9f66 --- /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 0000000000000000000000000000000000000000..651ffe6a724d347f7a6bc55ced07e32360501ed7 --- /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 0000000000000000000000000000000000000000..23eba4ba61bee198edcaeb499af2279aa0d46d9d --- /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 0000000000000000000000000000000000000000..ab280161d2bc80cb2ba94b2295a6c0df2a5c7991 --- /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 0000000000000000000000000000000000000000..c463c660a4f9213566f0722e579d02261f7a9db9 --- /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 0000000000000000000000000000000000000000..e6cda4699afb483a77ff2050eca342b680ee907f --- /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 0000000000000000000000000000000000000000..a835a8b4ca1c6547603fdfb45a6cc0ffa4956ab1 --- /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 0000000000000000000000000000000000000000..38fd40d49c7a3afd2fc21b59b80aadf35e6ad00b --- /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 0000000000000000000000000000000000000000..847d1bd777ca9fbc4e19ba14de1c70d247a3be32 --- /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 0000000000000000000000000000000000000000..e8933477f6b7e93bd3de99705c106d6eb0cd6f14 --- /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 0000000000000000000000000000000000000000..5b5b49d278d693988e450b52ddc153599462cc3c --- /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 0000000000000000000000000000000000000000..36c9e93fa52b6ff518fdaca2059ba435e5e73718 --- /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 0000000000000000000000000000000000000000..9ce7ad0eaecf9f68b7ec642dd20ecd7044d36207 --- /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 0000000000000000000000000000000000000000..e6c5717cb7745e566eea439a70ee9361c6e6e618 --- /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 0000000000000000000000000000000000000000..bde6d7891cb84f6bd64a1ee2723d22692922e977 --- /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 0000000000000000000000000000000000000000..e32292bdc88a49a994b93bccf6a0c1e0f0f08b4d --- /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 0000000000000000000000000000000000000000..2ba7a7d9f6a602505abaff8510157ceaa3cd6299 --- /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 0000000000000000000000000000000000000000..af2897ac0a092f1af67cfa4aafac0741b14e029a --- /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 0000000000000000000000000000000000000000..e53124d3aa6a7647fbc0eacdc0fbdc1c8c0bff97 --- /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 0000000000000000000000000000000000000000..c515556a29d2ee49ae51ce4aa0e2d609d9bd250d --- /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 0000000000000000000000000000000000000000..a6175ba46ab8351f114d6e40ea004a5e585d3c4d --- /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 0000000000000000000000000000000000000000..dfc1cd3d2c9ec3d70793bc81b7506e700d525a6a --- /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 0000000000000000000000000000000000000000..acac91c9377063a1b3ee84c9456c432bde25a68d --- /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 0000000000000000000000000000000000000000..9c989543c24a827f708c69c742183c560a993dd3 --- /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 0000000000000000000000000000000000000000..08180bddaeaeb35ac7976e800edc69f3d63d57f6 --- /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 0000000000000000000000000000000000000000..7690030720d3b199becea8c68aee2132aa83ef15 --- /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 0000000000000000000000000000000000000000..37443f8b6f130bdf9c546d50a4c50e69670c8176 --- /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 0000000000000000000000000000000000000000..c01910b29023a992633107e0f5b4efd5caf22b9d --- /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 0000000000000000000000000000000000000000..246a65375cdd5ec0cf46476f7d225c66d7ff9669 --- /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 0000000000000000000000000000000000000000..3d029c182305a86ee72fba5e78c70b1dab1cc479 --- /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 0000000000000000000000000000000000000000..253d5e8d6d3bc9b7dd4bdbc2517892228a993c7f --- /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 0000000000000000000000000000000000000000..e9a963758093d7af71cbfa68327b5f4b74d61e16 --- /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 0000000000000000000000000000000000000000..16da53787ebc7ae05232a3e58c5eeb75f2a4db71 --- /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 0000000000000000000000000000000000000000..0cdac3d7a20b7367af20665828144be013dd0b80 --- /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 0000000000000000000000000000000000000000..52e572bd16b36458baa20290265867b2d2e9d2a5 --- /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 072aea9ae03adec844eee4b692d2963375d3009c..3d99648bfee9c4adc72eb3c0b5cd6770f085ed55 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 @@ -56,18 +57,20 @@ 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; // 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 935864d681fd269fd90660acfbcb8c041cbb7a8f..6b94c61c9222c5a28ef4ae5a2a3e9068ab49bc10 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 @@ -46,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: }; @@ -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: 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: { +// 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; // 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: 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: { +// 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; // 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: 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: { +// 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; // 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: 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: { +// 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; // 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 6cbec0afbf9b7586983f8dcb22093c3960df0466..a6246df31c183be115b57b3cb428783e1142cd69 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() { @@ -47,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; @@ -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