https://github.com/igorkudrin updated 
https://github.com/llvm/llvm-project/pull/203824

>From 264ac339bd54d172fc1f3e9e469ef3d241b717d4 Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Sat, 13 Jun 2026 20:18:30 -0700
Subject: [PATCH 1/3] [Clang][Sema][NFCI] Simplify
 `resolveAllocationOverload()`

`resolveAllocationOverload()` performs multiple rounds of overload
resolution (typed and untyped, aligned and unaligned), each requiring a
slightly different argument list. Previously, the argument vector was
mutated in-place, which made the flow hard to follow.

This refactor prepares the list of arguments before calling
`resolveAllocationOverload()`. The preferred argument list is passed in
`PrefArgs`, while the fallback arguments are passed in `FallbackArgs`.
If the fallback resolution is not required, `FallbackArgs` is empty.
When making a nested call to perform the resolution with the fallback
arguments, the current set of candidates is passed in `PrefCandidates`
(formerly, `AlignedCandidates`). This argument also serves as a flag
used to distinguish the top-level call from nested fallback calls.
---
 clang/lib/Sema/SemaExprCXX.cpp | 175 +++++++++++++++------------------
 1 file changed, 77 insertions(+), 98 deletions(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 4e1652462b3ae..b4fd186d90354 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2717,15 +2717,15 @@ bool Sema::CheckAllocatedType(QualType AllocType, 
SourceLocation Loc,
 }
 
 enum class ResolveMode { Typed, Untyped };
-static bool resolveAllocationOverloadInterior(
+static bool resolveAllocationOverload(
     Sema &S, LookupResult &R, SourceRange Range, ResolveMode Mode,
-    SmallVectorImpl<Expr *> &Args, AlignedAllocationMode &PassAlignment,
-    FunctionDecl *&Operator, OverloadCandidateSet *AlignedCandidates,
-    Expr *AlignArg, bool Diagnose) {
-  unsigned NonTypeArgumentOffset = 0;
-  if (Mode == ResolveMode::Typed) {
-    ++NonTypeArgumentOffset;
-  }
+    SmallVectorImpl<Expr *> &PrefArgs, SmallVectorImpl<Expr *> &FallbackArgs,
+    AlignedAllocationMode &PassAlignment, FunctionDecl *&Operator,
+    OverloadCandidateSet *PrefCandidates, bool Diagnose) {
+
+  // If PrefCandidates are passed, this is the nested call, and so FallbackArgs
+  // should be used to fill current candidates.
+  auto &Args = PrefCandidates ? FallbackArgs : PrefArgs;
 
   OverloadCandidateSet Candidates(R.getNameLoc(),
                                   OverloadCandidateSet::CSK_Normal);
@@ -2766,17 +2766,11 @@ static bool resolveAllocationOverloadInterior(
   }
 
   case OR_No_Viable_Function:
-    // C++17 [expr.new]p13:
-    //   If no matching function is found and the allocated object type has
-    //   new-extended alignment, the alignment argument is removed from the
-    //   argument list, and overload resolution is performed again.
-    if (isAlignedAllocation(PassAlignment)) {
+    if (!PrefCandidates && !FallbackArgs.empty()) {
       PassAlignment = AlignedAllocationMode::No;
-      AlignArg = Args[NonTypeArgumentOffset + 1];
-      Args.erase(Args.begin() + NonTypeArgumentOffset + 1);
-      return resolveAllocationOverloadInterior(S, R, Range, Mode, Args,
-                                               PassAlignment, Operator,
-                                               &Candidates, AlignArg, 
Diagnose);
+      return resolveAllocationOverload(S, R, Range, Mode, PrefArgs,
+                                       FallbackArgs, PassAlignment, Operator,
+                                       &Candidates, Diagnose);
     }
 
     // MSVC will fall back on trying to find a matching global operator new
@@ -2791,10 +2785,9 @@ static bool resolveAllocationOverloadInterior(
       R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New));
       S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl());
       // FIXME: This will give bad diagnostics pointing at the wrong functions.
-      return resolveAllocationOverloadInterior(S, R, Range, Mode, Args,
-                                               PassAlignment, Operator,
-                                               /*Candidates=*/nullptr,
-                                               /*AlignArg=*/nullptr, Diagnose);
+      return resolveAllocationOverload(S, R, Range, Mode, PrefArgs,
+                                       FallbackArgs, PassAlignment, Operator,
+                                       /*PrefCandidates=*/nullptr, Diagnose);
     }
     if (Mode == ResolveMode::Typed) {
       // If we can't find a matching type aware operator we don't consider this
@@ -2831,12 +2824,13 @@ static bool resolveAllocationOverloadInterior(
       //
       // For an aligned allocation, separately check the aligned and unaligned
       // candidates with their respective argument lists.
-      SmallVector<OverloadCandidate*, 32> Cands;
-      SmallVector<OverloadCandidate*, 32> AlignedCands;
-      llvm::SmallVector<Expr*, 4> AlignedArgs;
-      if (AlignedCandidates) {
-        auto IsAligned = [NonTypeArgumentOffset](OverloadCandidate &C) {
-          auto AlignArgOffset = NonTypeArgumentOffset + 1;
+      SmallVector<OverloadCandidate *, 32> PrefCands;
+      SmallVector<OverloadCandidate *, 32> Cands;
+      if (PrefCandidates) {
+        assert(Mode == ResolveMode::Untyped &&
+               "Typed mode does not issue diagnostics");
+        auto IsAligned = [](OverloadCandidate &C) {
+          const unsigned AlignArgOffset = 1;
           return C.Function->getNumParams() > AlignArgOffset &&
                  C.Function->getParamDecl(AlignArgOffset)
                      ->getType()
@@ -2844,14 +2838,8 @@ static bool resolveAllocationOverloadInterior(
         };
         auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); };
 
-        AlignedArgs.reserve(Args.size() + NonTypeArgumentOffset + 1);
-        for (unsigned Idx = 0; Idx < NonTypeArgumentOffset + 1; ++Idx)
-          AlignedArgs.push_back(Args[Idx]);
-        AlignedArgs.push_back(AlignArg);
-        AlignedArgs.append(Args.begin() + NonTypeArgumentOffset + 1,
-                           Args.end());
-        AlignedCands = AlignedCandidates->CompleteCandidates(
-            S, OCD_AllCandidates, AlignedArgs, R.getNameLoc(), IsAligned);
+        PrefCands = PrefCandidates->CompleteCandidates(
+            S, OCD_AllCandidates, PrefArgs, R.getNameLoc(), IsAligned);
 
         Cands = Candidates.CompleteCandidates(S, OCD_AllCandidates, Args,
                                               R.getNameLoc(), IsUnaligned);
@@ -2862,9 +2850,9 @@ static bool resolveAllocationOverloadInterior(
 
       S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
           << R.getLookupName() << Range;
-      if (AlignedCandidates)
-        AlignedCandidates->NoteCandidates(S, AlignedArgs, AlignedCands, "",
-                                          R.getNameLoc());
+      if (PrefCandidates)
+        PrefCandidates->NoteCandidates(S, PrefArgs, PrefCands, "",
+                                       R.getNameLoc());
       Candidates.NoteCandidates(S, Args, Cands, "", R.getNameLoc());
     }
     return true;
@@ -2909,49 +2897,6 @@ static void LookupGlobalDeallocationFunctions(Sema &S, 
SourceLocation Loc,
   }
 }
 
-static bool resolveAllocationOverload(
-    Sema &S, LookupResult &R, SourceRange Range, SmallVectorImpl<Expr *> &Args,
-    ImplicitAllocationParameters &IAP, FunctionDecl *&Operator,
-    OverloadCandidateSet *AlignedCandidates, Expr *AlignArg, bool Diagnose) {
-  Operator = nullptr;
-  if (isTypeAwareAllocation(IAP.PassTypeIdentity)) {
-    assert(S.isStdTypeIdentity(Args[0]->getType(), nullptr));
-    // The internal overload resolution work mutates the argument list
-    // in accordance with the spec. We may want to change that in future,
-    // but for now we deal with this by making a copy of the non-type-identity
-    // arguments.
-    SmallVector<Expr *> UntypedParameters;
-    UntypedParameters.reserve(Args.size() - 1);
-    UntypedParameters.push_back(Args[1]);
-    // Type aware allocation implicitly includes the alignment parameter so
-    // only include it in the untyped parameter list if alignment was 
explicitly
-    // requested
-    if (isAlignedAllocation(IAP.PassAlignment))
-      UntypedParameters.push_back(Args[2]);
-    UntypedParameters.append(Args.begin() + 3, Args.end());
-
-    AlignedAllocationMode InitialAlignmentMode = IAP.PassAlignment;
-    IAP.PassAlignment = AlignedAllocationMode::Yes;
-    if (resolveAllocationOverloadInterior(
-            S, R, Range, ResolveMode::Typed, Args, IAP.PassAlignment, Operator,
-            AlignedCandidates, AlignArg, Diagnose))
-      return true;
-    if (Operator)
-      return false;
-
-    // If we got to this point we could not find a matching typed operator
-    // so we update the IAP flags, and revert to our stored copy of the
-    // type-identity-less argument list.
-    IAP.PassTypeIdentity = TypeAwareAllocationMode::No;
-    IAP.PassAlignment = InitialAlignmentMode;
-    Args = std::move(UntypedParameters);
-  }
-  assert(!S.isStdTypeIdentity(Args[0]->getType(), nullptr));
-  return resolveAllocationOverloadInterior(
-      S, R, Range, ResolveMode::Untyped, Args, IAP.PassAlignment, Operator,
-      AlignedCandidates, AlignArg, Diagnose);
-}
-
 bool Sema::FindAllocationFunctions(
     SourceLocation StartLoc, SourceRange Range,
     AllocationFunctionScope NewScope, AllocationFunctionScope DeleteScope,
@@ -2970,9 +2915,6 @@ bool Sema::FindAllocationFunctions(
   // 3) The first argument is always size_t. Append the arguments from the
   //   placement form.
 
-  SmallVector<Expr*, 8> AllocArgs;
-  AllocArgs.reserve(IAP.getNumImplicitArgs() + PlaceArgs.size());
-
   // C++ [expr.new]p8:
   //   If the allocated type is a non-array type, the allocation
   //   function's name is operator new and the deallocation function's
@@ -3004,29 +2946,36 @@ bool Sema::FindAllocationFunctions(
       IAP.PassTypeIdentity = TypeAwareAllocationMode::No;
   }
   TypeAwareAllocationMode OriginalTypeAwareState = IAP.PassTypeIdentity;
+  AlignedAllocationMode OriginalAlignedAllocationMode = IAP.PassAlignment;
 
   CXXScalarValueInitExpr TypeIdentityParam(TypeIdentity, nullptr, StartLoc);
-  if (isTypeAwareAllocation(IAP.PassTypeIdentity))
-    AllocArgs.push_back(&TypeIdentityParam);
 
   QualType SizeTy = Context.getSizeType();
   unsigned SizeTyWidth = Context.getTypeSize(SizeTy);
   IntegerLiteral Size(Context, llvm::APInt::getZero(SizeTyWidth), SizeTy,
                       SourceLocation());
-  AllocArgs.push_back(&Size);
 
   QualType AlignValT = Context.VoidTy;
-  bool IncludeAlignParam = isAlignedAllocation(IAP.PassAlignment) ||
-                           isTypeAwareAllocation(IAP.PassTypeIdentity);
-  if (IncludeAlignParam) {
+  if (isTypeAwareAllocation(OriginalTypeAwareState) ||
+      isAlignedAllocation(OriginalAlignedAllocationMode)) {
     DeclareGlobalNewDelete();
     AlignValT = Context.getCanonicalTagType(getStdAlignValT());
   }
   CXXScalarValueInitExpr Align(AlignValT, nullptr, SourceLocation());
-  if (IncludeAlignParam)
-    AllocArgs.push_back(&Align);
 
-  llvm::append_range(AllocArgs, PlaceArgs);
+  using ArgsVector = SmallVector<Expr *, 8>;
+  auto FillAllocArgs = [&](TypeAwareAllocationMode TAAM,
+                           AlignedAllocationMode AAM) {
+    ArgsVector AllocArgs;
+    AllocArgs.reserve(IAP.getNumImplicitArgs() + PlaceArgs.size());
+    if (isTypeAwareAllocation(TAAM))
+      AllocArgs.push_back(&TypeIdentityParam);
+    AllocArgs.push_back(&Size);
+    if (isAlignedAllocation(AAM))
+      AllocArgs.push_back(&Align);
+    llvm::append_range(AllocArgs, PlaceArgs);
+    return AllocArgs;
+  };
 
   // Find the allocation function.
   {
@@ -3071,10 +3020,40 @@ bool Sema::FindAllocationFunctions(
     // We do our own custom access checks below.
     R.suppressDiagnostics();
 
-    if (resolveAllocationOverload(*this, R, Range, AllocArgs, IAP, OperatorNew,
-                                  /*Candidates=*/nullptr,
-                                  /*AlignArg=*/nullptr, Diagnose))
-      return true;
+    OperatorNew = nullptr;
+    if (isTypeAwareAllocation(IAP.PassTypeIdentity)) {
+      IAP.PassAlignment = AlignedAllocationMode::Yes;
+      auto AllocArgs = FillAllocArgs(TypeAwareAllocationMode::Yes,
+                                     AlignedAllocationMode::Yes);
+      auto FallbackAllocArgs = FillAllocArgs(TypeAwareAllocationMode::Yes,
+                                             AlignedAllocationMode::No);
+
+      if (resolveAllocationOverload(*this, R, Range, ResolveMode::Typed,
+                                    AllocArgs, FallbackAllocArgs,
+                                    IAP.PassAlignment, OperatorNew,
+                                    /*PrefCandidates=*/nullptr, Diagnose))
+        return true;
+    }
+    if (!OperatorNew) {
+      IAP.PassTypeIdentity = TypeAwareAllocationMode::No;
+      IAP.PassAlignment = OriginalAlignedAllocationMode;
+      auto AllocArgs = FillAllocArgs(TypeAwareAllocationMode::No,
+                                     OriginalAlignedAllocationMode);
+      // C++17 [expr.new]p13:
+      //   If no matching function is found and the allocated object type has
+      //   new-extended alignment, the alignment argument is removed from the
+      //   argument list, and overload resolution is performed again.
+      auto FallbackAllocArgs =
+          isAlignedAllocation(OriginalAlignedAllocationMode)
+              ? FillAllocArgs(TypeAwareAllocationMode::No,
+                              AlignedAllocationMode::No)
+              : ArgsVector();
+      if (resolveAllocationOverload(*this, R, Range, ResolveMode::Untyped,
+                                    AllocArgs, FallbackAllocArgs,
+                                    IAP.PassAlignment, OperatorNew,
+                                    /*PrefCandidates=*/nullptr, Diagnose))
+        return true;
+    }
   }
 
   // We don't need an operator delete if we're running under -fno-exceptions.

>From 4cc954f841c75b41296f6d17e7bf54b2cdc821ab Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Fri, 19 Jun 2026 23:37:42 -0700
Subject: [PATCH 2/3] fixup! Pass the argument list without the alignment
 argument to the msvc-specific fallback

---
 clang/lib/Sema/SemaExprCXX.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b4fd186d90354..6a4d69551f3fa 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2784,9 +2784,13 @@ static bool resolveAllocationOverload(
       R.clear();
       R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New));
       S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl());
+      // Only try this fallback without the alignment argument.
+      assert(!isAlignedAllocation(PassAlignment));
+      auto &Args = FallbackArgs.empty() ? PrefArgs : FallbackArgs;
+      SmallVector<Expr *, 1> EmptyArgs;
       // FIXME: This will give bad diagnostics pointing at the wrong functions.
-      return resolveAllocationOverload(S, R, Range, Mode, PrefArgs,
-                                       FallbackArgs, PassAlignment, Operator,
+      return resolveAllocationOverload(S, R, Range, Mode, Args, EmptyArgs,
+                                       PassAlignment, Operator,
                                        /*PrefCandidates=*/nullptr, Diagnose);
     }
     if (Mode == ResolveMode::Typed) {

>From 5066d3aa84fb7836b9c988c32821334fa8fbf05e Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Sat, 20 Jun 2026 20:24:07 -0700
Subject: [PATCH 3/3] fixup! Streamline overload resolution

---
 clang/include/clang/Sema/Sema.h |   4 +-
 clang/lib/Sema/SemaExprCXX.cpp  | 375 +++++++++++++++++---------------
 clang/lib/Sema/SemaOverload.cpp |   2 +-
 3 files changed, 204 insertions(+), 177 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b8d760e7e0975..b9893234273d2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8656,7 +8656,7 @@ class Sema final : public SemaBase {
       SourceLocation StartLoc, SourceRange Range,
       AllocationFunctionScope NewScope, AllocationFunctionScope DeleteScope,
       QualType AllocType, bool IsArray, ImplicitAllocationParameters &IAP,
-      MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew,
+      ArrayRef<Expr *> PlaceArgs, FunctionDecl *&OperatorNew,
       FunctionDecl *&OperatorDelete, bool Diagnose = true);
 
   /// DeclareGlobalNewDelete - Declare the global forms of operator new and
@@ -10368,7 +10368,7 @@ class Sema final : public SemaBase {
   void DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range,
                                     DeclarationName Name,
                                     OverloadCandidateSet &CandidateSet,
-                                    FunctionDecl *Fn, MultiExprArg Args,
+                                    FunctionDecl *Fn, ArrayRef<Expr *> Args,
                                     bool IsMember = false);
 
   ExprResult InitializeExplicitObjectArgument(Sema &S, Expr *Obj,
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 6a4d69551f3fa..465ca02f3b177 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2716,42 +2716,42 @@ bool Sema::CheckAllocatedType(QualType AllocType, 
SourceLocation Loc,
   return false;
 }
 
-enum class ResolveMode { Typed, Untyped };
-static bool resolveAllocationOverload(
-    Sema &S, LookupResult &R, SourceRange Range, ResolveMode Mode,
-    SmallVectorImpl<Expr *> &PrefArgs, SmallVectorImpl<Expr *> &FallbackArgs,
-    AlignedAllocationMode &PassAlignment, FunctionDecl *&Operator,
-    OverloadCandidateSet *PrefCandidates, bool Diagnose) {
-
-  // If PrefCandidates are passed, this is the nested call, and so FallbackArgs
-  // should be used to fill current candidates.
-  auto &Args = PrefCandidates ? FallbackArgs : PrefArgs;
-
-  OverloadCandidateSet Candidates(R.getNameLoc(),
-                                  OverloadCandidateSet::CSK_Normal);
-  for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
-       Alloc != AllocEnd; ++Alloc) {
+static std::unique_ptr<OverloadCandidateSet> fillNewDeleteOverloadCandidateSet(
+    Sema &S, LookupResult &R, ArrayRef<Expr *> Args,
+    llvm::function_ref<bool(NamedDecl *)> Filter = [](NamedDecl *) {
+      return true;
+    }) {
+  auto Candidates = std::make_unique<OverloadCandidateSet>(
+      R.getNameLoc(), OverloadCandidateSet::CSK_Normal);
+  for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end();
+       FnOvl != FnOvlEnd; ++FnOvl) {
     // Even member operator new/delete are implicitly treated as
     // static, so don't use AddMemberCandidate.
-    NamedDecl *D = (*Alloc)->getUnderlyingDecl();
-    bool IsTypeAware = D->getAsFunction()->isTypeAwareOperatorNewOrDelete();
-    if (IsTypeAware == (Mode != ResolveMode::Typed))
+    NamedDecl *D = (*FnOvl)->getUnderlyingDecl();
+    if (!Filter(D))
       continue;
 
     if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
-      S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(),
+      S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(),
                                      /*ExplicitTemplateArgs=*/nullptr, Args,
-                                     Candidates,
+                                     *Candidates,
                                      /*SuppressUserConversions=*/false);
       continue;
     }
 
     FunctionDecl *Fn = cast<FunctionDecl>(D);
-    S.AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates,
+    S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, *Candidates,
                            /*SuppressUserConversions=*/false);
   }
 
-  // Do the resolution.
+  return Candidates;
+}
+
+static bool resolveAllocationOverload(Sema &S, LookupResult &R,
+                                      SourceRange Range,
+                                      OverloadCandidateSet &Candidates,
+                                      ArrayRef<Expr *> Args,
+                                      FunctionDecl *&Operator, bool Diagnose) {
   OverloadCandidateSet::iterator Best;
   switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) {
   case OR_Success: {
@@ -2766,100 +2766,8 @@ static bool resolveAllocationOverload(
   }
 
   case OR_No_Viable_Function:
-    if (!PrefCandidates && !FallbackArgs.empty()) {
-      PassAlignment = AlignedAllocationMode::No;
-      return resolveAllocationOverload(S, R, Range, Mode, PrefArgs,
-                                       FallbackArgs, PassAlignment, Operator,
-                                       &Candidates, Diagnose);
-    }
-
-    // MSVC will fall back on trying to find a matching global operator new
-    // if operator new[] cannot be found.  Also, MSVC will leak by not
-    // generating a call to operator delete or operator delete[], but we
-    // will not replicate that bug.
-    // FIXME: Find out how this interacts with the std::align_val_t fallback
-    // once MSVC implements it.
-    if (R.getLookupName().getCXXOverloadedOperator() == OO_Array_New &&
-        S.Context.getLangOpts().MSVCCompat && Mode != ResolveMode::Typed) {
-      R.clear();
-      R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New));
-      S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl());
-      // Only try this fallback without the alignment argument.
-      assert(!isAlignedAllocation(PassAlignment));
-      auto &Args = FallbackArgs.empty() ? PrefArgs : FallbackArgs;
-      SmallVector<Expr *, 1> EmptyArgs;
-      // FIXME: This will give bad diagnostics pointing at the wrong functions.
-      return resolveAllocationOverload(S, R, Range, Mode, Args, EmptyArgs,
-                                       PassAlignment, Operator,
-                                       /*PrefCandidates=*/nullptr, Diagnose);
-    }
-    if (Mode == ResolveMode::Typed) {
-      // If we can't find a matching type aware operator we don't consider this
-      // a failure.
-      Operator = nullptr;
-      return false;
-    }
-    if (Diagnose) {
-      // If this is an allocation of the form 'new (p) X' for some object
-      // pointer p (or an expression that will decay to such a pointer),
-      // diagnose the reason for the error.
-      if (!R.isClassLookup() && Args.size() == 2 &&
-          (Args[1]->getType()->isObjectPointerType() ||
-           Args[1]->getType()->isArrayType())) {
-        const QualType Arg1Type = Args[1]->getType();
-        QualType UnderlyingType = S.Context.getBaseElementType(Arg1Type);
-        if (UnderlyingType->isPointerType())
-          UnderlyingType = UnderlyingType->getPointeeType();
-        if (UnderlyingType.isConstQualified()) {
-          S.Diag(Args[1]->getExprLoc(),
-                 diag::err_placement_new_into_const_qualified_storage)
-              << Arg1Type << Args[1]->getSourceRange();
-          return true;
-        }
-        S.Diag(R.getNameLoc(), diag::err_need_header_before_placement_new)
-            << R.getLookupName() << Range;
-        // Listing the candidates is unlikely to be useful; skip it.
-        return true;
-      }
-
-      // Finish checking all candidates before we note any. This checking can
-      // produce additional diagnostics so can't be interleaved with our
-      // emission of notes.
-      //
-      // For an aligned allocation, separately check the aligned and unaligned
-      // candidates with their respective argument lists.
-      SmallVector<OverloadCandidate *, 32> PrefCands;
-      SmallVector<OverloadCandidate *, 32> Cands;
-      if (PrefCandidates) {
-        assert(Mode == ResolveMode::Untyped &&
-               "Typed mode does not issue diagnostics");
-        auto IsAligned = [](OverloadCandidate &C) {
-          const unsigned AlignArgOffset = 1;
-          return C.Function->getNumParams() > AlignArgOffset &&
-                 C.Function->getParamDecl(AlignArgOffset)
-                     ->getType()
-                     ->isAlignValT();
-        };
-        auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); };
-
-        PrefCands = PrefCandidates->CompleteCandidates(
-            S, OCD_AllCandidates, PrefArgs, R.getNameLoc(), IsAligned);
-
-        Cands = Candidates.CompleteCandidates(S, OCD_AllCandidates, Args,
-                                              R.getNameLoc(), IsUnaligned);
-      } else {
-        Cands = Candidates.CompleteCandidates(S, OCD_AllCandidates, Args,
-                                              R.getNameLoc());
-      }
-
-      S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
-          << R.getLookupName() << Range;
-      if (PrefCandidates)
-        PrefCandidates->NoteCandidates(S, PrefArgs, PrefCands, "",
-                                       R.getNameLoc());
-      Candidates.NoteCandidates(S, Args, Cands, "", R.getNameLoc());
-    }
-    return true;
+    // Let the caller handle fallback logic.
+    return false;
 
   case OR_Ambiguous:
     if (Diagnose) {
@@ -2881,6 +2789,68 @@ static bool resolveAllocationOverload(
   llvm_unreachable("Unreachable, bad result from BestViableFunction");
 }
 
+static void diagnoseNoViableFunctionForAllocationOverloadResolution(
+    Sema &S, LookupResult &R, SourceRange Range, ArrayRef<Expr *> PrefArgs,
+    ArrayRef<Expr *> FallbackArgs, OverloadCandidateSet &PrefCandidates,
+    OverloadCandidateSet *FallbackCandidates) {
+  // If this is an allocation of the form 'new (p) X' for some object
+  // pointer p (or an expression that will decay to such a pointer),
+  // diagnose the reason for the error.
+  auto NonAlignArgs = FallbackArgs.empty() ? PrefArgs : FallbackArgs;
+  if (!R.isClassLookup() && NonAlignArgs.size() == 2 &&
+      (NonAlignArgs[1]->getType()->isObjectPointerType() ||
+       NonAlignArgs[1]->getType()->isArrayType())) {
+    const QualType Arg1Type = NonAlignArgs[1]->getType();
+    QualType UnderlyingType = S.Context.getBaseElementType(Arg1Type);
+    if (UnderlyingType->isPointerType())
+      UnderlyingType = UnderlyingType->getPointeeType();
+    if (UnderlyingType.isConstQualified()) {
+      S.Diag(NonAlignArgs[1]->getExprLoc(),
+             diag::err_placement_new_into_const_qualified_storage)
+          << Arg1Type << NonAlignArgs[1]->getSourceRange();
+      return;
+    }
+    S.Diag(R.getNameLoc(), diag::err_need_header_before_placement_new)
+        << R.getLookupName() << Range;
+    // Listing the candidates is unlikely to be useful; skip it.
+    return;
+  }
+
+  // Finish checking all candidates before we note any. This checking can
+  // produce additional diagnostics so can't be interleaved with our
+  // emission of notes.
+  //
+  // For an aligned allocation, separately check the aligned and unaligned
+  // candidates with their respective argument lists.
+  SmallVector<OverloadCandidate *, 32> PrefCands;
+  SmallVector<OverloadCandidate *, 32> FallbackCands;
+  if (FallbackCandidates) {
+    assert(!FallbackArgs.empty() && PrefArgs.size() == FallbackArgs.size() + 
1);
+    auto IsAligned = [](OverloadCandidate &C) {
+      const unsigned AlignArgOffset = 1;
+      return C.Function->getNumParams() > AlignArgOffset &&
+             
C.Function->getParamDecl(AlignArgOffset)->getType()->isAlignValT();
+    };
+    auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); };
+
+    PrefCands = PrefCandidates.CompleteCandidates(
+        S, OCD_AllCandidates, PrefArgs, R.getNameLoc(), IsAligned);
+
+    FallbackCands = FallbackCandidates->CompleteCandidates(
+        S, OCD_AllCandidates, FallbackArgs, R.getNameLoc(), IsUnaligned);
+  } else {
+    PrefCands = PrefCandidates.CompleteCandidates(S, OCD_AllCandidates,
+                                                  PrefArgs, R.getNameLoc());
+  }
+
+  S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call)
+      << R.getLookupName() << Range;
+  PrefCandidates.NoteCandidates(S, PrefArgs, PrefCands, "", R.getNameLoc());
+  if (FallbackCandidates)
+    FallbackCandidates->NoteCandidates(S, FallbackArgs, FallbackCands, "",
+                                       R.getNameLoc());
+}
+
 enum class DeallocLookupMode { Untyped, OptionallyTyped };
 
 static void LookupGlobalDeallocationFunctions(Sema &S, SourceLocation Loc,
@@ -2905,7 +2875,7 @@ bool Sema::FindAllocationFunctions(
     SourceLocation StartLoc, SourceRange Range,
     AllocationFunctionScope NewScope, AllocationFunctionScope DeleteScope,
     QualType AllocType, bool IsArray, ImplicitAllocationParameters &IAP,
-    MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew,
+    ArrayRef<Expr *> PlaceArgs, FunctionDecl *&OperatorNew,
     FunctionDecl *&OperatorDelete, bool Diagnose) {
   // --- Choosing an allocation function ---
   // C++ 5.3.4p8 - 14 & 18
@@ -2950,7 +2920,6 @@ bool Sema::FindAllocationFunctions(
       IAP.PassTypeIdentity = TypeAwareAllocationMode::No;
   }
   TypeAwareAllocationMode OriginalTypeAwareState = IAP.PassTypeIdentity;
-  AlignedAllocationMode OriginalAlignedAllocationMode = IAP.PassAlignment;
 
   CXXScalarValueInitExpr TypeIdentityParam(TypeIdentity, nullptr, StartLoc);
 
@@ -2961,7 +2930,7 @@ bool Sema::FindAllocationFunctions(
 
   QualType AlignValT = Context.VoidTy;
   if (isTypeAwareAllocation(OriginalTypeAwareState) ||
-      isAlignedAllocation(OriginalAlignedAllocationMode)) {
+      isAlignedAllocation(IAP.PassAlignment)) {
     DeclareGlobalNewDelete();
     AlignValT = Context.getCanonicalTagType(getStdAlignValT());
   }
@@ -2982,7 +2951,8 @@ bool Sema::FindAllocationFunctions(
   };
 
   // Find the allocation function.
-  {
+  // Staged allocation function lookup using do-while(false) for early exit.
+  do {
     LookupResult R(*this, NewName, StartLoc, LookupOrdinaryName);
 
     // C++1z [expr.new]p9:
@@ -3024,41 +2994,117 @@ bool Sema::FindAllocationFunctions(
     // We do our own custom access checks below.
     R.suppressDiagnostics();
 
+    auto IsTypeAware = [](NamedDecl *D) {
+      return D->getAsFunction()->isTypeAwareOperatorNewOrDelete();
+    };
+    auto IsNonTypeAware = [](NamedDecl *D) {
+      return !D->getAsFunction()->isTypeAwareOperatorNewOrDelete();
+    };
     OperatorNew = nullptr;
+
+    // Step 1. Try type-aware allocation functions first.
     if (isTypeAwareAllocation(IAP.PassTypeIdentity)) {
-      IAP.PassAlignment = AlignedAllocationMode::Yes;
-      auto AllocArgs = FillAllocArgs(TypeAwareAllocationMode::Yes,
-                                     AlignedAllocationMode::Yes);
-      auto FallbackAllocArgs = FillAllocArgs(TypeAwareAllocationMode::Yes,
-                                             AlignedAllocationMode::No);
-
-      if (resolveAllocationOverload(*this, R, Range, ResolveMode::Typed,
-                                    AllocArgs, FallbackAllocArgs,
-                                    IAP.PassAlignment, OperatorNew,
-                                    /*PrefCandidates=*/nullptr, Diagnose))
+      auto Args = FillAllocArgs(TypeAwareAllocationMode::Yes,
+                                AlignedAllocationMode::Yes);
+      auto Candidates =
+          fillNewDeleteOverloadCandidateSet(*this, R, Args, IsTypeAware);
+      if (resolveAllocationOverload(*this, R, Range, *Candidates, Args,
+                                    OperatorNew, Diagnose))
         return true;
+      if (OperatorNew) {
+        IAP.PassAlignment = AlignedAllocationMode::Yes;
+        break;
+      }
+
+      // Step 1a. Try type-aware allocation functions without the alignment
+      // parameter.
+      // FIXME: According to P2719, whether the implicit alignment parameter is
+      // added or not should depend on the type of the first argument in the
+      // placement arguments list.
+      Args = FillAllocArgs(TypeAwareAllocationMode::Yes,
+                           AlignedAllocationMode::No);
+      Candidates =
+          fillNewDeleteOverloadCandidateSet(*this, R, Args, IsTypeAware);
+      if (resolveAllocationOverload(*this, R, Range, *Candidates, Args,
+                                    OperatorNew, Diagnose))
+        return true;
+      if (OperatorNew) {
+        IAP.PassAlignment = AlignedAllocationMode::No;
+        break;
+      }
     }
-    if (!OperatorNew) {
-      IAP.PassTypeIdentity = TypeAwareAllocationMode::No;
-      IAP.PassAlignment = OriginalAlignedAllocationMode;
-      auto AllocArgs = FillAllocArgs(TypeAwareAllocationMode::No,
-                                     OriginalAlignedAllocationMode);
-      // C++17 [expr.new]p13:
-      //   If no matching function is found and the allocated object type has
-      //   new-extended alignment, the alignment argument is removed from the
-      //   argument list, and overload resolution is performed again.
-      auto FallbackAllocArgs =
-          isAlignedAllocation(OriginalAlignedAllocationMode)
-              ? FillAllocArgs(TypeAwareAllocationMode::No,
-                              AlignedAllocationMode::No)
-              : ArgsVector();
-      if (resolveAllocationOverload(*this, R, Range, ResolveMode::Untyped,
-                                    AllocArgs, FallbackAllocArgs,
-                                    IAP.PassAlignment, OperatorNew,
-                                    /*PrefCandidates=*/nullptr, Diagnose))
+
+    // Step 2. Try non-type-aware allocation functions.
+    IAP.PassTypeIdentity = TypeAwareAllocationMode::No;
+    auto PrefArgs =
+        FillAllocArgs(TypeAwareAllocationMode::No, IAP.PassAlignment);
+    auto PrefCandidates =
+        fillNewDeleteOverloadCandidateSet(*this, R, PrefArgs, IsNonTypeAware);
+    if (resolveAllocationOverload(*this, R, Range, *PrefCandidates, PrefArgs,
+                                  OperatorNew, Diagnose))
+      return true;
+    if (OperatorNew)
+      break;
+
+    // Step 3. For overaligned types, try allocation functions without the
+    // alignment parameter.
+    // C++17 [expr.new]p13:
+    //   If no matching function is found and the allocated object type has
+    //   new-extended alignment, the alignment argument is removed from the
+    //   argument list, and overload resolution is performed again.
+    ArgsVector FallbackArgs;
+    std::unique_ptr<OverloadCandidateSet> FallbackCandidates;
+    if (isAlignedAllocation(IAP.PassAlignment)) {
+      FallbackArgs =
+          FillAllocArgs(TypeAwareAllocationMode::No, 
AlignedAllocationMode::No);
+      FallbackCandidates = fillNewDeleteOverloadCandidateSet(
+          *this, R, FallbackArgs, IsNonTypeAware);
+      if (resolveAllocationOverload(*this, R, Range, *FallbackCandidates,
+                                    FallbackArgs, OperatorNew, Diagnose))
         return true;
+      if (OperatorNew) {
+        IAP.PassAlignment = AlignedAllocationMode::No;
+        break;
+      }
     }
-  }
+
+    // Step 4. Try MSVC-specific fallback.
+    // MSVC will fall back on trying to find a matching global operator new
+    // if operator new[] cannot be found.  Also, MSVC will leak by not
+    // generating a call to operator delete or operator delete[], but we
+    // will not replicate that bug.
+    // FIXME: Find out how this interacts with the std::align_val_t fallback
+    // once MSVC implements it.
+    if (IsArray && Context.getLangOpts().MSVCCompat) {
+      // Note: R is intentionally shadowed for the MSVC fallback lookup.
+      LookupResult R(*this, 
Context.DeclarationNames.getCXXOperatorName(OO_New),
+                     StartLoc, LookupOrdinaryName);
+      LookupQualifiedName(R, Context.getTranslationUnitDecl());
+      auto Args =
+          FillAllocArgs(TypeAwareAllocationMode::No, 
AlignedAllocationMode::No);
+      auto Candidates =
+          fillNewDeleteOverloadCandidateSet(*this, R, Args, IsNonTypeAware);
+      if (resolveAllocationOverload(*this, R, Range, *Candidates, Args,
+                                    OperatorNew, Diagnose))
+        return true;
+      if (OperatorNew) {
+        IAP.PassAlignment = AlignedAllocationMode::No;
+        break;
+      }
+      // FIXME: This will give bad diagnostics pointing at the wrong functions.
+      if (Diagnose)
+        diagnoseNoViableFunctionForAllocationOverloadResolution(
+            *this, R, Range, Args, /*FallbackArgs=*/ArrayRef<Expr *>(),
+            *Candidates, /*FallbackCandidates=*/nullptr);
+      return true;
+    }
+
+    if (Diagnose)
+      diagnoseNoViableFunctionForAllocationOverloadResolution(
+          *this, R, Range, PrefArgs, FallbackArgs, *PrefCandidates,
+          FallbackCandidates.get());
+    return true;
+  } while (false);
 
   // We don't need an operator delete if we're running under -fno-exceptions.
   if (!getLangOpts().Exceptions) {
@@ -4263,32 +4309,13 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, 
CallExpr *TheCall,
   R.suppressDiagnostics();
 
   SmallVector<Expr *, 8> Args(TheCall->arguments());
-  OverloadCandidateSet Candidates(R.getNameLoc(),
-                                  OverloadCandidateSet::CSK_Normal);
-  for (LookupResult::iterator FnOvl = R.begin(), FnOvlEnd = R.end();
-       FnOvl != FnOvlEnd; ++FnOvl) {
-    // Even member operator new/delete are implicitly treated as
-    // static, so don't use AddMemberCandidate.
-    NamedDecl *D = (*FnOvl)->getUnderlyingDecl();
-
-    if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) {
-      S.AddTemplateOverloadCandidate(FnTemplate, FnOvl.getPair(),
-                                     /*ExplicitTemplateArgs=*/nullptr, Args,
-                                     Candidates,
-                                     /*SuppressUserConversions=*/false);
-      continue;
-    }
-
-    FunctionDecl *Fn = cast<FunctionDecl>(D);
-    S.AddOverloadCandidate(Fn, FnOvl.getPair(), Args, Candidates,
-                           /*SuppressUserConversions=*/false);
-  }
-
+  std::unique_ptr<OverloadCandidateSet> Candidates =
+      fillNewDeleteOverloadCandidateSet(S, R, Args);
   SourceRange Range = TheCall->getSourceRange();
 
   // Do the resolution.
   OverloadCandidateSet::iterator Best;
-  switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) {
+  switch (Candidates->BestViableFunction(S, R.getNameLoc(), Best)) {
   case OR_Success: {
     // Got one!
     FunctionDecl *FnDecl = Best->Function;
@@ -4308,7 +4335,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, 
CallExpr *TheCall,
   }
 
   case OR_No_Viable_Function:
-    Candidates.NoteCandidates(
+    Candidates->NoteCandidates(
         PartialDiagnosticAt(R.getNameLoc(),
                             S.PDiag(diag::err_ovl_no_viable_function_in_call)
                                 << R.getLookupName() << Range),
@@ -4316,7 +4343,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, 
CallExpr *TheCall,
     return true;
 
   case OR_Ambiguous:
-    Candidates.NoteCandidates(
+    Candidates->NoteCandidates(
         PartialDiagnosticAt(R.getNameLoc(),
                             S.PDiag(diag::err_ovl_ambiguous_call)
                                 << R.getLookupName() << Range),
@@ -4325,7 +4352,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, 
CallExpr *TheCall,
 
   case OR_Deleted:
     S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(),
-                                   Candidates, Best->Function, Args);
+                                   *Candidates, Best->Function, Args);
     return true;
   }
   llvm_unreachable("Unreachable, bad result from BestViableFunction");
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index c663765573612..ac6e8f5c63bf3 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -17364,7 +17364,7 @@ bool clang::shouldEnforceArgLimit(bool 
PartialOverloading,
 void Sema::DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range,
                                         DeclarationName Name,
                                         OverloadCandidateSet &CandidateSet,
-                                        FunctionDecl *Fn, MultiExprArg Args,
+                                        FunctionDecl *Fn, ArrayRef<Expr *> 
Args,
                                         bool IsMember) {
   StringLiteral *Msg = Fn->getDeletedMessage();
   CandidateSet.NoteCandidates(

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to