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
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")
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>,
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();
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 *
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) {
// 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
// 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
@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.
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;