Skip to content

Commit ba2b942

Browse files
committed
A pile of refactoring that i think cleans up the logic
1 parent 4622fb5 commit ba2b942

File tree

6 files changed

+80
-97
lines changed

6 files changed

+80
-97
lines changed

clang/include/clang/AST/Type.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2639,7 +2639,10 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
26392639
bool isTypeIdentitySpecialization() const; // std::type_identity<X> for any X
26402640
bool isDestroyingDeleteT() const;
26412641

2642-
TemplateDecl *tryGetSpecializedTemplateDecl() const;
2642+
/// If this type is a template specialization return the TemplateDecl
2643+
/// that was specialized. It this is not a template specialization,
2644+
/// returns NULL.
2645+
TemplateDecl *getSpecializedTemplateDecl() const;
26432646

26442647
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
26452648
bool is##Id##Type() const;

clang/lib/AST/DeclCXX.cpp

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,37 +2533,46 @@ bool CXXMethodDecl::isUsualDeallocationFunction(
25332533
getOverloadedOperator() != OO_Array_Delete)
25342534
return false;
25352535

2536-
bool IsTypeAware = isTypeAwareOperatorNewOrDelete();
2537-
if (IsTypeAware && isVariadic())
2538-
return false;
2536+
if (isTypeAwareOperatorNewOrDelete()) {
2537+
// A variadic type aware allocation function is not a usual deallocation
2538+
// function
2539+
if (isVariadic())
2540+
return false;
25392541

2540-
// C++ [basic.stc.dynamic.deallocation]p2:
2541-
// Pre-type aware allocators:
2542-
// A template instance is never a usual deallocation function,
2543-
// regardless of its signature.
2544-
// Pending final C++26 text:
2545-
// A template instance is only a usual deallocation function if it
2546-
// is a type aware deallocation function, only the type-identity
2547-
// parameter is dependent, and there is no parameter pack in the argument
2548-
// list.
2549-
if (FunctionTemplateDecl *PrimaryTemplate = getPrimaryTemplate()) {
2550-
if (!IsTypeAware)
2551-
// Stop early on if the specialization is not explicitly type aware
2542+
// Type aware deallocation functions are only usual if they only accept the
2543+
// mandatory arguments
2544+
if (getNumParams() != FunctionDecl::RequiredTypeAwareDeleteParameterCount)
25522545
return false;
25532546

2547+
FunctionTemplateDecl *PrimaryTemplate = getPrimaryTemplate();
2548+
if (!PrimaryTemplate)
2549+
return true;
2550+
2551+
// A template instance is is only a usual deallocation function if it has a
2552+
// type-identity parameter, the type-identity parameter is a dependent type
2553+
// (i.e. the type-identity parameter is of type std::type_identity<U> where
2554+
// U shall be a dependent type), and the type-identity parameter is the only
2555+
// dependent parameter, and there are no template packs in the parameter
2556+
// list.
25542557
FunctionDecl *SpecializedDecl = PrimaryTemplate->getTemplatedDecl();
2555-
// A type aware allocation function template is only valid if the first
2556-
// parameter is dependent
25572558
if (!SpecializedDecl->getParamDecl(0)->getType()->isDependentType())
25582559
return false;
2559-
2560-
// and none of the other parameters are dependent
25612560
for (unsigned Idx = 1; Idx < getNumParams(); ++Idx) {
25622561
if (SpecializedDecl->getParamDecl(Idx)->getType()->isDependentType())
25632562
return false;
25642563
}
2564+
return true;
25652565
}
25662566

2567+
// C++ [basic.stc.dynamic.deallocation]p2:
2568+
// A template instance is never a usual deallocation function,
2569+
// regardless of its signature.
2570+
// Post-P2719 adoption:
2571+
// A template instance is is only a usual deallocation function if it has a
2572+
// type-identity parameter
2573+
if (getPrimaryTemplate())
2574+
return false;
2575+
25672576
// C++ [basic.stc.dynamic.deallocation]p2:
25682577
// If a class T has a member deallocation function named operator delete
25692578
// with exactly one parameter, then that function is a usual (non-placement)
@@ -2572,18 +2581,13 @@ bool CXXMethodDecl::isUsualDeallocationFunction(
25722581
return true;
25732582
unsigned UsualParams = 1;
25742583

2575-
if (IsTypeAware)
2576-
++UsualParams;
2577-
25782584
// C++ P0722:
25792585
// A destroying operator delete is a usual deallocation function if
25802586
// removing the std::destroying_delete_t parameter and changing the
25812587
// first parameter type from T* to void* results in the signature of
25822588
// a usual deallocation function.
2583-
if (isDestroyingOperatorDelete()) {
2584-
assert(!IsTypeAware);
2589+
if (isDestroyingOperatorDelete())
25852590
++UsualParams;
2586-
}
25872591

25882592
// C++ <=14 [basic.stc.dynamic.deallocation]p2:
25892593
// [...] If class T does not declare such an operator delete but does
@@ -2595,11 +2599,6 @@ bool CXXMethodDecl::isUsualDeallocationFunction(
25952599
// (void* [, size_t] [, std::align_val_t] [, ...])
25962600
// and all such functions are usual deallocation functions. It's not clear
25972601
// that allowing varargs functions was intentional.
2598-
//
2599-
// P2719 extends usual deallocation functions to permit
2600-
// (type_identity<U>, void*, size_t, std::align_val_t)
2601-
// it does not permit variadic or template parameter packs
2602-
26032602
ASTContext &Context = getASTContext();
26042603
if (UsualParams < getNumParams() &&
26052604
Context.hasSameUnqualifiedType(getParamDecl(UsualParams)->getType(),
@@ -2619,8 +2618,8 @@ bool CXXMethodDecl::isUsualDeallocationFunction(
26192618
// FIXME(EricWF): Destroying Delete should be a language option. How do we
26202619
// handle when destroying delete is used prior to C++17?
26212620
if (Context.getLangOpts().CPlusPlus17 ||
2622-
Context.getLangOpts().AlignedAllocation || isDestroyingOperatorDelete() ||
2623-
IsTypeAware)
2621+
Context.getLangOpts().AlignedAllocation ||
2622+
isDestroyingOperatorDelete())
26242623
return true;
26252624

26262625
// This function is a usual deallocation function if there are no

clang/lib/AST/Type.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3140,7 +3140,7 @@ bool Type::isDestroyingDeleteT() const {
31403140
RD->getIdentifier()->isStr("destroying_delete_t");
31413141
}
31423142

3143-
TemplateDecl *Type::tryGetSpecializedTemplateDecl() const {
3143+
TemplateDecl *Type::getSpecializedTemplateDecl() const {
31443144
auto UnderlyingType = getCanonicalTypeInternal();
31453145
if (auto *TST = UnderlyingType->getAs<TemplateSpecializationType>())
31463146
return TST->getTemplateName().getAsTemplateDecl();
@@ -3152,7 +3152,7 @@ TemplateDecl *Type::tryGetSpecializedTemplateDecl() const {
31523152
}
31533153

31543154
bool Type::isTypeIdentitySpecialization() const {
3155-
const TemplateDecl *STDecl = tryGetSpecializedTemplateDecl();
3155+
const TemplateDecl *STDecl = getSpecializedTemplateDecl();
31563156
if (!STDecl)
31573157
return false;
31583158
IdentifierInfo *II = STDecl->getIdentifier();

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,15 +1844,16 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
18441844
auto Params = getUsualDeleteParams(DeleteFD);
18451845
auto ParamTypeIt = DeleteFTy->param_type_begin();
18461846

1847-
llvm::SmallVector<llvm::AllocaInst *, 2> TagAllocas;
1847+
std::optional<llvm::AllocaInst *> TagAlloca;
18481848
auto EmitTag = [&](QualType TagType, const char *TagName) {
1849+
assert(!TagAlloca);
18491850
llvm::Type *Ty = getTypes().ConvertType(TagType);
18501851
CharUnits Align = CGM.getNaturalTypeAlignment(TagType);
18511852
llvm::AllocaInst *TagAllocation = CreateTempAlloca(Ty, TagName);
18521853
TagAllocation->setAlignment(Align.getAsAlign());
18531854
DeleteArgs.add(RValue::getAggregate(Address(TagAllocation, Ty, Align)),
18541855
TagType);
1855-
TagAllocas.push_back(TagAllocation);
1856+
TagAlloca = TagAllocation;
18561857
};
18571858

18581859
// Pass std::type_identity tag if present
@@ -1903,14 +1904,11 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
19031904
// Emit the call to delete.
19041905
EmitNewDeleteCall(*this, DeleteFD, DeleteFTy, DeleteArgs);
19051906

1906-
// If call argument lowering didn't use the tag arguments allocas we remove
1907-
// them
1908-
for (auto *TagAlloca : TagAllocas) {
1909-
if (TagAlloca && TagAlloca->use_empty())
1910-
TagAlloca->eraseFromParent();
1911-
}
1907+
// If call argument lowering didn't use a generated tag argument alloca we
1908+
// remove them
1909+
if (TagAlloca && (*TagAlloca)->use_empty())
1910+
(*TagAlloca)->eraseFromParent();
19121911
}
1913-
19141912
namespace {
19151913
/// Calls the given 'operator delete' on a single object.
19161914
struct CallObjectDelete final : EHScopeStack::Cleanup {

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16422,8 +16422,8 @@ enum class AllocationOperatorKind { New, Delete };
1642216422
static inline bool CheckOperatorNewDeleteTypes(
1642316423
Sema &SemaRef, const FunctionDecl *FnDecl,
1642416424
AllocationOperatorKind OperatorKind, CanQualType ExpectedResultType,
16425-
CanQualType ExpectedFirstParamType, unsigned DependentParamTypeDiag,
16426-
unsigned InvalidParamTypeDiag, unsigned *MinimumNonDefaultArgs) {
16425+
CanQualType ExpectedSizeOrAddressParamType, unsigned DependentParamTypeDiag,
16426+
unsigned InvalidParamTypeDiag) {
1642716427
auto NormalizeType = [&SemaRef](QualType T) {
1642816428
if (SemaRef.getLangOpts().OpenCLCPlusPlus) {
1642916429
// The operator is valid on any address space for OpenCL.
@@ -16467,18 +16467,26 @@ static inline bool CheckOperatorNewDeleteTypes(
1646716467
++MinimumMandatoryArgumentCount;
1646816468
++SizeParameterIndex;
1646916469
}
16470-
*MinimumNonDefaultArgs = MinimumMandatoryArgumentCount;
1647116470

1647216471
if (FnDecl->getNumParams() < MinimumMandatoryArgumentCount)
1647316472
return SemaRef.Diag(FnDecl->getLocation(),
1647416473
diag::err_operator_new_delete_too_few_parameters)
1647516474
<< IsPotentiallyTypeAware << IsDestroyingDelete
1647616475
<< FnDecl->getDeclName() << MinimumMandatoryArgumentCount;
1647716476

16477+
for (unsigned Idx = 0; Idx < MinimumMandatoryArgumentCount; ++Idx) {
16478+
const ParmVarDecl *ParamDecl = FnDecl->getParamDecl(Idx);
16479+
if (ParamDecl->hasDefaultArg())
16480+
return SemaRef.Diag(FnDecl->getLocation(),
16481+
diag::err_operator_new_default_arg)
16482+
<< FnDecl->getDeclName() << Idx << ParamDecl->getDefaultArgRange();
16483+
}
16484+
1647816485
auto *FnType = FnDecl->getType()->castAs<FunctionType>();
1647916486
QualType CanResultType = NormalizeType(FnType->getReturnType());
1648016487
QualType CanExpectedResultType = NormalizeType(ExpectedResultType);
16481-
QualType CanExpectedFirstParamType = NormalizeType(ExpectedFirstParamType);
16488+
QualType CanExpectedSizeOrAddressParamType =
16489+
NormalizeType(ExpectedSizeOrAddressParamType);
1648216490

1648316491
// Check that the result type is what we expect.
1648416492
if (CanResultType != CanExpectedResultType) {
@@ -16520,12 +16528,11 @@ static inline bool CheckOperatorNewDeleteTypes(
1652016528
};
1652116529

1652216530
// Check that the first parameter type is what we expect.
16523-
if (CheckType(FirstNonTypeParam, CanExpectedFirstParamType, "size_t"))
16531+
if (CheckType(FirstNonTypeParam, CanExpectedSizeOrAddressParamType, "size_t"))
1652416532
return true;
1652516533

16526-
// If the first parameter type is a type_identity specialization
16527-
// we need to ensure the remaining mandatory parameters are present
16528-
// and have the correct type
16534+
// If the first parameter type is not a type-identity we're done, otherwise
16535+
// we need to ensure the size and alignment parameters have the correct type
1652916536
if (!IsPotentiallyTypeAware)
1653016537
return false;
1653116538

@@ -16554,24 +16561,10 @@ CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) {
1655416561
// C++ [basic.stc.dynamic.allocation]p1:
1655516562
// The return type shall be void*. The first parameter shall have type
1655616563
// std::size_t.
16557-
if (CheckOperatorNewDeleteTypes(SemaRef, FnDecl, AllocationOperatorKind::New,
16558-
SemaRef.Context.VoidPtrTy, SizeTy,
16559-
diag::err_operator_new_dependent_param_type,
16560-
diag::err_operator_new_param_type,
16561-
&MinimumNonDefaultArgs))
16562-
return true;
16563-
assert(MinimumNonDefaultArgs > 0 && MinimumNonDefaultArgs <= 4);
16564-
// C++ [basic.stc.dynamic.allocation]p1:
16565-
// The first parameter shall not have an associated default argument.
16566-
for (unsigned Idx = 0; Idx < MinimumNonDefaultArgs; ++Idx) {
16567-
const ParmVarDecl *ParamDecl = FnDecl->getParamDecl(Idx);
16568-
if (ParamDecl->hasDefaultArg()) {
16569-
return SemaRef.Diag(FnDecl->getLocation(),
16570-
diag::err_operator_new_default_arg)
16571-
<< FnDecl->getDeclName() << Idx << ParamDecl->getDefaultArgRange();
16572-
}
16573-
}
16574-
return false;
16564+
return CheckOperatorNewDeleteTypes(
16565+
SemaRef, FnDecl, AllocationOperatorKind::New, SemaRef.Context.VoidPtrTy,
16566+
SizeTy, diag::err_operator_new_dependent_param_type,
16567+
diag::err_operator_new_param_type);
1657516568
}
1657616569

1657716570
static bool
@@ -16590,20 +16583,12 @@ CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
1659016583
SemaRef.Context.getRecordType(MD->getParent())));
1659116584
};
1659216585

16593-
// C++ P0722:
16594-
// Within a class C, the first parameter of a destroying operator delete
16595-
// shall be of type C *. The first parameter of any other deallocation
16596-
// function shall be of type void *.
16597-
CanQualType ExpectedFirstParamType =
16598-
MD && MD->isDestroyingOperatorDelete()
16599-
? SemaRef.Context.getCanonicalType(SemaRef.Context.getPointerType(
16600-
SemaRef.Context.getRecordType(MD->getParent())))
16601-
: SemaRef.Context.VoidPtrTy;
16602-
1660316586
// C++ P2719: A destroying operator delete cannot be type aware
1660416587
// so as a QoL we actually check for this explicitly
16605-
bool IsTypeAwareClassMethod = MD && MD->isTypeAwareOperatorNewOrDelete();
16606-
if (IsTypeAwareClassMethod && MD->getNumParams() > 1) {
16588+
bool IsPotentiallyTypeAwareClassMethod =
16589+
MD && MD->getNumParams() > 0 &&
16590+
MD->getParamDecl(0)->getType()->isTypeIdentitySpecialization();
16591+
if (IsPotentiallyTypeAwareClassMethod) {
1660716592
QualType AddressParamType =
1660816593
SemaRef.Context.getCanonicalType(MD->getParamDecl(1)->getType());
1660916594
if (AddressParamType != SemaRef.Context.VoidPtrTy &&
@@ -16626,19 +16611,25 @@ CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
1662616611
}
1662716612
}
1662816613

16629-
unsigned MinimumNonDefaultArgs = 0;
16614+
// C++ P0722:
16615+
// Within a class C, the first parameter of a destroying operator delete
16616+
// shall be of type C *. The first parameter of any other deallocation
16617+
// function shall be of type void *.
16618+
CanQualType ExpectedAddressParamType =
16619+
MD && MD->isDestroyingOperatorDelete()
16620+
? SemaRef.Context.getCanonicalType(SemaRef.Context.getPointerType(
16621+
SemaRef.Context.getRecordType(MD->getParent())))
16622+
: SemaRef.Context.VoidPtrTy;
16623+
1663016624
// C++ [basic.stc.dynamic.deallocation]p2:
1663116625
// Each deallocation function shall return void
1663216626
if (CheckOperatorNewDeleteTypes(
1663316627
SemaRef, FnDecl, AllocationOperatorKind::Delete,
16634-
SemaRef.Context.VoidTy, ExpectedFirstParamType,
16628+
SemaRef.Context.VoidTy, ExpectedAddressParamType,
1663516629
diag::err_operator_delete_dependent_param_type,
16636-
diag::err_operator_delete_param_type, &MinimumNonDefaultArgs))
16630+
diag::err_operator_delete_param_type))
1663716631
return true;
1663816632

16639-
assert(MinimumNonDefaultArgs > 0 &&
16640-
MinimumNonDefaultArgs <=
16641-
FunctionDecl::RequiredTypeAwareDeleteParameterCount);
1664216633
// C++ P0722:
1664316634
// A destroying operator delete shall be a usual deallocation function.
1664416635
if (MD && !MD->getParent()->isDependentContext() &&
@@ -16649,14 +16640,6 @@ CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) {
1664916640
return true;
1665016641
}
1665116642
}
16652-
for (unsigned Idx = 0; Idx < MinimumNonDefaultArgs; ++Idx) {
16653-
const ParmVarDecl *ParamDecl = FnDecl->getParamDecl(Idx);
16654-
if (ParamDecl->hasDefaultArg()) {
16655-
return SemaRef.Diag(FnDecl->getLocation(),
16656-
diag::err_operator_new_default_arg)
16657-
<< FnDecl->getDeclName() << ParamDecl->getDefaultArgRange();
16658-
}
16659-
}
1666016643

1666116644
return false;
1666216645
}

clang/lib/Sema/SemaInit.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9902,7 +9902,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
99029902
// C++ [over.match.class.deduct#3]: ..., the defining-type-id of A must be
99039903
// of the form
99049904
// [typename] [nested-name-specifier] [template] simple-template-id
9905-
auto SpecializedTD = UnderlyingType->tryGetSpecializedTemplateDecl();
9905+
auto SpecializedTD = UnderlyingType->getSpecializedTemplateDecl();
99069906
Template = dyn_cast_or_null<ClassTemplateDecl>(SpecializedTD);
99079907
}
99089908
}

0 commit comments

Comments
 (0)