mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-02 08:01:11 +03:00
Use new druntime hooks _d_arraybounds_{slice,index} for more informative RangeErrors
Fixing dmd-testsuite's runnable/testbounds.d.
This commit is contained in:
parent
64d79ef753
commit
fab82436dd
6 changed files with 75 additions and 28 deletions
|
@ -88,10 +88,8 @@ DLValue *DtoAAIndex(const Loc &loc, Type *type, DValue *aa, DValue *key,
|
||||||
gIR->ir->CreateCondBr(cond, okbb, failbb);
|
gIR->ir->CreateCondBr(cond, okbb, failbb);
|
||||||
|
|
||||||
// set up failbb to call the array bounds error runtime function
|
// set up failbb to call the array bounds error runtime function
|
||||||
|
|
||||||
gIR->ir->SetInsertPoint(failbb);
|
gIR->ir->SetInsertPoint(failbb);
|
||||||
|
emitRangeError(gIR, loc);
|
||||||
DtoBoundsCheckFailCall(gIR, loc);
|
|
||||||
|
|
||||||
// if ok, proceed in okbb
|
// if ok, proceed in okbb
|
||||||
gIR->ir->SetInsertPoint(okbb);
|
gIR->ir->SetInsertPoint(okbb);
|
||||||
|
|
|
@ -1326,13 +1326,14 @@ void DtoIndexBoundsCheck(const Loc &loc, DValue *arr, DValue *index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arrty->ty == TY::Tpointer) {
|
if (arrty->ty == TY::Tpointer) {
|
||||||
// Length of pointers is unknown, ingore.
|
// Length of pointers is unknown, ignore.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::ICmpInst::Predicate cmpop = llvm::ICmpInst::ICMP_ULT;
|
LLValue *const llIndex = DtoRVal(index);
|
||||||
llvm::Value *cond = gIR->ir->CreateICmp(cmpop, DtoRVal(index),
|
LLValue *const llLength = DtoArrayLen(arr);
|
||||||
DtoArrayLen(arr), "bounds.cmp");
|
LLValue *const cond = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_ULT, llIndex,
|
||||||
|
llLength, "bounds.cmp");
|
||||||
|
|
||||||
llvm::BasicBlock *okbb = gIR->insertBB("bounds.ok");
|
llvm::BasicBlock *okbb = gIR->insertBB("bounds.ok");
|
||||||
llvm::BasicBlock *failbb = gIR->insertBBAfter(okbb, "bounds.fail");
|
llvm::BasicBlock *failbb = gIR->insertBBAfter(okbb, "bounds.fail");
|
||||||
|
@ -1340,24 +1341,54 @@ void DtoIndexBoundsCheck(const Loc &loc, DValue *arr, DValue *index) {
|
||||||
|
|
||||||
// set up failbb to call the array bounds error runtime function
|
// set up failbb to call the array bounds error runtime function
|
||||||
gIR->ir->SetInsertPoint(failbb);
|
gIR->ir->SetInsertPoint(failbb);
|
||||||
DtoBoundsCheckFailCall(gIR, loc);
|
emitArrayIndexError(gIR, loc, llIndex, llLength);
|
||||||
|
|
||||||
// if ok, proceed in okbb
|
// if ok, proceed in okbb
|
||||||
gIR->ir->SetInsertPoint(okbb);
|
gIR->ir->SetInsertPoint(okbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoBoundsCheckFailCall(IRState *irs, const Loc &loc) {
|
static void emitRangeErrorImpl(IRState *irs, const Loc &loc,
|
||||||
|
const char *cAssertMsg, const char *dFnName,
|
||||||
|
llvm::ArrayRef<LLValue *> extraArgs) {
|
||||||
Module *const module = irs->func()->decl->getModule();
|
Module *const module = irs->func()->decl->getModule();
|
||||||
|
|
||||||
if (global.params.checkAction == CHECKACTION_C) {
|
switch (global.params.checkAction) {
|
||||||
DtoCAssert(module, loc, DtoConstCString("array overflow"));
|
case CHECKACTION_C:
|
||||||
} else {
|
DtoCAssert(module, loc, DtoConstCString(cAssertMsg));
|
||||||
llvm::Function *errorfn =
|
break;
|
||||||
getRuntimeFunction(loc, irs->module, "_d_arraybounds");
|
case CHECKACTION_halt:
|
||||||
irs->CreateCallOrInvoke(errorfn, DtoModuleFileName(module, loc),
|
irs->ir->CreateCall(GET_INTRINSIC_DECL(trap), {});
|
||||||
DtoConstUint(loc.linnum));
|
|
||||||
|
|
||||||
// the function does not return
|
|
||||||
irs->ir->CreateUnreachable();
|
irs->ir->CreateUnreachable();
|
||||||
|
break;
|
||||||
|
case CHECKACTION_context:
|
||||||
|
case CHECKACTION_D: {
|
||||||
|
auto fn = getRuntimeFunction(loc, irs->module, dFnName);
|
||||||
|
LLSmallVector<LLValue *, 5> args;
|
||||||
|
args.reserve(2 + extraArgs.size());
|
||||||
|
args.push_back(DtoModuleFileName(module, loc));
|
||||||
|
args.push_back(DtoConstUint(loc.linnum));
|
||||||
|
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
|
||||||
|
irs->CreateCallOrInvoke(fn, args);
|
||||||
|
irs->ir->CreateUnreachable();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
llvm_unreachable("Unhandled checkAction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitRangeError(IRState *irs, const Loc &loc) {
|
||||||
|
emitRangeErrorImpl(irs, loc, "array overflow", "_d_arraybounds", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitArraySliceError(IRState *irs, const Loc &loc, LLValue *lower,
|
||||||
|
LLValue *upper, LLValue *length) {
|
||||||
|
emitRangeErrorImpl(irs, loc, "array slice out of bounds",
|
||||||
|
"_d_arraybounds_slice", {lower, upper, length});
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitArrayIndexError(IRState *irs, const Loc &loc, LLValue *index,
|
||||||
|
LLValue *length) {
|
||||||
|
emitRangeErrorImpl(irs, loc, "array index out of bounds",
|
||||||
|
"_d_arraybounds_index", {index, length});
|
||||||
|
}
|
||||||
|
|
|
@ -88,4 +88,8 @@ void DtoIndexBoundsCheck(const Loc &loc, DValue *arr, DValue *index);
|
||||||
|
|
||||||
/// Inserts a call to the druntime function that throws the range error, with
|
/// Inserts a call to the druntime function that throws the range error, with
|
||||||
/// the given location.
|
/// the given location.
|
||||||
void DtoBoundsCheckFailCall(IRState *p, const Loc &loc);
|
void emitRangeError(IRState *irs, const Loc &loc);
|
||||||
|
void emitArraySliceError(IRState *irs, const Loc &loc, LLValue *lower,
|
||||||
|
LLValue *upper, LLValue *length);
|
||||||
|
void emitArrayIndexError(IRState *irs, const Loc &loc, LLValue *index,
|
||||||
|
LLValue *length);
|
||||||
|
|
|
@ -559,6 +559,17 @@ static void buildRuntimeModule() {
|
||||||
createFwdDecl(LINK::c, voidTy, {"_d_assert_msg"}, {stringTy, stringTy, uintTy},
|
createFwdDecl(LINK::c, voidTy, {"_d_assert_msg"}, {stringTy, stringTy, uintTy},
|
||||||
{}, Attr_Cold_NoReturn);
|
{}, Attr_Cold_NoReturn);
|
||||||
|
|
||||||
|
// void _d_arraybounds_slice(string file, uint line, size_t lower,
|
||||||
|
// size_t upper, size_t length)
|
||||||
|
createFwdDecl(LINK::c, voidTy, {"_d_arraybounds_slice"},
|
||||||
|
{stringTy, uintTy, sizeTy, sizeTy, sizeTy}, {},
|
||||||
|
Attr_Cold_NoReturn);
|
||||||
|
|
||||||
|
// void _d_arraybounds_index(string file, uint line, size_t index,
|
||||||
|
// size_t length)
|
||||||
|
createFwdDecl(LINK::c, voidTy, {"_d_arraybounds_index"},
|
||||||
|
{stringTy, uintTy, sizeTy, sizeTy}, {}, Attr_Cold_NoReturn);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
19
gen/toir.cpp
19
gen/toir.cpp
|
@ -1120,22 +1120,24 @@ public:
|
||||||
LLValue *vup = DtoRVal(e->upr);
|
LLValue *vup = DtoRVal(e->upr);
|
||||||
p->arrays.pop_back();
|
p->arrays.pop_back();
|
||||||
|
|
||||||
const bool needCheckUpper =
|
const bool hasLength = etype->ty != TY::Tpointer;
|
||||||
(etype->ty != TY::Tpointer) && !e->upperIsInBounds;
|
const bool needCheckUpper = hasLength && !e->upperIsInBounds;
|
||||||
const bool needCheckLower = !e->lowerIsLessThanUpper;
|
const bool needCheckLower = !e->lowerIsLessThanUpper;
|
||||||
if (p->emitArrayBoundsChecks() && (needCheckUpper || needCheckLower)) {
|
if (p->emitArrayBoundsChecks() && (needCheckUpper || needCheckLower)) {
|
||||||
llvm::BasicBlock *okbb = p->insertBB("bounds.ok");
|
llvm::BasicBlock *okbb = p->insertBB("bounds.ok");
|
||||||
llvm::BasicBlock *failbb = p->insertBBAfter(okbb, "bounds.fail");
|
llvm::BasicBlock *failbb = p->insertBBAfter(okbb, "bounds.fail");
|
||||||
|
|
||||||
llvm::Value *okCond = nullptr;
|
LLValue *const vlen = hasLength ? DtoArrayLen(v) : nullptr;
|
||||||
|
|
||||||
|
LLValue *okCond = nullptr;
|
||||||
if (needCheckUpper) {
|
if (needCheckUpper) {
|
||||||
okCond = p->ir->CreateICmp(llvm::ICmpInst::ICMP_ULE, vup,
|
okCond = p->ir->CreateICmp(llvm::ICmpInst::ICMP_ULE, vup, vlen,
|
||||||
DtoArrayLen(v), "bounds.cmp.lo");
|
"bounds.cmp.up");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needCheckLower) {
|
if (needCheckLower) {
|
||||||
llvm::Value *cmp = p->ir->CreateICmp(llvm::ICmpInst::ICMP_ULE, vlo,
|
LLValue *cmp = p->ir->CreateICmp(llvm::ICmpInst::ICMP_ULE, vlo, vup,
|
||||||
vup, "bounds.cmp.up");
|
"bounds.cmp.lo");
|
||||||
if (okCond) {
|
if (okCond) {
|
||||||
okCond = p->ir->CreateAnd(okCond, cmp);
|
okCond = p->ir->CreateAnd(okCond, cmp);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1146,7 +1148,8 @@ public:
|
||||||
p->ir->CreateCondBr(okCond, okbb, failbb);
|
p->ir->CreateCondBr(okCond, okbb, failbb);
|
||||||
|
|
||||||
p->ir->SetInsertPoint(failbb);
|
p->ir->SetInsertPoint(failbb);
|
||||||
DtoBoundsCheckFailCall(p, e->loc);
|
emitArraySliceError(p, e->loc, vlo, vup,
|
||||||
|
vlen ? vlen : DtoConstSize_t(0));
|
||||||
|
|
||||||
p->ir->SetInsertPoint(okbb);
|
p->ir->SetInsertPoint(okbb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit a9d48bee11c50e3b07bfccc253091c6c7fdd4008
|
Subproject commit de5a8a3bb6466f53259e83de65a6894fc4cddf6e
|
Loading…
Add table
Add a link
Reference in a new issue