================
@@ -2918,55 +2880,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 (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);
+
+ // The MSVC global fallback path
----------------
ojhunt wrote:
I just made an optional buffer for the msvc LookupResult to avoid the
modification of the initial lookup result (and constified the initial lookup
result out of caution).
This allows the diagnostics to become much better, but I have actively avoided
any changes to output wherever possible.
One thing this does change is that we now just note that msvc fallback failed
(if it did), but now actually correctly names the function it was trying to
call initially.
https://github.com/llvm/llvm-project/pull/211482
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits