================
@@ -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:
I meant that in `diagnoseNoViableFunctionForAllocationOverloadResolution()`, we
should print the diagnostics in the same order as we tried the candidates.
Right now, we try aligned candidates first, and then unaligned. For cases from
CWG2282, the order will be opposite. Not a big deal, anyway.
https://github.com/llvm/llvm-project/pull/211482
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits