void ReturnSynthesizer::Transform() { if (!getTransaction()->getCompilationOpts().ResultEvaluation) return; FunctionDecl* FD = getTransaction()->getWrapperFD(); int foundAtPos = -1; Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos, /*omitDS*/false, m_Sema); if (lastExpr) { QualType RetTy = lastExpr->getType(); if (!RetTy->isVoidType() && RetTy.isTriviallyCopyableType(*m_Context)) { // Change the void function's return type // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); FunctionProtoType::ExtProtoInfo EPI; QualType FnTy = m_Context->getFunctionType(RetTy, llvm::ArrayRef<QualType>(), EPI); FD->setType(FnTy); CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); assert(CS && "Missing body?"); // Change it to a return stmt (Avoid dealloc/alloc of all el.) *(CS->body_begin() + foundAtPos) = m_Sema->ActOnReturnStmt(lastExpr->getExprLoc(), lastExpr).take(); } } else if (foundAtPos >= 0) { // check for non-void return statement CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); Stmt* CSS = *(CS->body_begin() + foundAtPos); if (ReturnStmt* RS = dyn_cast<ReturnStmt>(CSS)) { if (Expr* RetV = RS->getRetValue()) { QualType RetTy = RetV->getType(); // Any return statement will have been "healed" by Sema // to correspond to the original void return type of the // wrapper, using a ImplicitCastExpr 'void' <ToVoid>. // Remove that. if (RetTy->isVoidType()) { ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV); if (VoidCast) { RS->setRetValue(VoidCast->getSubExpr()); RetTy = VoidCast->getSubExpr()->getType(); } } if (!RetTy->isVoidType() && RetTy.isTriviallyCopyableType(*m_Context)) { Sema::ContextRAII pushedDC(*m_Sema, FD); FunctionProtoType::ExtProtoInfo EPI; QualType FnTy = m_Context->getFunctionType(RetTy, llvm::ArrayRef<QualType>(), EPI); FD->setType(FnTy); } // not returning void } // have return value } // is a return statement } // have a statement }
C2::FunctionDecl* C2Sema::createFuncDecl(const char* name, SourceLocation loc, bool is_public, Expr* rtype) { assert(rtype); TypeExpr* typeExpr = cast<TypeExpr>(rtype); if (typeExpr->hasLocalQualifier()) { // TODO let Parser check this (need extra arg for ParseSingleTypeSpecifier()) // TODO need local's location Diag(loc, diag::err_invalid_local_returntype); } FunctionDecl* D = new FunctionDecl(name, loc, is_public, typeExpr->getType()); delete typeExpr; QualType qt = typeContext.getFunctionType(D); D->setType(qt); return D; }
C2::Module* C2ModuleLoader::load(const std::string& name) { // NOTE: MEMLEAK on Types clang::SourceLocation loc; if (name == "stdio") { Module* stdioMod = new C2::Module("stdio", true, true); // int puts(const char* s); { FunctionDecl* func = new FunctionDecl("puts", loc, true, Type::Int32()); // TODO correct arg QualType QT(new PointerType(Type::Int8()), QUAL_CONST); QT->setCanonicalType(QT); VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "s", loc, QT, 0, true); Arg1->setType(QT); func->addArg(Arg1); stdioMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } //int printf(const char *format, ...); { FunctionDecl* func = new FunctionDecl("printf", loc, true, Type::Int32()); // NOTE: MEMLEAK ON TYPE, this will go away when we remove these dummy protos QualType QT(new PointerType(Type::Int8()), QUAL_CONST); QT->setCanonicalType(QT); VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "format", loc, QT, 0, true); Arg1->setType(QT); func->addArg(Arg1); func->setVariadic(); stdioMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } //int sprintf(char *str, const char *format, ...); { FunctionDecl* func = new FunctionDecl("sprintf", loc, true, Type::Int32()); // NOTE: MEMLEAK ON TYPE, this will go away when we remove these dummy protos QualType QT(new PointerType(Type::Int8()), QUAL_CONST); QT->setCanonicalType(QT); VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "str", loc, QT, 0, true); Arg1->setType(QT); func->addArg(Arg1); VarDecl* Arg2 = new VarDecl(VARDECL_PARAM, "format", loc, QT, 0, true); Arg2->setType(QT); func->addArg(Arg2); func->setVariadic(); stdioMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } return stdioMod; } if (name == "string") { Module* stringMod = new C2::Module("string", true, true); // void *memset(void *s, int c, size_t n); { QualType VP(new PointerType(Type::Void())); VP->setCanonicalType(VP); FunctionDecl* func = new FunctionDecl("memset", loc, true, VP); // NOTE: MEMLEAK ON TYPE, this will go away when we remove these dummy protos VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "s", loc, VP, 0, true); Arg1->setType(VP); func->addArg(Arg1); VarDecl* Arg2 = new VarDecl(VARDECL_PARAM, "c", loc, Type::Int32(), 0, true); Arg2->setType(Type::Int32()); func->addArg(Arg2); // TEMP size_t -> uint32 VarDecl* Arg3 = new VarDecl(VARDECL_PARAM, "n", loc, Type::UInt32(), 0, true); Arg3->setType(Type::UInt32()); func->addArg(Arg3); stringMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } return stringMod; } if (name == "stdlib") { Module* stdlibMod = new C2::Module("stdlib", true, true); //void exit(int status); { FunctionDecl* func = new FunctionDecl("exit", loc, true, Type::Void()); // TODO correct arg VarDecl* Arg1 = new VarDecl(VARDECL_PARAM, "status", loc, Type::Int32(), 0, true); Arg1->setType(Type::Int32()); func->addArg(Arg1); stdlibMod->addSymbol(func); // function type func->setType(QualType(new FunctionType(func), 0)); } return stdlibMod; } if (name == "c2") { Module* c2Mod = new C2::Module("c2", true, false); // uint64 buildtime { // make constant, CTC_NONE QualType QT = Type::UInt64(); QT.addConst(); uint64_t value = time(0); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, value, false)); // TODO get error without value if CTC_NONE, CTC_FULL gives out-of-bounds for value 123?!! init->setCTC(CTC_NONE); // Don't check range, only type init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "buildtime", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int8 min_int8 { QualType QT = Type::Int8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -128, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int8 max_int8 { QualType QT = Type::Int8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 127, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint8 min_uint8 { QualType QT = Type::UInt8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint8 max_uint8 { QualType QT = Type::UInt8(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 255, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint8", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int16 min_int16 { QualType QT = Type::Int16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -32768, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int16 max_int16 { QualType QT = Type::Int16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 32767, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint16 min_uint16 { QualType QT = Type::UInt16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint16 max_uint16 { QualType QT = Type::UInt16(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 65535, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint16", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int32 min_int32 { QualType QT = Type::Int32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -2147483648, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int32 max_int32 { QualType QT = Type::Int32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 2147483647, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint32 min_uint32 { QualType QT = Type::UInt32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint32 max_uint32 { QualType QT = Type::UInt32(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 4294967295, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint32", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int64 min_int64 { QualType QT = Type::Int64(); QT.addConst(); // NOTE: minimum should be -..808, but clang complains about it.. Expr* init = new IntegerLiteral(loc, llvm::APInt(64, -9223372036854775807ll, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_int64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // int64 max_int64 { QualType QT = Type::Int64(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 9223372036854775807ll, true)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_int64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint64 min_uint64 { QualType QT = Type::UInt64(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 0, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "min_uint64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } // uint64 max_uint64 { QualType QT = Type::UInt64(); QT.addConst(); Expr* init = new IntegerLiteral(loc, llvm::APInt(64, 18446744073709551615llu, false)); init->setCTC(CTC_FULL); init->setConstant(); init->setType(QT); VarDecl* var = new VarDecl(VARDECL_GLOBAL, "max_uint64", loc, QT, init, true); var->setType(QT); c2Mod->addSymbol(var); } return c2Mod; } return 0; }