diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -852,9 +852,7 @@ 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 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -298,6 +298,8 @@ 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 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2225,6 +2225,12 @@ def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group; def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group; +def fobjc_disable_direct_methods_for_testing : + Flag<["-"], "fobjc-disable-direct-methods-for-testing">, + Group, Flags<[CC1Option]>, + HelpText<"Ignore attribute objc_direct so that direct methods can be tested">, + MarshallingInfoFlag>; + def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group; def fopenmp : Flag<["-"], "fopenmp">, 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 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -826,7 +826,8 @@ } bool ObjCMethodDecl::isDirectMethod() const { - return hasAttr(); + return hasAttr() && + !getASTContext().getLangOpts().ObjCDisableDirectMethodsForTesting; } bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const { @@ -2295,6 +2296,11 @@ 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 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3665,6 +3665,9 @@ 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 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -4407,10 +4407,12 @@ void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method, ObjCMethodDecl *overridden) { - if (const auto *attr = overridden->getAttr()) { + if (overridden->isDirectMethod()) { + const auto *attr = overridden->getAttr(); Diag(method->getLocation(), diag::err_objc_override_direct_method); Diag(attr->getLocation(), diag::note_previous_declaration); - } else if (const auto *attr = method->getAttr()) { + } else if (method->isDirectMethod()) { + const auto *attr = method->getAttr(); Diag(attr->getLocation(), diag::err_objc_direct_on_override) << isa(overridden->getDeclContext()); Diag(overridden->getLocation(), diag::note_previous_declaration); @@ -4856,7 +4858,8 @@ // the canonical declaration. if (!ObjCMethod->isDirectMethod()) { const ObjCMethodDecl *CanonicalMD = ObjCMethod->getCanonicalDecl(); - if (const auto *attr = CanonicalMD->getAttr()) { + if (CanonicalMD->isDirectMethod()) { + const auto *attr = CanonicalMD->getAttr(); ObjCMethod->addAttr( ObjCDirectAttr::CreateImplicit(Context, attr->getLocation())); } @@ -4901,14 +4904,16 @@ Diag(IMD->getLocation(), diag::note_previous_declaration); }; - if (const auto *attr = ObjCMethod->getAttr()) { + if (ObjCMethod->isDirectMethod()) { + const auto *attr = ObjCMethod->getAttr(); 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()) { + } else if (IMD->isDirectMethod()) { + const auto *attr = IMD->getAttr(); 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 --- /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 + +@interface Y +@property (direct) int direct_property; +@end +@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_, + +@interface X +-(void)m __attribute__((objc_direct)); +@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 --- 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 --- /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)) +@interface X +-(void)direct_method DIRECT; +@end + +@implementation X +-(void)direct_method DIRECT {} +@end + +__attribute__((objc_root_class)) +DIRECT_MEMBERS +@interface Y +-(void)direct_method2; +@end + +@implementation Y +-(void)direct_method2 {} +@end + +__attribute__((objc_root_class)) +@interface Z +@property (direct) int direct_property; +@end + +@implementation Z @end