Merge pull request #11315 from itaiferber/fix-sr-5206-hack
Remove previous hack for SR-5206
diff --git a/include/swift/AST/RawComment.h b/include/swift/AST/RawComment.h
index b65981f..853ba45 100644
--- a/include/swift/AST/RawComment.h
+++ b/include/swift/AST/RawComment.h
@@ -67,6 +67,8 @@
bool isEmpty() const {
return Comments.empty();
}
+
+ CharSourceRange getCharSourceRange();
};
struct CommentInfo {
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 425ac06..e580cf0 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -297,6 +297,9 @@
/// Compare the symbols in the IR against the TBD file we would generate.
TBDValidationMode ValidateTBDAgainstIR = TBDValidationMode::None;
+ /// The install_name to use in the TBD file.
+ std::string TBDInstallName;
+
/// An enum with different modes for automatically crashing at defined times.
enum class DebugCrashMode {
None, ///< Don't automatically crash.
diff --git a/include/swift/IDE/SyntaxModel.h b/include/swift/IDE/SyntaxModel.h
index 7a3a077..ba6a780 100644
--- a/include/swift/IDE/SyntaxModel.h
+++ b/include/swift/IDE/SyntaxModel.h
@@ -137,6 +137,7 @@
CharSourceRange BodyRange;
CharSourceRange NameRange;
CharSourceRange TypeRange;
+ CharSourceRange DocRange;
std::vector<CharSourceRange> InheritedTypeRanges;
std::vector<SyntaxStructureElement> Elements;
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 8e9d1ba..1ad6a93 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -62,6 +62,13 @@
: Separate<["-"], "emit-fixits-path">, MetaVarName<"<path>">,
HelpText<"Output compiler fixits as source edits to <path>">;
+def tbd_install_name
+ : Separate<["-"], "tbd-install_name">, MetaVarName<"<path>">,
+ HelpText<"The install_name to use in an emitted TBD file">;
+
+def tbd_install_name_EQ : Joined<["-"], "tbd-install_name=">,
+ Alias<tbd_install_name>;
+
def verify : Flag<["-"], "verify">,
HelpText<"Verify diagnostics against expected-{error|warning|note} "
"annotations">;
diff --git a/include/swift/Runtime/Debug.h b/include/swift/Runtime/Debug.h
index 2939f41..26c02f9 100644
--- a/include/swift/Runtime/Debug.h
+++ b/include/swift/Runtime/Debug.h
@@ -124,6 +124,10 @@
LLVM_ATTRIBUTE_NORETURN LLVM_ATTRIBUTE_NOINLINE
void swift_abortRetainUnowned(const void *object);
+// Halt due to an overflow in swift_unownedRetain().
+LLVM_ATTRIBUTE_NORETURN LLVM_ATTRIBUTE_NOINLINE
+void swift_abortUnownedRetainOverflow();
+
/// This function dumps one line of a stack trace. It is assumed that \p framePC
/// is the address of the stack frame at index \p index. If \p shortOutput is
/// true, this functions prints only the name of the symbol and offset, ignores
diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def
index dfed9dd..794b628 100644
--- a/include/swift/SIL/SILNodes.def
+++ b/include/swift/SIL/SILNodes.def
@@ -287,7 +287,7 @@
// accross the cast (which reads the type metadata). With Semantic SIL we
// should be able to move this back to None - it should model the scoping
// and forbid the compiler from moving the ultimate retain.
- INST(UnconditionalCheckedCastValueInst, ConversionInst, unconditional_checked_cast_value, MayRead, DoesNotRelease)
+ INST(UnconditionalCheckedCastValueInst, ConversionInst, unconditional_checked_cast_value, MayRead, MayRelease)
INST(UnconditionalCheckedCastInst, ConversionInst, unconditional_checked_cast, MayRead, DoesNotRelease)
VALUE_RANGE(ConversionInst, UpcastInst, UnconditionalCheckedCastInst)
INST(IsNonnullInst, SILInstruction, is_nonnull, None, DoesNotRelease)
diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h
index 9dfa041..88b360c 100644
--- a/include/swift/TBDGen/TBDGen.h
+++ b/include/swift/TBDGen/TBDGen.h
@@ -12,14 +12,28 @@
#ifndef SWIFT_IRGEN_TBDGEN_H
#define SWIFT_IRGEN_TBDGEN_H
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
+namespace llvm {
+class raw_ostream;
+}
+
namespace swift {
class FileUnit;
+class ModuleDecl;
void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols,
- bool hasMultipleIRGenThreads, bool isWholeModule,
+ bool hasMultipleIRGenThreads,
bool silSerializeWitnessTables);
+void enumeratePublicSymbols(ModuleDecl *module, llvm::StringSet<> &symbols,
+ bool hasMultipleIRGenThreads,
+ bool silSerializeWitnessTables);
+
+void writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os,
+ bool hasMultipleIRGenThreads, bool silSerializeWitnessTables,
+ llvm::StringRef installName);
+
} // end namespace swift
#endif
diff --git a/lib/AST/RawComment.cpp b/lib/AST/RawComment.cpp
index 2925f81..a50bc7a 100644
--- a/lib/AST/RawComment.cpp
+++ b/lib/AST/RawComment.cpp
@@ -247,3 +247,18 @@
Context.setBriefComment(this, Result);
return Result;
}
+
+CharSourceRange RawComment::getCharSourceRange() {
+ if (this->isEmpty()) {
+ return CharSourceRange();
+ }
+
+ auto Start = this->Comments.front().Range.getStart();
+ if (Start.isInvalid()) {
+ return CharSourceRange();
+ }
+ auto End = this->Comments.back().Range.getEnd();
+ auto Length = (char *)End.getOpaquePointerValue() -
+ (char* )Start.getOpaquePointerValue();
+ return CharSourceRange(Start, Length);
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 6d048ce..dc5dbf8 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -211,6 +211,10 @@
}
}
+ if (const Arg *A = Args.getLastArg(OPT_tbd_install_name)) {
+ Opts.TBDInstallName = A->getValue();
+ }
+
if (const Arg *A = Args.getLastArg(OPT_warn_long_function_bodies)) {
unsigned attempt;
if (StringRef(A->getValue()).getAsInteger(10, attempt)) {
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index 882b8ab..d2c3817 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -3,7 +3,8 @@
ImportedModules.cpp
ReferenceDependencies.cpp
TBD.cpp
- DEPENDS SwiftOptions
+ DEPENDS
+ swift-syntax-generated-headers SwiftOptions
LINK_LIBRARIES
swiftIndex
swiftIDE
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 564f28a..fab5b51 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -745,8 +745,12 @@
if (!opts.TBDPath.empty()) {
const auto &silOpts = Invocation.getSILOptions();
auto hasMultipleIRGenThreads = silOpts.NumThreads > 1;
+ auto installName = opts.TBDInstallName.empty()
+ ? "lib" + Invocation.getModuleName().str() + ".dylib"
+ : opts.TBDInstallName;
+
if (writeTBD(Instance.getMainModule(), hasMultipleIRGenThreads,
- silOpts.SILSerializeWitnessTables, opts.TBDPath))
+ silOpts.SILSerializeWitnessTables, opts.TBDPath, installName))
return true;
}
diff --git a/lib/FrontendTool/TBD.cpp b/lib/FrontendTool/TBD.cpp
index 1b841d7..421bbec 100644
--- a/lib/FrontendTool/TBD.cpp
+++ b/lib/FrontendTool/TBD.cpp
@@ -39,7 +39,8 @@
}
bool swift::writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads,
- bool silSerializeWitnessTables, StringRef OutputFilename) {
+ bool silSerializeWitnessTables, StringRef OutputFilename,
+ StringRef installName) {
std::error_code EC;
llvm::raw_fd_ostream OS(OutputFilename, EC, llvm::sys::fs::F_None);
if (EC) {
@@ -47,15 +48,9 @@
OutputFilename, EC.message());
return true;
}
- llvm::StringSet<> symbols;
- for (auto file : M->getFiles())
- enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
- /*isWholeModule=*/true, silSerializeWitnessTables);
- // Ensure the order is stable.
- for (auto &symbol : sortSymbols(symbols)) {
- OS << symbol << "\n";
- }
+ writeTBDFile(M, OS, hasMultipleIRGenThreads, silSerializeWitnessTables,
+ installName);
return false;
}
@@ -128,9 +123,8 @@
bool silSerializeWitnessTables,
bool diagnoseExtraSymbolsInTBD) {
llvm::StringSet<> symbols;
- for (auto file : M->getFiles())
- enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
- /*isWholeModule=*/true, silSerializeWitnessTables);
+ enumeratePublicSymbols(M, symbols, hasMultipleIRGenThreads,
+ silSerializeWitnessTables);
return validateSymbolSet(M->getASTContext().Diags, symbols, IRModule,
diagnoseExtraSymbolsInTBD);
@@ -142,7 +136,7 @@
bool diagnoseExtraSymbolsInTBD) {
llvm::StringSet<> symbols;
enumeratePublicSymbols(file, symbols, hasMultipleIRGenThreads,
- /*isWholeModule=*/false, silSerializeWitnessTables);
+ silSerializeWitnessTables);
return validateSymbolSet(file->getParentModule()->getASTContext().Diags,
symbols, IRModule, diagnoseExtraSymbolsInTBD);
diff --git a/lib/FrontendTool/TBD.h b/lib/FrontendTool/TBD.h
index 98b2c8b..80f959e 100644
--- a/lib/FrontendTool/TBD.h
+++ b/lib/FrontendTool/TBD.h
@@ -25,7 +25,8 @@
class FrontendOptions;
bool writeTBD(ModuleDecl *M, bool hasMultipleIRGenThreads,
- bool silSerializeWitnessTables, llvm::StringRef OutputFilename);
+ bool silSerializeWitnessTables, llvm::StringRef OutputFilename,
+ llvm::StringRef installName);
bool inputFileKindCanHaveTBDValidated(InputFileKind kind);
bool validateTBD(ModuleDecl *M, llvm::Module &IRModule,
bool hasMultipleIRGenThreads, bool silSerializeWitnessTables,
diff --git a/lib/IDE/CodeCompletion.cpp b/lib/IDE/CodeCompletion.cpp
index a8afe18..a40e872 100644
--- a/lib/IDE/CodeCompletion.cpp
+++ b/lib/IDE/CodeCompletion.cpp
@@ -4967,6 +4967,9 @@
case StmtKind::Return:
case StmtKind::ForEach:
case StmtKind::RepeatWhile:
+ case StmtKind::If:
+ case StmtKind::While:
+ case StmtKind::Guard:
return true;
default:
return false;
@@ -5014,35 +5017,51 @@
}
}
- void analyzeStmt(Stmt *Parent, llvm::function_ref<void(Type)> Callback) {
- switch (Parent->getKind()) {
- case StmtKind::Return: {
- Callback(getReturnTypeFromContext(DC));
- break;
- }
- case StmtKind::ForEach: {
- auto FES = cast<ForEachStmt>(Parent);
- if (auto SEQ = FES->getSequence()) {
- if (SM.rangeContains(SEQ->getSourceRange(),
- ParsedExpr->getSourceRange())) {
- Callback(Context.getSequenceDecl()->getDeclaredInterfaceType());
- }
- }
- break;
- }
- case StmtKind::RepeatWhile: {
- auto Cond = cast<RepeatWhileStmt>(Parent)->getCond();
- if (Cond &&
- SM.rangeContains(Cond->getSourceRange(),
- ParsedExpr->getSourceRange())) {
- Callback(Context.getBoolDecl()->getDeclaredType());
- }
- break;
- }
- default:
- llvm_unreachable("Unhandled statement kinds.");
- }
- }
+ void analyzeStmt(Stmt *Parent, llvm::function_ref<void(Type)> Callback) {
+ switch (Parent->getKind()) {
+ case StmtKind::Return:
+ Callback(getReturnTypeFromContext(DC));
+ break;
+ case StmtKind::ForEach:
+ if (auto SEQ = cast<ForEachStmt>(Parent)->getSequence()) {
+ if (containsTarget(SEQ)) {
+ Callback(Context.getSequenceDecl()->getDeclaredInterfaceType());
+ }
+ }
+ break;
+ case StmtKind::RepeatWhile:
+ case StmtKind::If:
+ case StmtKind::While:
+ case StmtKind::Guard:
+ if (isBoolConditionOf(Parent)) {
+ Callback(Context.getBoolDecl()->getDeclaredInterfaceType());
+ }
+ break;
+ default:
+ llvm_unreachable("Unhandled statement kinds.");
+ }
+ }
+
+ bool isBoolConditionOf(Stmt *parent) {
+ if (auto *repeat = dyn_cast<RepeatWhileStmt>(parent)) {
+ return repeat->getCond() && containsTarget(repeat->getCond());
+ }
+ if (auto *conditional = dyn_cast<LabeledConditionalStmt>(parent)) {
+ for (StmtConditionElement cond : conditional->getCond()) {
+ if (auto *E = cond.getBooleanOrNull()) {
+ if (containsTarget(E)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ bool containsTarget(Expr *E) {
+ assert(E && "expected parent expression");
+ return SM.rangeContains(E->getSourceRange(), ParsedExpr->getSourceRange());
+ }
void analyzeDecl(Decl *D, llvm::function_ref<void(Type)> Callback) {
switch (D->getKind()) {
@@ -5050,7 +5069,7 @@
auto PBD = cast<PatternBindingDecl>(D);
for (unsigned I = 0; I < PBD->getNumPatternEntries(); ++ I) {
if (auto Init = PBD->getInit(I)) {
- if (SM.rangeContains(Init->getSourceRange(), ParsedExpr->getLoc())) {
+ if (containsTarget(Init)) {
if (PBD->getPattern(I)->hasType()) {
Callback(PBD->getPattern(I)->getType());
break;
diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp
index c37129c..c692a68 100644
--- a/lib/IDE/SyntaxModel.cpp
+++ b/lib/IDE/SyntaxModel.cpp
@@ -418,6 +418,12 @@
return CharSourceRange();
}
+static void setDecl(SyntaxStructureNode &N, Decl *D) {
+ N.Dcl = D;
+ N.Attrs = D->getAttrs();
+ N.DocRange = D->getRawComment().getCharSourceRange();
+}
+
} // anonymous namespace
bool SyntaxModelContext::walk(SyntaxModelWalker &Walker) {
@@ -753,7 +759,7 @@
} else {
// Pass Function / Method structure node.
SyntaxStructureNode SN;
- SN.Dcl = D;
+ setDecl(SN, D);
const DeclContext *DC = AFD->getDeclContext();
if (DC->isTypeContext()) {
if (FD && FD->isStatic()) {
@@ -772,12 +778,11 @@
AFD->getBodySourceRange());
SN.NameRange = charSourceRangeFromSourceRange(SM,
AFD->getSignatureSourceRange());
- SN.Attrs = AFD->getAttrs();
pushStructureNode(SN, AFD);
}
} else if (auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
SyntaxStructureNode SN;
- SN.Dcl = D;
+ setDecl(SN, D);
SN.Kind = syntaxStructureKindFromNominalTypeDecl(NTD);
SN.Range = charSourceRangeFromSourceRange(SM, NTD->getSourceRange());
SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, NTD->getBraces());
@@ -792,12 +797,11 @@
SN.Elements.emplace_back(SyntaxStructureElementKind::TypeRef, TR);
}
- SN.Attrs = NTD->getAttrs();
pushStructureNode(SN, NTD);
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
SyntaxStructureNode SN;
- SN.Dcl = D;
+ setDecl(SN, D);
SN.Kind = SyntaxStructureKind::Extension;
SN.Range = charSourceRangeFromSourceRange(SM, ED->getSourceRange());
SN.BodyRange = innerCharSourceRangeFromSourceRange(SM, ED->getBraces());
@@ -811,7 +815,6 @@
SN.Elements.emplace_back(SyntaxStructureElementKind::TypeRef, TR);
}
- SN.Attrs = ED->getAttrs();
pushStructureNode(SN, ED);
} else if (auto *PD = dyn_cast<ParamDecl>(D)) {
@@ -832,7 +835,7 @@
const DeclContext *DC = VD->getDeclContext();
if (DC->isTypeContext() || DC->isModuleScopeContext()) {
SyntaxStructureNode SN;
- SN.Dcl = D;
+ setDecl(SN, D);
SourceRange SR;
if (auto *PBD = VD->getParentPatternBinding())
SR = PBD->getSourceRange();
@@ -863,7 +866,6 @@
} else {
SN.Kind = SyntaxStructureKind::GlobalVariable;
}
- SN.Attrs = VD->getAttrs();
pushStructureNode(SN, VD);
}
@@ -915,7 +917,7 @@
} else if (auto *EnumCaseD = dyn_cast<EnumCaseDecl>(D)) {
SyntaxStructureNode SN;
- SN.Dcl = D;
+ setDecl(SN, D);
SN.Kind = SyntaxStructureKind::EnumCase;
SN.Range = charSourceRangeFromSourceRange(SM, D->getSourceRange());
@@ -939,7 +941,7 @@
if (EnumElemD->getName().empty())
continue;
SyntaxStructureNode SN;
- SN.Dcl = EnumElemD;
+ setDecl(SN, EnumElemD);
SN.Kind = SyntaxStructureKind::EnumElement;
SN.Range = charSourceRangeFromSourceRange(SM,
EnumElemD->getSourceRange());
@@ -956,23 +958,21 @@
}
} else if (auto *TypeAliasD = dyn_cast<TypeAliasDecl>(D)) {
SyntaxStructureNode SN;
- SN.Dcl = TypeAliasD;
+ setDecl(SN, D);
SN.Kind = SyntaxStructureKind::TypeAlias;
SN.Range = charSourceRangeFromSourceRange(SM,
TypeAliasD->getSourceRange());
SN.NameRange = CharSourceRange(TypeAliasD->getNameLoc(),
TypeAliasD->getName().getLength());
- SN.Attrs = TypeAliasD->getAttrs();
pushStructureNode(SN, TypeAliasD);
} else if (auto *SubscriptD = dyn_cast<SubscriptDecl>(D)) {
SyntaxStructureNode SN;
- SN.Dcl = SubscriptD;
+ setDecl(SN, D);
SN.Kind = SyntaxStructureKind::Subscript;
SN.Range = charSourceRangeFromSourceRange(SM,
SubscriptD->getSourceRange());
SN.BodyRange = innerCharSourceRangeFromSourceRange(SM,
SubscriptD->getBracesRange());
- SN.Attrs = SubscriptD->getAttrs();
pushStructureNode(SN, SubscriptD);
}
diff --git a/lib/IRGen/CMakeLists.txt b/lib/IRGen/CMakeLists.txt
index 7db17b0..f3a9e54 100644
--- a/lib/IRGen/CMakeLists.txt
+++ b/lib/IRGen/CMakeLists.txt
@@ -40,6 +40,7 @@
Linking.cpp
LoadableByAddress.cpp
LocalTypeData.cpp
+ MetadataLayout.cpp
StructLayout.cpp
SwiftTargetInfo.cpp
TypeLayoutVerifier.cpp
diff --git a/lib/IRGen/ClassMetadataLayout.h b/lib/IRGen/ClassMetadataVisitor.h
similarity index 89%
rename from lib/IRGen/ClassMetadataLayout.h
rename to lib/IRGen/ClassMetadataVisitor.h
index 0ef5a63..7d70d2b 100644
--- a/lib/IRGen/ClassMetadataLayout.h
+++ b/lib/IRGen/ClassMetadataVisitor.h
@@ -1,4 +1,4 @@
-//===--- ClassMetadataLayout.h - CRTP for class metadata --------*- C++ -*-===//
+//===--- ClassMetadataVisitor.h - CRTP for class metadata -------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -10,17 +10,20 @@
//
//===----------------------------------------------------------------------===//
//
-// A CRTP helper class for class metadata.
+// A CRTP helper class for visiting all of the known fields in a class
+// metadata object.
//
//===----------------------------------------------------------------------===//
-#ifndef SWIFT_IRGEN_CLASSMETADATALAYOUT_H
-#define SWIFT_IRGEN_CLASSMETADATALAYOUT_H
+#ifndef SWIFT_IRGEN_CLASSMETADATAVISITOR_H
+#define SWIFT_IRGEN_CLASSMETADATAVISITOR_H
+#include "swift/AST/ASTContext.h"
+#include "swift/AST/SubstitutionMap.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILVTableVisitor.h"
#include "IRGen.h"
-#include "MetadataLayout.h"
+#include "NominalMetadataVisitor.h"
namespace swift {
namespace irgen {
@@ -29,10 +32,10 @@
/// A CRTP class for laying out class metadata. Note that this does
/// *not* handle the metadata template stuff.
-template <class Impl> class ClassMetadataLayout
- : public MetadataLayout<Impl>,
+template <class Impl> class ClassMetadataVisitor
+ : public NominalMetadataVisitor<Impl>,
public SILVTableVisitor<Impl> {
- typedef MetadataLayout<Impl> super;
+ typedef NominalMetadataVisitor<Impl> super;
protected:
using super::IGM;
@@ -41,7 +44,7 @@
/// The most-derived class.
ClassDecl *const Target;
- ClassMetadataLayout(IRGenModule &IGM, ClassDecl *target)
+ ClassMetadataVisitor(IRGenModule &IGM, ClassDecl *target)
: super(IGM), SILVTableVisitor<Impl>(IGM.getSILTypes()), Target(target) {}
public:
@@ -76,6 +79,14 @@
addClassMembers(Target, Target->getDeclaredTypeInContext());
}
+ /// Notes the beginning of the field offset vector for a particular ancestor
+ /// of a generic-layout class.
+ void noteStartOfFieldOffsets(ClassDecl *whichClass) {}
+
+ /// Notes the end of the field offset vector for a particular ancestor
+ /// of a generic-layout class.
+ void noteEndOfFieldOffsets(ClassDecl *whichClass) {}
+
private:
/// Add fields associated with the given class and its bases.
void addClassMembers(ClassDecl *theClass, Type type) {
@@ -127,25 +138,17 @@
asImpl().noteEndOfFieldOffsets(theClass);
}
- /// Notes the beginning of the field offset vector for a particular ancestor
- /// of a generic-layout class.
- void noteStartOfFieldOffsets(ClassDecl *whichClass) {}
-
- /// Notes the end of the field offset vector for a particular ancestor
- /// of a generic-layout class.
- void noteEndOfFieldOffsets(ClassDecl *whichClass) {}
-
private:
void addFieldEntries(VarDecl *field) {
asImpl().addFieldOffset(field);
}
};
-/// An "implementation" of ClassMetadataLayout that just scans through
+/// An "implementation" of ClassMetadataVisitor that just scans through
/// the metadata layout, maintaining the offset of the next field.
template <class Impl>
-class ClassMetadataScanner : public ClassMetadataLayout<Impl> {
- typedef ClassMetadataLayout<Impl> super;
+class ClassMetadataScanner : public ClassMetadataVisitor<Impl> {
+ typedef ClassMetadataVisitor<Impl> super;
protected:
Size NextOffset = Size(0);
diff --git a/lib/IRGen/EnumMetadataLayout.h b/lib/IRGen/EnumMetadataVisitor.h
similarity index 78%
rename from lib/IRGen/EnumMetadataLayout.h
rename to lib/IRGen/EnumMetadataVisitor.h
index f454e04..917c6ca 100644
--- a/lib/IRGen/EnumMetadataLayout.h
+++ b/lib/IRGen/EnumMetadataVisitor.h
@@ -1,4 +1,4 @@
-//===--- EnumMetadataLayout.h - CRTP for enum metadata ----------*- C++ -*-===//
+//===--- EnumMetadataVisitor.h - CRTP for enum metadata ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -10,14 +10,16 @@
//
//===----------------------------------------------------------------------===//
//
-// A CRTP class useful for laying out enum metadata.
+// A CRTP class useful for visiting all of the fields in an
+// enum metadata object.
//
//===----------------------------------------------------------------------===//
-#ifndef SWIFT_IRGEN_ENUMMETADATALAYOUT_H
-#define SWIFT_IRGEN_ENUMMETADATALAYOUT_H
+#ifndef SWIFT_IRGEN_ENUMMETADATAVISITOR_H
+#define SWIFT_IRGEN_ENUMMETADATAVISITOR_H
-#include "MetadataLayout.h"
+#include "NominalMetadataVisitor.h"
+#include "GenEnum.h"
namespace swift {
namespace irgen {
@@ -26,8 +28,9 @@
///
/// This produces an object corresponding to the EnumMetadata type.
/// It does not itself doing anything special for metadata templates.
-template <class Impl> class EnumMetadataLayout : public MetadataLayout<Impl> {
- typedef MetadataLayout<Impl> super;
+template <class Impl> class EnumMetadataVisitor
+ : public NominalMetadataVisitor<Impl> {
+ using super = NominalMetadataVisitor<Impl>;
protected:
using super::IGM;
@@ -36,7 +39,7 @@
/// The Enum.
EnumDecl *const Target;
- EnumMetadataLayout(IRGenModule &IGM, EnumDecl *target)
+ EnumMetadataVisitor(IRGenModule &IGM, EnumDecl *target)
: super(IGM), Target(target) {}
public:
@@ -64,12 +67,12 @@
}
};
-/// An "implementation" of EnumMetadataLayout that just scans through
+/// An "implementation" of EnumMetadataVisitor that just scans through
/// the metadata layout, maintaining the next index: the offset (in
/// pointer-sized chunks) into the metadata for the next field.
template <class Impl>
-class EnumMetadataScanner : public EnumMetadataLayout<Impl> {
- typedef EnumMetadataLayout<Impl> super;
+class EnumMetadataScanner : public EnumMetadataVisitor<Impl> {
+ typedef EnumMetadataVisitor<Impl> super;
protected:
Size NextOffset = Size(0);
diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp
index a250a8a..a6fce95 100644
--- a/lib/IRGen/GenClass.cpp
+++ b/lib/IRGen/GenClass.cpp
@@ -50,6 +50,7 @@
#include "GenHeap.h"
#include "HeapTypeInfo.h"
#include "MemberAccessStrategy.h"
+#include "MetadataLayout.h"
using namespace swift;
@@ -607,7 +608,7 @@
}
case FieldAccess::ConstantIndirect: {
- Size indirectOffset = getClassFieldOffset(IGM, baseClass, field);
+ Size indirectOffset = getClassFieldOffsetOffset(IGM, baseClass, field);
return MemberAccessStrategy::getIndirectFixed(indirectOffset,
MemberAccessStrategy::OffsetKind::Bytes_Word);
}
diff --git a/lib/IRGen/GenKeyPath.cpp b/lib/IRGen/GenKeyPath.cpp
index e82303a..ce51170 100644
--- a/lib/IRGen/GenKeyPath.cpp
+++ b/lib/IRGen/GenKeyPath.cpp
@@ -27,6 +27,7 @@
#include "IRGenDebugInfo.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
+#include "MetadataLayout.h"
#include "ProtocolInfo.h"
#include "StructLayout.h"
#include "llvm/ADT/SetVector.h"
@@ -406,7 +407,7 @@
// For a struct stored property, we may know the fixed offset of the field,
// or we may need to fetch it out of the type's metadata at instantiation
// time.
- if (loweredBaseTy.getStructOrBoundGenericStruct()) {
+ if (auto theStruct = loweredBaseTy.getStructOrBoundGenericStruct()) {
if (auto offset = emitPhysicalStructMemberFixedOffset(*this,
loweredBaseTy,
property)) {
@@ -414,15 +415,15 @@
addFixedOffset(/*struct*/ true, offset);
break;
}
-
+
// If the offset isn't fixed, try instead to get the field offset out
// of the type metadata at instantiation time.
- auto fieldOffset = emitPhysicalStructMemberOffsetOfFieldOffset(
- *this, loweredBaseTy, property);
+ auto &metadataLayout = getMetadataLayout(theStruct);
+ auto fieldOffset = metadataLayout.getStaticFieldOffset(property);
+
auto header = KeyPathComponentHeader::forStructComponentWithUnresolvedFieldOffset();
fields.addInt32(header.getData());
- fields.add(llvm::ConstantExpr::getTruncOrBitCast(fieldOffset,
- Int32Ty));
+ fields.addInt32(fieldOffset.getValue());
break;
}
@@ -460,8 +461,8 @@
KeyPathComponentHeader::forClassComponentWithUnresolvedFieldOffset();
fields.addInt32(header.getData());
auto fieldOffset =
- getClassFieldOffset(*this, loweredBaseTy.getClassOrBoundGenericClass(),
- property);
+ getClassFieldOffsetOffset(*this, loweredBaseTy.getClassOrBoundGenericClass(),
+ property);
fields.addInt32(fieldOffset.getValue());
break;
}
@@ -514,8 +515,12 @@
idKind = KeyPathComponentHeader::VTableOffset;
auto dc = declRef.getDecl()->getDeclContext();
if (isa<ClassDecl>(dc)) {
- auto index = getVirtualMethodIndex(*this, declRef);
- idValue = llvm::ConstantInt::get(SizeTy, index);
+ auto overridden = getSILTypes().getOverriddenVTableEntry(declRef);
+ auto declaringClass =
+ cast<ClassDecl>(overridden.getDecl()->getDeclContext());
+ auto &metadataLayout = getMetadataLayout(declaringClass);
+ auto offset = metadataLayout.getStaticMethodOffset(overridden);
+ idValue = llvm::ConstantInt::get(SizeTy, offset.getValue());
idResolved = true;
} else if (auto methodProto = dyn_cast<ProtocolDecl>(dc)) {
auto &protoInfo = getProtocolInfo(methodProto);
diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp
index 5917fba..9591e62 100644
--- a/lib/IRGen/GenMeta.cpp
+++ b/lib/IRGen/GenMeta.cpp
@@ -37,9 +37,9 @@
#include "Address.h"
#include "Callee.h"
-#include "ClassMetadataLayout.h"
+#include "ClassMetadataVisitor.h"
#include "ConstantBuilder.h"
-#include "EnumMetadataLayout.h"
+#include "EnumMetadataVisitor.h"
#include "FixedTypeInfo.h"
#include "GenArchetype.h"
#include "GenClass.h"
@@ -51,9 +51,10 @@
#include "IRGenDebugInfo.h"
#include "IRGenMangler.h"
#include "IRGenModule.h"
+#include "MetadataLayout.h"
#include "ScalarTypeInfo.h"
#include "StructLayout.h"
-#include "StructMetadataLayout.h"
+#include "StructMetadataVisitor.h"
#include "GenMeta.h"
@@ -68,23 +69,9 @@
// metadata pointer.
assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
- // We require objectType to be a pointer type so that the GEP will
- // scale by the right amount. We could load an arbitrary type using
- // some extra bitcasting.
- assert(IGF.IGM.DataLayout.getTypeStoreSize(objectTy) ==
- IGF.IGM.DataLayout.getTypeStoreSize(IGF.IGM.SizeTy));
-
- // Cast to T*.
- auto objectPtrTy = objectTy->getPointerTo();
- auto metadataWords = IGF.Builder.CreateBitCast(metadata, objectPtrTy);
-
- auto indexV = llvm::ConstantInt::getSigned(IGF.IGM.SizeTy, index);
-
- // GEP to the slot.
- Address slot(IGF.Builder.CreateInBoundsGEP(metadataWords, indexV),
- IGF.IGM.getPointerAlignment());
-
- return slot;
+ return IGF.emitAddressAtOffset(metadata,
+ Offset(index * IGF.IGM.getPointerSize()),
+ objectTy, IGF.IGM.getPointerAlignment());
}
/// Emit a load from the given metadata at a constant index.
@@ -100,8 +87,6 @@
return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix);
}
-static int getClassParentIndex(IRGenModule &IGM, ClassDecl *classDecl);
-
static Address createPointerSizedGEP(IRGenFunction &IGF,
Address base,
Size offset) {
@@ -2156,7 +2141,7 @@
B.addInt32(asImpl().getGenericParamsOffset() / IGM.getPointerSize());
// The archetype order here needs to be consistent with
- // MetadataLayout::addGenericFields.
+ // MetadataVisitor::addGenericFields.
GenericTypeRequirements requirements(IGM, ntd);
@@ -2240,69 +2225,6 @@
}
};
- // A bunch of ugly macros to make it easy to declare certain
- // common kinds of searcher.
-#define BEGIN_METADATA_SEARCHER_0(SEARCHER, DECLKIND) \
- struct SEARCHER \
- : MetadataSearcher<DECLKIND##MetadataScanner<SEARCHER>> { \
- using super = MetadataSearcher; \
- SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target) \
- : super(IGM, target) {}
-#define BEGIN_METADATA_SEARCHER_1(SEARCHER, DECLKIND, TYPE_1, NAME_1) \
- struct SEARCHER \
- : MetadataSearcher<DECLKIND##MetadataScanner<SEARCHER>> { \
- using super = MetadataSearcher; \
- TYPE_1 NAME_1; \
- SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target, TYPE_1 NAME_1) \
- : super(IGM, target), NAME_1(NAME_1) {}
-#define BEGIN_METADATA_SEARCHER_2(SEARCHER, DECLKIND, TYPE_1, NAME_1, \
- TYPE_2, NAME_2) \
- struct SEARCHER \
- : MetadataSearcher<DECLKIND##MetadataScanner<SEARCHER>> { \
- using super = MetadataSearcher; \
- TYPE_1 NAME_1; \
- TYPE_2 NAME_2; \
- SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target, TYPE_1 NAME_1, \
- TYPE_2 NAME_2) \
- : super(IGM, target), NAME_1(NAME_1), NAME_2(NAME_2) {}
-#define END_METADATA_SEARCHER() \
- };
-
-#define BEGIN_GENERIC_METADATA_SEARCHER_0(SEARCHER) \
- template <template <class Impl> class Scanner> \
- struct SEARCHER : MetadataSearcher<Scanner<SEARCHER<Scanner>>> { \
- using super = MetadataSearcher<Scanner<SEARCHER<Scanner>>>; \
- using super::Target; \
- using TargetType = decltype(Target); \
- SEARCHER(IRGenModule &IGM, TargetType target) \
- : super(IGM, target) {}
-#define BEGIN_GENERIC_METADATA_SEARCHER_1(SEARCHER, TYPE_1, NAME_1) \
- template <template <class Impl> class Scanner> \
- struct SEARCHER : MetadataSearcher<Scanner<SEARCHER<Scanner>>> { \
- using super = MetadataSearcher<Scanner<SEARCHER<Scanner>>>; \
- using super::Target; \
- using TargetType = decltype(Target); \
- TYPE_1 NAME_1; \
- SEARCHER(IRGenModule &IGM, TargetType target, TYPE_1 NAME_1) \
- : super(IGM, target), NAME_1(NAME_1) {}
-#define BEGIN_GENERIC_METADATA_SEARCHER_2(SEARCHER, TYPE_1, NAME_1, \
- TYPE_2, NAME_2) \
- template <template <class Impl> class Scanner> \
- struct SEARCHER : MetadataSearcher<Scanner<SEARCHER<Scanner>>> { \
- using super = MetadataSearcher<Scanner<SEARCHER<Scanner>>>; \
- using super::Target; \
- using TargetType = decltype(Target); \
- TYPE_1 NAME_1; \
- TYPE_2 NAME_2; \
- SEARCHER(IRGenModule &IGM, TargetType target, \
- TYPE_1 NAME_1, TYPE_2 NAME_2) \
- : super(IGM, target), NAME_1(NAME_1), NAME_2(NAME_2) {}
-#define END_GENERIC_METADATA_SEARCHER(SOUGHT) \
- }; \
- using FindClass##SOUGHT = FindType##SOUGHT<ClassMetadataScanner>; \
- using FindStruct##SOUGHT = FindType##SOUGHT<StructMetadataScanner>; \
- using FindEnum##SOUGHT = FindType##SOUGHT<EnumMetadataScanner>;
-
/// The total size and address point of a metadata object.
struct MetadataSize {
Size FullSize;
@@ -3145,32 +3067,11 @@
// Classes
-static Address
-emitAddressOfFieldOffsetVectorInClassMetadata(IRGenFunction &IGF,
- ClassDecl *theClass,
- llvm::Value *metadata) {
- BEGIN_METADATA_SEARCHER_0(GetOffsetToFieldOffsetVector, Class)
- void noteStartOfFieldOffsets(ClassDecl *whichClass) {
- if (whichClass == Target)
- setTargetOffset();
- }
- END_METADATA_SEARCHER()
-
- auto offset =
- GetOffsetToFieldOffsetVector(IGF.IGM, theClass).getTargetOffset();
-
- Address addr(metadata, IGF.IGM.getPointerAlignment());
- addr = IGF.Builder.CreateBitCast(addr,
- IGF.IGM.SizeTy->getPointerTo());
- return createPointerSizedGEP(IGF, addr, offset);
-}
-
static llvm::Value *emitInitializeFieldOffsetVector(IRGenFunction &IGF,
ClassDecl *target,
llvm::Value *metadata) {
llvm::Value *fieldVector
- = emitAddressOfFieldOffsetVectorInClassMetadata(IGF, target, metadata)
- .getAddress();
+ = emitAddressOfFieldOffsetVector(IGF, metadata, target).getAddress();
// Collect the stored properties of the type.
llvm::SmallVector<VarDecl*, 4> storedProperties;
@@ -3230,8 +3131,8 @@
namespace {
/// An adapter for laying out class metadata.
template <class Impl>
- class ClassMetadataBuilderBase : public ClassMetadataLayout<Impl> {
- using super = ClassMetadataLayout<Impl>;
+ class ClassMetadataBuilderBase : public ClassMetadataVisitor<Impl> {
+ using super = ClassMetadataVisitor<Impl>;
Optional<MetadataSize> ClassObjectExtents;
@@ -3488,7 +3389,7 @@
ForDefinition);
auto offsetVar = cast<llvm::GlobalVariable>(offsetAddr.getAddress());
offsetVar->setConstant(false);
- auto offset = getClassFieldOffset(IGM, Target, var).getValue();
+ auto offset = getClassFieldOffsetOffset(IGM, Target, var).getValue();
auto offsetVal = llvm::ConstantInt::get(IGM.IntPtrTy, offset);
offsetVar->setInitializer(offsetVal);
@@ -3605,10 +3506,9 @@
// We can't use emitClassFieldOffset() here because that creates
// an invariant load, which could be hoisted above the point
// where the metadata becomes fully initialized
- Size offset = getClassFieldOffset(IGF.IGM, Target, prop);
- int index = IGF.IGM.getOffsetInWords(offset);
- auto offsetVal = emitLoadFromMetadataAtIndex(IGF, metadata, index,
- IGF.IGM.SizeTy);
+ auto slot =
+ emitAddressOfClassFieldOffset(IGF, metadata, Target, prop);
+ auto offsetVal = IGF.emitInvariantLoad(slot);
IGF.Builder.CreateStore(offsetVal, offsetA);
}
@@ -3733,10 +3633,9 @@
assert(parentType);
llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType);
- int index = getClassParentIndex(IGF.IGM, Target);
- Address slot = emitAddressOfMetadataSlotAtIndex(IGF, metadata, index,
- IGF.IGM.TypeMetadataPtrTy);
- IGF.Builder.CreateStore(parentMetadata, slot);
+ auto parentSlot =
+ emitAddressOfParentMetadataSlot(IGF, metadata, type->getDecl());
+ IGF.Builder.CreateStore(parentMetadata, parentSlot);
}
metadata = emitFinishInitializationOfClassMetadata(IGF, metadata);
@@ -4062,6 +3961,13 @@
}
}
+llvm::Value *IRGenFunction::emitInvariantLoad(Address address,
+ const llvm::Twine &name) {
+ auto load = Builder.CreateLoad(address, name);
+ setInvariantLoad(load);
+ return load;
+}
+
void IRGenFunction::setInvariantLoad(llvm::LoadInst *load) {
load->setMetadata(IGM.InvariantMetadataID, IGM.InvariantNode);
}
@@ -4146,176 +4052,6 @@
return vwtable;
}
-/// Load the metadata reference at the given index.
-static llvm::Value *emitLoadOfMetadataRefAtIndex(IRGenFunction &IGF,
- llvm::Value *metadata,
- int index) {
- return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index,
- IGF.IGM.TypeMetadataPtrTy);
-}
-
-/// Load the protocol witness table reference at the given index.
-static llvm::Value *emitLoadOfWitnessTableRefAtIndex(IRGenFunction &IGF,
- llvm::Value *metadata,
- int index) {
- return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index,
- IGF.IGM.WitnessTablePtrTy);
-}
-
-namespace {
- /// A class for finding the 'parent' index in a class metadata object.
- BEGIN_METADATA_SEARCHER_0(FindClassParentIndex, Class)
- void addParentMetadataRef(ClassDecl *forClass, Type classType) {
- if (forClass == Target) setTargetOffset();
- super::addParentMetadataRef(forClass, classType);
- }
- END_METADATA_SEARCHER()
-} // end anonymous namespace
-
-/// Return the index of the parent metadata pointer for the given class.
-static int getClassParentIndex(IRGenModule &IGM, ClassDecl *classDecl) {
- assert(classDecl->getDeclContext()->isTypeContext());
- return FindClassParentIndex(IGM, classDecl).getTargetIndex();
-}
-
-/// In both enums and structs, the parent index is at index 2.
-static constexpr int ValueTypeParentIndex = 2;
-
-/// Given a reference to some metadata, derive a reference to the
-/// type's parent type.
-llvm::Value *irgen::emitParentMetadataRef(IRGenFunction &IGF,
- NominalTypeDecl *decl,
- llvm::Value *metadata) {
- assert(decl->getDeclContext()->isTypeContext());
-
- switch (decl->getKind()) {
-#define NOMINAL_TYPE_DECL(id, parent)
-#define DECL(id, parent) \
- case DeclKind::id:
-#include "swift/AST/DeclNodes.def"
- llvm_unreachable("not a nominal type");
-
- case DeclKind::Protocol:
- llvm_unreachable("protocols never have parent types!");
-
- case DeclKind::Class: {
- int index = getClassParentIndex(IGF.IGM, cast<ClassDecl>(decl));
- return emitLoadOfMetadataRefAtIndex(IGF, metadata, index);
- }
-
- case DeclKind::Enum:
- case DeclKind::Struct:
- return emitLoadOfMetadataRefAtIndex(IGF, metadata, ValueTypeParentIndex);
- }
- llvm_unreachable("bad decl kind!");
-}
-
-namespace {
- /// A class for finding the start of the generic requirements section
- /// in a type metadata object.
- BEGIN_GENERIC_METADATA_SEARCHER_0(FindTypeGenericRequirements)
- template <class... T>
- void noteStartOfGenericRequirements() {
- this->setTargetOffset();
- }
-
- template <class... T>
- void noteStartOfGenericRequirements(ClassDecl *forClass) {
- if (forClass == Target)
- this->setTargetOffset();
- }
- END_GENERIC_METADATA_SEARCHER(GenericRequirements)
-} // end anonymous namespace
-
-static int getIndexOfGenericRequirement(IRGenModule &IGM,
- NominalTypeDecl *decl,
- unsigned reqtIndex) {
- switch (decl->getKind()) {
-#define NOMINAL_TYPE_DECL(id, parent)
-#define DECL(id, parent) \
- case DeclKind::id:
-#include "swift/AST/DeclNodes.def"
- llvm_unreachable("not a nominal type");
-
- case DeclKind::Protocol:
- llvm_unreachable("protocols are never generic!");
-
- case DeclKind::Class: {
- int index = FindClassGenericRequirements(IGM, cast<ClassDecl>(decl))
- .getTargetIndex() + (int) reqtIndex;
- return index;
- }
-
- case DeclKind::Enum: {
- int index = FindEnumGenericRequirements(IGM, cast<EnumDecl>(decl))
- .getTargetIndex() + (int) reqtIndex;
- return index;
- }
-
- case DeclKind::Struct: {
- int index = FindStructGenericRequirements(IGM, cast<StructDecl>(decl))
- .getTargetIndex() + (int) reqtIndex;
- return index;
- }
- }
- llvm_unreachable("bad decl kind!");
-}
-
-/// Given a reference to nominal type metadata of the given type,
-/// derive a reference to the nth argument metadata. The type must
-/// have generic arguments.
-llvm::Value *irgen::emitArgumentMetadataRef(IRGenFunction &IGF,
- NominalTypeDecl *decl,
- const GenericTypeRequirements &reqts,
- unsigned reqtIndex,
- llvm::Value *metadata) {
- assert(reqts.getRequirements()[reqtIndex].Protocol == nullptr);
- int index = getIndexOfGenericRequirement(IGF.IGM, decl, reqtIndex);
- return emitLoadOfMetadataRefAtIndex(IGF, metadata, index);
-}
-
-/// Given a reference to nominal type metadata of the given type,
-/// derive a reference to a protocol witness table for the nth
-/// argument metadata. The type must have generic arguments.
-llvm::Value *irgen::emitArgumentWitnessTableRef(IRGenFunction &IGF,
- NominalTypeDecl *decl,
- const GenericTypeRequirements &reqts,
- unsigned reqtIndex,
- llvm::Value *metadata) {
- assert(reqts.getRequirements()[reqtIndex].Protocol != nullptr);
- int index = getIndexOfGenericRequirement(IGF.IGM, decl, reqtIndex);
- return emitLoadOfWitnessTableRefAtIndex(IGF, metadata, index);
-}
-
-irgen::Size irgen::getClassFieldOffset(IRGenModule &IGM,
- ClassDecl *theClass,
- VarDecl *field) {
- /// A class for finding a field offset in a class metadata object.
- BEGIN_METADATA_SEARCHER_1(FindClassFieldOffset, Class,
- VarDecl *, TargetField)
- void addFieldOffset(VarDecl *field) {
- if (field == TargetField)
- setTargetOffset();
- super::addFieldOffset(field);
- }
- END_METADATA_SEARCHER()
-
- return FindClassFieldOffset(IGM, theClass, field).getTargetOffset();
-}
-
-/// Given a reference to class metadata of the given type,
-/// derive a reference to the field offset for a stored property.
-/// The type must have dependent generic layout.
-llvm::Value *irgen::emitClassFieldOffset(IRGenFunction &IGF,
- ClassDecl *theClass,
- VarDecl *field,
- llvm::Value *metadata) {
- irgen::Size offset = getClassFieldOffset(IGF.IGM, theClass, field);
- int index = IGF.IGM.getOffsetInWords(offset);
- return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index,
- IGF.IGM.SizeTy);
-}
-
/// Given a reference to class metadata of the given type,
/// load the fragile instance size and alignment of the class.
std::pair<llvm::Value *, llvm::Value *>
@@ -4599,19 +4335,6 @@
return phi;
}
-namespace {
- /// A class for finding a vtable entry offset for a method argument
- /// in a class metadata object.
- BEGIN_METADATA_SEARCHER_1(FindClassMethodIndex, Class,
- SILDeclRef, TargetMethod)
- void addMethod(SILDeclRef fn) {
- if (TargetMethod == fn)
- setTargetOffset();
- super::addMethod(fn);
- }
- END_METADATA_SEARCHER()
-} // end anonymous namespace
-
/// Load the correct virtual function for the given class method.
FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
llvm::Value *base,
@@ -4666,23 +4389,19 @@
auto sig = IGF.IGM.getSignature(methodType);
auto declaringClass = cast<ClassDecl>(overridden.getDecl()->getDeclContext());
- auto index = FindClassMethodIndex(IGF.IGM, declaringClass, overridden)
- .getTargetIndex();
- auto fnPtr = emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index,
- sig.getType()->getPointerTo());
+ auto methodInfo =
+ IGF.IGM.getMetadataLayout(declaringClass).getMethodInfo(IGF, overridden);
+ auto offset = methodInfo.getOffset();
+
+ auto slot = IGF.emitAddressAtOffset(metadata, offset,
+ sig.getType()->getPointerTo(),
+ IGF.IGM.getPointerAlignment());
+ auto fnPtr = IGF.emitInvariantLoad(slot);
return FunctionPointer(fnPtr, sig);
}
-unsigned irgen::getVirtualMethodIndex(IRGenModule &IGM,
- SILDeclRef method) {
- SILDeclRef overridden = IGM.getSILTypes().getOverriddenVTableEntry(method);
- auto declaringClass = cast<ClassDecl>(overridden.getDecl()->getDeclContext());
- return FindClassMethodIndex(IGM, declaringClass, overridden)
- .getTargetIndex();;
-}
-
//===----------------------------------------------------------------------===//
// Value types (structs and enums)
//===----------------------------------------------------------------------===//
@@ -4748,8 +4467,7 @@
// indirectable pointer.
llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType);
Address addr =
- emitAddressOfMetadataSlotAtIndex(IGF, metadata, ValueTypeParentIndex,
- IGF.IGM.TypeMetadataPtrTy);
+ emitAddressOfParentMetadataSlot(IGF, metadata, type->getDecl());
IGF.Builder.CreateStore(parentMetadata, addr);
}
@@ -4796,8 +4514,8 @@
/// An adapter for laying out struct metadata.
template <class Impl>
class StructMetadataBuilderBase
- : public ValueTypeMetadataBuilderBase<Impl,StructMetadataLayout<Impl>>{
- using super = ValueTypeMetadataBuilderBase<Impl,StructMetadataLayout<Impl>>;
+ : public ValueTypeMetadataBuilderBase<Impl,StructMetadataVisitor<Impl>>{
+ using super = ValueTypeMetadataBuilderBase<Impl,StructMetadataVisitor<Impl>>;
protected:
using super::IGM;
@@ -4992,8 +4710,8 @@
template<class Impl>
class EnumMetadataBuilderBase
- : public ValueTypeMetadataBuilderBase<Impl, EnumMetadataLayout<Impl>> {
- using super = ValueTypeMetadataBuilderBase<Impl, EnumMetadataLayout<Impl>>;
+ : public ValueTypeMetadataBuilderBase<Impl, EnumMetadataVisitor<Impl>> {
+ using super = ValueTypeMetadataBuilderBase<Impl, EnumMetadataVisitor<Impl>>;
protected:
using super::IGM;
@@ -5187,14 +4905,14 @@
namespace {
/// A CRTP layout class for foreign class metadata.
template <class Impl>
- class ForeignClassMetadataLayout
- : public MetadataLayout<Impl> {
- using super = MetadataLayout<Impl>;
+ class ForeignClassMetadataVisitor
+ : public NominalMetadataVisitor<Impl> {
+ using super = NominalMetadataVisitor<Impl>;
protected:
ClassDecl *Target;
using super::asImpl;
public:
- ForeignClassMetadataLayout(IRGenModule &IGM, ClassDecl *target)
+ ForeignClassMetadataVisitor(IRGenModule &IGM, ClassDecl *target)
: super(IGM), Target(target) {}
void layout() {
@@ -5299,13 +5017,13 @@
class ForeignClassMetadataBuilder;
class ForeignClassMetadataBuilderBase :
- public ForeignClassMetadataLayout<ForeignClassMetadataBuilder> {
+ public ForeignClassMetadataVisitor<ForeignClassMetadataBuilder> {
protected:
ConstantStructBuilder &B;
ForeignClassMetadataBuilderBase(IRGenModule &IGM, ClassDecl *target,
ConstantStructBuilder &B)
- : ForeignClassMetadataLayout(IGM, target), B(B) {}
+ : ForeignClassMetadataVisitor(IGM, target), B(B) {}
};
/// A builder for ForeignClassMetadata.
@@ -5373,9 +5091,8 @@
auto parentType = getTargetType().getNominalParent();
auto parentMetadata = IGF.emitTypeMetadataRef(parentType);
- int index = ValueTypeParentIndex;
- Address slot = emitAddressOfMetadataSlotAtIndex(IGF, metadata, index,
- IGF.IGM.TypeMetadataPtrTy);
+ Address slot =
+ emitAddressOfParentMetadataSlot(IGF, metadata, this->Target);
IGF.Builder.CreateStore(parentMetadata, slot);
}
}
@@ -5419,9 +5136,8 @@
auto parentType = getTargetType().getNominalParent();
auto parentMetadata = IGF.emitTypeMetadataRef(parentType);
- int index = ValueTypeParentIndex;
- Address slot = emitAddressOfMetadataSlotAtIndex(IGF, metadata, index,
- IGF.IGM.TypeMetadataPtrTy);
+ Address slot =
+ emitAddressOfParentMetadataSlot(IGF, metadata, this->Target);
IGF.Builder.CreateStore(parentMetadata, slot);
}
}
diff --git a/lib/IRGen/GenMeta.h b/lib/IRGen/GenMeta.h
index 193ccd2..5e9c9d6 100644
--- a/lib/IRGen/GenMeta.h
+++ b/lib/IRGen/GenMeta.h
@@ -135,7 +135,7 @@
int32_t getIndexOfGenericArgument(IRGenModule &IGM,
NominalTypeDecl *decl,
ArchetypeType *archetype);
-
+
/// Given a reference to nominal type metadata of the given type,
/// derive a reference to the parent type metadata. There must be a
/// parent type.
@@ -161,11 +161,6 @@
unsigned reqtIndex,
llvm::Value *metadata);
- /// Get the offset of a field in the class type metadata.
- Size getClassFieldOffset(IRGenModule &IGM,
- ClassDecl *theClass,
- VarDecl *field);
-
/// Given a reference to class type metadata of the given type,
/// decide the offset to the given field. This assumes that the
/// offset is stored in the metadata, i.e. its offset is potentially
@@ -237,9 +232,6 @@
CanSILFunctionType methodType,
bool useSuperVTable);
- /// Get the offset of the given class method within the class's vtables.
- unsigned getVirtualMethodIndex(IRGenModule &IGM, SILDeclRef method);
-
/// \brief Load a reference to the protocol descriptor for the given protocol.
///
/// For Swift protocols, this is a constant reference to the protocol
diff --git a/lib/IRGen/GenObjC.cpp b/lib/IRGen/GenObjC.cpp
index ffd5c6e..6d6bb11 100644
--- a/lib/IRGen/GenObjC.cpp
+++ b/lib/IRGen/GenObjC.cpp
@@ -871,8 +871,8 @@
// Otherwise, we have a loadable type that can either be passed directly or
// indirectly.
assert(info.getSILStorageType().isObject());
- auto &ti =
- cast<LoadableTypeInfo>(IGM.getTypeInfo(info.getSILStorageType()));
+ auto curSILType = info.getSILStorageType();
+ auto &ti = cast<LoadableTypeInfo>(IGM.getTypeInfo(curSILType));
// Load the indirectly passed parameter.
auto &nativeSchema = ti.nativeParameterValueSchema(IGM);
@@ -881,8 +881,16 @@
ti.loadAsTake(subIGF, paramAddr, translatedParams);
continue;
}
+ // Map from the native calling convention into the explosion schema.
+ auto &nativeParamSchema = ti.nativeParameterValueSchema(IGM);
+ Explosion nativeParam;
+ params.transferInto(nativeParam, nativeParamSchema.size());
+ Explosion nonNativeParam = nativeParamSchema.mapFromNative(
+ subIGF.IGM, subIGF, nativeParam, curSILType);
+ assert(nativeParam.empty());
+
// Pass along the value.
- ti.reexplode(subIGF, params, translatedParams);
+ ti.reexplode(subIGF, nonNativeParam, translatedParams);
}
// Prepare the call to the underlying method.
diff --git a/lib/IRGen/GenStruct.cpp b/lib/IRGen/GenStruct.cpp
index 3418599..0e54b3b 100644
--- a/lib/IRGen/GenStruct.cpp
+++ b/lib/IRGen/GenStruct.cpp
@@ -39,7 +39,7 @@
#include "MemberAccessStrategy.h"
#include "NonFixedTypeInfo.h"
#include "ResilientTypeInfo.h"
-#include "StructMetadataLayout.h"
+#include "StructMetadataVisitor.h"
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
@@ -414,6 +414,8 @@
}
llvm::Value *getOffsetForIndex(IRGenFunction &IGF, unsigned index) override {
+ // TODO: do this with StructMetadataLayout::getFieldOffset
+
// Get the field offset vector from the struct metadata.
llvm::Value *metadata = IGF.emitTypeMetadataRefForLayout(TheStruct);
Address fieldVector = emitAddressOfFieldOffsetVector(IGF,
@@ -826,41 +828,6 @@
FOR_STRUCT_IMPL(IGM, baseType, getConstantFieldOffset, field);
}
-llvm::Constant *
-irgen::emitPhysicalStructMemberOffsetOfFieldOffset(IRGenModule &IGM,
- SILType baseType,
- VarDecl *field) {
- class FieldScanner : public StructMetadataScanner<FieldScanner> {
- VarDecl *Field;
- public:
- FieldScanner(IRGenModule &IGM, StructDecl *Target, VarDecl *Field)
- : StructMetadataScanner(IGM, Target), Field(Field)
- {}
-
- Size OffsetOfFieldOffset = Size::invalid();
-
- void noteAddressPoint() {
- assert(OffsetOfFieldOffset == Size::invalid()
- && "found field offset before address point?");
- NextOffset = Size(0);
- }
-
- void addFieldOffset(VarDecl *theField) {
- if (Field == theField)
- OffsetOfFieldOffset = NextOffset;
- StructMetadataScanner::addFieldOffset(theField);
- }
- };
- FieldScanner scanner(IGM, baseType.getStructOrBoundGenericStruct(),
- field);
- scanner.layout();
- if (scanner.OffsetOfFieldOffset == Size::invalid())
- return nullptr;
-
- return llvm::ConstantInt::get(IGM.SizeTy,
- scanner.OffsetOfFieldOffset.getValue());
-}
-
MemberAccessStrategy
irgen::getPhysicalStructMemberAccessStrategy(IRGenModule &IGM,
SILType baseType, VarDecl *field) {
diff --git a/lib/IRGen/GenStruct.h b/lib/IRGen/GenStruct.h
index c49be2b..7d0c1f8 100644
--- a/lib/IRGen/GenStruct.h
+++ b/lib/IRGen/GenStruct.h
@@ -49,13 +49,6 @@
SILType baseType,
VarDecl *field);
- /// Return the constant offset within the struct's metadata object where the
- /// offset of that field is stored, or null if the field is not in the
- /// struct's field offset vector.
- llvm::Constant *emitPhysicalStructMemberOffsetOfFieldOffset(IRGenModule &IGM,
- SILType baseType,
- VarDecl *field);
-
/// Return a strategy for accessing the given stored struct property.
///
/// This API is used by RemoteAST.
diff --git a/lib/IRGen/IRGen.h b/lib/IRGen/IRGen.h
index 72f16b4..2956855 100644
--- a/lib/IRGen/IRGen.h
+++ b/lib/IRGen/IRGen.h
@@ -37,6 +37,7 @@
namespace irgen {
using Lowering::AbstractionPattern;
using clang::CodeGen::ConstantInitFuture;
+ class IRGenFunction;
/// In IRGen, we use Swift's ClusteredBitVector data structure to
/// store vectors of spare bits.
@@ -450,6 +451,42 @@
return Size(getValue());
}
+/// A static or dynamic offset.
+class Offset {
+ enum Kind {
+ Static,
+ Dynamic,
+ };
+ enum : uint64_t {
+ KindBits = 1,
+ KindMask = (1 << KindBits) - 1,
+ PayloadMask = ~uint64_t(KindMask)
+ };
+ uint64_t Data;
+
+public:
+ explicit Offset(llvm::Value *offset)
+ : Data(reinterpret_cast<uintptr_t>(offset) | Dynamic) {}
+ explicit Offset(Size offset)
+ : Data((static_cast<uint64_t>(offset.getValue()) << KindBits) | Static) {
+ assert(getStatic() == offset && "overflow");
+ }
+
+ bool isStatic() const { return (Data & KindMask) == Static; }
+ bool isDynamic() const { return (Data & KindMask) == Dynamic; }
+ Size getStatic() const {
+ assert(isStatic());
+ return Size(static_cast<int64_t>(Data) >> KindBits);
+ }
+ llvm::Value *getDynamic() const {
+ assert(isDynamic());
+ return reinterpret_cast<llvm::Value*>(Data & PayloadMask);
+ }
+
+ llvm::Value *getAsValue(IRGenFunction &IGF) const;
+ Offset offsetBy(IRGenFunction &IGF, Offset other) const;
+};
+
} // end namespace irgen
} // end namespace swift
diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp
index 00dd1d7..8d82923 100644
--- a/lib/IRGen/IRGenFunction.cpp
+++ b/lib/IRGen/IRGenFunction.cpp
@@ -372,3 +372,48 @@
void Explosion::dump() {
print(llvm::errs());
}
+
+llvm::Value *Offset::getAsValue(IRGenFunction &IGF) const {
+ if (isStatic()) {
+ return IGF.IGM.getSize(getStatic());
+ } else {
+ return getDynamic();
+ }
+}
+
+Offset Offset::offsetBy(IRGenFunction &IGF, Offset other) const {
+ if (isStatic() && other.isStatic()) {
+ return Offset(getStatic() + other.getStatic());
+ }
+ return Offset(IGF.Builder.CreateAdd(getDynamic(), other.getDynamic()));
+}
+
+Address IRGenFunction::emitAddressAtOffset(llvm::Value *base, Offset offset,
+ llvm::Type *objectTy,
+ Alignment objectAlignment,
+ const llvm::Twine &name) {
+ // Use a slightly more obvious IR pattern if it's a multiple of the type
+ // size. I'll confess that this is partly just to avoid updating tests.
+ if (offset.isStatic()) {
+ auto byteOffset = offset.getStatic();
+ Size objectSize(IGM.DataLayout.getTypeAllocSize(objectTy));
+ if (byteOffset.isMultipleOf(objectSize)) {
+ // Cast to T*.
+ auto objectPtrTy = objectTy->getPointerTo();
+ base = Builder.CreateBitCast(base, objectPtrTy);
+
+ // GEP to the slot, computing the index as a signed number.
+ auto scaledIndex =
+ int64_t(byteOffset.getValue()) / int64_t(objectSize.getValue());
+ auto indexValue = IGM.getSize(Size(scaledIndex));
+ auto slotPtr = Builder.CreateInBoundsGEP(base, indexValue);
+
+ return Address(slotPtr, objectAlignment);
+ }
+ }
+
+ // GEP to the slot.
+ auto offsetValue = offset.getAsValue(*this);
+ auto slotPtr = emitByteOffsetGEP(base, offsetValue, objectTy);
+ return Address(slotPtr, objectAlignment);
+}
diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h
index d68bef1..6901698 100644
--- a/lib/IRGen/IRGenFunction.h
+++ b/lib/IRGen/IRGenFunction.h
@@ -137,6 +137,13 @@
Address emitByteOffsetGEP(llvm::Value *base, llvm::Value *offset,
const TypeInfo &type,
const llvm::Twine &name = "");
+ Address emitAddressAtOffset(llvm::Value *base, Offset offset,
+ llvm::Type *objectType,
+ Alignment objectAlignment,
+ const llvm::Twine &name = "");
+
+ llvm::Value *emitInvariantLoad(Address address,
+ const llvm::Twine &name = "");
void emitStoreOfRelativeIndirectablePointer(llvm::Value *value,
Address addr,
diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h
index 3fc673f..5627a15 100644
--- a/lib/IRGen/IRGenModule.h
+++ b/lib/IRGen/IRGenModule.h
@@ -78,21 +78,12 @@
class ASTContext;
class BraceStmt;
class CanType;
- class ClassDecl;
- class ConstructorDecl;
- class Decl;
- class DestructorDecl;
- class ExtensionDecl;
- class FuncDecl;
class LinkLibrary;
class SILFunction;
- class EnumElementDecl;
- class EnumDecl;
class IRGenOptions;
class NormalProtocolConformance;
class ProtocolConformance;
class ProtocolCompositionType;
- class ProtocolDecl;
struct SILDeclRef;
class SILGlobalVariable;
class SILModule;
@@ -100,12 +91,7 @@
class SILWitnessTable;
class SourceLoc;
class SourceFile;
- class StructDecl;
class Type;
- class TypeAliasDecl;
- class TypeDecl;
- class ValueDecl;
- class VarDecl;
namespace Lowering {
class TypeConverter;
@@ -114,8 +100,10 @@
namespace irgen {
class Address;
class ClangTypeConverter;
+ class ClassMetadataLayout;
class DebugTypeInfo;
class EnumImplStrategy;
+ class EnumMetadataLayout;
class ExplosionSchema;
class FixedTypeInfo;
class ForeignFunctionInfo;
@@ -125,9 +113,12 @@
class IRGenFunction;
class LinkEntity;
class LoadableTypeInfo;
+ class MetadataLayout;
class NecessaryBindings;
+ class NominalMetadataLayout;
class ProtocolInfo;
class Signature;
+ class StructMetadataLayout;
class TypeConverter;
class TypeInfo;
enum class ValueWitness : unsigned;
@@ -652,7 +643,12 @@
ResilienceExpansion getResilienceExpansionForLayout(SILGlobalVariable *var);
SpareBitVector getSpareBitsForType(llvm::Type *scalarTy, Size size);
-
+
+ NominalMetadataLayout &getMetadataLayout(NominalTypeDecl *decl);
+ StructMetadataLayout &getMetadataLayout(StructDecl *decl);
+ ClassMetadataLayout &getMetadataLayout(ClassDecl *decl);
+ EnumMetadataLayout &getMetadataLayout(EnumDecl *decl);
+
private:
TypeConverter &Types;
friend class TypeConverter;
@@ -662,6 +658,9 @@
void initClangTypeConverter();
void destroyClangTypeConverter();
+ llvm::DenseMap<Decl*, MetadataLayout*> MetadataLayouts;
+ void destroyMetadataLayoutMap();
+
friend class GenericContextScope;
//--- Globals ---------------------------------------------------------------
diff --git a/lib/IRGen/MetadataLayout.cpp b/lib/IRGen/MetadataLayout.cpp
new file mode 100644
index 0000000..386932d
--- /dev/null
+++ b/lib/IRGen/MetadataLayout.cpp
@@ -0,0 +1,374 @@
+//===--- MetadataLayout.cpp - Metadata construct layout -------------------===//
+//
+// 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 includes code for laying out type metadata.
+//
+// It also implements certain low-level access routines for type metadata.
+// These routines are generally declared in one of two different places:
+//
+// - Mid-level routines to extract data from metadata are declared in
+// GenMeta.h. This file is a sort of sub-module of GenMeta.cpp.
+//
+// - Low-level routines to project the addresses of fields in metadata
+// are declared in MetadataLayout.h.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MetadataLayout.h"
+#include "GenMeta.h"
+
+#include "ClassMetadataVisitor.h"
+#include "EnumMetadataVisitor.h"
+#include "IRGenFunction.h"
+#include "StructMetadataVisitor.h"
+
+#include "swift/Basic/LLVM.h"
+#include "llvm/ADT/Optional.h"
+
+using namespace swift;
+using namespace irgen;
+
+namespace {
+
+template <class Impl, template <class> class Base>
+class LayoutScanner : public Base<Impl> {
+ Optional<Size> AddressPoint;
+
+protected:
+ template <class... As>
+ LayoutScanner(As &&... args) : Base<Impl>(std::forward<As>(args)...) {}
+
+public:
+ using StoredOffset = MetadataLayout::StoredOffset;
+
+ void noteAddressPoint() { AddressPoint = this->NextOffset; }
+ StoredOffset getNextOffset() {
+ return StoredOffset(this->NextOffset - AddressPoint.getValue());
+ }
+};
+
+}
+
+ClassMetadataLayout &IRGenModule::getMetadataLayout(ClassDecl *decl) {
+ return cast<ClassMetadataLayout>(
+ getMetadataLayout(static_cast<NominalTypeDecl*>(decl)));
+}
+
+EnumMetadataLayout &IRGenModule::getMetadataLayout(EnumDecl *decl) {
+ return cast<EnumMetadataLayout>(
+ getMetadataLayout(static_cast<NominalTypeDecl*>(decl)));
+}
+
+StructMetadataLayout &IRGenModule::getMetadataLayout(StructDecl *decl) {
+ return cast<StructMetadataLayout>(
+ getMetadataLayout(static_cast<NominalTypeDecl*>(decl)));
+}
+
+NominalMetadataLayout &IRGenModule::getMetadataLayout(NominalTypeDecl *decl) {
+ auto &entry = MetadataLayouts[decl];
+ if (!entry) {
+ if (auto theClass = dyn_cast<ClassDecl>(decl)) {
+ entry = new ClassMetadataLayout(*this, theClass);
+ } else if (auto theEnum = dyn_cast<EnumDecl>(decl)) {
+ entry = new EnumMetadataLayout(*this, theEnum);
+ } else if (auto theStruct = dyn_cast<StructDecl>(decl)) {
+ entry = new StructMetadataLayout(*this, theStruct);
+ } else {
+ llvm_unreachable("bad nominal type!");
+ }
+ }
+ return *cast<NominalMetadataLayout>(entry);
+}
+
+void IRGenModule::destroyMetadataLayoutMap() {
+ for (auto &entry : MetadataLayouts) {
+ entry.second->destroy();
+ }
+}
+
+void MetadataLayout::destroy() const {
+ switch (getKind()) {
+ case Kind::Class:
+ delete cast<ClassMetadataLayout>(this);
+ return;
+
+ case Kind::Struct:
+ delete cast<StructMetadataLayout>(this);
+ return;
+
+ case Kind::Enum:
+ delete cast<EnumMetadataLayout>(this);
+ return;
+ }
+ llvm_unreachable("bad kind");
+}
+
+/******************************* NOMINAL TYPES ********************************/
+
+Offset NominalMetadataLayout::getParentOffset(IRGenFunction &IGF) const {
+ assert(Parent.isValid());
+ assert(Parent.isStatic() && "resilient metadata layout unsupported!");
+ return Offset(Parent.getStaticOffset());
+}
+
+Offset
+NominalMetadataLayout::getGenericRequirementsOffset(IRGenFunction &IGF) const {
+ assert(GenericRequirements.isValid());
+ assert(GenericRequirements.isStatic() && "resilient metadata layout unsupported!");
+ return Offset(GenericRequirements.getStaticOffset());
+}
+
+/// Given a reference to some metadata, derive a reference to the
+/// type's parent type.
+llvm::Value *irgen::emitParentMetadataRef(IRGenFunction &IGF,
+ NominalTypeDecl *decl,
+ llvm::Value *metadata) {
+ auto slot = emitAddressOfParentMetadataSlot(IGF, metadata, decl);
+ return IGF.emitInvariantLoad(slot);
+}
+
+Address irgen::emitAddressOfParentMetadataSlot(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ NominalTypeDecl *decl) {
+ auto offset = IGF.IGM.getMetadataLayout(decl).getParentOffset(IGF);
+ return IGF.emitAddressAtOffset(metadata, offset,
+ IGF.IGM.TypeMetadataPtrTy,
+ IGF.IGM.getPointerAlignment());
+}
+
+static llvm::Value *emitLoadOfGenericRequirement(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ NominalTypeDecl *decl,
+ unsigned reqtIndex,
+ llvm::Type *reqtTy) {
+ auto offset =
+ IGF.IGM.getMetadataLayout(decl).getGenericRequirementsOffset(IGF);
+ offset = offset.offsetBy(IGF, Offset(reqtIndex * IGF.IGM.getPointerSize()));
+
+ auto slot = IGF.emitAddressAtOffset(metadata, offset, reqtTy,
+ IGF.IGM.getPointerAlignment());
+ auto witness = IGF.emitInvariantLoad(slot);
+ return witness;
+}
+
+/// Given a reference to nominal type metadata of the given type,
+/// derive a reference to the nth argument metadata. The type must
+/// have generic arguments.
+llvm::Value *irgen::emitArgumentMetadataRef(IRGenFunction &IGF,
+ NominalTypeDecl *decl,
+ const GenericTypeRequirements &reqts,
+ unsigned reqtIndex,
+ llvm::Value *metadata) {
+ assert(reqts.getRequirements()[reqtIndex].Protocol == nullptr);
+ return emitLoadOfGenericRequirement(IGF, metadata, decl, reqtIndex,
+ IGF.IGM.TypeMetadataPtrTy);
+}
+
+/// Given a reference to nominal type metadata of the given type,
+/// derive a reference to a protocol witness table for the nth
+/// argument metadata. The type must have generic arguments.
+llvm::Value *irgen::emitArgumentWitnessTableRef(IRGenFunction &IGF,
+ NominalTypeDecl *decl,
+ const GenericTypeRequirements &reqts,
+ unsigned reqtIndex,
+ llvm::Value *metadata) {
+ assert(reqts.getRequirements()[reqtIndex].Protocol != nullptr);
+ return emitLoadOfGenericRequirement(IGF, metadata, decl, reqtIndex,
+ IGF.IGM.WitnessTablePtrTy);
+}
+
+/********************************** CLASSES ***********************************/
+
+ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
+ : NominalMetadataLayout(Kind::Class) {
+
+ struct Scanner : LayoutScanner<Scanner, ClassMetadataScanner> {
+ using super = LayoutScanner;
+
+ ClassMetadataLayout &Layout;
+ Scanner(IRGenModule &IGM, ClassDecl *decl, ClassMetadataLayout &layout)
+ : super(IGM, decl), Layout(layout) {}
+
+ void addParentMetadataRef(ClassDecl *forClass, Type classType) {
+ if (forClass == Target)
+ Layout.Parent = getNextOffset();
+ super::addParentMetadataRef(forClass, classType);
+ }
+
+ void noteStartOfGenericRequirements(ClassDecl *forClass) {
+ if (forClass == Target)
+ Layout.GenericRequirements = getNextOffset();
+ super::noteStartOfGenericRequirements(forClass);
+ }
+
+ void addMethod(SILDeclRef fn) {
+ if (fn.getDecl()->getDeclContext() == Target)
+ Layout.MethodInfos.try_emplace(fn, getNextOffset());
+ super::addMethod(fn);
+ }
+
+ void noteStartOfFieldOffsets(ClassDecl *forClass) {
+ if (forClass == Target)
+ Layout.FieldOffsetVector = getNextOffset();
+ super::noteStartOfFieldOffsets(forClass);
+ }
+
+ void addFieldOffset(VarDecl *field) {
+ if (field->getDeclContext() == Target)
+ Layout.FieldOffsets.try_emplace(field, getNextOffset());
+ super::addFieldOffset(field);
+ }
+ };
+
+ Scanner(IGM, decl, *this).layout();
+}
+
+ClassMetadataLayout::MethodInfo
+ClassMetadataLayout::getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const{
+ auto &stored = getStoredMethodInfo(method);
+
+ assert(stored.TheOffset.isStatic() &&
+ "resilient class metadata layout unsupported!");
+ auto offset = Offset(stored.TheOffset.getStaticOffset());
+
+ return MethodInfo(offset);
+}
+
+Size ClassMetadataLayout::getStaticMethodOffset(SILDeclRef method) const{
+ auto &stored = getStoredMethodInfo(method);
+
+ assert(stored.TheOffset.isStatic() &&
+ "resilient class metadata layout unsupported!");
+ return stored.TheOffset.getStaticOffset();
+}
+
+Offset ClassMetadataLayout::getFieldOffset(IRGenFunction &IGF,
+ VarDecl *field) const {
+ // TODO: implement resilient metadata layout
+ return Offset(getStaticFieldOffset(field));
+}
+Size ClassMetadataLayout::getStaticFieldOffset(VarDecl *field) const {
+ auto &stored = getStoredFieldOffset(field);
+ assert(stored.isStatic() && "resilient class metadata layout unsupported!");
+ return stored.getStaticOffset();
+}
+
+Offset
+ClassMetadataLayout::getFieldOffsetVectorOffset(IRGenFunction &IGF) const {
+ // TODO: implement resilient metadata layout
+ assert(FieldOffsetVector.isStatic());
+ return Offset(FieldOffsetVector.getStaticOffset());
+}
+
+Size irgen::getClassFieldOffsetOffset(IRGenModule &IGM, ClassDecl *theClass,
+ VarDecl *field) {
+ return IGM.getMetadataLayout(theClass).getStaticFieldOffset(field);
+}
+
+/// Given a reference to class metadata of the given type,
+/// compute the field offset for a stored property.
+/// The type must have dependent generic layout.
+llvm::Value *irgen::emitClassFieldOffset(IRGenFunction &IGF,
+ ClassDecl *theClass,
+ VarDecl *field,
+ llvm::Value *metadata) {
+ auto slot = emitAddressOfClassFieldOffset(IGF, metadata, theClass, field);
+ return IGF.emitInvariantLoad(slot);
+}
+
+Address irgen::emitAddressOfClassFieldOffset(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ ClassDecl *theClass,
+ VarDecl *field) {
+ auto offset = IGF.IGM.getMetadataLayout(theClass).getFieldOffset(IGF, field);
+ auto slot = IGF.emitAddressAtOffset(metadata, offset, IGF.IGM.SizeTy,
+ IGF.IGM.getPointerAlignment());
+ return slot;
+}
+
+Address irgen::emitAddressOfFieldOffsetVector(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ ClassDecl *theClass) {
+ auto offset =
+ IGF.IGM.getMetadataLayout(theClass).getFieldOffsetVectorOffset(IGF);
+
+ return IGF.emitAddressAtOffset(metadata, offset, IGF.IGM.SizeTy,
+ IGF.IGM.getPointerAlignment());
+}
+
+/*********************************** ENUMS ************************************/
+
+EnumMetadataLayout::EnumMetadataLayout(IRGenModule &IGM, EnumDecl *decl)
+ : NominalMetadataLayout(Kind::Enum) {
+
+ struct Scanner : LayoutScanner<Scanner, EnumMetadataScanner> {
+ using super = LayoutScanner;
+
+ EnumMetadataLayout &Layout;
+ Scanner(IRGenModule &IGM, EnumDecl *decl, EnumMetadataLayout &layout)
+ : super(IGM, decl), Layout(layout) {}
+
+ void addParentMetadataRef() {
+ Layout.Parent = getNextOffset();
+ super::addParentMetadataRef();
+ }
+
+ void noteStartOfGenericRequirements() {
+ Layout.GenericRequirements = getNextOffset();
+ super::noteStartOfGenericRequirements();
+ }
+ };
+
+ Scanner(IGM, decl, *this).layout();
+}
+
+/********************************** STRUCTS ***********************************/
+
+StructMetadataLayout::StructMetadataLayout(IRGenModule &IGM, StructDecl *decl)
+ : NominalMetadataLayout(Kind::Struct) {
+
+ struct Scanner : LayoutScanner<Scanner, StructMetadataScanner> {
+ using super = LayoutScanner;
+
+ StructMetadataLayout &Layout;
+ Scanner(IRGenModule &IGM, StructDecl *decl, StructMetadataLayout &layout)
+ : super(IGM, decl), Layout(layout) {}
+
+ void addParentMetadataRef() {
+ Layout.Parent = getNextOffset();
+ super::addParentMetadataRef();
+ }
+
+ void noteStartOfGenericRequirements() {
+ Layout.GenericRequirements = getNextOffset();
+ super::noteStartOfGenericRequirements();
+ }
+
+ void addFieldOffset(VarDecl *field) {
+ Layout.FieldOffsets.try_emplace(field, getNextOffset());
+ super::addFieldOffset(field);
+ }
+ };
+
+ Scanner(IGM, decl, *this).layout();
+}
+
+Offset StructMetadataLayout::getFieldOffset(IRGenFunction &IGF,
+ VarDecl *field) const {
+ // TODO: implement resilient metadata layout
+ return Offset(getStaticFieldOffset(field));
+}
+Size StructMetadataLayout::getStaticFieldOffset(VarDecl *field) const {
+ auto &stored = getStoredFieldOffset(field);
+ assert(stored.isStatic() && "resilient struct metadata layout unsupported!");
+ return stored.getStaticOffset();
+}
diff --git a/lib/IRGen/MetadataLayout.h b/lib/IRGen/MetadataLayout.h
index dbc8a60..1589940 100644
--- a/lib/IRGen/MetadataLayout.h
+++ b/lib/IRGen/MetadataLayout.h
@@ -1,4 +1,4 @@
-//===--- MetadataLayout.h - CRTP for metadata layout ------------*- C++ -*-===//
+//===--- MetadataLayout.h - Type metadata layout ----------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -10,84 +10,249 @@
//
//===----------------------------------------------------------------------===//
//
-// A CRTP helper class for laying out type metadata.
+// Information recording the layout of type metadata objects.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_METADATALAYOUT_H
#define SWIFT_IRGEN_METADATALAYOUT_H
-#include "llvm/ADT/SmallVector.h"
-#include "swift/AST/Decl.h"
-#include "swift/SIL/TypeLowering.h"
-#include "GenericRequirement.h"
-#include "GenProto.h"
-#include "IRGenModule.h"
+#include "IRGen.h"
+#include "swift/SIL/SILDeclRef.h"
namespace swift {
+class ClassDecl;
+class EnumDecl;
+class StructDecl;
+class VarDecl;
+
namespace irgen {
+class Address;
+class IRGenFunction;
+class IRGenModule;
-/// A CRTP class for laying out type metadata. Note that this does
-/// *not* handle the metadata template stuff.
-template <class Impl> class MetadataLayout {
-protected:
- Impl &asImpl() { return *static_cast<Impl*>(this); }
+/// A base class for various kinds of metadata layout.
+class MetadataLayout {
+public:
+ enum class Kind {
+ Class,
+ Struct,
+ Enum
+ // Update NominalMetadataLayout::classof if you add a non-nominal layout.
+ };
+
+ class StoredOffset {
+ enum State {
+ /// The high bits are an integer displacement.
+ Static = 0,
+
+ /// The high bits are an llvm::Constant* for the displacement,
+ /// which may be null if it hasn't been computed yet.
+ Dynamic,
+ };
+ enum : uint64_t {
+ KindBits = 1,
+ KindMask = (1 << KindBits) - 1,
+ PayloadMask = ~uint64_t(KindMask)
+ };
+
+ mutable uintptr_t Data;
+ public:
+ StoredOffset() : Data(0) {}
+ explicit StoredOffset(llvm::Constant *offset)
+ : Data(reinterpret_cast<uintptr_t>(offset) | Dynamic) {}
+ explicit StoredOffset(Size offset)
+ : Data((static_cast<uint64_t>(offset.getValue()) << KindBits) | Static) {
+ assert(!offset.isZero() && "cannot store a zero offset");
+ assert(getStaticOffset() == offset && "overflow");
+ }
+
+ bool isValid() const { return Data != 0; }
+ bool isStatic() const { return isValid() && (Data & KindMask) == Static; }
+ bool isDynamic() const { return (Data & KindMask) == Dynamic; }
+ Size getStaticOffset() const {
+ assert(isStatic());
+ return Size(static_cast<int64_t>(Data) >> KindBits);
+ }
+ llvm::Constant *getDynamicOffsetVariable() const {
+ assert(isDynamic());
+ return reinterpret_cast<llvm::Constant*>(Data & PayloadMask);
+ }
+ void setDynamicOffsetVariable(llvm::Constant *pointer) const {
+ assert(isDynamic());
+ Data = reinterpret_cast<uintptr_t>(pointer) | Dynamic;
+ }
+ };
+
+private:
+ Kind TheKind;
protected:
- IRGenModule &IGM;
+ MetadataLayout(Kind theKind) : TheKind(theKind) {}
- MetadataLayout(IRGenModule &IGM) : IGM(IGM) {}
+ MetadataLayout(const MetadataLayout &other) = delete;
+ MetadataLayout &operator=(const MetadataLayout &other) = delete;
public:
- void layout() {
- // Common fields.
- asImpl().addValueWitnessTable();
- asImpl().noteAddressPoint();
- asImpl().addMetadataFlags();
- }
+ /// Destruct and deallocate this layout object.
+ void destroy() const;
- /// This is the address point.
- void noteAddressPoint() {}
-
- /// Add fields related to the generics of this class declaration.
- /// TODO: don't add new fields that are implied by the superclass
- /// fields. e.g., if B<T> extends A<T>, the witness for T in A's
- /// section should be enough.
- template <class... T>
- void addGenericFields(NominalTypeDecl *typeDecl, Type type,
- T &&...args) {
- // The archetype order here needs to be consistent with
- // NominalTypeDescriptorBase::addGenericParams.
-
- // Note that we intentionally don't std::forward 'args'.
- asImpl().noteStartOfGenericRequirements(args...);
-
- GenericTypeRequirements requirements(IGM, typeDecl);
- if (requirements.empty()) return;
-
- auto subs = type->castTo<BoundGenericType>()
- ->getContextSubstitutionMap(IGM.getSwiftModule(),
- typeDecl);
- requirements.enumerateFulfillments(IGM, subs,
- [&](unsigned reqtIndex, CanType argType,
- Optional<ProtocolConformanceRef> conf) {
- if (conf) {
- asImpl().addGenericWitnessTable(argType, *conf, args...);
- } else {
- asImpl().addGenericArgument(argType, args...);
- }
- });
-
- asImpl().noteEndOfGenericRequirements(args...);
- }
-
- template <class... T>
- void noteStartOfGenericRequirements(T &&...args) {}
-
- template <class... T>
- void noteEndOfGenericRequirements(T &&...args) {}
+ Kind getKind() const { return TheKind; }
};
+/// Base class for nominal type metadata layouts.
+class NominalMetadataLayout : public MetadataLayout {
+protected:
+ StoredOffset GenericRequirements;
+ StoredOffset Parent;
+
+ NominalMetadataLayout(Kind kind) : MetadataLayout(kind) {}
+
+public:
+ bool hasGenericRequirements() const {
+ return GenericRequirements.isValid();
+ }
+
+ Offset getGenericRequirementsOffset(IRGenFunction &IGF) const;
+ Offset getParentOffset(IRGenFunction &IGF) const;
+
+ static bool classof(const MetadataLayout *layout) {
+ return true; // No non-nominal metadata for now.
+ }
+};
+
+/// Layout for class type metadata.
+class ClassMetadataLayout : public NominalMetadataLayout {
+public:
+ class MethodInfo {
+ Offset TheOffset;
+ public:
+ MethodInfo(Offset offset)
+ : TheOffset(offset) {}
+ Offset getOffset() const { return TheOffset; }
+ };
+
+private:
+ struct StoredMethodInfo {
+ StoredOffset TheOffset;
+ StoredMethodInfo(StoredOffset offset) : TheOffset(offset) {}
+ };
+ llvm::DenseMap<SILDeclRef, StoredMethodInfo> MethodInfos;
+
+ /// Field offsets for various fields.
+ llvm::DenseMap<VarDecl*, StoredOffset> FieldOffsets;
+
+ /// The start of the field-offset vector.
+ StoredOffset FieldOffsetVector;
+
+ const StoredMethodInfo &getStoredMethodInfo(SILDeclRef method) const {
+ auto it = MethodInfos.find(method);
+ assert(it != MethodInfos.end());
+ return it->second;
+ }
+
+ const StoredOffset &getStoredFieldOffset(VarDecl *field) const {
+ auto it = FieldOffsets.find(field);
+ assert(it != FieldOffsets.end());
+ return it->second;
+ }
+
+ friend class IRGenModule;
+ ClassMetadataLayout(IRGenModule &IGM, ClassDecl *theClass);
+
+public:
+ MethodInfo getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const;
+
+ /// Assuming that the given method is at a static offset in the metadata,
+ /// return that static offset.
+ ///
+ /// DEPRECATED: callers should be updated to handle this in a
+ /// more arbitrary fashion.
+ Size getStaticMethodOffset(SILDeclRef method) const;
+
+ Offset getFieldOffset(IRGenFunction &IGF, VarDecl *field) const;
+
+ /// Assuming that the given field offset is at a static offset in
+ /// the metadata, return that static offset.
+ ///
+ /// DEPRECATED: callers should be updated to handle this in a
+ /// more arbitrary fashion.
+ Size getStaticFieldOffset(VarDecl *field) const;
+
+ Offset getFieldOffsetVectorOffset(IRGenFunction &IGF) const;
+
+ static bool classof(const MetadataLayout *layout) {
+ return layout->getKind() == Kind::Class;
+ }
+};
+
+/// Layout for enum type metadata.
+class EnumMetadataLayout : public NominalMetadataLayout {
+ // TODO: presumably it would be useful to store *something* here
+ // for resilience.
+
+ friend class IRGenModule;
+ EnumMetadataLayout(IRGenModule &IGM, EnumDecl *theEnum);
+
+public:
+ static bool classof(const MetadataLayout *layout) {
+ return layout->getKind() == Kind::Enum;
+ }
+};
+
+/// Layout for struct type metadata.
+class StructMetadataLayout : public NominalMetadataLayout {
+ llvm::DenseMap<VarDecl*, StoredOffset> FieldOffsets;
+
+ const StoredOffset &getStoredFieldOffset(VarDecl *field) const {
+ auto it = FieldOffsets.find(field);
+ assert(it != FieldOffsets.end());
+ return it->second;
+ }
+
+ friend class IRGenModule;
+ StructMetadataLayout(IRGenModule &IGM, StructDecl *theStruct);
+
+public:
+
+ Offset getFieldOffset(IRGenFunction &IGF, VarDecl *field) const;
+
+ /// Assuming that the given field offset is at a static offset in
+ /// the metadata, return that static offset.
+ ///
+ /// DEPRECATED: callers should be updated to handle this in a
+ /// more arbitrary fashion.
+ Size getStaticFieldOffset(VarDecl *field) const;
+
+ static bool classof(const MetadataLayout *layout) {
+ return layout->getKind() == Kind::Struct;
+ }
+};
+
+/// Emit the address of the 'parent' slot in the given nominal-type metadata.
+Address emitAddressOfParentMetadataSlot(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ NominalTypeDecl *decl);
+
+/// Emit the address of the field-offset slot in the given class metadata.
+Address emitAddressOfClassFieldOffset(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ ClassDecl *theClass,
+ VarDecl *field);
+
+/// Get the offset to a field offset in the class type metadata.
+///
+/// DEPRECATED: callers should be updated to handle this in a more
+/// arbitrary fashion.
+Size getClassFieldOffsetOffset(IRGenModule &IGM,
+ ClassDecl *theClass,
+ VarDecl *field);
+
+/// Emit the address of the field-offset vector in the given class metadata.
+Address emitAddressOfFieldOffsetVector(IRGenFunction &IGF,
+ llvm::Value *metadata,
+ ClassDecl *theClass);
+
} // end namespace irgen
} // end namespace swift
diff --git a/lib/IRGen/NominalMetadataVisitor.h b/lib/IRGen/NominalMetadataVisitor.h
new file mode 100644
index 0000000..214032f
--- /dev/null
+++ b/lib/IRGen/NominalMetadataVisitor.h
@@ -0,0 +1,96 @@
+//===--- NominalMetadataVisitor.h - CRTP for metadata layout ----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A CRTP helper class for visiting all of the fields in a nominal type
+// metadata object.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_IRGEN_NOMINALMETADATAVISITOR_H
+#define SWIFT_IRGEN_NOMINALMETADATAVISITOR_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "swift/AST/Decl.h"
+#include "swift/AST/SubstitutionMap.h"
+#include "swift/SIL/TypeLowering.h"
+#include "GenericRequirement.h"
+#include "GenProto.h"
+#include "IRGenModule.h"
+
+namespace swift {
+namespace irgen {
+
+/// A CRTP class for laying out type metadata. Note that this does
+/// *not* handle the metadata template stuff.
+template <class Impl> class NominalMetadataVisitor {
+protected:
+ Impl &asImpl() { return *static_cast<Impl*>(this); }
+
+protected:
+ IRGenModule &IGM;
+
+ NominalMetadataVisitor(IRGenModule &IGM) : IGM(IGM) {}
+
+public:
+ void layout() {
+ // Common fields.
+ asImpl().addValueWitnessTable();
+ asImpl().noteAddressPoint();
+ asImpl().addMetadataFlags();
+ }
+
+ /// This is the address point.
+ void noteAddressPoint() {}
+
+ /// Add fields related to the generics of this class declaration.
+ /// TODO: don't add new fields that are implied by the superclass
+ /// fields. e.g., if B<T> extends A<T>, the witness for T in A's
+ /// section should be enough.
+ template <class... T>
+ void addGenericFields(NominalTypeDecl *typeDecl, Type type,
+ T &&...args) {
+ // The archetype order here needs to be consistent with
+ // NominalTypeDescriptorBase::addGenericParams.
+
+ // Note that we intentionally don't std::forward 'args'.
+ asImpl().noteStartOfGenericRequirements(args...);
+
+ GenericTypeRequirements requirements(IGM, typeDecl);
+ if (requirements.empty()) return;
+
+ auto subs = type->castTo<BoundGenericType>()
+ ->getContextSubstitutionMap(IGM.getSwiftModule(),
+ typeDecl);
+ requirements.enumerateFulfillments(IGM, subs,
+ [&](unsigned reqtIndex, CanType argType,
+ Optional<ProtocolConformanceRef> conf) {
+ if (conf) {
+ asImpl().addGenericWitnessTable(argType, *conf, args...);
+ } else {
+ asImpl().addGenericArgument(argType, args...);
+ }
+ });
+
+ asImpl().noteEndOfGenericRequirements(args...);
+ }
+
+ template <class... T>
+ void noteStartOfGenericRequirements(T &&...args) {}
+
+ template <class... T>
+ void noteEndOfGenericRequirements(T &&...args) {}
+};
+
+} // end namespace irgen
+} // end namespace swift
+
+#endif
diff --git a/lib/IRGen/StructMetadataLayout.h b/lib/IRGen/StructMetadataVisitor.h
similarity index 82%
rename from lib/IRGen/StructMetadataLayout.h
rename to lib/IRGen/StructMetadataVisitor.h
index 2b918dd..3910b75 100644
--- a/lib/IRGen/StructMetadataLayout.h
+++ b/lib/IRGen/StructMetadataVisitor.h
@@ -1,4 +1,4 @@
-//===--- StructMetadataLayout.h - CRTP for struct metadata ------*- C++ -*-===//
+//===--- StructMetadataVisitor.h - CRTP for struct metadata ------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
@@ -17,7 +17,7 @@
#ifndef SWIFT_IRGEN_STRUCTMETADATALAYOUT_H
#define SWIFT_IRGEN_STRUCTMETADATALAYOUT_H
-#include "MetadataLayout.h"
+#include "NominalMetadataVisitor.h"
namespace swift {
namespace irgen {
@@ -26,8 +26,9 @@
///
/// This produces an object corresponding to the StructMetadata type.
/// It does not itself doing anything special for metadata templates.
-template <class Impl> class StructMetadataLayout : public MetadataLayout<Impl> {
- typedef MetadataLayout<Impl> super;
+template <class Impl> class StructMetadataVisitor
+ : public NominalMetadataVisitor<Impl> {
+ using super = NominalMetadataVisitor<Impl>;
protected:
using super::IGM;
@@ -36,7 +37,7 @@
/// The struct.
StructDecl *const Target;
- StructMetadataLayout(IRGenModule &IGM, StructDecl *target)
+ StructMetadataVisitor(IRGenModule &IGM, StructDecl *target)
: super(IGM), Target(target) {}
public:
@@ -64,11 +65,11 @@
void noteStartOfFieldOffsets() {}
};
-/// An "implementation" of StructMetadataLayout that just scans through
+/// An "implementation" of StructMetadataVisitor that just scans through
/// the metadata layout, maintaining the offset of the next field.
template <class Impl>
-class StructMetadataScanner : public StructMetadataLayout<Impl> {
- typedef StructMetadataLayout<Impl> super;
+class StructMetadataScanner : public StructMetadataVisitor<Impl> {
+ typedef StructMetadataVisitor<Impl> super;
protected:
Size NextOffset = Size(0);
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2a25a86..7bbf23b 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -3214,25 +3214,27 @@
return Status;
}
+ auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, EqualLoc, Id, IdLoc,
+ /*genericParams*/nullptr,
+ CurDeclContext);
+ TAD->getUnderlyingTypeLoc() = UnderlyingTy.getPtrOrNull();
+ TAD->getAttrs() = Attributes;
+
// Parse a 'where' clause if present, adding it to our GenericParamList.
if (Tok.is(tok::kw_where)) {
+ ContextChange CC(*this, TAD);
Status |= parseFreestandingGenericWhereClause(genericParams);
}
+ // Set after parsing the where clause, which might create genericParams.
+ TAD->setGenericParams(genericParams);
+
if (UnderlyingTy.isNull()) {
diagnose(Tok, diag::expected_equal_in_typealias);
Status.setIsParseError();
return Status;
}
- auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, EqualLoc, Id, IdLoc,
- genericParams, CurDeclContext);
- TAD->getUnderlyingTypeLoc() = UnderlyingTy.getPtrOrNull();
- TAD->getAttrs() = Attributes;
-
- if (Status.hasCodeCompletion() && CodeCompletion)
- CodeCompletion->setParsedDecl(TAD);
-
// Exit the scope introduced for the generic parameters.
GenericsScope.reset();
@@ -5014,9 +5016,10 @@
setLocalDiscriminator(ED);
ED->getAttrs() = Attributes;
+ ContextChange CC(*this, ED);
+
// Parse optional inheritance clause within the context of the enum.
if (Tok.is(tok::colon)) {
- ContextChange CC(*this, ED);
SmallVector<TypeLoc, 2> Inherited;
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
ED->setInherited(Context.AllocateCopy(Inherited));
@@ -5035,16 +5038,12 @@
ED->setGenericParams(GenericParams);
}
- if (Status.hasCodeCompletion() && CodeCompletion)
- CodeCompletion->setParsedDecl(ED);
-
SourceLoc LBLoc, RBLoc;
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_enum)) {
LBLoc = PreviousLoc;
RBLoc = LBLoc;
Status.setIsParseError();
} else {
- ContextChange CC(*this, ED);
Scope S(this, ScopeKind::ClassBody);
ParseDeclOptions Options(PD_HasContainerType | PD_AllowEnumElement | PD_InEnum);
if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_enum,
@@ -5277,9 +5276,10 @@
setLocalDiscriminator(SD);
SD->getAttrs() = Attributes;
+ ContextChange CC(*this, SD);
+
// Parse optional inheritance clause within the context of the struct.
if (Tok.is(tok::colon)) {
- ContextChange CC(*this, SD);
SmallVector<TypeLoc, 2> Inherited;
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
SD->setInherited(Context.AllocateCopy(Inherited));
@@ -5297,9 +5297,6 @@
}
SD->setGenericParams(GenericParams);
}
-
- if (Status.hasCodeCompletion() && CodeCompletion)
- CodeCompletion->setParsedDecl(SD);
SourceLoc LBLoc, RBLoc;
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_struct)) {
@@ -5308,7 +5305,6 @@
Status.setIsParseError();
} else {
// Parse the body.
- ContextChange CC(*this, SD);
Scope S(this, ScopeKind::StructBody);
ParseDeclOptions Options(PD_HasContainerType | PD_InStruct);
if (parseDeclList(LBLoc, RBLoc, diag::expected_rbrace_struct,
@@ -5365,9 +5361,10 @@
// Attach attributes.
CD->getAttrs() = Attributes;
+ ContextChange CC(*this, CD);
+
// Parse optional inheritance clause within the context of the class.
if (Tok.is(tok::colon)) {
- ContextChange CC(*this, CD);
SmallVector<TypeLoc, 2> Inherited;
Status |= parseInheritance(Inherited, /*classRequirementLoc=*/nullptr);
CD->setInherited(Context.AllocateCopy(Inherited));
@@ -5386,9 +5383,6 @@
CD->setGenericParams(GenericParams);
}
- if (Status.hasCodeCompletion() && CodeCompletion)
- CodeCompletion->setParsedDecl(CD);
-
SourceLoc LBLoc, RBLoc;
if (parseToken(tok::l_brace, LBLoc, diag::expected_lbrace_class)) {
LBLoc = PreviousLoc;
@@ -5396,7 +5390,6 @@
Status.setIsParseError();
} else {
// Parse the body.
- ContextChange CC(*this, CD);
Scope S(this, ScopeKind::ClassBody);
ParseDeclOptions Options(PD_HasContainerType | PD_AllowDestructor |
PD_InClass);
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index b3dd8f9..0fd2a79 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -202,7 +202,6 @@
case ValueKind::RefToBridgeObjectInst:
case ValueKind::BridgeObjectToRefInst:
case ValueKind::UnconditionalCheckedCastInst:
- case ValueKind::UnconditionalCheckedCastValueInst:
case ValueKind::TupleExtractInst:
case ValueKind::StructExtractInst:
case ValueKind::UncheckedEnumDataInst:
@@ -529,6 +528,7 @@
SHOULD_CHECK_FOR_DATAFLOW_VIOLATIONS}; \
}
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, CheckedCastValueBranch)
+CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, UnconditionalCheckedCastValue)
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, InitExistentialValue)
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, true, DeinitExistentialValue)
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
@@ -658,7 +658,6 @@
FORWARD_ANY_OWNERSHIP_INST(RefToBridgeObject)
FORWARD_ANY_OWNERSHIP_INST(BridgeObjectToRef)
FORWARD_ANY_OWNERSHIP_INST(UnconditionalCheckedCast)
-FORWARD_ANY_OWNERSHIP_INST(UnconditionalCheckedCastValue)
FORWARD_ANY_OWNERSHIP_INST(MarkUninitialized)
FORWARD_ANY_OWNERSHIP_INST(UncheckedEnumData)
#undef FORWARD_ANY_OWNERSHIP_INST
diff --git a/lib/SIL/ValueOwnershipKindClassifier.cpp b/lib/SIL/ValueOwnershipKindClassifier.cpp
index db49396..d18067e 100644
--- a/lib/SIL/ValueOwnershipKindClassifier.cpp
+++ b/lib/SIL/ValueOwnershipKindClassifier.cpp
@@ -45,7 +45,6 @@
CONSTANT_OWNERSHIP_INST(Owned, StrongPin)
CONSTANT_OWNERSHIP_INST(Owned, ThinToThickFunction)
CONSTANT_OWNERSHIP_INST(Owned, InitExistentialValue)
-CONSTANT_OWNERSHIP_INST(Owned, UnconditionalCheckedCastValue)
// One would think that these /should/ be unowned. In truth they are owned since
// objc metatypes do not go through the retain/release fast path. In their
@@ -132,6 +131,7 @@
}
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, StructExtract)
CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Guaranteed, TupleExtract)
+CONSTANT_OR_TRIVIAL_OWNERSHIP_INST(Owned, UnconditionalCheckedCastValue)
#undef CONSTANT_OR_TRIVIAL_OWNERSHIP_INST
// These are instructions that do not have any result, so we should never reach
diff --git a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
index 6659478..f3d37e9 100644
--- a/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
+++ b/lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp
@@ -150,10 +150,15 @@
SILArgument *Arg =
Continue->createPHIArgument(AI.getType(), ValueOwnershipKind::Owned);
if (!isa<TryApplyInst>(AI)) {
- IdenBuilder.createBranch(AI.getLoc(), Continue,
- ArrayRef<SILValue>(IdenAI.getInstruction()));
- VirtBuilder.createBranch(AI.getLoc(), Continue,
- ArrayRef<SILValue>(VirtAI.getInstruction()));
+ if (AI.getSubstCalleeType()->isNoReturnFunction()) {
+ IdenBuilder.createUnreachable(AI.getLoc());
+ VirtBuilder.createUnreachable(AI.getLoc());
+ } else {
+ IdenBuilder.createBranch(AI.getLoc(), Continue,
+ ArrayRef<SILValue>(IdenAI.getInstruction()));
+ VirtBuilder.createBranch(AI.getLoc(), Continue,
+ ArrayRef<SILValue>(VirtAI.getInstruction()));
+ }
}
// Remove the old Apply instruction.
diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp
index b71a6cf..2f71055 100644
--- a/lib/Sema/CSDiag.cpp
+++ b/lib/Sema/CSDiag.cpp
@@ -2134,7 +2134,8 @@
/// Attempt to produce a diagnostic for a mismatch between an expression's
/// type and its assumed contextual type.
- bool diagnoseContextualConversionError(Expr *expr, Type contextualType);
+ bool diagnoseContextualConversionError(Expr *expr, Type contextualType,
+ ContextualTypePurpose CTP);
/// For an expression being type checked with a CTP_CalleeResult contextual
/// type, try to diagnose a problem.
@@ -2143,7 +2144,8 @@
/// Attempt to produce a diagnostic for a mismatch between a call's
/// type and its assumed contextual type.
bool diagnoseCallContextualConversionErrors(ApplyExpr *callEpxr,
- Type contextualType);
+ Type contextualType,
+ ContextualTypePurpose CTP);
private:
/// Validate potential contextual type for type-checking one of the
@@ -3899,9 +3901,9 @@
/// of function type, giving more specific and simpler diagnostics, attaching
/// notes on the parameter, and offering fixits to insert @escaping. Returns
/// true if it detects and issues an error, false if it does nothing.
-static bool tryDiagnoseNonEscapingParameterToEscaping(Expr *expr, Type srcType,
- Type dstType,
- ConstraintSystem &CS) {
+static bool tryDiagnoseNonEscapingParameterToEscaping(
+ Expr *expr, Type srcType, Type dstType, ContextualTypePurpose dstPurpose,
+ ConstraintSystem &CS) {
assert(expr);
// Need to be referencing a parameter of function type
auto declRef = dyn_cast<DeclRefExpr>(expr);
@@ -3921,7 +3923,7 @@
// Pick a specific diagnostic for the specific use
auto paramDecl = cast<ParamDecl>(declRef->getDecl());
- switch (CS.getContextualTypePurpose()) {
+ switch (dstPurpose) {
case CTP_CallArgument:
CS.TC.diagnose(declRef->getLoc(), diag::passing_noescape_to_escaping,
paramDecl->getName());
@@ -3949,13 +3951,13 @@
return true;
}
-bool FailureDiagnosis::diagnoseContextualConversionError(Expr *expr,
- Type contextualType) {
+bool FailureDiagnosis::diagnoseContextualConversionError(
+ Expr *expr, Type contextualType, ContextualTypePurpose CTP) {
// If the constraint system has a contextual type, then we can test to see if
// this is the problem that prevents us from solving the system.
if (!contextualType) {
// This contextual conversion constraint doesn't install an actual type.
- if (CS.getContextualTypePurpose() == CTP_CalleeResult)
+ if (CTP == CTP_CalleeResult)
return diagnoseCalleeResultContextualConversionError();
return false;
@@ -3995,7 +3997,7 @@
// If this is conversion failure due to a return statement with an argument
// that cannot be coerced to the result type of the function, emit a
// specific error.
- switch (CS.getContextualTypePurpose()) {
+ switch (CTP) {
case CTP_Unused:
case CTP_CannotFail:
llvm_unreachable("These contextual type purposes cannot fail with a "
@@ -4156,8 +4158,7 @@
// If this is a conversion from T to () in a call argument context, it is
// almost certainly an extra argument being passed in.
- if (CS.getContextualTypePurpose() == CTP_CallArgument &&
- contextualType->isVoid()) {
+ if (CTP == CTP_CallArgument && contextualType->isVoid()) {
diagnose(expr->getLoc(), diag::extra_argument_to_nullary_call)
.highlight(expr->getSourceRange());
return true;
@@ -4212,7 +4213,7 @@
// Try for better/more specific diagnostics for non-escaping to @escaping
if (tryDiagnoseNonEscapingParameterToEscaping(expr, exprType, contextualType,
- CS))
+ CTP, CS))
return true;
// Don't attempt fixits if we have an unsolved type variable, since
@@ -4261,7 +4262,7 @@
}
// Attempt to add a fixit for the error.
- switch (CS.getContextualTypePurpose()) {
+ switch (CTP) {
case CTP_CallArgument:
case CTP_ArrayElement:
case CTP_DictionaryKey:
@@ -6303,7 +6304,8 @@
// related to function type, let's try to diagnose it.
if (possibleTypes.empty() && contextualType &&
!contextualType->hasUnresolvedType())
- return diagnoseContextualConversionError(callExpr, contextualType);
+ return diagnoseContextualConversionError(callExpr, contextualType,
+ CS.getContextualTypePurpose());
} else {
possibleTypes.push_back(currentType);
}
@@ -6404,7 +6406,7 @@
/// Check if there failure associated with expression is related
/// to given contextual type.
bool FailureDiagnosis::diagnoseCallContextualConversionErrors(
- ApplyExpr *callExpr, Type contextualType) {
+ ApplyExpr *callExpr, Type contextualType, ContextualTypePurpose CTP) {
if (!contextualType || contextualType->hasUnresolvedType())
return false;
@@ -6436,7 +6438,7 @@
// If type-checking with contextual type didn't produce any results
// it means that we have a contextual mismatch.
if (withContextual.empty())
- return diagnoseContextualConversionError(callExpr, contextualType);
+ return diagnoseContextualConversionError(callExpr, contextualType, CTP);
// If call produces a single type when type-checked with contextual
// expression, it means that the problem is elsewhere, any other
@@ -6482,7 +6484,8 @@
if (diagnoseTrailingClosureErrors(callExpr))
return true;
- if (diagnoseCallContextualConversionErrors(callExpr, CS.getContextualType()))
+ if (diagnoseCallContextualConversionErrors(callExpr, CS.getContextualType(),
+ CS.getContextualTypePurpose()))
return true;
auto *fnExpr = callExpr->getFn();
@@ -7004,11 +7007,31 @@
return true;
}
- // If the source type is already an error type, we've already posted an error.
- auto srcExpr = typeCheckChildIndependently(assignExpr->getSrc(),
- destType->getRValueType(),
- CTP_AssignSource);
- if (!srcExpr) return true;
+ auto *srcExpr = assignExpr->getSrc();
+ auto contextualType = destType->getRValueType();
+
+ // Let's try to type-check assignment source expression without using
+ // destination as a contextual type, that allows us to diagnose
+ // contextual problems related to source much easier.
+ //
+ // If source expression requires contextual type to be present,
+ // let's avoid this step because it's always going to fail.
+ {
+ auto *srcExpr = assignExpr->getSrc();
+ ExprTypeSaverAndEraser eraser(srcExpr);
+
+ ConcreteDeclRef ref = nullptr;
+ auto type = CS.TC.getTypeOfExpressionWithoutApplying(srcExpr, CS.DC, ref);
+
+ if (type && !type->isEqual(contextualType))
+ return diagnoseContextualConversionError(
+ assignExpr->getSrc(), contextualType, CTP_AssignSource);
+ }
+
+ srcExpr = typeCheckChildIndependently(assignExpr->getSrc(), contextualType,
+ CTP_AssignSource);
+ if (!srcExpr)
+ return true;
// If we are assigning to _ and have unresolved types on the RHS, then we have
// an ambiguity problem.
@@ -8860,7 +8883,8 @@
return;
// If this is a contextual conversion problem, dig out some information.
- if (diagnosis.diagnoseContextualConversionError(expr, getContextualType()))
+ if (diagnosis.diagnoseContextualConversionError(expr, getContextualType(),
+ getContextualTypePurpose()))
return;
// If we can diagnose a problem based on the constraints left laying around in
diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp
index 48b3c1a..381aca8 100644
--- a/lib/Sema/ConstraintSystem.cpp
+++ b/lib/Sema/ConstraintSystem.cpp
@@ -1279,16 +1279,11 @@
// For a static member referenced through a metatype or an instance
// member referenced through an instance, strip off the 'self'.
type = openedFnType->getResult();
- } else if (isDynamicResult && isa<AbstractFunctionDecl>(value)) {
- // For a dynamic result referring to an instance function through
- // an object of metatype type, replace the 'Self' parameter with
- // a AnyObject member.
- auto anyObjectTy = TC.Context.getAnyObjectType();
- type = openedFnType->replaceSelfParameterType(anyObjectTy);
} else {
// For an unbound instance method reference, replace the 'Self'
// parameter with the base type.
- type = openedFnType->replaceSelfParameterType(baseObjTy);
+ openedType = openedFnType->replaceSelfParameterType(baseObjTy);
+ type = openedType;
}
// When accessing protocol members with an existential base, replace
diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp
index acc9164..10f5aff 100644
--- a/lib/Sema/TypeCheckType.cpp
+++ b/lib/Sema/TypeCheckType.cpp
@@ -481,6 +481,28 @@
// type.
if (auto parentType = unboundType->getParent()) {
if (parentType->hasUnboundGenericType()) {
+ // If we're working with a nominal type declaration, just construct
+ // a bound generic type without checking the generic arguments.
+ if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl)) {
+ SmallVector<Type, 2> args;
+ for (auto &genericArg : genericArgs) {
+ // Propagate failure.
+ if (validateType(genericArg, dc, options, resolver,
+ unsatisfiedDependency))
+ return ErrorType::get(Context);
+
+ auto substTy = genericArg.getType();
+
+ // Unsatisfied dependency case.
+ if (!substTy)
+ return nullptr;
+
+ args.push_back(substTy);
+ }
+
+ return BoundGenericType::get(nominalDecl, parentType, args);
+ }
+
assert(!resultType->hasTypeParameter());
return resultType;
}
diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp
index da70abc..201d9e0 100644
--- a/lib/TBDGen/TBDGen.cpp
+++ b/lib/TBDGen/TBDGen.cpp
@@ -28,101 +28,17 @@
#include "swift/SIL/TypeLowering.h"
#include "llvm/ADT/StringSet.h"
+#include "TBDGenVisitor.h"
+
using namespace swift;
using namespace swift::irgen;
+using namespace swift::tbdgen;
using StringSet = llvm::StringSet<>;
static bool isPrivateDecl(ValueDecl *VD) {
return getDeclLinkage(VD) != FormalLinkage::PublicUnique;
}
-namespace {
-class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
- StringSet &Symbols;
- const UniversalLinkageInfo &UniversalLinkInfo;
- ModuleDecl *SwiftModule;
- bool FileHasEntryPoint;
- bool SILSerializeWitnessTables;
-
- bool InsideAbstractStorageDecl = false;
-
- void addSymbol(StringRef name) {
- auto isNewValue = Symbols.insert(name).second;
- (void)isNewValue;
- assert(isNewValue && "already inserted");
- }
-
- void addSymbol(SILDeclRef declRef);
-
- void addSymbol(LinkEntity entity) {
- auto linkage =
- LinkInfo::get(UniversalLinkInfo, SwiftModule, entity, ForDefinition);
-
- auto externallyVisible =
- llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) &&
- linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility;
-
- if (externallyVisible)
- addSymbol(linkage.getName());
- }
-
- void addConformances(DeclContext *DC);
-
-public:
- TBDGenVisitor(StringSet &symbols,
- const UniversalLinkageInfo &universalLinkInfo,
- ModuleDecl *swiftModule, bool fileHasEntryPoint,
- bool silSerializeWitnessTables)
- : Symbols(symbols), UniversalLinkInfo(universalLinkInfo),
- SwiftModule(swiftModule), FileHasEntryPoint(fileHasEntryPoint),
- SILSerializeWitnessTables(silSerializeWitnessTables) {}
-
- void visitMembers(Decl *D) {
- SmallVector<Decl *, 4> members;
- auto addMembers = [&](DeclRange range) {
- for (auto member : range)
- members.push_back(member);
- };
- if (auto ED = dyn_cast<ExtensionDecl>(D))
- addMembers(ED->getMembers());
- else if (auto NTD = dyn_cast<NominalTypeDecl>(D))
- addMembers(NTD->getMembers());
- else if (auto ASD = dyn_cast<AbstractStorageDecl>(D))
- ASD->getAllAccessorFunctions(members);
-
- for (auto member : members) {
- ASTVisitor::visit(member);
- }
- }
-
- void visitPatternBindingDecl(PatternBindingDecl *PBD);
-
- void visitValueDecl(ValueDecl *VD);
-
- void visitAbstractFunctionDecl(AbstractFunctionDecl *AFD);
-
- void visitTypeAliasDecl(TypeAliasDecl *TAD) {
- // any information here is encoded elsewhere
- }
-
- void visitNominalTypeDecl(NominalTypeDecl *NTD);
-
- void visitClassDecl(ClassDecl *CD);
-
- void visitConstructorDecl(ConstructorDecl *CD);
-
- void visitExtensionDecl(ExtensionDecl *ED);
-
- void visitProtocolDecl(ProtocolDecl *PD);
-
- void visitAbstractStorageDecl(AbstractStorageDecl *ASD);
-
- void visitVarDecl(VarDecl *VD);
-
- void visitDecl(Decl *D) { visitMembers(D); }
-};
-} // end anonymous namespace
-
static bool isGlobalOrStaticVar(VarDecl *VD) {
return VD->isStatic() || VD->getDeclContext()->isModuleScopeContext();
}
@@ -410,23 +326,70 @@
#endif
}
+static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile,
+ StringSet &symbols,
+ bool hasMultipleIRGenThreads,
+ bool silSerializeWitnessTables,
+ llvm::raw_ostream *os,
+ StringRef installName) {
+ auto isWholeModule = singleFile == nullptr;
+ const auto &target = M->getASTContext().LangOpts.Target;
+ UniversalLinkageInfo linkInfo(target, hasMultipleIRGenThreads, isWholeModule);
+
+ TBDGenVisitor visitor(symbols, target, linkInfo, M, silSerializeWitnessTables,
+ installName);
+
+ auto visitFile = [&](FileUnit *file) {
+ SmallVector<Decl *, 16> decls;
+ file->getTopLevelDecls(decls);
+
+ visitor.setFileHasEntryPoint(file->hasEntryPoint());
+
+ for (auto d : decls)
+ visitor.visit(d);
+ };
+
+ if (singleFile) {
+ assert(M == singleFile->getParentModule() && "mismatched file and module");
+ visitFile(singleFile);
+ } else {
+ for (auto *file : M->getFiles()) {
+ visitFile(file);
+ }
+ }
+
+ if (os) {
+ // The correct TBD formatting code is temporarily non-open source, so this
+ // is just a list of the symbols.
+ std::vector<StringRef> sorted;
+ for (auto &symbol : symbols)
+ sorted.push_back(symbol.getKey());
+ std::sort(sorted.begin(), sorted.end());
+ for (const auto &symbol : sorted) {
+ *os << symbol << "\n";
+ }
+ }
+}
+
void swift::enumeratePublicSymbols(FileUnit *file, StringSet &symbols,
bool hasMultipleIRGenThreads,
- bool isWholeModule,
bool silSerializeWitnessTables) {
- UniversalLinkageInfo linkInfo(file->getASTContext().LangOpts.Target,
- hasMultipleIRGenThreads, isWholeModule);
-
- SmallVector<Decl *, 16> decls;
- file->getTopLevelDecls(decls);
-
- auto hasEntryPoint = file->hasEntryPoint();
-
- TBDGenVisitor visitor(symbols, linkInfo, file->getParentModule(),
- hasEntryPoint, silSerializeWitnessTables);
- for (auto d : decls)
- visitor.visit(d);
-
- if (hasEntryPoint)
- symbols.insert("main");
+ enumeratePublicSymbolsAndWrite(
+ file->getParentModule(), file, symbols, hasMultipleIRGenThreads,
+ silSerializeWitnessTables, nullptr, StringRef());
+}
+void swift::enumeratePublicSymbols(ModuleDecl *M, StringSet &symbols,
+ bool hasMultipleIRGenThreads,
+ bool silSerializeWitnessTables) {
+ enumeratePublicSymbolsAndWrite(M, nullptr, symbols, hasMultipleIRGenThreads,
+ silSerializeWitnessTables, nullptr,
+ StringRef());
+}
+void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os,
+ bool hasMultipleIRGenThreads,
+ bool silSerializeWitnessTables,
+ StringRef installName) {
+ StringSet symbols;
+ enumeratePublicSymbolsAndWrite(M, nullptr, symbols, hasMultipleIRGenThreads,
+ silSerializeWitnessTables, &os, installName);
}
diff --git a/lib/TBDGen/TBDGenVisitor.h b/lib/TBDGen/TBDGenVisitor.h
new file mode 100644
index 0000000..5316e19
--- /dev/null
+++ b/lib/TBDGen/TBDGenVisitor.h
@@ -0,0 +1,137 @@
+//===--- TBDGenVisitor.h - AST Visitor for TBD generation -----------------===//
+//
+// 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 defines the visitor that finds all symbols in a swift AST.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SWIFT_TBDGEN_TBDGENVISITOR_H
+#define SWIFT_TBDGEN_TBDGENVISITOR_H
+
+#include "swift/AST/ASTMangler.h"
+#include "swift/AST/ASTVisitor.h"
+#include "swift/AST/Module.h"
+#include "swift/AST/ParameterList.h"
+#include "swift/Basic/LLVM.h"
+#include "swift/IRGen/Linking.h"
+#include "swift/SIL/FormalLinkage.h"
+#include "swift/SIL/SILDeclRef.h"
+#include "swift/SIL/SILWitnessTable.h"
+#include "swift/SIL/TypeLowering.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace swift::irgen;
+using StringSet = llvm::StringSet<>;
+
+namespace swift {
+namespace tbdgen {
+
+class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
+public:
+ StringSet &Symbols;
+ const llvm::Triple &Triple;
+ const UniversalLinkageInfo &UniversalLinkInfo;
+ ModuleDecl *SwiftModule;
+ StringRef InstallName;
+
+private:
+ bool FileHasEntryPoint = false;
+ bool SILSerializeWitnessTables;
+
+ bool InsideAbstractStorageDecl = false;
+
+ void addSymbol(StringRef name) {
+ auto isNewValue = Symbols.insert(name).second;
+ (void)isNewValue;
+ assert(isNewValue && "already inserted");
+ }
+
+ void addSymbol(SILDeclRef declRef);
+
+ void addSymbol(LinkEntity entity) {
+ auto linkage =
+ LinkInfo::get(UniversalLinkInfo, SwiftModule, entity, ForDefinition);
+
+ auto externallyVisible =
+ llvm::GlobalValue::isExternalLinkage(linkage.getLinkage()) &&
+ linkage.getVisibility() != llvm::GlobalValue::HiddenVisibility;
+
+ if (externallyVisible)
+ addSymbol(linkage.getName());
+ }
+
+ void addConformances(DeclContext *DC);
+
+public:
+ TBDGenVisitor(StringSet &symbols, const llvm::Triple &triple,
+ const UniversalLinkageInfo &universalLinkInfo,
+ ModuleDecl *swiftModule, bool silSerializeWitnessTables,
+ StringRef installName)
+ : Symbols(symbols), Triple(triple), UniversalLinkInfo(universalLinkInfo),
+ SwiftModule(swiftModule), InstallName(installName),
+ SILSerializeWitnessTables(silSerializeWitnessTables) {}
+
+ void setFileHasEntryPoint(bool hasEntryPoint) {
+ FileHasEntryPoint = hasEntryPoint;
+
+ if (hasEntryPoint)
+ addSymbol("main");
+ }
+
+ void visitMembers(Decl *D) {
+ SmallVector<Decl *, 4> members;
+ auto addMembers = [&](DeclRange range) {
+ for (auto member : range)
+ members.push_back(member);
+ };
+ if (auto ED = dyn_cast<ExtensionDecl>(D))
+ addMembers(ED->getMembers());
+ else if (auto NTD = dyn_cast<NominalTypeDecl>(D))
+ addMembers(NTD->getMembers());
+ else if (auto ASD = dyn_cast<AbstractStorageDecl>(D))
+ ASD->getAllAccessorFunctions(members);
+
+ for (auto member : members) {
+ ASTVisitor::visit(member);
+ }
+ }
+
+ void visitPatternBindingDecl(PatternBindingDecl *PBD);
+
+ void visitValueDecl(ValueDecl *VD);
+
+ void visitAbstractFunctionDecl(AbstractFunctionDecl *AFD);
+
+ void visitTypeAliasDecl(TypeAliasDecl *TAD) {
+ // any information here is encoded elsewhere
+ }
+
+ void visitNominalTypeDecl(NominalTypeDecl *NTD);
+
+ void visitClassDecl(ClassDecl *CD);
+
+ void visitConstructorDecl(ConstructorDecl *CD);
+
+ void visitExtensionDecl(ExtensionDecl *ED);
+
+ void visitProtocolDecl(ProtocolDecl *PD);
+
+ void visitAbstractStorageDecl(AbstractStorageDecl *ASD);
+
+ void visitVarDecl(VarDecl *VD);
+
+ void visitDecl(Decl *D) { visitMembers(D); }
+};
+} // end namespace tbdgen
+} // end namespace swift
+
+#endif
diff --git a/stdlib/public/SDK/Foundation/DateComponents.swift b/stdlib/public/SDK/Foundation/DateComponents.swift
index 1dac171..c7ff74b 100644
--- a/stdlib/public/SDK/Foundation/DateComponents.swift
+++ b/stdlib/public/SDK/Foundation/DateComponents.swift
@@ -411,24 +411,22 @@
}
public func encode(to encoder: Encoder) throws {
- // TODO: Replace all with encodeIfPresent, when added.
var container = encoder.container(keyedBy: CodingKeys.self)
- if self.calendar != nil { try container.encode(self.calendar!, forKey: .calendar) }
- if self.timeZone != nil { try container.encode(self.timeZone!, forKey: .timeZone) }
- if self.era != nil { try container.encode(self.era!, forKey: .era) }
- if self.year != nil { try container.encode(self.year!, forKey: .year) }
- if self.month != nil { try container.encode(self.month!, forKey: .month) }
- if self.day != nil { try container.encode(self.day!, forKey: .day) }
- if self.hour != nil { try container.encode(self.hour!, forKey: .hour) }
- if self.minute != nil { try container.encode(self.minute!, forKey: .minute) }
- if self.second != nil { try container.encode(self.second!, forKey: .second) }
- if self.nanosecond != nil { try container.encode(self.nanosecond!, forKey: .nanosecond) }
-
- if self.weekday != nil { try container.encode(self.weekday!, forKey: .weekday) }
- if self.weekdayOrdinal != nil { try container.encode(self.weekdayOrdinal!, forKey: .weekdayOrdinal) }
- if self.quarter != nil { try container.encode(self.quarter!, forKey: .quarter) }
- if self.weekOfMonth != nil { try container.encode(self.weekOfMonth!, forKey: .weekOfMonth) }
- if self.weekOfYear != nil { try container.encode(self.weekOfYear!, forKey: .weekOfYear) }
- if self.yearForWeekOfYear != nil { try container.encode(self.yearForWeekOfYear!, forKey: .yearForWeekOfYear) }
+ try container.encodeIfPresent(self.calendar, forKey: .calendar)
+ try container.encodeIfPresent(self.timeZone, forKey: .timeZone)
+ try container.encodeIfPresent(self.era, forKey: .era)
+ try container.encodeIfPresent(self.year, forKey: .year)
+ try container.encodeIfPresent(self.month, forKey: .month)
+ try container.encodeIfPresent(self.day, forKey: .day)
+ try container.encodeIfPresent(self.hour, forKey: .hour)
+ try container.encodeIfPresent(self.minute, forKey: .minute)
+ try container.encodeIfPresent(self.second, forKey: .second)
+ try container.encodeIfPresent(self.nanosecond, forKey: .nanosecond)
+ try container.encodeIfPresent(self.weekday, forKey: .weekday)
+ try container.encodeIfPresent(self.weekdayOrdinal, forKey: .weekdayOrdinal)
+ try container.encodeIfPresent(self.quarter, forKey: .quarter)
+ try container.encodeIfPresent(self.weekOfMonth, forKey: .weekOfMonth)
+ try container.encodeIfPresent(self.weekOfYear, forKey: .weekOfYear)
+ try container.encodeIfPresent(self.yearForWeekOfYear, forKey: .yearForWeekOfYear)
}
}
diff --git a/stdlib/public/SwiftShims/RefCount.h b/stdlib/public/SwiftShims/RefCount.h
index 29ec54a..277fd1b 100644
--- a/stdlib/public/SwiftShims/RefCount.h
+++ b/stdlib/public/SwiftShims/RefCount.h
@@ -564,10 +564,12 @@
else
return doDecrementStrongExtraRefCount<DontClearPinnedFlag>(dec);
}
-
+ // Returns the old reference count before the increment.
LLVM_ATTRIBUTE_ALWAYS_INLINE
- void incrementUnownedRefCount(uint32_t inc) {
- setUnownedRefCount(getUnownedRefCount() + inc);
+ uint32_t incrementUnownedRefCount(uint32_t inc) {
+ uint32_t old = getUnownedRefCount();
+ setUnownedRefCount(old + inc);
+ return old;
}
LLVM_ATTRIBUTE_ALWAYS_INLINE
@@ -757,6 +759,9 @@
LLVM_ATTRIBUTE_NOINLINE
bool tryIncrementNonAtomicSlow(RefCountBits oldbits);
+ LLVM_ATTRIBUTE_NOINLINE
+ void incrementUnownedSlow(uint32_t inc);
+
public:
enum Initialized_t { Initialized };
@@ -1139,8 +1144,12 @@
newbits = oldbits;
assert(newbits.getUnownedRefCount() != 0);
- newbits.incrementUnownedRefCount(inc);
- // FIXME: overflow check?
+ uint32_t oldValue = newbits.incrementUnownedRefCount(inc);
+
+ // Check overflow and use the side table on overflow.
+ if (newbits.getUnownedRefCount() != oldValue + inc)
+ return incrementUnownedSlow(inc);
+
} while (!refCounts.compare_exchange_weak(oldbits, newbits,
std::memory_order_relaxed));
}
@@ -1152,8 +1161,12 @@
auto newbits = oldbits;
assert(newbits.getUnownedRefCount() != 0);
- newbits.incrementUnownedRefCount(inc);
- // FIXME: overflow check?
+ uint32_t oldValue = newbits.incrementUnownedRefCount(inc);
+
+ // Check overflow and use the side table on overflow.
+ if (newbits.getUnownedRefCount() != oldValue + inc)
+ return incrementUnownedSlow(inc);
+
refCounts.store(newbits, std::memory_order_relaxed);
}
diff --git a/stdlib/public/core/DoubleWidth.swift.gyb b/stdlib/public/core/DoubleWidth.swift.gyb
index 0e95abb..2368977 100644
--- a/stdlib/public/core/DoubleWidth.swift.gyb
+++ b/stdlib/public/core/DoubleWidth.swift.gyb
@@ -314,8 +314,8 @@
let initialOffset = q.leadingZeroBitCount +
(DoubleWidth.bitWidth - rhs.leadingZeroBitCount) - 1
- // TODO(performance): Use &>> instead here?
// Start with remainder capturing the high bits of q.
+ // (These need to be smart shifts, as initialOffset can be > q.bitWidth)
var r = q >> Magnitude(DoubleWidth.bitWidth - initialOffset)
q <<= Magnitude(initialOffset)
@@ -396,8 +396,9 @@
let mid2 = sum(b.carry, c.carry, d.partial)
let low = DoubleWidth<Low>((mid1.partial, a.partial))
- let high = DoubleWidth(
- (High(mid2.carry + d.carry), mid1.carry + mid2.partial))
+ let high = DoubleWidth((
+ High(mid2.carry + d.carry), mid1.carry + mid2.partial
+ ))
if isNegative {
let (lowComplement, overflow) = (~low).addingReportingOverflow(1)
@@ -433,6 +434,7 @@
return
}
+ // Shift is larger than this type's bit width.
if rhs._storage.high != (0 as High) ||
rhs._storage.low >= DoubleWidth.bitWidth
{
@@ -476,32 +478,30 @@
}
public static func &<<=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
+ // Need to use smart shifts here, since rhs can be > Base.bitWidth
let rhs = rhs & DoubleWidth(DoubleWidth.bitWidth - 1)
lhs._storage.high <<= High(rhs._storage.low)
- if Base.bitWidth > rhs._storage.low {
- lhs._storage.high |= High(truncatingIfNeeded: lhs._storage.low >>
- (numericCast(Base.bitWidth) - rhs._storage.low))
- } else {
- lhs._storage.high |= High(truncatingIfNeeded: lhs._storage.low <<
- (rhs._storage.low - numericCast(Base.bitWidth)))
- }
+
+ let lowInHigh = Base.bitWidth > rhs._storage.low
+ ? lhs._storage.low >> (numericCast(Base.bitWidth) - rhs._storage.low)
+ : lhs._storage.low << (rhs._storage.low - numericCast(Base.bitWidth))
+ lhs._storage.high |= High(truncatingIfNeeded: lowInHigh)
+
lhs._storage.low <<= rhs._storage.low
}
public static func &>>=(lhs: inout DoubleWidth, rhs: DoubleWidth) {
+ // Need to use smart shifts here, since rhs can be > Base.bitWidth
let rhs = rhs & DoubleWidth(DoubleWidth.bitWidth - 1)
lhs._storage.low >>= rhs._storage.low
- if Base.bitWidth > rhs._storage.low {
- lhs._storage.low |= Low(
- truncatingIfNeeded:
- lhs._storage.high << (numericCast(Base.bitWidth) - rhs._storage.low))
- } else {
- lhs._storage.low |= Low(
- truncatingIfNeeded: lhs._storage.high >>
- (rhs._storage.low - numericCast(Base.bitWidth)))
- }
+
+ let highInLow = Base.bitWidth > rhs._storage.low
+ ? lhs._storage.high << (numericCast(Base.bitWidth) - rhs._storage.low)
+ : lhs._storage.high >> (rhs._storage.low - numericCast(Base.bitWidth))
+ lhs._storage.low |= Low(truncatingIfNeeded: highInLow)
+
lhs._storage.high >>= High(truncatingIfNeeded: rhs._storage.low)
}
@@ -573,8 +573,10 @@
@_transparent
public var byteSwapped: DoubleWidth {
- return DoubleWidth((High(truncatingIfNeeded: low.byteSwapped),
- Low(truncatingIfNeeded: high.byteSwapped)))
+ return DoubleWidth((
+ High(truncatingIfNeeded: low.byteSwapped),
+ Low(truncatingIfNeeded: high.byteSwapped)
+ ))
}
}
diff --git a/stdlib/public/core/FloatingPointTypes.swift.gyb b/stdlib/public/core/FloatingPointTypes.swift.gyb
index 6a2ad9a..c02ba7d 100644
--- a/stdlib/public/core/FloatingPointTypes.swift.gyb
+++ b/stdlib/public/core/FloatingPointTypes.swift.gyb
@@ -1403,8 +1403,8 @@
/// Creates a value that exactly represents the given integer.
///
- /// If the given integer is outside the representable range of this type, the
- /// result is `nil`.
+ /// If the given integer is outside the representable range of this type or
+ /// can't be represented exactly, the result is `nil`.
///
/// - Parameter value: The integer to represent as a floating-point value.
% if srcBits < SignificandBitCount:
diff --git a/stdlib/public/core/Integers.swift.gyb b/stdlib/public/core/Integers.swift.gyb
index a132b27..8243f8b 100644
--- a/stdlib/public/core/Integers.swift.gyb
+++ b/stdlib/public/core/Integers.swift.gyb
@@ -818,11 +818,11 @@
///
/// - Parameter rhs: The value to add to this value.
/// - Returns: A tuple containing the result of the addition along with a
- /// flag indicating whether overflow occurred. If the `overflow` component
- /// is `false`, the `partialValue` component contains the entire sum. If
- /// the `overflow` component is `true`, an overflow occurred and the
- /// `partialValue` component contains the truncated sum of this value and
- /// `rhs`.
+ /// Boolean value indicating whether overflow occurred. If the `overflow`
+ /// component is `false`, the `partialValue` component contains the entire
+ /// sum. If the `overflow` component is `true`, an overflow occurred and
+ /// the `partialValue` component contains the truncated sum of this value
+ /// and `rhs`.
""",
'-': """\
/// Returns the difference of this value and the given value along with a
@@ -842,7 +842,7 @@
///
/// - Parameter rhs: The value to multiply by this value.
/// - Returns: A tuple containing the result of the multiplication along with
- /// a flag indicating whether overflow occurred. If the `overflow`
+ /// a Boolean value indicating whether overflow occurred. If the `overflow`
/// component is `false`, the `partialValue` component contains the entire
/// product. If the `overflow` component is `true`, an overflow
/// occurred and the `partialValue` component contains the truncated
@@ -857,25 +857,25 @@
///
/// - Parameter rhs: The value to divide this value by.
/// - Returns: A tuple containing the result of the division along with a
- /// flag indicating whether overflow occurred. If the `overflow` component
- /// is `false`, the `partialValue` component contains the entire quotient.
- /// If the `overflow` component is `true`, an overflow occurred and
- /// the `partialValue` component contains the truncated quotient.
+ /// Boolean value indicating whether overflow occurred. If the `overflow`
+ /// component is `false`, the `partialValue` component contains the entire
+ /// quotient. If the `overflow` component is `true`, an overflow occurred
+ /// and the `partialValue` component contains the truncated quotient.
""",
'%': """\
// FIXME(integers): the comment is for division instead of remainder
- /// Returns the remainder of dividing this value by the given value along with
- /// a flag indicating whether overflow occurred in the operation.
+ /// Returns the remainder of dividing this value by the given value along
+ /// with a flag indicating whether overflow occurred in the operation.
///
/// Dividing by zero is not an error when using this method. For a value `x`,
/// the result of `x.dividedReportingOverflow(by: 0)` is `(x, true)`.
///
/// - Parameter rhs: The value to divide this value by.
/// - Returns: A tuple containing the result of the division along with a
- /// flag indicating whether overflow occurred. If the `overflow` component
- /// is `false`, the `partialValue` component contains the entire quotient.
- /// If the `overflow` component is `true`, an overflow occurred and
- /// the `partialValue` component contains the truncated quotient.
+ /// Boolean value indicating whether overflow occurred. If the `overflow`
+ /// component is `false`, the `partialValue` component contains the entire
+ /// quotient. If the `overflow` component is `true`, an overflow occurred
+ /// and the `partialValue` component contains the truncated quotient.
""",
}
return comments[operator]
@@ -990,7 +990,7 @@
/// let y = Int8(exactly: 1_000)
/// // y == nil
///
- /// - Parameter source: A value to convert to this type of integer.
+ /// - Parameter source: A value to convert to this type.
init?<T : BinaryInteger>(exactly source: T)
// FIXME(ABI)#44 (Recursive Protocol Constraints): should be just
@@ -1098,6 +1098,23 @@
}
extension SignedNumeric {
+ /// Returns the additive inverse of the specified value.
+ ///
+ /// The negation operator (prefix `-`) returns the additive inverse of its
+ /// argument.
+ ///
+ /// let x = 21
+ /// let y = -x
+ /// // y == -21
+ ///
+ /// The resulting value must be representable in the same type as the
+ /// argument. In particular, negating a signed, fixed-width integer type's
+ /// minimum results in a value that cannot be represented.
+ ///
+ /// let z = -Int8.min
+ /// // Overflow error
+ ///
+ /// - Returns: The additive inverse of the argument.
@_transparent
public static prefix func - (_ operand: Self) -> Self {
var result = operand
@@ -1105,6 +1122,14 @@
return result
}
+ /// Replaces this value with its additive inverse.
+ ///
+ /// The following example uses the `negate()` method to negate the value of
+ /// an integer `x`:
+ ///
+ /// var x = 21
+ /// x.negate()
+ /// // x == -21
@_transparent
public mutating func negate() {
self = 0 - self
@@ -1140,6 +1165,17 @@
}
extension Numeric {
+ /// Returns the given number unchanged.
+ ///
+ /// You can use the unary plus operator (`+`) to provide symmetry in your
+ /// code for positive numbers when also using the unary minus operator.
+ ///
+ /// let x = -21
+ /// let y = +21
+ /// // x == -21
+ /// // y == 21
+ ///
+ /// - Returns: The given argument without any changes.
@_transparent
public static prefix func + (x: Self) -> Self {
return x
@@ -1433,11 +1469,13 @@
// FIXME: Should be `Words : Collection where Words.Element == UInt`
// See <rdar://problem/31798916> for why it isn't.
- /// A type that represents the words of a binary integer.
- /// Must implement the `Collection` protocol with an `UInt` element type.
+ /// A type that represents the words of a binary integer.
+ ///
+ /// The `Words` type must conform to the `Collection` protocol with an
+ /// `Element` type of `UInt`.
associatedtype Words : Sequence where Words.Element == UInt
- /// Returns a collection containing the words of this value's binary
+ /// A collection containing the words of this value's binary
/// representation, in order from the least significant to most significant.
///
/// Negative values are returned in two's complement representation,
@@ -1543,6 +1581,20 @@
self = 0
}
+ /// Creates an integer from the given floating-point value, if it can be
+ /// represented exactly.
+ ///
+ /// If the value passed as `source` is not representable exactly, the result
+ /// is `nil`. In the following example, the constant `x` is successfully
+ /// created from a value of `21.0`, while the attempt to initialize the
+ /// constant `y` from `21.5` fails:
+ ///
+ /// let x = Int(exactly: 21.0)
+ /// // x == Optional(21)
+ /// let y = Int(exactly: 21.5)
+ /// // y == nil
+ ///
+ /// - Parameter source: A floating-point value to convert to an integer.
public init?<T : BinaryFloatingPoint>(exactly source: T) {
// FIXME(integers): implement
fatalError()
@@ -1885,10 +1937,10 @@
/// the right shift operator (`<<`), both of which are available to any type
/// that conforms to the `FixedWidthInteger` protocol.
///
-/// The next example declares the generic `squared` function, which accepts an
+/// The next example declares a generic `squared` function, which accepts an
/// instance `x` of any fixed-width integer type. The function uses the
-/// `multipliedReportingOverflow(by:)` method to multiply `x` by itself and check
-/// whether the result is too large to represent in the same type.
+/// `multipliedReportingOverflow(by:)` method to multiply `x` by itself and
+/// check whether the result is too large to represent in the same type.
///
/// func squared<T: FixedWidthInteger>(_ x: T) -> T? {
/// let (result, overflow) = x.multipliedReportingOverflow(by: x)
@@ -1950,12 +2002,12 @@
% end
/// Returns a tuple containing the high and low parts of the result of
- /// multiplying its arguments.
+ /// multiplying this value by the given value.
///
/// Use this method to calculate the full result of a product that would
/// otherwise overflow. Unlike traditional truncating multiplication, the
- /// `multipliedFullWidth(by:)` method returns an instance of DoubleWith<Self>,
- /// containing both the `high` and `low` parts of the product of `self` and
+ /// `multipliedFullWidth(by:)` method returns a tuple
+ /// containing both the `high` and `low` parts of the product of this value and
/// `other`. The following example uses this method to multiply two `UInt8`
/// values that normally overflow when multiplied:
///
@@ -1974,27 +2026,24 @@
/// let z = UInt16(result.high) << 8 | UInt16(result.low)
/// // z == 2000
///
- /// - Parameters:
- /// - other: A value to multiply `self` by.
+ /// - Parameter other: The value to multiply this value by.
/// - Returns: A tuple containing the high and low parts of the result of
- /// multiplying `self` and `other`.
- // FIXME(integers): figure out how to return DoubleWidth<Self> or correct the
- // doc comment
+ /// multiplying this value and `other`.
+ // FIXME(integers): figure out how to return DoubleWidth<Self>
func multipliedFullWidth(by other: Self) -> (high: Self, low: Self.Magnitude)
/// Returns a tuple containing the quotient and remainder of dividing the
- /// first argument by `self`.
+ /// given value by this value.
///
/// The resulting quotient must be representable within the bounds of the
- /// type. If the quotient of dividing `dividend` by `self` is too large to
- /// represent in the type, a runtime error may occur.
+ /// type. If the quotient of dividing `dividend` by this value is too large
+ /// to represent in the type, a runtime error may occur.
///
- /// - Parameters:
- /// - dividend: A DoubleWidth<Self> value containing the high and low parts
- /// of a double-width integer. The `high` component of the value carries
- /// the sign, if the type is signed.
+ /// - Parameter dividend: A tuple containing the high and low parts of a
+ /// double-width integer. The `high` component of the value carries the
+ /// sign, if the type is signed.
/// - Returns: A tuple containing the quotient and remainder of `dividend`
- /// divided by `self`.
+ /// divided by this value.
func dividingFullWidth(_ dividend: (high: Self, low: Self.Magnitude))
-> (quotient: Self, remainder: Self)
@@ -2003,7 +2052,7 @@
/// The number of bits equal to 1 in this value's binary representation.
///
/// For example, in a fixed-width integer type with a `bitWidth` value of 8,
- /// the number 31 has five bits equal to 1.
+ /// the number *31* has five bits equal to *1*.
///
/// let x: Int8 = 0b0001_1111
/// // x == 31
@@ -2013,7 +2062,7 @@
/// The number of leading zeros in this value's binary representation.
///
/// For example, in a fixed-width integer type with a `bitWidth` value of 8,
- /// the number 31 has three leading zeros.
+ /// the number *31* has three leading zeros.
///
/// let x: Int8 = 0b0001_1111
/// // x == 31
@@ -2082,6 +2131,7 @@
@available(swift, deprecated: 3.1, obsoleted: 4.0, message: "Use 0")
public static var allZeros: Self { return 0 }
+ /// The number of bits in the binary representation of this value.
@_inlineable
public var bitWidth: Int { return Self.bitWidth }
@@ -2154,6 +2204,23 @@
//===----------------------------------------------------------------------===//
extension FixedWidthInteger {
+ /// Returns the inverse of the bits set in the argument.
+ ///
+ /// The bitwise NOT operator (`~`) is a prefix operator that returns a value
+ /// in which all the bits of its argument are flipped: Bits that are `1` in
+ /// the argument are `0` in the result, and bits that are `0` in the argument
+ /// are `1` in the result. This is equivalent to the inverse of a set. For
+ /// example:
+ ///
+ /// let x: UInt8 = 5 // 0b00000101
+ /// let notX = ~x // 0b11111010
+ ///
+ /// Performing a bitwise NOT operation on 0 returns a value with every bit
+ /// set to `1`.
+ ///
+ /// let allOnes = ~UInt8.min // 0b11111111
+ ///
+ /// - Complexity: O(1).
@_transparent
public static prefix func ~ (x: Self) -> Self {
return 0 &- x &- 1
@@ -2215,6 +2282,26 @@
}
extension FixedWidthInteger {
+ /// Creates a new instance with the representable value that's closest to the
+ /// given integer.
+ ///
+ /// If the value passed as `source` is greater than the maximum representable
+ /// value in this type, the result is the type's `max` value. If `source` is
+ /// less than the smallest representable value in this type, the result is
+ /// the type's `min` value.
+ ///
+ /// In this example, `x` is initialized as an `Int8` instance by clamping
+ /// `500` to the range `-128...127`, and `y` is initialized as a `UInt`
+ /// instance by clamping `-500` to the range `0...UInt.max`.
+ ///
+ /// let x = Int8(clamping: 500)
+ /// // x == 127
+ /// // x == Int8.max
+ ///
+ /// let y = UInt(clamping: -500)
+ /// // y == 0
+ ///
+ /// - Parameter source: An integer to convert to this type.
@_semantics("optimize.sil.specialize.generic.partial.never")
public init<Other: BinaryInteger>(clamping source: Other) {
if _slowPath(source < Self.min) {
@@ -2261,6 +2348,42 @@
}
% end
+ /// Creates a new instance from the bit pattern of the given instance by
+ /// sign-extending or truncating to fit this type.
+ ///
+ /// When the bit width of `T` (the type of `source`) is equal to or greater
+ /// than this type's bit width, the result is the truncated
+ /// least-significant bits of `source`. For example, when converting a
+ /// 16-bit value to an 8-bit type, only the lower 8 bits of `source` are
+ /// used.
+ ///
+ /// let p: Int16 = -500
+ /// // 'p' has a binary representation of 11111110_00001100
+ /// let q = Int8(extendingOrTruncating: p)
+ /// // q == 12
+ /// // 'q' has a binary representation of 00001100
+ ///
+ /// When the bit width of `T` is less than this type's bit width, the result
+ /// is *sign-extended* to fill the remaining bits. That is, if `source` is
+ /// negative, the result is padded with ones; otherwise, the result is
+ /// padded with zeros.
+ ///
+ /// let u: Int8 = 21
+ /// // 'u' has a binary representation of 00010101
+ /// let v = Int16(extendingOrTruncating: u)
+ /// // v == 21
+ /// // 'v' has a binary representation of 00000000_00010101
+ ///
+ /// let w: Int8 = -21
+ /// // 'w' has a binary representation of 11101011
+ /// let x = Int16(extendingOrTruncating: w)
+ /// // x == -21
+ /// // 'x' has a binary representation of 11111111_11101011
+ /// let y = UInt16(extendingOrTruncating: w)
+ /// // y == 65515
+ /// // 'y' has a binary representation of 11111111_11101011
+ ///
+ /// - Parameter source: An integer to convert to this type.
@inline(__always)
public init<T : BinaryInteger>(truncatingIfNeeded source: T) {
if Self.bitWidth <= ${word_bits} {
@@ -2373,6 +2496,21 @@
self.init(truncatingIfNeeded: source)
}
+ /// Creates a new instance from the given integer, if it can be represented
+ /// exactly.
+ ///
+ /// If the value passed as `source` is not representable exactly, the result
+ /// is `nil`. In the following example, the constant `x` is successfully
+ /// created from a value of `100`, while the attempt to initialize the
+ /// constant `y` from `1_000` fails because the `Int8` type can represent
+ /// `127` at maximum:
+ ///
+ /// let x = Int8(exactly: 100)
+ /// // x == Optional(100)
+ /// let y = Int8(exactly: 1_000)
+ /// // y == nil
+ ///
+ /// - Parameter source: A value to convert to this type of integer.
@_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init?<T : BinaryInteger>(exactly source: T) {
@@ -2454,6 +2592,21 @@
self.init(truncatingIfNeeded: source)
}
+ /// Creates a new instance from the given integer, if it can be represented
+ /// exactly.
+ ///
+ /// If the value passed as `source` is not representable exactly, the result
+ /// is `nil`. In the following example, the constant `x` is successfully
+ /// created from a value of `100`, while the attempt to initialize the
+ /// constant `y` from `1_000` fails because the `Int8` type can represent
+ /// `127` at maximum:
+ ///
+ /// let x = Int8(exactly: 100)
+ /// // x == Optional(100)
+ /// let y = Int8(exactly: 1_000)
+ /// // y == nil
+ ///
+ /// - Parameter source: A value to convert to this type of integer.
@_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init?<T : BinaryInteger>(exactly source: T) {
@@ -2557,6 +2710,26 @@
#if !os(Windows) && (arch(i386) || arch(x86_64))
% end
+ /// Creates an integer from the given floating-point value, rounding toward
+ /// zero.
+ ///
+ /// Any fractional part of the value passed as `source` is removed, rounding
+ /// the value toward zero.
+ ///
+ /// let x = Int(21.5)
+ /// // x == 21
+ /// let y = Int(-21.5)
+ /// // y == -21
+ ///
+ /// If `source` is outside the bounds of this type after rounding toward
+ /// zero, a runtime error may occur.
+ ///
+ /// let z = UInt(-21.5)
+ /// // Error: ...the result would be less than UInt.min
+ ///
+ /// - Parameter source: A floating-point value to convert to an integer.
+ /// `source` must be representable in this type after rounding toward
+ /// zero.
@_transparent
public init(_ source: ${FloatType}) {
_precondition(source.isFinite,
@@ -2568,6 +2741,20 @@
self._value = Builtin.fpto${u}i_FPIEEE${FloatBits}_${BuiltinName}(source._value)
}
+ /// Creates an integer from the given floating-point value, if it can be
+ /// represented exactly.
+ ///
+ /// If the value passed as `source` is not representable exactly, the result
+ /// is `nil`. In the following example, the constant `x` is successfully
+ /// created from a value of `21.0`, while the attempt to initialize the
+ /// constant `y` from `21.5` fails:
+ ///
+ /// let x = Int(exactly: 21.0)
+ /// // x == Optional(21)
+ /// let y = Int(exactly: 21.5)
+ /// // y == nil
+ ///
+ /// - Parameter source: A floating-point value to convert to an integer.
@_transparent
public init?(exactly source: ${FloatType}) {
self._value = Builtin.fpto${u}i_FPIEEE${FloatBits}_${BuiltinName}(source._value)
@@ -2597,6 +2784,7 @@
// unwrapped. <rdar://problem/29004429>
// See corresponding definitions in the FixedWidthInteger extension.
% for x in binaryArithmetic['Numeric'] + binaryArithmetic["BinaryInteger"][:1]:
+${assignmentOperatorComment(x.operator, True)}
@_transparent
public static func ${x.operator}=(_ lhs: inout ${Self}, _ rhs: ${Self}) {
% if x.kind == '/':
@@ -2628,6 +2816,7 @@
% for x in chain(*binaryArithmetic.values()):
+${overflowOperationComment(x.operator)}
@_transparent
public func ${x.name}ReportingOverflow(
${x.firstArg} other: ${Self}
@@ -2660,6 +2849,7 @@
}
% end
+${assignmentOperatorComment('%', True)}
@_transparent
public static func %=(_ lhs: inout ${Self}, _ rhs: ${Self}) {
// No LLVM primitives for checking overflow of division
@@ -2694,6 +2884,7 @@
}
% for x in binaryBitwise:
+${assignmentOperatorComment(x.operator, True)}
@_transparent
public static func ${x.operator}=(_ lhs: inout ${Self}, _ rhs: ${Self}) {
lhs = ${Self}(Builtin.${x.llvmName}_Int${bits}(lhs._value, rhs._value))
@@ -2712,9 +2903,26 @@
% end
+ /// The number of bits used for the underlying binary representation of
+ /// values of this type.
+ ///
+% if self_type.is_word:
+ /// The bit width of ${Article.lower()} `${Self}` instance is 32 on 32-bit
+ /// platforms and 64 on 64-bit platforms.
+% else:
+ /// The bit width of ${Article.lower()} `${Self}` instance is ${bits}.
+% end
@_transparent
public static var bitWidth : Int { return ${bits} }
+ /// The number of leading zeros in this value's binary representation.
+ ///
+ /// For example, in an integer type with a `bitWidth` value of 8,
+ /// the number *31* has three leading zeros.
+ ///
+ /// let x: Int8 = 0b0001_1111
+ /// // x == 31
+ /// // x.leadingZeroBitCount == 3
@_transparent
public var leadingZeroBitCount: Int {
return Int(
@@ -2723,6 +2931,13 @@
)._lowWord._value)
}
+ /// The number of trailing zeros in this value's binary representation.
+ ///
+ /// For example, the number *-8* has three trailing zeros.
+ ///
+ /// let x = Int8(bitPattern: 0b1111_1000)
+ /// // x == -8
+ /// // x.trailingZeroBitCount == 3
@_transparent
public var trailingZeroBitCount: Int {
return Int(
@@ -2731,6 +2946,14 @@
)._lowWord._value)
}
+ /// The number of bits equal to 1 in this value's binary representation.
+ ///
+ /// For example, in a fixed-width integer type with a `bitWidth` value of 8,
+ /// the number *31* has five bits equal to *1*.
+ ///
+ /// let x: Int8 = 0b0001_1111
+ /// // x == 31
+ /// // x.nonzeroBitCount == 5
@_transparent
public var nonzeroBitCount: Int {
return Int(
@@ -2777,6 +3000,13 @@
}
}
+ /// A collection containing the words of this value's binary
+ /// representation, in order from the least significant to most significant.
+% if signed:
+ ///
+ /// Negative values are returned in two's complement representation,
+ /// regardless of the type's underlying implementation.
+% end
@_transparent
public var words: Words {
return Words(self)
@@ -2802,6 +3032,21 @@
public typealias Magnitude = ${U}${Self}
% if signed:
+ /// The magnitude of this value.
+ ///
+ /// For any numeric value `x`, `x.magnitude` is the absolute value of `x`.
+ /// You can use the `magnitude` property in operations that are simpler to
+ /// implement in terms of unsigned values, such as printing the value of an
+ /// integer, which is just printing a '-' character in front of an absolute
+ /// value.
+ ///
+ /// let x = -200
+ /// // x.magnitude == 200
+ ///
+ /// The global `abs(_:)` function provides more familiar syntax when you need
+ /// to find an absolute value. In addition, because `abs(_:)` always returns
+ /// a value of the same type, even in a generic context, using the function
+ /// instead of the `magnitude` property is encouraged.
@_transparent
public var magnitude: U${Self} {
let base = U${Self}(_value)
@@ -2810,6 +3055,34 @@
% end
% dbits = bits*2
+ /// Returns a tuple containing the high and low parts of the result of
+ /// multiplying this value by the given value.
+ ///
+ /// Use this method to calculate the full result of a product that would
+ /// otherwise overflow. Unlike traditional truncating multiplication, the
+ /// `multipliedFullWidth(by:)` method returns a tuple
+ /// containing both the `high` and `low` parts of the product of this value and
+ /// `other`. The following example uses this method to multiply two `UInt8`
+ /// values that normally overflow when multiplied:
+ ///
+ /// let x: UInt8 = 100
+ /// let y: UInt8 = 20
+ /// let result = x.multipliedFullWidth(by: y)
+ /// // result.high == 0b00000111
+ /// // result.low == 0b11010000
+ ///
+ /// The product of `x` and `y` is 2000, which is too large to represent in a
+ /// `UInt8` instance. The `high` and `low` properties of the `result` value
+ /// represent 2000 when concatenated to form a double-width integer; that
+ /// is, using `result.high` as the high byte and `result.low` as the low byte
+ /// of a `UInt16` instance.
+ ///
+ /// let z = UInt16(result.high) << 8 | UInt16(result.low)
+ /// // z == 2000
+ ///
+ /// - Parameter other: The value to multiply this value by.
+ /// - Returns: A tuple containing the high and low parts of the result of
+ /// multiplying this value and `other`.
// FIXME(integers): tests
public func multipliedFullWidth(by other: ${Self})
-> (high: ${Self}, low: ${Self}.Magnitude) {
@@ -2830,6 +3103,18 @@
% end
}
+ /// Returns a tuple containing the quotient and remainder of dividing the
+ /// given value by this value.
+ ///
+ /// The resulting quotient must be representable within the bounds of the
+ /// type. If the quotient of dividing `dividend` by this value is too large
+ /// to represent in the type, a runtime error may occur.
+ ///
+ /// - Parameter dividend: A tuple containing the high and low parts of a
+ /// double-width integer. The `high` component of the value carries the
+ /// sign, if the type is signed.
+ /// - Returns: A tuple containing the quotient and remainder of `dividend`
+ /// divided by this value.
// FIXME(integers): tests
public func dividingFullWidth(
_ dividend: (high: ${Self}, low: ${Self}.Magnitude)
@@ -2912,6 +3197,11 @@
@available(swift, obsoleted: 4)
public static var _sizeInBytes: ${Self} { return ${bits}/8 }
+ /// Returns `-1` if this value is negative and `1` if it's positive;
+ /// otherwise, `0`.
+ ///
+ /// - Returns: The sign of this number, expressed as an integer of the same
+ /// type.
@inline(__always)
public func signum() -> ${Self} {
let isPositive = ${Self}(Builtin.zext_Int1_Int${bits}(
@@ -2922,6 +3212,26 @@
%# end of concrete type: ${Self}
extension ${Self} {
+ /// Creates an integer from the given floating-point value, rounding toward
+ /// zero.
+ ///
+ /// Any fractional part of the value passed as `source` is removed, rounding
+ /// the value toward zero.
+ ///
+ /// let x = Int(21.5)
+ /// // x == 21
+ /// let y = Int(-21.5)
+ /// // y == -21
+ ///
+ /// If `source` is outside the bounds of this type after rounding toward
+ /// zero, a runtime error may occur.
+ ///
+ /// let z = UInt(-21.5)
+ /// // Error: ...the result would be less than UInt.min
+ ///
+ /// - Parameter source: A floating-point value to convert to an integer.
+ /// `source` must be representable in this type after rounding toward
+ /// zero.
// FIXME(integers): implement me in a less terrible way
public init<T : BinaryFloatingPoint>(_ source: T) {
% for (FloatType, FloatBits) in [
@@ -3016,6 +3326,7 @@
% for x in binaryBitwise + maskingShifts + list(chain(*binaryArithmetic.values())):
+${operatorComment(x.operator, True)}
@_transparent
public static func ${x.operator}(_ lhs: ${Self}, _ rhs: ${Self}) -> ${Self} {
var lhs = lhs
@@ -3027,6 +3338,7 @@
% for op in maskingShifts:
+${operatorComment(x.operator, True)}
@available(swift, obsoleted: 4)
@_transparent
public static func ${op.nonMaskingOperator}(
@@ -3037,6 +3349,7 @@
return lhs
}
+${assignmentOperatorComment(x.operator, True)}
@available(swift, obsoleted: 4)
@_transparent
public static func ${op.nonMaskingOperator}=(
diff --git a/stdlib/public/core/StringIndexConversions.swift b/stdlib/public/core/StringIndexConversions.swift
index e23cb51..1039184 100644
--- a/stdlib/public/core/StringIndexConversions.swift
+++ b/stdlib/public/core/StringIndexConversions.swift
@@ -16,9 +16,7 @@
///
/// If the index passed as `sourcePosition` represents the start of an
/// extended grapheme cluster---the element type of a string---then the
- /// initializer succeeds. If the index instead represents the position of a
- /// Unicode scalar within an extended grapheme cluster or the position of an
- /// encoded Unicode scalar value, the result is `nil`.
+ /// initializer succeeds.
///
/// The following example converts the position of the Unicode scalar `"e"`
/// into its corresponding position in the string. The character at that
@@ -43,7 +41,7 @@
/// let nextScalarsIndex = cafe.unicodeScalars.index(after: scalarsIndex)
/// let nextStringIndex = String.Index(nextScalarsIndex, within: cafe)
///
- /// print(nextIndex)
+ /// print(nextStringIndex)
/// // Prints "nil"
///
/// - Parameters:
diff --git a/stdlib/public/core/UnsafePointer.swift.gyb b/stdlib/public/core/UnsafePointer.swift.gyb
index bfac620..cb64594 100644
--- a/stdlib/public/core/UnsafePointer.swift.gyb
+++ b/stdlib/public/core/UnsafePointer.swift.gyb
@@ -1180,9 +1180,9 @@
/// - Parameter pointer: The pointer to use as the source for the new
/// integer.
@_inlineable
- public init<U>(bitPattern: ${Self}<U>?) {
- if let bitPattern = bitPattern {
- self = Int(Builtin.ptrtoint_Word(bitPattern._rawValue))
+ public init<U>(bitPattern pointer: ${Self}<U>?) {
+ if let pointer = pointer {
+ self = Int(Builtin.ptrtoint_Word(pointer._rawValue))
} else {
self = 0
}
@@ -1198,9 +1198,9 @@
/// - Parameter pointer: The pointer to use as the source for the new
/// integer.
@_inlineable
- public init<U>(bitPattern: ${Self}<U>?) {
- if let bitPattern = bitPattern {
- self = UInt(Builtin.ptrtoint_Word(bitPattern._rawValue))
+ public init<U>(bitPattern pointer: ${Self}<U>?) {
+ if let pointer = pointer {
+ self = UInt(Builtin.ptrtoint_Word(pointer._rawValue))
} else {
self = 0
}
diff --git a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
index 5d9f612..e496ac2 100644
--- a/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
+++ b/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb
@@ -507,8 +507,8 @@
/// Initializes the buffer's memory with the given elements, binding the
/// initialized memory to the elements' type.
///
- /// When calling the `initialize(as:from:)` method on a buffer `b`, the
- /// memory referenced by `b` must be uninitialized or initialized to a
+ /// When calling the `initializeMemory(as:from:)` method on a buffer `b`,
+ /// the memory referenced by `b` must be uninitialized or initialized to a
/// trivial type, and must be properly aligned for accessing `S.Element`.
/// The buffer must contain sufficient memory to accommodate
/// `source.underestimatedCount`.
diff --git a/stdlib/public/core/UnsafeRawPointer.swift.gyb b/stdlib/public/core/UnsafeRawPointer.swift.gyb
index e439b3b..52320b5 100644
--- a/stdlib/public/core/UnsafeRawPointer.swift.gyb
+++ b/stdlib/public/core/UnsafeRawPointer.swift.gyb
@@ -981,10 +981,17 @@
}
extension Int {
+ /// Creates a new value with the bit pattern of the given pointer.
+ ///
+ /// The new value represents the address of the pointer passed as `pointer`.
+ /// If `pointer` is `nil`, the result is `0`.
+ ///
+ /// - Parameter pointer: The pointer to use as the source for the new
+ /// integer.
@_inlineable
- public init(bitPattern: Unsafe${Mutable}RawPointer?) {
- if let bitPattern = bitPattern {
- self = Int(Builtin.ptrtoint_Word(bitPattern._rawValue))
+ public init(bitPattern pointer: Unsafe${Mutable}RawPointer?) {
+ if let pointer = pointer {
+ self = Int(Builtin.ptrtoint_Word(pointer._rawValue))
} else {
self = 0
}
@@ -992,10 +999,17 @@
}
extension UInt {
+ /// Creates a new value with the bit pattern of the given pointer.
+ ///
+ /// The new value represents the address of the pointer passed as `pointer`.
+ /// If `pointer` is `nil`, the result is `0`.
+ ///
+ /// - Parameter pointer: The pointer to use as the source for the new
+ /// integer.
@_inlineable
- public init(bitPattern: Unsafe${Mutable}RawPointer?) {
- if let bitPattern = bitPattern {
- self = UInt(Builtin.ptrtoint_Word(bitPattern._rawValue))
+ public init(bitPattern pointer: Unsafe${Mutable}RawPointer?) {
+ if let pointer = pointer {
+ self = UInt(Builtin.ptrtoint_Word(pointer._rawValue))
} else {
self = 0
}
diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp
index da1030e..c6cf2ce 100644
--- a/stdlib/public/runtime/Errors.cpp
+++ b/stdlib/public/runtime/Errors.cpp
@@ -339,6 +339,13 @@
"fatal error: object was retained too many times");
}
+// Crash due to an unowned retain count overflow.
+// FIXME: can't pass the object's address from InlineRefCounts without hacks
+void swift::swift_abortUnownedRetainOverflow() {
+ swift::fatalError(FatalErrorFlags::ReportBacktrace,
+ "fatal error: object's unowned reference was retained too many times");
+}
+
// Crash due to retain of a dead unowned reference.
// FIXME: can't pass the object's address from InlineRefCounts without hacks
void swift::swift_abortRetainUnowned(const void *object) {
diff --git a/stdlib/public/runtime/RefCount.cpp b/stdlib/public/runtime/RefCount.cpp
index 4064946..09f4975 100644
--- a/stdlib/public/runtime/RefCount.cpp
+++ b/stdlib/public/runtime/RefCount.cpp
@@ -143,6 +143,22 @@
return nullptr;
}
+template <typename RefCountBits>
+void RefCounts<RefCountBits>::incrementUnownedSlow(uint32_t n) {
+ auto side = allocateSideTable();
+ if (side)
+ return side->incrementUnowned(n);
+ // Overflow but side table allocation failed.
+ swift_abortUnownedRetainOverflow();
+}
+
+template void RefCounts<InlineRefCountBits>::incrementUnownedSlow(uint32_t n);
+template <>
+void RefCounts<SideTableRefCountBits>::incrementUnownedSlow(uint32_t n) {
+ // Overflow from side table to a new side table?!
+ swift_abortUnownedRetainOverflow();
+}
+
// namespace swift
} // namespace swift
diff --git a/test/ClangImporter/objc_parse.swift b/test/ClangImporter/objc_parse.swift
index 7ced153..9063d02 100644
--- a/test/ClangImporter/objc_parse.swift
+++ b/test/ClangImporter/objc_parse.swift
@@ -175,7 +175,7 @@
dict[NSString()] = a
let value = dict[NSString()]
- dict[nil] = a // expected-error {{ambiguous reference}}
+ dict[nil] = a // expected-error {{cannot assign value of type 'A' to type 'Any?'}}
let q = dict[nil] // expected-error {{ambiguous subscript}}
_ = q
}
diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift
index 0cf2542..6c9dd31 100644
--- a/test/Constraints/diagnostics.swift
+++ b/test/Constraints/diagnostics.swift
@@ -1085,3 +1085,9 @@
func f_31849281(x: Int, y: Int, z: Int) {}
f_31849281(42, y: 10, x: 20) // expected-error {{argument 'x' must precede unnamed argument #1}} {{12-12=x: 20, }} {{21-28=}}
+
+func sr5081() {
+ var a = ["1", "2", "3", "4", "5"]
+ var b = [String]()
+ b = a[2...4] // expected-error {{cannot assign value of type 'ArraySlice<String>' to type '[String]'}}
+}
diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift
index 89e439a..e6773c3 100644
--- a/test/Constraints/generics.swift
+++ b/test/Constraints/generics.swift
@@ -429,7 +429,7 @@
func genericFunc<T>(t: T) {
_ = [T: GenericClass] // expected-error {{generic parameter 'A' could not be inferred}}
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}}
- // expected-error@-2 2 {{type 'T' does not conform to protocol 'Hashable'}}
+ // expected-error@-2 3 {{type 'T' does not conform to protocol 'Hashable'}}
}
struct SR_3525<T> {}
diff --git a/test/Generics/inheritance.swift b/test/Generics/inheritance.swift
index 874dcd2..bc4d432 100644
--- a/test/Generics/inheritance.swift
+++ b/test/Generics/inheritance.swift
@@ -25,8 +25,8 @@
a = obj
// Invalid assignments
- obj = a // expected-error{{'A' is not convertible to 'T'}}
- obj = b // expected-error{{'B' is not convertible to 'T'}}
+ obj = a // expected-error{{cannot assign value of type 'A' to type 'T'}}
+ obj = b // expected-error{{cannot assign value of type 'B' to type 'T'}}
// Downcast that is actually a coercion
a = (obj as? A)! // expected-warning{{conditional cast from 'T' to 'A' always succeeds}}
diff --git a/test/IDE/complete_keywords.swift b/test/IDE/complete_keywords.swift
index ac57a3c..9aadb99 100644
--- a/test/IDE/complete_keywords.swift
+++ b/test/IDE/complete_keywords.swift
@@ -208,8 +208,8 @@
//
// Literals
//
-// KW_EXPR-DAG: Literal[Boolean]/None: false[#Bool#]{{; name=.+$}}
-// KW_EXPR-DAG: Literal[Boolean]/None: true[#Bool#]{{; name=.+$}}
+// KW_EXPR-DAG: Literal[Boolean]/None{{(/TypeRelation\[Identical\])?}}: false[#Bool#]{{; name=.+$}}
+// KW_EXPR-DAG: Literal[Boolean]/None{{(/TypeRelation\[Identical\])?}}: true[#Bool#]{{; name=.+$}}
// KW_EXPR-DAG: Literal[Nil]/None: nil{{; name=.+$}}
// KW_EXPR: End completions
diff --git a/test/IDE/complete_stmt_controlling_expr.swift b/test/IDE/complete_stmt_controlling_expr.swift
index 2758b6f..80b4087 100644
--- a/test/IDE/complete_stmt_controlling_expr.swift
+++ b/test/IDE/complete_stmt_controlling_expr.swift
@@ -1,17 +1,21 @@
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_1 | %FileCheck %s -check-prefix=COND_COMMON
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_2 | %FileCheck %s -check-prefix=COND_COMMON
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_GUARD_1 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_1 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_2 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_2B | %FileCheck %s -check-prefix=COND-WITH-RELATION
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_3 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_4 | %FileCheck %s -check-prefix=COND_COMMON
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_1 | %FileCheck %s -check-prefix=COND_COMMON
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_2 | %FileCheck %s -check-prefix=COND_COMMON
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_3 | %FileCheck %s -check-prefix=COND_COMMON
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_4 | %FileCheck %s -check-prefix=COND_COMMON
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_1 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_2 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_3 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_4 | %FileCheck %s -check-prefix=COND-WITH-RELATION
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_5 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_IF_ELSE_IF_6 | %FileCheck %s -check-prefix=COND_COMMON
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_WHILE_1 | %FileCheck %s -check-prefix=COND_COMMON
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_WHILE_2 | %FileCheck %s -check-prefix=COND_COMMON
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_WHILE_1 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_WHILE_2 | %FileCheck %s -check-prefix=COND-WITH-RELATION
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_WHILE_2B | %FileCheck %s -check-prefix=COND-WITH-RELATION
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_WHILE_3 | %FileCheck %s -check-prefix=COND_COMMON
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=COND_WHILE_4 | %FileCheck %s -check-prefix=COND_COMMON
@@ -132,13 +136,13 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_GUARD_6 | %FileCheck %s -check-prefix=UNRESOLVED_B
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_GUARD_7 | %FileCheck %s -check-prefix=UNRESOLVED_B
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IF_LET_BIND_1 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IF_LET_BIND_2 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IF_LET_BIND_1 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT_BOOL
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IF_LET_BIND_2 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT_BOOL
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=IF_LET_BIND_3 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_1 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_2 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_3 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
-// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_4 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_1 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT_BOOL
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_2 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT_BOOL
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_3 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT_BOOL
+// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_4 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT_BOOL
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GUARD_LET_BIND_5 | %FileCheck %s -check-prefix=FOOSTRUCT_DOT
@@ -149,6 +153,12 @@
func intGen() -> Int { return 1 }
}
+func testGuard1(_ fooObject: FooStruct) {
+ var localInt = 42
+ var localFooObject = FooStruct(localInt)
+ guard #^COND_GUARD_1^#
+}
+
func testIf1(_ fooObject: FooStruct) {
var localInt = 42
var localFooObject = FooStruct(localInt)
@@ -162,6 +172,13 @@
}
}
+func testIf2b(_ fooObject: FooStruct) {
+ var localInt = 42
+ var localFooObject = FooStruct(localInt)
+ if true, #^COND_IF_2B^# {
+ }
+}
+
func testIf3(_ fooObject: FooStruct) {
var localInt = 42
var localFooObject = FooStruct(localInt)
@@ -237,6 +254,13 @@
}
}
+func testWhile2b(_ fooObject: FooStruct) {
+ var localInt = 42
+ var localFooObject = FooStruct(localInt)
+ while true, #^COND_WHILE_2B^# {
+ }
+}
+
func testWhile3(_ fooObject: FooStruct) {
var localInt = 42
var localFooObject = FooStruct(localInt)
@@ -612,3 +636,9 @@
// FOOSTRUCT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: boolGen()[#Bool#];
// FOOSTRUCT_DOT-DAG: Decl[InstanceMethod]/CurrNominal: intGen()[#Int#];
// FOOSTRUCT_DOT: End completions
+
+// FOOSTRUCT_DOT_BOOL: Begin completions
+// FOOSTRUCT_DOT_BOOL-DAG: Decl[InstanceVar]/CurrNominal: instanceVar[#Int#];
+// FOOSTRUCT_DOT_BOOL-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: boolGen()[#Bool#];
+// FOOSTRUCT_DOT_BOOL-DAG: Decl[InstanceMethod]/CurrNominal: intGen()[#Int#];
+// FOOSTRUCT_DOT_BOOL: End completions
diff --git a/test/IRGen/Inputs/usr/include/Gizmo.h b/test/IRGen/Inputs/usr/include/Gizmo.h
index 5b4e937..c9cf43e 100644
--- a/test/IRGen/Inputs/usr/include/Gizmo.h
+++ b/test/IRGen/Inputs/usr/include/Gizmo.h
@@ -23,6 +23,13 @@
} size;
};
+struct Fob {
+ unsigned long a;
+ unsigned b;
+ unsigned c;
+ unsigned long d;
+} Fob;
+
typedef long NSInteger;
@interface Gizmo : NSObject
@@ -37,6 +44,7 @@
- (struct NSRect) frame;
- (void) setFrame: (struct NSRect) rect;
- (void) frob;
+- (void) test: (struct Fob) fob;
+ (void) runce;
@end
diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil
index dc2fdf3..3823ee6 100644
--- a/test/IRGen/generic_classes.sil
+++ b/test/IRGen/generic_classes.sil
@@ -348,7 +348,7 @@
// CHECK-objc: store i64 [[T2]], i64* [[T1]], align 8
// Initialize our own dependent field offsets.
// CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i64*
-// CHECK: [[OFFSETS:%.*]] = getelementptr inbounds i64, i64* [[METADATA_ARRAY]], i32 23
+// CHECK: [[OFFSETS:%.*]] = getelementptr inbounds i64, i64* [[METADATA_ARRAY]], i64 23
// CHECK: [[T0:%.*]] = bitcast %swift.type* %B to i8***
// CHECK: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 -1
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[T1]], align 8
diff --git a/test/IRGen/partial_apply_objc.sil b/test/IRGen/partial_apply_objc.sil
index b0b7082..4d7795b 100644
--- a/test/IRGen/partial_apply_objc.sil
+++ b/test/IRGen/partial_apply_objc.sil
@@ -198,3 +198,30 @@
%g = partial_apply %f(%c) : $@convention(thin) Gizmo -> ()
return %g : $@callee_owned () -> ()
}
+
+// CHECK: define internal swiftcc void @_T0Ta.17(i64, i64, i64, %swift.refcounted* swiftself)
+// CHECK: [[TMPCOERCE:%.*]] = alloca { i64, i64, i64 }
+// CHECK: [[INDIRECTTEMP:%.*]] = alloca %TSC3FobV
+// CHECK: [[ADDR:%.*]] = getelementptr inbounds { i64, i64, i64 }, { i64, i64, i64 }* [[TMPCOERCE]], i32 0, i32 0
+// CHECK: store i64 %0, i64* [[ADDR]]
+// CHECK: [[ADDR:%.]] = getelementptr inbounds { i64, i64, i64 }, { i64, i64, i64 }* [[TMPCOERCE]], i32 0, i32 1
+// CHECK: store i64 %1, i64* [[ADDR]]
+// CHECK: [[ADDR:%.*]] = getelementptr inbounds { i64, i64, i64 }, { i64, i64, i64 }* [[TMPCOERCE]], i32 0, i32 2
+// CHECK: store i64 %2, i64* [[ADDR]]
+// CHECK: load i64
+// CHECK: load i32
+// CHECK: load i32
+// CHECK: load i64
+// CHECK: store i64
+// CHECK: store i32
+// CHECK: store i32
+// CHECK: store i64
+// CHECK: objc_msgSend
+// CHECK: ret void
+
+sil @objc_partial_apply_2 : $@convention(thin) Gizmo -> @callee_owned (Fob) -> () {
+entry(%c : $Gizmo):
+ %m = class_method [volatile] %c : $Gizmo, #Gizmo.test!1.foreign : (Gizmo) -> (Fob) -> (), $@convention(objc_method) (Fob, Gizmo) -> ()
+ %p = partial_apply %m(%c) : $@convention(objc_method) (Fob, Gizmo) -> ()
+ return %p : $@callee_owned (Fob) -> ()
+}
diff --git a/test/Interpreter/unowned_overflow.swift b/test/Interpreter/unowned_overflow.swift
new file mode 100644
index 0000000..4eacea1
--- /dev/null
+++ b/test/Interpreter/unowned_overflow.swift
@@ -0,0 +1,35 @@
+// RUN: %target-run-simple-swift | %FileCheck %s
+// REQUIRES: executable_test
+
+class Owner {
+ var children: [Child] = []
+
+ func addChild(_ c: Child) {
+ children.append(c)
+ }
+
+ func removeChildren() {
+ children.removeAll()
+ }
+
+ func test() {
+ // Overflow of unowned ref count on 32bit.
+ for _ in 0 ..< 500 {
+ addChild(Child(self))
+ }
+ removeChildren()
+ }
+}
+
+class Child {
+ unowned var owner: Owner
+
+ init(_ o: Owner) {
+ owner = o
+ }
+}
+
+let o = Owner()
+o.test()
+print("success")
+// CHECK: success
diff --git a/test/Parse/pointer_conversion.swift.gyb b/test/Parse/pointer_conversion.swift.gyb
index b7ef738..dae6ff8 100644
--- a/test/Parse/pointer_conversion.swift.gyb
+++ b/test/Parse/pointer_conversion.swift.gyb
@@ -60,7 +60,7 @@
// We don't allow these conversions outside of function arguments.
var x: UnsafeMutablePointer<Int> = &i // expected-error{{cannot pass immutable value as inout argument: 'i' is immutable}}
- x = &ii // expected-error{{cannot assign value of type '[Int]' to type 'Int'}}
+ x = &ii // expected-error{{cannot assign value of type 'inout [Int]' to type 'UnsafeMutablePointer<Int>'}}
_ = x
}
diff --git a/test/SIL/ownership-verifier/opaque_use_verifier.sil b/test/SIL/ownership-verifier/opaque_use_verifier.sil
index d57b0b1..267b279 100644
--- a/test/SIL/ownership-verifier/opaque_use_verifier.sil
+++ b/test/SIL/ownership-verifier/opaque_use_verifier.sil
@@ -57,3 +57,25 @@
destroy_value %1 : $T
return %4 : $T
}
+
+public protocol AnyObject : class {}
+
+sil @takeType : $@convention(thin) (@thick AnyObject.Type) -> () {
+bb0(%0 : @trivial $@thick AnyObject.Type):
+ %18 = tuple ()
+ return %18 : $()
+}
+
+// Test an unconditional cast from an owned value to a trivial value.
+sil @castToTrivial : $@convention(thin) (@owned AnyObject) -> () {
+bb0(%0 : @owned $AnyObject):
+ %6 = function_ref @takeType : $@convention(thin) (@thick AnyObject.Type) -> ()
+ %8 = begin_borrow %0 : $AnyObject
+ %9 = copy_value %8 : $AnyObject
+ %10 = unconditional_checked_cast_value take_always %9 : $AnyObject to $@thick AnyObject.Type
+ %11 = apply %6(%10) : $@convention(thin) (@thick AnyObject.Type) -> ()
+ end_borrow %8 from %0 : $AnyObject, $AnyObject
+ destroy_value %0 : $AnyObject
+ %18 = tuple ()
+ return %18 : $()
+}
\ No newline at end of file
diff --git a/test/SILGen/decls.swift b/test/SILGen/decls.swift
index 633db72..09c408d 100644
--- a/test/SILGen/decls.swift
+++ b/test/SILGen/decls.swift
@@ -167,3 +167,25 @@
init() {
}
}
+
+// Make sure unbound method references on class hierarchies are
+// properly represented in the AST
+
+class Base {
+ func method1() -> Self { return self }
+ func method2() -> Self { return self }
+}
+
+class Derived : Base {
+ override func method2() -> Self { return self }
+}
+
+func generic<T>(arg: T) { }
+
+func unboundMethodReferences() {
+ generic(arg: Derived.method1)
+ generic(arg: Derived.method2)
+
+ _ = type(of: Derived.method1)
+ _ = type(of: Derived.method2)
+}
diff --git a/test/SILOptimizer/devirt_speculative.sil b/test/SILOptimizer/devirt_speculative.sil
index 9fd835b..0a9b006 100644
--- a/test/SILOptimizer/devirt_speculative.sil
+++ b/test/SILOptimizer/devirt_speculative.sil
@@ -3,16 +3,19 @@
sil_stage canonical
import Builtin
+import Swift
@objc class MyNSObject {}
private class Base : MyNSObject {
override init()
@inline(never) func foo()
+ @inline(never) func exit() -> Never
}
private class Sub : Base {
override init()
@inline(never) override func foo()
+ @inline(never) override func exit() -> Never
}
sil private [noinline] @_TBaseFooFun : $@convention(method) (@guaranteed Base) -> () {
@@ -27,12 +30,19 @@
return %1 : $()
}
+
+sil @Base_exit : $@convention(method) (@guaranteed Base) -> Never
+
+sil @Sub_exit : $@convention(method) (@guaranteed Sub) -> Never
+
sil_vtable Base {
#Base.foo!1: _TBaseFooFun
+ #Base.exit!1: Base_exit
}
sil_vtable Sub {
#Base.foo!1: _TSubFooFun
+ #Base.exit!1: Sub_exit
}
sil @test_objc_ancestry : $@convention(thin) (@guaranteed Base) -> () {
@@ -124,3 +134,23 @@
%3 = tuple()
return %3 : $()
}
+
+// Check that NoReturn functions are devirtualized properly.
+// The new apply should be followed by an unreachable instruction
+// instead of a branch instruction.
+// CHECK-LABEL: sil{{.*}}test_devirt_of_noreturn_function
+// CHECK: checked_cast_br
+// CHECK: function_ref @Base_exit
+// CHECK-NEXT: apply
+// CHECK-NEXT: unreachable
+// CHECK: checked_cast_br
+// CHECK: function_ref @Sub_exit
+// CHECK-NEXT: apply
+// CHECK-NEXT: unreachable
+sil hidden [noinline] @test_devirt_of_noreturn_function : $@convention(thin) (@owned Base) -> () {
+bb0(%0 : $Base):
+ %2 = class_method %0 : $Base, #Base.exit!1 : (Base) -> () -> Never, $@convention(method) (@guaranteed Base) -> Never
+ %3 = apply %2(%0) : $@convention(method) (@guaranteed Base) -> Never
+ unreachable
+}
+
diff --git a/test/SourceKit/CodeComplete/complete_literals.swift b/test/SourceKit/CodeComplete/complete_literals.swift
index f2ca730..2a0b232 100644
--- a/test/SourceKit/CodeComplete/complete_literals.swift
+++ b/test/SourceKit/CodeComplete/complete_literals.swift
@@ -45,10 +45,16 @@
// RUN: %complete-test -tok=EXPR1 %s -raw | %FileCheck %s -check-prefix=LITERALS
// RUN: %complete-test -tok=EXPR2 %s -raw | %FileCheck %s -check-prefix=LITERALS
-// RUN: %complete-test -tok=EXPR3 %s -raw | %FileCheck %s -check-prefix=LITERALS
let x1 = #^EXPR1^#
x1 + #^EXPR2^#
+
+// RUN: %complete-test -tok=EXPR3 %s -raw | %FileCheck %s -check-prefix=LITERAL_BOOL
if #^EXPR3^# { }
+// LITERAL_BOOL-NOT: source.lang.swift.literal
+// LITERAL_BOOL: key.kind: source.lang.swift.literal.boolean
+// LITERAL_BOOL-NOT: source.lang.swift.literal
+// LITERAL_BOOL: key.kind: source.lang.swift.literal.boolean
+// LITERAL_BOOL-NOT: source.lang.swift.literal
// RUN: %complete-test -tok=EXPR4 %s -raw | %FileCheck %s -check-prefix=LITERAL_INT
foo(#^EXPR4^#)
diff --git a/test/SourceKit/InterfaceGen/gen_clang_module.swift.response b/test/SourceKit/InterfaceGen/gen_clang_module.swift.response
index bddccba..4135743 100644
--- a/test/SourceKit/InterfaceGen/gen_clang_module.swift.response
+++ b/test/SourceKit/InterfaceGen/gen_clang_module.swift.response
@@ -4116,6 +4116,8 @@
key.namelength: 8,
key.bodyoffset: 237,
key.bodylength: 106,
+ key.docoffset: 157,
+ key.doclength: 26,
key.inheritedtypes: [
{
key.name: "RawRepresentable"
@@ -4199,7 +4201,9 @@
key.length: 31,
key.typename: "FooEnum1",
key.nameoffset: 384,
- key.namelength: 9
+ key.namelength: 9,
+ key.docoffset: 346,
+ key.doclength: 27
},
{
key.kind: source.lang.swift.decl.struct,
@@ -4423,6 +4427,8 @@
key.namelength: 19,
key.bodyoffset: 970,
key.bodylength: 133,
+ key.docoffset: 894,
+ key.doclength: 37,
key.inheritedtypes: [
{
key.name: "Int"
@@ -4502,6 +4508,8 @@
key.namelength: 17,
key.bodyoffset: 1186,
key.bodylength: 210,
+ key.docoffset: 1106,
+ key.doclength: 35,
key.inheritedtypes: [
{
key.name: "OptionSet"
@@ -4803,7 +4811,9 @@
key.offset: 1974,
key.length: 29,
key.nameoffset: 1984,
- key.namelength: 11
+ key.namelength: 11,
+ key.docoffset: 1938,
+ key.doclength: 29
},
{
key.kind: source.lang.swift.decl.var.global,
@@ -4814,7 +4824,9 @@
key.length: 20,
key.typename: "Int32",
key.nameoffset: 2043,
- key.namelength: 9
+ key.namelength: 9,
+ key.docoffset: 2005,
+ key.doclength: 27
},
{
key.kind: source.lang.swift.decl.function.free,
@@ -4824,6 +4836,8 @@
key.length: 34,
key.nameoffset: 2099,
key.namelength: 20,
+ key.docoffset: 2061,
+ key.doclength: 26,
key.substructure: [
{
key.kind: source.lang.swift.decl.var.parameter,
@@ -4967,7 +4981,9 @@
key.offset: 2627,
key.length: 26,
key.nameoffset: 2632,
- key.namelength: 21
+ key.namelength: 21,
+ key.docoffset: 2557,
+ key.doclength: 62
},
{
key.kind: source.lang.swift.decl.function.free,
@@ -4985,7 +5001,9 @@
key.offset: 2800,
key.length: 26,
key.nameoffset: 2805,
- key.namelength: 21
+ key.namelength: 21,
+ key.docoffset: 2733,
+ key.doclength: 59
},
{
key.kind: source.lang.swift.decl.function.free,
@@ -4994,7 +5012,9 @@
key.offset: 2888,
key.length: 26,
key.nameoffset: 2893,
- key.namelength: 21
+ key.namelength: 21,
+ key.docoffset: 2828,
+ key.doclength: 53
},
{
key.kind: source.lang.swift.decl.function.free,
@@ -5003,7 +5023,9 @@
key.offset: 2982,
key.length: 26,
key.nameoffset: 2987,
- key.namelength: 21
+ key.namelength: 21,
+ key.docoffset: 2916,
+ key.doclength: 59
},
{
key.kind: source.lang.swift.decl.function.free,
@@ -5013,6 +5035,8 @@
key.length: 58,
key.nameoffset: 3072,
key.namelength: 44,
+ key.docoffset: 3010,
+ key.doclength: 50,
key.substructure: [
{
key.kind: source.lang.swift.decl.var.parameter,
@@ -5036,6 +5060,8 @@
key.namelength: 15,
key.bodyoffset: 3193,
key.bodylength: 545,
+ key.docoffset: 3127,
+ key.doclength: 33,
key.substructure: [
{
key.kind: source.lang.swift.decl.function.method.instance,
@@ -5044,7 +5070,9 @@
key.offset: 3258,
key.length: 19,
key.nameoffset: 3263,
- key.namelength: 14
+ key.namelength: 14,
+ key.docoffset: 3204,
+ key.doclength: 43
},
{
key.kind: source.lang.swift.decl.function.method.instance,
@@ -5053,7 +5081,9 @@
key.offset: 3363,
key.length: 40,
key.nameoffset: 3368,
- key.namelength: 35
+ key.namelength: 35,
+ key.docoffset: 3288,
+ key.doclength: 64
},
{
key.kind: source.lang.swift.decl.function.method.instance,
@@ -5062,7 +5092,9 @@
key.offset: 3503,
key.length: 40,
key.nameoffset: 3508,
- key.namelength: 35
+ key.namelength: 35,
+ key.docoffset: 3414,
+ key.doclength: 77
},
{
key.kind: source.lang.swift.decl.function.method.static,
@@ -5243,6 +5275,8 @@
key.namelength: 15,
key.bodyoffset: 4192,
key.bodylength: 422,
+ key.docoffset: 4096,
+ key.doclength: 33,
key.inheritedtypes: [
{
key.name: "FooClassBase"
diff --git a/test/SourceKit/InterfaceGen/gen_header.swift.response b/test/SourceKit/InterfaceGen/gen_header.swift.response
index 2306182..b24b116 100644
--- a/test/SourceKit/InterfaceGen/gen_header.swift.response
+++ b/test/SourceKit/InterfaceGen/gen_header.swift.response
@@ -222,7 +222,9 @@
key.nameoffset: 179,
key.namelength: 8,
key.bodyoffset: 189,
- key.bodylength: 1
+ key.bodylength: 1,
+ key.docoffset: 106,
+ key.doclength: 62
},
{
key.kind: source.lang.swift.decl.protocol,
diff --git a/test/SourceKit/InterfaceGen/gen_swift_source.swift.response b/test/SourceKit/InterfaceGen/gen_swift_source.swift.response
index ad2ffce..7834451 100644
--- a/test/SourceKit/InterfaceGen/gen_swift_source.swift.response
+++ b/test/SourceKit/InterfaceGen/gen_swift_source.swift.response
@@ -390,6 +390,8 @@
key.namelength: 19,
key.bodyoffset: 200,
key.bodylength: 51,
+ key.docoffset: 139,
+ key.doclength: 27,
key.substructure: [
{
key.kind: source.lang.swift.decl.function.method.instance,
@@ -498,7 +500,9 @@
key.length: 13,
key.typename: "Int",
key.nameoffset: 512,
- key.namelength: 4
+ key.namelength: 4,
+ key.docoffset: 473,
+ key.doclength: 22
},
{
key.kind: source.lang.swift.decl.var.instance,
@@ -509,7 +513,9 @@
key.length: 24,
key.typename: "(Int, Int)",
key.nameoffset: 564,
- key.namelength: 2
+ key.namelength: 2,
+ key.docoffset: 527,
+ key.doclength: 19
}
]
},
diff --git a/test/TypeCoercion/overload_noncall.swift b/test/TypeCoercion/overload_noncall.swift
index e21cf69..2f56637 100644
--- a/test/TypeCoercion/overload_noncall.swift
+++ b/test/TypeCoercion/overload_noncall.swift
@@ -52,7 +52,7 @@
x = accept_XY(&xy);
x = xy
- x = &xy; // expected-error{{'&' used with non-inout argument of type 'X'}}
+ x = &xy; // expected-error{{cannot assign value of type 'inout X' to type 'X'}}
accept_Z(&xy); // expected-error{{cannot convert value of type 'X' to expected argument type 'Z'}}
}
diff --git a/test/decl/nested/type_in_type.swift b/test/decl/nested/type_in_type.swift
index 303237d..d716e1b 100644
--- a/test/decl/nested/type_in_type.swift
+++ b/test/decl/nested/type_in_type.swift
@@ -381,12 +381,28 @@
struct Fangs<B: ExpressibleByDogLiteral> { }
}
+struct NotADog {}
+
func pets<T>(fur: T) -> Claws<Kitten>.Fangs<T> {
return Claws<Kitten>.Fangs<T>()
}
+func something<T>() -> T { // expected-note {{in call to function 'something()'}}
+ while true {}
+}
+
func test() {
let _: Claws<Kitten>.Fangs<Puppy> = pets(fur: Puppy())
+
+ // <https://bugs.swift.org/browse/SR-5600>
+ let _: Claws.Fangs<Puppy> = pets(fur: Puppy())
+ let _: Claws.Fangs<Puppy> = Claws<Kitten>.Fangs()
+ let _: Claws.Fangs<Puppy> = Claws.Fangs()
+ // expected-error@-1 {{cannot convert value of type 'Claws<_>.Fangs<_>' to specified type 'Claws.Fangs<Puppy>'}}
+ let _: Claws.Fangs<NotADog> = something()
+ // expected-error@-1 {{generic parameter 'T' could not be inferred}} // FIXME: bad diagnostic
+ _ = Claws.Fangs<NotADog>()
+ // expected-error@-1 {{type 'NotADog' does not conform to protocol 'ExpressibleByDogLiteral'}}
}
// https://bugs.swift.org/browse/SR-4379
diff --git a/test/stdlib/Integers.swift.gyb b/test/stdlib/Integers.swift.gyb
index c2e6000..175bef8 100644
--- a/test/stdlib/Integers.swift.gyb
+++ b/test/stdlib/Integers.swift.gyb
@@ -761,22 +761,30 @@
}
dwTests.test("Bitshifts") {
- typealias DWU16 = DoubleWidth<UInt8>
- typealias DWU32 = DoubleWidth<DWU16>
- typealias DWU64 = DoubleWidth<DWU32>
+ typealias DWU64 = DoubleWidth<DoubleWidth<DoubleWidth<UInt8>>>
+ typealias DWI64 = DoubleWidth<DoubleWidth<DoubleWidth<Int8>>>
- func f(_ x: UInt64) {
- let y = DWU64(x)
- for i in -65...65 {
+ func f<T: FixedWidthInteger, U: FixedWidthInteger>(_ x: T, type: U.Type) {
+ let y = U(x)
+ expectEqual(T.bitWidth, U.bitWidth)
+ for i in -(T.bitWidth + 1)...(T.bitWidth + 1) {
expectTrue(x << i == y << i)
expectTrue(x >> i == y >> i)
+
+ expectTrue(x &<< i == y &<< i)
+ expectTrue(x &>> i == y &>> i)
}
}
- f(1)
- f(~(~0 >> 1))
- f(.max)
- f(0b11110000_10100101_11110000_10100101_11110000_10100101_11110000_10100101)
+ f(1 as UInt64, type: DWU64.self)
+ f(~(~0 as UInt64 >> 1), type: DWU64.self)
+ f(UInt64.max, type: DWU64.self)
+ f(0b11110000_10100101_11110000_10100101_11110000_10100101_11110000_10100101 as UInt64, type: DWU64.self)
+
+ f(1 as Int64, type: DWI64.self)
+ f(Int64.min, type: DWI64.self)
+ f(Int64.max, type: DWI64.self)
+ f(0b01010101_10100101_11110000_10100101_11110000_10100101_11110000_10100101 as Int64, type: DWI64.self)
}
dwTests.test("Remainder/DividingBy0") {
diff --git a/test/stdlib/UnsafePointerDiagnostics.swift b/test/stdlib/UnsafePointerDiagnostics.swift
index 316fc1a..21a51d0 100644
--- a/test/stdlib/UnsafePointerDiagnostics.swift
+++ b/test/stdlib/UnsafePointerDiagnostics.swift
@@ -56,8 +56,8 @@
_ = UnsafeRawPointer(oumps)
_ = UnsafeRawPointer(oups)
- _ = UnsafeMutablePointer<Void>(rp) // expected-warning 3 {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}} expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{overloads for 'UnsafeMutablePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}} expected-note{{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type}}
- _ = UnsafeMutablePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}} expected-warning 3 {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}} expected-note{{overloads for 'UnsafeMutablePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
+ _ = UnsafeMutablePointer<Void>(rp) // expected-warning 4 {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}} expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{overloads for 'UnsafeMutablePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}} expected-note{{Pointer conversion restricted: use '.assumingMemoryBound(to:)' or '.bindMemory(to:capacity:)' to view memory as a type}}
+ _ = UnsafeMutablePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafeMutablePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}} expected-warning 4 {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}} expected-note{{overloads for 'UnsafeMutablePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
_ = UnsafeMutablePointer<Void>(umpv) // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(upv) // expected-error {{'init' has been renamed to 'init(mutating:)'}} expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(umpi) // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
@@ -65,8 +65,8 @@
_ = UnsafeMutablePointer<Void>(umps) // expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
_ = UnsafeMutablePointer<Void>(ups) // expected-error {{'init' has been renamed to 'init(mutating:)'}} expected-warning {{UnsafeMutablePointer<Void> has been replaced by UnsafeMutableRawPointer}}
- _ = UnsafePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{}} expected-warning 3 {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}} expected-note{{overloads for 'UnsafePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafePointer<Pointee>), (UnsafePointer<Pointee>?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
- _ = UnsafePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}} expected-warning 3 {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}} expected-note{{overloads for 'UnsafePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafePointer<Pointee>), (UnsafePointer<Pointee>?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
+ _ = UnsafePointer<Void>(rp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeRawPointer)'}} expected-note {{}} expected-warning 4 {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}} expected-note{{overloads for 'UnsafePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafePointer<Pointee>), (UnsafePointer<Pointee>?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
+ _ = UnsafePointer<Void>(mrp) // expected-error {{cannot invoke initializer for type 'UnsafePointer<Void>' with an argument list of type '(UnsafeMutableRawPointer)'}} expected-note {{}} expected-warning 4 {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}} expected-note{{overloads for 'UnsafePointer<Void>' exist with these partially matching parameter lists: (RawPointer), (OpaquePointer), (OpaquePointer?), (UnsafePointer<Pointee>), (UnsafePointer<Pointee>?), (UnsafeMutablePointer<Pointee>), (UnsafeMutablePointer<Pointee>?)}}
_ = UnsafePointer<Void>(umpv) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
_ = UnsafePointer<Void>(upv) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
_ = UnsafePointer<Void>(umpi) // expected-warning {{UnsafePointer<Void> has been replaced by UnsafeRawPointer}}
diff --git a/tools/SourceKit/include/SourceKit/Core/LangSupport.h b/tools/SourceKit/include/SourceKit/Core/LangSupport.h
index 42cba51..c497844 100644
--- a/tools/SourceKit/include/SourceKit/Core/LangSupport.h
+++ b/tools/SourceKit/include/SourceKit/Core/LangSupport.h
@@ -211,6 +211,8 @@
unsigned NameLength,
unsigned BodyOffset,
unsigned BodyLength,
+ unsigned DocOffset,
+ unsigned DocLength,
StringRef DisplayName,
StringRef TypeName,
StringRef RuntimeName,
diff --git a/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def
index 6ca789d..e8e70e9 100644
--- a/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def
+++ b/tools/SourceKit/include/SourceKit/Core/ProtocolUIDs.def
@@ -69,6 +69,8 @@
KEY(BodyLength, "key.bodylength")
KEY(ThrowOffset, "key.throwoffset")
KEY(ThrowLength, "key.throwlength")
+KEY(DocOffset, "key.docoffset")
+KEY(DocLength, "key.doclength")
KEY(IsLocal, "key.is_local")
KEY(InheritedTypes, "key.inheritedtypes")
KEY(Attributes, "key.attributes")
diff --git a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp
index fb6d4ec..f764891 100644
--- a/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp
+++ b/tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp
@@ -1027,6 +1027,15 @@
BodyOffset = BodyEnd = 0;
}
+ unsigned DocOffset = 0;
+ unsigned DocEnd = 0;
+ if (Node.DocRange.isValid()) {
+ DocOffset = SrcManager.getLocOffsetInBuffer(Node.DocRange.getStart(),
+ BufferID);
+ DocEnd = SrcManager.getLocOffsetInBuffer(Node.DocRange.getEnd(),
+ BufferID);
+ }
+
UIdent Kind = SwiftLangSupport::getUIDForSyntaxStructureKind(Node.Kind);
UIdent AccessLevel;
UIdent SetterAccessLevel;
@@ -1080,6 +1089,7 @@
Kind, AccessLevel, SetterAccessLevel,
NameStart, NameEnd - NameStart,
BodyOffset, BodyEnd - BodyOffset,
+ DocOffset, DocEnd - DocOffset,
DisplayName,
TypeName, RuntimeName,
SelectorName,
@@ -1144,7 +1154,7 @@
UIdent Kind = SwiftLangSupport::getUIDForSyntaxNodeKind(Node.Kind);
Consumer.beginDocumentSubStructure(StartOffset, EndOffset - StartOffset,
Kind, UIdent(), UIdent(), 0, 0,
- 0, 0,
+ 0, 0, 0, 0,
StringRef(),
StringRef(), StringRef(),
StringRef(),
diff --git a/tools/SourceKit/tools/sourcekitd/include/sourcekitd/DocStructureArray.h b/tools/SourceKit/tools/sourcekitd/include/sourcekitd/DocStructureArray.h
index d29f9f9..6c931c6 100644
--- a/tools/SourceKit/tools/sourcekitd/include/sourcekitd/DocStructureArray.h
+++ b/tools/SourceKit/tools/sourcekitd/include/sourcekitd/DocStructureArray.h
@@ -33,6 +33,7 @@
SourceKit::UIdent SetterAccessLevel,
unsigned NameOffset, unsigned NameLength,
unsigned BodyOffset, unsigned BodyLength,
+ unsigned DocOffset, unsigned DocLength,
llvm::StringRef DisplayName, llvm::StringRef TypeName,
llvm::StringRef RuntimeName,
llvm::StringRef SelectorName,
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp
index 8bae3e9..486b1e3 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/DocStructureArray.cpp
@@ -34,6 +34,8 @@
unsigned NameLength;
unsigned BodyOffset;
unsigned BodyLength;
+ unsigned DocOffset;
+ unsigned DocLength;
std::string DisplayName;
std::string TypeName;
std::string RuntimeName;
@@ -72,6 +74,8 @@
unsigned, // NameLength
unsigned, // BodyOffset
unsigned, // BodyLength
+ unsigned, // DocOffset
+ unsigned, // DocLength
Optional<StringRef>, // DisplayName
Optional<StringRef>, // TypeName
Optional<StringRef>, // RuntimeName
@@ -167,7 +171,8 @@
unsigned Offset, unsigned Length, SourceKit::UIdent Kind,
SourceKit::UIdent AccessLevel, SourceKit::UIdent SetterAccessLevel,
unsigned NameOffset, unsigned NameLength, unsigned BodyOffset,
- unsigned BodyLength, StringRef DisplayName, StringRef TypeName,
+ unsigned BodyLength, unsigned DocOffset, unsigned DocLength,
+ StringRef DisplayName, StringRef TypeName,
StringRef RuntimeName, StringRef SelectorName,
ArrayRef<StringRef> InheritedTypes, ArrayRef<UIdent> Attrs) {
@@ -181,6 +186,8 @@
NameLength,
BodyOffset,
BodyLength,
+ DocOffset,
+ DocLength,
DisplayName,
TypeName,
RuntimeName,
@@ -216,10 +223,10 @@
impl.structureBuilder.addEntry(
node.Offset, node.Length, node.Kind, node.AccessLevel,
node.SetterAccessLevel, node.NameOffset, node.NameLength, node.BodyOffset,
- node.BodyLength, str(node.DisplayName), str(node.TypeName),
- str(node.RuntimeName), str(node.SelectorName), node.InheritedTypesOffset,
- node.AttrsOffset, impl.addElements(node.elements),
- impl.addChildren(node.childIndices));
+ node.BodyLength, node.DocOffset, node.DocLength, str(node.DisplayName),
+ str(node.TypeName), str(node.RuntimeName), str(node.SelectorName),
+ node.InheritedTypesOffset, node.AttrsOffset,
+ impl.addElements(node.elements), impl.addChildren(node.childIndices));
}
std::unique_ptr<llvm::MemoryBuffer> DocStructureArrayBuilder::createBuffer() {
@@ -280,6 +287,8 @@
unsigned NameLength;
unsigned BodyOffset;
unsigned BodyLength;
+ unsigned DocOffset;
+ unsigned DocLength;
const char *DisplayName;
const char *TypeName;
const char *RuntimeName;
@@ -331,6 +340,8 @@
unsigned, // NameLength
unsigned, // BodyOffset
unsigned, // BodyLength
+ unsigned, // DocOffset
+ unsigned, // DocLength
const char *, // DisplayName
const char *, // TypeName
const char *, // RuntimeName
@@ -353,8 +364,9 @@
reader.readEntries(
index, result.Offset, result.Length, result.Kind, result.AccessLevel,
result.SetterAccessLevel, result.NameOffset, result.NameLength,
- result.BodyOffset, result.BodyLength, result.DisplayName, result.TypeName,
- result.RuntimeName, result.SelectorName, result.InheritedTypesOffset,
+ result.BodyOffset, result.BodyLength, result.DocOffset, result.DocLength,
+ result.DisplayName, result.TypeName, result.RuntimeName,
+ result.SelectorName, result.InheritedTypesOffset,
result.AttrsOffset, result.ElementsOffset, result.ChildIndicesOffset);
return result;
}
@@ -461,6 +473,10 @@
APPLY(KeyBodyOffset, Int, node.BodyOffset);
APPLY(KeyBodyLength, Int, node.BodyLength);
}
+ if (node.DocOffset || node.DocLength) {
+ APPLY(KeyDocOffset, Int, node.DocOffset);
+ APPLY(KeyDocLength, Int, node.DocLength);
+ }
if (node.DisplayName)
APPLY(KeyName, String, node.DisplayName);
if (node.TypeName)
diff --git a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp
index 17e62df..3c419d2 100644
--- a/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp
+++ b/tools/SourceKit/tools/sourcekitd/lib/API/Requests.cpp
@@ -1894,6 +1894,8 @@
unsigned NameLength,
unsigned BodyOffset,
unsigned BodyLength,
+ unsigned DocOffset,
+ unsigned DocLength,
StringRef DisplayName,
StringRef TypeName,
StringRef RuntimeName,
@@ -2119,6 +2121,8 @@
unsigned NameLength,
unsigned BodyOffset,
unsigned BodyLength,
+ unsigned DocOffset,
+ unsigned DocLength,
StringRef DisplayName,
StringRef TypeName,
StringRef RuntimeName,
@@ -2128,8 +2132,8 @@
if (EnableStructure) {
DocStructure.beginSubStructure(
Offset, Length, Kind, AccessLevel, SetterAccessLevel, NameOffset,
- NameLength, BodyOffset, BodyLength, DisplayName, TypeName, RuntimeName,
- SelectorName, InheritedTypes, Attrs);
+ NameLength, BodyOffset, BodyLength, DocOffset, DocLength, DisplayName,
+ TypeName, RuntimeName, SelectorName, InheritedTypes, Attrs);
}
return true;
}
diff --git a/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp b/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp
index b76e7a8..3dc28a9 100644
--- a/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp
+++ b/unittests/SourceKit/SwiftLang/CursorInfoTest.cpp
@@ -52,6 +52,8 @@
unsigned NameLength,
unsigned BodyOffset,
unsigned BodyLength,
+ unsigned DocOffset,
+ unsigned DocLength,
StringRef DisplayName,
StringRef TypeName,
StringRef RuntimeName,
diff --git a/unittests/SourceKit/SwiftLang/EditingTest.cpp b/unittests/SourceKit/SwiftLang/EditingTest.cpp
index fb70741..11162a8 100644
--- a/unittests/SourceKit/SwiftLang/EditingTest.cpp
+++ b/unittests/SourceKit/SwiftLang/EditingTest.cpp
@@ -57,6 +57,8 @@
unsigned NameLength,
unsigned BodyOffset,
unsigned BodyLength,
+ unsigned DocOffset,
+ unsigned DocLength,
StringRef DisplayName,
StringRef TypeName,
StringRef RuntimeName,
diff --git a/unittests/runtime/Refcounting.cpp b/unittests/runtime/Refcounting.cpp
index 2ac88d0..7732221 100644
--- a/unittests/runtime/Refcounting.cpp
+++ b/unittests/runtime/Refcounting.cpp
@@ -153,6 +153,24 @@
EXPECT_EQ(1u, value);
}
+TEST(RefcountingTest, unowned_retain_release_n_overflow) {
+ // This test would test overflow on 32bit platforms.
+ // These platforms have 7 unowned reference count bits.
+ size_t value = 0;
+ auto object = allocTestObject(&value, 1);
+ EXPECT_EQ(0u, value);
+ swift_unownedRetain_n(object, 128);
+ EXPECT_EQ(129u, swift_unownedRetainCount(object));
+ swift_unownedRetain(object);
+ EXPECT_EQ(130u, swift_unownedRetainCount(object));
+ swift_unownedRelease_n(object, 128);
+ EXPECT_EQ(2u, swift_unownedRetainCount(object));
+ swift_unownedRelease(object);
+ EXPECT_EQ(1u, swift_unownedRetainCount(object));
+ swift_release(object);
+ EXPECT_EQ(1u, value);
+}
+
TEST(RefcountingTest, isUniquelyReferenced) {
size_t value = 0;
auto object = allocTestObject(&value, 1);