[clang] [RFC] Initial implementation of P2719 (PR #113510)
Oliver Hunt via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 31 16:55:58 PDT 2025
================
@@ -16327,79 +16531,181 @@ static CanQualType RemoveAddressSpaceFromPtr(Sema &SemaRef,
PtrTy->getPointeeType().getUnqualifiedType(), PtrQuals)));
}
-static inline bool
-CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl,
- CanQualType ExpectedResultType,
- CanQualType ExpectedFirstParamType,
- unsigned DependentParamTypeDiag,
- unsigned InvalidParamTypeDiag) {
- QualType ResultType =
- FnDecl->getType()->castAs<FunctionType>()->getReturnType();
+enum class AllocationOperatorKind { New, Delete };
+
+static bool IsPotentiallyTypeAwareOperatorNewOrDelete(Sema &SemaRef,
+ const FunctionDecl *FD,
+ bool *WasMalformed) {
+ const Decl *MalformedDecl = nullptr;
+ if (FD->getNumParams() > 0 &&
+ SemaRef.isStdTypeIdentity(FD->getParamDecl(0)->getType(),
+ /*TypeArgument=*/nullptr, &MalformedDecl))
+ return true;
- if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
- // The operator is valid on any address space for OpenCL.
- // Drop address space from actual and expected result types.
- if (const auto *PtrTy = ResultType->getAs<PointerType>())
- ResultType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy);
+ if (!MalformedDecl)
+ return false;
+
+ if (WasMalformed)
+ *WasMalformed = true;
+
+ // SemaRef.Diag(MalformedDecl->getLocation(),
+ // diag::err_malformed_std_class_template) << "type_identity";
+ return true;
+}
+
+static bool isDestroyingDeleteT(QualType Type) {
+ auto *RD = Type->getAsCXXRecordDecl();
+ return RD && RD->isInStdNamespace() && RD->getIdentifier() &&
+ RD->getIdentifier()->isStr("destroying_delete_t");
+}
+
+static bool IsPotentiallyDestroyingOperatorDelete(Sema &SemaRef,
+ const FunctionDecl *FD) {
+ // C++ P0722:
+ // Within a class C, a single object deallocation function with signature
+ // (T, std::destroying_delete_t, <more params>)
+ // is a destroying operator delete.
+ bool IsPotentiallyTypeAware = IsPotentiallyTypeAwareOperatorNewOrDelete(
+ SemaRef, FD, /*WasMalformed=*/nullptr);
+ unsigned DestroyingDeleteIdx = IsPotentiallyTypeAware + /* address */ 1;
+ return isa<CXXMethodDecl>(FD) && FD->getOverloadedOperator() == OO_Delete &&
+ FD->getNumParams() > DestroyingDeleteIdx &&
+ isDestroyingDeleteT(FD->getParamDecl(DestroyingDeleteIdx)->getType());
+}
+
+static inline bool CheckOperatorNewDeleteTypes(
+ Sema &SemaRef, FunctionDecl *FnDecl, AllocationOperatorKind OperatorKind,
+ CanQualType ExpectedResultType, CanQualType ExpectedSizeOrAddressParamType,
+ unsigned DependentParamTypeDiag, unsigned InvalidParamTypeDiag) {
+ auto NormalizeType = [&SemaRef](QualType T) {
+ if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
+ // The operator is valid on any address space for OpenCL.
+ // Drop address space from actual and expected result types.
+ if (const auto PtrTy = T->template getAs<PointerType>())
+ T = RemoveAddressSpaceFromPtr(SemaRef, PtrTy);
+ }
+ return SemaRef.Context.getCanonicalType(T);
+ };
- if (auto ExpectedPtrTy = ExpectedResultType->getAs<PointerType>())
- ExpectedResultType = RemoveAddressSpaceFromPtr(SemaRef, ExpectedPtrTy);
+ const unsigned NumParams = FnDecl->getNumParams();
+ unsigned FirstNonTypeParam = 0;
+ bool MalformedTypeIdentity = false;
+ bool IsPotentiallyTypeAware = IsPotentiallyTypeAwareOperatorNewOrDelete(
+ SemaRef, FnDecl, &MalformedTypeIdentity);
+ unsigned MinimumMandatoryArgumentCount = 1;
+ unsigned SizeParameterIndex = 0;
+ if (IsPotentiallyTypeAware) {
+ if (!FnDecl->isTemplateInstantiation()) {
+ unsigned DiagID = SemaRef.getLangOpts().CPlusPlus26
+ ? diag::warn_cxx26_type_aware_allocators
+ : diag::ext_cxx26_type_aware_allocators;
+ SemaRef.Diag(FnDecl->getLocation(), DiagID);
+ }
+
+ if (OperatorKind == AllocationOperatorKind::New) {
+ SizeParameterIndex = 1;
+ MinimumMandatoryArgumentCount =
+ FunctionDecl::RequiredTypeAwareNewParameterCount;
+ } else {
+ SizeParameterIndex = 2;
+ MinimumMandatoryArgumentCount =
+ FunctionDecl::RequiredTypeAwareDeleteParameterCount;
+ }
+ FirstNonTypeParam = 1;
}
+ bool IsPotentiallyDestroyingDelete =
+ IsPotentiallyDestroyingOperatorDelete(SemaRef, FnDecl);
+
+ if (IsPotentiallyDestroyingDelete) {
+ ++MinimumMandatoryArgumentCount;
+ ++SizeParameterIndex;
+ }
+
+ if (NumParams < MinimumMandatoryArgumentCount)
+ return SemaRef.Diag(FnDecl->getLocation(),
+ diag::err_operator_new_delete_too_few_parameters)
+ << IsPotentiallyTypeAware << IsPotentiallyDestroyingDelete
+ << FnDecl->getDeclName() << MinimumMandatoryArgumentCount;
----------------
ojhunt wrote:
The decl name is being used to form the sentence "type aware X requires matching Y in same scope" e.g "type aware 'operator new' requires matching 'operator delete' in the same scope" and similar.
https://github.com/llvm/llvm-project/pull/113510
More information about the cfe-commits
mailing list