[clang] b660abc - [ObjC] Add a command line flag that disables recognition of objc_direct for testability
Erik Pilkington via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 6 08:17:56 PDT 2021
Author: Erik Pilkington
Date: 2021-04-06T11:17:01-04:00
New Revision: b660abc80d0d0943c54e9440636ddfa89c2d626d
URL: https://github.com/llvm/llvm-project/commit/b660abc80d0d0943c54e9440636ddfa89c2d626d
DIFF: https://github.com/llvm/llvm-project/commit/b660abc80d0d0943c54e9440636ddfa89c2d626d.diff
LOG: [ObjC] Add a command line flag that disables recognition of objc_direct for testability
Programmers would like to be able to test direct methods by calling them from a
different linkage unit or mocking them, both of which are impossible. This
patch adds a flag that effectively disables the attribute, which will fix this
when enabled in testable builds. rdar://71190891
Differential revision: https://reviews.llvm.org/D95845
Added:
clang/test/CodeGenObjC/disable-direct-method.m
clang/test/SemaObjC/disable-direct-method.m
Modified:
clang/include/clang/AST/DeclObjC.h
clang/include/clang/Basic/LangOptions.def
clang/include/clang/Driver/Options.td
clang/lib/AST/DeclObjC.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Sema/SemaDeclObjC.cpp
clang/test/Driver/clang_f_opts.c
Removed:
################################################################################
diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h
index b1bce069920c..6bb9cdf67034 100644
--- a/clang/include/clang/AST/DeclObjC.h
+++ b/clang/include/clang/AST/DeclObjC.h
@@ -852,9 +852,7 @@ class ObjCPropertyDecl : public NamedDecl {
bool isClassProperty() const {
return PropertyAttributes & ObjCPropertyAttribute::kind_class;
}
- bool isDirectProperty() const {
- return PropertyAttributes & ObjCPropertyAttribute::kind_direct;
- }
+ bool isDirectProperty() const;
ObjCPropertyQueryKind getQueryKind() const {
return isClassProperty() ? ObjCPropertyQueryKind::OBJC_PR_query_class :
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 1560a1f38aeb..b29dae5e2076 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -298,6 +298,8 @@ LANGOPT(ObjCSubscriptingLegacyRuntime , 1, 0, "Subscripting support in l
BENIGN_LANGOPT(CompatibilityQualifiedIdBlockParamTypeChecking, 1, 0,
"compatibility mode for type checking block parameters "
"involving qualified id types")
+LANGOPT(ObjCDisableDirectMethodsForTesting, 1, 0,
+ "Disable recognition of objc_direct methods")
LANGOPT(CFProtectionBranch , 1, 0, "Control-Flow Branch Protection enabled")
LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map")
ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "OpenCL address space map mangling mode")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 38977cc0b874..1a71d68ec4e2 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2225,6 +2225,12 @@ def fobjc_nonfragile_abi : Flag<["-"], "fobjc-nonfragile-abi">, Group<f_Group>;
def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group<f_Group>;
def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>;
+def fobjc_disable_direct_methods_for_testing :
+ Flag<["-"], "fobjc-disable-direct-methods-for-testing">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Ignore attribute objc_direct so that direct methods can be tested">,
+ MarshallingInfoFlag<LangOpts<"ObjCDisableDirectMethodsForTesting">>;
+
def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused, FlangOption, FC1Option]>,
HelpText<"Parse OpenMP pragmas and generate parallel code.">;
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index 5f82fcec90e3..6e790f03b027 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -826,7 +826,8 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
}
bool ObjCMethodDecl::isDirectMethod() const {
- return hasAttr<ObjCDirectAttr>();
+ return hasAttr<ObjCDirectAttr>() &&
+ !getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting;
}
bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const {
@@ -2295,6 +2296,11 @@ QualType ObjCPropertyDecl::getUsageType(QualType objectType) const {
ObjCSubstitutionContext::Property);
}
+bool ObjCPropertyDecl::isDirectProperty() const {
+ return (PropertyAttributes & ObjCPropertyAttribute::kind_direct) &&
+ !getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting;
+}
+
//===----------------------------------------------------------------------===//
// ObjCPropertyImplDecl
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 96a43656bf99..aaf6f83a0cfa 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3665,6 +3665,9 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D,
WeakArg->render(Args, CmdArgs);
}
}
+
+ if (Args.hasArg(options::OPT_fobjc_disable_direct_methods_for_testing))
+ CmdArgs.push_back("-fobjc-disable-direct-methods-for-testing");
}
static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args,
diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp
index 60253a82e93a..e0f8c6e92d5a 100644
--- a/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/clang/lib/Sema/SemaDeclObjC.cpp
@@ -4407,10 +4407,12 @@ class OverrideSearch {
void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method,
ObjCMethodDecl *overridden) {
- if (const auto *attr = overridden->getAttr<ObjCDirectAttr>()) {
+ if (overridden->isDirectMethod()) {
+ const auto *attr = overridden->getAttr<ObjCDirectAttr>();
Diag(method->getLocation(), diag::err_objc_override_direct_method);
Diag(attr->getLocation(), diag::note_previous_declaration);
- } else if (const auto *attr = method->getAttr<ObjCDirectAttr>()) {
+ } else if (method->isDirectMethod()) {
+ const auto *attr = method->getAttr<ObjCDirectAttr>();
Diag(attr->getLocation(), diag::err_objc_direct_on_override)
<< isa<ObjCProtocolDecl>(overridden->getDeclContext());
Diag(overridden->getLocation(), diag::note_previous_declaration);
@@ -4856,7 +4858,8 @@ Decl *Sema::ActOnMethodDeclaration(
// the canonical declaration.
if (!ObjCMethod->isDirectMethod()) {
const ObjCMethodDecl *CanonicalMD = ObjCMethod->getCanonicalDecl();
- if (const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>()) {
+ if (CanonicalMD->isDirectMethod()) {
+ const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>();
ObjCMethod->addAttr(
ObjCDirectAttr::CreateImplicit(Context, attr->getLocation()));
}
@@ -4901,14 +4904,16 @@ Decl *Sema::ActOnMethodDeclaration(
Diag(IMD->getLocation(), diag::note_previous_declaration);
};
- if (const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>()) {
+ if (ObjCMethod->isDirectMethod()) {
+ const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>();
if (ObjCMethod->getCanonicalDecl() != IMD) {
diagContainerMismatch();
} else if (!IMD->isDirectMethod()) {
Diag(attr->getLocation(), diag::err_objc_direct_missing_on_decl);
Diag(IMD->getLocation(), diag::note_previous_declaration);
}
- } else if (const auto *attr = IMD->getAttr<ObjCDirectAttr>()) {
+ } else if (IMD->isDirectMethod()) {
+ const auto *attr = IMD->getAttr<ObjCDirectAttr>();
if (ObjCMethod->getCanonicalDecl() != IMD) {
diagContainerMismatch();
} else {
diff --git a/clang/test/CodeGenObjC/disable-direct-method.m b/clang/test/CodeGenObjC/disable-direct-method.m
new file mode 100644
index 000000000000..fb5d5702fa30
--- /dev/null
+++ b/clang/test/CodeGenObjC/disable-direct-method.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 -fobjc-disable-direct-methods-for-testing %s -o - | FileCheck %s
+
+ at interface Y
+ at property (direct) int direct_property;
+ at end
+ at implementation Y @end
+
+// CHECK: @OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [16 x i8] c"direct_property\00"
+// CHECK: @"_OBJC_$_PROP_LIST_Y" =
+// CHECK-SAME: @OBJC_PROP_NAME_ATTR_,
+
+ at interface X
+-(void)m __attribute__((objc_direct));
+ at end
+
+// CHECK-LABEL: define void @f
+void f(X *x) {
+ [x m];
+
+ // CHECK: call void bitcast ({{.*}} @objc_msgSend to {{.*}})
+}
diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c
index 12369361f811..3ea9410adbea 100644
--- a/clang/test/Driver/clang_f_opts.c
+++ b/clang/test/Driver/clang_f_opts.c
@@ -576,3 +576,8 @@
// RUN: %clang -### -S -fno-temp-file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-TEMP-FILE %s
// CHECK-NO-TEMP-FILE: "-fno-temp-file"
+
+// RUN: %clang -### -xobjective-c -fobjc-disable-direct-methods-for-testing %s 2>&1 | FileCheck -check-prefix=CHECK_DISABLE_DIRECT %s
+// RUN: %clang -### -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DISABLE_DIRECT %s
+// CHECK_DISABLE_DIRECT: -fobjc-disable-direct-methods-for-testing
+// CHECK_NO_DISABLE_DIRECT-NOT: -fobjc-disable-direct-methods-for-testing
diff --git a/clang/test/SemaObjC/disable-direct-method.m b/clang/test/SemaObjC/disable-direct-method.m
new file mode 100644
index 000000000000..a6fdaba33551
--- /dev/null
+++ b/clang/test/SemaObjC/disable-direct-method.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -verify -fobjc-disable-direct-methods-for-testing %s
+
+// expected-no-diagnostics
+
+#define DIRECT __attribute__((objc_direct))
+#define DIRECT_MEMBERS __attribute__((objc_direct_members))
+
+__attribute__((objc_root_class))
+ at interface X
+-(void)direct_method DIRECT;
+ at end
+
+ at implementation X
+-(void)direct_method DIRECT {}
+ at end
+
+__attribute__((objc_root_class))
+DIRECT_MEMBERS
+ at interface Y
+-(void)direct_method2;
+ at end
+
+ at implementation Y
+-(void)direct_method2 {}
+ at end
+
+__attribute__((objc_root_class))
+ at interface Z
+ at property (direct) int direct_property;
+ at end
+
+ at implementation Z @end
More information about the cfe-commits
mailing list