Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5200,6 +5200,15 @@ 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); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -8285,6 +8285,7 @@ } } + DiagnoseUseOfDecl(OperatorDelete, Loc); MarkFunctionReferenced(Loc, OperatorDelete); Destructor->setOperatorDelete(OperatorDelete, ThisArg); } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -66,6 +66,12 @@ 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 @@ // The function 'main' shall not be used within a program. if (cast(D)->isMain()) Diag(Loc, diag::ext_main_used); + + diagnoseUnavailableAlignedAllocation(*cast(D), Loc); } // See if this is an auto-typed variable whose initializer we are parsing. Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -1745,28 +1745,33 @@ 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. +bool +Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const { + if (!getLangOpts().AlignedAllocationUnavailable) + return false; if (FD.isDefined()) - return; - + return false; bool IsAligned = false; - if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) { - const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple(); + 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. +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); } } @@ -2150,13 +2155,11 @@ 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: @@ -3406,8 +3409,7 @@ } } - 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 @@ -3540,6 +3542,9 @@ 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(); Index: test/CXX/drs/dr2xx.cpp =================================================================== --- test/CXX/drs/dr2xx.cpp +++ test/CXX/drs/dr2xx.cpp @@ -718,7 +718,7 @@ 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 @@ }; 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 { Index: test/SemaCXX/unavailable_aligned_allocation.cpp =================================================================== --- test/SemaCXX/unavailable_aligned_allocation.cpp +++ test/SemaCXX/unavailable_aligned_allocation.cpp @@ -124,7 +124,73 @@ // expected-note@-20 2 {{if you supply your own aligned allocation functions}} #endif -// No errors if user-defined aligned allocation functions are available. +// 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 + void *operator new(std::size_t __sz, std::align_val_t) { static char array[256]; return &array;