Index: cfe/trunk/include/clang/AST/Decl.h =================================================================== --- cfe/trunk/include/clang/AST/Decl.h +++ cfe/trunk/include/clang/AST/Decl.h @@ -2019,7 +2019,10 @@ /// These functions have special behavior under C++1y [expr.new]: /// An implementation is allowed to omit a call to a replaceable global /// allocation function. [...] - bool isReplaceableGlobalAllocationFunction() const; + /// + /// If this function is an aligned allocation/deallocation function, return + /// true through IsAligned. + bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const; /// Compute the language linkage. LanguageLinkage getLanguageLinkage() const; Index: cfe/trunk/include/clang/Basic/DiagnosticGroups.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td @@ -311,6 +311,7 @@ def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; def : DiagGroup<"effc++", [NonVirtualDtor]>; def OveralignedType : DiagGroup<"over-aligned">; +def AlignedAllocationUnavailable : DiagGroup<"aligned-allocation-unavailable">; def OldStyleCast : DiagGroup<"old-style-cast">; def : DiagGroup<"old-style-definition">; def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -6407,6 +6407,12 @@ "type %0 requires %1 bytes of alignment and the default allocator only " "guarantees %2 bytes">, InGroup, DefaultIgnore; +def warn_aligned_allocation_unavailable :Warning< + "aligned %select{allocation|deallocation}0 function of type '%1' possibly " + "unavailable on %2">, InGroup, DefaultError; +def note_silence_unligned_allocation_unavailable : Note< + "if you supply your own aligned allocation functions, use " + "-Wno-aligned-allocation-unavailable to silence this diagnostic">; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " Index: cfe/trunk/include/clang/Basic/LangOptions.def =================================================================== --- cfe/trunk/include/clang/Basic/LangOptions.def +++ cfe/trunk/include/clang/Basic/LangOptions.def @@ -199,6 +199,7 @@ LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") LANGOPT(AlignedAllocation , 1, 0, "aligned allocation") +LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable") LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'") LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts") BENIGN_LANGOPT(ModulesCodegen , 1, 0, "Modules code generation") Index: cfe/trunk/include/clang/Driver/CC1Options.td =================================================================== --- cfe/trunk/include/clang/Driver/CC1Options.td +++ cfe/trunk/include/clang/Driver/CC1Options.td @@ -568,6 +568,9 @@ def fno_pch_timestamp : Flag<["-"], "fno-pch-timestamp">, HelpText<"Disable inclusion of timestamp in precompiled headers">; +def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">, + HelpText<"Aligned allocation/deallocation functions are unavailable">; + //===----------------------------------------------------------------------===// // Language Options //===----------------------------------------------------------------------===// Index: cfe/trunk/lib/AST/Decl.cpp =================================================================== --- cfe/trunk/lib/AST/Decl.cpp +++ cfe/trunk/lib/AST/Decl.cpp @@ -2630,7 +2630,7 @@ return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy); } -bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { +bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const { if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) return false; if (getDeclName().getCXXOverloadedOperator() != OO_New && @@ -2676,8 +2676,11 @@ // In C++17, the next parameter can be a 'std::align_val_t' for aligned // new/delete. - if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) + if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) { + if (IsAligned) + *IsAligned = true; Consume(); + } // Finally, if this is not a sized delete, the final parameter can // be a 'const std::nothrow_t&'. Index: cfe/trunk/lib/Driver/ToolChains/Darwin.h =================================================================== --- cfe/trunk/lib/Driver/ToolChains/Darwin.h +++ cfe/trunk/lib/Driver/ToolChains/Darwin.h @@ -384,6 +384,14 @@ return TargetVersion < VersionTuple(V0, V1, V2); } + /// Return true if c++17 aligned allocation/deallocation functions are not + /// implemented in the c++ standard library of the deployment target we are + /// targeting. + bool isAlignedAllocationUnavailable() const; + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + StringRef getPlatformFamily() const; static StringRef getSDKName(StringRef isysroot); StringRef getOSLibraryNameSuffix() const; Index: cfe/trunk/lib/Driver/ToolChains/Darwin.cpp =================================================================== --- cfe/trunk/lib/Driver/ToolChains/Darwin.cpp +++ cfe/trunk/lib/Driver/ToolChains/Darwin.cpp @@ -1667,6 +1667,27 @@ AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); } +bool Darwin::isAlignedAllocationUnavailable() const { + switch (TargetPlatform) { + case MacOS: // Earlier than 10.13. + return TargetVersion < VersionTuple(10U, 13U, 0U); + case IPhoneOS: + case IPhoneOSSimulator: + case TvOS: + case TvOSSimulator: // Earlier than 11.0. + return TargetVersion < VersionTuple(11U, 0U, 0U); + case WatchOS: + case WatchOSSimulator: // Earlier than 4.0. + return TargetVersion < VersionTuple(4U, 0U, 0U); + } +} + +void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + if (isAlignedAllocationUnavailable()) + CC1Args.push_back("-faligned-alloc-unavailable"); +} + DerivedArgList * Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const { Index: cfe/trunk/lib/Frontend/CompilerInvocation.cpp =================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp @@ -2106,6 +2106,8 @@ Opts.AlignedAllocation = Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation, Opts.AlignedAllocation); + Opts.AlignedAllocationUnavailable = + Opts.AlignedAllocation && Args.hasArg(OPT_aligned_alloc_unavailable); Opts.NewAlignOverride = getLastArgIntValue(Args, OPT_fnew_alignment_EQ, 0, Diags); if (Opts.NewAlignOverride && !llvm::isPowerOf2_32(Opts.NewAlignOverride)) { Index: cfe/trunk/lib/Sema/SemaExprCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp @@ -1646,6 +1646,27 @@ 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) { + S.Diag(Loc, diag::warn_aligned_allocation_unavailable) + << IsDelete << FD.getType().getAsString() + << S.getASTContext().getTargetInfo().getTriple().str(); + S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable); + } +} + ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, @@ -2023,11 +2044,13 @@ 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: @@ -3243,6 +3266,9 @@ PDiag(diag::err_access_dtor) << PointeeElem); } } + + diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, + *this); } CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( Index: cfe/trunk/test/Driver/unavailable_aligned_allocation.cpp =================================================================== --- cfe/trunk/test/Driver/unavailable_aligned_allocation.cpp +++ cfe/trunk/test/Driver/unavailable_aligned_allocation.cpp @@ -0,0 +1,54 @@ +// RUN: %clang -target x86_64-apple-macosx10.12 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target arm64-apple-ios10 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target arm64-apple-tvos10 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target thumbv7-apple-watchos3 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.13 -mios-simulator-version-min=10 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.13 -mtvos-simulator-version-min=10 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.13 -mwatchos-simulator-version-min=3 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// UNAVAILABLE: "-faligned-alloc-unavailable" + +// RUN: %clang -target x86_64-apple-macosx10.13 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target arm64-apple-ios11 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target arm64-apple-tvos11 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target armv7k-apple-watchos4 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-unknown-linux-gnu -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.12 -mios-simulator-version-min=11 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.12 -mtvos-simulator-version-min=11 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.12 -mwatchos-simulator-version-min=4 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// AVAILABLE-NOT: "-faligned-alloc-unavailable" Index: cfe/trunk/test/SemaCXX/unavailable_aligned_allocation.cpp =================================================================== --- cfe/trunk/test/SemaCXX/unavailable_aligned_allocation.cpp +++ cfe/trunk/test/SemaCXX/unavailable_aligned_allocation.cpp @@ -0,0 +1,109 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -faligned-alloc-unavailable -std=c++1z -verify %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++1z -verify -DNO_ERRORS %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -faligned-allocation -faligned-alloc-unavailable -std=c++14 -verify %s + +namespace std { + typedef decltype(sizeof(0)) size_t; + enum class align_val_t : std::size_t {}; + struct nothrow_t {}; + nothrow_t nothrow; +} + +void *operator new(std::size_t __sz, const std::nothrow_t&) noexcept; +void *operator new[](std::size_t __sz, const std::nothrow_t&) noexcept; + +void *operator new(std::size_t __sz, std::align_val_t, const std::nothrow_t&) noexcept; +void *operator new[](std::size_t __sz, std::align_val_t, const std::nothrow_t&) noexcept; +void operator delete(void *, std::align_val_t, const std::nothrow_t&); +void operator delete[](void *, std::align_val_t, const std::nothrow_t&); +void operator delete(void*, std::size_t, std::align_val_t) noexcept; +void operator delete[](void*, std::size_t, std::align_val_t) noexcept; + +void *operator new(std::size_t, std::align_val_t, long long); + +struct alignas(256) OveralignedS { + int x[16]; +}; + +struct S { + int x[16]; +}; + +void test() { + auto *p = new S; + delete p; + p = new (std::nothrow) S; + + auto *pa = new S[4]; + delete[] pa; + pa = new (std::nothrow) S[4]; +} + +void testOveraligned() { + auto *p = new OveralignedS; + p = new ((std::align_val_t)8) OveralignedS; + delete p; + p = new (std::nothrow) OveralignedS; + + auto *pa = new OveralignedS[4]; + pa = new ((std::align_val_t)8) OveralignedS[4]; + delete[] pa; + pa = new (std::nothrow) OveralignedS[4]; + // No error here since it is not calling a replaceable allocation function. + p = new ((std::align_val_t)8, 10LL) OveralignedS; +} + +#ifdef NO_ERRORS +// expected-no-diagnostics +#else +// expected-error@-16 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' possibly unavailable on}} +// expected-note@-17 {{if you supply your own aligned allocation functions}} +// expected-error@-18 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' possibly unavailable on}} +// expected-note@-19 {{if you supply your own aligned allocation functions}} + +// expected-error@-20 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' possibly unavailable on}} +// expected-note@-21 {{if you supply your own aligned allocation functions}} +// expected-error@-22 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' possibly unavailable on}} +// expected-note@-23 {{if you supply your own aligned allocation functions}} + +// expected-error@-24 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' possibly unavailable on}} +// expected-note@-25 {{if you supply your own aligned allocation functions}} + +// expected-error@-26 {{aligned allocation function of type 'void *(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept' possibly unavailable on}} +// expected-note@-27 {{if you supply your own aligned allocation functions}} +// expected-error@-28 {{aligned deallocation function of type 'void (void *, std::align_val_t, const std::nothrow_t &) noexcept' possibly unavailable on}} +// expected-note@-29 {{if you supply your own aligned allocation functions}} + +// expected-error@-29 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' possibly unavailable on}} +// expected-note@-30 {{if you supply your own aligned allocation functions}} +// expected-error@-31 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' possibly unavailable on}} +// expected-note@-32 {{if you supply your own aligned allocation functions}} + +// expected-error@-33 {{aligned allocation function of type 'void *(unsigned long, enum std::align_val_t)' possibly unavailable on}} +// expected-note@-34 {{if you supply your own aligned allocation functions}} +// expected-error@-35 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' possibly unavailable on}} +// expected-note@-36 {{if you supply your own aligned allocation functions}} + +// expected-error@-37 {{aligned deallocation function of type 'void (void *, enum std::align_val_t) noexcept' possibly unavailable on}} +// expected-note@-38 {{if you supply your own aligned allocation functions}} + +// expected-error@-39 {{aligned allocation function of type 'void *(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept' possibly unavailable on}} +// expected-note@-40 {{if you supply your own aligned allocation functions}} +// expected-error@-41 {{aligned deallocation function of type 'void (void *, std::align_val_t, const std::nothrow_t &) noexcept' possibly unavailable on}} +// expected-note@-42 {{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]; + return &array; +} + +void operator delete(void *p, std::align_val_t) { +} + +void testOveraligned2() { + auto p = new ((std::align_val_t)8) OveralignedS; + delete p; +}