Author: Volodymyr Sapsai
Date: 2020-05-14T12:08:19-07:00
New Revision: 6a3469f58d0c230e86043f6975f048968334dfa4

URL: 
https://github.com/llvm/llvm-project/commit/6a3469f58d0c230e86043f6975f048968334dfa4
DIFF: 
https://github.com/llvm/llvm-project/commit/6a3469f58d0c230e86043f6975f048968334dfa4.diff

LOG: [ObjC] Add compatibility mode for type checking of qualified id block 
parameters.

Commit 73152a2ec20766ac45673a129bf1f5fc97ca9bbe fixed type checking for
blocks with qualified id parameters. But there are existing APIs in
Apple SDKs relying on the old type checking behavior. Specifically,
these are APIs using NSItemProviderCompletionHandler in
Foundation/NSItemProvider.h. To keep existing code working and to allow
developers to use affected APIs introduce a compatibility mode that
enables the previous and the fixed type checking. This mode is enabled
only on Darwin platforms.

Reviewed By: jyknight, ahatanak

Differential Revision: https://reviews.llvm.org/D79511

Added: 
    

Modified: 
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Driver/CC1Options.td
    clang/lib/AST/ASTContext.cpp
    clang/lib/Driver/ToolChains/Darwin.cpp
    clang/lib/Frontend/CompilerInvocation.cpp
    clang/test/Driver/darwin-objc-options.m
    clang/test/SemaObjC/block-type-safety.m

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/LangOptions.def 
b/clang/include/clang/Basic/LangOptions.def
index c582a58e731f..e94305da46ba 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -278,6 +278,9 @@ LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated 
reference counting")
 LANGOPT(ObjCWeakRuntime     , 1, 0, "__weak support in the ARC runtime")
 LANGOPT(ObjCWeak            , 1, 0, "Objective-C __weak in ARC and MRC files")
 LANGOPT(ObjCSubscriptingLegacyRuntime         , 1, 0, "Subscripting support in 
legacy ObjectiveC runtime")
+BENIGN_LANGOPT(CompatibilityQualifiedIdBlockParamTypeChecking, 1, 0,
+               "compatibility mode for type checking block parameters "
+               "involving qualified id types")
 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/CC1Options.td 
b/clang/include/clang/Driver/CC1Options.td
index 526a51085ce7..9d2bfbf949ef 100644
--- a/clang/include/clang/Driver/CC1Options.td
+++ b/clang/include/clang/Driver/CC1Options.td
@@ -813,6 +813,9 @@ def fsigned_wchar : Flag<["-"], "fsigned-wchar">,
   HelpText<"Use a signed type for wchar_t">;
 def fno_signed_wchar : Flag<["-"], "fno-signed-wchar">,
   HelpText<"Use an unsigned type for wchar_t">;
+def fcompatibility_qualified_id_block_param_type_checking : Flag<["-"], 
"fcompatibility-qualified-id-block-type-checking">,
+  HelpText<"Allow using blocks with parameters of more specific type than "
+           "the type system guarantees when a parameter is qualified id">;
 
 // FIXME: Remove these entirely once functionality/tests have been excised.
 def fobjc_gc_only : Flag<["-"], "fobjc-gc-only">, Group<f_Group>,

diff  --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 8f3858126253..c457a5537168 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -8599,10 +8599,18 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
                   RHSOPT->isObjCQualifiedIdType());
   }
 
-  if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
-    return finish(ObjCQualifiedIdTypesAreCompatible(
-        (BlockReturnType ? LHSOPT : RHSOPT),
-        (BlockReturnType ? RHSOPT : LHSOPT), false));
+  if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) {
+    if (getLangOpts().CompatibilityQualifiedIdBlockParamTypeChecking)
+      // Use for block parameters previous type checking for compatibility.
+      return finish(ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT, false) ||
+                    // Or corrected type checking as in non-compat mode.
+                    (!BlockReturnType &&
+                     ObjCQualifiedIdTypesAreCompatible(RHSOPT, LHSOPT, 
false)));
+    else
+      return finish(ObjCQualifiedIdTypesAreCompatible(
+          (BlockReturnType ? LHSOPT : RHSOPT),
+          (BlockReturnType ? RHSOPT : LHSOPT), false));
+  }
 
   const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
   const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();

diff  --git a/clang/lib/Driver/ToolChains/Darwin.cpp 
b/clang/lib/Driver/ToolChains/Darwin.cpp
index f6e93eecb460..3bf7f9cbc139 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -2376,6 +2376,10 @@ void Darwin::addClangTargetOptions(const 
llvm::opt::ArgList &DriverArgs,
     OS << "-target-sdk-version=" << SDKInfo->getVersion();
     CC1Args.push_back(DriverArgs.MakeArgString(OS.str()));
   }
+
+  // Enable compatibility mode for NSItemProviderCompletionHandler in
+  // Foundation/NSItemProvider.h.
+  CC1Args.push_back("-fcompatibility-qualified-id-block-type-checking");
 }
 
 DerivedArgList *

diff  --git a/clang/lib/Frontend/CompilerInvocation.cpp 
b/clang/lib/Frontend/CompilerInvocation.cpp
index ff2683c3db70..7e4bb6ea97e3 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3381,6 +3381,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList 
&Args, InputKind IK,
 
   Opts.BranchTargetEnforcement = Args.hasArg(OPT_mbranch_target_enforce);
   Opts.SpeculativeLoadHardening = Args.hasArg(OPT_mspeculative_load_hardening);
+
+  Opts.CompatibilityQualifiedIdBlockParamTypeChecking =
+      Args.hasArg(OPT_fcompatibility_qualified_id_block_param_type_checking);
 }
 
 static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {

diff  --git a/clang/test/Driver/darwin-objc-options.m 
b/clang/test/Driver/darwin-objc-options.m
index 60827f2937ed..6684a5272175 100644
--- a/clang/test/Driver/darwin-objc-options.m
+++ b/clang/test/Driver/darwin-objc-options.m
@@ -40,3 +40,9 @@
 
 // Don't crash with an unexpected target triple.
 // RUN: %clang -target i386-apple-ios7 -S -### %s
+
+// Add -fcompatibility-qualified-id-block-type-checking only on Darwin.
+// RUN: %clang -target x86_64-apple-darwin10 -### %s 2>&1 | FileCheck 
--check-prefix=DARWIN_COMPATIBILITY %s
+// RUN: %clang -target x86_64-linux-gnu -### %s 2>&1 | FileCheck 
--check-prefix=OTHER_COMPATIBILITY %s
+// DARWIN_COMPATIBILITY: -fcompatibility-qualified-id-block-type-checking
+// OTHER_COMPATIBILITY-NOT: -fcompatibility-qualified-id-block-type-checking

diff  --git a/clang/test/SemaObjC/block-type-safety.m 
b/clang/test/SemaObjC/block-type-safety.m
index 66fda2d0b66b..4a5a1dd344f0 100644
--- a/clang/test/SemaObjC/block-type-safety.m
+++ b/clang/test/SemaObjC/block-type-safety.m
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class \
+// RUN:   -fcompatibility-qualified-id-block-type-checking 
-DCOMPATIBILITY_QUALIFIED_ID_TYPE_CHECKING=1 %s
 // test for block type safety.
 
 @interface Super  @end
@@ -132,6 +134,7 @@ @interface NSAllArray <NSCopying>
 @interface NSAllArray (FooConformance) <Foo>
 @end
 
+#ifndef COMPATIBILITY_QUALIFIED_ID_TYPE_CHECKING
 int test5() {
     // Returned value is used outside of a block, so error on changing
     // a return type to a more general than expected.
@@ -149,6 +152,25 @@ int test5() {
     blockWithParam = genericBlockWithParam;
     return 0;
 }
+#else
+// In Apple SDK APIs using NSItemProviderCompletionHandler require to work with
+// blocks that have parameters more specific than in method signatures. As
+// explained in non-compatibility test above, it is not safe in general. But
+// to keep existing code working we support a compatibility mode that uses
+// previous type checking.
+int test5() {
+    NSAllArray *(^block)(id);
+    id <Foo> (^genericBlock)(id);
+    genericBlock = block;
+    block = genericBlock; // expected-error {{incompatible block pointer types 
assigning to 'NSAllArray *(^)(id)' from 'id<Foo> (^)(id)'}}
+
+    void (^blockWithParam)(NSAllArray *);
+    void (^genericBlockWithParam)(id<Foo>);
+    genericBlockWithParam = blockWithParam;
+    blockWithParam = genericBlockWithParam;
+    return 0;
+}
+#endif
 
 // rdar://10798770
 typedef int NSInteger;


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to