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

`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.

>From 35e6cd3ee18756869cf75d01236588b444c135fa Mon Sep 17 00:00:00 2001
From: Igor Kudrin <[email protected]>
Date: Sat, 13 Jun 2026 20:18:30 -0700
Subject: [PATCH] [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 | 180 +++++++++++++++------------------
 1 file changed, 82 insertions(+), 98 deletions(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 4e1652462b3ae..fbbeb012c1728 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, an 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,18 @@ 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(!isAlignedAllocation(PassAlignment) &&
+               "This is a nested call that searches for an unaligned "
+               "allocation function");
+        assert(PrefArgs.size() == FallbackArgs.size() + 1 &&
+               "FallbackArgs are PrefArgs with the alignment argument 
removed");
+        assert(Mode == ResolveMode::Untyped &&
+               "Typed mode does not print diagnostic");
+        auto IsAligned = [](OverloadCandidate &C) {
+          const unsigned AlignArgOffset = 1;
           return C.Function->getNumParams() > AlignArgOffset &&
                  C.Function->getParamDecl(AlignArgOffset)
                      ->getType()
@@ -2844,14 +2843,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 +2855,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 +2902,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 +2920,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 +2951,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 +3025,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.

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

Reply via email to