r360006 - [c++20] Implement P1009R2: allow omitting the array bound in an array

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sun May 5 20:47:15 PDT 2019


Author: rsmith
Date: Sun May  5 20:47:15 2019
New Revision: 360006

URL: http://llvm.org/viewvc/llvm-project?rev=360006&view=rev
Log:
[c++20] Implement P1009R2: allow omitting the array bound in an array
new expression.

This was voted into C++20 as a defect report resolution, so we
retroactively apply it to all prior language modes (though it can never
actually be used before C++11 mode).

Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/Stmt.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/Analysis/CFG.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/test/CodeGenCXX/new-array-init.cpp
    cfe/trunk/test/PCH/cxx-exprs.cpp
    cfe/trunk/test/SemaCXX/new-delete.cpp
    cfe/trunk/tools/libclang/CIndex.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Sun May  5 20:47:15 2019
@@ -2058,7 +2058,7 @@ private:
   CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
              FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
              bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs,
-             SourceRange TypeIdParens, Expr *ArraySize,
+             SourceRange TypeIdParens, Optional<Expr *> ArraySize,
              InitializationStyle InitializationStyle, Expr *Initializer,
              QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
              SourceRange DirectInitRange);
@@ -2073,7 +2073,7 @@ public:
   Create(const ASTContext &Ctx, bool IsGlobalNew, FunctionDecl *OperatorNew,
          FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
          bool UsualArrayDeleteWantsSize, ArrayRef<Expr *> PlacementArgs,
-         SourceRange TypeIdParens, Expr *ArraySize,
+         SourceRange TypeIdParens, Optional<Expr *> ArraySize,
          InitializationStyle InitializationStyle, Expr *Initializer,
          QualType Ty, TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
          SourceRange DirectInitRange);
@@ -2116,15 +2116,15 @@ public:
 
   bool isArray() const { return CXXNewExprBits.IsArray; }
 
-  Expr *getArraySize() {
-    return isArray()
-               ? cast<Expr>(getTrailingObjects<Stmt *>()[arraySizeOffset()])
-               : nullptr;
+  Optional<Expr *> getArraySize() {
+    if (!isArray())
+      return None;
+    return cast_or_null<Expr>(getTrailingObjects<Stmt *>()[arraySizeOffset()]);
   }
-  const Expr *getArraySize() const {
-    return isArray()
-               ? cast<Expr>(getTrailingObjects<Stmt *>()[arraySizeOffset()])
-               : nullptr;
+  Optional<const Expr *> getArraySize() const {
+    if (!isArray())
+      return None;
+    return cast_or_null<Expr>(getTrailingObjects<Stmt *>()[arraySizeOffset()]);
   }
 
   unsigned getNumPlacementArgs() const {

Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Sun May  5 20:47:15 2019
@@ -1008,7 +1008,7 @@ protected:
     CastIterator(StmtPtr *I) : Base(I) {}
 
     typename Base::value_type operator*() const {
-      return cast<T>(*this->I);
+      return cast_or_null<T>(*this->I);
     }
   };
 

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Sun May  5 20:47:15 2019
@@ -6413,8 +6413,8 @@ AST_MATCHER(CXXNewExpr, isArray) {
 /// cxxNewExpr(hasArraySize(intgerLiteral(equals(10))))
 ///   matches the expression 'new MyClass[10]'.
 AST_MATCHER_P(CXXNewExpr, hasArraySize, internal::Matcher<Expr>, InnerMatcher) {
-  return Node.isArray() &&
-    InnerMatcher.matches(*Node.getArraySize(), Finder, Builder);
+  return Node.isArray() && *Node.getArraySize() &&
+         InnerMatcher.matches(**Node.getArraySize(), Finder, Builder);
 }
 
 /// Matches a class declaration that is defined.

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun May  5 20:47:15 2019
@@ -6373,13 +6373,15 @@ def err_variably_modified_typeid : Error
 def err_static_illegal_in_new : Error<
   "the 'static' modifier for the array size is not legal in new expressions">;
 def err_array_new_needs_size : Error<
-  "array size must be specified in new expressions">;
+  "array size must be specified in new expression with no initializer">;
 def err_bad_new_type : Error<
   "cannot allocate %select{function|reference}1 type %0 with new">;
 def err_new_incomplete_type : Error<
   "allocation of incomplete type %0">;
 def err_new_array_nonconst : Error<
   "only the first dimension of an allocated array may have dynamic size">;
+def err_new_array_size_unknown_from_init : Error<
+  "cannot determine allocated array size from initializer">;
 def err_new_array_init_args : Error<
   "array 'new' cannot have initialization arguments">;
 def ext_new_paren_array_nonconst : ExtWarn<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sun May  5 20:47:15 2019
@@ -5308,7 +5308,7 @@ public:
                          SourceRange TypeIdParens,
                          QualType AllocType,
                          TypeSourceInfo *AllocTypeInfo,
-                         Expr *ArraySize,
+                         Optional<Expr *> ArraySize,
                          SourceRange DirectInitRange,
                          Expr *Initializer);
 

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Sun May  5 20:47:15 2019
@@ -175,6 +175,14 @@ namespace clang {
       return Importer.Import_New(From);
     }
 
+    // Import an Optional<T> by importing the contained T, if any.
+    template<typename T>
+    Expected<Optional<T>> import(Optional<T> From) {
+      if (!From)
+        return Optional<T>();
+      return import(*From);
+    }
+
     template <class T>
     Expected<std::tuple<T>>
     importSeq(const T &From) {
@@ -6896,7 +6904,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXNe
 
   FunctionDecl *ToOperatorNew, *ToOperatorDelete;
   SourceRange ToTypeIdParens, ToSourceRange, ToDirectInitRange;
-  Expr *ToArraySize, *ToInitializer;
+  Optional<Expr *> ToArraySize;
+  Expr *ToInitializer;
   QualType ToType;
   TypeSourceInfo *ToAllocatedTypeSourceInfo;
   std::tie(

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Sun May  5 20:47:15 2019
@@ -97,7 +97,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew,
                        FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
                        bool UsualArrayDeleteWantsSize,
                        ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
-                       Expr *ArraySize, InitializationStyle InitializationStyle,
+                       Optional<Expr *> ArraySize,
+                       InitializationStyle InitializationStyle,
                        Expr *Initializer, QualType Ty,
                        TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
                        SourceRange DirectInitRange)
@@ -112,7 +113,7 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew,
          "Only NoInit can have no initializer!");
 
   CXXNewExprBits.IsGlobalNew = IsGlobalNew;
-  CXXNewExprBits.IsArray = ArraySize != nullptr;
+  CXXNewExprBits.IsArray = ArraySize.hasValue();
   CXXNewExprBits.ShouldPassAlignment = ShouldPassAlignment;
   CXXNewExprBits.UsualArrayDeleteWantsSize = UsualArrayDeleteWantsSize;
   CXXNewExprBits.StoredInitializationStyle =
@@ -122,12 +123,14 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew,
   CXXNewExprBits.NumPlacementArgs = PlacementArgs.size();
 
   if (ArraySize) {
-    if (ArraySize->isInstantiationDependent())
-      ExprBits.InstantiationDependent = true;
-    if (ArraySize->containsUnexpandedParameterPack())
-      ExprBits.ContainsUnexpandedParameterPack = true;
+    if (Expr *SizeExpr = *ArraySize) {
+      if (SizeExpr->isInstantiationDependent())
+        ExprBits.InstantiationDependent = true;
+      if (SizeExpr->containsUnexpandedParameterPack())
+        ExprBits.ContainsUnexpandedParameterPack = true;
+    }
 
-    getTrailingObjects<Stmt *>()[arraySizeOffset()] = ArraySize;
+    getTrailingObjects<Stmt *>()[arraySizeOffset()] = *ArraySize;
   }
 
   if (Initializer) {
@@ -179,11 +182,11 @@ CXXNewExpr::Create(const ASTContext &Ctx
                    FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete,
                    bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize,
                    ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
-                   Expr *ArraySize, InitializationStyle InitializationStyle,
-                   Expr *Initializer, QualType Ty,
-                   TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
-                   SourceRange DirectInitRange) {
-  bool IsArray = ArraySize != nullptr;
+                   Optional<Expr *> ArraySize,
+                   InitializationStyle InitializationStyle, Expr *Initializer,
+                   QualType Ty, TypeSourceInfo *AllocatedTypeInfo,
+                   SourceRange Range, SourceRange DirectInitRange) {
+  bool IsArray = ArraySize.hasValue();
   bool HasInit = Initializer != nullptr;
   unsigned NumPlacementArgs = PlacementArgs.size();
   bool IsParenTypeId = TypeIdParens.isValid();

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Sun May  5 20:47:15 2019
@@ -1976,10 +1976,11 @@ void StmtPrinter::VisitCXXNewExpr(CXXNew
   if (E->isParenTypeId())
     OS << "(";
   std::string TypeS;
-  if (Expr *Size = E->getArraySize()) {
+  if (Optional<Expr *> Size = E->getArraySize()) {
     llvm::raw_string_ostream s(TypeS);
     s << '[';
-    Size->printPretty(s, Helper, Policy);
+    if (*Size)
+      (*Size)->printPretty(s, Helper, Policy);
     s << ']';
   }
   E->getAllocatedType().print(OS, Policy, TypeS);

Modified: cfe/trunk/lib/Analysis/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Sun May  5 20:47:15 2019
@@ -4339,8 +4339,8 @@ CFGBlock *CFGBuilder::VisitCXXNewExpr(CX
   if (BuildOpts.AddCXXNewAllocator)
     appendNewAllocator(Block, NE);
 
-  if (NE->isArray())
-    Block = Visit(NE->getArraySize());
+  if (NE->isArray() && *NE->getArraySize())
+    Block = Visit(*NE->getArraySize());
 
   for (CXXNewExpr::arg_iterator I = NE->placement_arg_begin(),
        E = NE->placement_arg_end(); I != E; ++I)

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Sun May  5 20:47:15 2019
@@ -681,9 +681,9 @@ static llvm::Value *EmitCXXNewAllocSize(
   // We multiply the size of all dimensions for NumElements.
   // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
   numElements =
-    ConstantEmitter(CGF).tryEmitAbstract(e->getArraySize(), e->getType());
+    ConstantEmitter(CGF).tryEmitAbstract(*e->getArraySize(), e->getType());
   if (!numElements)
-    numElements = CGF.EmitScalarExpr(e->getArraySize());
+    numElements = CGF.EmitScalarExpr(*e->getArraySize());
   assert(isa<llvm::IntegerType>(numElements->getType()));
 
   // The number of elements can be have an arbitrary integer type;
@@ -693,7 +693,7 @@ static llvm::Value *EmitCXXNewAllocSize(
   // important way: if the count is negative, it's an error even if
   // the cookie size would bring the total size >= 0.
   bool isSigned
-    = e->getArraySize()->getType()->isSignedIntegerOrEnumerationType();
+    = (*e->getArraySize())->getType()->isSignedIntegerOrEnumerationType();
   llvm::IntegerType *numElementsType
     = cast<llvm::IntegerType>(numElements->getType());
   unsigned numElementsWidth = numElementsType->getBitWidth();

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Sun May  5 20:47:15 2019
@@ -2929,12 +2929,12 @@ Parser::ParseCXXNewExpression(bool UseGl
 /// passed to ParseDeclaratorInternal.
 ///
 ///        direct-new-declarator:
-///                   '[' expression ']'
+///                   '[' expression[opt] ']'
 ///                   direct-new-declarator '[' constant-expression ']'
 ///
 void Parser::ParseDirectNewDeclarator(Declarator &D) {
   // Parse the array dimensions.
-  bool first = true;
+  bool First = true;
   while (Tok.is(tok::l_square)) {
     // An array-size expression can't start with a lambda.
     if (CheckProhibitedCXX11Attribute())
@@ -2943,14 +2943,15 @@ void Parser::ParseDirectNewDeclarator(De
     BalancedDelimiterTracker T(*this, tok::l_square);
     T.consumeOpen();
 
-    ExprResult Size(first ? ParseExpression()
-                                : ParseConstantExpression());
+    ExprResult Size =
+        First ? (Tok.is(tok::r_square) ? ExprResult() : ParseExpression())
+              : ParseConstantExpression();
     if (Size.isInvalid()) {
       // Recover
       SkipUntil(tok::r_square, StopAtSemi);
       return;
     }
-    first = false;
+    First = false;
 
     T.consumeClose();
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun May  5 20:47:15 2019
@@ -1663,7 +1663,7 @@ Sema::ActOnCXXNew(SourceLocation StartLo
                   SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
                   SourceLocation PlacementRParen, SourceRange TypeIdParens,
                   Declarator &D, Expr *Initializer) {
-  Expr *ArraySize = nullptr;
+  Optional<Expr *> ArraySize;
   // If the specified type is an array, unwrap it and save the expression.
   if (D.getNumTypeObjects() > 0 &&
       D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
@@ -1674,7 +1674,7 @@ Sema::ActOnCXXNew(SourceLocation StartLo
     if (Chunk.Arr.hasStatic)
       return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new)
         << D.getSourceRange());
-    if (!Chunk.Arr.NumElts)
+    if (!Chunk.Arr.NumElts && !Initializer)
       return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size)
         << D.getSourceRange());
 
@@ -1787,7 +1787,7 @@ Sema::BuildCXXNew(SourceRange Range, boo
                   SourceRange TypeIdParens,
                   QualType AllocType,
                   TypeSourceInfo *AllocTypeInfo,
-                  Expr *ArraySize,
+                  Optional<Expr *> ArraySize,
                   SourceRange DirectInitRange,
                   Expr *Initializer) {
   SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
@@ -1838,9 +1838,11 @@ Sema::BuildCXXNew(SourceRange Range, boo
   auto *Deduced = AllocType->getContainedDeducedType();
   if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
     if (ArraySize)
-      return ExprError(Diag(ArraySize->getExprLoc(),
-                            diag::err_deduced_class_template_compound_type)
-                       << /*array*/ 2 << ArraySize->getSourceRange());
+      return ExprError(
+          Diag(ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(),
+               diag::err_deduced_class_template_compound_type)
+          << /*array*/ 2
+          << (ArraySize ? (*ArraySize)->getSourceRange() : TypeRange));
 
     InitializedEntity Entity
       = InitializedEntity::InitializeNew(StartLoc, AllocType);
@@ -1906,8 +1908,9 @@ Sema::BuildCXXNew(SourceRange Range, boo
 
   QualType ResultType = Context.getPointerType(AllocType);
 
-  if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) {
-    ExprResult result = CheckPlaceholderExpr(ArraySize);
+  if (ArraySize && *ArraySize &&
+      (*ArraySize)->getType()->isNonOverloadPlaceholderType()) {
+    ExprResult result = CheckPlaceholderExpr(*ArraySize);
     if (result.isInvalid()) return ExprError();
     ArraySize = result.get();
   }
@@ -1919,19 +1922,19 @@ Sema::BuildCXXNew(SourceRange Range, boo
   // C++1y [expr.new]p6: The expression [...] is implicitly converted to
   //   std::size_t.
   llvm::Optional<uint64_t> KnownArraySize;
-  if (ArraySize && !ArraySize->isTypeDependent()) {
+  if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) {
     ExprResult ConvertedSize;
     if (getLangOpts().CPlusPlus14) {
       assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?");
 
-      ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(),
+      ConvertedSize = PerformImplicitConversion(*ArraySize, Context.getSizeType(),
                                                 AA_Converting);
 
       if (!ConvertedSize.isInvalid() &&
-          ArraySize->getType()->getAs<RecordType>())
+          (*ArraySize)->getType()->getAs<RecordType>())
         // Diagnose the compatibility of this conversion.
         Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion)
-          << ArraySize->getType() << 0 << "'size_t'";
+          << (*ArraySize)->getType() << 0 << "'size_t'";
     } else {
       class SizeConvertDiagnoser : public ICEConvertDiagnoser {
       protected:
@@ -1985,16 +1988,16 @@ Sema::BuildCXXNew(SourceRange Range, boo
                           : diag::ext_array_size_conversion)
                    << T << ConvTy->isEnumeralType() << ConvTy;
         }
-      } SizeDiagnoser(ArraySize);
+      } SizeDiagnoser(*ArraySize);
 
-      ConvertedSize = PerformContextualImplicitConversion(StartLoc, ArraySize,
+      ConvertedSize = PerformContextualImplicitConversion(StartLoc, *ArraySize,
                                                           SizeDiagnoser);
     }
     if (ConvertedSize.isInvalid())
       return ExprError();
 
     ArraySize = ConvertedSize.get();
-    QualType SizeType = ArraySize->getType();
+    QualType SizeType = (*ArraySize)->getType();
 
     if (!SizeType->isIntegralOrUnscopedEnumerationType())
       return ExprError();
@@ -2006,18 +2009,18 @@ Sema::BuildCXXNew(SourceRange Range, boo
     // 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()) {
+    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 ((*ArraySize)->isIntegerConstantExpr(Value, Context)) {
         if (Value.isSigned() && Value.isNegative()) {
-          return ExprError(Diag(ArraySize->getBeginLoc(),
+          return ExprError(Diag((*ArraySize)->getBeginLoc(),
                                 diag::err_typecheck_negative_array_size)
-                           << ArraySize->getSourceRange());
+                           << (*ArraySize)->getSourceRange());
         }
 
         if (!AllocType->isDependentType()) {
@@ -2025,15 +2028,15 @@ Sema::BuildCXXNew(SourceRange Range, boo
             ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
           if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context))
             return ExprError(
-                Diag(ArraySize->getBeginLoc(), diag::err_array_too_large)
-                << Value.toString(10) << ArraySize->getSourceRange());
+                Diag((*ArraySize)->getBeginLoc(), 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->getBeginLoc(), diag::ext_new_paren_array_nonconst)
-            << ArraySize->getSourceRange()
+        Diag((*ArraySize)->getBeginLoc(), diag::ext_new_paren_array_nonconst)
+            << (*ArraySize)->getSourceRange()
             << FixItHint::CreateRemoval(TypeIdParens.getBegin())
             << FixItHint::CreateRemoval(TypeIdParens.getEnd());
 
@@ -2056,10 +2059,10 @@ Sema::BuildCXXNew(SourceRange Range, boo
   AllocationFunctionScope Scope = UseGlobal ? AFS_Global : AFS_Both;
   if (!AllocType->isDependentType() &&
       !Expr::hasAnyTypeDependentArguments(PlacementArgs) &&
-      FindAllocationFunctions(StartLoc,
-                              SourceRange(PlacementLParen, PlacementRParen),
-                              Scope, Scope, AllocType, ArraySize, PassAlignment,
-                              PlacementArgs, OperatorNew, OperatorDelete))
+      FindAllocationFunctions(
+          StartLoc, SourceRange(PlacementLParen, PlacementRParen), Scope, Scope,
+          AllocType, ArraySize.hasValue(), PassAlignment, PlacementArgs,
+          OperatorNew, OperatorDelete))
     return ExprError();
 
   // If this is an array allocation, compute whether the usual array
@@ -2152,6 +2155,22 @@ Sema::BuildCXXNew(SourceRange Range, boo
       FullInit = Binder->getSubExpr();
 
     Initializer = FullInit.get();
+
+    // FIXME: If we have a KnownArraySize, check that the array bound of the
+    // initializer is no greater than that constant value.
+
+    if (ArraySize && !*ArraySize) {
+      auto *CAT = Context.getAsConstantArrayType(Initializer->getType());
+      if (CAT) {
+        // FIXME: Track that the array size was inferred rather than explicitly
+        // specified.
+        ArraySize = IntegerLiteral::Create(
+            Context, CAT->getSize(), Context.getSizeType(), TypeRange.getEnd());
+      } else {
+        Diag(TypeRange.getEnd(), diag::err_new_array_size_unknown_from_init)
+            << Initializer->getSourceRange();
+      }
+    }
   }
 
   // Mark the new and delete operators as referenced.

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Sun May  5 20:47:15 2019
@@ -2745,7 +2745,7 @@ public:
                                SourceRange TypeIdParens,
                                QualType AllocatedType,
                                TypeSourceInfo *AllocatedTypeInfo,
-                               Expr *ArraySize,
+                               Optional<Expr *> ArraySize,
                                SourceRange DirectInitRange,
                                Expr *Initializer) {
     return getSema().BuildCXXNew(StartLoc, UseGlobal,
@@ -10378,9 +10378,16 @@ TreeTransform<Derived>::TransformCXXNewE
     return ExprError();
 
   // Transform the size of the array we're allocating (if any).
-  ExprResult ArraySize = getDerived().TransformExpr(E->getArraySize());
-  if (ArraySize.isInvalid())
-    return ExprError();
+  Optional<Expr *> ArraySize;
+  if (Optional<Expr *> OldArraySize = E->getArraySize()) {
+    ExprResult NewArraySize;
+    if (*OldArraySize) {
+      NewArraySize = getDerived().TransformExpr(*OldArraySize);
+      if (NewArraySize.isInvalid())
+        return ExprError();
+    }
+    ArraySize = NewArraySize.get();
+  }
 
   // Transform the placement arguments (if any).
   bool ArgumentChanged = false;
@@ -10417,7 +10424,7 @@ TreeTransform<Derived>::TransformCXXNewE
 
   if (!getDerived().AlwaysRebuild() &&
       AllocTypeInfo == E->getAllocatedTypeSourceInfo() &&
-      ArraySize.get() == E->getArraySize() &&
+      ArraySize == E->getArraySize() &&
       NewInit.get() == OldInit &&
       OperatorNew == E->getOperatorNew() &&
       OperatorDelete == E->getOperatorDelete() &&
@@ -10444,7 +10451,7 @@ TreeTransform<Derived>::TransformCXXNewE
   }
 
   QualType AllocType = AllocTypeInfo->getType();
-  if (!ArraySize.get()) {
+  if (!ArraySize) {
     // If no array size was specified, but the new expression was
     // instantiated with an array type (e.g., "new T" where T is
     // instantiated with "int[4]"), extract the outer bound from the
@@ -10472,7 +10479,7 @@ TreeTransform<Derived>::TransformCXXNewE
       E->getBeginLoc(), E->isGlobalNew(),
       /*FIXME:*/ E->getBeginLoc(), PlacementArgs,
       /*FIXME:*/ E->getBeginLoc(), E->getTypeIdParens(), AllocType,
-      AllocTypeInfo, ArraySize.get(), E->getDirectInitRange(), NewInit.get());
+      AllocTypeInfo, ArraySize, E->getDirectInitRange(), NewInit.get());
 }
 
 template<typename Derived>

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Sun May  5 20:47:15 2019
@@ -984,7 +984,7 @@ ProgramStateRef MallocChecker::ProcessZe
   }
   else if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
     if (NE->isArray())
-      Arg = NE->getArraySize();
+      Arg = *NE->getArraySize();
     else
       return State;
   }
@@ -1116,7 +1116,7 @@ ProgramStateRef MallocChecker::addExtent
   SVal ElementCount;
   const SubRegion *Region;
   if (NE->isArray()) {
-    const Expr *SizeExpr = NE->getArraySize();
+    const Expr *SizeExpr = *NE->getArraySize();
     ElementCount = C.getSVal(SizeExpr);
     // Store the extent size for the (symbolic)region
     // containing the elements.

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=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/new-array-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/new-array-init.cpp Sun May  5 20:47:15 2019
@@ -123,3 +123,25 @@ void constexpr_test() {
   // SIO: call i8* @_Zna{{.}}(i32 4)
   new int[0+1]{0};
 }
+
+// CHECK-LABEL: define void @_Z13unknown_boundv
+void unknown_bound() {
+  struct Aggr { int x, y, z; };
+  new Aggr[]{1, 2, 3, 4};
+  // CHECK: call {{.*}}_Znaj(i32 24)
+  // CHECK: store i32 1
+  // CHECK: store i32 2
+  // CHECK: store i32 3
+  // CHECK: store i32 4
+  // CHECK: store i32 0
+  // CHECK: store i32 0
+  // CHECK-NOT: store
+  // CHECK: }
+}
+
+// CHECK-LABEL: define void @_Z20unknown_bound_stringv
+void unknown_bound_string() {
+  new char[]{"hello"};
+  // CHECK: call {{.*}}_Znaj(i32 6)
+  // CHECK: memcpy{{.*}} i32 6,
+}

Modified: cfe/trunk/test/PCH/cxx-exprs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-exprs.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx-exprs.cpp (original)
+++ cfe/trunk/test/PCH/cxx-exprs.cpp Sun May  5 20:47:15 2019
@@ -20,10 +20,16 @@ public:
   }
 };
 
+template<typename ...T> int *arr_new(T ...v) {
+  return new int[]{v...};
+}
+
 #else
 
 New<int> *clone_new(New<int> *n) {
   return n->clone();
 }
 
+int *use_arr_new = arr_new(1, 2, 3);
+
 #endif

Modified: cfe/trunk/test/SemaCXX/new-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/new-delete.cpp Sun May  5 20:47:15 2019
@@ -65,6 +65,12 @@ void good_news()
   typedef foo x[2];
   typedef foo y[2][2];
   x* f3 = new y;
+
+#if __cplusplus >= 201103L
+  (void)new int[]{};
+  (void)new int[]{1, 2, 3};
+  (void)new char[]{"hello"};
+#endif
 }
 
 struct abstract {
@@ -126,9 +132,14 @@ void bad_news(int *ip)
   (void)::new ((S*)0) U; // expected-error {{no matching function for call to 'operator new'}}
   // This must fail, because any member version hides all global versions.
   (void)new U; // expected-error {{no matching function for call to 'operator new'}}
-  (void)new (int[]); // expected-error {{array size must be specified in new expressions}}
+  (void)new (int[]); // expected-error {{array size must be specified in new expression with no initializer}}
   (void)new int&; // expected-error {{cannot allocate reference type 'int &' with new}}
-  // Some lacking cases due to lack of sema support.
+  (void)new int[]; // expected-error {{array size must be specified in new expression with no initializer}}
+  (void)new int[](); // expected-error {{cannot determine allocated array size from initializer}}
+  // FIXME: This is a terrible diagnostic.
+#if __cplusplus < 201103L
+  (void)new int[]{}; // expected-error {{array size must be specified in new expression with no initializer}}
+#endif
 }
 
 void good_deletes()
@@ -601,3 +612,12 @@ struct A {
   void g() { this->::delete; } // expected-error {{expected unqualified-id}}
 };
 }
+
+#if __cplusplus >= 201103L
+template<typename ...T> int *dependent_array_size(T ...v) {
+  return new int[]{v...}; // expected-error {{cannot initialize}}
+}
+int *p0 = dependent_array_size();
+int *p3 = dependent_array_size(1, 2, 3);
+int *fail = dependent_array_size("hello"); // expected-note {{instantiation of}}
+#endif

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Sun May  5 20:47:15 2019
@@ -2479,7 +2479,7 @@ void EnqueueVisitor::VisitCXXNewExpr(con
   // Enqueue the initializer , if any.
   AddStmt(E->getInitializer());
   // Enqueue the array size, if any.
-  AddStmt(E->getArraySize());
+  AddStmt(E->getArraySize().getValueOr(nullptr));
   // Enqueue the allocated type.
   AddTypeLoc(E->getAllocatedTypeSourceInfo());
   // Enqueue the placement arguments.

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=360006&r1=360005&r2=360006&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Sun May  5 20:47:15 2019
@@ -110,7 +110,7 @@ with <a href="http://libcxx.llvm.org/">l
     </tr>
       <tr> <!-- from Kona 2019-->
         <td><a href="http://wg21.link/p1009r2">P1009R2</a> (<a href="#dr">DR</a>)</td>
-        <td class="none" align="center">No</td>
+        <td class="svn" align="center">SVN</td>
       </tr>
     <tr>
       <td>Static assertions</td>




More information about the cfe-commits mailing list