Merge pull request #10462 from xedin/closure-diagnostics-4.0
[4.0] [QoI] Improve diagnostics for single argument calls with trailing closures
diff --git a/docs/Runtime.md b/docs/Runtime.md
index 2da0813..6d62b46 100644
--- a/docs/Runtime.md
+++ b/docs/Runtime.md
@@ -71,6 +71,7 @@
```
000000000001cb30 T _swift_allocBox
+000000000001cb30 T _swift_allocEmptyBox
000000000001c990 T _swift_allocObject
000000000001ca60 T _swift_bufferAllocate
000000000001ca90 T _swift_bufferHeaderSize
diff --git a/include/swift/ABI/KeyPath.h b/include/swift/ABI/KeyPath.h
index dd48ae3..199598d 100644
--- a/include/swift/ABI/KeyPath.h
+++ b/include/swift/ABI/KeyPath.h
@@ -173,14 +173,13 @@
enum ComputedPropertyIDKind {
Pointer,
- StoredPropertyOffset,
+ StoredPropertyIndex,
VTableOffset,
};
constexpr static uint32_t
getResolutionStrategy(ComputedPropertyIDKind idKind) {
return idKind == Pointer ? _SwiftKeyPathComponentHeader_ComputedIDUnresolvedIndirectPointer
- : idKind == StoredPropertyOffset ? _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFieldOffset
: (assert("no resolution strategy implemented" && false), 0);
}
@@ -196,7 +195,7 @@
? _SwiftKeyPathComponentHeader_ComputedSettableFlag : 0)
| (kind == SettableMutating
? _SwiftKeyPathComponentHeader_ComputedMutatingFlag : 0)
- | (idKind == StoredPropertyOffset
+ | (idKind == StoredPropertyIndex
? _SwiftKeyPathComponentHeader_ComputedIDByStoredPropertyFlag : 0)
| (idKind == VTableOffset
? _SwiftKeyPathComponentHeader_ComputedIDByVTableOffsetFlag : 0)
diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def
index 0b02cf9..1e683fb 100644
--- a/include/swift/AST/DiagnosticsParse.def
+++ b/include/swift/AST/DiagnosticsParse.def
@@ -182,6 +182,9 @@
"expected declaration", ())
ERROR(expected_identifier_in_decl,none,
"expected identifier in %0 declaration", (StringRef))
+ERROR(number_cant_start_decl_name,none,
+ "%0 name can only start with a letter or underscore, not a number",
+ (StringRef))
ERROR(expected_identifier_after_case_comma,none,
"expected identifier after comma in enum 'case' declaration", ())
ERROR(decl_redefinition,none,
diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def
index e92cd92..ceb7b82 100644
--- a/include/swift/AST/DiagnosticsSema.def
+++ b/include/swift/AST/DiagnosticsSema.def
@@ -267,6 +267,18 @@
"declared closure result %0 is incompatible with contextual type %1",
(Type, Type))
+// FIXME: make this an error when we've fixed the Dispatch problem.
+WARNING(err_noescape_param_call,none,
+ "passing a %select{|closure which captures a }1non-escaping function "
+ "parameter %0 to a call to a non-escaping function parameter can allow "
+ "re-entrant modification of a variable",
+ (DeclName, unsigned))
+WARNING(warn_noescape_param_call,none,
+ "passing a %select{|closure which captures a }1non-escaping function "
+ "parameter %0 to a call to a non-escaping function parameter can allow "
+ "re-entrant modification of a variable and will be illegal in Swift 4",
+ (DeclName, unsigned))
+
ERROR(cannot_call_function_value,none,
"cannot invoke value of function type with argument list '%0'",
(StringRef))
@@ -1337,9 +1349,6 @@
"inheritance clause", (Type))
ERROR(extension_protocol_inheritance,none,
"extension of protocol %0 cannot have an inheritance clause", (Type))
-ERROR(extension_protocol_via_typealias,none,
- "protocol %0 in the module being compiled cannot be extended via a "
- "type alias", (Type))
ERROR(objc_generic_extension_using_type_parameter,none,
"extension of a generic Objective-C class cannot access the class's "
"generic parameters at runtime", ())
diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h
index 5dc5f9b..846bbfd 100644
--- a/include/swift/AST/Expr.h
+++ b/include/swift/AST/Expr.h
@@ -2858,9 +2858,11 @@
SourceIsScalar_t isSourceScalar,
ConcreteDeclRef defaultArgsOwner,
ArrayRef<unsigned> VariadicArgs,
- MutableArrayRef<Expr *> CallerDefaultArgs, Type ty)
+ Type VarargsArrayTy,
+ MutableArrayRef<Expr *> CallerDefaultArgs,
+ Type ty)
: ImplicitConversionExpr(ExprKind::TupleShuffle, subExpr, ty),
- ElementMapping(elementMapping), VarargsArrayTy(),
+ ElementMapping(elementMapping), VarargsArrayTy(VarargsArrayTy),
DefaultArgsOwner(defaultArgsOwner), VariadicArgs(VariadicArgs),
CallerDefaultArgs(CallerDefaultArgs)
{
@@ -2876,8 +2878,6 @@
/// single-element tuple for the purposes of interpreting behavior.
bool isSourceScalar() const { return TupleShuffleExprBits.IsSourceScalar; }
- /// Set the varargs array type to use.
- void setVarargsArrayType(Type T) { VarargsArrayTy = T; }
Type getVarargsArrayType() const {
assert(!VarargsArrayTy.isNull());
return VarargsArrayTy;
diff --git a/include/swift/Runtime/HeapObject.h b/include/swift/Runtime/HeapObject.h
index 66d7198..b4c1ae0 100644
--- a/include/swift/Runtime/HeapObject.h
+++ b/include/swift/Runtime/HeapObject.h
@@ -169,6 +169,10 @@
BoxPair::Return swift_makeBoxUnique(OpaqueValue *buffer, Metadata const *type,
size_t alignMask);
+/// Returns the address of a heap object representing all empty box types.
+SWIFT_RUNTIME_EXPORT
+HeapObject* swift_allocEmptyBox();
+
// Allocate plain old memory. This is the generalized entry point
// Never returns nil. The returned memory is uninitialized.
//
diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h
index 544780d..38009f8 100644
--- a/include/swift/Runtime/Metadata.h
+++ b/include/swift/Runtime/Metadata.h
@@ -1840,6 +1840,9 @@
static bool classof(const TargetMetadata<Runtime> *metadata) {
return metadata->getKind() == MetadataKind::HeapLocalVariable;
}
+ constexpr TargetHeapLocalVariableMetadata()
+ : TargetHeapMetadata<Runtime>(MetadataKind::HeapLocalVariable),
+ OffsetToFirstCapture(0), CaptureDescription(nullptr) {}
};
using HeapLocalVariableMetadata
= TargetHeapLocalVariableMetadata<InProcess>;
diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def
index 75c885b..8305984 100644
--- a/include/swift/Runtime/RuntimeFunctions.def
+++ b/include/swift/Runtime/RuntimeFunctions.def
@@ -73,6 +73,11 @@
ARGS(RefCountedPtrTy),
ATTRS(NoUnwind, ReadNone))
+FUNCTION(AllocEmptyBox, swift_allocEmptyBox, DefaultCC,
+ RETURNS(RefCountedPtrTy),
+ ARGS(),
+ ATTRS(NoUnwind))
+
// RefCounted *swift_allocObject(Metadata *type, size_t size, size_t alignMask);
FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(AllocObject, swift_allocObject,
_swift_allocObject, _swift_allocObject_, RegisterPreservingCC,
diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp
index 4d6a324..394b1d1 100644
--- a/lib/AST/DeclContext.cpp
+++ b/lib/AST/DeclContext.cpp
@@ -61,17 +61,10 @@
auto ED = cast<ExtensionDecl>(this);
auto type = ED->getExtendedType();
- if (type.isNull() || type->hasError())
+ if (!type)
return nullptr;
- if (auto ND = type->getNominalOrBoundGenericNominal())
- return ND;
-
- if (auto unbound = dyn_cast<UnboundGenericType>(type.getPointer())) {
- return unbound->getDecl();
- }
-
- return nullptr;
+ return type->getAnyNominal();
}
case DeclContextKind::GenericTypeDecl:
diff --git a/lib/IRGen/ConstantBuilder.h b/lib/IRGen/ConstantBuilder.h
index c0c975e..71eaa00 100644
--- a/lib/IRGen/ConstantBuilder.h
+++ b/lib/IRGen/ConstantBuilder.h
@@ -107,6 +107,14 @@
Size getNextOffsetFromGlobal() const {
return Size(super::getNextOffsetFromGlobal().getQuantity());
}
+
+ void addAlignmentPadding(Alignment align) {
+ auto misalignment = getNextOffsetFromGlobal() % IGM().getPointerAlignment();
+ if (misalignment != Size(0))
+ add(llvm::ConstantAggregateZero::get(
+ llvm::ArrayType::get(IGM().Int8Ty,
+ align.getValue() - misalignment.getValue())));
+ }
};
class ConstantArrayBuilder
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index b123200..56e7402 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -506,6 +506,13 @@
}
}
+unsigned
+irgen::getClassFieldIndex(IRGenModule &IGM, SILType baseType, VarDecl *field) {
+ auto &baseClassTI = IGM.getTypeInfo(baseType).as<ClassTypeInfo>();
+ auto &classLayout = baseClassTI.getClassLayout(IGM, baseType);
+ return classLayout.getFieldIndex(field);
+}
+
FieldAccess
irgen::getClassFieldAccess(IRGenModule &IGM, SILType baseType, VarDecl *field) {
auto &baseClassTI = IGM.getTypeInfo(baseType).as<ClassTypeInfo>();
diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h
index 55f664c..6656897 100644
--- a/lib/IRGen/GenClass.h
+++ b/lib/IRGen/GenClass.h
@@ -140,6 +140,10 @@
SILType baseType,
VarDecl *field);
+ unsigned getClassFieldIndex(IRGenModule &IGM,
+ SILType baseType,
+ VarDecl *field);
+
FieldAccess getClassFieldAccess(IRGenModule &IGM,
SILType baseType,
VarDecl *field);
diff --git a/lib/IRGen/GenHeap.cpp b/lib/IRGen/GenHeap.cpp
index 6220aeb..c1421e1 100644
--- a/lib/IRGen/GenHeap.cpp
+++ b/lib/IRGen/GenHeap.cpp
@@ -1430,7 +1430,7 @@
allocate(IRGenFunction &IGF, SILType boxedType, GenericEnvironment *env,
const llvm::Twine &name) const override {
return OwnedAddress(IGF.getTypeInfo(boxedType).getUndefAddress(),
- IGF.IGM.RefCountedNull);
+ IGF.emitAllocEmptyBoxCall());
}
void
@@ -1584,7 +1584,11 @@
// For fixed-sized types, we can emit concrete box metadata.
auto &fixedTI = cast<FixedTypeInfo>(eltTI);
- // For empty types, we don't really need to allocate anything.
+ // Because we assume in enum's that payloads with a Builtin.NativeObject which
+ // is also the type for indirect enum cases have extra inhabitants of pointers
+ // we can't have a nil pointer as a representation for an empty box type --
+ // nil conflicts with the extra inhabitants. We return a static singleton
+ // empty box object instead.
if (fixedTI.isKnownEmpty(ResilienceExpansion::Maximal)) {
if (!EmptyBoxTI)
EmptyBoxTI = new EmptyBoxTypeInfo(IGM);
diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp
index daf39d9..e7bf073 100644
--- a/lib/IRGen/GenKeyPath.cpp
+++ b/lib/IRGen/GenKeyPath.cpp
@@ -123,7 +123,7 @@
fields.add(emitMetadataGenerator(rootTy));
fields.add(emitMetadataGenerator(valueTy));
- // TODO: 32-bit still has a padding word
+ // TODO: 32-bit heap object header still has an extra word
if (SizeTy == Int32Ty) {
fields.addInt32(0);
}
@@ -155,65 +155,31 @@
// Leave a placeholder for the buffer header, since we need to know the full
// buffer size to fill it in.
auto headerPlaceholder = fields.addPlaceholderWithSize(Int32Ty);
+ fields.addAlignmentPadding(getPointerAlignment());
auto startOfKeyPathBuffer = fields.getNextOffsetFromGlobal();
// Build out the components.
auto baseTy = rootTy;
- auto getPropertyOffsetOrIndirectOffset
- = [&](SILType loweredBaseTy, VarDecl *property)
- -> std::pair<llvm::Constant*, bool> {
- llvm::Constant *offset;
- bool isResolved;
- bool isStruct;
- if (loweredBaseTy.getStructOrBoundGenericStruct()) {
- offset = emitPhysicalStructMemberFixedOffset(*this,
- loweredBaseTy,
- property);
- isStruct = true;
- } else if (loweredBaseTy.getClassOrBoundGenericClass()) {
- offset = tryEmitConstantClassFragilePhysicalMemberOffset(*this,
- loweredBaseTy,
- property);
- isStruct = false;
- } else {
- llvm_unreachable("property of non-struct, non-class?!");
- }
-
- // If the offset isn't fixed, try instead to get the field offset vector
- // offset for the field to look it up dynamically.
- isResolved = offset != nullptr;
- if (!isResolved) {
- if (isStruct) {
- offset = emitPhysicalStructMemberOffsetOfFieldOffset(
- *this, loweredBaseTy, property);
- assert(offset && "field is neither fixed-offset nor in offset vector");
- } else {
- auto offsetValue = getClassFieldOffset(*this,
- loweredBaseTy.getClassOrBoundGenericClass(),
- property);
- offset = llvm::ConstantInt::get(Int32Ty, offsetValue.getValue());
- }
- }
-
- return {offset, isResolved};
- };
+ auto assertPointerAlignment = [&]{
+ assert(fields.getNextOffsetFromGlobal() % getPointerAlignment() == Size(0)
+ && "must be pointer-aligned here");
+ };
for (unsigned i : indices(pattern->getComponents())) {
+ assertPointerAlignment();
SILType loweredBaseTy;
Lowering::GenericContextScope scope(getSILTypes(),
pattern->getGenericSignature());
loweredBaseTy = getLoweredType(AbstractionPattern::getOpaque(),
baseTy->getLValueOrInOutObjectType());
-
auto &component = pattern->getComponents()[i];
switch (auto kind = component.getKind()) {
case KeyPathPatternComponent::Kind::StoredProperty: {
auto property = cast<VarDecl>(component.getStoredPropertyDecl());
auto addFixedOffset = [&](bool isStruct, llvm::Constant *offset) {
- offset = llvm::ConstantExpr::getTruncOrBitCast(offset, Int32Ty);
if (auto offsetInt = dyn_cast_or_null<llvm::ConstantInt>(offset)) {
auto offsetValue = offsetInt->getValue().getZExtValue();
if (KeyPathComponentHeader::offsetCanBeInline(offsetValue)) {
@@ -228,7 +194,7 @@
? KeyPathComponentHeader::forStructComponentWithOutOfLineOffset()
: KeyPathComponentHeader::forClassComponentWithOutOfLineOffset();
fields.addInt32(header.getData());
- fields.add(offset);
+ fields.add(llvm::ConstantExpr::getTruncOrBitCast(offset, Int32Ty));
};
// For a struct stored property, we may know the fixed offset of the field,
@@ -247,11 +213,10 @@
// of the type metadata at instantiation time.
auto fieldOffset = emitPhysicalStructMemberOffsetOfFieldOffset(
*this, loweredBaseTy, property);
- fieldOffset = llvm::ConstantExpr::getTruncOrBitCast(fieldOffset,
- Int32Ty);
auto header = KeyPathComponentHeader::forStructComponentWithUnresolvedFieldOffset();
fields.addInt32(header.getData());
- fields.add(fieldOffset);
+ fields.add(llvm::ConstantExpr::getTruncOrBitCast(fieldOffset,
+ Int32Ty));
break;
}
@@ -276,6 +241,7 @@
auto header =
KeyPathComponentHeader::forClassComponentWithUnresolvedIndirectOffset();
fields.addInt32(header.getData());
+ fields.addAlignmentPadding(getPointerAlignment());
auto offsetVar = getAddrOfFieldOffset(property, /*indirect*/ false,
NotForDefinition);
fields.add(cast<llvm::Constant>(offsetVar.getAddress()));
@@ -358,10 +324,36 @@
break;
}
case KeyPathPatternComponent::ComputedPropertyId::Property:
- idKind = KeyPathComponentHeader::StoredPropertyOffset;
- std::tie(idValue, idResolved) =
- getPropertyOffsetOrIndirectOffset(loweredBaseTy, id.getProperty());
- idValue = llvm::ConstantExpr::getZExtOrBitCast(idValue, SizeTy);
+ // Use the index of the stored property within the aggregate to key
+ // the property.
+ auto property = id.getProperty();
+ idKind = KeyPathComponentHeader::StoredPropertyIndex;
+ if (baseTy->getStructOrBoundGenericStruct()) {
+ idResolved = true;
+ idValue = llvm::ConstantInt::get(SizeTy,
+ getPhysicalStructFieldIndex(*this,
+ SILType::getPrimitiveAddressType(baseTy), property));
+ } else if (baseTy->getClassOrBoundGenericClass()) {
+ // TODO: This field index would require runtime resolution with Swift
+ // native class resilience. We never directly access ObjC-imported
+ // ivars so we can disregard ObjC ivar resilience for this computation
+ // and start counting at the Swift native root.
+ switch (getClassFieldAccess(*this, loweredBaseTy, property)) {
+ case FieldAccess::ConstantDirect:
+ case FieldAccess::ConstantIndirect:
+ case FieldAccess::NonConstantDirect:
+ idResolved = true;
+ idValue = llvm::ConstantInt::get(SizeTy,
+ getClassFieldIndex(*this,
+ SILType::getPrimitiveAddressType(baseTy), property));
+ break;
+ case FieldAccess::NonConstantIndirect:
+ llvm_unreachable("not implemented");
+ }
+
+ } else {
+ llvm_unreachable("neither struct nor class");
+ }
break;
}
@@ -369,6 +361,7 @@
idKind, !isInstantiableInPlace, idResolved);
fields.addInt32(header.getData());
+ fields.addAlignmentPadding(getPointerAlignment());
fields.add(idValue);
if (isInstantiableInPlace) {
@@ -392,6 +385,7 @@
// For all but the last component, we pack in the type of the component.
if (i + 1 != pattern->getComponents().size()) {
+ fields.addAlignmentPadding(getPointerAlignment());
fields.add(emitMetadataGenerator(component.getComponentType()));
}
baseTy = component.getComponentType();
diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp
index 0b91a76..e9a95db 100644
--- a/lib/IRGen/IRGenFunction.cpp
+++ b/lib/IRGen/IRGenFunction.cpp
@@ -209,6 +209,20 @@
return call;
}
+llvm::Value *IRGenFunction::emitAllocEmptyBoxCall() {
+ llvm::Attribute::AttrKind attrKinds[] = {
+ llvm::Attribute::NoUnwind,
+ };
+ auto attrs = llvm::AttributeSet::get(IGM.LLVMContext,
+ llvm::AttributeSet::FunctionIndex,
+ attrKinds);
+ llvm::CallInst *call =
+ Builder.CreateCall(IGM.getAllocEmptyBoxFn(), {});
+ call->setCallingConv(IGM.DefaultCC);
+ call->setAttributes(attrs);
+ return call;
+}
+
static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn,
std::initializer_list<llvm::Value *> args) {
auto cc = IGF.IGM.DefaultCC;
diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h
index d28a092..ab552dc 100644
--- a/lib/IRGen/IRGenFunction.h
+++ b/lib/IRGen/IRGenFunction.h
@@ -188,6 +188,8 @@
llvm::Value *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata);
+ llvm::Value *emitAllocEmptyBoxCall();
+
// Emit a reference to the canonical type metadata record for the given AST
// type. This can be used to identify the type at runtime. For types with
// abstraction difference, the metadata contains the layout information for
diff --git a/lib/Migrator/TupleSplatMigratorPass.cpp b/lib/Migrator/TupleSplatMigratorPass.cpp
index d1ecc1e..8c77492 100644
--- a/lib/Migrator/TupleSplatMigratorPass.cpp
+++ b/lib/Migrator/TupleSplatMigratorPass.cpp
@@ -96,20 +96,10 @@
}
unsigned ClosureArity = Closure->getParameters()->size();
- if (NativeArity == ClosureArity)
+ if (NativeArity <= ClosureArity)
return false;
ShorthandFinder Finder(Closure);
- if (NativeArity == 1 && ClosureArity > 1) {
- // Prepend $0. to existing references
- Finder.forEachReference([this](Expr *Ref, ParamDecl* Def) {
- if (auto *TE = dyn_cast<TupleElementExpr>(Ref))
- Ref = TE->getBase();
- SourceLoc AfterDollar = Ref->getStartLoc().getAdvancedLoc(1);
- Editor.insert(AfterDollar, "0.");
- });
- return true;
- }
if (ClosureArity == 1 && NativeArity > 1) {
// Remove $0. from existing references or if it's only $0, replace it
@@ -176,161 +166,8 @@
return true;
};
- // Handles such kind of cases:
- // \code
- // func test(_: ((Int, Int)) -> ()) {}
- // test({ (x,y) in })
- // \endcode
- // This compiles fine in Swift 3 but Swift 4 complains with
- // error: cannot convert value of type '(_, _) -> ()' to expected
- // argument type '((Int, Int)) -> ()'
- //
- // It will fix the code to "test({ let (x,y) = $0; })".
- //
- auto handleTupleMapToClosureArgs = [&](const CallExpr *E) -> bool {
- auto fnTy = E->getFn()->getType()->getAs<FunctionType>();
- if (!fnTy)
- return false;
- auto fnTy2 = fnTy->getInput()->getAs<FunctionType>();
- if (!fnTy2) {
- // This may have been a tuple type of one element.
- if (auto tuple = fnTy->getInput()->getAs<TupleType>()) {
- if (tuple->getNumElements() == 1) {
- fnTy2 = tuple->getElement(0).getType()->getAs<FunctionType>();
- }
- }
- }
- if (!fnTy2) {
- return false;
- }
- auto parenT = dyn_cast<ParenType>(fnTy2->getInput().getPointer());
- if (!parenT)
- return false;
- auto tupleInFn = parenT->getAs<TupleType>();
- if (!tupleInFn)
- return false;
- if (!E->getArg())
- return false;
- auto argE = E->getArg()->getSemanticsProvidingExpr();
- while (auto *ICE = dyn_cast<ImplicitConversionExpr>(argE))
- argE = ICE->getSubExpr();
- argE = argE->getSemanticsProvidingExpr();
- auto closureE = dyn_cast<ClosureExpr>(argE);
- if (!closureE) {
- if (auto *FCE = dyn_cast<FunctionConversionExpr>(argE)) {
- closureE = dyn_cast<ClosureExpr>(FCE->getSubExpr());
- }
- }
- if (!closureE)
- return false;
- if (closureE->getInLoc().isInvalid())
- return false;
- auto paramList = closureE->getParameters();
- if (!paramList ||
- paramList->getLParenLoc().isInvalid() || paramList->getRParenLoc().isInvalid())
- return false;
- if (paramList->size() != tupleInFn->getNumElements())
- return false;
- if (paramList->size() == 0)
- return false;
-
- auto hasParamListWithNoTypes = [&]() {
- if (closureE->hasExplicitResultType())
- return false;
- for (auto *param : *paramList) {
- auto tyLoc = param->getTypeLoc();
- if (!tyLoc.isNull())
- return false;
- }
- return true;
- };
-
- if (hasParamListWithNoTypes()) {
- // Simpler form depending on type inference.
- // Change "(x, y) in " to "let (x, y) = $0;".
-
- Editor.insert(paramList->getLParenLoc(), "let ");
- for (auto *param : *paramList) {
- // If the argument list is like "(_ x, _ y)", remove the underscores.
- if (param->getArgumentNameLoc().isValid()) {
- Editor.remove(CharSourceRange(SM, param->getArgumentNameLoc(),
- param->getNameLoc()));
- }
- // If the argument list has type annotations, remove them.
- auto tyLoc = param->getTypeLoc();
- if (!tyLoc.isNull() && !tyLoc.getSourceRange().isInvalid()) {
- auto nameRange = CharSourceRange(param->getNameLoc(),
- param->getNameStr().size());
- auto tyRange = Lexer::getCharSourceRangeFromSourceRange(SM,
- tyLoc.getSourceRange());
- Editor.remove(CharSourceRange(SM, nameRange.getEnd(),
- tyRange.getEnd()));
- }
- }
-
- // If the original closure was a single expression without the need
- // for a `return` statement, it needs one now, because we've added a new
- // assignment statement just above.
- if (closureE->hasSingleExpressionBody()) {
- Editor.replaceToken(closureE->getInLoc(), "= $0; return");
- } else {
- Editor.replaceToken(closureE->getInLoc(), "= $0;");
- }
-
- return true;
- }
-
- // Includes types in the closure signature. The following will do a
- // more complicated edit than the above:
- // (x: Int, y: Int) -> Int in
- // to
- // (__val:(Int, Int)) -> Int in let (x,y) = __val;
-
- std::string paramListText;
- {
- llvm::raw_string_ostream OS(paramListText);
- OS << "(__val:(";
- for (size_t i = 0, e = paramList->size(); i != e; ++i) {
- if (i != 0)
- OS << ", ";
- auto param = paramList->get(i);
- auto tyLoc = param->getTypeLoc();
- if (!tyLoc.isNull() && !tyLoc.getSourceRange().isInvalid()) {
- OS << SM.extractText(
- Lexer::getCharSourceRangeFromSourceRange(SM,
- tyLoc.getSourceRange()));
- } else {
- param->getType().print(OS);
- }
- }
- OS << "))";
- }
- std::string varBindText;
- {
- llvm::raw_string_ostream OS(varBindText);
- OS << " let (";
- for (size_t i = 0, e = paramList->size(); i != e; ++i) {
- if (i != 0)
- OS << ",";
- auto param = paramList->get(i);
- OS << param->getNameStr();
- }
- OS << ") = __val;";
-
- if (closureE->hasSingleExpressionBody()) {
- OS << " return";
- }
- }
-
- Editor.replace(paramList->getSourceRange(), paramListText);
- Editor.insertAfterToken(closureE->getInLoc(), varBindText);
- return true;
- };
-
if (handleCallsToEmptyTuple(E))
return;
- if (handleTupleMapToClosureArgs(E))
- return;
}
bool walkToExprPre(Expr *E) override {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 158f3ed..1f4a382 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2739,6 +2739,23 @@
P.checkForInputIncomplete();
+ if (P.Tok.is(tok::integer_literal) || P.Tok.is(tok::floating_literal) ||
+ (P.Tok.is(tok::unknown) && isdigit(P.Tok.getText()[0]))) {
+ // Per rdar://problem/32316666, using numbers for identifiers is a common
+ // error for beginners, so it's worth handling this in a special way.
+ P.diagnose(P.Tok, diag::number_cant_start_decl_name, DeclKindName);
+
+ // Pretend this works as an identifier, which shouldn't be observable since
+ // actual uses of it will hit random other errors, e.g. `1()` won't be
+ // callable.
+ Result = P.Context.getIdentifier(P.Tok.getText());
+ Loc = P.Tok.getLoc();
+ P.consumeToken();
+
+ // We recovered, so this is a success.
+ return makeParserSuccess();
+ }
+
if (P.Tok.isKeyword()) {
P.diagnose(P.Tok, diag::keyword_cant_be_identifier, P.Tok.getText());
P.diagnose(P.Tok, diag::backticks_to_escape)
@@ -4682,7 +4699,12 @@
Token NameTok = Tok;
SourceLoc NameLoc;
- if (Tok.is(tok::identifier) || Tok.isKeyword()) {
+ if (Tok.isAny(tok::identifier, tok::integer_literal, tok::floating_literal,
+ tok::unknown) ||
+ Tok.isKeyword()) {
+ // This non-operator path is quite accepting of what tokens might be a name,
+ // because we're aggressive about recovering/providing good diagnostics for
+ // beginners.
ParserStatus NameStatus =
parseIdentifierDeclName(*this, SimpleName, NameLoc, "function",
tok::l_paren, tok::arrow, tok::l_brace,
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index 752701c..179e84b 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -1422,8 +1422,6 @@
// in the metatype.
assert(!declRef.getDecl()->getDeclContext()->isTypeContext()
&& "c pointers to static methods not implemented");
- assert(declRef.getSubstitutions().empty()
- && "c pointers to generics not implemented");
loc = declRef.getDecl();
};
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index e5c837d..3a4d0f5 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -4877,20 +4877,17 @@
// Create the tuple shuffle.
ArrayRef<int> mapping = tc.Context.AllocateCopy(sources);
auto callerDefaultArgsCopy = tc.Context.AllocateCopy(callerDefaultArgs);
- auto shuffle =
+ return
cs.cacheType(new (tc.Context) TupleShuffleExpr(
expr, mapping,
TupleShuffleExpr::SourceIsTuple,
callee,
tc.Context.AllocateCopy(variadicArgs),
+ arrayType,
callerDefaultArgsCopy,
toSugarType));
- shuffle->setVarargsArrayType(arrayType);
- return shuffle;
}
-
-
Expr *ExprRewriter::coerceScalarToTuple(Expr *expr, TupleType *toTuple,
int toScalarIdx,
ConstraintLocatorBuilder locator) {
@@ -4975,13 +4972,13 @@
Type destSugarTy = hasInit? toTuple
: TupleType::get(sugarFields, tc.Context);
-
- return cs.cacheType(
- new (tc.Context) TupleShuffleExpr(expr,
+
+ return cs.cacheType(new (tc.Context) TupleShuffleExpr(expr,
tc.Context.AllocateCopy(elements),
TupleShuffleExpr::SourceIsScalar,
callee,
tc.Context.AllocateCopy(variadicArgs),
+ arrayType,
tc.Context.AllocateCopy(callerDefaultArgs),
destSugarTy));
}
@@ -5609,16 +5606,15 @@
// Create the tuple shuffle.
ArrayRef<int> mapping = tc.Context.AllocateCopy(sources);
auto callerDefaultArgsCopy = tc.Context.AllocateCopy(callerDefaultArgs);
- auto *shuffle =
+ return
cs.cacheType(new (tc.Context) TupleShuffleExpr(
arg, mapping,
isSourceScalar,
callee,
tc.Context.AllocateCopy(variadicArgs),
+ sliceType,
callerDefaultArgsCopy,
paramType));
- shuffle->setVarargsArrayType(sliceType);
- return shuffle;
}
static ClosureExpr *getClosureLiteralExpr(Expr *expr) {
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 6985707..12b19e9 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1372,7 +1372,9 @@
typeVar2 = dyn_cast<TypeVariableType>(type2.getPointer());
// If the types are obviously equivalent, we're done.
- if (type1.getPointer() == type2.getPointer())
+ if (isa<ParenType>(type1.getPointer()) ==
+ isa<ParenType>(type2.getPointer()) &&
+ type1->isEqual(type2))
return SolutionKind::Solved;
} else {
typeVar1 = desugar1->getAs<TypeVariableType>();
diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp
index 2a41dc4..07754f4 100644
--- a/lib/Sema/MiscDiagnostics.cpp
+++ b/lib/Sema/MiscDiagnostics.cpp
@@ -210,7 +210,7 @@
}
// Verify noescape parameter uses.
- checkNoEscapeParameterUse(DRE, nullptr);
+ checkNoEscapeParameterUse(DRE, nullptr, OperandKind::None);
// Verify warn_unqualified_access uses.
checkUnqualifiedAccessUse(DRE);
@@ -239,7 +239,7 @@
if (auto MakeEsc = dyn_cast<MakeTemporarilyEscapableExpr>(E)) {
if (auto DRE =
dyn_cast<DeclRefExpr>(MakeEsc->getNonescapingClosureValue()))
- checkNoEscapeParameterUse(DRE, MakeEsc);
+ checkNoEscapeParameterUse(DRE, MakeEsc, OperandKind::MakeEscapable);
}
// Check function calls, looking through implicit conversions on the
@@ -263,33 +263,11 @@
while (auto ignoredBase = dyn_cast<DotSyntaxBaseIgnoredExpr>(Base))
Base = ignoredBase->getRHS();
if (auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
- checkNoEscapeParameterUse(DRE, Call);
+ checkNoEscapeParameterUse(DRE, Call, OperandKind::Callee);
checkForSuspiciousBitCasts(DRE, Call);
}
- auto *Arg = Call->getArg();
-
- // The argument could be shuffled if it includes default arguments,
- // label differences, or other exciting things like that.
- if (auto *TSE = dyn_cast<TupleShuffleExpr>(Arg))
- Arg = TSE->getSubExpr();
-
- // The argument is either a ParenExpr or TupleExpr.
- ArrayRef<Expr*> arguments;
- SmallVector<Expr *, 1> Scratch;
- if (auto *TE = dyn_cast<TupleExpr>(Arg))
- arguments = TE->getElements();
- else if (auto *PE = dyn_cast<ParenExpr>(Arg)) {
- Scratch.push_back(PE->getSubExpr());
- arguments = makeArrayRef(Scratch);
- }
- else {
- Scratch.push_back(Call->getArg());
- arguments = makeArrayRef(Scratch);
- }
-
- // Check each argument.
- for (auto arg : arguments) {
+ visitArguments(Call, [&](Expr *arg) {
// InOutExpr's are allowed in argument lists directly.
if (auto *IOE = dyn_cast<InOutExpr>(arg)) {
if (isa<CallExpr>(Call))
@@ -307,18 +285,12 @@
AcceptableInOutExprs.insert(IOE);
}
- while (1) {
- if (auto conv = dyn_cast<ImplicitConversionExpr>(arg))
- arg = conv->getSubExpr();
- else if (auto *PE = dyn_cast<ParenExpr>(arg))
- arg = PE->getSubExpr();
- else
- break;
- }
+ // Also give special treatment to noescape function arguments.
+ arg = lookThroughArgument(arg);
if (auto *DRE = dyn_cast<DeclRefExpr>(arg))
- checkNoEscapeParameterUse(DRE, Call);
- }
+ checkNoEscapeParameterUse(DRE, Call, OperandKind::Argument);
+ });
}
// If we have an assignment expression, scout ahead for acceptable _'s.
@@ -359,6 +331,38 @@
return { true, E };
}
+ static void visitArguments(ApplyExpr *apply,
+ llvm::function_ref<void(Expr*)> fn) {
+ auto *arg = apply->getArg();
+
+ // The argument could be shuffled if it includes default arguments,
+ // label differences, or other exciting things like that.
+ if (auto *TSE = dyn_cast<TupleShuffleExpr>(arg))
+ arg = TSE->getSubExpr();
+
+ // The argument is either a ParenExpr or TupleExpr.
+ if (auto *TE = dyn_cast<TupleExpr>(arg)) {
+ for (auto elt : TE->getElements())
+ fn(elt);
+ } else if (auto *PE = dyn_cast<ParenExpr>(arg)) {
+ fn(PE->getSubExpr());
+ } else {
+ fn(arg);
+ }
+ }
+
+ static Expr *lookThroughArgument(Expr *arg) {
+ while (1) {
+ if (auto conv = dyn_cast<ImplicitConversionExpr>(arg))
+ arg = conv->getSubExpr();
+ else if (auto *PE = dyn_cast<ParenExpr>(arg))
+ arg = PE->getSubExpr();
+ else
+ break;
+ }
+ return arg;
+ }
+
Expr *walkToExprPost(Expr *E) override {
checkInvalidPartialApplication(E);
return E;
@@ -446,9 +450,118 @@
TC.diagnose(E->getStartLoc(), diag::value_of_module_type);
}
+ class NoEscapeArgument {
+ llvm::PointerIntPair<ParamDecl*, 1, bool> ParamAndIsCapture;
+ public:
+ NoEscapeArgument() {}
+ NoEscapeArgument(ParamDecl *param, bool isCapture)
+ : ParamAndIsCapture(param, isCapture) {
+ assert(param);
+ }
+
+ explicit operator bool() const {
+ return ParamAndIsCapture.getPointer() != nullptr;
+ }
+
+ ParamDecl *getDecl() const { return ParamAndIsCapture.getPointer(); }
+ bool isDeclACapture() const { return ParamAndIsCapture.getInt(); }
+
+ static NoEscapeArgument find(TypeChecker &tc, ValueDecl *decl,
+ bool isCapture) {
+ if (auto param = dyn_cast<ParamDecl>(decl)) {
+ if (auto fnType =
+ param->getInterfaceType()->getAs<AnyFunctionType>()) {
+ if (fnType->isNoEscape())
+ return { param, isCapture };
+ }
+ return {};
+ }
+
+ if (auto fn = dyn_cast<AbstractFunctionDecl>(decl)) {
+ if (fn->getDeclContext()->isLocalContext()) {
+ return findInCaptures(tc, fn);
+ }
+ return {};
+ }
+
+ // FIXME: captures of computed local vars? Can these be non-escaping?
+ return {};
+ }
+
+ static NoEscapeArgument findInCaptures(TypeChecker &tc,
+ AnyFunctionRef fn) {
+ // Ensure we have accurate capture information for the function.
+ tc.computeCaptures(fn);
+
+ for (const auto &capture : fn.getCaptureInfo().getCaptures()) {
+ if (capture.isDynamicSelfMetadata()) continue;
+ if (auto param = find(tc, capture.getDecl(), true))
+ return param;
+ }
+ return {};
+ }
+ };
+
+ /// Enforce the exclusivity rule against calling a non-escaping
+ /// function parameter with another non-escaping function parameter
+ /// as an argument.
+ void checkNoEscapeParameterCall(ApplyExpr *apply) {
+ NoEscapeArgument noescapeArgument;
+ Expr *problematicArg = nullptr;
+
+ visitArguments(apply, [&](Expr *arg) {
+ // Just find the first problematic argument.
+ if (noescapeArgument) return;
+
+ // Remember the expression which used the argument.
+ problematicArg = arg;
+
+ // Look through the same set of nodes that we look through when
+ // checking for no-escape functions.
+ arg = lookThroughArgument(arg);
+
+ // If the argument isn't noescape, ignore it.
+ auto fnType = arg->getType()->getAs<AnyFunctionType>();
+ if (!fnType || !fnType->isNoEscape())
+ return;
+
+ // Okay, it should be a closure or a decl ref.
+ if (auto declRef = dyn_cast<DeclRefExpr>(arg)) {
+ noescapeArgument =
+ NoEscapeArgument::find(TC, declRef->getDecl(), false);
+ } else if (auto closure = dyn_cast<AbstractClosureExpr>(arg)) {
+ noescapeArgument =
+ NoEscapeArgument::findInCaptures(TC, closure);
+ } else {
+ // This can happen with withoutActuallyEscaping.
+ assert(isa<OpaqueValueExpr>(arg) &&
+ "unexpected expression yielding noescape closure");
+ }
+ });
+
+ if (!noescapeArgument) return;
+
+ // In Swift 3, this is just a warning.
+ TC.diagnose(apply->getLoc(),
+ TC.Context.isSwiftVersion3()
+ ? diag::warn_noescape_param_call
+ : diag::err_noescape_param_call,
+ noescapeArgument.getDecl()->getName(),
+ noescapeArgument.isDeclACapture())
+ .highlight(problematicArg->getSourceRange());
+ }
+
+ enum class OperandKind {
+ None,
+ Callee,
+ Argument,
+ MakeEscapable,
+ };
+
/// The DRE argument is a reference to a noescape parameter. Verify that
/// its uses are ok.
- void checkNoEscapeParameterUse(DeclRefExpr *DRE, Expr *ParentExpr=nullptr) {
+ void checkNoEscapeParameterUse(DeclRefExpr *DRE, Expr *parent,
+ OperandKind useKind) {
// This only cares about declarations of noescape function type.
auto AFT = DRE->getDecl()->getInterfaceType()->getAs<AnyFunctionType>();
if (!AFT || !AFT->isNoEscape())
@@ -463,10 +576,15 @@
// either as the callee or as an argument (in which case, the typechecker
// validates that the noescape bit didn't get stripped off), or as
// a special case, in the binding of a withoutActuallyEscaping block.
- if (ParentExpr
- && (isa<ApplyExpr>(ParentExpr) // param()
- || isa<MakeTemporarilyEscapableExpr>(ParentExpr)))
- return;
+ if (parent) {
+ if (auto apply = dyn_cast<ApplyExpr>(parent)) {
+ if (isa<ParamDecl>(DRE->getDecl()) && useKind == OperandKind::Callee)
+ checkNoEscapeParameterCall(apply);
+ return;
+ } else if (isa<MakeTemporarilyEscapableExpr>(parent)) {
+ return;
+ }
+ }
TC.diagnose(DRE->getStartLoc(), diag::invalid_noescape_use,
DRE->getDecl()->getBaseName(),
diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp
index bf5358d..6efcf20 100644
--- a/lib/Sema/TypeCheckDecl.cpp
+++ b/lib/Sema/TypeCheckDecl.cpp
@@ -7804,18 +7804,6 @@
// FIXME: Probably the above comes up elsewhere, perhaps getAs<>()
// should be fixed.
if (auto proto = extendedType->getCanonicalType()->getAs<ProtocolType>()) {
- if (!isa<ProtocolType>(extendedType.getPointer()) &&
- proto->getDecl()->getParentModule() == ext->getParentModule()) {
- // Protocols in the same module cannot be extended via a typealias;
- // we could end up being unable to resolve the generic signature.
- diagnose(ext->getLoc(), diag::extension_protocol_via_typealias, proto)
- .fixItReplace(ext->getExtendedTypeLoc().getSourceRange(),
- proto->getDecl()->getName().str());
- ext->setInvalid();
- ext->getExtendedTypeLoc().setInvalidType(Context);
- return;
- }
-
GenericEnvironment *env;
std::tie(env, extendedType) =
checkExtensionGenericParams(*this, ext, proto, ext->getGenericParams());
diff --git a/stdlib/public/SDK/UIKit/UIKit.swift b/stdlib/public/SDK/UIKit/UIKit.swift
index 29b2991..f37db95 100644
--- a/stdlib/public/SDK/UIKit/UIKit.swift
+++ b/stdlib/public/SDK/UIKit/UIKit.swift
@@ -13,6 +13,10 @@
import Foundation
@_exported import UIKit
+#if os(iOS) || os(tvOS)
+import _SwiftUIKitOverlayShims
+#endif
+
//===----------------------------------------------------------------------===//
// UIGeometry
//===----------------------------------------------------------------------===//
@@ -277,13 +281,15 @@
#if os(iOS) || os(tvOS)
@available(iOS 11.0, tvOS 11.0, *)
extension UIFocusEnvironment {
+ @available(iOS 11.0, tvOS 11.0, *)
public func contains(_ environment: UIFocusEnvironment) -> Bool {
- return UIFocusSystem.environment(self, contains: environment)
+ return _swift_UIKit_UIFocusEnvironmentContainsEnvironment(self, environment)
}
}
@available(iOS 11.0, tvOS 11.0, *)
extension UIFocusItem {
+ @available(iOS 11.0, tvOS 11.0, *)
public var isFocused: Bool {
return self === UIScreen.main.focusedItem
}
diff --git a/stdlib/public/SwiftShims/CMakeLists.txt b/stdlib/public/SwiftShims/CMakeLists.txt
index ad8293a..782822b 100644
--- a/stdlib/public/SwiftShims/CMakeLists.txt
+++ b/stdlib/public/SwiftShims/CMakeLists.txt
@@ -16,9 +16,10 @@
Visibility.h
DispatchOverlayShims.h
- ObjectiveCOverlayShims.h
OSOverlayShims.h
+ ObjectiveCOverlayShims.h
SafariServicesOverlayShims.h
+ UIKitOverlayShims.h
XCTestOverlayShims.h
XPCOverlayShims.h
diff --git a/stdlib/public/SwiftShims/KeyPath.h b/stdlib/public/SwiftShims/KeyPath.h
index b8846e7..5f3b021 100644
--- a/stdlib/public/SwiftShims/KeyPath.h
+++ b/stdlib/public/SwiftShims/KeyPath.h
@@ -90,8 +90,6 @@
= 0x0000000FU;
static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDResolved
= 0x00000000U;
-static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFieldOffset
- = 0x00000001U;
static const __swift_uint32_t _SwiftKeyPathComponentHeader_ComputedIDUnresolvedIndirectPointer
= 0x00000002U;
diff --git a/stdlib/public/SwiftShims/UIKitOverlayShims.h b/stdlib/public/SwiftShims/UIKitOverlayShims.h
new file mode 100644
index 0000000..c98552b
--- /dev/null
+++ b/stdlib/public/SwiftShims/UIKitOverlayShims.h
@@ -0,0 +1,34 @@
+//===--- UIKitOverlayShims.h ---===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See https://swift.org/LICENSE.txt for license information
+// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===--------------------===//
+
+#ifndef SWIFT_STDLIB_SHIMS_UIKIT_OVERLAY_H
+#define SWIFT_STDLIB_SHIMS_UIKIT_OVERLAY_H
+
+@import UIKit;
+
+#if __has_feature(nullability)
+#pragma clang assume_nonnull begin
+#endif
+
+#if TARGET_OS_TV || TARGET_OS_IOS
+static inline BOOL _swift_UIKit_UIFocusEnvironmentContainsEnvironment(id<UIFocusEnvironment> environment, id<UIFocusEnvironment> otherEnvironment) {
+ return [UIFocusSystem environment:environment containsEnvironment:otherEnvironment];
+}
+#endif // TARGET_OS_TV || TARGET_OS_IOS
+
+#if __has_feature(nullability)
+#pragma clang assume_nonnull end
+#endif
+
+
+#endif // SWIFT_STDLIB_SHIMS_UIKIT_OVERLAY_H
+
diff --git a/stdlib/public/SwiftShims/module.modulemap b/stdlib/public/SwiftShims/module.modulemap
index c33d512..5b48587 100644
--- a/stdlib/public/SwiftShims/module.modulemap
+++ b/stdlib/public/SwiftShims/module.modulemap
@@ -40,6 +40,10 @@
header "SafariServicesOverlayShims.h"
}
+module _SwiftUIKitOverlayShims {
+ header "UIKitOverlayShims.h"
+}
+
module _SwiftXCTestOverlayShims {
header "XCTestOverlayShims.h"
}
diff --git a/stdlib/public/core/KeyPath.swift b/stdlib/public/core/KeyPath.swift
index 632e9ca..7fcd866 100644
--- a/stdlib/public/core/KeyPath.swift
+++ b/stdlib/public/core/KeyPath.swift
@@ -350,58 +350,6 @@
// MARK: Implementation details
-// Keypaths store word-sized values with 32-bit alignment for memory efficiency.
-// Since RawPointer's APIs currently require alignment, this means we need
-// to do some shuffling for the unaligned load/stores.
-
-extension UnsafeRawBufferPointer {
- internal func _loadKeyPathWord<T>(fromByteOffset offset: Int = 0,
- as _: T.Type) -> T {
- _sanityCheck(_isPOD(T.self) &&
- MemoryLayout<T>.size == MemoryLayout<Int>.size,
- "not a word-sized trivial type")
- if MemoryLayout<Int>.size == 8 {
- let words = load(fromByteOffset: offset, as: (Int32, Int32).self)
- return unsafeBitCast(words, to: T.self)
- } else if MemoryLayout<Int>.size == 4 {
- return load(fromByteOffset: offset, as: T.self)
- } else {
- _sanityCheckFailure("unsupported architecture")
- }
- }
-}
-
-extension UnsafeMutableRawBufferPointer {
- internal func _loadKeyPathWord<T>(fromByteOffset offset: Int = 0,
- as _: T.Type) -> T {
- _sanityCheck(_isPOD(T.self) &&
- MemoryLayout<T>.size == MemoryLayout<Int>.size,
- "not a word-sized trivial type")
- if MemoryLayout<Int>.size == 8 {
- let words = load(fromByteOffset: offset, as: (Int32, Int32).self)
- return unsafeBitCast(words, to: T.self)
- } else if MemoryLayout<Int>.size == 4 {
- return load(fromByteOffset: offset, as: T.self)
- } else {
- _sanityCheckFailure("unsupported architecture")
- }
- }
- internal func _storeKeyPathWord<T>(of value: T,
- toByteOffset offset: Int = 0) {
- _sanityCheck(_isPOD(T.self) &&
- MemoryLayout<T>.size == MemoryLayout<Int>.size,
- "not a word-sized trivial type")
- if MemoryLayout<Int>.size == 8 {
- let words = unsafeBitCast(value, to: (Int32, Int32).self)
- storeBytes(of: words, toByteOffset: offset, as: (Int32,Int32).self)
- } else if MemoryLayout<Int>.size == 4 {
- storeBytes(of: value, toByteOffset: offset, as: T.self)
- } else {
- _sanityCheckFailure("unsupported architecture")
- }
- }
-}
-
internal enum KeyPathComponentKind {
/// The keypath projects within the storage of the outer value, like a
/// stored property in a struct.
@@ -642,9 +590,6 @@
static var computedIDResolved: UInt32 {
return _SwiftKeyPathComponentHeader_ComputedIDResolved
}
- static var computedIDUnresolvedFieldOffset: UInt32 {
- return _SwiftKeyPathComponentHeader_ComputedIDUnresolvedFieldOffset
- }
static var computedIDUnresolvedIndirectPointer: UInt32 {
return _SwiftKeyPathComponentHeader_ComputedIDUnresolvedIndirectPointer
}
@@ -695,6 +640,12 @@
_sanityCheckFailure("invalid header")
}
}
+
+ // The component header is 4 bytes, but may be followed by an aligned
+ // pointer field for some kinds of component, forcing padding.
+ static var pointerAlignmentSkew: Int {
+ return MemoryLayout<Int>.size - MemoryLayout<Int32>.size
+ }
var bodySize: Int {
switch kind {
@@ -705,8 +656,8 @@
return 0
case .computed:
let ptrSize = MemoryLayout<Int>.size
- // minimum two pointers for id and get
- var total = ptrSize * 2
+ // align to pointer, minimum two pointers for id and get
+ var total = Header.pointerAlignmentSkew + ptrSize * 2
// additional word for a setter
if payload & Header.computedSettableFlag != 0 {
total += ptrSize
@@ -748,9 +699,8 @@
var _computedIDValue: Int {
_sanityCheck(header.kind == .computed,
"not a computed property")
- _sanityCheck(body.count >= MemoryLayout<Int>.size,
- "component is not big enough")
- return body._loadKeyPathWord(as: Int.self)
+ return body.load(fromByteOffset: Header.pointerAlignmentSkew,
+ as: Int.self)
}
var _computedID: ComputedPropertyID {
@@ -764,11 +714,10 @@
var _computedGetter: UnsafeRawPointer {
_sanityCheck(header.kind == .computed,
"not a computed property")
- _sanityCheck(body.count >= MemoryLayout<Int>.size * 2,
- "component is not big enough")
- return body._loadKeyPathWord(fromByteOffset: MemoryLayout<Int>.size,
- as: UnsafeRawPointer.self)
+ return body.load(
+ fromByteOffset: Header.pointerAlignmentSkew + MemoryLayout<Int>.size,
+ as: UnsafeRawPointer.self)
}
var _computedSetter: UnsafeRawPointer {
@@ -776,11 +725,10 @@
"not a computed property")
_sanityCheck(header.payload & Header.computedSettableFlag != 0,
"not a settable property")
- _sanityCheck(body.count >= MemoryLayout<Int>.size * 3,
- "component is not big enough")
- return body._loadKeyPathWord(fromByteOffset: MemoryLayout<Int>.size * 2,
- as: UnsafeRawPointer.self)
+ return body.load(
+ fromByteOffset: Header.pointerAlignmentSkew + MemoryLayout<Int>.size * 2,
+ as: UnsafeRawPointer.self)
}
var value: KeyPathComponent {
@@ -838,7 +786,7 @@
return
}
}
-
+
func clone(into buffer: inout UnsafeMutableRawBufferPointer,
endOfReferencePrefix: Bool) {
var newHeader = header
@@ -860,28 +808,32 @@
.optionalWrap:
break
case .computed:
+ // Fields are pointer-aligned after the header
+ componentSize += Header.pointerAlignmentSkew
// TODO: nontrivial arguments need to be copied by value witness
_sanityCheck(header.payload & Header.computedHasArgumentsFlag == 0,
"arguments not implemented")
- buffer._storeKeyPathWord(of: _computedIDValue, toByteOffset: 4)
- buffer._storeKeyPathWord(of: _computedGetter,
- toByteOffset: 4 + MemoryLayout<Int>.size)
+ buffer.storeBytes(of: _computedIDValue,
+ toByteOffset: MemoryLayout<Int>.size,
+ as: Int.self)
+ buffer.storeBytes(of: _computedGetter,
+ toByteOffset: 2 * MemoryLayout<Int>.size,
+ as: UnsafeRawPointer.self)
componentSize += MemoryLayout<Int>.size * 2
if header.payload & Header.computedSettableFlag != 0 {
- buffer._storeKeyPathWord(of: _computedSetter,
- toByteOffset: 4 + MemoryLayout<Int>.size * 2)
+ buffer.storeBytes(of: _computedSetter,
+ toByteOffset: MemoryLayout<Int>.size * 3,
+ as: UnsafeRawPointer.self)
componentSize += MemoryLayout<Int>.size
}
}
- _sanityCheck(buffer.count >= componentSize)
buffer = UnsafeMutableRawBufferPointer(
start: buffer.baseAddress.unsafelyUnwrapped + componentSize,
- count: buffer.count - componentSize
- )
+ count: buffer.count - componentSize)
}
-
+
func projectReadOnly<CurValue, NewValue>(_ base: CurValue) -> NewValue {
switch value {
case .struct(let offset):
@@ -1062,9 +1014,8 @@
init(base: UnsafeRawPointer) {
let header = base.load(as: Header.self)
data = UnsafeRawBufferPointer(
- start: base + MemoryLayout<Header>.size,
- count: header.size
- )
+ start: base + MemoryLayout<Int>.size,
+ count: header.size)
trivial = header.trivial
hasReferencePrefix = header.hasReferencePrefix
}
@@ -1086,7 +1037,7 @@
let body: UnsafeRawBufferPointer
let size = header.bodySize
if size != 0 {
- body = popRaw(size)
+ body = popRaw(size: size, alignment: 4)
} else {
body = UnsafeRawBufferPointer(start: nil, count: 0)
}
@@ -1097,22 +1048,15 @@
if data.count == 0 {
nextType = nil
} else {
- if MemoryLayout<Any.Type>.size == 8 {
- // Words in the key path buffer are 32-bit aligned
- nextType = unsafeBitCast(pop((Int32, Int32).self),
- to: Any.Type.self)
- } else if MemoryLayout<Any.Type>.size == 4 {
- nextType = pop(Any.Type.self)
- } else {
- _sanityCheckFailure("unexpected word size")
- }
+ nextType = pop(Any.Type.self)
}
return (component, nextType)
}
mutating func pop<T>(_ type: T.Type) -> T {
_sanityCheck(_isPOD(T.self), "should be POD")
- let raw = popRaw(MemoryLayout<T>.size)
+ let raw = popRaw(size: MemoryLayout<T>.size,
+ alignment: MemoryLayout<T>.alignment)
let resultBuf = UnsafeMutablePointer<T>.allocate(capacity: 1)
_memcpy(dest: resultBuf,
src: UnsafeMutableRawPointer(mutating: raw.baseAddress.unsafelyUnwrapped),
@@ -1121,13 +1065,18 @@
resultBuf.deallocate(capacity: 1)
return result
}
- mutating func popRaw(_ size: Int) -> UnsafeRawBufferPointer {
- _sanityCheck(data.count >= size,
- "not enough space for next component?")
- let result = UnsafeRawBufferPointer(start: data.baseAddress, count: size)
+ mutating func popRaw(size: Int, alignment: Int) -> UnsafeRawBufferPointer {
+ var baseAddress = data.baseAddress.unsafelyUnwrapped
+ var misalignment = Int(bitPattern: baseAddress) % alignment
+ if misalignment != 0 {
+ misalignment = alignment - misalignment
+ baseAddress += misalignment
+ }
+
+ let result = UnsafeRawBufferPointer(start: baseAddress, count: size)
data = UnsafeRawBufferPointer(
- start: data.baseAddress.unsafelyUnwrapped + size,
- count: data.count - size
+ start: baseAddress + size,
+ count: data.count - size - misalignment
)
return result
}
@@ -1340,9 +1289,11 @@
// Result buffer has room for both key paths' components, plus the
// header, plus space for the middle type.
- let resultSize = rootBuffer.data.count + leafBuffer.data.count
- + MemoryLayout<KeyPathBuffer.Header>.size
- + MemoryLayout<Int>.size
+ // Align up the root so that we can put the component type after it.
+ let alignMask = MemoryLayout<Int>.alignment - 1
+ let rootSize = (rootBuffer.data.count + alignMask) & ~alignMask
+ let resultSize = rootSize + leafBuffer.data.count
+ + 2 * MemoryLayout<Int>.size
// Tail-allocate space for the KVC string.
let totalResultSize = (resultSize + appendedKVCLength + 3) & ~3
@@ -1360,40 +1311,40 @@
count: resultSize)
}
- func pushRaw(_ count: Int) {
- _sanityCheck(destBuffer.count >= count)
- destBuffer = UnsafeMutableRawBufferPointer(
- start: destBuffer.baseAddress.unsafelyUnwrapped + count,
- count: destBuffer.count - count
- )
- }
- func pushType(_ type: Any.Type) {
- let intSize = MemoryLayout<Int>.size
- _sanityCheck(destBuffer.count >= intSize)
- if intSize == 8 {
- let words = unsafeBitCast(type, to: (UInt32, UInt32).self)
- destBuffer.storeBytes(of: words.0,
- as: UInt32.self)
- destBuffer.storeBytes(of: words.1, toByteOffset: 4,
- as: UInt32.self)
- } else if intSize == 4 {
- destBuffer.storeBytes(of: type, as: Any.Type.self)
- } else {
- _sanityCheckFailure("unsupported architecture")
+ func pushRaw(size: Int, alignment: Int)
+ -> UnsafeMutableRawBufferPointer {
+ var baseAddress = destBuffer.baseAddress.unsafelyUnwrapped
+ var misalign = Int(bitPattern: baseAddress) % alignment
+ if misalign != 0 {
+ misalign = alignment - misalign
+ baseAddress = baseAddress.advanced(by: misalign)
}
- pushRaw(intSize)
+ let result = UnsafeMutableRawBufferPointer(
+ start: baseAddress,
+ count: size)
+ destBuffer = UnsafeMutableRawBufferPointer(
+ start: baseAddress + size,
+ count: destBuffer.count - size - misalign)
+ return result
+ }
+ func push<T>(_ value: T) {
+ let buf = pushRaw(size: MemoryLayout<T>.size,
+ alignment: MemoryLayout<T>.alignment)
+ buf.storeBytes(of: value, as: T.self)
}
// Save space for the header.
let leafIsReferenceWritable = type(of: leaf).kind == .reference
let header = KeyPathBuffer.Header(
- size: resultSize - MemoryLayout<KeyPathBuffer.Header>.size,
+ size: resultSize - MemoryLayout<Int>.size,
trivial: rootBuffer.trivial && leafBuffer.trivial,
hasReferencePrefix: rootBuffer.hasReferencePrefix
|| leafIsReferenceWritable
)
- destBuffer.storeBytes(of: header, as: KeyPathBuffer.Header.self)
- pushRaw(MemoryLayout<KeyPathBuffer.Header>.size)
+ push(header)
+ // Start the components at pointer alignment
+ _ = pushRaw(size: RawKeyPathComponent.Header.pointerAlignmentSkew,
+ alignment: 4)
let leafHasReferencePrefix = leafBuffer.hasReferencePrefix
@@ -1415,13 +1366,12 @@
component.clone(
into: &destBuffer,
- endOfReferencePrefix: endOfReferencePrefix
- )
+ endOfReferencePrefix: endOfReferencePrefix)
if let type = type {
- pushType(type)
+ push(type)
} else {
// Insert our endpoint type between the root and leaf components.
- pushType(Value.self)
+ push(Value.self as Any.Type)
break
}
}
@@ -1432,11 +1382,10 @@
component.clone(
into: &destBuffer,
- endOfReferencePrefix: component.header.endOfReferencePrefix
- )
+ endOfReferencePrefix: component.header.endOfReferencePrefix)
if let type = type {
- pushType(type)
+ push(type)
} else {
break
}
@@ -1570,7 +1519,7 @@
let bufferPtr = objectPtr.advanced(by: keyPathObjectHeaderSize)
let buffer = KeyPathBuffer(base: bufferPtr)
- let totalSize = buffer.data.count + MemoryLayout<KeyPathBuffer.Header>.size
+ let totalSize = buffer.data.count + MemoryLayout<Int>.size
let bufferData = UnsafeMutableRawBufferPointer(
start: bufferPtr,
count: totalSize)
@@ -1610,7 +1559,7 @@
let bufferPtr = pattern.advanced(by: keyPathObjectHeaderSize)
var buffer = KeyPathBuffer(base: bufferPtr)
- let size = buffer.data.count + MemoryLayout<KeyPathBuffer.Header>.size
+ let size = buffer.data.count + MemoryLayout<Int>.size
scanComponents: while true {
let header = buffer.pop(RawKeyPathComponent.Header.self)
@@ -1661,7 +1610,8 @@
header.payload & RawKeyPathComponent.Header.computedHasArgumentsFlag == 0,
"arguments not implemented yet")
- _ = buffer.popRaw(MemoryLayout<Int>.size * (settable ? 3 : 2))
+ _ = buffer.popRaw(size: MemoryLayout<Int>.size * (settable ? 3 : 2),
+ alignment: MemoryLayout<Int>.alignment)
case .optionalChain,
.optionalWrap:
@@ -1678,7 +1628,8 @@
if buffer.data.count == 0 { break }
// Pop the type accessor reference.
- _ = buffer.popRaw(MemoryLayout<Int>.size)
+ _ = buffer.popRaw(size: MemoryLayout<Int>.size,
+ alignment: MemoryLayout<Int>.alignment)
}
// Grab the class object for the key path type we'll end up with.
@@ -1712,27 +1663,26 @@
var patternBuffer = origPatternBuffer
let destHeaderPtr = origDestData.baseAddress.unsafelyUnwrapped
- _sanityCheck(origDestData.count >= MemoryLayout<KeyPathBuffer.Header>.size)
var destData = UnsafeMutableRawBufferPointer(
- start: destHeaderPtr.advanced(by: MemoryLayout<KeyPathBuffer.Header>.size),
- count: origDestData.count - MemoryLayout<KeyPathBuffer.Header>.size)
+ start: destHeaderPtr.advanced(by: MemoryLayout<Int>.size),
+ count: origDestData.count - MemoryLayout<Int>.size)
func pushDest<T>(_ value: T) {
- // TODO: If key path patterns were better optimized to try to be constant-
- // memory objects, then it might become profitable to try to avoid writes
- // here in the case when the dest memory contains the value we want to write
- // here so that we don't dirty memory. (In practice the current
- // implementation will always dirty the page when the key path is
- // instantiated.)
_sanityCheck(_isPOD(T.self))
var value2 = value
let size = MemoryLayout<T>.size
- _sanityCheck(destData.count >= size)
- _memcpy(dest: destData.baseAddress.unsafelyUnwrapped, src: &value2,
+ let alignment = MemoryLayout<T>.alignment
+ var baseAddress = destData.baseAddress.unsafelyUnwrapped
+ var misalign = Int(bitPattern: baseAddress) % alignment
+ if misalign != 0 {
+ misalign = alignment - misalign
+ baseAddress = baseAddress.advanced(by: misalign)
+ }
+ _memcpy(dest: baseAddress, src: &value2,
size: UInt(size))
destData = UnsafeMutableRawBufferPointer(
- start: destData.baseAddress.unsafelyUnwrapped.advanced(by: size),
- count: destData.count - size)
+ start: baseAddress.advanced(by: size),
+ count: destData.count - size - misalign)
}
// Track where the reference prefix begins.
@@ -1748,6 +1698,7 @@
let componentAddr = destData.baseAddress.unsafelyUnwrapped
let header = patternBuffer.pop(RawKeyPathComponent.Header.self)
+
func tryToResolveOffset() {
if header.payload == RawKeyPathComponent.Header.unresolvedFieldOffsetPayload {
// Look up offset in type metadata. The value in the pattern is the
@@ -1774,8 +1725,12 @@
newHeader.payload = RawKeyPathComponent.Header.outOfLineOffsetPayload
pushDest(newHeader)
pushDest(offsetValue)
- shrinkage += MemoryLayout<UnsafeRawPointer>.size
- - MemoryLayout<UInt32>.size
+ // On 64-bit systems the pointer to the ivar offset variable is
+ // pointer-sized and -aligned, but the resulting offset ought to be
+ // 32 bits only, so we can shrink the result object a bit.
+ if MemoryLayout<Int>.size == 8 {
+ shrinkage += MemoryLayout<UnsafeRawPointer>.size
+ }
return
}
@@ -1820,15 +1775,6 @@
case RawKeyPathComponent.Header.computedIDResolved:
// Nothing to do.
break
- case RawKeyPathComponent.Header.computedIDUnresolvedFieldOffset:
- // The value in the pattern is an offset into the type metadata that
- // points to the field offset for the stored property identifying the
- // component.
- _sanityCheck(header.payload
- & RawKeyPathComponent.Header.computedIDByStoredPropertyFlag != 0,
- "only stored property IDs should need offset resolution")
- let metadataPtr = unsafeBitCast(base, to: UnsafeRawPointer.self)
- id = metadataPtr.load(fromByteOffset: id, as: Int.self)
case RawKeyPathComponent.Header.computedIDUnresolvedIndirectPointer:
// The value in the pattern is a pointer to the actual unique word-sized
// value in memory.
@@ -1857,21 +1803,9 @@
if patternBuffer.data.count == 0 { break }
// Resolve the component type.
- if MemoryLayout<Int>.size == 4 {
- let componentTyAccessor = patternBuffer.pop(MetadataAccessor.self)
- base = unsafeBitCast(componentTyAccessor(arguments), to: Any.Type.self)
- pushDest(base)
- } else if MemoryLayout<Int>.size == 8 {
- let componentTyAccessorWords = patternBuffer.pop((UInt32,UInt32).self)
- let componentTyAccessor = unsafeBitCast(componentTyAccessorWords,
- to: MetadataAccessor.self)
- base = unsafeBitCast(componentTyAccessor(arguments), to: Any.Type.self)
- let componentTyWords = unsafeBitCast(base,
- to: (UInt32, UInt32).self)
- pushDest(componentTyWords)
- } else {
- fatalError("unsupported architecture")
- }
+ let componentTyAccessor = patternBuffer.pop(MetadataAccessor.self)
+ base = unsafeBitCast(componentTyAccessor(arguments), to: Any.Type.self)
+ pushDest(base)
previousComponentAddr = componentAddr
}
diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp
index 8302920..307d2d5 100644
--- a/stdlib/public/runtime/Errors.cpp
+++ b/stdlib/public/runtime/Errors.cpp
@@ -245,7 +245,11 @@
// Do nothing. This function is meant to be used by the debugger.
// The following is necessary to avoid calls from being optimized out.
- asm volatile("" ::: "memory");
+ asm volatile("" // Do nothing.
+ : // Output list, empty.
+ : "r" (isFatal), "r" (message), "r" (details) // Input list.
+ : // Clobber list, empty.
+ );
}
void swift::reportToDebugger(bool isFatal, const char *message,
diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp
index c9a311c..992956e 100644
--- a/stdlib/public/runtime/HeapObject.cpp
+++ b/stdlib/public/runtime/HeapObject.cpp
@@ -31,6 +31,7 @@
#include <cstdio>
#include <cstdlib>
#include <thread>
+#include "../SwiftShims/GlobalObjects.h"
#include "../SwiftShims/RuntimeShims.h"
#if SWIFT_OBJC_INTEROP
# include <objc/NSObject.h>
@@ -227,6 +228,30 @@
return metadata->project(o);
}
+namespace { // Begin anonymous namespace.
+
+struct _SwiftEmptyBoxStorage {
+ HeapObject header;
+};
+
+swift::HeapLocalVariableMetadata _emptyBoxStorageMetadata;
+
+/// The singleton empty box storage object.
+_SwiftEmptyBoxStorage _EmptyBoxStorage = {
+ // HeapObject header;
+ {
+ &_emptyBoxStorageMetadata,
+ }
+};
+
+} // End anonymous namespace.
+
+HeapObject *swift::swift_allocEmptyBox() {
+ auto heapObject = reinterpret_cast<HeapObject*>(&_EmptyBoxStorage);
+ SWIFT_RT_ENTRY_CALL(swift_retain)(heapObject);
+ return heapObject;
+}
+
// Forward-declare this, but define it after swift_release.
extern "C" LLVM_LIBRARY_VISIBILITY LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
void _swift_release_dealloc(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL);
diff --git a/test/IRGen/access_markers.sil b/test/IRGen/access_markers.sil
index 40b2dee..06f1b70 100644
--- a/test/IRGen/access_markers.sil
+++ b/test/IRGen/access_markers.sil
@@ -114,8 +114,7 @@
bb0(%0 : ${ var () }):
// CHECK: entry:
%2 = project_box %0 : ${ var () }, 0
-
- // CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
+ // CHECK-NEXT: call {{.*}}void @writeEmptyTuple(%swift.opaque* nocapture undef)
%3 = begin_access [modify] [dynamic] %2 : $*()
%write_fn = function_ref @writeEmptyTuple : $@convention(thin) (@inout ()) -> ()
apply %write_fn(%3) : $@convention(thin) (@inout ()) -> ()
diff --git a/test/IRGen/keypaths.sil b/test/IRGen/keypaths.sil
index 851792f..9771318 100644
--- a/test/IRGen/keypaths.sil
+++ b/test/IRGen/keypaths.sil
@@ -27,8 +27,9 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0018 - instantiable in-line, size 4
+// -- 0x8000_0004 - instantiable in-line, size 4
// CHECK-SAME: i32 -2147483644,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- offset of S.x
// CHECK-SAME: i32 0 }>
@@ -37,8 +38,9 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0018 - instantiable in-line, size 4
+// -- 0x8000_0004 - instantiable in-line, size 4
// CHECK-SAME: i32 -2147483644,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- offset of S.y
// CHECK-32-SAME: i32 4 }>
// CHECK-64-SAME: i32 8 }>
@@ -48,8 +50,9 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0018 - instantiable in-line, size 4
+// -- 0x8000_0004 - instantiable in-line, size 4
// CHECK-SAME: i32 -2147483644,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- offset of S.z
// CHECK-32-SAME: i32 16 }>
// CHECK-64-SAME: i32 32 }>
@@ -59,8 +62,9 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0018 - instantiable in-line, size 4
+// -- 0x8000_0004 - instantiable in-line, size 4
// CHECK-SAME: i32 -2147483644,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x4000_0000 (class) + offset of C.x
// CHECK-32-SAME: i32 1073741836 }>
// CHECK-64-SAME: i32 1073741840 }>
@@ -70,8 +74,9 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0018 - instantiable in-line, size 4
+// -- 0x8000_0004 - instantiable in-line, size 4
// CHECK-SAME: i32 -2147483644,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x4000_0000 (class) + offset of C.y
// CHECK-32-SAME: i32 1073741840 }>
// CHECK-64-SAME: i32 1073741848 }>
@@ -81,8 +86,9 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0018 - instantiable in-line, size 4
+// -- 0x8000_0004 - instantiable in-line, size 4
// CHECK-SAME: i32 -2147483644,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x4000_0000 (class) + offset of C.z
// CHECK-32-SAME: i32 1073741852 }>
// CHECK-64-SAME: i32 1073741872 }>
@@ -92,13 +98,15 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0010 - instantiable in-line, size 12
+// -- 0x8000_000c - instantiable in-line, size 12
// CHECK-32-SAME: i32 -2147483636,
-// -- 0x8000_0018 - instantiable in-line, size 16
-// CHECK-64-SAME: i32 -2147483632,
+// -- 0x8000_0014 - instantiable in-line, size 16
+// CHECK-64-SAME: i32 -2147483628,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- offset of S.z
// CHECK-32-SAME: i32 16,
// CHECK-64-SAME: i32 32,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// CHECK: %swift.type* (i8*)*
// -- 0x4000_0000 (class) + offset of C.x
// CHECK-32-SAME: i32 1073741836 }>
@@ -109,13 +117,15 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0010 - instantiable in-line, size 12
+// -- 0x8000_000c - instantiable in-line, size 12
// CHECK-32-SAME: i32 -2147483636,
-// -- 0x8000_0018 - instantiable in-line, size 16
-// CHECK-64-SAME: i32 -2147483632,
+// -- 0x8000_0014 - instantiable in-line, size 16
+// CHECK-64-SAME: i32 -2147483628,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x4000_0000 (class) + offset of C.z
// CHECK-32-SAME: i32 1073741852,
// CHECK-64-SAME: i32 1073741872,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// CHECK: %swift.type* (i8*)*
// -- offset of S.x
// CHECK-SAME: i32 0 }>
@@ -125,12 +135,14 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_0014 - instantiable in-line, size 20
-// CHECK-64-SAME: i32 -2147483628,
+// -- 0x8000_0018 - instantiable in-line, size 24
+// CHECK-64-SAME: i32 -2147483624,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x8000_000c - instantiable in-line, size 12
// CHECK-32-SAME: i32 -2147483636,
// -- 0x2000_0000 - computed, get-only, identified by function pointer, no args
// CHECK-SAME: i32 536870912,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// CHECK-SAME: void ()* @k_id,
// CHECK-SAME: void (%TSi*, %T8keypaths1SV*)* @k_get }>
@@ -139,12 +151,14 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_001c - instantiable in-line, size 28
-// CHECK-64-SAME: i32 -2147483620,
+// -- 0x8000_0020 - instantiable in-line, size 32
+// CHECK-64-SAME: i32 -2147483616,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x8000_0010 - instantiable in-line, size 16
// CHECK-32-SAME: i32 -2147483632,
// -- 0x2a00_0000 - computed, settable, nonmutating, identified by vtable, no args
// CHECK-SAME: i32 704643072,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// CHECK-SAME: [[WORD]]
// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_get,
// CHECK-SAME: void (%TSi*, %T8keypaths1CC**)* @l_set }>
@@ -154,12 +168,14 @@
// CHECK-SAME: [[WORD]] 0,
// CHECK-SAME: %swift.type* (i8*)*
// CHECK-SAME: %swift.type* (i8*)*
-// -- 0x8000_001c - instantiable in-line, size 28
-// CHECK-64-SAME: i32 -2147483620,
+// -- 0x8000_0020 - instantiable in-line, size 32
+// CHECK-64-SAME: i32 -2147483616,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x8000_0010 - instantiable in-line, size 16
// CHECK-32-SAME: i32 -2147483632,
// -- 0x3c00_0000 - computed, settable, nonmutating, identified by property offset, no args
// CHECK-SAME: i32 1006632960,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// CHECK-SAME: [[WORD]]
// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_get,
// CHECK-SAME: void (%swift.function*, %T8keypaths1SV*)* @m_set }>
@@ -172,6 +188,7 @@
// CHECK-SAME: %swift.type* (i8*)* [[I_GET_A:@[a-z_.0-9]+]],
// -- size 8
// CHECK-SAME: i32 8,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x1ffffffe - struct with runtime-resolved offset
// CHECK-SAME: i32 536870910,
// CHECK-32-SAME: i32 12 }>
@@ -184,6 +201,7 @@
// CHECK-SAME: %swift.type* (i8*)* [[J_GET_A:@[a-z_.0-9]+]],
// -- size 8
// CHECK-SAME: i32 8,
+// CHECK-64-SAME: [4 x i8] zeroinitializer,
// -- 0x1ffffffe - struct with runtime-resolved offset
// CHECK-SAME: i32 536870910,
// CHECK-32-SAME: i32 16 }>
diff --git a/test/IRGen/partial_apply.sil b/test/IRGen/partial_apply.sil
index 24d11cd..61d55e0 100644
--- a/test/IRGen/partial_apply.sil
+++ b/test/IRGen/partial_apply.sil
@@ -365,7 +365,8 @@
// CHECK-LABEL: define{{( protected)?}} swiftcc void @empty_box()
sil @empty_box : $@convention(thin) () -> () {
entry:
- // CHECK: store %swift.refcounted* null
+ // CHECK: [[BOX:%.*]] = call {{.*}}swift_allocEmptyBox
+ // CHECK: store %swift.refcounted* [[BOX]]
// CHECK: store %swift.opaque* undef
%b = alloc_box $<τ_0_0> { var τ_0_0 } <()>
%ba = project_box %b : $<τ_0_0> { var τ_0_0 } <()>, 0
diff --git a/test/Interpreter/enum.swift b/test/Interpreter/enum.swift
index c6debb8..d9170d8 100644
--- a/test/Interpreter/enum.swift
+++ b/test/Interpreter/enum.swift
@@ -553,5 +553,50 @@
// CHECK-NEXT: Right(foo)
presentEitherOrsOf(t: (), u: "foo")
+// SR-5148
+enum Payload {
+ case email
+}
+enum Test {
+ case a
+ indirect case b(Payload)
+}
+
+@inline(never)
+func printA() {
+ print("an a")
+}
+
+@inline(never)
+func printB() {
+ print("an b")
+}
+
+@inline(never)
+func testCase(_ testEmail: Test) {
+ switch testEmail {
+ case .a:
+ printA()
+ case .b:
+ printB()
+ }
+}
+
+@inline(never)
+func createTestB() -> Test {
+ return Test.b(.email)
+}
+
+@inline(never)
+func createTestA() -> Test {
+ return Test.a
+}
+
+// CHECK-NEXT: an b
+testCase(createTestB())
+// CHECK-NEXT: b(a.Payload.email)
+print(createTestB())
+// CHECK-NEXT: a
+print(createTestA())
// CHECK-NEXT: done
print("done")
diff --git a/test/Migrator/no_extraneous_argument_labels.swift.expected b/test/Migrator/no_extraneous_argument_labels.swift.expected
index 971aba8..f4e74c1 100644
--- a/test/Migrator/no_extraneous_argument_labels.swift.expected
+++ b/test/Migrator/no_extraneous_argument_labels.swift.expected
@@ -7,6 +7,6 @@
var args: [String] = []
let dictionary: [String: String] = [:]
args.append(contentsOf: oc.map { orderedColumn in
- dictionary.first { let (column, value) = $0; return true }!.value
+ dictionary.first { (column, value) in true }!.value
})
}
diff --git a/test/Migrator/tuple-arguments.swift.expected b/test/Migrator/tuple-arguments.swift.expected
index f4ae4e1..bf51964 100644
--- a/test/Migrator/tuple-arguments.swift.expected
+++ b/test/Migrator/tuple-arguments.swift.expected
@@ -21,41 +21,41 @@
test5({ (x,y,z) in })
func test6(_: ((Int, Int)) -> ()) {}
-test6({ let (x,y) = $0; })
+test6({ (x,y) in })
func test7(_: ((Int, Int, Int)) -> ()) {}
-test7({ let (x,y,z) = $0; })
-test6({ let (x, y) = $0; })
-test6({ let (_, _) = $0; })
-test6({ (__val:(Int, Int)) in let (x,y) = __val; })
-test6({ (__val:(Int, Int)) ->() in let (_,_) = __val; })
+test7({ (x,y,z) in })
+test6({ (_ x, _ y) in })
+test6({ (_, _) in })
+test6({ (x:Int, y:Int) in })
+test6({ (_, _) ->() in })
func test8(_: ((Int, Int)) -> Int) {}
-test8 { (__val:(Int, Int)) -> Int in let (_,_) = __val; return 2 }
-test8 { let (x, y) = $0; return x }
+test8 { (_, _) -> Int in 2 }
+test8 { (x, y) in x }
func isEven(_ x: Int) -> Bool { return x % 2 == 0 }
let items = Array(zip(0..<10, 0..<10))
-_ = items.filter { let (_, x) = $0; return isEven(x) }
+_ = items.filter { (_, x) in isEven(x) }
_ = items.filter { _ in true }
func toString(indexes: Int?...) -> String {
- let _ = indexes.enumerated().flatMap({ (__val:(Int, Int?)) -> String? in let (i,index) = __val;
+ let _ = indexes.enumerated().flatMap({ (i: Int, index: Int?) -> String? in
let _: Int = i
if index != nil {}
return ""
})
let _ = indexes.reduce(0) { print(($0, $1)); return $0 + ($1 ?? 0)}
let _ = indexes.reduce(0) { (true ? ($0, $1) : (1, 2)).0 + ($1 ?? 0) }
- let _ = [(1, 2)].contains { $0.0 != $0.1 }
+ let _ = [(1, 2)].contains { $0 != $1 }
_ = ["Hello", "Foo"].sorted { print(($0, $1)); return $0.characters.count > $1.characters.count }
- _ = ["Hello" : 2].map { ($0.0, ($0.1)) }
+ _ = ["Hello" : 2].map { ($0, ($1)) }
}
extension Dictionary {
public mutating func merge(with dictionary: Dictionary) {
- dictionary.forEach { updateValue($0.1, forKey: $0.0) }
+ dictionary.forEach { updateValue($1, forKey: $0) }
}
}
let dictionary: [String: String] = [:]
-_ = dictionary.first { let (column, value) = $0; return true }!.value
+_ = dictionary.first { (column, value) in true }!.value
diff --git a/test/Parse/number_identifier_errors.swift b/test/Parse/number_identifier_errors.swift
new file mode 100644
index 0000000..5650c0d
--- /dev/null
+++ b/test/Parse/number_identifier_errors.swift
@@ -0,0 +1,74 @@
+// RUN: %target-typecheck-verify-swift
+
+// Per rdar://problem/32316666 , it is a common mistake for beginners
+// to start a function name with a number, so it's worth
+// special-casing the diagnostic to make it clearer.
+
+func 1() {}
+// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
+func 2.0() {}
+// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
+func 3func() {}
+// expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
+// expected-error@-2 {{expected a digit after integer literal prefix}}
+
+protocol 4 {
+ // expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}}
+ associatedtype 5
+ // expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}}
+}
+protocol 6.0 {
+ // expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}}
+ associatedtype 7.0
+ // expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}}
+}
+protocol 8protocol {
+ // expected-error@-1 {{protocol name can only start with a letter or underscore, not a number}}
+ // expected-error@-2 {{expected a digit after integer literal prefix}}
+ associatedtype 9associatedtype
+ // expected-error@-1 {{associatedtype name can only start with a letter or underscore, not a number}}
+ // expected-error@-2 {{expected a digit after integer literal prefix}}
+}
+
+typealias 10 = Int
+// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}}
+typealias 11.0 = Int
+// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}}
+typealias 12typealias = Int
+// expected-error@-1 {{typealias name can only start with a letter or underscore, not a number}}
+// expected-error@-2 {{expected a digit after integer literal prefix}}
+
+struct 13 {}
+// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}}
+struct 14.0 {}
+// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}}
+struct 15struct {}
+// expected-error@-1 {{struct name can only start with a letter or underscore, not a number}}
+// expected-error@-2 {{expected a digit after integer literal prefix}}
+
+enum 16 {}
+// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}}
+enum 17.0 {}
+// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}}
+enum 18enum {}
+// expected-error@-1 {{enum name can only start with a letter or underscore, not a number}}
+// expected-error@-2 {{expected a digit in floating point exponent}}
+
+class 19 {
+ // expected-error@-1 {{class name can only start with a letter or underscore, not a number}}
+ func 20() {}
+ // expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
+}
+class 21.0 {
+ // expected-error@-1 {{class name can only start with a letter or underscore, not a number}}
+ func 22.0() {}
+ // expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
+}
+
+class 23class {
+ // expected-error@-1 {{class name can only start with a letter or underscore, not a number}}
+ // expected-error@-2 {{expected a digit after integer literal prefix}}
+ func 24method() {}
+ // expected-error@-1 {{function name can only start with a letter or underscore, not a number}}
+ // expected-error@-2 {{expected a digit after integer literal prefix}}
+}
diff --git a/test/SILGen/c_function_pointers.swift b/test/SILGen/c_function_pointers.swift
index 7724353..18e5141 100644
--- a/test/SILGen/c_function_pointers.swift
+++ b/test/SILGen/c_function_pointers.swift
@@ -63,3 +63,9 @@
init(a: ()) {}
init(b: ()) {}
}
+
+func pointers_to_nested_local_functions_in_generics<T>(x: T) -> Int{
+ func foo(y: Int) -> Int { return y }
+
+ return calls(foo, 0)
+}
diff --git a/test/SILGen/variadic-subscript-single-arg.swift b/test/SILGen/variadic-subscript-single-arg.swift
new file mode 100644
index 0000000..833f6cd
--- /dev/null
+++ b/test/SILGen/variadic-subscript-single-arg.swift
@@ -0,0 +1,9 @@
+// RUN: %target-swift-frontend -emit-silgen -verify %s
+
+struct Butt {
+ subscript(butts: Int...) -> Int {
+ return 0
+ }
+}
+
+_ = Butt()[1]
diff --git a/test/SILOptimizer/access_enforcement_noescape.swift b/test/SILOptimizer/access_enforcement_noescape.swift
index 760cf4c..e6a730e 100644
--- a/test/SILOptimizer/access_enforcement_noescape.swift
+++ b/test/SILOptimizer/access_enforcement_noescape.swift
@@ -26,12 +26,6 @@
// Helper
func doOneInout(_: ()->(), _: inout Int) {}
-// FIXME: statically prohibit a call to a non-escaping closure
-// parameter using another non-escaping closure parameter as an argument.
-func reentrantNoescape(fn: (() -> ()) -> ()) {
- fn { fn {} }
-}
-
// Error: Cannot capture nonescaping closure.
// func reentrantCapturedNoescape(fn: (() -> ()) -> ()) {
// let c = { fn {} }
diff --git a/test/attr/attr_noescape.swift b/test/attr/attr_noescape.swift
index e3c0936..2e8fc08 100644
--- a/test/attr/attr_noescape.swift
+++ b/test/attr/attr_noescape.swift
@@ -304,6 +304,7 @@
// expected-warning@-2{{@noescape is the default and is deprecated}} {{46-56=}}
// expected-warning@-3{{@noescape is the default and is deprecated}} {{57-66=}}
return g(f)
+ // expected-warning@-1{{passing a non-escaping function parameter 'f' to a call to a non-escaping function parameter}}
}
// <rdar://problem/19997577> @noescape cannot be applied to locals, leading to duplication of code
diff --git a/test/decl/ext/generic.swift b/test/decl/ext/generic.swift
index a3b1b54..b9d6178 100644
--- a/test/decl/ext/generic.swift
+++ b/test/decl/ext/generic.swift
@@ -158,3 +158,9 @@
}
extension S5 : P4 {}
+
+// rdar://problem/21607421
+public typealias Array2 = Array
+extension Array2 where QQQ : VVV {}
+// expected-error@-1 {{use of undeclared type 'QQQ'}}
+// expected-error@-2 {{use of undeclared type 'VVV'}}
diff --git a/test/decl/ext/protocol.swift b/test/decl/ext/protocol.swift
index 32b8c69..760d7df 100644
--- a/test/decl/ext/protocol.swift
+++ b/test/decl/ext/protocol.swift
@@ -921,9 +921,10 @@
}
}
+// rdar://problem/20756244
protocol BadProto3 { }
typealias BadProto4 = BadProto3
-extension BadProto4 { } // expected-error{{protocol 'BadProto3' in the module being compiled cannot be extended via a type alias}}{{11-20=BadProto3}}
+extension BadProto4 { } // okay
typealias RawRepresentableAlias = RawRepresentable
extension RawRepresentableAlias { } // okay
@@ -948,6 +949,6 @@
typealias A = BadProto1
typealias B = BadProto1
-extension A & B { // expected-error{{protocol 'BadProto1' in the module being compiled cannot be extended via a type alias}}
+extension A & B { // okay
}
diff --git a/test/decl/protocol/conforms/associated_type.swift b/test/decl/protocol/conforms/associated_type.swift
index be7e38c..92a5a79 100644
--- a/test/decl/protocol/conforms/associated_type.swift
+++ b/test/decl/protocol/conforms/associated_type.swift
@@ -1,4 +1,5 @@
-// RUN: %target-typecheck-verify-swift
+// RUN: %target-typecheck-verify-swift -swift-version 3
+// RUN: %target-typecheck-verify-swift -swift-version 4
class C { }
@@ -9,3 +10,23 @@
struct X : P { // expected-error{{type 'X' does not conform to protocol 'P'}}
typealias AssocP = Int // expected-note{{possibly intended match 'X.AssocP' (aka 'Int') does not inherit from 'C'}}
}
+
+// SR-5166
+protocol FooType {
+ associatedtype BarType
+
+ func foo(bar: BarType)
+ func foo(action: (BarType) -> Void)
+}
+
+protocol Bar {}
+
+class Foo: FooType {
+ typealias BarType = Bar
+
+ func foo(bar: Bar) {
+ }
+
+ func foo(action: (Bar) -> Void) {
+ }
+}
diff --git a/test/expr/postfix/call/noescape-param-exclusivity-swift3.swift b/test/expr/postfix/call/noescape-param-exclusivity-swift3.swift
new file mode 100644
index 0000000..adefa90
--- /dev/null
+++ b/test/expr/postfix/call/noescape-param-exclusivity-swift3.swift
@@ -0,0 +1,5 @@
+// RUN: %target-typecheck-verify-swift -swift-version 3
+
+func foo(fn: (() -> ()) -> ()) {
+ fn { fn {} } // expected-warning {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable and will be illegal in Swift 4}}
+}
diff --git a/test/expr/postfix/call/noescape-param-exclusivity.swift b/test/expr/postfix/call/noescape-param-exclusivity.swift
new file mode 100644
index 0000000..41af147
--- /dev/null
+++ b/test/expr/postfix/call/noescape-param-exclusivity.swift
@@ -0,0 +1,40 @@
+// RUN: %target-typecheck-verify-swift -swift-version 4
+
+// FIXME: make these errors
+
+func test0(fn: (() -> ()) -> ()) {
+ fn { fn {} } // expected-warning {{passing a closure which captures a non-escaping function parameter 'fn' to a call to a non-escaping function parameter can allow re-entrant modification of a variable}}
+}
+
+func test1(fn: (() -> ()) -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}}
+ // TODO: infer that this function is noescape from its captures
+ func foo() {
+ fn { fn {} } // expected-warning {{can allow re-entrant modification}}
+ // expected-error@-1 {{declaration closing over non-escaping parameter 'fn' may allow it to escape}}
+ }
+}
+
+func test2(x: inout Int, fn: (() -> ()) -> ()) {
+ func foo(myfn: () -> ()) {
+ x += 1
+ myfn()
+ }
+
+ // Make sure we only complain about calls to noescape parameters.
+ foo { fn {} }
+}
+
+func test3(fn: (() -> ()) -> ()) {
+ { myfn in myfn { fn {} } }(fn) // expected-warning {{can allow re-entrant modification}}
+}
+
+func test4(fn: (() -> ()) -> ()) { // expected-note {{parameter 'fn' is implicitly non-escaping}}
+ // TODO: infer that this function is noescape from its captures
+ func foo() {
+ fn {}
+ // expected-error@-1 {{declaration closing over non-escaping parameter 'fn' may allow it to escape}}
+ // FIXME: if the above is ever not an error, we should diagnose at the call below
+ }
+
+ fn(foo)
+}
diff --git a/test/stdlib/KeyPathImplementation.swift b/test/stdlib/KeyPathImplementation.swift
index d3c3e24..521912e 100644
--- a/test/stdlib/KeyPathImplementation.swift
+++ b/test/stdlib/KeyPathImplementation.swift
@@ -135,20 +135,33 @@
}
mutating func push(_ value: UInt32) {
- assert(buffer.count >= 4, "not enough room")
buffer.storeBytes(of: value, as: UInt32.self)
buffer = .init(start: buffer.baseAddress! + 4, count: buffer.count - 4)
}
+ mutating func push(_ value: Any.Type) {
+ var misalign = Int(bitPattern: buffer.baseAddress) % MemoryLayout<Int>.alignment
+ if misalign != 0 {
+ misalign = MemoryLayout<Int>.alignment - misalign
+ buffer = .init(start: buffer.baseAddress! + misalign,
+ count: buffer.count - misalign)
+ }
+ buffer.storeBytes(of: value, as: Any.Type.self)
+ buffer = .init(start: buffer.baseAddress! + MemoryLayout<Int>.size,
+ count: buffer.count - MemoryLayout<Int>.size)
+ }
mutating func addHeader(trivial: Bool, hasReferencePrefix: Bool) {
assert(state == .header, "not expecting a header")
- let size = buffer.count - 4
+ let size = buffer.count - MemoryLayout<Int>.size
assert(buffer.count > 0 && buffer.count <= 0x3FFF_FFFF,
"invalid buffer size")
let header: UInt32 = UInt32(size)
| (trivial ? 0x8000_0000 : 0)
| (hasReferencePrefix ? 0x4000_0000 : 0)
push(header)
+ if MemoryLayout<Int>.size == 8 {
+ push(0)
+ }
self.hasReferencePrefix = hasReferencePrefix
state.advance()
}
@@ -194,18 +207,7 @@
mutating func addType(_ type: Any.Type) {
assert(state == .type, "not expecting a type")
- if MemoryLayout<Int>.size == 8 {
- // Components are 4-byte aligned, but pointers are 8-byte aligned, so
- // we have to store word-by-word
- let words = unsafeBitCast(type, to: (UInt32, UInt32).self)
- push(words.0)
- push(words.1)
- } else if MemoryLayout<Int>.size == 4 {
- let word = unsafeBitCast(type, to: UInt32.self)
- push(word)
- } else {
- fatalError("unsupported architecture")
- }
+ push(type)
state.advance()
}
}
@@ -223,30 +225,30 @@
keyPathImpl.test("struct components") {
let s_x = WritableKeyPath<S<String>, Int>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<String>.x_offset)
}
let s_y = WritableKeyPath<S<String>, LifetimeTracked?>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<String>.y_offset)
}
let s_z = WritableKeyPath<S<String>, String>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<String>.z_offset)
}
let s_p = WritableKeyPath<S<String>, Point>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<String>.p_offset)
}
- let twoComponentSize = 12 + MemoryLayout<Int>.size
+ let twoComponentSize = MemoryLayout<Int>.size * 3 + 4
let s_p_x = WritableKeyPath<S<String>, Double>
.build(capacityInBytes: twoComponentSize) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
@@ -331,19 +333,19 @@
keyPathImpl.test("class components") {
let c_x = ReferenceWritableKeyPath<C<String>, Int>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addClassComponent(offset: C<String>.x_offset)
}
let c_y = ReferenceWritableKeyPath<C<String>, LifetimeTracked?>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addClassComponent(offset: C<String>.y_offset)
}
let c_z = ReferenceWritableKeyPath<C<String>, String>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addClassComponent(offset: C<String>.z_offset)
}
@@ -394,7 +396,7 @@
keyPathImpl.test("reference prefix") {
let s_c_x = ReferenceWritableKeyPath<S<String>, Int>
- .build(capacityInBytes: 12 + MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 3 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
$0.addStructComponent(offset: S<String>.c_offset,
endsReferencePrefix: true)
@@ -403,7 +405,7 @@
}
let s_c_y = ReferenceWritableKeyPath<S<String>, LifetimeTracked?>
- .build(capacityInBytes: 12 + MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 3 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
$0.addStructComponent(offset: S<String>.c_offset,
endsReferencePrefix: true)
@@ -412,7 +414,7 @@
}
let s_c_z = ReferenceWritableKeyPath<S<String>, String>
- .build(capacityInBytes: 12 + MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 3 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
$0.addStructComponent(offset: S<String>.c_offset,
endsReferencePrefix: true)
@@ -484,14 +486,14 @@
keyPathImpl.test("overflowed offsets") {
let s_p = WritableKeyPath<S<String>, Point>
- .build(capacityInBytes: 12) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 8) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<String>.p_offset,
forceOverflow: true)
}
let c_z = ReferenceWritableKeyPath<C<String>, String>
- .build(capacityInBytes: 12) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 8) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addClassComponent(offset: C<String>.z_offset,
forceOverflow: true)
@@ -516,7 +518,7 @@
keyPathImpl.test("equality") {
let s_c_z_p_x = ReferenceWritableKeyPath<S<S<String>>, Double>
- .build(capacityInBytes: 20 + 3 * MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 7 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// S<S<String>>.c
$0.addStructComponent(offset: S<S<String>>.c_offset,
@@ -537,7 +539,7 @@
// Structurally equivalent to s_c_z_p_x
let s_c_z_p_x_2 = ReferenceWritableKeyPath<S<S<String>>, Double>
- .build(capacityInBytes: 20 + 3 * MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 7 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// S<S<String>>.c
$0.addStructComponent(offset: S<S<String>>.c_offset,
@@ -561,7 +563,7 @@
// Structurally equivalent, force-overflowed offset components
let s_c_z_p_x_3 = ReferenceWritableKeyPath<S<S<String>>, Double>
- .build(capacityInBytes: 36 + 3 * MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 4 * MemoryLayout<Int>.size + 4 * 8) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// S<S<String>>.c
$0.addStructComponent(offset: S<S<String>>.c_offset,
@@ -589,7 +591,7 @@
// Same path type, different suffixes
let s_c_z_p_y = ReferenceWritableKeyPath<S<S<String>>, Double>
- .build(capacityInBytes: 20 + 3 * MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 7 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// S<S<String>>.c
$0.addStructComponent(offset: S<S<String>>.c_offset,
@@ -610,7 +612,7 @@
// Different path type
let s_c_z_p = ReferenceWritableKeyPath<S<S<String>>, Point>
- .build(capacityInBytes: 16 + 2 * MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 5 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// S<S<String>>.c
$0.addStructComponent(offset: S<S<String>>.c_offset,
@@ -628,7 +630,7 @@
// Same path, no reference prefix
let s_c_z_p_x_readonly = KeyPath<S<S<String>>, Double>
- .build(capacityInBytes: 20 + 3 * MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 7 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
// S<S<String>>.c
$0.addStructComponent(offset: S<S<String>>.c_offset)
@@ -648,7 +650,7 @@
// Same path type, different paths
let s_p_y_readonly = KeyPath<S<S<String>>, Double>
- .build(capacityInBytes: 12 + MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 3 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
// S<S<String>>.p
$0.addStructComponent(offset: S<S<String>>.p_offset)
@@ -661,7 +663,7 @@
expectNotEqual(s_c_z_p_x_readonly, s_p_y_readonly)
let o_o_o_o = ReferenceWritableKeyPath<Oroborous, Oroborous>
- .build(capacityInBytes: 16 + 2*MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 5 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
// O.o
$0.addClassComponent(offset: classHeaderSize)
@@ -675,7 +677,7 @@
// Different reference prefix length
let o_o_o_o_rp1 = ReferenceWritableKeyPath<Oroborous, Oroborous>
- .build(capacityInBytes: 16 + 2*MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 5 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// O.o
$0.addClassComponent(offset: classHeaderSize,
@@ -688,7 +690,7 @@
$0.addClassComponent(offset: classHeaderSize)
}
let o_o_o_o_rp2 = ReferenceWritableKeyPath<Oroborous, Oroborous>
- .build(capacityInBytes: 16 + 2*MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 5 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// O.o
$0.addClassComponent(offset: classHeaderSize)
@@ -701,7 +703,7 @@
$0.addClassComponent(offset: classHeaderSize)
}
let o_o_o_o_rp2_2 = ReferenceWritableKeyPath<Oroborous, Oroborous>
- .build(capacityInBytes: 16 + 2*MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 5 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
// O.o
$0.addClassComponent(offset: classHeaderSize)
@@ -729,7 +731,7 @@
// Same type, different length of components with same prefix
let o_o_o = ReferenceWritableKeyPath<Oroborous, Oroborous>
- .build(capacityInBytes: 12 + MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 3 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
// O.o
$0.addClassComponent(offset: classHeaderSize)
@@ -744,12 +746,12 @@
keyPathImpl.test("appending") {
let s_p = WritableKeyPath<S<String>, Point>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<String>.p_offset)
}
let p_y = WritableKeyPath<Point, Double>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: Point.y_offset)
}
@@ -772,7 +774,7 @@
expectEqual(s_p_y.hashValue, s_p_y2.hashValue)
let s_p_y_manual = WritableKeyPath<S<String>, Double>
- .build(capacityInBytes: 12 + MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 3 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<String>.p_offset)
$0.addType(Point.self)
@@ -783,7 +785,7 @@
expectEqual(s_p_y.hashValue, s_p_y_manual.hashValue)
let c_z = ReferenceWritableKeyPath<C<S<String>>, S<String>>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addClassComponent(offset: C<S<String>>.z_offset)
}
@@ -799,7 +801,7 @@
expectEqual(value2.z.p.x, 0.5)
let c_z_p_y_manual = ReferenceWritableKeyPath<C<S<String>>, Double>
- .build(capacityInBytes: 16 + MemoryLayout<Int>.size * 2) {
+ .build(capacityInBytes: 5 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addClassComponent(offset: C<S<String>>.z_offset)
$0.addType(S<String>.self)
@@ -813,7 +815,7 @@
expectEqual(c_z_p_y.hashValue, c_z_p_y_manual.hashValue)
let s_c = WritableKeyPath<S<S<String>>, C<S<String>>>
- .build(capacityInBytes: 8) {
+ .build(capacityInBytes: MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: false)
$0.addStructComponent(offset: S<S<String>>.c_offset)
}
@@ -828,7 +830,7 @@
expectEqual(value2[keyPath: c_z_p_y], 11.0)
let s_c_z_p_y_manual = ReferenceWritableKeyPath<S<S<String>>, Double>
- .build(capacityInBytes: 20 + MemoryLayout<Int>.size * 3) {
+ .build(capacityInBytes: 7 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
$0.addStructComponent(offset: S<S<String>>.c_offset,
endsReferencePrefix: true)
@@ -846,7 +848,7 @@
typealias CP = CratePair<S<S<String>>, Int>
let cratePair_left_value = ReferenceWritableKeyPath<CP, S<S<String>>>
- .build(capacityInBytes: 12 + MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 3 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
$0.addStructComponent(offset: CratePair<S<S<String>>, Int>.left_offset,
endsReferencePrefix: true)
@@ -868,7 +870,7 @@
let cratePair_left_value_c_z_p_y_manual
= ReferenceWritableKeyPath<CP, Double>
- .build(capacityInBytes: 28 + 5*MemoryLayout<Int>.size) {
+ .build(capacityInBytes: 11 * MemoryLayout<Int>.size + 4) {
$0.addHeader(trivial: true, hasReferencePrefix: true)
$0.addStructComponent(offset: CP.left_offset)
$0.addType(Crate<S<S<String>>>.self)
diff --git a/validation-test/compiler_crashers/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift b/validation-test/compiler_crashers_fixed/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift
similarity index 88%
rename from validation-test/compiler_crashers/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift
rename to validation-test/compiler_crashers_fixed/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift
index e8b8e2a..f54117f 100644
--- a/validation-test/compiler_crashers/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift
+++ b/validation-test/compiler_crashers_fixed/28738-impl-genericparams-empty-key-depth-impl-genericparams-back-getdepth-key-index-im.swift
@@ -6,5 +6,5 @@
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
// REQUIRES: asserts
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
protocol P}extension P{{}typealias a:P}extension P.a{protocol P