Skip to content

Commit bc83940

Browse files
committed
Make pointer nullability explicit using Optional.
Implements SE-0055: https://github.com/apple/swift-evolution/blob/master/proposals/0055-optional-unsafe-pointers.md - Add NULL as an extra inhabitant of Builtin.RawPointer (currently hardcoded to 0 rather than being target-dependent). - Import non-object pointers as Optional/IUO when nullable/null_unspecified (like everything else). - Change the type checker's *-to-pointer conversions to handle a layer of optional. - Use 'AutoreleasingUnsafeMutablePointer<NSError?>?' as the type of error parameters exported to Objective-C. - Drop NilLiteralConvertible conformance for all pointer types. - Update the standard library and then all the tests. I've decided to leave this commit only updating existing tests; any new tests will come in the following commits. (That may mean some additional implementation work to follow.) The other major piece that's missing here is migration. I'm hoping we get a lot of that with Swift 1.1's work for optional object references, but I still need to investigate.
1 parent 8e292da commit bc83940

File tree

150 files changed

+2365
-2160
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

150 files changed

+2365
-2160
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,9 @@ extern "C" const ValueWitnessTable _TWVXwGSqBo_; // weak Builtin.NativeObject?
907907
SWIFT_RUNTIME_EXPORT
908908
extern "C" const ExtraInhabitantsValueWitnessTable _TWVBb; // Builtin.BridgeObject
909909

910+
SWIFT_RUNTIME_EXPORT
911+
extern "C" const ExtraInhabitantsValueWitnessTable _TWVBp; // Builtin.RawPointer
912+
910913
#if SWIFT_OBJC_INTEROP
911914
// The ObjC-pointer table can be used for arbitrary ObjC pointer types.
912915
SWIFT_RUNTIME_EXPORT
@@ -1288,6 +1291,8 @@ extern "C" const FullOpaqueMetadata _TMBo; // Builtin.NativeObject
12881291
SWIFT_RUNTIME_EXPORT
12891292
extern "C" const FullOpaqueMetadata _TMBb; // Builtin.BridgeObject
12901293
SWIFT_RUNTIME_EXPORT
1294+
extern "C" const FullOpaqueMetadata _TMBp; // Builtin.RawPointer
1295+
SWIFT_RUNTIME_EXPORT
12911296
extern "C" const FullOpaqueMetadata _TMBB; // Builtin.UnsafeValueBuffer
12921297
#if SWIFT_OBJC_INTEROP
12931298
SWIFT_RUNTIME_EXPORT

lib/AST/ASTContext.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3620,7 +3620,7 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
36203620

36213621
// Pre-populate the foreign-representable cache with known types.
36223622
if (auto stdlib = getStdlibModule()) {
3623-
addTrivial(getIdentifier("OpaquePointer"), stdlib);
3623+
addTrivial(getIdentifier("OpaquePointer"), stdlib, true);
36243624

36253625
// Builtin types
36263626
// FIXME: Layering violation to use the ClangImporter's define.
@@ -3636,13 +3636,13 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
36363636
}
36373637

36383638
if (auto objectiveC = getLoadedModule(Id_ObjectiveC)) {
3639-
addTrivial(Id_Selector, objectiveC);
3639+
addTrivial(Id_Selector, objectiveC, true);
36403640

36413641
// Note: ObjCBool is odd because it's bridged to Bool in APIs,
36423642
// but can also be trivially bridged.
36433643
addTrivial(getIdentifier("ObjCBool"), objectiveC);
36443644

3645-
addTrivial(getSwiftId(KnownFoundationEntity::NSZone), objectiveC);
3645+
addTrivial(getSwiftId(KnownFoundationEntity::NSZone), objectiveC, true);
36463646
}
36473647

36483648
if (auto coreGraphics = getLoadedModule(getIdentifier("CoreGraphics"))) {

lib/AST/Type.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,10 +2116,6 @@ getForeignRepresentable(Type type, ForeignLanguage language, DeclContext *dc) {
21162116
// Pointers may be representable in ObjC.
21172117
PointerTypeKind pointerKind;
21182118
if (auto pointerElt = type->getAnyPointerElementType(pointerKind)) {
2119-
// FIXME: Optionality should be embedded in the pointer types.
2120-
if (wasOptional)
2121-
return failure();
2122-
21232119
switch (pointerKind) {
21242120
case PTK_UnsafeMutablePointer:
21252121
case PTK_UnsafePointer:

lib/ClangImporter/ImportType.cpp

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,8 @@ namespace {
8585
/// The source type is a function pointer type.
8686
CFunctionPointer,
8787

88-
/// The source type is a specially-handled pointer type (usually a mapped
89-
/// typedef) that nonetheless needs to preserve nullability.
90-
CustomNullablePointer,
88+
/// The source type is any other pointer type.
89+
OtherPointer,
9190
};
9291

9392
ImportHintKind Kind;
@@ -126,7 +125,7 @@ namespace {
126125
case ImportHint::ObjCBridged:
127126
case ImportHint::ObjCPointer:
128127
case ImportHint::CFunctionPointer:
129-
case ImportHint::CustomNullablePointer:
128+
case ImportHint::OtherPointer:
130129
return true;
131130
}
132131
}
@@ -292,7 +291,7 @@ namespace {
292291
Impl.SwiftContext.getSwiftName(
293292
KnownFoundationEntity::NSZone));
294293
if (wrapperTy)
295-
return wrapperTy;
294+
return {wrapperTy, ImportHint::OtherPointer};
296295
}
297296
}
298297

@@ -315,7 +314,8 @@ namespace {
315314
// If the pointed-to type is unrepresentable in Swift, import as
316315
// OpaquePointer.
317316
if (!pointeeType)
318-
return getOpaquePointerType();
317+
return {Impl.SwiftContext.getOpaquePointerDecl()->getDeclaredType(),
318+
ImportHint::OtherPointer};
319319

320320
if (pointeeQualType->isFunctionType()) {
321321
auto funcTy = pointeeType->castTo<FunctionType>();
@@ -329,29 +329,29 @@ namespace {
329329

330330
auto quals = pointeeQualType.getQualifiers();
331331

332-
if (quals.hasConst())
332+
if (quals.hasConst()) {
333333
return {Impl.getNamedSwiftTypeSpecialization(Impl.getStdlibModule(),
334334
"UnsafePointer",
335335
pointeeType),
336-
ImportHint::None};
336+
ImportHint::OtherPointer};
337+
}
338+
337339
// Mutable pointers with __autoreleasing or __unsafe_unretained
338340
// ownership map to AutoreleasingUnsafeMutablePointer<T>.
339-
else if (quals.getObjCLifetime() == clang::Qualifiers::OCL_Autoreleasing
340-
|| quals.getObjCLifetime() == clang::Qualifiers::OCL_ExplicitNone)
341+
if (quals.getObjCLifetime() == clang::Qualifiers::OCL_Autoreleasing ||
342+
quals.getObjCLifetime() == clang::Qualifiers::OCL_ExplicitNone) {
341343
return {
342344
Impl.getNamedSwiftTypeSpecialization(
343345
Impl.getStdlibModule(), "AutoreleasingUnsafeMutablePointer",
344346
pointeeType),
345-
ImportHint::None};
347+
ImportHint::OtherPointer};
348+
}
349+
346350
// All other mutable pointers map to UnsafeMutablePointer.
347351
return {Impl.getNamedSwiftTypeSpecialization(Impl.getStdlibModule(),
348352
"UnsafeMutablePointer",
349353
pointeeType),
350-
ImportHint::None};
351-
}
352-
353-
Type getOpaquePointerType() {
354-
return Impl.getNamedSwiftType(Impl.getStdlibModule(), "OpaquePointer");
354+
ImportHint::OtherPointer};
355355
}
356356

357357
ImportResult VisitBlockPointerType(const clang::BlockPointerType *type) {
@@ -568,11 +568,8 @@ namespace {
568568
hint = ImportHint::CFPointer;
569569
} else if (mappedType->isAnyExistentialType()) { // id, Class
570570
hint = ImportHint::ObjCPointer;
571-
} else if (type->isBlockPointerType()) {
572-
// FIXME: This should eventually be "isAnyPointerType", but right now
573-
// non-object, non-block pointers are never Optional in Swift; they
574-
// just can have a value of 'nil' themselves.
575-
hint = ImportHint::CustomNullablePointer;
571+
} else if (type->isPointerType() || type->isBlockPointerType()) {
572+
hint = ImportHint::OtherPointer;
576573
}
577574
// Any other interesting mapped types should be hinted here.
578575

lib/IDE/CodeCompletion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3309,6 +3309,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33093309
// If the expected type is ObjectiveC.Selector, add #selector.
33103310
if (Ctx.LangOpts.EnableObjCInterop) {
33113311
for (auto T : ExpectedTypes) {
3312+
T = T->lookThroughAllAnyOptionalTypes();
33123313
if (auto structDecl = T->getStructOrBoundGenericStruct()) {
33133314
if (structDecl->getName() == Ctx.Id_Selector &&
33143315
structDecl->getParentModule()->getName() == Ctx.Id_ObjectiveC) {

lib/IRGen/GenMeta.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1765,7 +1765,8 @@ namespace {
17651765
if (t == C.TheEmptyTupleType
17661766
|| t == C.TheNativeObjectType
17671767
|| t == C.TheUnknownObjectType
1768-
|| t == C.TheBridgeObjectType)
1768+
|| t == C.TheBridgeObjectType
1769+
|| t == C.TheRawPointerType)
17691770
return true;
17701771
if (auto intTy = dyn_cast<BuiltinIntegerType>(t)) {
17711772
auto width = intTy->getWidth();

lib/IRGen/GenType.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,53 @@ namespace {
411411
Alignment align)
412412
: PODSingleScalarTypeInfo(storage, size, std::move(spareBits), align) {}
413413
};
414-
414+
415+
/// A TypeInfo implementation for bare non-null pointers (like `void *`).
416+
class RawPointerTypeInfo final :
417+
public PODSingleScalarTypeInfo<RawPointerTypeInfo, LoadableTypeInfo> {
418+
public:
419+
RawPointerTypeInfo(llvm::Type *storage, Size size, Alignment align)
420+
: PODSingleScalarTypeInfo(
421+
storage, size,
422+
SpareBitVector::getConstant(size.getValueInBits(), false),
423+
align) {}
424+
425+
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
426+
return true;
427+
}
428+
429+
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
430+
return 1;
431+
}
432+
433+
APInt getFixedExtraInhabitantValue(IRGenModule &IGM, unsigned bits,
434+
unsigned index) const override {
435+
assert(index == 0);
436+
return APInt(bits, 0);
437+
}
438+
439+
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF,
440+
Address src,
441+
SILType T) const override {
442+
// Copied from BridgeObjectTypeInfo.
443+
src = IGF.Builder.CreateBitCast(src, IGF.IGM.IntPtrTy->getPointerTo());
444+
auto val = IGF.Builder.CreateLoad(src);
445+
auto zero = llvm::ConstantInt::get(IGF.IGM.IntPtrTy, 0);
446+
auto isNonzero = IGF.Builder.CreateICmpNE(val, zero);
447+
// We either have extra inhabitant 0 or no extra inhabitant (-1).
448+
// Conveniently, this is just a sext i1 -> i32 away.
449+
return IGF.Builder.CreateSExt(isNonzero, IGF.IGM.Int32Ty);
450+
}
451+
452+
void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index,
453+
Address dest, SILType T) const override {
454+
// Copied from BridgeObjectTypeInfo.
455+
// There's only one extra inhabitant, 0.
456+
dest = IGF.Builder.CreateBitCast(dest, IGF.IGM.IntPtrTy->getPointerTo());
457+
IGF.Builder.CreateStore(llvm::ConstantInt::get(IGF.IGM.IntPtrTy, 0),dest);
458+
}
459+
};
460+
415461
/// A TypeInfo implementation for opaque storage. Swift will preserve any
416462
/// data stored into this arbitrarily sized and aligned field, but doesn't
417463
/// know anything about the data.
@@ -720,6 +766,20 @@ const LoadableTypeInfo &TypeConverter::getBridgeObjectTypeInfo() {
720766
return *BridgeObjectTI;
721767
}
722768

769+
const LoadableTypeInfo &IRGenModule::getRawPointerTypeInfo() {
770+
return Types.getRawPointerTypeInfo();
771+
}
772+
773+
const LoadableTypeInfo &TypeConverter::getRawPointerTypeInfo() {
774+
if (RawPointerTI) return *RawPointerTI;
775+
RawPointerTI = new RawPointerTypeInfo(IGM.Int8PtrTy,
776+
IGM.getPointerSize(),
777+
IGM.getPointerAlignment());
778+
RawPointerTI->NextConverted = FirstType;
779+
FirstType = RawPointerTI;
780+
return *RawPointerTI;
781+
}
782+
723783
const LoadableTypeInfo &TypeConverter::getEmptyTypeInfo() {
724784
if (EmptyTI) return *EmptyTI;
725785
EmptyTI = new EmptyTypeInfo(IGM.Int8Ty);
@@ -1263,6 +1323,7 @@ TypeCacheEntry TypeConverter::convertType(CanType ty) {
12631323
getFixedBufferSize(IGM),
12641324
getFixedBufferAlignment(IGM));
12651325
case TypeKind::BuiltinRawPointer:
1326+
return &getRawPointerTypeInfo();
12661327
case TypeKind::BuiltinFloat:
12671328
case TypeKind::BuiltinInteger:
12681329
case TypeKind::BuiltinVector: {

lib/IRGen/GenType.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class TypeConverter {
8686
const LoadableTypeInfo *NativeObjectTI = nullptr;
8787
const LoadableTypeInfo *UnknownObjectTI = nullptr;
8888
const LoadableTypeInfo *BridgeObjectTI = nullptr;
89+
const LoadableTypeInfo *RawPointerTI = nullptr;
8990
const LoadableTypeInfo *WitnessTablePtrTI = nullptr;
9091
const LoadableTypeInfo *TypeMetadataPtrTI = nullptr;
9192
const LoadableTypeInfo *ObjCClassPtrTI = nullptr;
@@ -148,6 +149,7 @@ class TypeConverter {
148149
const LoadableTypeInfo &getNativeObjectTypeInfo();
149150
const LoadableTypeInfo &getUnknownObjectTypeInfo();
150151
const LoadableTypeInfo &getBridgeObjectTypeInfo();
152+
const LoadableTypeInfo &getRawPointerTypeInfo();
151153
const LoadableTypeInfo &getTypeMetadataPtrTypeInfo();
152154
const LoadableTypeInfo &getObjCClassPtrTypeInfo();
153155
const LoadableTypeInfo &getWitnessTablePtrTypeInfo();

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ class IRGenModule {
550550
const LoadableTypeInfo &getNativeObjectTypeInfo();
551551
const LoadableTypeInfo &getUnknownObjectTypeInfo();
552552
const LoadableTypeInfo &getBridgeObjectTypeInfo();
553+
const LoadableTypeInfo &getRawPointerTypeInfo();
553554
llvm::Type *getStorageTypeForUnlowered(Type T);
554555
llvm::Type *getStorageTypeForLowered(CanType T);
555556
llvm::Type *getStorageType(SILType T);

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
430430
// parameter, print it.
431431
if (errorConvention && i == errorConvention->getErrorParameterIndex()) {
432432
os << piece << ":(";
433-
print(errorConvention->getErrorParameterType(), OTK_None);
433+
print(errorConvention->getErrorParameterType(), None);
434434
os << ")error";
435435
continue;
436436
}
@@ -918,10 +918,8 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
918918
return false;
919919

920920
os << iter->second.first;
921-
if (iter->second.second) {
922-
// FIXME: Selectors and pointers should be nullable.
923-
printNullability(OptionalTypeKind::OTK_ImplicitlyUnwrappedOptional);
924-
}
921+
if (iter->second.second)
922+
printNullability(optionalKind);
925923
return true;
926924
}
927925

@@ -932,13 +930,6 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
932930
os << " */";
933931
}
934932

935-
bool isClangObjectPointerType(const clang::TypeDecl *clangTypeDecl) const {
936-
ASTContext &ctx = M.getASTContext();
937-
auto &clangASTContext = ctx.getClangModuleLoader()->getClangASTContext();
938-
clang::QualType clangTy = clangASTContext.getTypeDeclType(clangTypeDecl);
939-
return clangTy->isObjCRetainableType();
940-
}
941-
942933
bool isClangPointerType(const clang::TypeDecl *clangTypeDecl) const {
943934
ASTContext &ctx = M.getASTContext();
944935
auto &clangASTContext = ctx.getClangModuleLoader()->getClangASTContext();
@@ -958,13 +949,9 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
958949
auto *clangTypeDecl = cast<clang::TypeDecl>(alias->getClangDecl());
959950
os << clangTypeDecl->getName();
960951

961-
// Print proper nullability for CF types, but _Null_unspecified for
962-
// all other non-object Clang pointer types.
963952
if (aliasTy->hasReferenceSemantics() ||
964-
isClangObjectPointerType(clangTypeDecl)) {
953+
isClangPointerType(clangTypeDecl)) {
965954
printNullability(optionalKind);
966-
} else if (isClangPointerType(clangTypeDecl)) {
967-
printNullability(OptionalTypeKind::OTK_ImplicitlyUnwrappedOptional);
968955
}
969956
return;
970957
}
@@ -1069,8 +1056,7 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
10691056
if (isConst)
10701057
os << " const";
10711058
os << " *";
1072-
// FIXME: Pointer types should be nullable.
1073-
printNullability(OptionalTypeKind::OTK_ImplicitlyUnwrappedOptional);
1059+
printNullability(optionalKind);
10741060
return true;
10751061
}
10761062

lib/SIL/SILFunctionType.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,10 @@ enum class ConventionsKind : uint8_t {
379379
// (An ObjC class type wouldn't be const-qualified.)
380380
if (clangTy->isPointerType()
381381
&& clangTy->getPointeeType().isConstQualified()) {
382+
// Peek through optionals.
383+
if (auto substObjTy = substTy.getAnyOptionalObjectType())
384+
substTy = substObjTy;
385+
382386
// Void pointers aren't usefully indirectable.
383387
if (clangTy->isVoidPointerType())
384388
return false;
@@ -395,10 +399,6 @@ enum class ConventionsKind : uint8_t {
395399
// imported as methods.
396400
return false;
397401

398-
// Peek through optionals.
399-
if (auto substObjTy = substTy.getAnyOptionalObjectType())
400-
substTy = substObjTy;
401-
402402
if (clangTy->getPointeeType()->getAs<clang::RecordType>()) {
403403
// CF type as foreign class
404404
if (substTy->getClassOrBoundGenericClass()

lib/SILGen/SILGen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,10 @@ SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) {
300300
Type PointerInt8Ty = BoundGenericType::get(PointerDecl,
301301
nullptr,
302302
Int8Decl->getDeclaredType());
303+
Type OptPointerInt8Ty = OptionalType::get(PointerInt8Ty);
303304
PtrPtrInt8Ty = BoundGenericType::get(PointerDecl,
304305
nullptr,
305-
PointerInt8Ty)
306+
OptPointerInt8Ty)
306307
->getCanonicalType();
307308
}
308309
}

0 commit comments

Comments
 (0)