/// 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;
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">;
"type %0 requires %1 bytes of alignment and the default allocator only "
"guarantees %2 bytes">,
InGroup<OveralignedType>, DefaultIgnore;
+def warn_aligned_allocation_unavailable :Warning<
+ "aligned %select{allocation|deallocation}0 function of type '%1' possibly "
+ "unavailable on %2">, InGroup<AlignedAllocationUnavailable>, 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 "
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")
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
//===----------------------------------------------------------------------===//
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 &&
// 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&'.
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 {
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;
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)) {
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,
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:
PDiag(diag::err_access_dtor) << PointeeElem);
}
}
+
+ diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true,
+ *this);
}
CXXDeleteExpr *Result = new (Context) CXXDeleteExpr(
--- /dev/null
+// 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"
--- /dev/null
+// 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;
+}