Index: cfe/trunk/lib/CodeGen/CGObjC.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGObjC.cpp +++ cfe/trunk/lib/CodeGen/CGObjC.cpp @@ -3416,4 +3416,37 @@ return Builder.CreateICmpNE(CallRes, llvm::Constant::getNullValue(Int32Ty)); } +void CodeGenModule::emitAtAvailableLinkGuard() { + if (!IsOSVersionAtLeastFn) + return; + // @available requires CoreFoundation only on Darwin. + if (!Target.getTriple().isOSDarwin()) + return; + // Add -framework CoreFoundation to the linker commands. We still want to + // emit the core foundation reference down below because otherwise if + // CoreFoundation is not used in the code, the linker won't link the + // framework. + auto &Context = getLLVMContext(); + llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"), + llvm::MDString::get(Context, "CoreFoundation")}; + LinkerOptionsMetadata.push_back(llvm::MDNode::get(Context, Args)); + // Emit a reference to a symbol from CoreFoundation to ensure that + // CoreFoundation is linked into the final binary. + llvm::FunctionType *FTy = + llvm::FunctionType::get(Int32Ty, {VoidPtrTy}, false); + llvm::Constant *CFFunc = + CreateRuntimeFunction(FTy, "CFBundleGetVersionNumber"); + + llvm::FunctionType *CheckFTy = llvm::FunctionType::get(VoidTy, {}, false); + llvm::Function *CFLinkCheckFunc = cast(CreateBuiltinFunction( + CheckFTy, "__clang_at_available_requires_core_foundation_framework")); + CFLinkCheckFunc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); + CFLinkCheckFunc->setVisibility(llvm::GlobalValue::HiddenVisibility); + CodeGenFunction CGF(*this); + CGF.Builder.SetInsertPoint(CGF.createBasicBlock("", CFLinkCheckFunc)); + CGF.EmitNounwindRuntimeCall(CFFunc, llvm::Constant::getNullValue(VoidPtrTy)); + CGF.Builder.CreateUnreachable(); + addCompilerUsedGlobal(CFLinkCheckFunc); +} + CGObjCRuntime::~CGObjCRuntime() {} Index: cfe/trunk/lib/CodeGen/CodeGenModule.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h +++ cfe/trunk/lib/CodeGen/CodeGenModule.h @@ -1286,6 +1286,10 @@ /// Emit any vtables which we deferred and still have a use for. void EmitDeferredVTables(); + /// Emit a dummy function that reference a CoreFoundation symbol when + /// @available is used on Darwin. + void emitAtAvailableLinkGuard(); + /// Emit the llvm.used and llvm.compiler.used metadata. void emitLLVMUsed(); Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp @@ -414,6 +414,7 @@ CoverageMapping->emit(); if (CodeGenOpts.SanitizeCfiCrossDso) CodeGenFunction(*this).EmitCfiCheckFail(); + emitAtAvailableLinkGuard(); emitLLVMUsed(); if (SanStats) SanStats->finish(); Index: cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m =================================================================== --- cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m +++ cfe/trunk/test/CodeGenObjC/availability-cf-link-guard.m @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - %s | FileCheck --check-prefixes=CHECK,CHECK_LINK_OPT %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - -D USE_BUILTIN %s | FileCheck --check-prefixes=CHECK,CHECK_LINK_OPT %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.11 -emit-llvm -o - -D DEF_CF %s | FileCheck --check-prefixes=CHECK_CF,CHECK_LINK_OPT %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.12 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK_NO_GUARD %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -emit-llvm -o - %s | FileCheck --check-prefix=CHECK_NO_GUARD %s + +#ifdef DEF_CF +struct CFBundle; +typedef struct CFBundle *CFBundleRef; +unsigned CFBundleGetVersionNumber(CFBundleRef bundle); +// CHECK_CF: declare i32 @CFBundleGetVersionNumber(%struct.CFBundle*) +// CHECK_CF: @__clang_at_available_requires_core_foundation_framework +// CHECK_CF-NEXT: call {{.*}}@CFBundleGetVersionNumber +#endif + +void use_at_available() { +#ifdef DEF_CF + CFBundleGetVersionNumber(0); +#endif +#ifdef USE_BUILTIN + if (__builtin_available(macos 10.12, *)) + ; +#else + if (@available(macos 10.12, *)) + ; +#endif +} + +// CHECK: @llvm.compiler.used{{.*}}@__clang_at_available_requires_core_foundation_framework + +// CHECK: declare i32 @CFBundleGetVersionNumber(i8*) + +// CHECK-LABEL: linkonce hidden void @__clang_at_available_requires_core_foundation_framework +// CHECK: call i32 @CFBundleGetVersionNumber(i8* null) +// CHECK-NEXT: unreachable + +// CHECK_NO_GUARD-NOT: __clang_at_available_requires_core_foundation_framework +// CHECK_NO_GUARD-NOT: CFBundleGetVersionNumber + +// CHECK_LINK_OPT: !"Linker Options", ![[OPTS:[0-9]+]] +// CHECK_LINK_OPT: ![[OPTS]] = !{![[FRAMEWORK:[0-9]+]] +// CHECK_LINK_OPT: ![[FRAMEWORK]] = !{!"-framework", !"CoreFoundation"} + +// CHECK_NO_GUARD-NOT: "Linker Options" +// CHECK_NO_GUARD-NOT: CoreFoundation