From 5b0a110410710c5e5b3a197edced3676c92b6e89 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 6 May 2019 03:47:15 +0000 Subject: [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 --- lib/Sema/SemaExprCXX.cpp | 73 ++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 27 deletions(-) (limited to 'lib/Sema/SemaExprCXX.cpp') 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 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 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(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 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()) + (*ArraySize)->getType()->getAs()) // 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. -- cgit v1.2.3