Skip to content

IRGen: Differentiate between Swift.Bool and ObjCBool #4173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2166,9 +2166,6 @@ ERROR(builtin_string_literal_broken_proto,none,
ERROR(string_literal_broken_proto,none,
"protocol 'ExpressibleByStringLiteral' is broken", ())

ERROR(bool_type_broken,none,
"could not find a Bool type defined for 'is'", ())

// Array literals
ERROR(array_protocol_broken,none,
"ExpressibleByArrayLiteral protocol definition is broken", ())
Expand Down
13 changes: 10 additions & 3 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ namespace {
pointeeType = Impl.importType(pointeeQualType,
ImportTypeKind::Pointee,
AllowNSUIntegerAsInt,
/*can fully bridge*/false);
/*isFullyBridgeable*/false);

// If the pointed-to type is unrepresentable in Swift, import as
// OpaquePointer.
Expand Down Expand Up @@ -418,7 +418,7 @@ namespace {
Type elementType = Impl.importType(type->getElementType(),
ImportTypeKind::Pointee,
AllowNSUIntegerAsInt,
/*can fully bridge*/false);
/*isFullyBridgeable*/false);
if (!elementType)
return Type();

Expand Down Expand Up @@ -2272,7 +2272,14 @@ Type ClangImporter::Implementation::importMethodType(
OptionalityOfReturn);
// Adjust the result type for a throwing function.
if (swiftResultTy && errorInfo) {
origSwiftResultTy = swiftResultTy->getCanonicalType();

// Get the original unbridged result type.
origSwiftResultTy = importType(resultType, resultKind,
allowNSUIntegerAsIntInResult,
/*isFullyBridgeable*/false,
OptionalityOfReturn)
->getCanonicalType();

swiftResultTy = adjustResultTypeForThrowingFunction(*errorInfo,
swiftResultTy);
}
Expand Down
9 changes: 0 additions & 9 deletions lib/IRGen/GenClangType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,15 +743,6 @@ clang::CanQualType ClangTypeConverter::convert(IRGenModule &IGM, CanType type) {
auto ptrTy = ctx.getObjCObjectPointerType(clangType);
return ctx.getCanonicalType(ptrTy);
}
} else if (decl == IGM.Context.getBoolDecl()) {
// FIXME: Handle _Bool and DarwinBoolean.
auto &ctx = IGM.getClangASTContext();
auto &TI = ctx.getTargetInfo();
// FIXME: Figure out why useSignedCharForObjCBool() returns
// 'true' on Linux
if (IGM.ObjCInterop && TI.useSignedCharForObjCBool()) {
return ctx.SignedCharTy;
}
}
}

Expand Down
52 changes: 33 additions & 19 deletions lib/SILGen/SILGenForeignError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,20 @@ void SILGenFunction::emitForeignErrorBlock(SILLocation loc,
static SILValue emitUnwrapIntegerResult(SILGenFunction &gen,
SILLocation loc,
SILValue value) {
while (!value->getType().is<BuiltinIntegerType>()) {
auto structDecl = value->getType().getStructOrBoundGenericStruct();
assert(structDecl && "value for error result wasn't of struct type!");
assert(std::next(structDecl->getStoredProperties().begin())
== structDecl->getStoredProperties().end());
auto property = *structDecl->getStoredProperties().begin();
value = gen.B.createStructExtract(loc, value, property);
}
CanType boolType = gen.SGM.Types.getBoolType();

value = gen.emitBridgedToNativeValue(
loc, ManagedValue::forUnmanaged(value),
SILFunctionTypeRepresentation::CFunctionPointer,
boolType).forward(gen);

auto structDecl = value->getType().getStructOrBoundGenericStruct();
assert(structDecl && "value for error result wasn't of struct type!");
assert(std::next(structDecl->getStoredProperties().begin())
== structDecl->getStoredProperties().end());
auto property = *structDecl->getStoredProperties().begin();
value = gen.B.createStructExtract(loc, value, property);
assert(value->getType().is<BuiltinIntegerType>());

return value;
}
Expand All @@ -315,20 +321,28 @@ emitResultIsZeroErrorCheck(SILGenFunction &gen, SILLocation loc,

SILValue resultValue =
emitUnwrapIntegerResult(gen, loc, result.getUnmanagedValue());
SILValue zero =
gen.B.createIntegerLiteral(loc, resultValue->getType(), 0);

ASTContext &ctx = gen.getASTContext();
SILValue resultIsError =
gen.B.createBuiltinBinaryFunction(loc,
zeroIsError ? "cmp_eq" : "cmp_ne",
resultValue->getType(),
SILType::getBuiltinIntegerType(1, ctx),
{resultValue, zero});
CanType resultType = resultValue->getType().getSwiftRValueType();

if (!resultType->isBuiltinIntegerType(1)) {
SILValue zero =
gen.B.createIntegerLiteral(loc, resultValue->getType(), 0);

ASTContext &ctx = gen.getASTContext();
resultValue =
gen.B.createBuiltinBinaryFunction(loc,
"cmp_ne",
resultValue->getType(),
SILType::getBuiltinIntegerType(1, ctx),
{resultValue, zero});
}

SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter);
SILBasicBlock *contBB = gen.createBasicBlock();
gen.B.createCondBranch(loc, resultIsError, errorBB, contBB);

if (zeroIsError)
gen.B.createCondBranch(loc, resultValue, contBB, errorBB);
else
gen.B.createCondBranch(loc, resultValue, errorBB, contBB);

gen.emitForeignErrorBlock(loc, errorBB, errorSlot);

Expand Down
15 changes: 13 additions & 2 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3025,8 +3025,19 @@ bool TypeChecker::isRepresentableInObjC(
// Functions that return nothing (void) can be throwing; they indicate
// failure with a 'false' result.
kind = ForeignErrorConvention::ZeroResult;
errorResultType = Context.getBoolDecl()
->getDeclaredInterfaceType()->getCanonicalType();
NominalTypeDecl *boolDecl = Context.getObjCBoolDecl();
// On Linux, we might still run @objc tests even though there's
// no ObjectiveC Foundation, so use Swift.Bool instead of crapping
// out.
if (boolDecl == nullptr)
boolDecl = Context.getBoolDecl();

if (boolDecl == nullptr) {
diagnose(AFD->getLoc(), diag::broken_bool);
return false;
}

errorResultType = boolDecl->getDeclaredType()->getCanonicalType();
} else if (!resultType->getAnyOptionalObjectType() &&
isBridgedToObjectiveCClass(dc, resultType)) {
// Functions that return a (non-optional) type bridged to Objective-C
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,13 @@ Type TypeChecker::lookupBoolType(const DeclContext *dc) {
getStdlibModule(dc)->lookupValue({}, Context.getIdentifier("Bool"),
NLKind::QualifiedLookup, results);
if (results.size() != 1) {
diagnose(SourceLoc(), diag::bool_type_broken);
diagnose(SourceLoc(), diag::broken_bool);
return Type();
}

auto tyDecl = dyn_cast<TypeDecl>(results.front());
if (!tyDecl) {
diagnose(SourceLoc(), diag::bool_type_broken);
diagnose(SourceLoc(), diag::broken_bool);
return Type();
}

Expand Down
6 changes: 6 additions & 0 deletions test/IRGen/Inputs/abi/Gadget.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ struct BigStruct {

@interface Gadget : NSObject
- (BOOL) negate:(BOOL) b;
- (_Bool) invert:(_Bool) b;

- (BOOL) negateThrowing:(BOOL) b error:(NSError **) error;

// This one is not imported as a 'throws' function in Swift
- (_Bool) invertThrowing:(_Bool) b error:(NSError **) error;
@end

@protocol Pasta
Expand Down
42 changes: 42 additions & 0 deletions test/IRGen/abitypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,48 @@ class Foo {
return g.negate(b)
}

// x86_64-macosx: define hidden i1 @_TFC8abitypes3Foo7negate3fSbSb(i1, %C8abitypes3Foo*) {{.*}} {
// x86_64-macosx: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(invert:)", align 8
// x86_64-macosx: [[NEG:%[0-9]+]] = call zeroext i1 bitcast (void ()* @objc_msgSend to i1 (%1*, i8*, i1)*)(%1* [[RECEIVER:%[0-9]+]], i8* [[SEL]], i1 zeroext %0)
// x86_64-macosx: ret i1 [[NEG]]
// x86_64-macosx: }

// x86_64-ios: define hidden i1 @_TFC8abitypes3Foo7negate3fSbSb(i1, %C8abitypes3Foo*) {{.*}} {
// x86_64-ios: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(invert:)", align 8
// x86_64-ios: [[NEG:%[0-9]+]] = call zeroext i1 bitcast (void ()* @objc_msgSend to i1 (%1*, i8*, i1)*)(%1* [[RECEIVER:%[0-9]+]], i8* [[SEL]], i1 zeroext %0)
// x86_64-ios: ret i1 [[NEG]]
// x86_64-ios: }

// i386-ios: define hidden i1 @_TFC8abitypes3Foo7negate3fSbSb(i1, %C8abitypes3Foo*) {{.*}} {
// i386-ios: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(invert:)", align 4
// i386-ios: [[NEG:%[0-9]+]] = call zeroext i1 bitcast (void ()* @objc_msgSend to i1 (%1*, i8*, i1)*)(%1* [[RECEIVER:%[0-9]+]], i8* [[SEL]], i1 zeroext %0)
// i386-ios: ret i1 [[NEG]]
// i386-ios: }

dynamic func negate3(_ b: Bool) -> Bool {
var g = Gadget()
return g.invert(b)
}

// x86_64-macosx: define hidden void @_TFC8abitypes3Foo10throwsTestfzSbT_(i1, %C8abitypes3Foo*, %swift.error**) {{.*}} {
// x86_64-macosx: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(negateThrowing:error:)", align 8
// x86_64-macosx: call signext i8 bitcast (void ()* @objc_msgSend to i8 (%1*, i8*, i8, %2**)*)(%1* {{%[0-9]+}}, i8* [[SEL]], i8 signext {{%[0-9]+}}, %2** {{%[0-9]+}})
// x86_64-macosx: }

// x86_64-ios: define hidden void @_TFC8abitypes3Foo10throwsTestfzSbT_(i1, %C8abitypes3Foo*, %swift.error**) {{.*}} {
// x86_64-ios: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(negateThrowing:error:)", align 8
// x86_64-ios: call zeroext i1 bitcast (void ()* @objc_msgSend to i1 (%1*, i8*, i1, %2**)*)(%1* {{%[0-9]+}}, i8* [[SEL]], i1 zeroext {{%[0-9]+}}, %2** {{%[0-9]+}})
// x86_64-ios: }

// i386-ios: define hidden void @_TFC8abitypes3Foo10throwsTestfzSbT_(i1, %C8abitypes3Foo*, %swift.error**) {{.*}} {
// i386-ios: [[SEL:%[0-9]+]] = load i8*, i8** @"\01L_selector(negateThrowing:error:)", align 4
// i386-ios: call signext i8 bitcast (void ()* @objc_msgSend to i8 (%1*, i8*, i8, %2**)*)(%1* {{%[0-9]+}}, i8* [[SEL]], i8 signext {{%[0-9]+}}, %2** {{%[0-9]+}})
// i386-ios: }
dynamic func throwsTest(_ b: Bool) throws {
var g = Gadget()
try g.negateThrowing(b)
}

// x86_64-macosx: define hidden i32* @_TToFC8abitypes3Foo24copyUnsafeMutablePointer{{.*}}(i8*, i8*, i32*) unnamed_addr {{.*}} {
dynamic func copyUnsafeMutablePointer(_ p: UnsafeMutablePointer<Int32>) -> UnsafeMutablePointer<Int32> {
return p
Expand Down
5 changes: 5 additions & 0 deletions test/Interpreter/Inputs/ObjCClasses/ObjCClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ NS_ASSUME_NONNULL_BEGIN
+ (unsigned) count;
@end

@interface TestingBool : NSObject
- (void) shouldBeTrueObjCBool: (BOOL)value;
- (void) shouldBeTrueCBool: (_Bool)value;
@end

NS_ASSUME_NONNULL_END

#endif
13 changes: 13 additions & 0 deletions test/Interpreter/Inputs/ObjCClasses/ObjCClasses.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#import "ObjCClasses.h"
#import <Foundation/NSError.h>
#include <stdio.h>
#include <assert.h>

@implementation HasHiddenIvars
@synthesize x;
Expand Down Expand Up @@ -151,3 +152,15 @@ + (unsigned) count {
}

@end

@implementation TestingBool

- (void) shouldBeTrueObjCBool: (BOOL)value {
assert(value);
}

- (void) shouldBeTrueCBool: (_Bool)value {
assert(value);
}

@end
15 changes: 15 additions & 0 deletions test/Interpreter/objc_bool.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
//
// RUN: %target-clang -fobjc-arc %S/Inputs/ObjCClasses/ObjCClasses.m -c -o %t/ObjCClasses.o
// RUN: %target-build-swift -I %S/Inputs/ObjCClasses/ -Xlinker %t/ObjCClasses.o %s -o %t/a.out
// RUN: %target-run %t/a.out

// REQUIRES: executable_test
// REQUIRES: objc_interop

import ObjCClasses
import Foundation

TestingBool().shouldBeTrueObjCBool(true)
TestingBool().shouldBeTrueCBool(true)
Loading