================
@@ -2918,55 +2883,184 @@ 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))
+static void DiagnoseAllocationLookupFailure(
+    Sema &SemaRef, LookupResult &R, SourceRange Range,
+    std::optional<AllocationArgumentSet> &ArgumentCandidates,
+    ArrayRef<Expr *> PlacementArguments) {
+  ImplicitAllocationArguments *UnalignedArgumentList = nullptr;
+  ImplicitAllocationArguments *AlignedArgumentList = nullptr;
+  for (ImplicitAllocationArguments &AllocationArguments :
+       ArgumentCandidates->Candidates) {
+    if (AllocationArguments.PassTypeIdentity == TypeAwareAllocationMode::Yes)
+      continue;
+    if (AllocationArguments.PassAlignment == AlignedAllocationMode::Yes)
+      AlignedArgumentList = &AllocationArguments;
+    else
+      UnalignedArgumentList = &AllocationArguments;
+  }
+  if (!UnalignedArgumentList)
+    return;
+
+  // We re-resolve the rejected candidates for diagnostics rather than 
requiring
+  // them to be tracked during the initial resolution path. This both 
simplifies
+  // the resolution logic, and helps with performance.
+  auto Rerun = [&](ImplicitAllocationArguments &ArgumentList,
+                   OverloadCandidateSet &Candidates,
+                   SmallVectorImpl<Expr *> &Args) {
+    llvm::append_range(Args, ArgumentList.getImplicitArguments());
+    llvm::append_range(Args, PlacementArguments);
+    FunctionDecl *Unused = nullptr;
+    resolveAllocationOverload(SemaRef, R, Range, ArgumentList, Args, Unused,
+                              Candidates, /*Diagnose=*/false);
+  };
+  std::optional<OverloadCandidateSet> AlignedCandidates;
+  Expr *AlignArg = nullptr;
+  if (AlignedArgumentList) {
+    AlignedCandidates.emplace(R.getNameLoc(), 
OverloadCandidateSet::CSK_Normal);
+    SmallVector<Expr *, 4> AlignedArgs;
+    Rerun(*AlignedArgumentList, *AlignedCandidates, AlignedArgs);
+    AlignArg = AlignedArgumentList->getAlignmentArgument();
+  }
+  OverloadCandidateSet UnalignedCandidates(R.getNameLoc(),
+                                           OverloadCandidateSet::CSK_Normal);
+  SmallVector<Expr *, 4> UnalignedArgs;
+  Rerun(*UnalignedArgumentList, UnalignedCandidates, UnalignedArgs);
+  diagnoseNoViableFunctionForAllocationOverloadResolution(
+      SemaRef, R, Range, UnalignedArgs, UnalignedCandidates,
+      AlignedCandidates ? &*AlignedCandidates : nullptr, AlignArg);
+}
+
+bool Sema::getTypeIdentityArgument(QualType Type, SourceLocation Loc,
+                                   Expr **FoundExpr) {
+  auto [Slot, Inserted] =
+      AllocationTypeIdentityArguments.insert({Type, nullptr});
+  if (!Inserted) {
+    if (!Slot->second)
       return true;
-    if (Operator)
-      return false;
+    *FoundExpr = Slot->second;
+    return false;
+  }
+  QualType TypeIdentity = tryBuildStdTypeIdentity(Type, SourceLocation());
+  if (TypeIdentity.isNull())
+    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,
-    QualType AllocType, bool IsArray, ImplicitAllocationParameters &IAP,
-    MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew,
-    FunctionDecl *&OperatorDelete, bool Diagnose) {
+  if (RequireCompleteType(Loc, TypeIdentity, diag::err_incomplete_type))
+    return true;
+  Expr *TypeIdentityArgument =
+      new (Context) CXXScalarValueInitExpr(TypeIdentity, nullptr, Loc);
+  Slot->second = TypeIdentityArgument;
+  *FoundExpr = TypeIdentityArgument;
+  return false;
+}
+
+ImplicitAllocationArguments::ImplicitAllocationArguments(
+    Sema &SemaRef, Expr *TypeIdentityArg, Expr *SizeArg, Expr *AlignArg,
+    bool IsMSVCCompatibilityFallback)
+    : PassTypeIdentity(typeAwareAllocationModeFromBool(TypeIdentityArg)),
+      PassAlignment(alignedAllocationModeFromBool(AlignArg)),
+      IsMSVCCompatibilityFallback(IsMSVCCompatibilityFallback),
+      ArgumentCount(0) {
+  ASTContext &Ctx = SemaRef.getASTContext();
+  if (TypeIdentityArg) {
+    assert(SemaRef.isStdTypeIdentity(TypeIdentityArg->getType(), nullptr));
+    ImplicitArguments[ArgumentCount++] = TypeIdentityArg;
+  }
+  assert(SizeArg);
+  assert(Ctx.hasSameType(SizeArg->getType(), Ctx.getSizeType()));
+  ImplicitArguments[ArgumentCount++] = SizeArg;
+  if (AlignArg) {
+    assert(AlignArg->getType()->isAlignValT());
+    ImplicitArguments[ArgumentCount++] = AlignArg;
+  }
+}
+
+void ImplicitAllocationArguments::updateLookupForMSVCCompatibility(
+    Sema &S, LookupResult &R) {
+  if (!IsMSVCCompatibilityFallback)
+    return;
+  // 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.
+  R.clear();
+  R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New));
+  // FIXME: This will give bad diagnostics pointing at the wrong functions.
+  S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl());
+}
+
+std::optional<AllocationArgumentSet>
+Sema::resolveAllocationArguments(LookupResult &R,
+                                 const ImplicitAllocationParameters &IAP,
+                                 ArrayRef<Expr *> PlacementArguments) {
+  // FIXME: Should Sema create per-callsite versions expressions so they can be
+  // reused during codegen? This would likely create yet another case where we
+  // need to serialize information, however it would ensure identical arguments
+  // between Sema and CodeGen.
+  if (!AllocationSizeExpr) {
+    DeclareGlobalNewDelete();
+    QualType SizeTy = Context.getSizeType();
+    unsigned SizeTyWidth = Context.getTypeSize(SizeTy);
+    AllocationSizeExpr = IntegerLiteral::Create(
+        Context, llvm::APInt::getZero(SizeTyWidth), SizeTy, SourceLocation());
+    if (EnumDecl *StdAlignValT = getStdAlignValT()) {
+      QualType AlignValT = Context.getCanonicalTagType(StdAlignValT);
+      AllocationAlignmentExpr = new (Context)
+          CXXScalarValueInitExpr(AlignValT, nullptr, SourceLocation());
+    }
+  }
+
+  AllocationArgumentSet FoundArguments = {
+      isTypeAwareAllocation(IAP.PassTypeIdentity), {}};
+  if (isTypeAwareAllocation(IAP.PassTypeIdentity)) {
+    Expr *TypeIdentityArgument = nullptr;
+    if (getTypeIdentityArgument(IAP.Type, R.getNameLoc(),
+                                &TypeIdentityArgument))
+      return std::nullopt;
+    if (TypeIdentityArgument) {
+      Expr *AlignmentExpr = AllocationAlignmentExpr;
+      if (!PlacementArguments.empty() &&
+          PlacementArguments.front()->getType()->isAlignValT())
+        AlignmentExpr = nullptr;
+      FoundArguments.Candidates.push_back(ImplicitAllocationArguments(
+          *this, TypeIdentityArgument, AllocationSizeExpr, AlignmentExpr,
+          /*IsMSVCCompatibilityFallback=*/false));
+    } else
+      FoundArguments.TypeAwareViable = false;
+  }
+
+  ImplicitAllocationArguments UnalignedArguments(
+      *this, /*TypeIdentityArg=*/nullptr, AllocationSizeExpr,
+      /*AlignArg=*/nullptr, /*IsMSVCCompatibilityFallback=*/false);
+  ImplicitAllocationArguments AlignedArguments(
+      *this, /*TypeIdentityArg=*/nullptr, AllocationSizeExpr,
+      AllocationAlignmentExpr, /*IsMSVCCompatibilityFallback=*/false);
+
+  // 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 (IAP.PassAlignment == AlignedAllocationMode::Yes)
+    FoundArguments.Candidates.push_back(AlignedArguments);
+  FoundArguments.Candidates.push_back(UnalignedArguments);
----------------
igorkudrin wrote:

This, and also adjusting the order of diagnostic messages.

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

Reply via email to