forked from OSchip/llvm-project
[Sema] Produce diagnostics when C++17 aligned allocation/deallocation
functions that are unavailable on Darwin are explicitly called or called from deleting destructors. rdar://problem/40736230 Differential Revision: https://reviews.llvm.org/D47757 llvm-svn: 349890
This commit is contained in:
parent
b6dac89c87
commit
71645c2feb
|
@ -5202,6 +5202,15 @@ public:
|
|||
SourceRange DirectInitRange,
|
||||
Expr *Initializer);
|
||||
|
||||
/// Determine whether \p FD is an aligned allocation or deallocation
|
||||
/// function that is unavailable.
|
||||
bool isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const;
|
||||
|
||||
/// Produce diagnostics if \p FD is an aligned allocation or deallocation
|
||||
/// function that is unavailable.
|
||||
void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
|
||||
SourceLocation Loc);
|
||||
|
||||
bool CheckAllocatedType(QualType AllocType, SourceLocation Loc,
|
||||
SourceRange R);
|
||||
|
||||
|
|
|
@ -8288,6 +8288,7 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) {
|
|||
}
|
||||
}
|
||||
|
||||
DiagnoseUseOfDecl(OperatorDelete, Loc);
|
||||
MarkFunctionReferenced(Loc, OperatorDelete);
|
||||
Destructor->setOperatorDelete(OperatorDelete, ThisArg);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,12 @@ bool Sema::CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid) {
|
|||
if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
|
||||
DeduceReturnType(FD, SourceLocation(), /*Diagnose*/ false))
|
||||
return false;
|
||||
|
||||
// See if this is an aligned allocation/deallocation function that is
|
||||
// unavailable.
|
||||
if (TreatUnavailableAsInvalid &&
|
||||
isUnavailableAlignedAllocationFunction(*FD))
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if this function is unavailable.
|
||||
|
@ -228,6 +234,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
|||
// The function 'main' shall not be used within a program.
|
||||
if (cast<FunctionDecl>(D)->isMain())
|
||||
Diag(Loc, diag::ext_main_used);
|
||||
|
||||
diagnoseUnavailableAlignedAllocation(*cast<FunctionDecl>(D), Loc);
|
||||
}
|
||||
|
||||
// See if this is an auto-typed variable whose initializer we are parsing.
|
||||
|
|
|
@ -1744,28 +1744,33 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const {
|
||||
if (!getLangOpts().AlignedAllocationUnavailable)
|
||||
return false;
|
||||
if (FD.isDefined())
|
||||
return false;
|
||||
bool IsAligned = false;
|
||||
if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Emit a diagnostic if an aligned allocation/deallocation function that is not
|
||||
// implemented in the standard library is selected.
|
||||
static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
|
||||
SourceLocation Loc, bool IsDelete,
|
||||
Sema &S) {
|
||||
if (!S.getLangOpts().AlignedAllocationUnavailable)
|
||||
return;
|
||||
|
||||
// Return if there is a definition.
|
||||
if (FD.isDefined())
|
||||
return;
|
||||
|
||||
bool IsAligned = false;
|
||||
if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) {
|
||||
const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple();
|
||||
void Sema::diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD,
|
||||
SourceLocation Loc) {
|
||||
if (isUnavailableAlignedAllocationFunction(FD)) {
|
||||
const llvm::Triple &T = getASTContext().getTargetInfo().getTriple();
|
||||
StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling(
|
||||
S.getASTContext().getTargetInfo().getPlatformName());
|
||||
getASTContext().getTargetInfo().getPlatformName());
|
||||
|
||||
S.Diag(Loc, diag::err_aligned_allocation_unavailable)
|
||||
OverloadedOperatorKind Kind = FD.getDeclName().getCXXOverloadedOperator();
|
||||
bool IsDelete = Kind == OO_Delete || Kind == OO_Array_Delete;
|
||||
Diag(Loc, diag::err_aligned_allocation_unavailable)
|
||||
<< IsDelete << FD.getType().getAsString() << OSName
|
||||
<< alignedAllocMinVersion(T.getOS()).getAsString();
|
||||
S.Diag(Loc, diag::note_silence_aligned_allocation_unavailable);
|
||||
Diag(Loc, diag::note_silence_aligned_allocation_unavailable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2149,13 +2154,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
|||
if (DiagnoseUseOfDecl(OperatorNew, StartLoc))
|
||||
return ExprError();
|
||||
MarkFunctionReferenced(StartLoc, OperatorNew);
|
||||
diagnoseUnavailableAlignedAllocation(*OperatorNew, StartLoc, false, *this);
|
||||
}
|
||||
if (OperatorDelete) {
|
||||
if (DiagnoseUseOfDecl(OperatorDelete, StartLoc))
|
||||
return ExprError();
|
||||
MarkFunctionReferenced(StartLoc, OperatorDelete);
|
||||
diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this);
|
||||
}
|
||||
|
||||
// C++0x [expr.new]p17:
|
||||
|
@ -3405,8 +3408,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
|
|||
}
|
||||
}
|
||||
|
||||
diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true,
|
||||
*this);
|
||||
DiagnoseUseOfDecl(OperatorDelete, StartLoc);
|
||||
|
||||
// Convert the operand to the type of the first parameter of operator
|
||||
// delete. This is only necessary if we selected a destroying operator
|
||||
|
@ -3539,6 +3541,9 @@ Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult,
|
|||
return ExprError();
|
||||
assert(OperatorNewOrDelete && "should be found");
|
||||
|
||||
DiagnoseUseOfDecl(OperatorNewOrDelete, TheCall->getExprLoc());
|
||||
MarkFunctionReferenced(TheCall->getExprLoc(), OperatorNewOrDelete);
|
||||
|
||||
TheCall->setType(OperatorNewOrDelete->getReturnType());
|
||||
for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) {
|
||||
QualType ParamTy = OperatorNewOrDelete->getParamDecl(i)->getType();
|
||||
|
|
|
@ -718,7 +718,7 @@ namespace dr261 { // dr261: no
|
|||
A() {}
|
||||
};
|
||||
|
||||
// FIXME: These are ill-formed, with a required diagnostic, for the same
|
||||
// FIXME: This is ill-formed, with a required diagnostic, for the same
|
||||
// reason.
|
||||
struct B {
|
||||
inline void operator delete(void*) __attribute__((unused));
|
||||
|
@ -726,7 +726,7 @@ namespace dr261 { // dr261: no
|
|||
};
|
||||
struct C {
|
||||
inline void operator delete(void*) __attribute__((unused));
|
||||
virtual ~C() {}
|
||||
virtual ~C() {} // expected-warning {{'operator delete' was marked unused but was used}}
|
||||
};
|
||||
|
||||
struct D {
|
||||
|
|
|
@ -124,6 +124,73 @@ void testOveralignedCheckOS() {
|
|||
// expected-note@-20 2 {{if you supply your own aligned allocation functions}}
|
||||
#endif
|
||||
|
||||
// Test that diagnostics are produced when an unavailable aligned deallocation
|
||||
// function is called from a deleting destructor.
|
||||
struct alignas(256) OveralignedS2 {
|
||||
int a[4];
|
||||
virtual ~OveralignedS2();
|
||||
};
|
||||
|
||||
OveralignedS2::~OveralignedS2() {}
|
||||
|
||||
#ifdef NO_ERRORS
|
||||
// expected-no-diagnostics
|
||||
#else
|
||||
#if defined(IOS)
|
||||
// expected-error@-6 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on iOS 11 or newer}}}
|
||||
// expected-note@-7 {{if you supply your own aligned allocation functions}}
|
||||
#elif defined(TVOS)
|
||||
// expected-error@-9 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on tvOS 11 or newer}}}
|
||||
// expected-note@-10 {{if you supply your own aligned allocation functions}}
|
||||
#elif defined(WATCHOS)
|
||||
// expected-error@-12 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on watchOS 4 or newer}}}
|
||||
// expected-note@-13 {{if you supply your own aligned allocation functions}}
|
||||
#else
|
||||
// expected-error@-15 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on macOS 10.13 or newer}}}
|
||||
// expected-note@-16 {{if you supply your own aligned allocation functions}}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void testExplicitOperatorNewDelete() {
|
||||
void *p = operator new(128);
|
||||
operator delete(p);
|
||||
p = operator new[](128);
|
||||
operator delete[](p);
|
||||
p = __builtin_operator_new(128);
|
||||
__builtin_operator_delete(p);
|
||||
}
|
||||
|
||||
void testExplicitOperatorNewDeleteOveraligned() {
|
||||
void *p = operator new(128, (std::align_val_t)64);
|
||||
operator delete(p, (std::align_val_t)64);
|
||||
p = operator new[](128, (std::align_val_t)64);
|
||||
operator delete[](p, (std::align_val_t)64);
|
||||
p = __builtin_operator_new(128, (std::align_val_t)64);
|
||||
__builtin_operator_delete(p, (std::align_val_t)64);
|
||||
}
|
||||
|
||||
#ifdef NO_ERRORS
|
||||
// expected-no-diagnostics
|
||||
#else
|
||||
// expected-error@-11 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
|
||||
// expected-note@-12 {{if you supply your own aligned allocation functions}}
|
||||
|
||||
// expected-error@-13 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
|
||||
// expected-note@-14 {{if you supply your own aligned allocation functions}}
|
||||
|
||||
// expected-error@-15 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
|
||||
// expected-note@-16 {{if you supply your own aligned allocation functions}}
|
||||
|
||||
// expected-error@-17 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
|
||||
// expected-note@-18 {{if you supply your own aligned allocation functions}}
|
||||
|
||||
// expected-error@-19 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' is only available on}}
|
||||
// expected-note@-20 {{if you supply your own aligned allocation functions}}
|
||||
|
||||
// expected-error@-21 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' is only available on}}
|
||||
// expected-note@-22 {{if you supply your own aligned allocation functions}}
|
||||
#endif
|
||||
|
||||
// No errors if user-defined aligned allocation functions are available.
|
||||
void *operator new(std::size_t __sz, std::align_val_t) {
|
||||
static char array[256];
|
||||
|
|
Loading…
Reference in New Issue