Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -34,6 +34,7 @@ #include "clang/Basic/Visibility.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" @@ -2147,8 +2148,19 @@ /// This function must be an allocation or deallocation function. bool isReservedGlobalPlacementOperator() const; + enum class AllocationFunctionClassification : unsigned { + None = 0, + Allocation = 1 << 0, + Deallocation = 1 << 1, + Aligned = 1 << 2, + Sized = 1 << 3, + Array = 1 << 4, + LLVM_BITMASK_LARGEST_ENUMERATOR = Array, + }; + /// Determines whether this function is one of the replaceable - /// global allocation functions: + /// global allocation functions, and classifies the kind of allocation or + /// deallocation function it is: /// void *operator new(size_t); /// void *operator new(size_t, const std::nothrow_t &) noexcept; /// void *operator new[](size_t); @@ -2163,9 +2175,13 @@ /// An implementation is allowed to omit a call to a replaceable global /// allocation function. [...] /// - /// If this function is an aligned allocation/deallocation function, return - /// true through IsAligned. - bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const; + AllocationFunctionClassification + classifyReplaceableGlobalAllocationFunction() const; + + bool isReplaceableGlobalAllocationFunction() const { + return classifyReplaceableGlobalAllocationFunction() != + AllocationFunctionClassification::None; + } /// Determine whether this is a destroying operator delete. bool isDestroyingOperatorDelete() const; @@ -2517,6 +2533,9 @@ } }; +// Used by FunctionDecl::AllocationFunctionClassification +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + /// Represents a member of a struct/union/class. class FieldDecl : public DeclaratorDecl, public Mergeable { unsigned BitField : 1; Index: include/clang/Basic/AlignedAllocation.h =================================================================== --- include/clang/Basic/AlignedAllocation.h +++ /dev/null @@ -1,44 +0,0 @@ -//===--- AlignedAllocation.h - Aligned Allocation ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// Defines a function that returns the minimum OS versions supporting -/// C++17's aligned allocation functions. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H -#define LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H - -#include "clang/Basic/VersionTuple.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/ErrorHandling.h" - -namespace clang { - -inline VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) { - switch (OS) { - default: - break; - case llvm::Triple::Darwin: - case llvm::Triple::MacOSX: // Earliest supporting version is 10.13. - return VersionTuple(10U, 13U); - case llvm::Triple::IOS: - case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0. - return VersionTuple(11U); - case llvm::Triple::WatchOS: // Earliest supporting version is 4.0.0. - return VersionTuple(4U); - } - - llvm_unreachable("Unexpected OS"); -} - -} // end namespace clang - -#endif // LLVM_CLANG_BASIC_ALIGNED_ALLOCATION_H Index: include/clang/Basic/AllocationAvailability.h =================================================================== --- /dev/null +++ include/clang/Basic/AllocationAvailability.h @@ -0,0 +1,62 @@ +//===--- AllocationAvailability.h - Allocation Availability -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines a functions that return the minimum OS versions supporting various +/// C++ allocation functions. Including C++17's aligned allocation and C++14's +/// sized deallocation. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ALLOCATION_AVAILABILITY_H +#define LLVM_CLANG_BASIC_ALLOCATION_AVAILABILITY_H + +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +inline VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) { + switch (OS) { + default: + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: // Earliest supporting version is 10.13. + return VersionTuple(10U, 13U); + case llvm::Triple::IOS: + case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0. + return VersionTuple(11U); + case llvm::Triple::WatchOS: // Earliest supporting version is 4.0.0. + return VersionTuple(4U); + } + + llvm_unreachable("Unexpected OS"); +} + +inline VersionTuple sizedDeallocMinVersion(llvm::Triple::OSType OS) { + switch (OS) { + default: + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: // Earliest supporting version is 10.12. + return VersionTuple(10U, 12U); + case llvm::Triple::IOS: + case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0. + return VersionTuple(10U); + case llvm::Triple::WatchOS: // Earliest supporting version is 4.0.0. + return VersionTuple(3U); + } + + llvm_unreachable("Unexpected OS"); +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_ALLOCATION_AVAILABILITY_H Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -352,7 +352,6 @@ def NullPointerArithmetic : DiagGroup<"null-pointer-arithmetic">; 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: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6419,12 +6419,14 @@ "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' is only " - "available on %2 %3 or newer">, 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_allocation_function_unavailable : Error< + "%select{aligned allocation|aligned deallocation|sized deallocation}0 function " + "of type '%1' is only available on %2 %3 or newer">; +def note_silence_allocation_function_unavailable : Note< + "if you supply your own " + "%select{aligned allocation|aligned allocation|sized deallocation}0 functions, use " + "%select{-faligned-allocation|-faligned-allocation|-fsized-deallocation}0 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: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -213,8 +213,10 @@ LANGOPT(CUDARelocatableDeviceCode, 1, 0, "generate relocatable device code") LANGOPT(SizedDeallocation , 1, 0, "sized deallocation") +LANGOPT(SizedDeallocationUnavailable, 1, 0, "sized deallocation functions are unavailable") 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: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -612,6 +612,9 @@ def aligned_alloc_unavailable : Flag<["-"], "faligned-alloc-unavailable">, HelpText<"Aligned allocation/deallocation functions are unavailable">; +def sized_deallocation_unavailable : Flag<["-"], "fsized-deallocation-unavailable">, + HelpText<"Sized deallocation functions are unavailable">; + //===----------------------------------------------------------------------===// // Language Options Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1443,7 +1443,8 @@ Group; def fsized_deallocation : Flag<["-"], "fsized-deallocation">, Flags<[CC1Option]>, HelpText<"Enable C++14 sized global deallocation functions">, Group; -def fno_sized_deallocation: Flag<["-"], "fno-sized-deallocation">, Group; +def fno_sized_deallocation: Flag<["-"], "fno-sized-deallocation">, Flags<[CC1Option]>, + HelpText<"Disable C++14 sized global deallocation functions">, Group; def faligned_allocation : Flag<["-"], "faligned-allocation">, Flags<[CC1Option]>, HelpText<"Enable C++17 aligned allocation functions">, Group; def fno_aligned_allocation: Flag<["-"], "fno-aligned-allocation">, Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5205,6 +5205,9 @@ FunctionDecl *FindDeallocationFunctionForDestructor(SourceLocation StartLoc, CXXRecordDecl *RD); + void DiagnoseUnavailableAllocationFunction(const FunctionDecl *FD, + SourceLocation Loc); + /// ActOnCXXDelete - Parsed a C++ 'delete' expression ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -2746,30 +2746,41 @@ return (proto->getParamType(1).getCanonicalType() == Context.VoidPtrTy); } -bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const { +FunctionDecl::AllocationFunctionClassification +FunctionDecl::classifyReplaceableGlobalAllocationFunction() const { + using AFC = AllocationFunctionClassification; if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) - return false; - if (getDeclName().getCXXOverloadedOperator() != OO_New && - getDeclName().getCXXOverloadedOperator() != OO_Delete && - getDeclName().getCXXOverloadedOperator() != OO_Array_New && - getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) - return false; + return AFC::None; + OverloadedOperatorKind OpKind = getDeclName().getCXXOverloadedOperator(); + std::pair Classifications[] = { + {OO_New, AFC::Allocation}, + {OO_Array_New, AFC::Allocation | AFC::Array}, + {OO_Delete, AFC::Deallocation}, + {OO_Array_Delete, AFC::Deallocation | AFC::Array}}; + auto It = llvm::find_if(Classifications, + [&](std::pair Info) { + return Info.first == OpKind; + }); + if (It == std::end(Classifications)) + return AFC::None; + + AFC Result = It->second; if (isa(getDeclContext())) - return false; + return AFC::None; // This can only fail for an invalid 'operator new' declaration. if (!getDeclContext()->getRedeclContext()->isTranslationUnit()) - return false; + return AFC::None; const auto *FPT = getType()->castAs(); if (FPT->getNumParams() == 0 || FPT->getNumParams() > 3 || FPT->isVariadic()) - return false; + return AFC::None; // If this is a single-parameter function, it must be a replaceable global // allocation or deallocation function. if (FPT->getNumParams() == 1) - return true; + return Result; unsigned Params = 1; QualType Ty = FPT->getParamType(Params); @@ -2781,35 +2792,33 @@ }; // In C++14, the next parameter can be a 'std::size_t' for sized delete. - bool IsSizedDelete = false; - if (Ctx.getLangOpts().SizedDeallocation && - (getDeclName().getCXXOverloadedOperator() == OO_Delete || - getDeclName().getCXXOverloadedOperator() == OO_Array_Delete) && + if (Ctx.getLangOpts().SizedDeallocation && bool(Result & AFC::Deallocation) && Ctx.hasSameType(Ty, Ctx.getSizeType())) { - IsSizedDelete = true; + Result |= AFC::Sized; Consume(); } // 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 (IsAligned) - *IsAligned = true; + Result |= AFC::Aligned; Consume(); } // Finally, if this is not a sized delete, the final parameter can // be a 'const std::nothrow_t&'. - if (!IsSizedDelete && !Ty.isNull() && Ty->isReferenceType()) { + if (!bool(Result & AFC::Sized) && !Ty.isNull() && Ty->isReferenceType()) { Ty = Ty->getPointeeType(); if (Ty.getCVRQualifiers() != Qualifiers::Const) - return false; + return AFC::None; const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); if (RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace()) Consume(); } - return Params == FPT->getNumParams(); + if (Params != FPT->getNumParams()) + return AFC::None; + return Result; } bool FunctionDecl::isDestroyingOperatorDelete() const { Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4357,12 +4357,15 @@ options::OPT_fno_relaxed_template_template_args, false)) CmdArgs.push_back("-frelaxed-template-template-args"); - // -fsized-deallocation is off by default, as it is an ABI-breaking change for - // most platforms. - if (Args.hasFlag(options::OPT_fsized_deallocation, - options::OPT_fno_sized_deallocation, false)) - CmdArgs.push_back("-fsized-deallocation"); - + // -fsized-deallocation is on by default in C++14 onwards and otherwise off + // by default. + if (Arg *A = Args.getLastArg(options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation)) { + if (A->getOption().matches(options::OPT_fno_sized_deallocation)) + CmdArgs.push_back("-fno-sized-deallocation"); + else + CmdArgs.push_back("-fsized-deallocation"); + } // -faligned-allocation is on by default in C++17 onwards and otherwise off // by default. if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation, Index: lib/Driver/ToolChains/Darwin.h =================================================================== --- lib/Driver/ToolChains/Darwin.h +++ lib/Driver/ToolChains/Darwin.h @@ -413,6 +413,11 @@ /// targeting. bool isAlignedAllocationUnavailable() const; + /// Return true if C++14 sized deallocation functions are not + /// implemented in the C++ standard library of the deployment target we are + /// targeting. + bool isSizedDeallocationUnavailable() const; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; Index: lib/Driver/ToolChains/Darwin.cpp =================================================================== --- lib/Driver/ToolChains/Darwin.cpp +++ lib/Driver/ToolChains/Darwin.cpp @@ -10,7 +10,7 @@ #include "Darwin.h" #include "Arch/ARM.h" #include "CommonArgs.h" -#include "clang/Basic/AlignedAllocation.h" +#include "clang/Basic/AllocationAvailability.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Driver/Compilation.h" @@ -1994,32 +1994,44 @@ AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, RLO_IsEmbedded); } -bool Darwin::isAlignedAllocationUnavailable() const { - llvm::Triple::OSType OS; +static llvm::Triple::OSType getOSType(const Darwin &TC) { + switch (TC.TargetPlatform) { + case Darwin::MacOS: + return llvm::Triple::MacOSX; + case Darwin::IPhoneOS: + return llvm::Triple::IOS; + case Darwin::TvOS: + return llvm::Triple::TvOS; + case Darwin::WatchOS: + return llvm::Triple::WatchOS; + } + llvm_unreachable("unhandled case"); +} - switch (TargetPlatform) { - case MacOS: // Earlier than 10.13. - OS = llvm::Triple::MacOSX; - break; - case IPhoneOS: - OS = llvm::Triple::IOS; - break; - case TvOS: // Earlier than 11.0. - OS = llvm::Triple::TvOS; - break; - case WatchOS: // Earlier than 4.0. - OS = llvm::Triple::WatchOS; - break; - } +bool Darwin::isAlignedAllocationUnavailable() const { + return TargetVersion < alignedAllocMinVersion(getOSType(*this)); +} - return TargetVersion < alignedAllocMinVersion(OS); +bool Darwin::isSizedDeallocationUnavailable() const { + return TargetVersion < sizedDeallocMinVersion(getOSType(*this)); } void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const { - if (isAlignedAllocationUnavailable()) - CC1Args.push_back("-faligned-alloc-unavailable"); + // Pass "-faligned-alloc-unavailable" only when the user hasn't manually + // enabled or disabled aligned allocations and hasn't specified a custom + // standard library installation. + if (!DriverArgs.hasArgNoClaim(options::OPT_nostdincxx)) { + if (!DriverArgs.hasArgNoClaim(options::OPT_faligned_allocation, + options::OPT_fno_aligned_allocation) && + isAlignedAllocationUnavailable()) + CC1Args.push_back("-faligned-alloc-unavailable"); + if (!DriverArgs.hasArgNoClaim(options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation) && + isSizedDeallocationUnavailable()) + CC1Args.push_back("-fsized-deallocation-unavailable"); + } } DerivedArgList * Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1980,6 +1980,7 @@ Opts.GNUKeywords = Opts.GNUMode; Opts.CXXOperatorNames = Opts.CPlusPlus; + Opts.SizedDeallocation = Opts.CPlusPlus14; Opts.AlignedAllocation = Opts.CPlusPlus17; Opts.DollarIdents = !Opts.AsmPreprocessor; @@ -2399,7 +2400,11 @@ Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin); Opts.RelaxedTemplateTemplateArgs = Args.hasArg(OPT_frelaxed_template_template_args); - Opts.SizedDeallocation = Args.hasArg(OPT_fsized_deallocation); + Opts.SizedDeallocation = + Args.hasFlag(OPT_fsized_deallocation, OPT_fno_sized_deallocation, + Opts.SizedDeallocation); + Opts.SizedDeallocationUnavailable = + Opts.SizedDeallocation && Args.hasArg(OPT_sized_deallocation_unavailable); Opts.AlignedAllocation = Args.hasFlag(OPT_faligned_allocation, OPT_fno_aligned_allocation, Opts.AlignedAllocation); Index: lib/Frontend/InitPreprocessor.cpp =================================================================== --- lib/Frontend/InitPreprocessor.cpp +++ lib/Frontend/InitPreprocessor.cpp @@ -530,7 +530,7 @@ Builder.defineMacro("__cpp_aggregate_nsdmi", "201304"); Builder.defineMacro("__cpp_variable_templates", "201304"); } - if (LangOpts.SizedDeallocation) + if (LangOpts.SizedDeallocation && !LangOpts.SizedDeallocationUnavailable) Builder.defineMacro("__cpp_sized_deallocation", "201309"); // C++17 features. @@ -551,7 +551,7 @@ Builder.defineMacro("__cpp_nontype_template_args", "201411"); Builder.defineMacro("__cpp_fold_expressions", "201603"); } - if (LangOpts.AlignedAllocation) + if (LangOpts.AlignedAllocation && !LangOpts.AlignedAllocationUnavailable) Builder.defineMacro("__cpp_aligned_new", "201606"); // TS features. Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -222,10 +222,14 @@ Pos->second.clear(); } + const auto *FD = cast(D); + // C++ [basic.start.main]p3: // The function 'main' shall not be used within a program. - if (cast(D)->isMain()) + if (FD->isMain()) Diag(Loc, diag::ext_main_used); + + // DiagnoseUnavailableAllocationFunction(FD, 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 @@ -12,7 +12,6 @@ /// //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" @@ -24,7 +23,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" -#include "clang/Basic/AlignedAllocation.h" +#include "clang/Basic/AllocationAvailability.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -34,6 +33,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" @@ -1679,29 +1679,50 @@ return false; } +enum AllocationFunctionKind { + AFK_AlignedAllocation, + AFK_AlignedDeallocation, + AFK_SizedDeallocation +}; + // 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; - +void Sema::DiagnoseUnavailableAllocationFunction(const FunctionDecl *FD, + SourceLocation Loc) { // Return if there is a definition. - if (FD.isDefined()) + if (FD->isDefined()) return; - bool IsAligned = false; - if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) { - const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple(); - StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling( - S.getASTContext().getTargetInfo().getPlatformName()); + using AFC = FunctionDecl::AllocationFunctionClassification; + AFC Classify = FD->classifyReplaceableGlobalAllocationFunction(); + if (Classify == AFC::None) + return; - S.Diag(Loc, diag::warn_aligned_allocation_unavailable) - << IsDelete << FD.getType().getAsString() << OSName - << alignedAllocMinVersion(T.getOS()).getAsString(); - S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable); - } + // Figure out if the found allocation/deallocation function is unavailable + // and gather the required information for the diagnostic. + AllocationFunctionKind AllocKind; + if (bool(Classify & AFC::Aligned) && + getLangOpts().AlignedAllocationUnavailable) + AllocKind = bool(Classify & AFC::Allocation) ? AFK_AlignedAllocation + : AFK_AlignedDeallocation; + else if (bool(Classify & AFC::Sized) && + getLangOpts().SizedDeallocationUnavailable) + AllocKind = AFK_SizedDeallocation; + else + return; // nothing to do + + const llvm::Triple &T = Context.getTargetInfo().getTriple(); + VersionTuple MinVer = AllocKind == AFK_SizedDeallocation + ? sizedDeallocMinVersion(T.getOS()) + : alignedAllocMinVersion(T.getOS()); + StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling( + Context.getTargetInfo().getPlatformName()); + + Diag(Loc, diag::err_allocation_function_unavailable) + << (unsigned)AllocKind << FD->getType().getAsString() << OSName + << MinVer.getAsString(); + Diag(Loc, diag::note_silence_allocation_function_unavailable) + << (unsigned)AllocKind; } ExprResult @@ -2091,13 +2112,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: @@ -3316,6 +3335,8 @@ Overaligned, DeleteName); } + if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) + return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of destructor if we're going to call it. @@ -3329,9 +3350,6 @@ } } - diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, - *this); - // Convert the operand to the type of the first parameter of operator // delete. This is only necessary if we selected a destroying operator // delete that we are going to call (non-virtually); converting to void* Index: test/CodeGenCXX/cxx1y-sized-deallocation.cpp =================================================================== --- test/CodeGenCXX/cxx1y-sized-deallocation.cpp +++ test/CodeGenCXX/cxx1y-sized-deallocation.cpp @@ -1,12 +1,12 @@ // Check that delete exprs call the sized deallocation function if -// -fsized-deallocation is passed in both C++11 and C++14. +// -fsized-deallocation is passed in C++11 or the dialect is C++14. // RUN: %clang_cc1 -std=c++11 -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s -// RUN: %clang_cc1 -std=c++14 -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++14 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s -// Check that we don't used sized deallocation without -fsized-deallocation and -// C++14. +// Check that we don't used sized deallocation without -fsized-deallocation in C++11 +// or when -fno-sized-deallocation is passed in C++14. // RUN: %clang_cc1 -std=c++11 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNSIZED -// RUN: %clang_cc1 -std=c++14 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNSIZED +// RUN: %clang_cc1 -std=c++14 -fno-sized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNSIZED // CHECK-UNSIZED-NOT: _ZdlPvm // CHECK-UNSIZED-NOT: _ZdaPvm Index: test/CodeGenCXX/cxx1z-aligned-allocation.cpp =================================================================== --- test/CodeGenCXX/cxx1z-aligned-allocation.cpp +++ test/CodeGenCXX/cxx1z-aligned-allocation.cpp @@ -1,10 +1,10 @@ // Check that delete exprs call aligned (de)allocation functions if // -faligned-allocation is passed in both C++11 and C++14. // RUN: %clang_cc1 -std=c++11 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s -// RUN: %clang_cc1 -std=c++14 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s -// RUN: %clang_cc1 -std=c++1z -fexceptions -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++14 -fexceptions -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++1z -fexceptions %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s -// RUN: %clang_cc1 -std=c++1z -fexceptions -fsized-deallocation %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s --check-prefix=CHECK-MS +// RUN: %clang_cc1 -std=c++1z -fexceptions %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s --check-prefix=CHECK-MS // Check that we don't used aligned (de)allocation without -faligned-allocation or C++1z. // RUN: %clang_cc1 -std=c++14 -DUNALIGNED -fexceptions %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNALIGNED Index: test/Driver/unavailable_aligned_allocation.cpp =================================================================== --- test/Driver/unavailable_aligned_allocation.cpp +++ test/Driver/unavailable_aligned_allocation.cpp @@ -51,4 +51,16 @@ // RUN: -c -### %s 2>&1 \ // RUN: | FileCheck %s -check-prefix=AVAILABLE // +// Check that passing -faligned-allocation, -fno-aligned-allocation, or +// -nostdinc++ stops the driver from passing -faligned-alloc-unavailable to cc1. +// +// RUN: %clang -target x86_64-apple-macosx10.12 -faligned-allocation -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.12 -fno-aligned-allocation -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.12 -nostdinc++ -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE + // AVAILABLE-NOT: "-faligned-alloc-unavailable" Index: test/Driver/unavailable_sized_deallocation.cpp =================================================================== --- /dev/null +++ test/Driver/unavailable_sized_deallocation.cpp @@ -0,0 +1,66 @@ +// RUN: %clang -target x86_64-apple-macosx10.11 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target arm64-apple-ios9 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target arm64-apple-tvos9 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target thumbv7-apple-watchos2 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target x86_64-apple-darwin -mios-simulator-version-min=9 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target x86_64-apple-darwin -mtvos-simulator-version-min=9 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// RUN: %clang -target x86_64-apple-darwin -mwatchos-simulator-version-min=2 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=UNAVAILABLE +// +// UNAVAILABLE: "-fsized-deallocation-unavailable" + +// RUN: %clang -target x86_64-apple-macosx10.12 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target arm64-apple-ios10 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target arm64-apple-tvos10 -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target armv7k-apple-watchos3 -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-darwin -mios-simulator-version-min=10 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-darwin -mtvos-simulator-version-min=10 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-darwin -mwatchos-simulator-version-min=3 \ +// RUN: -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// Check that passing -fsized-deallocation, -fno-sized-deallocation, or +// -nostdinc++ stops the driver from passing -fsized-deallocation-unavailable to cc1. +// +// RUN: %clang -target x86_64-apple-macosx10.11 -fsized-deallocation -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.11 -fno-sized-deallocation -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE +// +// RUN: %clang -target x86_64-apple-macosx10.11 -nostdinc++ -c -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix=AVAILABLE + +// AVAILABLE-NOT: "-fsized-deallocation-unavailable" Index: test/Lexer/aligned-allocation.cpp =================================================================== --- /dev/null +++ test/Lexer/aligned-allocation.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++17 -verify %s \ +// RUN: -DEXPECT_DEFINED +// +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++17 -verify %s \ +// RUN: -faligned-alloc-unavailable +// +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++17 -verify %s \ +// RUN: -faligned-allocation -faligned-alloc-unavailable + +// Test that __cpp_aligned_new is not defined when CC1 is passed +// -faligned-alloc-unavailable by the Darwin driver, even when aligned +// allocation is actually enabled. + +// expected-no-diagnostics +#ifdef EXPECT_DEFINED +# ifndef __cpp_aligned_new +# error "__cpp_aligned_new" should be defined +# endif +#else +# ifdef __cpp_aligned_new +# error "__cpp_aligned_new" should not be defined +# endif +#endif Index: test/Lexer/cxx-features.cpp =================================================================== --- test/Lexer/cxx-features.cpp +++ test/Lexer/cxx-features.cpp @@ -1,12 +1,12 @@ // RUN: %clang_cc1 -std=c++98 -fcxx-exceptions -verify %s // RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -verify %s -// RUN: %clang_cc1 -std=c++1y -fcxx-exceptions -fsized-deallocation -verify %s -// RUN: %clang_cc1 -std=c++14 -fcxx-exceptions -fsized-deallocation -verify %s -// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fsized-deallocation -verify %s -// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fsized-deallocation -fconcepts-ts -DCONCEPTS_TS=1 -verify %s -// RUN: %clang_cc1 -fno-rtti -fno-threadsafe-statics -verify %s -DNO_EXCEPTIONS -DNO_RTTI -DNO_THREADSAFE_STATICS -fsized-deallocation -// RUN: %clang_cc1 -fcoroutines-ts -DNO_EXCEPTIONS -DCOROUTINES -verify -fsized-deallocation %s -// RUN: %clang_cc1 -fchar8_t -DNO_EXCEPTIONS -DCHAR8_T -verify -fsized-deallocation %s +// RUN: %clang_cc1 -std=c++1y -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++14 -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fconcepts-ts -DCONCEPTS_TS=1 -verify %s +// RUN: %clang_cc1 -fno-rtti -fno-threadsafe-statics -verify %s -DNO_EXCEPTIONS -DNO_RTTI -DNO_THREADSAFE_STATICS +// RUN: %clang_cc1 -fcoroutines-ts -DNO_EXCEPTIONS -DCOROUTINES -verify %s +// RUN: %clang_cc1 -fchar8_t -DNO_EXCEPTIONS -DCHAR8_T -verify %s // expected-no-diagnostics Index: test/Lexer/sized-deallocation.cpp =================================================================== --- /dev/null +++ test/Lexer/sized-deallocation.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -fexceptions -std=c++14 -verify %s \ +// RUN: -DEXPECT_DEFINED +// +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.13.0 -fexceptions -std=c++14 -verify %s \ +// RUN: -fsized-deallocation-unavailable +// +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12.0 -fexceptions -std=c++14 -verify %s \ +// RUN: -fsized-deallocation -fsized-deallocation-unavailable + +// Test that __cpp_sized_deallocation is not defined when CC1 is passed +// -fsized-deallocation-unavailable by the Darwin driver, even when sized +// deallocation is actually enabled. + +// expected-no-diagnostics +#ifdef EXPECT_DEFINED +#ifndef __cpp_sized_deallocation +#error "__cpp_sized_deallocation" should be defined +#endif +#else +#ifdef __cpp_sized_deallocation +#error "__cpp_sized_deallocation" should not be defined +#endif +#endif Index: test/SemaCXX/MicrosoftExtensions.cpp =================================================================== --- test/SemaCXX/MicrosoftExtensions.cpp +++ test/SemaCXX/MicrosoftExtensions.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -DTEST1 +// RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -fno-sized-deallocation -DTEST1 // RUN: %clang_cc1 -std=c++98 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -DTEST1 // RUN: %clang_cc1 -std=c++11 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fms-extensions -fexceptions -fcxx-exceptions -DTEST1 // RUN: %clang_cc1 %s -triple i686-pc-win32 -fsyntax-only -Wmicrosoft -Wc++11-extensions -Wno-long-long -verify -fexceptions -fcxx-exceptions -DTEST2 Index: test/SemaCXX/builtin-operator-new-delete.cpp =================================================================== --- test/SemaCXX/builtin-operator-new-delete.cpp +++ test/SemaCXX/builtin-operator-new-delete.cpp @@ -64,6 +64,9 @@ void *operator new(size_t, void*, bool) throw(); // expected-note 1+ {{candidate function}} void *operator new[](size_t, void*, bool) throw(); +void operator delete(void *, size_t, std::align_val_t); // expected-note 1+ {{candidate}} +void operator delete[](void *, size_t, std::align_val_t); + void *NP = 0; void test_typo_in_args() { Index: test/SemaCXX/cxx1y-sized-deallocation.cpp =================================================================== --- test/SemaCXX/cxx1y-sized-deallocation.cpp +++ test/SemaCXX/cxx1y-sized-deallocation.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++1y -verify %s -fsized-deallocation -fexceptions -fcxx-exceptions +// RUN: %clang_cc1 -std=c++1y -verify %s -fexceptions -fcxx-exceptions using size_t = decltype(sizeof(0)); void operator delete(void *, size_t) noexcept; // expected-note {{'operator delete' declared here}} Index: test/SemaCXX/test.cpp =================================================================== --- /dev/null +++ test/SemaCXX/test.cpp @@ -0,0 +1,26 @@ + +namespace std { +typedef decltype(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +struct nothrow_t {}; +nothrow_t nothrow; +} // namespace std + +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, const std::nothrow_t &) noexcept; +void *operator new[](std::size_t __sz, const std::nothrow_t &) noexcept; +void operator delete(void *, std::size_t) noexcept; +void operator delete[](void *, std::size_t) noexcept; + +void *operator new(std::size_t, std::size_t, long long); + +struct S { + int x[16]; +}; + +void test() { + void *v = operator new(42); + operator delete(v, 42); +} Index: test/SemaCXX/unavailable_sized_deallocation.cpp =================================================================== --- /dev/null +++ test/SemaCXX/unavailable_sized_deallocation.cpp @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -fexceptions -fsized-deallocation-unavailable -std=c++14 -verify %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -fexceptions -std=c++14 -verify -DNO_ERRORS %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11.0 -fexceptions -fsized-deallocation -fsized-deallocation-unavailable -std=c++14 -verify %s +// RUN: %clang_cc1 -triple arm64-apple-ios9.0.0 -fexceptions -fsized-deallocation-unavailable -std=c++14 -verify -DIOS %s +// RUN: %clang_cc1 -triple arm64-apple-ios9.0.0 -fexceptions -std=c++14 -verify -DNO_ERRORS %s +// RUN: %clang_cc1 -triple arm64-apple-tvos9.0.0 -fexceptions -fsized-deallocation-unavailable -std=c++14 -verify -DTVOS %s +// RUN: %clang_cc1 -triple arm64-apple-tvos9.0.0 -fexceptions -std=c++14 -verify -DNO_ERRORS %s +// RUN: %clang_cc1 -triple armv7k-apple-watchos2.0.0 -fexceptions -fsized-deallocation-unavailable -std=c++14 -verify -DWATCHOS %s +// RUN: %clang_cc1 -triple armv7k-apple-watchos2.0.0 -fexceptions -std=c++14 -verify -DNO_ERRORS %s + +#ifdef NO_ERRORS +// expected-no-diagnostics +#endif + +namespace std { +typedef decltype(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +struct nothrow_t {}; +nothrow_t nothrow; +} // namespace std + +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, const std::nothrow_t &) noexcept; +void *operator new[](std::size_t __sz, const std::nothrow_t &) noexcept; +void operator delete(void *, std::size_t) noexcept; +void operator delete[](void *, std::size_t) noexcept; + +void *operator new(std::size_t, std::size_t, long long); + +struct S { + int x[16]; +}; + +void test() { + auto *p = new S; +#ifndef NO_ERRORS +// expected-error@-2 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on}} +// expected-note@-3 {{if you supply your own sized deallocation functions}} +#endif + + delete p; +#ifndef NO_ERRORS +// expected-error@-2 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on}} +// expected-note@-3 {{if you supply your own sized deallocation functions}} +#endif + + auto *pa = new S[4]; +#ifndef NO_ERRORS +// expected-error@-2 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on}} +// expected-note@-3 {{if you supply your own sized deallocation functions}} +#endif + + delete[] pa; // OK, doesn't call sized delete. + + void *v = operator new(42); + operator delete(v, 42); +#ifndef NO_ERRORS +// expected-error@-2 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on}} +// expected-note@-3 {{if you supply your own sized deallocation functions}} +#endif +} + +void testCheckOS(S *p) { + delete p; +} +#if defined(IOS) +// expected-error@-3 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on iOS 10 or newer}}} +#elif defined(TVOS) +// expected-error@-5 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on tvOS 10 or newer}}} +#elif defined(WATCHOS) +// expected-error@-7 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on watchOS 3 or newer}}} +#elif !defined(NO_ERRORS) +// expected-error@-9 {{sized deallocation function of type 'void (void *, std::size_t) noexcept' is only available on macOS 10.12 or newer}}} +#endif +#ifndef NO_ERRORS +// expected-note@-12 1 {{if you supply your own sized deallocation functions}} +#endif + +// No errors if user-defined sized deallocation functions are available. +void *operator new(std::size_t __sz, std::size_t) { + static char array[256]; + return &array; +} + +void operator delete(void *p, std::size_t) { +} + +void testOveraligned2() { + auto p = new S; + delete p; +}