From 3ec084da5906ef96c8f2a45a9685395765c50ac6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 26 Dec 2013 22:48:11 +0100 Subject: [PATCH] Return undef instead of null on toConstElem failure. This fixes a segfault with associative array literals of arrays of associative array literals, which occured because of arrayLiteralToConst not handling null values properly. Ensuring that null pointers are handled correctly in all toConstElem callers is much more error-prone than just returning an LLVM undef, an error is emitted anyway. The root of the problem is actually in the kludgly implementation of AssocArrayLiteral::toElem, we should revisit this at some point. --- dmd2/expression.h | 8 +++++++- gen/toir.cpp | 27 +++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/dmd2/expression.h b/dmd2/expression.h index 07816a4f..c436854a 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -237,9 +237,15 @@ public: virtual elem *toElem(IRState *irs); elem *toElemDtor(IRState *irs); #if IN_LLVM + /// Emits an LLVM constant corresponding to the expression. + /// + /// Due to the current implementation of AssocArrayLiteralExp::toElem,the + /// implementations have to be able to handle being called on expressions + /// that are not actually constant. In such a case, an LLVM undef of the + /// expected type should be returned (_not_ null). virtual llvm::Constant *toConstElem(IRState *irs); - virtual void cacheLvalue(IRState* irs); + virtual void cacheLvalue(IRState* irs); llvm::Value* cachedLvalue; virtual AssignExp* isAssignExp() { return NULL; } diff --git a/gen/toir.cpp b/gen/toir.cpp index d038753f..9f3b660f 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -652,8 +652,8 @@ LLConstant* AddExp::toConstElem(IRState* p) } error("expression '%s' is not a constant", toChars()); - fatal(); - return NULL; + if (!global.gag) fatal(); + return llvm::UndefValue::get(DtoType(type)); } /// Tries to remove a MulExp by a constant value of baseSize from e. Returns @@ -766,8 +766,8 @@ LLConstant* MinExp::toConstElem(IRState* p) } error("expression '%s' is not a constant", toChars()); - fatal(); - return NULL; + if (!global.gag) fatal(); + return llvm::UndefValue::get(DtoType(type)); } DValue* MinExp::toElem(IRState* p) @@ -1231,7 +1231,7 @@ Lerr: error("cannot cast %s to %s at compile time", e1->type->toChars(), type->toChars()); if (!global.gag) fatal(); - return NULL; + return llvm::UndefValue::get(DtoType(type)); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1290,11 +1290,7 @@ llvm::Constant* SymOffExp::toConstElem(IRState* p) IF_LOG Logger::println("SymOffExp::toConstElem: %s @ %s", toChars(), type->toChars()); LOG_SCOPE; - // We might get null here due to the hackish implementation of - // AssocArrayLiteralExp::toElem. llvm::Constant* base = DtoConstSymbolAddress(loc, var); - if (!base) return 0; - llvm::Constant* result; if (offset == 0) { @@ -1462,7 +1458,8 @@ LLConstant* AddrExp::toConstElem(IRState* p) else if (e1->op == TOKslice) { error("non-constant expression '%s'", toChars()); - fatal(); + if (!global.gag) fatal(); + return llvm::UndefValue::get(DtoType(type)); } // not yet supported else @@ -2872,7 +2869,8 @@ LLConstant* FuncExp::toConstElem(IRState* p) { assert(fd->tok == TOKdelegate || fd->tok == TOKreserved); error("delegate literals as constant expressions are not yet allowed"); - return 0; + if (!global.gag) fatal(); + return llvm::UndefValue::get(DtoType(type)); } // We need to actually codegen the function here, as literals are not added @@ -3557,5 +3555,10 @@ llvm::Constant* Expression::toConstElem(IRState * p) error("expression '%s' is not a constant", toChars()); if (!global.gag) fatal(); - return NULL; + + // Do not return null here, as AssocArrayLiteralExp::toElem determines + // whether it can allocate the needed arrays statically by just invoking + // toConstElem on its key/value expressions, and handling the null value + // consequently would require error-prone adaptions in all other code. + return llvm::UndefValue::get(DtoType(type)); }