Skip to content

Commit 9cdbec1

Browse files
committed
Merge pull request #1878 from jrose-apple/optional-pointers
Implements SE-0055: "Make unsafe pointer nullability explicit using Optional"
2 parents 1056a9b + 8151aa1 commit 9cdbec1

File tree

158 files changed

+2877
-2233
lines changed

Some content is hidden

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

158 files changed

+2877
-2233
lines changed

CHANGELOG.md

+23
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@ Note: This is in reverse chronological order, so newer entries are added to the
33
Swift 3.0
44
-------
55

6+
* As part of the changes for SE-0055 (see below), the *pointee* types of
7+
imported pointers (e.g. the `id` in `id *`) are no longer assumed to always
8+
be `_Nullable` even if annotated otherwise. However, an implicit or explicit
9+
annotation of `_Null_unspecified` on a pointee type is still imported as
10+
`Optional`.
11+
12+
* [SE-0055](https://github.com/apple/swift-evolution/blob/master/proposals/0055-optional-unsafe-pointers.md):
13+
The types `UnsafePointer`, `UnsafeMutablePointer`,
14+
`AutoreleasingUnsafeMutablePointer`, `OpaquePointer`, `Selector`, and `Zone`
15+
(formerly `NSZone`) now represent non-nullable pointers, i.e. pointers that
16+
are never `nil`. A nullable pointer is now represented using `Optional`, e.g.
17+
`UnsafePointer<Int>?` For types imported from C, non-object pointers (such as
18+
`int *`) now have their nullability taken into account.
19+
20+
One possible area of difficulty is passing a nullable pointer to a function
21+
that uses C variadics. Swift will not permit this directly, so as a
22+
workaround please use the following idiom to pass it as a pointer-sized
23+
integer value instead:
24+
25+
```swift
26+
unsafeBitCast(nullablePointer, to: Int.self)
27+
```
28+
629
* [SE-0046] (https://github.com/apple/swift-evolution/blob/master/proposals/0046-first-label.md) Function parameters now have consistent labelling across all function parameters. With this update the first parameter declarations will now match the existing behavior of the second and later parameters. This change makes the language simpler.
730

831
Functions that were written and called as follows

include/swift/Runtime/Metadata.h

+5
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

+3-3
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

-4
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

+26-30
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
}
@@ -151,17 +150,16 @@ namespace {
151150
getOptionalType(Type payloadType,
152151
ImportTypeKind kind,
153152
OptionalTypeKind OptKind = OTK_ImplicitlyUnwrappedOptional) {
154-
// Import pointee types as true Optional.
155-
if (kind == ImportTypeKind::Pointee)
156-
return OptionalType::get(payloadType);
157-
158153
switch (OptKind) {
159-
case OTK_ImplicitlyUnwrappedOptional:
160-
return ImplicitlyUnwrappedOptionalType::get(payloadType);
161-
case OTK_None:
162-
return payloadType;
163-
case OTK_Optional:
154+
case OTK_None:
155+
return payloadType;
156+
case OTK_Optional:
157+
return OptionalType::get(payloadType);
158+
case OTK_ImplicitlyUnwrappedOptional:
159+
// Import pointee types as true Optional.
160+
if (kind == ImportTypeKind::Pointee)
164161
return OptionalType::get(payloadType);
162+
return ImplicitlyUnwrappedOptionalType::get(payloadType);
165163
}
166164
}
167165

@@ -292,7 +290,7 @@ namespace {
292290
Impl.SwiftContext.getSwiftName(
293291
KnownFoundationEntity::NSZone));
294292
if (wrapperTy)
295-
return wrapperTy;
293+
return {wrapperTy, ImportHint::OtherPointer};
296294
}
297295
}
298296

@@ -315,7 +313,8 @@ namespace {
315313
// If the pointed-to type is unrepresentable in Swift, import as
316314
// OpaquePointer.
317315
if (!pointeeType)
318-
return getOpaquePointerType();
316+
return {Impl.SwiftContext.getOpaquePointerDecl()->getDeclaredType(),
317+
ImportHint::OtherPointer};
319318

320319
if (pointeeQualType->isFunctionType()) {
321320
auto funcTy = pointeeType->castTo<FunctionType>();
@@ -329,29 +328,29 @@ namespace {
329328

330329
auto quals = pointeeQualType.getQualifiers();
331330

332-
if (quals.hasConst())
331+
if (quals.hasConst()) {
333332
return {Impl.getNamedSwiftTypeSpecialization(Impl.getStdlibModule(),
334333
"UnsafePointer",
335334
pointeeType),
336-
ImportHint::None};
335+
ImportHint::OtherPointer};
336+
}
337+
337338
// Mutable pointers with __autoreleasing or __unsafe_unretained
338339
// ownership map to AutoreleasingUnsafeMutablePointer<T>.
339-
else if (quals.getObjCLifetime() == clang::Qualifiers::OCL_Autoreleasing
340-
|| quals.getObjCLifetime() == clang::Qualifiers::OCL_ExplicitNone)
340+
if (quals.getObjCLifetime() == clang::Qualifiers::OCL_Autoreleasing ||
341+
quals.getObjCLifetime() == clang::Qualifiers::OCL_ExplicitNone) {
341342
return {
342343
Impl.getNamedSwiftTypeSpecialization(
343344
Impl.getStdlibModule(), "AutoreleasingUnsafeMutablePointer",
344345
pointeeType),
345-
ImportHint::None};
346+
ImportHint::OtherPointer};
347+
}
348+
346349
// All other mutable pointers map to UnsafeMutablePointer.
347350
return {Impl.getNamedSwiftTypeSpecialization(Impl.getStdlibModule(),
348351
"UnsafeMutablePointer",
349352
pointeeType),
350-
ImportHint::None};
351-
}
352-
353-
Type getOpaquePointerType() {
354-
return Impl.getNamedSwiftType(Impl.getStdlibModule(), "OpaquePointer");
353+
ImportHint::OtherPointer};
355354
}
356355

357356
ImportResult VisitBlockPointerType(const clang::BlockPointerType *type) {
@@ -568,11 +567,8 @@ namespace {
568567
hint = ImportHint::CFPointer;
569568
} else if (mappedType->isAnyExistentialType()) { // id, Class
570569
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;
570+
} else if (type->isPointerType() || type->isBlockPointerType()) {
571+
hint = ImportHint::OtherPointer;
576572
}
577573
// Any other interesting mapped types should be hinted here.
578574

lib/IDE/CodeCompletion.cpp

+1
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

+2-1
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

+62-1
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

+2
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

+1
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

+5-19
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

0 commit comments

Comments
 (0)