aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-06 03:47:15 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-06 03:47:15 +0000
commit5b0a110410710c5e5b3a197edced3676c92b6e89 (patch)
tree8a3994ce841efa3aa2dfb291957cdd316053d3a1
parentf14f7e2753fb69cec95009f4f3b2e3eab14e4f10 (diff)
[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). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360006 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ExprCXX.h20
-rw-r--r--include/clang/AST/Stmt.h2
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--lib/AST/ASTImporter.cpp11
-rw-r--r--lib/AST/ExprCXX.cpp27
-rw-r--r--lib/AST/StmtPrinter.cpp5
-rw-r--r--lib/Analysis/CFG.cpp4
-rw-r--r--lib/CodeGen/CGExprCXX.cpp6
-rw-r--r--lib/Parse/ParseExprCXX.cpp11
-rw-r--r--lib/Sema/SemaExprCXX.cpp73
-rw-r--r--lib/Sema/TreeTransform.h21
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp4
-rw-r--r--test/CodeGenCXX/new-array-init.cpp22
-rw-r--r--test/PCH/cxx-exprs.cpp6
-rw-r--r--test/SemaCXX/new-delete.cpp24
-rw-r--r--tools/libclang/CIndex.cpp2
-rwxr-xr-xwww/cxx_status.html2
19 files changed, 170 insertions, 80 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 2d5a5b4386..05574c2312 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -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 {
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 72222cbc36..e50d5770bd 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -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);
}
};
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 57dff7993d..d973b48a17 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -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.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 84145c1d32..b94b5d3312 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6373,13 +6373,15 @@ def err_variably_modified_typeid : Error<"'typeid' of variably modified type %0"
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<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 2a737fedea..138f985ffc 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -5308,7 +5308,7 @@ public:
SourceRange TypeIdParens,
QualType AllocType,
TypeSourceInfo *AllocTypeInfo,
- Expr *ArraySize,
+ Optional<Expr *> ArraySize,
SourceRange DirectInitRange,
Expr *Initializer);
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 004c466c8d..1ab99bec38 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -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::VisitCXXNewExpr(CXXNewExpr *E) {
FunctionDecl *ToOperatorNew, *ToOperatorDelete;
SourceRange ToTypeIdParens, ToSourceRange, ToDirectInitRange;
- Expr *ToArraySize, *ToInitializer;
+ Optional<Expr *> ToArraySize;
+ Expr *ToInitializer;
QualType ToType;
TypeSourceInfo *ToAllocatedTypeSourceInfo;
std::tie(
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index b1ce167401..bbf7e044aa 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -97,7 +97,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
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, FunctionDecl *OperatorNew,
"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, FunctionDecl *OperatorNew,
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, bool IsGlobalNew,
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();
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 38eb344620..012bd4a898 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1976,10 +1976,11 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
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);
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index fdd845e980..0928fa2786 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -4339,8 +4339,8 @@ CFGBlock *CFGBuilder::VisitCXXNewExpr(CXXNewExpr *NE,
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)
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index b0078c22c8..25b0abbc03 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -681,9 +681,9 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
// 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(CodeGenFunction &CGF,
// 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();
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 87a6b4df8f..fbafb43688 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -2929,12 +2929,12 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
/// 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(Declarator &D) {
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();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 36e82d3900..881e0f6546 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1663,7 +1663,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
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 StartLoc, bool UseGlobal,
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, bool UseGlobal,
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, bool UseGlobal,
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, bool UseGlobal,
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, bool UseGlobal,
// 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, bool UseGlobal,
: 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, bool UseGlobal,
// 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, bool UseGlobal,
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, bool UseGlobal,
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, bool UseGlobal,
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.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index a8ea6b01d1..b1b2a911c2 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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>::TransformCXXNewExpr(CXXNewExpr *E) {
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>::TransformCXXNewExpr(CXXNewExpr *E) {
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>::TransformCXXNewExpr(CXXNewExpr *E) {
}
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>::TransformCXXNewExpr(CXXNewExpr *E) {
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>
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index f7ad8fac17..50d23422c8 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -984,7 +984,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(
}
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::addExtentSize(CheckerContext &C,
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.
diff --git a/test/CodeGenCXX/new-array-init.cpp b/test/CodeGenCXX/new-array-init.cpp
index 90cd600229..b504d5e780 100644
--- a/test/CodeGenCXX/new-array-init.cpp
+++ b/test/CodeGenCXX/new-array-init.cpp
@@ -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,
+}
diff --git a/test/PCH/cxx-exprs.cpp b/test/PCH/cxx-exprs.cpp
index b7707e0b93..e02bb0aa05 100644
--- a/test/PCH/cxx-exprs.cpp
+++ b/test/PCH/cxx-exprs.cpp
@@ -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
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index 870a5921d2..4db1206b6c 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -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
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index a5a8998f61..d7eee5e684 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -2479,7 +2479,7 @@ void EnqueueVisitor::VisitCXXNewExpr(const CXXNewExpr *E) {
// 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.
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 2a39009216..ad7f8ab13f 100755
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -110,7 +110,7 @@ with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++.
</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>