diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-10-05 22:41:02 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-10-05 22:41:02 +0000 |
commit | 76767b5a5757212d47c2bc4d55751ad28bf535be (patch) | |
tree | 6a0d577fe38f7bc43a7471e79df5770c5d0c69da /lib/CodeGen/CGExprCXX.cpp | |
parent | 9deb8dd73416c9e81ed263cea329cfeeb5874694 (diff) |
PR22924, PR22845, some of CWG1464: When checking the initializer for an array
new expression, distinguish between the case of a constant and non-constant
initializer. In the former case, if the bound is erroneous (too many
initializer elements, bound is negative, or allocated size overflows), reject,
and take the bound into account when determining whether we need to
default-construct any elements. In the remanining cases, move the logic to
check for default-constructibility of trailing elements into the initialization
code rather than inventing a bogus array bound, to cope with cases where the
number of initialized elements is not the same as the number of initializer
list elements (this can happen due to string literal initialization or brace
elision).
This also fixes rejects-valid and crash-on-valid errors when initializing a
new'd array of character type from a braced string literal.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@283406 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGExprCXX.cpp')
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 93 |
1 files changed, 66 insertions, 27 deletions
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 4f54a0962f..e022663788 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -877,8 +877,68 @@ void CodeGenFunction::EmitNewArrayInitializer( CharUnits ElementAlign = BeginPtr.getAlignment().alignmentOfArrayElement(ElementSize); + // Attempt to perform zero-initialization using memset. + auto TryMemsetInitialization = [&]() -> bool { + // FIXME: If the type is a pointer-to-data-member under the Itanium ABI, + // we can initialize with a memset to -1. + if (!CGM.getTypes().isZeroInitializable(ElementType)) + return false; + + // Optimization: since zero initialization will just set the memory + // to all zeroes, generate a single memset to do it in one shot. + + // Subtract out the size of any elements we've already initialized. + auto *RemainingSize = AllocSizeWithoutCookie; + if (InitListElements) { + // We know this can't overflow; we check this when doing the allocation. + auto *InitializedSize = llvm::ConstantInt::get( + RemainingSize->getType(), + getContext().getTypeSizeInChars(ElementType).getQuantity() * + InitListElements); + RemainingSize = Builder.CreateSub(RemainingSize, InitializedSize); + } + + // Create the memset. + Builder.CreateMemSet(CurPtr, Builder.getInt8(0), RemainingSize, false); + return true; + }; + // If the initializer is an initializer list, first do the explicit elements. if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { + // Initializing from a (braced) string literal is a special case; the init + // list element does not initialize a (single) array element. + if (ILE->isStringLiteralInit()) { + // Initialize the initial portion of length equal to that of the string + // literal. The allocation must be for at least this much; we emitted a + // check for that earlier. + AggValueSlot Slot = + AggValueSlot::forAddr(CurPtr, ElementType.getQualifiers(), + AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); + EmitAggExpr(ILE->getInit(0), Slot); + + // Move past these elements. + InitListElements = + cast<ConstantArrayType>(ILE->getType()->getAsArrayTypeUnsafe()) + ->getSize().getZExtValue(); + CurPtr = + Address(Builder.CreateInBoundsGEP(CurPtr.getPointer(), + Builder.getSize(InitListElements), + "string.init.end"), + CurPtr.getAlignment().alignmentAtOffset(InitListElements * + ElementSize)); + + // Zero out the rest, if any remain. + llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements); + if (!ConstNum || !ConstNum->equalsInt(InitListElements)) { + bool OK = TryMemsetInitialization(); + (void)OK; + assert(OK && "couldn't memset character type?"); + } + return; + } + InitListElements = ILE->getNumInits(); // If this is a multi-dimensional array new, we will initialize multiple @@ -945,32 +1005,6 @@ void CodeGenFunction::EmitNewArrayInitializer( CurPtr = Builder.CreateBitCast(CurPtr, BeginPtr.getType()); } - // Attempt to perform zero-initialization using memset. - auto TryMemsetInitialization = [&]() -> bool { - // FIXME: If the type is a pointer-to-data-member under the Itanium ABI, - // we can initialize with a memset to -1. - if (!CGM.getTypes().isZeroInitializable(ElementType)) - return false; - - // Optimization: since zero initialization will just set the memory - // to all zeroes, generate a single memset to do it in one shot. - - // Subtract out the size of any elements we've already initialized. - auto *RemainingSize = AllocSizeWithoutCookie; - if (InitListElements) { - // We know this can't overflow; we check this when doing the allocation. - auto *InitializedSize = llvm::ConstantInt::get( - RemainingSize->getType(), - getContext().getTypeSizeInChars(ElementType).getQuantity() * - InitListElements); - RemainingSize = Builder.CreateSub(RemainingSize, InitializedSize); - } - - // Create the memset. - Builder.CreateMemSet(CurPtr, Builder.getInt8(0), RemainingSize, false); - return true; - }; - // If all elements have already been initialized, skip any further // initialization. llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements); @@ -1349,7 +1383,12 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // If there is a brace-initializer, cannot allocate fewer elements than inits. unsigned minElements = 0; if (E->isArray() && E->hasInitializer()) { - if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E->getInitializer())) + const InitListExpr *ILE = dyn_cast<InitListExpr>(E->getInitializer()); + if (ILE && ILE->isStringLiteralInit()) + minElements = + cast<ConstantArrayType>(ILE->getType()->getAsArrayTypeUnsafe()) + ->getSize().getZExtValue(); + else if (ILE) minElements = ILE->getNumInits(); } |