@@ -6691,7 +6691,9 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
66916691 if (Size && Size > Value.getArrayInitializedElts())
66926692 expandArray(Value, Value.getArraySize() - 1);
66936693
6694- for (; Size != 0; --Size) {
6694+ // The size of the array might have been reduced by
6695+ // a placement new.
6696+ for (Size = Value.getArraySize(); Size != 0; --Size) {
66956697 APValue &Elem = Value.getArrayInitializedElt(Size - 1);
66966698 if (!HandleLValueArrayAdjustment(Info, &LocE, ElemLV, ElemT, -1) ||
66976699 !HandleDestructionImpl(Info, CallRange, ElemLV, Elem, ElemT))
@@ -10003,23 +10005,14 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
1000310005 return false;
1000410006
1000510007 FunctionDecl *OperatorNew = E->getOperatorNew();
10008+ QualType AllocType = E->getAllocatedType();
10009+ QualType TargetType = AllocType;
1000610010
1000710011 bool IsNothrow = false;
1000810012 bool IsPlacement = false;
10009- if (OperatorNew->isReservedGlobalPlacementOperator() &&
10010- Info.CurrentCall->isStdFunction() && !E->isArray()) {
10011- // FIXME Support array placement new.
10012- assert(E->getNumPlacementArgs() == 1);
10013- if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
10014- return false;
10015- if (Result.Designator.Invalid)
10016- return false;
10017- IsPlacement = true;
10018- } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
10019- Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
10020- << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
10021- return false;
10022- } else if (E->getNumPlacementArgs()) {
10013+
10014+ if (E->getNumPlacementArgs() == 1 &&
10015+ E->getPlacementArg(0)->getType()->isNothrowT()) {
1002310016 // The only new-placement list we support is of the form (std::nothrow).
1002410017 //
1002510018 // FIXME: There is no restriction on this, but it's not clear that any
@@ -10030,22 +10023,38 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
1003010023 // (which should presumably be valid only if N is a multiple of
1003110024 // alignof(int), and in any case can't be deallocated unless N is
1003210025 // alignof(X) and X has new-extended alignment).
10033- if (E->getNumPlacementArgs() != 1 ||
10034- !E->getPlacementArg(0)->getType()->isNothrowT())
10035- return Error(E, diag::note_constexpr_new_placement);
10036-
1003710026 LValue Nothrow;
1003810027 if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
1003910028 return false;
1004010029 IsNothrow = true;
10030+ } else if (OperatorNew->isReservedGlobalPlacementOperator()) {
10031+ if (Info.CurrentCall->isStdFunction() || Info.getLangOpts().CPlusPlus26) {
10032+ if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
10033+ return false;
10034+ if (Result.Designator.Invalid)
10035+ return false;
10036+ TargetType = E->getPlacementArg(0)->getType();
10037+ IsPlacement = true;
10038+ } else {
10039+ Info.FFDiag(E, diag::note_constexpr_new_placement)
10040+ << /*C++26 feature*/ 1 << E->getSourceRange();
10041+ return false;
10042+ }
10043+ } else if (E->getNumPlacementArgs()) {
10044+ Info.FFDiag(E, diag::note_constexpr_new_placement)
10045+ << /*Unsupported*/ 0 << E->getSourceRange();
10046+ return false;
10047+ } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
10048+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
10049+ << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
10050+ return false;
1004110051 }
1004210052
1004310053 const Expr *Init = E->getInitializer();
1004410054 const InitListExpr *ResizedArrayILE = nullptr;
1004510055 const CXXConstructExpr *ResizedArrayCCE = nullptr;
1004610056 bool ValueInit = false;
1004710057
10048- QualType AllocType = E->getAllocatedType();
1004910058 if (std::optional<const Expr *> ArraySize = E->getArraySize()) {
1005010059 const Expr *Stripped = *ArraySize;
1005110060 for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
@@ -10139,9 +10148,17 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
1013910148 bool found(APValue &Subobj, QualType SubobjType) {
1014010149 // FIXME: Reject the cases where [basic.life]p8 would not permit the
1014110150 // old name of the object to be used to name the new object.
10142- if (!Info.Ctx.hasSameUnqualifiedType(SubobjType, AllocType)) {
10143- Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type) <<
10144- SubobjType << AllocType;
10151+ unsigned SubobjectSize = 1;
10152+ unsigned AllocSize = 1;
10153+ if (auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
10154+ AllocSize = CAT->getZExtSize();
10155+ if (auto *CAT = dyn_cast<ConstantArrayType>(SubobjType))
10156+ SubobjectSize = CAT->getZExtSize();
10157+ if (SubobjectSize < AllocSize ||
10158+ !Info.Ctx.hasSimilarType(Info.Ctx.getBaseElementType(SubobjType),
10159+ Info.Ctx.getBaseElementType(AllocType))) {
10160+ Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type)
10161+ << SubobjType << AllocType;
1014510162 return false;
1014610163 }
1014710164 Value = &Subobj;
0 commit comments