diff --git a/gen/aa.cpp b/gen/aa.cpp index bdaec8d6d8..4a25698646 100644 --- a/gen/aa.cpp +++ b/gen/aa.cpp @@ -12,6 +12,7 @@ #include "declaration.h" #include "module.h" #include "mtype.h" +#include "gen/arrays.h" #include "gen/dvalue.h" #include "gen/irstate.h" #include "gen/llvm.h" @@ -91,14 +92,7 @@ DLValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, gIR->scope() = IRScope(failbb); - llvm::Function *errorfn = - getRuntimeFunction(loc, gIR->module, "_d_arraybounds"); - gIR->CreateCallOrInvoke( - errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc), - DtoConstUint(loc.linnum)); - - // the function does not return - gIR->ir->CreateUnreachable(); + DtoBoundsCheckFailCall(gIR, loc); // if ok, proceed in okbb gIR->scope() = IRScope(okbb); diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 770152df48..e64d34a8c8 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -1377,12 +1377,17 @@ void DtoIndexBoundsCheck(Loc &loc, DValue *arr, DValue *index) { } void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) { - llvm::Function *errorfn = - getRuntimeFunction(loc, irs->module, "_d_arraybounds"); - irs->CreateCallOrInvoke( - errorfn, DtoModuleFileName(irs->func()->decl->getModule(), loc), - DtoConstUint(loc.linnum)); + Module *const module = irs->func()->decl->getModule(); - // the function does not return - irs->ir->CreateUnreachable(); + if (global.params.betterC) { + DtoCAssert(module, loc, DtoConstCString("array overflow")); + } else { + llvm::Function *errorfn = + getRuntimeFunction(loc, irs->module, "_d_arraybounds"); + irs->CreateCallOrInvoke(errorfn, DtoModuleFileName(module, loc), + DtoConstUint(loc.linnum)); + + // the function does not return + irs->ir->CreateUnreachable(); + } } diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 1c59847ec3..2e9cc469d1 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -278,11 +278,37 @@ void DtoAssert(Module *M, Loc &loc, DValue *msg) { gIR->ir->CreateUnreachable(); } +void DtoCAssert(Module *M, Loc &loc, LLValue *msg) { + const auto file = DtoConstCString(loc.filename ? loc.filename + : M->srcfile->name->toChars()); + const auto line = DtoConstUint(loc.linnum); + const auto fn = getCAssertFunction(loc, gIR->module); + + llvm::SmallVector args; + if (global.params.targetTriple->isOSDarwin()) { + const auto irFunc = gIR->func(); + const auto funcName = + irFunc && irFunc->decl ? irFunc->decl->toPrettyChars() : ""; + args.push_back(DtoConstCString(funcName)); + args.push_back(file); + args.push_back(line); + args.push_back(msg); + } else { + args.push_back(msg); + args.push_back(file); + args.push_back(line); + } + + gIR->funcGen().callOrInvoke(fn, args); + + gIR->ir->CreateUnreachable(); +} + /****************************************************************************** * MODULE FILE NAME ******************************************************************************/ -LLValue *DtoModuleFileName(Module *M, const Loc &loc) { +LLConstant *DtoModuleFileName(Module *M, const Loc &loc) { return DtoConstString(loc.filename ? loc.filename : M->srcfile->name->toChars()); } diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index a30144557d..16f9be90fd 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -61,9 +61,10 @@ LLValue *DtoAllocaDump(LLValue *val, LLType *asType, int alignment = 0, // assertion generator void DtoAssert(Module *M, Loc &loc, DValue *msg); +void DtoCAssert(Module *M, Loc &loc, LLValue *msg); // returns module file name -LLValue *DtoModuleFileName(Module *M, const Loc &loc); +LLConstant *DtoModuleFileName(Module *M, const Loc &loc); /// emits goto to LabelStatement with the target identifier void DtoGoto(Loc &loc, LabelDsymbol *target); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index 93e368285e..6a7426c85c 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -160,6 +160,21 @@ llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target, //////////////////////////////////////////////////////////////////////////////// +static const char *getCAssertFunctionName() { + if (global.params.targetTriple->isOSDarwin()) { + return "__assert_rtn"; + } else if (global.params.targetTriple->isWindowsMSVCEnvironment()) { + return "_assert"; + } + return "__assert"; +} + +llvm::Function *getCAssertFunction(const Loc &loc, llvm::Module &target) { + return getRuntimeFunction(loc, target, getCAssertFunctionName()); +} + +//////////////////////////////////////////////////////////////////////////////// + // extern (D) alias dg_t = int delegate(void*); static Type *rt_dg1() { static Type *dg_t = nullptr; @@ -330,6 +345,17 @@ static void buildRuntimeModule() { ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// + // C assert function: + // OSX: void __assert_rtn(const char *func, const char *file, unsigned line, + // const char *msg) + // else: void [_]_assert(const char *msg, const char *file, unsigned line) + createFwdDecl( + LINKc, Type::tvoid, {getCAssertFunctionName()}, + global.params.targetTriple->isOSDarwin() + ? llvm::ArrayRef({voidPtrTy, voidPtrTy, uintTy, voidPtrTy}) + : llvm::ArrayRef({voidPtrTy, voidPtrTy, uintTy}), + {}, Attr_Cold_NoReturn); + // void _d_assert(string file, uint line) // void _d_arraybounds(string file, uint line) createFwdDecl(LINKc, Type::tvoid, {"_d_assert", "_d_arraybounds"}, diff --git a/gen/runtime.h b/gen/runtime.h index 458f0408f4..8834d83fe4 100644 --- a/gen/runtime.h +++ b/gen/runtime.h @@ -30,6 +30,8 @@ void freeRuntime(); llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target, const char *name); +llvm::Function *getCAssertFunction(const Loc &loc, llvm::Module &target); + void emitInstrumentationFnEnter(FuncDeclaration *decl); void emitInstrumentationFnLeave(FuncDeclaration *decl); diff --git a/gen/statements.cpp b/gen/statements.cpp index 73ffe81c93..3104eb00fa 100644 --- a/gen/statements.cpp +++ b/gen/statements.cpp @@ -1644,15 +1644,21 @@ public: stmt->loc.toChars()); LOG_SCOPE; assert(!irs->dcomputetarget); - + auto &PGO = irs->funcGen().pgo; PGO.setCurrentStmt(stmt); + Module *const module = irs->func()->decl->getModule(); + + if (global.params.betterC) { + DtoCAssert(module, stmt->loc, DtoConstCString("no switch default")); + return; + } + llvm::Function *fn = getRuntimeFunction(stmt->loc, irs->module, "_d_switch_error"); - LLValue *moduleInfoSymbol = - getIrModule(irs->func()->decl->getModule())->moduleInfoSymbol(); + LLValue *moduleInfoSymbol = getIrModule(module)->moduleInfoSymbol(); LLType *moduleInfoType = DtoType(Module::moduleinfo->type); LLCallSite call = irs->CreateCallOrInvoke( diff --git a/gen/toir.cpp b/gen/toir.cpp index d7167e3394..9642da61e0 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1684,8 +1684,16 @@ public: * msg is not evaluated at all. So should use toElemDtor() * instead of toElem(). */ - DtoAssert(p->func()->decl->getModule(), e->loc, - e->msg ? toElemDtor(e->msg) : nullptr); + DValue *const msg = e->msg ? toElemDtor(e->msg) : nullptr; + Module *const module = p->func()->decl->getModule(); + if (global.params.betterC) { + const auto cMsg = + msg ? DtoArrayPtr(msg) // assuming `msg` is null-terminated, like DMD + : DtoConstCString(e->e1->toChars()); + DtoCAssert(module, e->e1->loc, cMsg); + } else { + DtoAssert(module, e->loc, msg); + } // passed: p->scope() = IRScope(passedbb); diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 08517f2171..a79d2caf7f 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -413,12 +413,13 @@ LLConstant *DtoConstFP(Type *t, const real_t value) { //////////////////////////////////////////////////////////////////////////////// -LLConstant *DtoConstString(const char *str) { +LLConstant *DtoConstCString(const char *str) { llvm::StringRef s(str ? str : ""); - llvm::GlobalVariable *gvar = (gIR->stringLiteral1ByteCache.find(s) == - gIR->stringLiteral1ByteCache.end()) - ? nullptr - : gIR->stringLiteral1ByteCache[s]; + + const auto it = gIR->stringLiteral1ByteCache.find(s); + llvm::GlobalVariable *gvar = + it == gIR->stringLiteral1ByteCache.end() ? nullptr : it->getValue(); + if (gvar == nullptr) { llvm::Constant *init = llvm::ConstantDataArray::getString(gIR->context(), s, true); @@ -432,12 +433,16 @@ LLConstant *DtoConstString(const char *str) { #endif gIR->stringLiteral1ByteCache[s] = gvar; } + LLConstant *idxs[] = {DtoConstUint(0), DtoConstUint(0)}; - return DtoConstSlice(DtoConstSize_t(s.size()), - llvm::ConstantExpr::getGetElementPtr( - gvar->getInitializer()->getType(), - gvar, idxs, true), - Type::tchar->arrayOf()); + return llvm::ConstantExpr::getGetElementPtr(gvar->getInitializer()->getType(), + gvar, idxs, true); +} + +LLConstant *DtoConstString(const char *str) { + LLConstant *cString = DtoConstCString(str); + LLConstant *length = DtoConstSize_t(str ? strlen(str) : 0); + return DtoConstSlice(length, cString, Type::tchar->arrayOf()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/gen/tollvm.h b/gen/tollvm.h index 2c17265d46..41e62a8b0d 100644 --- a/gen/tollvm.h +++ b/gen/tollvm.h @@ -97,6 +97,7 @@ LLConstantInt *DtoConstInt(int i); LLConstantInt *DtoConstUbyte(unsigned char i); LLConstant *DtoConstFP(Type *t, real_t value); +LLConstant *DtoConstCString(const char *); LLConstant *DtoConstString(const char *); LLConstant *DtoConstBool(bool);