ImportC: Account for StringExp typed as static array with length > string length

Fixes dmd-testsuite's compilable/test23066.c.
This commit is contained in:
Martin Kinkelin 2022-10-07 00:04:16 +02:00
parent f31738b2d6
commit 14759a744e
5 changed files with 38 additions and 24 deletions

View file

@ -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);
}); });
} }

View file

@ -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);
} }

View file

@ -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.

View file

@ -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;
} }

View file

@ -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 {