Merge pull request #35111 from nate-chandler/concurrency/irgen/for-now-async-is-not-simple
[Async CC] Never use simple partial apply for async functions.
diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst
index 7d72e56..9c084ad 100644
--- a/docs/ABI/Mangling.rst
+++ b/docs/ABI/Mangling.rst
@@ -493,6 +493,7 @@
type ::= 'Bb' // Builtin.BridgeObject
type ::= 'BB' // Builtin.UnsafeValueBuffer
type ::= 'Bc' // Builtin.RawUnsafeContinuation
+ type ::= 'BD' // Builtin.DefaultActorStorage
type ::= 'Bf' NATURAL '_' // Builtin.Float<n>
type ::= 'Bi' NATURAL '_' // Builtin.Int<n>
type ::= 'BI' // Builtin.IntLiteral
diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def
index aea2a4a..0a3ff64 100644
--- a/include/swift/AST/TypeNodes.def
+++ b/include/swift/AST/TypeNodes.def
@@ -110,6 +110,7 @@
BUILTIN_TYPE(BuiltinNativeObject, BuiltinType)
BUILTIN_TYPE(BuiltinBridgeObject, BuiltinType)
BUILTIN_TYPE(BuiltinUnsafeValueBuffer, BuiltinType)
+ BUILTIN_TYPE(BuiltinDefaultActorStorage, BuiltinType)
BUILTIN_TYPE(BuiltinVector, BuiltinType)
TYPE_RANGE(Builtin, BuiltinInteger, BuiltinVector)
TYPE(Tuple, Type)
@@ -185,6 +186,7 @@
SINGLETON_TYPE(NativeObject, BuiltinNativeObject)
SINGLETON_TYPE(BridgeObject, BuiltinBridgeObject)
SINGLETON_TYPE(UnsafeValueBuffer, BuiltinUnsafeValueBuffer)
+SINGLETON_TYPE(DefaultActorStorage, BuiltinDefaultActorStorage)
SINGLETON_TYPE(SILToken, SILToken)
#undef SINGLETON_TYPE
#endif
diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h
index a89e318..a44404d 100644
--- a/include/swift/AST/Types.h
+++ b/include/swift/AST/Types.h
@@ -1420,6 +1420,22 @@
};
DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinJobType, BuiltinType);
+/// BuiltinDefaultActorStorageType - The type of the stored property
+/// that's added implicitly to default actors. No C equivalent because
+/// the C types all include a heap-object header. Similarly, this type
+/// generally does not appear in the AST/SIL around default actors;
+/// it's purely a convenience in IRGen.
+class BuiltinDefaultActorStorageType : public BuiltinType {
+ friend class ASTContext;
+ BuiltinDefaultActorStorageType(const ASTContext &C)
+ : BuiltinType(TypeKind::BuiltinDefaultActorStorage, C) {}
+public:
+ static bool classof(const TypeBase *T) {
+ return T->getKind() == TypeKind::BuiltinDefaultActorStorage;
+ }
+};
+DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinDefaultActorStorageType, BuiltinType);
+
/// BuiltinNativeObjectType - The builtin opaque object-pointer type.
/// Useful for keeping an object alive when it is otherwise being
/// manipulated via an unsafe pointer type.
diff --git a/include/swift/Basic/Fingerprint.h b/include/swift/Basic/Fingerprint.h
index 3caaa28..da18ef4 100644
--- a/include/swift/Basic/Fingerprint.h
+++ b/include/swift/Basic/Fingerprint.h
@@ -60,53 +60,51 @@
class Fingerprint final {
public:
/// The size (in bytes) of the raw value of all fingerprints.
- ///
- /// This constant's value is justified by a static assertion in the
- /// corresponding cpp file.
constexpr static size_t DIGEST_LENGTH = 32;
+ using Core = std::pair<uint64_t, uint64_t>;
private:
- std::string Core;
+ Core core;
public:
+ /// Creates a fingerprint value from a pair of 64-bit integers.
+ explicit Fingerprint(Fingerprint::Core value) : core(value) {}
+
/// Creates a fingerprint value from the given input string that is known to
/// be a 32-byte hash value.
///
/// In +asserts builds, strings that violate this invariant will crash. If a
/// fingerprint value is needed to represent an "invalid" state, use a
/// vocabulary type like \c Optional<Fingerprint> instead.
- explicit Fingerprint(std::string value) : Core(std::move(value)) {
- assert(Core.size() == Fingerprint::DIGEST_LENGTH &&
- "Only supports 32-byte hash values!");
- }
+ static Fingerprint fromString(llvm::StringRef value);
/// Creates a fingerprint value from the given input string literal.
template <std::size_t N>
explicit Fingerprint(const char (&literal)[N])
- : Core{literal, N-1} {
+ : Fingerprint{Fingerprint::fromString({literal, N-1}).core} {
static_assert(N == Fingerprint::DIGEST_LENGTH + 1,
"String literal must be 32 bytes in length!");
}
/// Creates a fingerprint value by consuming the given \c MD5Result from LLVM.
explicit Fingerprint(llvm::MD5::MD5Result &&MD5Value)
- : Core{MD5Value.digest().str()} {}
+ : core{MD5Value.words()} {}
public:
/// Retrieve the raw underlying bytes of this fingerprint.
- llvm::StringRef getRawValue() const { return Core; }
+ llvm::SmallString<Fingerprint::DIGEST_LENGTH> getRawValue() const;
public:
friend bool operator==(const Fingerprint &lhs, const Fingerprint &rhs) {
- return lhs.Core == rhs.Core;
+ return lhs.core == rhs.core;
}
friend bool operator!=(const Fingerprint &lhs, const Fingerprint &rhs) {
- return lhs.Core != rhs.Core;
+ return lhs.core != rhs.core;
}
friend llvm::hash_code hash_value(const Fingerprint &fp) {
- return llvm::hash_value(fp.Core);
+ return llvm::hash_value(fp.core);
}
public:
@@ -115,7 +113,7 @@
/// This fingerprint is a perfectly fine value for an MD5 hash, but it is
/// completely arbitrary.
static Fingerprint ZERO() {
- return Fingerprint("00000000000000000000000000000000");
+ return Fingerprint(Fingerprint::Core{0, 0});
}
private:
@@ -124,7 +122,7 @@
///
/// Very well, LLVM. A default value you shall have.
friend class llvm::yaml::IO;
- Fingerprint() : Core(DIGEST_LENGTH, '0') {}
+ Fingerprint() : core{Fingerprint::Core{0, 0}} {}
};
void simple_display(llvm::raw_ostream &out, const Fingerprint &fp);
diff --git a/include/swift/Reflection/Records.h b/include/swift/Reflection/Records.h
index 80478cc..d24efae 100644
--- a/include/swift/Reflection/Records.h
+++ b/include/swift/Reflection/Records.h
@@ -37,6 +37,9 @@
// Is this a mutable `var` property?
IsVar = 0x2,
+
+ // Is this an artificial field?
+ IsArtificial = 0x4,
};
int_type Data = 0;
@@ -49,6 +52,10 @@
return (Data & IsVar) == IsVar;
}
+ bool isArtificial() const {
+ return (Data & IsArtificial) == IsArtificial;
+ }
+
void setIsIndirectCase(bool IndirectCase=true) {
if (IndirectCase)
Data |= IsIndirectCase;
@@ -63,6 +70,13 @@
Data &= ~IsVar;
}
+ void setIsArtificial(bool artificial=true) {
+ if (artificial)
+ Data |= IsArtificial;
+ else
+ Data &= ~IsArtificial;
+ }
+
int_type getRawValue() const {
return Data;
}
diff --git a/include/swift/Strings.h b/include/swift/Strings.h
index a869c42..b9c056d 100644
--- a/include/swift/Strings.h
+++ b/include/swift/Strings.h
@@ -47,6 +47,9 @@
constexpr static const StringLiteral SEMANTICS_PROGRAMTERMINATION_POINT =
"programtermination_point";
+constexpr static const StringLiteral DEFAULT_ACTOR_STORAGE_FIELD_NAME =
+ "$defaultActor";
+
/// The name of the Builtin type prefix
constexpr static const StringLiteral BUILTIN_TYPE_NAME_PREFIX = "Builtin.";
@@ -119,6 +122,9 @@
/// The name of the Builtin type for Job
constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_JOB = {
"Builtin.Job"};
+/// The name of the Builtin type for DefaultActorStorage
+constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE = {
+ "Builtin.DefaultActorStorage"};
/// The name of the Builtin type for UnknownObject
///
/// This no longer exists as an AST-accessible type, but it's still used for
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 2b529ac..52ba7f2 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -3561,6 +3561,7 @@
TRIVIAL_TYPE_PRINTER(BuiltinIntegerLiteral, builtin_integer_literal)
TRIVIAL_TYPE_PRINTER(BuiltinJob, builtin_job)
+ TRIVIAL_TYPE_PRINTER(BuiltinDefaultActorStorage, builtin_default_actor_storage)
TRIVIAL_TYPE_PRINTER(BuiltinRawPointer, builtin_raw_pointer)
TRIVIAL_TYPE_PRINTER(BuiltinRawUnsafeContinuation, builtin_raw_unsafe_continuation)
TRIVIAL_TYPE_PRINTER(BuiltinNativeObject, builtin_native_object)
diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp
index 65f1e9a..df071a0 100644
--- a/lib/AST/ASTMangler.cpp
+++ b/lib/AST/ASTMangler.cpp
@@ -975,6 +975,8 @@
return appendOperator("BI");
case TypeKind::BuiltinJob:
return appendOperator("Bj");
+ case TypeKind::BuiltinDefaultActorStorage:
+ return appendOperator("BD");
case TypeKind::BuiltinRawPointer:
return appendOperator("Bp");
case TypeKind::BuiltinRawUnsafeContinuation:
diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp
index 5760581..091d708 100644
--- a/lib/AST/ASTPrinter.cpp
+++ b/lib/AST/ASTPrinter.cpp
@@ -3946,6 +3946,7 @@
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinRawPointerType)
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinRawUnsafeContinuationType)
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinJobType)
+ ASTPRINTER_PRINT_BUILTINTYPE(BuiltinDefaultActorStorageType)
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinNativeObjectType)
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinBridgeObjectType)
ASTPRINTER_PRINT_BUILTINTYPE(BuiltinUnsafeValueBufferType)
diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp
index af72df2..fa0ea2c 100644
--- a/lib/AST/Builtins.cpp
+++ b/lib/AST/Builtins.cpp
@@ -83,6 +83,8 @@
return Context.TheRawUnsafeContinuationType;
if (Name == "Job")
return Context.TheJobType;
+ if (Name == "DefaultActorStorage")
+ return Context.TheDefaultActorStorageType;
if (Name == "NativeObject")
return Context.TheNativeObjectType;
if (Name == "BridgeObject")
@@ -2733,6 +2735,9 @@
case BuiltinTypeKind::BuiltinJob:
printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_JOB);
break;
+ case BuiltinTypeKind::BuiltinDefaultActorStorage:
+ printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE);
+ break;
case BuiltinTypeKind::BuiltinNativeObject:
printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_NATIVEOBJECT);
break;
diff --git a/lib/AST/FineGrainedDependencyFormat.cpp b/lib/AST/FineGrainedDependencyFormat.cpp
index 4294767..6842377 100644
--- a/lib/AST/FineGrainedDependencyFormat.cpp
+++ b/lib/AST/FineGrainedDependencyFormat.cpp
@@ -232,7 +232,7 @@
if (node == nullptr)
llvm::report_fatal_error("Unexpected FINGERPRINT_NODE record");
- node->setFingerprint(Fingerprint{BlobData.str()});
+ node->setFingerprint(Fingerprint::fromString(BlobData));
break;
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 9535ab9..70fc6ac 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -210,6 +210,7 @@
case TypeKind::BuiltinRawPointer:
case TypeKind::BuiltinRawUnsafeContinuation:
case TypeKind::BuiltinJob:
+ case TypeKind::BuiltinDefaultActorStorage:
case TypeKind::BuiltinUnsafeValueBuffer:
case TypeKind::BuiltinVector:
case TypeKind::Tuple:
@@ -5007,6 +5008,7 @@
case TypeKind::BuiltinRawPointer:
case TypeKind::BuiltinRawUnsafeContinuation:
case TypeKind::BuiltinJob:
+ case TypeKind::BuiltinDefaultActorStorage:
case TypeKind::BuiltinUnsafeValueBuffer:
case TypeKind::BuiltinVector:
case TypeKind::Tuple:
diff --git a/lib/Basic/Fingerprint.cpp b/lib/Basic/Fingerprint.cpp
index 389ecd3..ec4ca98 100644
--- a/lib/Basic/Fingerprint.cpp
+++ b/lib/Basic/Fingerprint.cpp
@@ -12,8 +12,12 @@
#include "swift/Basic/Fingerprint.h"
#include "swift/Basic/STLExtras.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
+#include <inttypes.h>
+#include <sstream>
+
using namespace swift;
llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &OS,
@@ -25,19 +29,26 @@
out << fp.getRawValue();
}
-namespace {
- template <class T> struct SmallStringBound;
- template <size_t N> struct SmallStringBound<llvm::SmallString<N>> {
- static constexpr size_t value = N;
- };
-};
+Fingerprint Fingerprint::fromString(StringRef value) {
+ assert(value.size() == Fingerprint::DIGEST_LENGTH &&
+ "Only supports 32-byte hash values!");
+ auto fp = Fingerprint::ZERO();
+ {
+ std::istringstream s(value.drop_back(Fingerprint::DIGEST_LENGTH/2).str());
+ s >> std::hex >> fp.core.first;
+ }
+ {
+ std::istringstream s(value.drop_front(Fingerprint::DIGEST_LENGTH/2).str());
+ s >> std::hex >> fp.core.second;
+ }
+ return fp;
+}
-// Assert that the \c DIGEST_LENGTH value we export from the \c Fingerprint
-// has the right byte length. It's unlikely this value will change in LLVM,
-// but it's always good to have compile-time justification for a
-// magic constant - especially one that gets used for serialization.
-using MD5Digest_t =
- decltype (&llvm::MD5::MD5Result::digest)(llvm::MD5::MD5Result);
-static_assert(SmallStringBound<std::result_of<MD5Digest_t>::type>::value ==
- Fingerprint::DIGEST_LENGTH,
- "MD5 digest size does not match size expected by Fingerprint!");
+llvm::SmallString<Fingerprint::DIGEST_LENGTH> Fingerprint::getRawValue() const {
+ llvm::SmallString<Fingerprint::DIGEST_LENGTH> Str;
+ llvm::raw_svector_ostream Res(Str);
+ Res << llvm::format_hex_no_prefix(core.first, 16);
+ Res << llvm::format_hex_no_prefix(core.second, 16);
+ assert(*this == Fingerprint::fromString(Str));
+ return Str;
+}
diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp
index 6e7b133..2811cf3 100644
--- a/lib/Demangling/Demangler.cpp
+++ b/lib/Demangling/Demangler.cpp
@@ -1184,6 +1184,10 @@
Ty = createNode(Node::Kind::BuiltinTypeName,
BUILTIN_TYPE_NAME_JOB);
break;
+ case 'D':
+ Ty = createNode(Node::Kind::BuiltinTypeName,
+ BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE);
+ break;
case 'c':
Ty = createNode(Node::Kind::BuiltinTypeName,
BUILTIN_TYPE_NAME_RAWUNSAFECONTINUATION);
diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp
index b29e8c8..c54a8a8 100644
--- a/lib/Demangling/OldRemangler.cpp
+++ b/lib/Demangling/OldRemangler.cpp
@@ -2177,8 +2177,8 @@
}
void Remangler::mangleCanonicalSpecializedGenericMetaclass(Node *node) {
- Buffer << "MM";
mangleSingleChildNode(node); // type
+ Buffer << "MM";
}
void Remangler::mangleCanonicalSpecializedGenericTypeMetadataAccessFunction(
diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp
index 5fde0aa..ea90ba6 100644
--- a/lib/Demangling/Remangler.cpp
+++ b/lib/Demangling/Remangler.cpp
@@ -748,6 +748,8 @@
Buffer << 'c';
} else if (text == BUILTIN_TYPE_NAME_JOB) {
Buffer << 'j';
+ } else if (text == BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE) {
+ Buffer << 'D';
} else if (text == BUILTIN_TYPE_NAME_SILTOKEN) {
Buffer << 't';
} else if (text == BUILTIN_TYPE_NAME_INTLITERAL) {
diff --git a/lib/IRGen/ClassLayout.cpp b/lib/IRGen/ClassLayout.cpp
index 65adf4e..87bca56 100644
--- a/lib/IRGen/ClassLayout.cpp
+++ b/lib/IRGen/ClassLayout.cpp
@@ -27,7 +27,7 @@
ClassLayout::ClassLayout(const StructLayoutBuilder &builder,
ClassMetadataOptions options,
llvm::Type *classTy,
- ArrayRef<VarDecl *> allStoredProps,
+ ArrayRef<Field> allStoredProps,
ArrayRef<FieldAccess> allFieldAccesses,
ArrayRef<ElementLayout> allElements,
Size headerSize)
diff --git a/lib/IRGen/ClassLayout.h b/lib/IRGen/ClassLayout.h
index 014e518..19c8918 100644
--- a/lib/IRGen/ClassLayout.h
+++ b/lib/IRGen/ClassLayout.h
@@ -19,6 +19,7 @@
#define SWIFT_IRGEN_CLASSLAYOUT_H
#include "llvm/ADT/ArrayRef.h"
+#include "Field.h"
#include "IRGen.h"
#include "StructLayout.h"
@@ -119,7 +120,7 @@
/// Lazily-initialized array of all fragile stored properties directly defined
/// in the class itself.
- ArrayRef<VarDecl *> AllStoredProperties;
+ ArrayRef<Field> AllStoredProperties;
/// Lazily-initialized array of all field access methods.
ArrayRef<FieldAccess> AllFieldAccesses;
@@ -132,7 +133,7 @@
ClassLayout(const StructLayoutBuilder &builder,
ClassMetadataOptions options,
llvm::Type *classTy,
- ArrayRef<VarDecl *> allStoredProps,
+ ArrayRef<Field> allStoredProps,
ArrayRef<FieldAccess> allFieldAccesses,
ArrayRef<ElementLayout> allElements,
Size headerSize);
@@ -201,7 +202,7 @@
}
std::pair<FieldAccess, ElementLayout>
- getFieldAccessAndElement(VarDecl *field) const {
+ getFieldAccessAndElement(Field field) const {
// FIXME: This is algorithmically terrible.
auto found = std::find(AllStoredProperties.begin(),
AllStoredProperties.end(), field);
diff --git a/lib/IRGen/ClassMetadataVisitor.h b/lib/IRGen/ClassMetadataVisitor.h
index 441eabf..ef11895 100644
--- a/lib/IRGen/ClassMetadataVisitor.h
+++ b/lib/IRGen/ClassMetadataVisitor.h
@@ -25,6 +25,7 @@
#include "swift/SIL/SILVTable.h"
#include "swift/SIL/SILVTableVisitor.h"
#include "IRGen.h"
+#include "Field.h"
#include "NominalMetadataVisitor.h"
namespace swift {
@@ -157,10 +158,9 @@
// But we currently always give classes field-offset vectors,
// whether they need them or not.
asImpl().noteStartOfFieldOffsets(theClass);
- for (auto field :
- theClass->getStoredPropertiesAndMissingMemberPlaceholders()) {
- addFieldEntries(field);
- }
+ forEachField(IGM, theClass, [&](Field field) {
+ asImpl().addFieldEntries(field);
+ });
asImpl().noteEndOfFieldOffsets(theClass);
// If the class has resilient metadata, we cannot make any assumptions
@@ -183,13 +183,16 @@
}
- void addFieldEntries(Decl *field) {
- if (auto var = dyn_cast<VarDecl>(field)) {
- asImpl().addFieldOffset(var);
+ void addFieldEntries(Field field) {
+ switch (field.getKind()) {
+ case Field::Var:
+ asImpl().addFieldOffset(field.getVarDecl());
return;
- }
- if (auto placeholder = dyn_cast<MissingMemberDecl>(field)) {
- asImpl().addFieldOffsetPlaceholders(placeholder);
+ case Field::MissingMember:
+ asImpl().addFieldOffsetPlaceholders(field.getMissingMemberDecl());
+ return;
+ case Field::DefaultActorStorage:
+ asImpl().addDefaultActorStorageFieldOffset();
return;
}
}
@@ -227,6 +230,7 @@
addPointer();
}
void addMethodOverride(SILDeclRef baseRef, SILDeclRef declRef) {}
+ void addDefaultActorStorageFieldOffset() { addPointer(); }
void addFieldOffset(VarDecl *var) { addPointer(); }
void addFieldOffsetPlaceholders(MissingMemberDecl *mmd) {
for (unsigned i = 0, e = mmd->getNumberOfFieldOffsetVectorEntries();
diff --git a/lib/IRGen/Field.h b/lib/IRGen/Field.h
new file mode 100644
index 0000000..f2f6f5e
--- /dev/null
+++ b/lib/IRGen/Field.h
@@ -0,0 +1,107 @@
+//===--- Field.h - Abstract stored field ------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides an abstraction for some sort of stored field
+// in a type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_IRGEN_FIELD_H
+#define SWIFT_IRGEN_FIELD_H
+
+#include "swift/AST/Decl.h"
+
+namespace swift {
+class SILType;
+
+namespace irgen {
+class IRGenModule;
+
+/// Return the number of fields that will be visited by forEachField,
+/// which determines a number of things in the ABI, including the length
+/// of the field vector in the type metadata.
+///
+/// Generally this is the length of the stored properties, but
+/// root default actors have an implicit field for their default-actor
+/// storage, and there may also be missing members.
+///
+/// Even if you're sure that you're in a case where only the stored
+/// properties are needed, calling this (and forEachField) instead of
+/// directly accessing the stored properties is good practice.
+unsigned getNumFields(const NominalTypeDecl *type);
+
+struct Field {
+public:
+ enum Kind: uintptr_t {
+ Var,
+ MissingMember,
+ DefaultActorStorage,
+ FirstArtificial = DefaultActorStorage
+ };
+ enum : uintptr_t { KindMask = 0x3 };
+private:
+ uintptr_t declOrKind;
+public:
+ Field(VarDecl *decl)
+ : declOrKind(reinterpret_cast<uintptr_t>(decl) | Var) {
+ assert(decl);
+ assert(getKind() == Var);
+ }
+ Field(MissingMemberDecl *decl)
+ : declOrKind(reinterpret_cast<uintptr_t>(decl) | MissingMember) {
+ assert(decl);
+ assert(getKind() == MissingMember);
+ }
+ Field(Kind kind) : declOrKind(kind) {
+ assert(kind >= FirstArtificial);
+ }
+
+ Kind getKind() const {
+ return Kind(declOrKind & KindMask);
+ }
+ VarDecl *getVarDecl() const {
+ assert(getKind() == Var);
+ return reinterpret_cast<VarDecl*>(declOrKind);
+ }
+ MissingMemberDecl *getMissingMemberDecl() const {
+ assert(getKind() == MissingMember);
+ return reinterpret_cast<MissingMemberDecl*>(declOrKind & ~KindMask);
+ }
+
+ /// Is this a concrete field? When we're emitting a type, all the
+ /// fields should be concrete; non-concrete fields occur only with
+ /// imported declarations.
+ bool isConcrete() const { return getKind() != MissingMember; }
+
+ /// Return the type of this concrete field.
+ SILType getType(IRGenModule &IGM, SILType baseType) const;
+
+ /// Return the interface type of this concrete field.
+ Type getInterfaceType(IRGenModule &IGM) const;
+
+ /// Return the nam eof this concrete field.
+ llvm::StringRef getName() const;
+
+ bool operator==(Field other) const { return declOrKind == other.declOrKind; }
+ bool operator!=(Field other) const { return declOrKind != other.declOrKind; }
+};
+
+/// Iterate all the fields of the given struct or class type, including
+/// any implicit fields that might be accounted for in
+/// getFieldVectorLength.
+void forEachField(IRGenModule &IGM, const NominalTypeDecl *typeDecl,
+ llvm::function_ref<void(Field field)> fn);
+
+} // end namespace irgen
+} // end namespace swift
+
+#endif
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index e90ea54..d6243e7 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -88,7 +88,7 @@
namespace {
class ClassLayoutBuilder : public StructLayoutBuilder {
SmallVector<ElementLayout, 8> Elements;
- SmallVector<VarDecl*, 8> AllStoredProperties;
+ SmallVector<Field, 8> AllStoredProperties;
SmallVector<FieldAccess, 8> AllFieldAccesses;
// If we're building a layout with tail-allocated elements, we do
@@ -277,14 +277,22 @@
void addDirectFieldsFromClass(ClassDecl *rootClass, SILType rootClassType,
ClassDecl *theClass, SILType classType,
bool superclass) {
- if (theClass->isRootDefaultActor())
- addDefaultActorHeader();
+ bool collectStoredProperties =
+ !superclass ||
+ (rootClass->isGenericContext() && !rootClassType.getASTType()
+ ->getRecursiveProperties()
+ .hasUnboundGeneric());
- for (VarDecl *var : theClass->getStoredProperties()) {
- SILType type = classType.getFieldType(var, IGM.getSILModule(),
- TypeExpansionContext::minimal());
+ forEachField(IGM, theClass, [&](Field field) {
+ // Ignore missing properties here; we should have flagged these
+ // with the classHasIncompleteLayout call above.
+ if (!field.isConcrete()) {
+ assert(Options & ClassMetadataFlags::ClassHasMissingMembers);
+ return;
+ }
// Lower the field type.
+ SILType type = field.getType(IGM, classType);
auto *eltType = &IGM.getTypeInfo(type);
if (CompletelyFragileLayout && !eltType->isFixedSize()) {
LoweringModeScope scope(IGM, TypeConverter::Mode::Legacy);
@@ -301,21 +309,16 @@
auto element = ElementLayout::getIncomplete(*eltType);
bool isKnownEmpty = !addField(element, LayoutStrategy::Universal);
- bool isSpecializedGeneric =
- (rootClass->isGenericContext() && !rootClassType.getASTType()
- ->getRecursiveProperties()
- .hasUnboundGeneric());
-
// The 'Elements' list only contains superclass fields when we're
// building a layout for tail allocation.
- if (!superclass || TailTypes || isSpecializedGeneric)
+ if (collectStoredProperties || TailTypes)
Elements.push_back(element);
- if (!superclass || isSpecializedGeneric) {
- AllStoredProperties.push_back(var);
+ if (collectStoredProperties) {
+ AllStoredProperties.push_back(field);
AllFieldAccesses.push_back(getFieldAccess(isKnownEmpty));
}
- }
+ });
if (!superclass) {
// If we're calculating the layout of a specialized generic class type,
@@ -338,9 +341,9 @@
for (unsigned index : indices(AllFieldAccesses)) {
auto &access = AllFieldAccesses[index];
- auto *var = AllStoredProperties[index];
+ auto field = AllStoredProperties[index];
if (access == FieldAccess::NonConstantDirect)
- access = abstractLayout->getFieldAccessAndElement(var).first;
+ access = abstractLayout->getFieldAccessAndElement(field).first;
}
}
@@ -1034,7 +1037,7 @@
};
llvm::SmallString<16> CategoryName;
- SmallVector<VarDecl*, 8> Ivars;
+ SmallVector<Field, 8> Ivars;
SmallVector<MethodDescriptor, 16> InstanceMethods;
SmallVector<MethodDescriptor, 16> ClassMethods;
SmallVector<MethodDescriptor, 16> OptInstanceMethods;
@@ -1073,6 +1076,9 @@
: IGM(IGM), TheEntity(theUnion), TheExtension(nullptr),
FieldLayout(&fieldLayout) {
visitConformances(getClass());
+
+ if (getClass()->isRootDefaultActor())
+ Ivars.push_back(Field::DefaultActorStorage);
visitMembers(getClass());
if (Lowering::usesObjCAllocator(getClass())) {
@@ -1805,20 +1811,26 @@
/// uint32_t alignment; // actually the log2 of the alignment
/// uint32_t size;
/// };
- void buildIvar(ConstantArrayBuilder &ivars, VarDecl *ivar) {
+ void buildIvar(ConstantArrayBuilder &ivars, Field field) {
assert(FieldLayout && "can't build ivar for category");
- auto fields = ivars.beginStruct();
-
// For now, we never try to emit specialized versions of the
// metadata statically, so compute the field layout using the
// originally-declared type.
- auto pair = FieldLayout->getFieldAccessAndElement(ivar);
+ auto pair = FieldLayout->getFieldAccessAndElement(field);
llvm::Constant *offsetPtr;
switch (pair.first) {
case FieldAccess::ConstantDirect:
case FieldAccess::NonConstantDirect: {
+ // Default actor storage doesn't get an ivar access variable.
+ if (field.getKind() == Field::DefaultActorStorage) {
+ offsetPtr = nullptr;
+ break;
+ }
+
+ // Otherwise, we should have a normal stored property.
+ auto ivar = field.getVarDecl();
// If the field offset is fixed relative to the start of the superclass,
// reference the global from the ivar metadata so that the Objective-C
// runtime will slide it down.
@@ -1829,22 +1841,28 @@
case FieldAccess::ConstantIndirect:
// Otherwise, swift_initClassMetadata() will point the Objective-C
// runtime into the field offset vector of the instantiated metadata.
- offsetPtr
- = llvm::ConstantPointerNull::get(IGM.IntPtrTy->getPointerTo());
+ offsetPtr = nullptr;
break;
}
- fields.add(offsetPtr);
+ StringRef name = field.getName();
+ const TypeInfo &storageTI = pair.second.getType();
+ auto fields = ivars.beginStruct();
+
+ if (offsetPtr)
+ fields.add(offsetPtr);
+ else
+ fields.addNullPointer(IGM.IntPtrTy->getPointerTo());
// TODO: clang puts this in __TEXT,__objc_methname,cstring_literals
- fields.add(IGM.getAddrOfGlobalString(ivar->getName().str()));
+ fields.add(IGM.getAddrOfGlobalString(name));
// TODO: clang puts this in __TEXT,__objc_methtype,cstring_literals
fields.add(IGM.getAddrOfGlobalString(""));
Size size;
Alignment alignment;
- if (auto fixedTI = dyn_cast<FixedTypeInfo>(&pair.second.getType())) {
+ if (auto fixedTI = dyn_cast<FixedTypeInfo>(&storageTI)) {
size = fixedTI->getFixedSize();
alignment = fixedTI->getFixedAlignment();
} else {
@@ -1855,7 +1873,7 @@
// If the size is larger than we can represent in 32-bits,
// complain about the unimplementable ivar.
if (uint32_t(size.getValue()) != size.getValue()) {
- IGM.error(ivar->getLoc(),
+ IGM.error(field.getVarDecl()->getLoc(),
"ivar size (" + Twine(size.getValue()) +
" bytes) overflows Objective-C ivar layout");
size = Size(0);
@@ -1878,8 +1896,8 @@
return buildOptionalList(Ivars, eltSize, "_IVARS_",
/*constant*/ true,
[&](ConstantArrayBuilder &descriptors,
- VarDecl *ivar) {
- buildIvar(descriptors, ivar);
+ Field field) {
+ buildIvar(descriptors, field);
});
}
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 4fb879a..2fcdf3c 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -49,6 +49,7 @@
#include "ClassTypeInfo.h"
#include "ConstantBuilder.h"
#include "EnumMetadataVisitor.h"
+#include "Field.h"
#include "FixedTypeInfo.h"
#include "ForeignClassMetadataVisitor.h"
#include "GenArchetype.h"
@@ -1396,10 +1397,8 @@
}
void addLayoutInfo() {
- auto properties = getType()->getStoredProperties();
-
// uint32_t NumFields;
- B.addInt32(properties.size());
+ B.addInt32(getNumFields(getType()));
// uint32_t FieldOffsetVectorOffset;
B.addInt32(FieldVectorOffset / IGM.getPointerSize());
@@ -1786,8 +1785,6 @@
B.addInt32(0);
}
- auto properties = getType()->getStoredProperties();
-
// union {
// uint32_t MetadataNegativeSizeInWords;
// RelativeDirectPointer<StoredClassMetadataBounds>
@@ -1827,7 +1824,7 @@
B.addInt32(numImmediateMembers);
// uint32_t NumFields;
- B.addInt32(properties.size());
+ B.addInt32(getNumFields(getType()));
// uint32_t FieldOffsetVectorOffset;
B.addInt32(getFieldVectorOffset() / IGM.getPointerSize());
@@ -2196,33 +2193,30 @@
.getAddress();
// Collect the stored properties of the type.
- llvm::SmallVector<VarDecl*, 4> storedProperties;
- for (auto prop : target->getStoredProperties()) {
- storedProperties.push_back(prop);
- }
+ unsigned numFields = getNumFields(target);
// Fill out an array with the field type metadata records.
Address fields = IGF.createAlloca(
- llvm::ArrayType::get(IGM.Int8PtrPtrTy,
- storedProperties.size()),
+ llvm::ArrayType::get(IGM.Int8PtrPtrTy, numFields),
IGM.getPointerAlignment(), "classFields");
- IGF.Builder.CreateLifetimeStart(fields,
- IGM.getPointerSize() * storedProperties.size());
+ IGF.Builder.CreateLifetimeStart(fields, IGM.getPointerSize() * numFields);
fields = IGF.Builder.CreateStructGEP(fields, 0, Size(0));
unsigned index = 0;
- for (auto prop : storedProperties) {
- auto propTy = T.getFieldType(prop, IGF.getSILModule(),
- TypeExpansionContext::minimal());
- llvm::Value *metadata = emitTypeLayoutRef(IGF, propTy, collector);
- Address field = IGF.Builder.CreateConstArrayGEP(fields, index,
- IGM.getPointerSize());
- IGF.Builder.CreateStore(metadata, field);
+ forEachField(IGM, target, [&](Field field) {
+ assert(field.isConcrete() &&
+ "initializing offset vector for type with missing member?");
+ SILType propTy = field.getType(IGM, T);
+ llvm::Value *fieldLayout = emitTypeLayoutRef(IGF, propTy, collector);
+ Address fieldLayoutAddr =
+ IGF.Builder.CreateConstArrayGEP(fields, index, IGM.getPointerSize());
+ IGF.Builder.CreateStore(fieldLayout, fieldLayoutAddr);
++index;
- }
+ });
+ assert(index == numFields);
// Ask the runtime to lay out the struct or class.
- auto numFields = IGM.getSize(Size(storedProperties.size()));
+ auto numFieldsV = IGM.getSize(Size(numFields));
if (auto *classDecl = dyn_cast<ClassDecl>(target)) {
// Compute class layout flags.
@@ -2252,7 +2246,7 @@
IGF.Builder.CreateCall(IGM.getInitClassMetadata2Fn(),
{metadata,
IGM.getSize(Size(uintptr_t(flags))),
- numFields, fields.getAddress(), fieldVector});
+ numFieldsV, fields.getAddress(), fieldVector});
break;
case ClassMetadataStrategy::Update:
@@ -2266,7 +2260,7 @@
IGF.Builder.CreateCall(IGM.getUpdateClassMetadata2Fn(),
{metadata,
IGM.getSize(Size(uintptr_t(flags))),
- numFields, fields.getAddress(), fieldVector});
+ numFieldsV, fields.getAddress(), fieldVector});
break;
case ClassMetadataStrategy::Fixed:
@@ -2289,11 +2283,10 @@
// Call swift_initStructMetadata().
IGF.Builder.CreateCall(IGM.getInitStructMetadataFn(),
{metadata, IGM.getSize(Size(uintptr_t(flags))),
- numFields, fields.getAddress(), fieldVector});
+ numFieldsV, fields.getAddress(), fieldVector});
}
- IGF.Builder.CreateLifetimeEnd(fields,
- IGM.getPointerSize() * storedProperties.size());
+ IGF.Builder.CreateLifetimeEnd(fields, IGM.getPointerSize() * numFields);
}
static void emitInitializeValueMetadata(IRGenFunction &IGF,
@@ -2341,8 +2334,13 @@
// field offset globals for us; but if ObjC interop is disabled, we
// have to do that ourselves, assuming we didn't just emit them all
// correctly in the first place.
+ // FIXME: make the runtime do this in all cases, because there's no
+ // good reason it shouldn't
if (!IGM.ObjCInterop) {
- for (auto prop : classDecl->getStoredProperties()) {
+ forEachField(IGM, classDecl, [&](Field field) {
+ // FIXME: should we handle the other cases here?
+ if (field.getKind() != Field::Var) return;
+ auto prop = field.getVarDecl();
auto fieldInfo = fieldLayout.getFieldAccessAndElement(prop);
if (fieldInfo.first == FieldAccess::NonConstantDirect) {
Address offsetA = IGM.getAddrOfFieldOffset(prop, ForDefinition);
@@ -2355,7 +2353,7 @@
auto offsetVal = IGF.emitInvariantLoad(slot);
IGF.Builder.CreateStore(offsetVal, offsetA);
}
- }
+ });
}
}
@@ -2753,7 +2751,23 @@
ClassDecl *classDecl,
const ClassLayout &fragileLayout,
const ClassLayout &resilientLayout) {
- for (auto prop : classDecl->getStoredProperties()) {
+ forEachField(IGM, classDecl, [&](Field field) {
+ switch (field.getKind()) {
+ // This is case we actually care about.
+ case Field::Var:
+ break;
+
+ // We should never be in this case when emitting a type.
+ case Field::MissingMember:
+ llvm_unreachable("unexpected missing member when emitting type");
+
+ // We don't need to emit an offset global for the default-actor
+ // storage, which is never accessed directly.
+ case Field::DefaultActorStorage:
+ return;
+ }
+
+ auto prop = field.getVarDecl();
auto fieldInfo = fragileLayout.getFieldAccessAndElement(prop);
auto access = fieldInfo.first;
auto element = fieldInfo.second;
@@ -2813,7 +2827,7 @@
// No global variable is needed.
break;
}
- }
+ });
}
static ClassFlags getClassFlags(ClassDecl *classDecl) {
@@ -3124,6 +3138,10 @@
B.add(data);
}
+ void addDefaultActorStorageFieldOffset() {
+ B.addInt(IGM.SizeTy, getDefaultActorStorageFieldOffset(IGM).getValue());
+ }
+
void addReifiedVTableEntry(SILDeclRef fn) {
// Find the vtable entry.
assert(VTable && "no vtable?!");
@@ -4236,7 +4254,7 @@
if (!isa<FixedTypeInfo>(ti))
return false;
- if (Target->getStoredProperties().empty())
+ if (getNumFields(Target) == 0)
return false;
return true;
diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp
index c6dd84d..34c2b22 100644
--- a/lib/IRGen/GenReflection.cpp
+++ b/lib/IRGen/GenReflection.cpp
@@ -28,10 +28,12 @@
#include "ConstantBuilder.h"
#include "Explosion.h"
+#include "Field.h"
#include "GenClass.h"
#include "GenDecl.h"
#include "GenEnum.h"
#include "GenHeap.h"
+#include "GenMeta.h"
#include "GenProto.h"
#include "GenType.h"
#include "IRGenDebugInfo.h"
@@ -672,13 +674,8 @@
private:
const NominalTypeDecl *NTD;
- void addFieldDecl(const ValueDecl *value, Type type,
- bool indirect=false) {
- reflection::FieldRecordFlags flags;
- flags.setIsIndirectCase(indirect);
- if (auto var = dyn_cast<VarDecl>(value))
- flags.setIsVar(!var->isLet());
-
+ void addField(reflection::FieldRecordFlags flags,
+ Type type, StringRef name) {
B.addInt32(flags.getRawValue());
if (!type) {
@@ -693,7 +690,6 @@
}
if (IGM.IRGen.Opts.EnableReflectionNames) {
- auto name = value->getBaseIdentifier().str();
auto fieldName = IGM.getAddrOfFieldName(name);
B.addRelativeAddress(fieldName);
} else {
@@ -701,6 +697,27 @@
}
}
+ void addField(Field field) {
+ reflection::FieldRecordFlags flags;
+ bool isLet = false;
+
+ switch (field.getKind()) {
+ case Field::Var: {
+ auto var = field.getVarDecl();
+ isLet = var->isLet();
+ break;
+ }
+ case Field::MissingMember:
+ llvm_unreachable("emitting reflection for type with missing member");
+ case Field::DefaultActorStorage:
+ flags.setIsArtificial();
+ break;
+ }
+ flags.setIsVar(!isLet);
+
+ addField(flags, field.getInterfaceType(IGM), field.getName());
+ }
+
void layoutRecord() {
auto kind = FieldDescriptorKind::Struct;
@@ -716,10 +733,20 @@
B.addInt16(uint16_t(kind));
B.addInt16(FieldRecordSize);
- auto properties = NTD->getStoredProperties();
- B.addInt32(properties.size());
- for (auto property : properties)
- addFieldDecl(property, property->getInterfaceType());
+ B.addInt32(getNumFields(NTD));
+ forEachField(IGM, NTD, [&](Field field) {
+ addField(field);
+ });
+ }
+
+ void addField(const EnumDecl *enumDecl, const EnumElementDecl *decl,
+ bool hasPayload) {
+ reflection::FieldRecordFlags flags;
+ if (hasPayload && (decl->isIndirect() || enumDecl->isIndirect()))
+ flags.setIsIndirectCase();
+
+ addField(flags, decl->getArgumentInterfaceType(),
+ decl->getBaseIdentifier().str());
}
void layoutEnum() {
@@ -741,14 +768,11 @@
+ strategy.getElementsWithNoPayload().size());
for (auto enumCase : strategy.getElementsWithPayload()) {
- bool indirect = (enumCase.decl->isIndirect() ||
- enumDecl->isIndirect());
- addFieldDecl(enumCase.decl, enumCase.decl->getArgumentInterfaceType(),
- indirect);
+ addField(enumDecl, enumCase.decl, /*has payload*/ true);
}
for (auto enumCase : strategy.getElementsWithNoPayload()) {
- addFieldDecl(enumCase.decl, enumCase.decl->getArgumentInterfaceType());
+ addField(enumDecl, enumCase.decl, /*has payload*/ false);
}
}
diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp
index 9177e36..3ad9e0d 100644
--- a/lib/IRGen/GenType.cpp
+++ b/lib/IRGen/GenType.cpp
@@ -2090,6 +2090,20 @@
align = IGM.getCappedAlignment(align);
return createPrimitive(llvmTy, size, align);
}
+ case TypeKind::BuiltinDefaultActorStorage: {
+ // Builtin.DefaultActorStorage represents the extra storage
+ // (beyond the heap header) of a default actor class. It is
+ // fixed-size and totally opaque.
+ auto numWords = NumWords_DefaultActor;
+
+ auto ty = llvm::StructType::create(IGM.getLLVMContext(),
+ llvm::ArrayType::get(IGM.Int8PtrTy, numWords),
+ "swift.defaultactor");
+ auto size = IGM.getPointerSize() * numWords;
+ auto align = Alignment(2 * IGM.getPointerAlignment().getValue());
+ auto spareBits = SpareBitVector::getConstant(size.getValueInBits(), false);
+ return new PrimitiveTypeInfo(ty, size, std::move(spareBits), align);
+ }
case TypeKind::PrimaryArchetype:
case TypeKind::OpenedArchetype:
diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp
index d820482..1deabde 100644
--- a/lib/IRGen/IRGenDebugInfo.cpp
+++ b/lib/IRGen/IRGenDebugInfo.cpp
@@ -1633,6 +1633,7 @@
case TypeKind::SILBox:
case TypeKind::SILToken:
case TypeKind::BuiltinUnsafeValueBuffer:
+ case TypeKind::BuiltinDefaultActorStorage:
LLVM_DEBUG(llvm::dbgs() << "Unhandled type: ";
DbgTy.getType()->dump(llvm::dbgs()); llvm::dbgs() << "\n");
diff --git a/lib/IRGen/MetadataLayout.cpp b/lib/IRGen/MetadataLayout.cpp
index 5ea2eb6..d136f11 100644
--- a/lib/IRGen/MetadataLayout.cpp
+++ b/lib/IRGen/MetadataLayout.cpp
@@ -267,6 +267,8 @@
ClassMetadataLayout &Layout;
+ bool IsInTargetFields = false;
+
Scanner(IRGenModule &IGM, ClassDecl *decl, ClassMetadataLayout &layout)
: super(IGM, decl), Layout(layout) {}
@@ -347,19 +349,37 @@
}
void noteStartOfFieldOffsets(ClassDecl *forClass) {
- if (forClass == Target)
+ if (forClass == Target) {
+ assert(!IsInTargetFields);
+ IsInTargetFields = true;
Layout.FieldOffsetVector = getNextOffset();
+ }
super::noteStartOfFieldOffsets(forClass);
}
+ void noteEndOfFieldOffsets(ClassDecl *forClass) {
+ assert(IsInTargetFields == (forClass == Target));
+ if (IsInTargetFields)
+ IsInTargetFields = false;
+ super::noteEndOfFieldOffsets(forClass);
+ }
+
void addFieldOffset(VarDecl *field) {
- if (field->getDeclContext() == Target) {
+ assert(IsInTargetFields == (field->getDeclContext() == Target));
+ if (IsInTargetFields) {
++Layout.NumImmediateMembers;
Layout.FieldOffsets.try_emplace(field, getNextOffset());
}
super::addFieldOffset(field);
}
+ void addDefaultActorStorageFieldOffset() {
+ if (IsInTargetFields) {
+ ++Layout.NumImmediateMembers;
+ }
+ super::addDefaultActorStorageFieldOffset();
+ }
+
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
if (placeholder->getDeclContext() == Target) {
Layout.NumImmediateMembers +=
diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp
index 9620ea0..26f7311 100644
--- a/lib/IRGen/MetadataRequest.cpp
+++ b/lib/IRGen/MetadataRequest.cpp
@@ -1714,10 +1714,16 @@
llvm_unreachable("error type should not appear in IRGen");
}
- MetadataResponse visitSILBlockStorageType(CanSILBlockStorageType type,
- DynamicMetadataRequest request) {
- llvm_unreachable("cannot ask for metadata of block storage");
+ // These types are artificial types used for for internal purposes and
+ // should never appear in a metadata request.
+#define INTERNAL_ONLY_TYPE(ID) \
+ MetadataResponse visit##ID##Type(Can##ID##Type type, \
+ DynamicMetadataRequest request) { \
+ llvm_unreachable("cannot ask for metadata of compiler-internal type"); \
}
+ INTERNAL_ONLY_TYPE(SILBlockStorage)
+ INTERNAL_ONLY_TYPE(BuiltinDefaultActorStorage)
+#undef INTERNAL_ONLY_TYPE
MetadataResponse visitSILBoxType(CanSILBoxType type,
DynamicMetadataRequest request) {
diff --git a/lib/IRGen/StructLayout.cpp b/lib/IRGen/StructLayout.cpp
index 0e83305..2f6bc93 100644
--- a/lib/IRGen/StructLayout.cpp
+++ b/lib/IRGen/StructLayout.cpp
@@ -22,6 +22,7 @@
#include "swift/ABI/MetadataValues.h"
#include "BitPatternBuilder.h"
+#include "Field.h"
#include "FixedTypeInfo.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
@@ -200,7 +201,7 @@
headerSize = CurSize;
}
-void StructLayoutBuilder::addDefaultActorHeader() {
+void StructLayoutBuilder::addDefaultActorHeader(ElementLayout &elt) {
assert(StructFields.size() == 1 &&
StructFields[0] == IGM.RefCountedStructTy &&
"adding default actor header at wrong offset");
@@ -215,12 +216,18 @@
// get internal padding.
assert(CurSize.isMultipleOf(IGM.getPointerSize()));
assert(align >= CurAlignment);
+ assert(CurSize == getDefaultActorStorageFieldOffset(IGM));
+ elt.completeFixed(IsNotPOD, CurSize, /*struct index*/ 1);
CurSize += size;
CurAlignment = align;
StructFields.push_back(ty);
headerSize = CurSize;
}
+Size irgen::getDefaultActorStorageFieldOffset(IRGenModule &IGM) {
+ return IGM.RefCountedStructSize;
+}
+
bool StructLayoutBuilder::addFields(llvm::MutableArrayRef<ElementLayout> elts,
LayoutStrategy strategy) {
// Track whether we've added any storage to our layout.
@@ -398,3 +405,68 @@
}
return spareBits.build();
}
+
+unsigned irgen::getNumFields(const NominalTypeDecl *target) {
+ auto numFields =
+ target->getStoredPropertiesAndMissingMemberPlaceholders().size();
+ if (auto cls = dyn_cast<ClassDecl>(target)) {
+ if (cls->isRootDefaultActor())
+ numFields++;
+ }
+ return numFields;
+}
+
+void irgen::forEachField(IRGenModule &IGM, const NominalTypeDecl *typeDecl,
+ llvm::function_ref<void(Field field)> fn) {
+ auto classDecl = dyn_cast<ClassDecl>(typeDecl);
+ if (classDecl && classDecl->isRootDefaultActor()) {
+ fn(Field::DefaultActorStorage);
+ }
+
+ for (auto decl :
+ typeDecl->getStoredPropertiesAndMissingMemberPlaceholders()) {
+ if (auto var = dyn_cast<VarDecl>(decl)) {
+ fn(var);
+ } else {
+ fn(cast<MissingMemberDecl>(decl));
+ }
+ }
+}
+
+SILType Field::getType(IRGenModule &IGM, SILType baseType) const {
+ switch (getKind()) {
+ case Field::Var:
+ return baseType.getFieldType(getVarDecl(), IGM.getSILModule(),
+ TypeExpansionContext::minimal());
+ case Field::MissingMember:
+ llvm_unreachable("cannot ask for type of missing member");
+ case Field::DefaultActorStorage:
+ return SILType::getPrimitiveObjectType(
+ IGM.Context.TheDefaultActorStorageType);
+ }
+ llvm_unreachable("bad field kind");
+}
+
+Type Field::getInterfaceType(IRGenModule &IGM) const {
+ switch (getKind()) {
+ case Field::Var:
+ return getVarDecl()->getInterfaceType();
+ case Field::MissingMember:
+ llvm_unreachable("cannot ask for type of missing member");
+ case Field::DefaultActorStorage:
+ return IGM.Context.TheDefaultActorStorageType;
+ }
+ llvm_unreachable("bad field kind");
+}
+
+StringRef Field::getName() const {
+ switch (getKind()) {
+ case Field::Var:
+ return getVarDecl()->getName().str();
+ case Field::MissingMember:
+ llvm_unreachable("cannot ask for type of missing member");
+ case Field::DefaultActorStorage:
+ return DEFAULT_ACTOR_STORAGE_FIELD_NAME;
+ }
+ llvm_unreachable("bad field kind");
+}
diff --git a/lib/IRGen/StructLayout.h b/lib/IRGen/StructLayout.h
index 7d5ab54..d91d658 100644
--- a/lib/IRGen/StructLayout.h
+++ b/lib/IRGen/StructLayout.h
@@ -297,7 +297,7 @@
void addNSObjectHeader();
/// Add the default-actor header to the layout. This must be the second
/// thing added to the layout, following the Swift heap header.
- void addDefaultActorHeader();
+ void addDefaultActorHeader(ElementLayout &elt);
/// Add a number of fields to the layout. The field layouts need
/// only have the TypeInfo set; the rest will be filled out.
@@ -458,6 +458,8 @@
const llvm::Twine &name = "") const;
};
+Size getDefaultActorStorageFieldOffset(IRGenModule &IGM);
+
} // end namespace irgen
} // end namespace swift
diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp
index ff6b658..58203c0 100644
--- a/lib/SIL/IR/TypeLowering.cpp
+++ b/lib/SIL/IR/TypeLowering.cpp
@@ -265,6 +265,15 @@
isSensitive});
}
+ RetTy visitBuiltinDefaultActorStorageType(
+ CanBuiltinDefaultActorStorageType type,
+ AbstractionPattern origType,
+ IsTypeExpansionSensitive_t isSensitive) {
+ return asImpl().handleAddressOnly(type, {IsNotTrivial, IsFixedABI,
+ IsAddressOnly, IsNotResilient,
+ isSensitive});
+ }
+
RetTy visitAnyFunctionType(CanAnyFunctionType type,
AbstractionPattern origType,
IsTypeExpansionSensitive_t isSensitive) {
diff --git a/lib/SILGen/SILGenPattern.cpp b/lib/SILGen/SILGenPattern.cpp
index 954ccad..3fbae1f 100644
--- a/lib/SILGen/SILGenPattern.cpp
+++ b/lib/SILGen/SILGenPattern.cpp
@@ -1398,6 +1398,25 @@
llvm_unreachable("covered switch");
}
+/// Given that we've broken down a source value into this subobject,
+/// and that we were supposed to use the given consumption rules on
+/// it, construct an appropriate managed value.
+static ConsumableManagedValue
+getManagedSubobject(SILGenFunction &SGF, ManagedValue value,
+ CastConsumptionKind consumption) {
+ switch (consumption) {
+ case CastConsumptionKind::BorrowAlways:
+ case CastConsumptionKind::CopyOnSuccess:
+ return {value.unmanagedBorrow(), consumption};
+ case CastConsumptionKind::TakeAlways:
+ case CastConsumptionKind::TakeOnSuccess: {
+ auto loc = RegularLocation::getAutoGeneratedLocation();
+ return {value.ensurePlusOne(SGF, loc), consumption};
+ }
+ }
+ llvm_unreachable("covered switch");
+}
+
static ConsumableManagedValue
emitReabstractedSubobject(SILGenFunction &SGF, SILLocation loc,
ConsumableManagedValue value,
@@ -2064,29 +2083,34 @@
}
// Emit the switch_enum_addr instruction.
- SILValue srcValue = src.getFinalManagedValue().forward(SGF);
- SGF.B.createSwitchEnumAddr(loc, srcValue, blocks.getDefaultBlock(),
+ //
+ // NOTE: switch_enum_addr does not actually consume the underlying value.
+ SGF.B.createSwitchEnumAddr(loc, src.getValue(), blocks.getDefaultBlock(),
blocks.getCaseBlocks(), blocks.getCounts(),
defaultCaseCount);
// Okay, now emit all the cases.
- blocks.forEachCase([&](EnumElementDecl *elt, SILBasicBlock *caseBB,
+ blocks.forEachCase([&](EnumElementDecl *eltDecl, SILBasicBlock *caseBB,
const CaseInfo &caseInfo) {
SILLocation loc = caseInfo.FirstMatcher;
auto &specializedRows = caseInfo.SpecializedRows;
SGF.B.setInsertionPoint(caseBB);
+ // We need to make sure our cleanup stays around long enough for us to emit
+ // our destroy, so setup a cleanup state restoration scope for each case.
+ CleanupStateRestorationScope srcScope(SGF.Cleanups);
+ forwardIntoIrrefutableSubtree(SGF, srcScope, src);
+
// We're in conditionally-executed code; enter a scope.
Scope scope(SGF.Cleanups, CleanupLocation::get(loc));
-
+
// Create a BB argument or 'unchecked_take_enum_data_addr'
// instruction to receive the enum case data if it has any.
-
SILType eltTy;
bool hasElt = false;
- if (elt->hasAssociatedValues()) {
- eltTy = src.getType().getEnumElementType(elt, SGF.SGM.M,
+ if (eltDecl->hasAssociatedValues()) {
+ eltTy = src.getType().getEnumElementType(eltDecl, SGF.SGM.M,
SGF.getTypeExpansionContext());
hasElt = !eltTy.getASTType()->isVoid();
}
@@ -2108,6 +2132,15 @@
}
}
+ // Forward src along this path so we don't emit a destroy_addr on our
+ // subject value for this case.
+ //
+ // FIXME: Do we actually want to do this? SILGen tests today assume this
+ // pattern. It might be worth leaving the destroy_addr there to create
+ // additional liveness information. For now though, we maintain the
+ // current behavior.
+ src.getFinalManagedValue().forward(SGF);
+
SILValue result;
if (hasNonAny) {
result = SGF.emitEmptyTuple(loc);
@@ -2132,16 +2165,18 @@
eltConsumption = CastConsumptionKind::TakeAlways;
}
- SILValue eltValue;
+ ManagedValue eltValue;
// We can only project destructively from an address-only enum, so
// copy the value if we can't consume it.
// TODO: Should have a more efficient way to copy payload
// nondestructively from an enum.
switch (eltConsumption) {
- case CastConsumptionKind::TakeAlways:
- eltValue =
- SGF.B.createUncheckedTakeEnumDataAddr(loc, srcValue, elt, eltTy);
+ case CastConsumptionKind::TakeAlways: {
+ auto finalValue = src.getFinalManagedValue();
+ eltValue = SGF.B.createUncheckedTakeEnumDataAddr(loc, finalValue,
+ eltDecl, eltTy);
break;
+ }
case CastConsumptionKind::BorrowAlways:
// If we reach this point, we know that we have a loadable
// element type from an enum with mixed address
@@ -2150,11 +2185,15 @@
// address only types do not support BorrowAlways.
llvm_unreachable("not allowed");
case CastConsumptionKind::CopyOnSuccess: {
- auto copy = SGF.emitTemporaryAllocation(loc, srcValue->getType());
- SGF.B.createCopyAddr(loc, srcValue, copy, IsNotTake, IsInitialization);
+ auto temp = SGF.emitTemporary(loc, SGF.getTypeLowering(src.getType()));
+ SGF.B.createCopyAddr(loc, src.getValue(), temp->getAddress(), IsNotTake,
+ IsInitialization);
+ temp->finishInitialization(SGF);
+
// We can always take from the copy.
eltConsumption = CastConsumptionKind::TakeAlways;
- eltValue = SGF.B.createUncheckedTakeEnumDataAddr(loc, copy, elt, eltTy);
+ eltValue = SGF.B.createUncheckedTakeEnumDataAddr(
+ loc, temp->getManagedAddress(), eltDecl, eltTy);
break;
}
@@ -2168,25 +2207,24 @@
// the value. This invariant makes it easy to specialize code for
// ownership.
if (eltTL->isLoadable()) {
- // If we do not have a loadable value, just use getManagedSubObject
+ // If we do not have a loadable value, just use getManagedSubobject
// Load a loadable data value.
- auto managedEltValue = ManagedValue::forUnmanaged(eltValue);
if (eltConsumption == CastConsumptionKind::CopyOnSuccess) {
- managedEltValue = SGF.B.createLoadBorrow(loc, managedEltValue);
+ eltValue = SGF.B.createLoadBorrow(loc, eltValue);
eltConsumption = CastConsumptionKind::BorrowAlways;
} else {
assert(eltConsumption == CastConsumptionKind::TakeAlways);
- managedEltValue = SGF.B.createLoadTake(loc, managedEltValue);
+ eltValue = SGF.B.createLoadTake(loc, eltValue);
}
- origCMV = {managedEltValue, eltConsumption};
+ origCMV = {eltValue, eltConsumption};
} else {
- origCMV = getManagedSubobject(SGF, eltValue, *eltTL, eltConsumption);
+ origCMV = getManagedSubobject(SGF, eltValue, eltConsumption);
}
eltCMV = origCMV;
// If the payload is boxed, project it.
- if (elt->isIndirect() || elt->getParentEnum()->isIndirect()) {
+ if (eltDecl->isIndirect() || eltDecl->getParentEnum()->isIndirect()) {
ManagedValue boxedValue =
SGF.B.createProjectBox(loc, origCMV.getFinalManagedValue(), 0);
eltTL = &SGF.getTypeLowering(boxedValue.getType());
@@ -2202,14 +2240,14 @@
// Reabstract to the substituted type, if needed.
CanType substEltTy =
- sourceType->getTypeOfMember(SGF.SGM.M.getSwiftModule(), elt,
- elt->getArgumentInterfaceType())
+ sourceType->getTypeOfMember(SGF.SGM.M.getSwiftModule(), eltDecl,
+ eltDecl->getArgumentInterfaceType())
->getCanonicalType();
AbstractionPattern origEltTy =
- (elt->getParentEnum()->isOptionalDecl()
+ (eltDecl->getParentEnum()->isOptionalDecl()
? AbstractionPattern(substEltTy)
- : SGF.SGM.M.Types.getAbstractionPattern(elt));
+ : SGF.SGM.M.Types.getAbstractionPattern(eltDecl));
eltCMV = emitReabstractedSubobject(SGF, loc, eltCMV, *eltTL,
origEltTy, substEltTy);
diff --git a/lib/Sema/TypeCheckEffects.cpp b/lib/Sema/TypeCheckEffects.cpp
index 37b8432..bdb83d5 100644
--- a/lib/Sema/TypeCheckEffects.cpp
+++ b/lib/Sema/TypeCheckEffects.cpp
@@ -1532,12 +1532,17 @@
Self.Flags.set(ContextFlags::IsTryCovered);
Self.Flags.clear(ContextFlags::HasTryThrowSite);
}
-
+
void enterAwait() {
Self.Flags.set(ContextFlags::IsAsyncCovered);
Self.Flags.clear(ContextFlags::HasAnyAsyncSite);
}
+ void enterAsyncLet() {
+ Self.Flags.set(ContextFlags::IsTryCovered);
+ Self.Flags.set(ContextFlags::IsAsyncCovered);
+ }
+
void refineLocalContext(Context newContext) {
Self.CurContext = newContext;
}
@@ -1602,7 +1607,7 @@
OldFlags.mergeFrom(ContextFlags::HasAnyAwait, Self.Flags);
OldMaxThrowingKind = std::max(OldMaxThrowingKind, Self.MaxThrowingKind);
}
-
+
bool wasTopLevelDebuggerFunction() const {
return OldFlags.has(ContextFlags::IsTopLevelDebuggerFunction);
}
@@ -1678,6 +1683,7 @@
case AutoClosureExpr::Kind::AsyncLet:
scope.resetCoverage();
+ scope.enterAsyncLet();
shouldPreserveCoverage = false;
break;
}
@@ -1817,10 +1823,11 @@
}
ShouldRecurse_t checkAsyncLet(PatternBindingDecl *patternBinding) {
- // Diagnose async calls in a context that doesn't handle async.
- if (!CurContext.handlesAsync()) {
- CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, patternBinding);
- }
+ // Diagnose async let in a context that doesn't handle async.
+ if (!CurContext.handlesAsync()) {
+ CurContext.diagnoseUnhandledAsyncSite(Ctx.Diags, patternBinding);
+ }
+
return ShouldRecurse;
}
diff --git a/lib/Serialization/ModuleFileCoreTableInfo.h b/lib/Serialization/ModuleFileCoreTableInfo.h
index a2cc855..0ecc463 100644
--- a/lib/Serialization/ModuleFileCoreTableInfo.h
+++ b/lib/Serialization/ModuleFileCoreTableInfo.h
@@ -600,9 +600,9 @@
static data_type ReadData(internal_key_type key, const uint8_t *data,
unsigned length) {
using namespace llvm::support;
- auto str = std::string{reinterpret_cast<const char *>(data),
- Fingerprint::DIGEST_LENGTH};
- return Fingerprint{str};
+ auto str = llvm::StringRef{reinterpret_cast<const char *>(data),
+ Fingerprint::DIGEST_LENGTH};
+ return Fingerprint::fromString(str);
}
};
diff --git a/test/Concurrency/async_let_isolation.swift b/test/Concurrency/async_let_isolation.swift
index 006cff9..1028ec9 100644
--- a/test/Concurrency/async_let_isolation.swift
+++ b/test/Concurrency/async_let_isolation.swift
@@ -30,7 +30,7 @@
func outside() async {
let a = MyActor()
- async let x = a.synchronous() // expected-error {{call is 'async' in an 'async let' initializer that is not marked with 'await'}}
+ async let x = a.synchronous() // okay, await is implicit
async let y = await a.synchronous()
_ = await x
_ = await y
diff --git a/test/Driver/sanitize_recover.swift b/test/Driver/sanitize_recover.swift
index d35b209..ca7ca24 100644
--- a/test/Driver/sanitize_recover.swift
+++ b/test/Driver/sanitize_recover.swift
@@ -1,4 +1,3 @@
-// REQUIRES: 64784401
// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address -sanitize-recover=foo %s 2>&1 | %FileCheck -check-prefix=SAN_RECOVER_INVALID_ARG %s
// RUN: not %swiftc_driver -driver-print-jobs -sanitize=address -sanitize-recover=thread %s 2>&1 | %FileCheck -check-prefix=SAN_RECOVER_UNSUPPORTED_ARG %s
// RUN: %swiftc_driver -v -sanitize-recover=address %s -o %t 2>&1 | %FileCheck -check-prefix=SAN_RECOVER_MISSING_INSTRUMENTATION_OPTION %s
diff --git a/test/IRGen/actor_class.swift b/test/IRGen/actor_class.swift
index b72ab96..540d5b6 100644
--- a/test/IRGen/actor_class.swift
+++ b/test/IRGen/actor_class.swift
@@ -1,10 +1,11 @@
-// RUN: %target-swift-frontend -emit-ir %s -swift-version 5 -enable-experimental-concurrency | %target-FileCheck %s
+// RUN: %target-swift-frontend -emit-ir %s -swift-version 5 -enable-experimental-concurrency | %IRGenFileCheck %s
// REQUIRES: concurrency
// rdar_72047158
// XFAIL: CPU=arm64e
-// CHECK: %T11actor_class7MyClassC = type <{ %swift.refcounted, [10 x i8*], %TSi }>
+// CHECK: %T11actor_class7MyClassC = type <{ %swift.refcounted, %swift.defaultactor, %TSi }>
+// CHECK: %swift.defaultactor = type { [10 x i8*] }
// CHECK-objc-LABEL: @"$s11actor_class7MyClassCMm" = global
// CHECK-objc-SAME: %objc_class* @"OBJC_METACLASS_$__TtCs12_SwiftObject"
@@ -19,10 +20,23 @@
// CHECK-64-SAME: i32 104,
// CHECK-32-SAME: i32 52,
// Alignment mask
-// CHECK-SAME: i16 15,
+// CHECK-64-SAME: i16 15,
+// CHECK-32-SAME: i16 7,
// Field offset for 'x'
// CHECK-objc-SAME: [[INT]] {{48|96}},
+// Type descriptor.
+// CHECK-LABEL: @"$s11actor_class9ExchangerCMn" = {{.*}}constant
+// superclass ref, negative bounds, positive bounds, num immediate members, num fields, field offset vector offset
+// CHECK-SAME: i32 0, i32 2, i32 [[#CLASS_METADATA_HEADER+9]], i32 9, i32 2, i32 [[#CLASS_METADATA_HEADER+1]],
+
+// Reflection field records.
+// CHECK-LABEL: @"$s11actor_class9ExchangerCMF" = internal constant
+// Field descriptor kind, field size, num fields,
+// (artificial var, "BD", ...)
+// CHECK-SAME: i16 1, i16 12, i32 2, i32 6,
+// CHECK-SAME: @"symbolic BD"
+
public actor class MyClass {
public var x: Int
public init() { self.x = 0 }
@@ -36,7 +50,7 @@
// CHECK-LABEL: define {{.*}}@"$s11actor_class7MyClassC1xSivg"
// CHECK: [[T0:%.*]] = getelementptr inbounds %T11actor_class7MyClassC, %T11actor_class7MyClassC* %0, i32 0, i32 2
// CHECK: [[T1:%.*]] = getelementptr inbounds %TSi, %TSi* [[T0]], i32 0, i32 0
-// CHECK: load [[INT]], [[INT]]* [[T1]], align 16
+// CHECK: load [[INT]], [[INT]]* [[T1]], align
// CHECK-LABEL: define {{.*}}swiftcc %T11actor_class7MyClassC* @"$s11actor_class7MyClassCACycfc"
// CHECK: swift_defaultActor_initialize
@@ -45,3 +59,21 @@
// CHECK-LABEL: define {{.*}}swiftcc %swift.refcounted* @"$s11actor_class7MyClassCfd"
// CHECK: swift_defaultActor_destroy
// CHECK-LABEL: ret
+
+public actor class Exchanger<T> {
+ public var value: T
+
+ public init(value: T) { self.value = value }
+ public func exchange(newValue: T) -> T {
+ let oldValue = value
+ value = newValue
+ return oldValue
+ }
+}
+// CHECK-LABEL: define{{.*}} void @"$s11actor_class9ExchangerC5valuexvg"(
+// Note that this is one more than the field offset vector offset from
+// the class descriptor, since this is the second field.
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[INT]], [[INT]]* {{.*}}, [[INT]] [[#CLASS_METADATA_HEADER+2]]
+// CHECK-NEXT: [[OFFSET:%.*]] = load [[INT]], [[INT]]* [[T0]], align
+// CHECK-NEXT: [[T0:%.*]] = bitcast %T11actor_class9ExchangerC* %1 to i8*
+// CHECK-NEXT: getelementptr inbounds i8, i8* [[T0]], [[INT]] [[OFFSET]]
diff --git a/test/IRGen/actor_class_objc.swift b/test/IRGen/actor_class_objc.swift
index 5e5af0a..ed9a91e 100644
--- a/test/IRGen/actor_class_objc.swift
+++ b/test/IRGen/actor_class_objc.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -emit-ir %s -swift-version 5 -enable-experimental-concurrency | %target-FileCheck %s
+// RUN: %target-swift-frontend -emit-ir %s -swift-version 5 -enable-experimental-concurrency | %IRGenFileCheck %s
// REQUIRES: concurrency
// REQUIRES: objc_interop
@@ -7,7 +7,8 @@
import Foundation
-// CHECK: %T16actor_class_objc7MyClassC = type <{ %swift.refcounted, [10 x i8*], %TSi }>
+// CHECK: %T16actor_class_objc7MyClassC = type <{ %swift.refcounted, %swift.defaultactor, %TSi }>
+// CHECK: %swift.defaultactor = type { [10 x i8*] }
// CHECK-LABEL: @"OBJC_METACLASS_$__TtC16actor_class_objc7MyClass" = global
// Metaclass is an instance of the root class.
@@ -25,7 +26,8 @@
// CHECK-64-SAME: i32 104,
// CHECK-32-SAME: i32 52,
// Alignment mask
-// CHECK-SAME: i16 15,
+// CHECK-64-SAME: i16 15,
+// CHECK-32-SAME: i16 7,
// Field offset for 'x'
// CHECK-64-SAME: i64 96,
// CHECK-32-SAME: i32 48,
@@ -42,7 +44,7 @@
// CHECK-LABEL: define {{.*}} @"$s16actor_class_objc7MyClassC1xSivg"
// CHECK: [[T0:%.*]] = getelementptr inbounds %T16actor_class_objc7MyClassC, %T16actor_class_objc7MyClassC* %0, i32 0, i32 2
// CHECK: [[T1:%.*]] = getelementptr inbounds %TSi, %TSi* [[T0]], i32 0, i32 0
-// CHECK: load [[INT]], [[INT]]* [[T1]], align 16
+// CHECK: load [[INT]], [[INT]]* [[T1]], align
// CHECK-LABEL: define {{.*}}swiftcc %T16actor_class_objc7MyClassC* @"$s16actor_class_objc7MyClassCACycfc"
// CHECK: swift_defaultActor_initialize
diff --git a/test/Interpreter/switch_default.swift b/test/Interpreter/switch_default.swift
new file mode 100644
index 0000000..5880578
--- /dev/null
+++ b/test/Interpreter/switch_default.swift
@@ -0,0 +1,28 @@
+// RUN: %target-run-simple-swift
+
+// REQUIRES: executable_test
+
+import StdlibUnittest
+
+var SwitchDefaultTestSuite = TestSuite("Switch.Default")
+defer { runAllTests() }
+
+class Klass {}
+protocol Protocol {}
+
+enum Enum {
+ case value1(LifetimeTracked)
+ case value2(Protocol)
+}
+
+SwitchDefaultTestSuite.test("do not leak default case payload") {
+ // We are passing in Enum.value1 so we go down the default and leak our
+ // lifetime tracked.
+ func f(_ e: Enum?) {
+ switch (e) {
+ case .value2: return
+ default: return
+ }
+ }
+ f(.value1(LifetimeTracked(0)))
+}
diff --git a/test/SILGen/switch_default.swift b/test/SILGen/switch_default.swift
new file mode 100644
index 0000000..ace48b6
--- /dev/null
+++ b/test/SILGen/switch_default.swift
@@ -0,0 +1,54 @@
+// RUN: %target-swift-emit-silgen -module-name switch_default %s | %FileCheck %s
+
+class Klass {}
+protocol Protocol {}
+
+enum Enum {
+ case value1(Klass)
+ case value2(Protocol)
+}
+
+// CHECK-LABEL: sil hidden [ossa] @$s14switch_default33testAddressOnlySubjectDefaultCaseyyAA4EnumOSgF : $@convention(thin) (@in_guaranteed Optional<Enum>) -> () {
+// CHECK: bb0([[ARG:%.*]] :
+// CHECK: [[STACK:%.*]] = alloc_stack $Optional<Enum>
+// CHECK: copy_addr [[ARG]] to [initialization] [[STACK]]
+// CHECK: switch_enum_addr [[STACK]] : $*Optional<Enum>, case #Optional.some!enumelt: [[SOME_BB:bb[0-9]*]], default [[DEFAULT_BB:bb[0-9]*]]
+//
+// CHECK: [[SOME_BB]]:
+// CHECK: [[STACK_1:%.*]] = alloc_stack $Optional<Enum>
+// CHECK: copy_addr [[STACK]] to [initialization] [[STACK_1]]
+// CHECK: [[TAKEN_ADDR:%.*]] = unchecked_take_enum_data_addr [[STACK_1]]
+// CHECK: switch_enum_addr [[TAKEN_ADDR]] : $*Enum, case #Enum.value2!enumelt: [[VALUE2_BB:bb[0-9]*]], default [[DEFAULT_BB_2:bb[0-9]*]]
+//
+// CHECK: [[VALUE2_BB]]:
+// CHECK: [[TAKEN_TAKEN_ADDR:%.*]] = unchecked_take_enum_data_addr [[TAKEN_ADDR]]
+// CHECK: destroy_addr [[TAKEN_TAKEN_ADDR]]
+// CHECK: dealloc_stack [[STACK_1]]
+// CHECK: destroy_addr [[STACK]]
+// CHECK: dealloc_stack [[STACK]]
+// CHECK: br [[EXIT_BB:bb[0-9]+]]
+//
+// We used to leak here!
+// CHECK: [[DEFAULT_BB_2]]:
+// CHECK: destroy_addr [[TAKEN_ADDR]]
+// CHECK: dealloc_stack [[STACK_1]]
+// CHECK: br [[CONT_BB:bb[0-9]*]]
+//
+// CHECK: [[DEFAULT_BB]]:
+// CHECK: br [[CONT_BB]]
+//
+// CHECK: [[CONT_BB]]:
+// CHECK: destroy_addr [[STACK]]
+// CHECK: dealloc_stack [[STACK]]
+// CHECK: br [[EXIT_BB]]
+//
+// CHECK: [[EXIT_BB]]:
+// CHECK-NEXT: tuple
+// CHECK-NEXT: return
+// } // end sil function '$s14switch_default33testAddressOnlySubjectDefaultCaseyyAA4EnumOSgF'
+func testAddressOnlySubjectDefaultCase(_ e: Enum?) {
+ switch (e) {
+ case .value2: return
+ default: return
+ }
+}
diff --git a/test/expr/unary/async_await.swift b/test/expr/unary/async_await.swift
index 812e3df..b2fa40d 100644
--- a/test/expr/unary/async_await.swift
+++ b/test/expr/unary/async_await.swift
@@ -165,12 +165,9 @@
} catch {
}
- async let x1 = getIntUnsafely() // expected-error{{call can throw but is not marked with 'try'}}
- // expected-note@-1{{did you mean to use 'try'}}
- // expected-note@-2{{did you mean to handle error as optional value?}}
- // expected-note@-3{{did you mean to disable error propagation?}}
+ async let x1 = getIntUnsafely() // okay, try is implicit here
- async let x2 = getInt() // expected-error{{call is 'async' in an 'async let' initializer that is not marked with 'await'}}
+ async let x2 = getInt() // okay, await is implicit here
async let x3 = try getIntUnsafely()
async let x4 = try! getIntUnsafely()
diff --git a/test/lit.cfg b/test/lit.cfg
index 49fdf74..7c7951a 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -2146,9 +2146,18 @@
config.substitutions.append( ('%diff', 'diff') )
config.substitutions.append( ('%long-tmp', '%t') )
+# Compute the size of the Swift class metadata header in words.
+run_class_metadata_header_size = 2
+if run_objc_interop == 'objc':
+ run_class_metadata_header_size = 5
+if run_ptrsize == '64':
+ run_class_metadata_header_size = run_class_metadata_header_size + 5
+else:
+ run_class_metadata_header_size = run_class_metadata_header_size + 8
+
# A FileCheck that automatically supports a large variety of target
-# conditionalization.
-run_target_filecheck = '%s --check-prefix=CHECK --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s -DINT=i%s' % (
+# conditionalization that's useful in IRGen.
+IRGenFileCheck = '%s --check-prefix=CHECK --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s --check-prefix=CHECK-%s -DINT=i%s -D#CLASS_METADATA_HEADER=%s' % (
run_filecheck,
run_os,
run_cpu,
@@ -2156,8 +2165,9 @@
run_ptrsize,
run_ptrauth,
run_objc_interop,
- run_ptrsize)
-config.substitutions.append( ('%target-FileCheck', run_target_filecheck) )
+ run_ptrsize,
+ run_class_metadata_header_size)
+config.substitutions.append( ('%IRGenFileCheck', IRGenFileCheck) )
visual_studio_version = os.environ.get('VisualStudioVersion')
if kIsWindows and visual_studio_version:
diff --git a/tools/swift-dependency-tool/swift-dependency-tool.cpp b/tools/swift-dependency-tool/swift-dependency-tool.cpp
index 625ac60..d773eb2 100644
--- a/tools/swift-dependency-tool/swift-dependency-tool.cpp
+++ b/tools/swift-dependency-tool/swift-dependency-tool.cpp
@@ -69,7 +69,7 @@
os << fp.getRawValue();
}
static StringRef input(StringRef s, void *, swift::Fingerprint &fp) {
- fp = swift::Fingerprint{s.str()};
+ fp = swift::Fingerprint::fromString(s);
return StringRef();
}
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
diff --git a/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp b/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp
index b979db3..502e194 100644
--- a/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp
+++ b/unittests/Driver/MockingFineGrainedDependencyGraphs.cpp
@@ -45,7 +45,7 @@
assert(!swiftDeps.empty());
swiftDeps.resize(Fingerprint::DIGEST_LENGTH, 'X');
auto interfaceHash =
- interfaceHashIfNonEmpty.getValueOr(Fingerprint{swiftDeps});
+ interfaceHashIfNonEmpty.getValueOr(Fingerprint::fromString(swiftDeps));
SourceManager sm;
DiagnosticEngine diags(sm);
diff --git a/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp b/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp
index 27adf39..6352f7d 100644
--- a/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp
+++ b/unittests/Driver/UnitTestSourceFileDepGraphFactory.cpp
@@ -57,7 +57,7 @@
fingerprintString.resize(Fingerprint::DIGEST_LENGTH, 'X');
const Optional<Fingerprint> fingerprint = fingerprintString.empty()
? Optional<Fingerprint>()
- : Fingerprint{fingerprintString};
+ : Fingerprint::fromString(fingerprintString);
AbstractSourceFileDepGraphFactory::addADefinedDecl(key.getValue(),
fingerprint);