mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 10:57:35 +03:00
ImportC: Account for StringExp typed as static array with length > string length
Fixes dmd-testsuite's compilable/test23066.c.
This commit is contained in:
parent
f31738b2d6
commit
14759a744e
5 changed files with 38 additions and 24 deletions
|
@ -235,7 +235,8 @@ LLGlobalVariable *IRState::getCachedStringLiteral(StringExp *se) {
|
||||||
keyData.length);
|
keyData.length);
|
||||||
|
|
||||||
return getCachedStringLiteralImpl(module, *cache, key, [se]() {
|
return getCachedStringLiteralImpl(module, *cache, key, [se]() {
|
||||||
return buildStringLiteralConstant(se, true);
|
// null-terminate
|
||||||
|
return buildStringLiteralConstant(se, se->numberOfCodeUnits() + 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1654,30 +1654,31 @@ llvm::Constant *DtoConstSymbolAddress(const Loc &loc, Declaration *decl) {
|
||||||
llvm_unreachable("Taking constant address not implemented.");
|
llvm_unreachable("Taking constant address not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm) {
|
llvm::Constant *buildStringLiteralConstant(StringExp *se,
|
||||||
if (se->sz == 1) {
|
uint64_t bufferLength) {
|
||||||
|
const auto stringLength = se->numberOfCodeUnits();
|
||||||
|
assert(bufferLength >= stringLength);
|
||||||
|
|
||||||
|
if (se->sz == 1 && bufferLength <= stringLength + 1) {
|
||||||
const DString data = se->peekString();
|
const DString data = se->peekString();
|
||||||
|
const bool nullTerminate = (bufferLength == stringLength + 1);
|
||||||
return llvm::ConstantDataArray::getString(
|
return llvm::ConstantDataArray::getString(
|
||||||
gIR->context(), {data.ptr, data.length}, zeroTerm);
|
gIR->context(), {data.ptr, data.length}, nullTerminate);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *dtype = se->type->toBasetype();
|
Type *dtype = se->type->toBasetype();
|
||||||
Type *cty = dtype->nextOf()->toBasetype();
|
Type *cty = dtype->nextOf()->toBasetype();
|
||||||
|
|
||||||
LLType *ct = DtoMemType(cty);
|
LLType *ct = DtoMemType(cty);
|
||||||
auto len = se->numberOfCodeUnits();
|
LLArrayType *at = LLArrayType::get(ct, bufferLength);
|
||||||
if (zeroTerm) {
|
|
||||||
len += 1;
|
|
||||||
}
|
|
||||||
LLArrayType *at = LLArrayType::get(ct, len);
|
|
||||||
|
|
||||||
std::vector<LLConstant *> vals;
|
std::vector<LLConstant *> vals;
|
||||||
vals.reserve(len);
|
vals.reserve(bufferLength);
|
||||||
for (size_t i = 0; i < se->numberOfCodeUnits(); ++i) {
|
for (uint64_t i = 0; i < stringLength; ++i) {
|
||||||
vals.push_back(LLConstantInt::get(ct, se->getCodeUnit(i), false));
|
vals.push_back(LLConstantInt::get(ct, se->getCodeUnit(i), false));
|
||||||
}
|
}
|
||||||
if (zeroTerm) {
|
const auto nullChar = LLConstantInt::get(ct, 0, false);
|
||||||
vals.push_back(LLConstantInt::get(ct, 0, false));
|
for (uint64_t i = stringLength; i < bufferLength; ++i) {
|
||||||
|
vals.push_back(nullChar);
|
||||||
}
|
}
|
||||||
return LLConstantArray::get(at, vals);
|
return LLConstantArray::get(at, vals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,7 +232,8 @@ LLConstant *toConstantArray(LLType *ct, LLArrayType *at, T *str, size_t len,
|
||||||
return LLConstantArray::get(at, vals);
|
return LLConstantArray::get(at, vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm);
|
llvm::Constant *buildStringLiteralConstant(StringExp *se,
|
||||||
|
uint64_t bufferLength);
|
||||||
|
|
||||||
/// Returns true if the specified symbol is to be defined on declaration,
|
/// Returns true if the specified symbol is to be defined on declaration,
|
||||||
/// primarily for -linkonce-templates.
|
/// primarily for -linkonce-templates.
|
||||||
|
|
|
@ -165,8 +165,9 @@ public:
|
||||||
Type *const t = e->type->toBasetype();
|
Type *const t = e->type->toBasetype();
|
||||||
|
|
||||||
if (auto ts = t->isTypeSArray()) {
|
if (auto ts = t->isTypeSArray()) {
|
||||||
bool zeroTerm = ts->dim->toInteger() == e->numberOfCodeUnits() + 1;
|
const auto arrayLength = ts->dim->toInteger();
|
||||||
result = buildStringLiteralConstant(e, zeroTerm);
|
assert(arrayLength >= e->numberOfCodeUnits());
|
||||||
|
result = buildStringLiteralConstant(e, arrayLength);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
gen/toir.cpp
24
gen/toir.cpp
|
@ -415,20 +415,30 @@ public:
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
Type *dtype = e->type->toBasetype();
|
Type *dtype = e->type->toBasetype();
|
||||||
|
const auto stringLength = e->numberOfCodeUnits();
|
||||||
|
|
||||||
|
if (auto tsa = dtype->isTypeSArray()) {
|
||||||
|
const auto arrayLength = tsa->dim->toInteger();
|
||||||
|
assert(arrayLength >= stringLength);
|
||||||
|
// ImportC: static array length may exceed string length incl. null
|
||||||
|
// terminator - bypass string-literal cache and create a separate constant
|
||||||
|
// with zero-initialized tail
|
||||||
|
if (arrayLength > stringLength + 1) {
|
||||||
|
auto constant = buildStringLiteralConstant(e, arrayLength);
|
||||||
|
result = new DLValue(e->type, constant);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
llvm::GlobalVariable *gvar = p->getCachedStringLiteral(e);
|
llvm::GlobalVariable *gvar = p->getCachedStringLiteral(e);
|
||||||
LLConstant *arrptr = DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
|
LLConstant *arrptr = DtoGEP(gvar->getValueType(), gvar, 0u, 0u);
|
||||||
|
|
||||||
if (dtype->ty == TY::Tarray) {
|
if (dtype->ty == TY::Tarray) {
|
||||||
LLConstant *clen =
|
LLConstant *clen = LLConstantInt::get(DtoSize_t(), stringLength, false);
|
||||||
LLConstantInt::get(DtoSize_t(), e->numberOfCodeUnits(), false);
|
|
||||||
result = new DSliceValue(e->type, DtoConstSlice(clen, arrptr, dtype));
|
result = new DSliceValue(e->type, DtoConstSlice(clen, arrptr, dtype));
|
||||||
} else if (dtype->ty == TY::Tsarray) {
|
} else if (dtype->ty == TY::Tsarray) {
|
||||||
Type *cty = dtype->nextOf()->toBasetype();
|
// array length matches string length with or without null terminator
|
||||||
LLType *ct = DtoMemType(cty);
|
result = new DLValue(e->type, DtoBitCast(gvar, DtoPtrToType(dtype)));
|
||||||
LLType *dstType =
|
|
||||||
getPtrToType(LLArrayType::get(ct, e->numberOfCodeUnits()));
|
|
||||||
result = new DLValue(e->type, DtoBitCast(gvar, dstType));
|
|
||||||
} else if (dtype->ty == TY::Tpointer) {
|
} else if (dtype->ty == TY::Tpointer) {
|
||||||
result = new DImValue(e->type, DtoBitCast(arrptr, DtoType(dtype)));
|
result = new DImValue(e->type, DtoBitCast(arrptr, DtoType(dtype)));
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue