From b111ec94b3474c4eff15b19a74cd815cdb469aaa Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Mon, 2 Mar 2015 19:01:14 +0000 Subject: [PATCH] Add clang support for Objective-C application extensions. This adds the -fapplication-extension option, along with the ios_app_extension and macosx_app_extension availability attributes. Patch by Ted Kremenek llvm-svn: 230989 --- clang/include/clang/Basic/Attr.td | 2 ++ clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/Options.td | 5 ++++ clang/lib/AST/DeclBase.cpp | 30 ++++++++++++++++------ clang/lib/Driver/Tools.cpp | 10 ++++++++ clang/lib/Frontend/CompilerInvocation.cpp | 1 + clang/lib/Lex/PPMacroExpansion.cpp | 1 + clang/test/Sema/attr-availability-app-extensions.c | 18 +++++++++++++ 8 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 clang/test/Sema/attr-availability-app-extensions.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 48e04be..fb49132 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -442,6 +442,8 @@ def Availability : InheritableAttr { return llvm::StringSwitch(Platform) .Case("ios", "iOS") .Case("macosx", "OS X") + .Case("ios_app_extension", "iOS (App Extension)") + .Case("macosx_app_extension", "OS X (App Extension)") .Default(llvm::StringRef()); } }]; let HasCustomParsing = 1; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index fb39887..21de1e3 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -84,6 +84,7 @@ BENIGN_LANGOPT(EncodeExtendedBlockSig , 1, 0, "Encoding extended block type signature") BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1, "Objective-C related result type inference") +LANGOPT(AppExt , 1, 0, "Objective-C App Extension") LANGOPT(Trigraphs , 1, 0,"trigraphs") LANGOPT(LineComment , 1, 0, "'//' comments") LANGOPT(Bool , 1, 0, "bool, true, and false keywords") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 6b7a47c..bcc4393 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -819,6 +819,11 @@ def fobjc_atdefs : Flag<["-"], "fobjc-atdefs">, Group; def fobjc_call_cxx_cdtors : Flag<["-"], "fobjc-call-cxx-cdtors">, Group; def fobjc_exceptions: Flag<["-"], "fobjc-exceptions">, Group, HelpText<"Enable Objective-C exceptions">, Flags<[CC1Option]>; +def fapplication_extension : Flag<["-"], "fapplication-extension">, + Group, Flags<[CC1Option]>, + HelpText<"Restrict code to those available for App Extensions">; +def fno_application_extension : Flag<["-"], "fno-application-extension">, + Group; def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group, Flags<[CC1Option]>, HelpText<"Use GC exclusively for Objective-C related memory management">; diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 75a219a..0390d81 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -336,20 +336,34 @@ bool Decl::isReferenced() const { static AvailabilityResult CheckAvailability(ASTContext &Context, const AvailabilityAttr *A, std::string *Message) { - StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); - StringRef PrettyPlatformName - = AvailabilityAttr::getPrettyPlatformName(TargetPlatform); - if (PrettyPlatformName.empty()) - PrettyPlatformName = TargetPlatform; + VersionTuple TargetMinVersion = + Context.getTargetInfo().getPlatformMinVersion(); - VersionTuple TargetMinVersion = Context.getTargetInfo().getPlatformMinVersion(); if (TargetMinVersion.empty()) return AR_Available; + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef ActualPlatform = A->getPlatform()->getName(); + StringRef RealizedPlatform = ActualPlatform; + if (Context.getLangOpts().AppExt) { + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + RealizedPlatform = RealizedPlatform.slice(0, suffix); + } + + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + // Match the platform name. - if (A->getPlatform()->getName() != TargetPlatform) + if (RealizedPlatform != TargetPlatform) return AR_Available; - + + StringRef PrettyPlatformName + = AvailabilityAttr::getPrettyPlatformName(ActualPlatform); + + if (PrettyPlatformName.empty()) + PrettyPlatformName = ActualPlatform; + std::string HintMessage; if (!A->getMessage().empty()) { HintMessage = " - "; diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index de3d5a6..eff0ca7 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -4216,6 +4216,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + if (Args.hasFlag(options::OPT_fapplication_extension, + options::OPT_fno_application_extension, false)) + CmdArgs.push_back("-fapplication-extension"); + // Handle GCC-style exception args. if (!C.getDriver().IsCLMode()) addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, @@ -5811,6 +5815,12 @@ void darwin::Link::AddLinkArgs(Compilation &C, if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) CmdArgs.push_back("-export_dynamic"); + // If we are using App Extension restrictions, pass a flag to the linker + // telling it that the compiled code has been audited. + if (Args.hasFlag(options::OPT_fapplication_extension, + options::OPT_fno_application_extension, false)) + CmdArgs.push_back("-application_extension"); + // If we are using LTO, then automatically create a temporary file path for // the linker to use, so that it's lifetime will extend past a possible // dsymutil step. diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 2098dec..962e8e1 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1578,6 +1578,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal); Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack); Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name); + Opts.AppExt = Args.hasArg(OPT_fapplication_extension); Opts.ImplementationOfModule = Args.getLastArgValue(OPT_fmodule_implementation_of); Opts.ModuleFeatures = Args.getAllArgValues(OPT_fmodule_feature); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index b986ada..80ec3c4 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -868,6 +868,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("attribute_analyzer_noreturn", true) .Case("attribute_availability", true) .Case("attribute_availability_with_message", true) + .Case("attribute_availability_app_extension", true) .Case("attribute_cf_returns_not_retained", true) .Case("attribute_cf_returns_retained", true) .Case("attribute_deprecated_with_message", true) diff --git a/clang/test/Sema/attr-availability-app-extensions.c b/clang/test/Sema/attr-availability-app-extensions.c new file mode 100644 index 0000000..a847092 --- /dev/null +++ b/clang/test/Sema/attr-availability-app-extensions.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -fsyntax-only -fapplication-extension %s -verify +// RUN: %clang_cc1 -triple armv7-apple-ios9.0 -fsyntax-only -fapplication-extension %s -verify + +#if __has_feature(attribute_availability_app_extension) + __attribute__((availability(macosx_app_extension,unavailable))) + __attribute__((availability(ios_app_extension,unavailable))) +#endif +void f0(int); // expected-note {{'f0' has been explicitly marked unavailable here}} + +__attribute__((availability(macosx,unavailable))) +__attribute__((availability(ios,unavailable))) +void f1(int); // expected-note {{'f1' has been explicitly marked unavailable here}} + +void test() { + f0(1); // expected-error {{'f0' is unavailable: not available on}} + f1(1); // expected-error {{'f1' is unavailable}} +} + -- 2.7.4