================
@@ -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);
----------------
ojhunt wrote:
right - I could do it with file check I guess? Maybe a task for tomorrow :D
This is great because it will make it super easy to add new implicit arguments
to operator new! :D :D :D (please, no one do this)
https://github.com/llvm/llvm-project/pull/211482
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits