r283406 - PR22924, PR22845, some of CWG1464: When checking the initializer for an array

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 5 15:41:02 PDT 2016


Author: rsmith
Date: Wed Oct  5 17:41:02 2016
New Revision: 283406

URL: http://llvm.org/viewvc/llvm-project?rev=283406&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/Analysis/cfg.cpp
    cfe/trunk/test/CodeGenCXX/new-array-init.cpp
    cfe/trunk/test/SemaCXX/new-delete-cxx0x.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Wed Oct  5 17:41:02 2016
@@ -62,7 +62,6 @@ def NullConversion : DiagGroup<"null-con
 def ImplicitConversionFloatingPointToBool :
   DiagGroup<"implicit-conversion-floating-point-to-bool">;
 def ObjCLiteralConversion : DiagGroup<"objc-literal-conversion">;
-def BadArrayNewLength : DiagGroup<"bad-array-new-length">;
 def MacroRedefined : DiagGroup<"macro-redefined">;
 def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">;
 def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Oct  5 17:41:02 2016
@@ -1745,8 +1745,10 @@ def warn_uninit_byref_blockvar_captured_
 def note_block_var_fixit_add_initialization : Note<
   "did you mean to use __block %0?">;
 def note_in_omitted_aggregate_initializer : Note<
-  "in implicit initialization of %select{array element %1|field %1}0 "
-  "with omitted initializer">;
+  "in implicit initialization of %select{"
+  "array element %1 with omitted initializer|"
+  "field %1 with omitted initializer|"
+  "trailing array elements in runtime-sized array new}0">;
 def note_in_reference_temporary_list_initializer : Note<
   "in initialization of temporary of type %0 created to "
   "list-initialize this reference">;
@@ -4556,9 +4558,6 @@ def err_vm_func_decl : Error<
   "function declaration cannot have variably modified type">;
 def err_array_too_large : Error<
   "array is too large (%0 elements)">;
-def warn_array_new_too_large : Warning<"array is too large (%0 elements)">,
-  // FIXME PR11644: ", will throw std::bad_array_new_length at runtime"
-  InGroup<BadArrayNewLength>;
 
 // -Wpadded, -Wpacked
 def warn_padded_struct_field : Warning<
@@ -4576,9 +4575,6 @@ def warn_unnecessary_packed : Warning<
   "packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore;
 
 def err_typecheck_negative_array_size : Error<"array size is negative">;
-def warn_typecheck_negative_array_new_size : Warning<"array size is negative">,
-  // FIXME PR11644: ", will throw std::bad_array_new_length at runtime"
-  InGroup<BadArrayNewLength>;
 def warn_typecheck_function_qualifiers_ignored : Warning<
   "'%0' qualifier on function type %1 has no effect">,
   InGroup<IgnoredQualifiers>;

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Wed Oct  5 17:41:02 2016
@@ -395,6 +395,12 @@ public:
     return Base & 0x1;
   }
 
+  /// \brief Determine whether this is an array new with an unknown bound.
+  bool isVariableLengthArrayNew() const {
+    return getKind() == EK_New && dyn_cast_or_null<IncompleteArrayType>(
+                                      getType()->getAsArrayTypeUnsafe());
+  }
+
   /// \brief Determine the location of the 'return' keyword when initializing
   /// the result of a function call.
   SourceLocation getReturnLoc() const {

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Wed Oct  5 17:41:02 2016
@@ -877,8 +877,68 @@ void CodeGenFunction::EmitNewArrayInitia
   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::EmitNewArrayInitia
     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::EmitCXXNew
   // 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();
   }
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Oct  5 17:41:02 2016
@@ -1600,6 +1600,7 @@ Sema::BuildCXXNew(SourceRange Range, boo
   //   conversion function to integral or unscoped enumeration type exists.
   // C++1y [expr.new]p6: The expression [...] is implicitly converted to
   //   std::size_t.
+  llvm::Optional<uint64_t> KnownArraySize;
   if (ArraySize && !ArraySize->isTypeDependent()) {
     ExprResult ConvertedSize;
     if (getLangOpts().CPlusPlus14) {
@@ -1684,44 +1685,34 @@ Sema::BuildCXXNew(SourceRange Range, boo
     //   The expression in a direct-new-declarator shall have integral type
     //   with a non-negative value.
     //
-    // Let's see if this is a constant < 0. If so, we reject it out of
-    // hand. Otherwise, if it's not a constant, we must have an unparenthesized
-    // array type.
-    //
-    // Note: such a construct has well-defined semantics in C++11: it throws
-    // std::bad_array_new_length.
+    // Let's see if this is a constant < 0. If so, we reject it out of hand,
+    // per CWG1464. Otherwise, if it's not a constant, we must have an
+    // unparenthesized array type.
     if (!ArraySize->isValueDependent()) {
       llvm::APSInt Value;
       // We've already performed any required implicit conversion to integer or
       // unscoped enumeration type.
+      // FIXME: Per CWG1464, we are required to check the value prior to
+      // converting to size_t. This will never find a negative array size in
+      // C++14 onwards, because Value is always unsigned here!
       if (ArraySize->isIntegerConstantExpr(Value, Context)) {
-        if (Value < llvm::APSInt(
-                        llvm::APInt::getNullValue(Value.getBitWidth()),
-                                 Value.isUnsigned())) {
-          if (getLangOpts().CPlusPlus11)
-            Diag(ArraySize->getLocStart(),
-                 diag::warn_typecheck_negative_array_new_size)
-              << ArraySize->getSourceRange();
-          else
-            return ExprError(Diag(ArraySize->getLocStart(),
-                                  diag::err_typecheck_negative_array_size)
-                             << ArraySize->getSourceRange());
-        } else if (!AllocType->isDependentType()) {
+        if (Value.isSigned() && Value.isNegative()) {
+          return ExprError(Diag(ArraySize->getLocStart(),
+                                diag::err_typecheck_negative_array_size)
+                           << ArraySize->getSourceRange());
+        }
+
+        if (!AllocType->isDependentType()) {
           unsigned ActiveSizeBits =
             ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
-          if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
-            if (getLangOpts().CPlusPlus11)
-              Diag(ArraySize->getLocStart(),
-                   diag::warn_array_new_too_large)
-                << Value.toString(10)
-                << ArraySize->getSourceRange();
-            else
-              return ExprError(Diag(ArraySize->getLocStart(),
-                                    diag::err_array_too_large)
-                               << Value.toString(10)
-                               << ArraySize->getSourceRange());
-          }
+          if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
+            return ExprError(Diag(ArraySize->getLocStart(),
+                                  diag::err_array_too_large)
+                             << Value.toString(10)
+                             << ArraySize->getSourceRange());
         }
+
+        KnownArraySize = Value.getZExtValue();
       } else if (TypeIdParens.isValid()) {
         // Can't have dynamic array size when the type-id is in parentheses.
         Diag(ArraySize->getLocStart(), diag::ext_new_paren_array_nonconst)
@@ -1794,26 +1785,14 @@ Sema::BuildCXXNew(SourceRange Range, boo
     }
   }
 
-  QualType InitType = AllocType;
   // Array 'new' can't have any initializers except empty parentheses.
   // Initializer lists are also allowed, in C++11. Rely on the parser for the
   // dialect distinction.
-  if (ResultType->isArrayType() || ArraySize) {
-    if (!isLegalArrayNewInitializer(initStyle, Initializer)) {
-      SourceRange InitRange(Inits[0]->getLocStart(),
-                            Inits[NumInits - 1]->getLocEnd());
-      Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
-      return ExprError();
-    }
-    if (InitListExpr *ILE = dyn_cast_or_null<InitListExpr>(Initializer)) {
-      // We do the initialization typechecking against the array type
-      // corresponding to the number of initializers + 1 (to also check
-      // default-initialization).
-      unsigned NumElements = ILE->getNumInits() + 1;
-      InitType = Context.getConstantArrayType(AllocType,
-          llvm::APInt(Context.getTypeSize(Context.getSizeType()), NumElements),
-                                              ArrayType::Normal, 0);
-    }
+  if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) {
+    SourceRange InitRange(Inits[0]->getLocStart(),
+                          Inits[NumInits - 1]->getLocEnd());
+    Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
+    return ExprError();
   }
 
   // If we can perform the initialization, and we've not already done so,
@@ -1821,6 +1800,19 @@ Sema::BuildCXXNew(SourceRange Range, boo
   if (!AllocType->isDependentType() &&
       !Expr::hasAnyTypeDependentArguments(
           llvm::makeArrayRef(Inits, NumInits))) {
+    // The type we initialize is the complete type, including the array bound.
+    QualType InitType;
+    if (KnownArraySize)
+      InitType = Context.getConstantArrayType(
+          AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()),
+                                 *KnownArraySize),
+          ArrayType::Normal, 0);
+    else if (ArraySize)
+      InitType =
+          Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0);
+    else
+      InitType = AllocType;
+
     // C++11 [expr.new]p15:
     //   A new-expression that creates an object of type T initializes that
     //   object as follows:
@@ -1840,7 +1832,8 @@ Sema::BuildCXXNew(SourceRange Range, boo
 
     InitializedEntity Entity
       = InitializedEntity::InitializeNew(StartLoc, InitType);
-    InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits));
+    InitializationSequence InitSeq(*this, Entity, Kind,
+                                   MultiExprArg(Inits, NumInits));
     ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
                                           MultiExprArg(Inits, NumInits));
     if (FullInit.isInvalid())
@@ -1848,6 +1841,7 @@ Sema::BuildCXXNew(SourceRange Range, boo
 
     // FullInit is our initializer; strip off CXXBindTemporaryExprs, because
     // we don't want the initialized object to be destructed.
+    // FIXME: We should not create these in the first place.
     if (CXXBindTemporaryExpr *Binder =
             dyn_cast_or_null<CXXBindTemporaryExpr>(FullInit.get()))
       FullInit = Binder->getSubExpr();

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Oct  5 17:41:02 2016
@@ -469,9 +469,14 @@ ExprResult InitListChecker::PerformEmpty
         SemaRef.Diag(Entity.getDecl()->getLocation(),
                      diag::note_in_omitted_aggregate_initializer)
           << /*field*/1 << Entity.getDecl();
-      else if (Entity.getKind() == InitializedEntity::EK_ArrayElement)
+      else if (Entity.getKind() == InitializedEntity::EK_ArrayElement) {
+        bool IsTrailingArrayNewMember =
+            Entity.getParent() &&
+            Entity.getParent()->isVariableLengthArrayNew();
         SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer)
-          << /*array element*/0 << Entity.getElementIndex();
+          << (IsTrailingArrayNewMember ? 2 : /*array element*/0)
+          << Entity.getElementIndex();
+      }
     }
     return ExprError();
   }
@@ -685,8 +690,12 @@ InitListChecker::FillInEmptyInitializati
   unsigned NumElements = NumInits;
   if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) {
     ElementType = AType->getElementType();
-    if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType))
+    if (const auto *CAType = dyn_cast<ConstantArrayType>(AType))
       NumElements = CAType->getSize().getZExtValue();
+    // For an array new with an unknown bound, ask for one additional element
+    // in order to populate the array filler.
+    if (Entity.isVariableLengthArrayNew())
+      ++NumElements;
     ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context,
                                                          0, Entity);
   } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) {
@@ -1685,10 +1694,13 @@ void InitListChecker::CheckArrayType(con
                                                      ArrayType::Normal, 0);
   }
   if (!hadError && VerifyOnly) {
-    // Check if there are any members of the array that get value-initialized.
-    // If so, check if doing that is possible.
+    // If there are any members of the array that get value-initialized, check
+    // that is possible. That happens if we know the bound and don't have
+    // enough elements, or if we're performing an array new with an unknown
+    // bound.
     // FIXME: This needs to detect holes left by designated initializers too.
-    if (maxElementsKnown && elementIndex < maxElements)
+    if ((maxElementsKnown && elementIndex < maxElements) ||
+        Entity.isVariableLengthArrayNew())
       CheckEmptyInitializable(InitializedEntity::InitializeElement(
                                                   SemaRef.Context, 0, Entity),
                               IList->getLocEnd());

Modified: cfe/trunk/test/Analysis/cfg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cfg.cpp?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/cfg.cpp (original)
+++ cfe/trunk/test/Analysis/cfg.cpp Wed Oct  5 17:41:02 2016
@@ -138,7 +138,7 @@ void test_deletedtor() {
 // CHECK: [B1]
 // CHECK-NEXT:   1: 5
 // CHECK-NEXT:   2: CFGNewAllocator(A *)
-// CHECK-NEXT:   3:  (CXXConstructExpr, class A)
+// CHECK-NEXT:   3:  (CXXConstructExpr, class A [5])
 // CHECK-NEXT:   4: new A {{\[\[}}B1.1]]
 // CHECK-NEXT:   5: A *a = new A [5];
 // CHECK-NEXT:   6: a
@@ -363,7 +363,7 @@ void test_placement_new() {
 // CHECK-NEXT:  4: [B1.3] (ImplicitCastExpr, BitCast, void *)
 // CHECK-NEXT:  5: 5
 // CHECK-NEXT:  6: CFGNewAllocator(MyClass *)
-// CHECK-NEXT:  7:  (CXXConstructExpr, class MyClass)
+// CHECK-NEXT:  7:  (CXXConstructExpr, class MyClass [5])
 // CHECK-NEXT:  8: new ([B1.4]) MyClass {{\[\[}}B1.5]]
 // CHECK-NEXT:  9: MyClass *obj = new (buffer) MyClass [5];
 // CHECK-NEXT:  Preds (1): B2

Modified: cfe/trunk/test/CodeGenCXX/new-array-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/new-array-init.cpp?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/new-array-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/new-array-init.cpp Wed Oct  5 17:41:02 2016
@@ -1,5 +1,8 @@
 // RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
 
+// CHECK: @[[ABC4:.*]] = {{.*}} constant [4 x i8] c"abc\00"
+// CHECK: @[[ABC15:.*]] = {{.*}} constant [15 x i8] c"abc\00\00\00\00
+
 // CHECK-LABEL: define void @_Z2fni
 void fn(int n) {
   // CHECK: icmp ult i{{32|64}} %{{[^ ]+}}, 3
@@ -11,13 +14,6 @@ void fn(int n) {
   new int[n] { 1, 2, 3 };
 }
 
-// CHECK-LABEL: define void @_Z15const_underflowv
-void const_underflow() {
-  // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
-  // CHECK: call i8* @_Zna{{.}}(i{{32|64}} -1)
-  new int[2] { 1, 2, 3 };
-}
-
 // CHECK-LABEL: define void @_Z11const_exactv
 void const_exact() {
   // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3
@@ -46,3 +42,77 @@ void check_array_value_init() {
   // CHECK: icmp eq
   // CHECK: br i1
 }
+
+// CHECK-LABEL: define void @_Z15string_nonconsti
+void string_nonconst(int n) {
+  // CHECK: icmp slt i{{32|64}} %{{[^ ]+}}, 4
+  // FIXME: Conditionally throw an exception rather than passing -1 to alloc function
+  // CHECK: select
+  // CHECK: %[[PTR:.*]] = call i8* @_Zna{{.}}(i{{32|64}}
+  // CHECK: call void @llvm.memcpy{{.*}}(i8* %[[PTR]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[ABC4]], i32 0, i32 0), i32 4,
+  // CHECK: %[[REST:.*]] = getelementptr inbounds i8, i8* %[[PTR]], i32 4
+  // CHECK: %[[RESTSIZE:.*]] = sub {{.*}}, 4
+  // CHECK: call void @llvm.memset{{.*}}(i8* %[[REST]], i8 0, i{{32|64}} %[[RESTSIZE]],
+  new char[n] { "abc" };
+}
+
+// CHECK-LABEL: define void @_Z12string_exactv
+void string_exact() {
+  // CHECK-NOT: icmp
+  // CHECK: %[[PTR:.*]] = call i8* @_Zna{{.}}(i{{32|64}} 4)
+  // CHECK: call void @llvm.memcpy{{.*}}(i8* %[[PTR]], i8* getelementptr inbounds ([4 x i8], [4 x i8]* @[[ABC4]], i32 0, i32 0), i32 4,
+  // CHECK-NOT: memset
+  new char[4] { "abc" };
+}
+
+// CHECK-LABEL: define void @_Z17string_sufficientv
+void string_sufficient() {
+  // CHECK-NOT: icmp
+  // CHECK: %[[PTR:.*]] = call i8* @_Zna{{.}}(i{{32|64}} 15)
+  // FIXME: For very large arrays, it would be preferable to emit a small copy and a memset.
+  // CHECK: call void @llvm.memcpy{{.*}}(i8* %[[PTR]], i8* getelementptr inbounds ([15 x i8], [15 x i8]* @[[ABC15]], i32 0, i32 0), i32 15,
+  // CHECK-NOT: memset
+  new char[15] { "abc" };
+}
+
+// CHECK-LABEL: define void @_Z10aggr_exactv
+void aggr_exact() {
+  // CHECK-NOT: icmp
+  // CHECK: %[[MEM:.*]] = call i8* @_Zna{{.}}(i{{32|64}} 16)
+  // CHECK: %[[PTR0:.*]] = bitcast i8* %[[MEM]] to %[[AGGR:.*]]*
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR0]], i32 0, i32 0{{$}}
+  // CHECK: store i32 1, i32* %[[FIELD]]
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR0]], i32 0, i32 1{{$}}
+  // CHECK: store i32 2, i32* %[[FIELD]]
+  // CHECK: %[[PTR1:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR0]], i32 1{{$}}
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR1]], i32 0, i32 0{{$}}
+  // CHECK: store i32 3, i32* %[[FIELD]]
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR1]], i32 0, i32 1{{$}}
+  // CHECK: store i32 0, i32* %[[FIELD]]
+  // CHECK-NOT: store
+  // CHECK-NOT: memset
+  struct Aggr { int a, b; };
+  new Aggr[2] { 1, 2, 3 };
+}
+
+// CHECK-LABEL: define void @_Z15aggr_sufficienti
+void aggr_sufficient(int n) {
+  // CHECK: icmp ult i32 %{{.*}}, 2
+  // CHECK: %[[MEM:.*]] = call i8* @_Zna{{.}}(
+  // CHECK: %[[PTR0:.*]] = bitcast i8* %[[MEM]] to %[[AGGR:.*]]*
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR0]], i32 0, i32 0{{$}}
+  // CHECK: store i32 1, i32* %[[FIELD]]
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR0]], i32 0, i32 1{{$}}
+  // CHECK: store i32 2, i32* %[[FIELD]]
+  // CHECK: %[[PTR1:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR0]], i32 1{{$}}
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR1]], i32 0, i32 0{{$}}
+  // CHECK: store i32 3, i32* %[[FIELD]]
+  // CHECK: %[[FIELD:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR1]], i32 0, i32 1{{$}}
+  // CHECK: store i32 0, i32* %[[FIELD]]
+  // CHECK: %[[PTR2:.*]] = getelementptr inbounds %[[AGGR]], %[[AGGR]]* %[[PTR1]], i32 1{{$}}
+  // CHECK: %[[REMAIN:.*]] = sub i32 {{.*}}, 16
+  // CHECK: %[[MEM:.*]] = bitcast %[[AGGR]]* %[[PTR2]] to i8*
+  // CHECK: call void @llvm.memset{{.*}}(i8* %[[MEM]], i8 0, i32 %[[REMAIN]],
+  struct Aggr { int a, b; };
+  new Aggr[n] { 1, 2, 3 };
+}

Modified: cfe/trunk/test/SemaCXX/new-delete-cxx0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete-cxx0x.cpp?rev=283406&r1=283405&r2=283406&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete-cxx0x.cpp (original)
+++ cfe/trunk/test/SemaCXX/new-delete-cxx0x.cpp Wed Oct  5 17:41:02 2016
@@ -1,13 +1,19 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -triple=i686-pc-linux-gnu
 
 void ugly_news(int *ip) {
-  // These are ill-formed according to one reading of C++98, and at the least
-  // have undefined behavior.
-  // FIXME: They're ill-formed in C++11.
-  (void)new int[-1]; // expected-warning {{array size is negative}}
-  (void)new int[2000000000]; // expected-warning {{array is too large}}
+  (void)new int[-1]; // expected-error {{array size is negative}}
+  (void)new int[2000000000]; // expected-error {{array is too large}}
 }
 
+void pr22845a() {
+  constexpr int i = -1;
+  int *p = new int[i]; // expected-error {{array size is negative}}
+}
+
+void pr22845b() {
+  constexpr int i = 1;
+  int *p = new int[i]{1, 2}; // expected-error {{excess elements in array initializer}}
+}
 
 struct S {
   S(int);
@@ -15,13 +21,14 @@ struct S {
   ~S();
 };
 
-struct T { // expected-note 2 {{not viable}}
-  T(int); // expected-note {{not viable}}
+struct T { // expected-note 1+{{not viable}}
+  T(int); // expected-note 1+{{not viable}}
 };
 
-void fn() {
+void fn(int n) {
   (void) new int[2] {1, 2};
   (void) new S[2] {1, 2};
+  (void) new S[3] {1, 2};
   // C++11 [expr.new]p19:
   //   If the new-expression creates an object or an array of objects of class
   //   type, access and ambiguity control are done for the allocation function,
@@ -29,5 +36,28 @@ void fn() {
   //
   // Note that this happens even if the array bound is constant and the
   // initializer initializes every array element.
-  (void) new T[2] {1, 2}; // expected-error {{no matching constructor}} expected-note {{in implicit initialization of array element 2}}
+  //
+  // It's not clear that this is the intended interpretation, however -- we
+  // obviously don't want to check for a default constructor for 'new S(0)'.
+  // Instead, we only check for a default constructor in the case of an array
+  // new with a non-constant bound or insufficient initializers.
+  (void) new T[2] {1, 2}; // ok
+  (void) new T[3] {1, 2}; // expected-error {{no matching constructor}} expected-note {{in implicit initialization of array element 2}}
+  (void) new T[n] {1, 2}; // expected-error {{no matching constructor}} expected-note {{in implicit initialization of trailing array elements in runtime-sized array new}}
+}
+
+struct U {
+  T t; // expected-note 3{{in implicit initialization of field 't'}}
+  S s;
+};
+void g(int n) {
+  // Aggregate initialization, brace-elision, and array new combine to create
+  // this monstrosity.
+  (void) new U[2] {1, 2}; // expected-error {{no matching constructor}} expected-note {{in implicit initialization of array element 1}}
+  (void) new U[2] {1, 2, 3}; // ok
+  (void) new U[2] {1, 2, 3, 4}; // ok
+  (void) new U[2] {1, 2, 3, 4, 5}; // expected-error {{excess elements in array initializer}}
+
+  (void) new U[n] {1, 2}; // expected-error {{no matching constructor}} expected-note {{in implicit initialization of trailing array elements}}
+  (void) new U[n] {1, 2, 3}; // expected-error {{no matching constructor}} expected-note {{in implicit initialization of trailing array elements}}
 }




More information about the cfe-commits mailing list