Merge pull request #10728 from itaiferber/non-optional-coding-paths
Make coding paths non-optional [DO NOT MERGE]
diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def
index b3d227b..e098c22 100644
--- a/include/swift/AST/DiagnosticsFrontend.def
+++ b/include/swift/AST/DiagnosticsFrontend.def
@@ -167,6 +167,17 @@
ERROR(error_parse_input_file,none,
"error parsing input file '%0' (%1)", (StringRef, StringRef))
+ERROR(error_write_index_unit,none,
+ "writing index unit file: %0", (StringRef))
+ERROR(error_create_index_dir,none,
+ "creating index directory: %0", (StringRef))
+ERROR(error_write_index_record,none,
+ "writing index record file: %0", (StringRef))
+ERROR(error_index_failed_status_check,none,
+ "failed file status check: %0", (StringRef))
+ERROR(error_index_inputs_more_than_outputs,none,
+ "index output filenames do not match input source files", ())
+
ERROR(error_formatting_multiple_file_ranges,none,
"file ranges don't support multiple input files", ())
diff --git a/include/swift/ClangImporter/ClangImporterOptions.h b/include/swift/ClangImporter/ClangImporterOptions.h
index 9704256..b3da68c 100644
--- a/include/swift/ClangImporter/ClangImporterOptions.h
+++ b/include/swift/ClangImporter/ClangImporterOptions.h
@@ -37,6 +37,9 @@
/// Equivalent to Clang's -mcpu=.
std::string TargetCPU;
+ /// The path to which we should store indexing data, if any.
+ std::string IndexStorePath;
+
/// The bridging header or PCH that will be imported.
std::string BridgingHeader;
diff --git a/include/swift/Driver/Types.def b/include/swift/Driver/Types.def
index 0306909..98cb9b3 100644
--- a/include/swift/Driver/Types.def
+++ b/include/swift/Driver/Types.def
@@ -61,6 +61,10 @@
TYPE("tbd", TBD, "tbd", "")
TYPE("module-trace", ModuleTrace, "trace.json", "")
+// BEGIN APPLE-ONLY OUTPUT TYPES
+TYPE("index-data", IndexData, "", "")
+// END APPLE-ONLY OUTPUT TYPES
+
// Misc types
TYPE("pcm", ClangModuleFile, "pcm", "")
TYPE("pch", PCH, "pch", "")
diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h
index 021e27b..92ce827 100644
--- a/include/swift/Frontend/FrontendOptions.h
+++ b/include/swift/Frontend/FrontendOptions.h
@@ -132,6 +132,12 @@
/// The path to collect the group information for the compiled source files.
std::string GroupInfoPath;
+ /// The path to which we should store indexing data, if any.
+ std::string IndexStorePath;
+
+ /// Emit index data for imported serialized swift system modules.
+ bool IndexSystemModules = false;
+
/// If non-zero, warn when a function body takes longer than this many
/// milliseconds to type-check.
///
diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h
index 0691661..7f2ba5e 100644
--- a/include/swift/IDE/Utils.h
+++ b/include/swift/IDE/Utils.h
@@ -188,6 +188,7 @@
SourceLoc LocToResolve;
SemaToken SemaTok;
Type ContainerType;
+ llvm::SmallVector<Expr*, 4> TrailingExprStack;
public:
explicit SemaLocResolver(SourceFile &SrcFile) : SrcFile(SrcFile) { }
@@ -216,7 +217,6 @@
SourceLoc Loc, bool IsRef, Type Ty = Type());
bool tryResolve(ModuleEntity Mod, SourceLoc Loc);
bool tryResolve(Stmt *St);
- bool tryResolve(Expr *Exp);
bool visitSubscriptReference(ValueDecl *D, CharSourceRange Range,
bool IsOpenBracket) override;
};
diff --git a/include/swift/Index/IndexRecord.h b/include/swift/Index/IndexRecord.h
new file mode 100644
index 0000000..8ddcb44
--- /dev/null
+++ b/include/swift/Index/IndexRecord.h
@@ -0,0 +1,83 @@
+//===--- IndexRecord.h - Entry point for recording index data ---*- C++ -*-===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SWIFT_INDEX_INDEXRECORD_H
+#define SWIFT_INDEX_INDEXRECORD_H
+
+#include "swift/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace swift {
+class DependencyTracker;
+class ModuleDecl;
+class SourceFile;
+
+namespace index {
+
+/// Index the given source file and store the results to \p indexStorePath.
+///
+/// \param primarySourceFile The source file to index.
+///
+/// \param indexUnitToken A unique identifier for this translation unit in the
+/// form of a file path.
+///
+/// \param indexStorePath The location to write the indexing data to.
+///
+/// \param indexSystemModules If true, emit index data for imported serialized
+/// swift system modules.
+///
+/// \param isDebugCompilation true for non-optimized compiler invocation.
+///
+/// \param targetTriple The target for this compilation.
+///
+/// \param dependencyTracker The set of dependencies seen while building.
+bool indexAndRecord(SourceFile *primarySourceFile, StringRef indexUnitToken,
+ StringRef indexStorePath, bool indexSystemModules,
+ bool isDebugCompilation, StringRef targetTriple,
+ const DependencyTracker &dependencyTracker);
+
+/// Index the given module and store the results to \p indexStorePath.
+///
+/// \param module The module to index.
+///
+/// \param indexUnitTokens A list of unique identifiers for the index units to
+/// be written. This may either be one unit per source file of \p module, or it
+/// may be a single unit, in which case all the index information will be
+/// combined into a single unit.
+///
+/// \param moduleUnitToken A unique identifier for this module unit in the form
+/// of a file path. Only used if \p indexUnitTokens are specified for each
+/// source file, otherwise the single \p indexUnitTokens value is used instead.
+///
+/// \param indexStorePath The location to write the indexing data to.
+///
+/// \param indexSystemModules If true, emit index data for imported serialized
+/// swift system modules.
+///
+/// \param isDebugCompilation true for non-optimized compiler invocation.
+///
+/// \param targetTriple The target for this compilation.
+///
+/// \param dependencyTracker The set of dependencies seen while building.
+bool indexAndRecord(ModuleDecl *module, ArrayRef<std::string> indexUnitTokens,
+ StringRef moduleUnitToken, StringRef indexStorePath,
+ bool indexSystemModules, bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker);
+// FIXME: indexUnitTokens could be StringRef, but that creates an impedance
+// mismatch in the caller.
+
+} // end namespace index
+} // end namespace swift
+
+#endif // SWIFT_INDEX_INDEXRECORD_H
diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td
index 4bc4968..d814367 100644
--- a/include/swift/Option/FrontendOptions.td
+++ b/include/swift/Option/FrontendOptions.td
@@ -414,6 +414,9 @@
HelpText<"Use the pass pipeline defined by <pass_pipeline_file>">,
MetaVarName<"<pass_pipeline_file>">;
+def index_system_modules : Flag<["-"], "index-system-modules">,
+ HelpText<"Emit index data for imported serialized swift system modules">;
+
def dump_interface_hash : Flag<["-"], "dump-interface-hash">,
HelpText<"Parse input file(s) and dump interface token hash(es)">,
ModeOpt;
diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td
index 73b9261..2bdbe29 100644
--- a/include/swift/Option/Options.td
+++ b/include/swift/Option/Options.td
@@ -646,6 +646,18 @@
HelpText<"Specify the type of coverage instrumentation for Sanitizers and"
" additional options separated by commas">;
+def index_file : Flag<["-"], "index-file">,
+ HelpText<"Produce index data for a source file">, ModeOpt,
+ Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
+def index_file_path : Separate<["-"], "index-file-path">,
+ Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>,
+ HelpText<"Produce index data for file <path>">,
+ MetaVarName<"<path>">;
+
+def index_store_path : Separate<["-"], "index-store-path">,
+ Flags<[FrontendOption]>, MetaVarName<"<path>">,
+ HelpText<"Store indexing data to <path>">;
+
def enforce_exclusivity_EQ : Joined<["-"], "enforce-exclusivity=">,
Flags<[FrontendOption]>, MetaVarName<"<enforcement>">,
HelpText<"Enforce law of exclusivity">;
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index a7dd881..2d44cbf 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1681,7 +1681,7 @@
if (auto funcTy = signature.InterfaceType->getAs<AnyFunctionType>()) {
signature.InterfaceType
= GenericFunctionType::get(genericSig,
- funcTy->getInput(),
+ funcTy->getParams(),
funcTy->getResult(),
funcTy->getExtInfo())
->getCanonicalType();
@@ -3021,9 +3021,8 @@
// Tuples preserve variance.
if (auto tuple = type->getAs<TupleType>()) {
auto kind = SelfReferenceKind::None();
- for (auto &elt: tuple->getElements()) {
- kind |= findProtocolSelfReferences(proto, elt.getType(),
- skipAssocTypes);
+ for (auto &elt : tuple->getElements()) {
+ kind |= findProtocolSelfReferences(proto, elt.getType(), skipAssocTypes);
}
return kind;
}
@@ -3031,8 +3030,11 @@
// Function preserve variance in the result type, and flip variance in
// the parameter type.
if (auto funcTy = type->getAs<AnyFunctionType>()) {
- auto inputKind = findProtocolSelfReferences(proto, funcTy->getInput(),
- skipAssocTypes);
+ auto inputKind = SelfReferenceKind::None();
+ for (auto &elt : funcTy->getParams()) {
+ inputKind |= findProtocolSelfReferences(proto, elt.getType(),
+ skipAssocTypes);
+ }
auto resultKind = findProtocolSelfReferences(proto, funcTy->getResult(),
skipAssocTypes);
@@ -3292,8 +3294,7 @@
LookUpConformanceInModule(module));
builder.addGenericParameter(selfType);
auto selfPA =
- builder.resolveArchetype(selfType,
- ArchetypeResolutionKind::CompleteWellFormed);
+ builder.resolveArchetype(selfType, ArchetypeResolutionKind::WellFormed);
builder.addRequirement(
requirement,
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index 9870f8f..e41522e 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -488,21 +488,25 @@
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return false;
- pa = pa->getRepresentative();
+ if (pa->isConcreteType()) return false;
// If this type was mapped to a concrete type, then there is no
// requirement.
+ pa = pa->getRepresentative();
+
if (pa->isConcreteType()) return false;
// If there is a layout constraint, it might be a class.
- if (auto layout = pa->getLayout())
- if (layout->isClass())
- return true;
+ if (auto layout = pa->getLayout()) {
+ if (layout->isClass()) return true;
+ }
// If there is a superclass bound, then obviously it must be a class.
+ // FIXME: We shouldn't need this?
if (pa->getSuperclass()) return true;
// If any of the protocols are class-bound, then it must be a class.
+ // FIXME: We shouldn't need this?
for (auto proto : pa->getConformsTo()) {
if (proto->requiresClass()) return true;
}
@@ -519,8 +523,6 @@
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return nullptr;
- pa = pa->getRepresentative();
-
// If this type was mapped to a concrete type, then there is no
// requirement.
if (pa->isConcreteType()) return nullptr;
@@ -540,8 +542,6 @@
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return { };
- pa = pa->getRepresentative();
-
// If this type was mapped to a concrete type, then there are no
// requirements.
if (pa->isConcreteType()) return { };
@@ -567,8 +567,6 @@
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return false;
- pa = pa->getRepresentative();
-
// FIXME: Deal with concrete conformances here?
if (pa->isConcreteType()) return false;
@@ -596,9 +594,6 @@
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return Type();
- pa = pa->getRepresentative();
- if (!pa->isConcreteType()) return Type();
-
return pa->getConcreteType();
}
@@ -611,7 +606,6 @@
builder.resolveArchetype(type, ArchetypeResolutionKind::CompleteWellFormed);
if (!pa) return LayoutConstraint();
- pa = pa->getRepresentative();
return pa->getLayout();
}
@@ -882,7 +876,7 @@
auto pa =
inProtoSigBuilder.resolveArchetype(
storedType,
- ArchetypeResolutionKind::WellFormed);
+ ArchetypeResolutionKind::CompleteWellFormed);
auto equivClass = pa->getOrCreateEquivalenceClass();
// Find the conformance of this potential archetype to the protocol in
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index 981d26e..a95d2bb 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -1063,37 +1063,6 @@
return true;
}
- // For a nested type match, look for another type with that name.
- // FIXME: Actually, look for 5 of them. This is totally bogus.
- if (kind == NestedTypeNameMatch) {
- unsigned grossCount = 0;
- auto pa = storage.dyn_cast<const RequirementSource *>()
- ->getAffectedPotentialArchetype();
- while (auto parent = pa->getParent()) {
- if (pa->getNestedName() == nestedName) {
- if (++grossCount > 4) {
- ++NumRecursive;
- return true;
- }
- }
-
- pa = parent;
- }
-
- // Also check the root type.
- grossCount = 0;
- for (Type type = rootType;
- auto depTy = type->getAs<DependentMemberType>();
- type = depTy->getBase()) {
- if (depTy->getName() == nestedName) {
- if (++grossCount > 4) {
- ++NumRecursive;
- return true;
- }
- }
- }
- }
-
return false;
}
@@ -1960,14 +1929,10 @@
}
case ArchetypeResolutionKind::AlreadyKnown:
- break;
+ return nullptr;
}
}
- // If we still don't have a result potential archetype, we're done.
- if (!resultPA)
- return nullptr;
-
// If we have a potential archetype that requires more processing, do so now.
if (shouldUpdatePA) {
// For concrete types, introduce a same-type requirement to the aliased
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 32dab3c..0f13814 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -694,7 +694,7 @@
// Determine the input and result types of this function.
auto fnType = this->castTo<AnyFunctionType>();
- Type inputType = fnType->getInput();
+ auto inputType = fnType->getParams();
Type resultType =
fnType->getResult()->replaceCovariantResultType(newResultType,
uncurryLevel - 1);
diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp
index 3ac1d7c..4343e1a 100644
--- a/lib/ClangImporter/ClangImporter.cpp
+++ b/lib/ClangImporter/ClangImporter.cpp
@@ -46,6 +46,7 @@
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Index/IndexingAction.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/Preprocessor.h"
@@ -705,6 +706,11 @@
invocationArgStrs.push_back(overrideResourceDir);
}
+ if (!importerOpts.IndexStorePath.empty()) {
+ invocationArgStrs.push_back("-index-store-path");
+ invocationArgStrs.push_back(importerOpts.IndexStorePath);
+ }
+
for (auto extraArg : importerOpts.ExtraArgs) {
invocationArgStrs.push_back(extraArg);
}
@@ -1306,6 +1312,7 @@
invocation->getFrontendOpts().Inputs.push_back(
clang::FrontendInputFile(headerPath, clang::IK_ObjC));
invocation->getFrontendOpts().OutputFile = outputPCHPath;
+ invocation->getFrontendOpts().ProgramAction = clang::frontend::GeneratePCH;
invocation->getPreprocessorOpts().resetNonModularOptions();
clang::CompilerInstance emitInstance(
@@ -1319,8 +1326,15 @@
emitInstance.createSourceManager(fileManager);
emitInstance.setTarget(&Impl.Instance->getTarget());
- clang::GeneratePCHAction action;
- emitInstance.ExecuteAction(action);
+ std::unique_ptr<clang::FrontendAction> action;
+ action.reset(new clang::GeneratePCHAction());
+ if (!emitInstance.getFrontendOpts().IndexStorePath.empty()) {
+ action = clang::index::
+ createIndexDataRecordingAction(emitInstance.getFrontendOpts(),
+ std::move(action));
+ }
+ emitInstance.ExecuteAction(*action);
+
if (emitInstance.getDiagnostics().hasErrorOccurred()) {
Impl.SwiftContext.Diags.diagnose({},
diag::bridging_header_pch_error,
@@ -1407,6 +1421,17 @@
auto importRAII = diagClient.handleImport(clangPath.front().first,
importLoc);
+ std::string preservedIndexStorePathOption;
+ auto &clangFEOpts = Impl.Instance->getFrontendOpts();
+ if (!clangFEOpts.IndexStorePath.empty()) {
+ StringRef moduleName = path[0].first->getName();
+ // Ignore the SwiftShims module for the index data.
+ if (moduleName == Impl.SwiftContext.SwiftShimsModuleName.str()) {
+ preservedIndexStorePathOption = clangFEOpts.IndexStorePath;
+ clangFEOpts.IndexStorePath.clear();
+ }
+ }
+
// FIXME: The source location here is completely bogus. It can't be
// invalid, it can't be the same thing twice in a row, and it has to come
// from an actual buffer, so we make a fake buffer and just use a counter.
@@ -1427,6 +1452,12 @@
clang::ModuleLoadResult result =
Impl.Instance->loadModule(clangImportLoc, path, visibility,
/*IsInclusionDirective=*/false);
+
+ if (!preservedIndexStorePathOption.empty()) {
+ // Restore the -index-store-path option.
+ clangFEOpts.IndexStorePath = preservedIndexStorePathOption;
+ }
+
if (result && makeVisible)
Impl.getClangPreprocessor().makeModuleVisible(result, clangImportLoc);
return result;
diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp
index c2367b1..2e580e9 100644
--- a/lib/ClangImporter/ImportDecl.cpp
+++ b/lib/ClangImporter/ImportDecl.cpp
@@ -1434,7 +1434,7 @@
return fnType;
Type interfaceType = GenericFunctionType::get(
- sig, fnType->getInput(), fnType->getResult(), AnyFunctionType::ExtInfo());
+ sig, fnType->getParams(), fnType->getResult(), AnyFunctionType::ExtInfo());
return interfaceType;
}
@@ -1552,9 +1552,7 @@
->castTo<AnyFunctionType>()
->getResult()
->castTo<AnyFunctionType>()
- ->getInput()
- ->castTo<TupleType>()
- ->getElementType(0);
+ ->getParams().front().getType();
ParamDecl *keyDecl = PL->get(1);
return {elementType, keyDecl};
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index a9f4eba..f19d8c5 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1153,6 +1153,17 @@
OI.CompilerMode = OutputInfo::Mode::SingleCompile;
break;
+ // BEGIN APPLE-ONLY OUTPUT ACTIONS
+ case options::OPT_index_file:
+ OI.CompilerMode = OutputInfo::Mode::SingleCompile;
+ OI.CompilerOutputType = types::TY_IndexData;
+ break;
+ // END APPLE-ONLY OUTPUT ACTIONS
+
+ case options::OPT_update_code:
+ OI.CompilerOutputType = types::TY_Remapping;
+ OI.LinkAction = LinkKind::None;
+ break;
case options::OPT_parse:
case options::OPT_typecheck:
case options::OPT_dump_parse:
@@ -1329,6 +1340,27 @@
OI.SelectedSanitizer);
}
+static void
+currentDependsOnPCHIfPresent(JobAction *PCH,
+ std::unique_ptr<Action> &Current,
+ ActionList &Actions) {
+ if (PCH) {
+ // FIXME: When we have a PCH job, it's officially owned by the Actions
+ // array; but it's also a secondary input to each of the current
+ // JobActions, which means that we need to flip the "owns inputs" bit
+ // on the JobActions so they don't try to free it. That in turn means
+ // we need to transfer ownership of all the JobActions' existing
+ // inputs to the Actions array, since the JobActions either own or
+ // don't own _all_ of their inputs. Ownership can't vary
+ // input-by-input.
+ auto *job = cast<JobAction>(Current.get());
+ auto inputs = job->getInputs();
+ Actions.append(inputs.begin(), inputs.end());
+ job->setOwnsInputs(false);
+ job->addInput(PCH);
+ }
+}
+
void Driver::buildActions(const ToolChain &TC,
const DerivedArgList &Args,
const InputFileList &Inputs,
@@ -1393,6 +1425,7 @@
Current.reset(new CompileJobAction(Current.release(),
types::TY_LLVM_BC,
previousBuildState));
+ currentDependsOnPCHIfPresent(PCH, Current, Actions);
AllModuleInputs.push_back(Current.get());
Current.reset(new BackendJobAction(Current.release(),
OI.CompilerOutputType, 0));
@@ -1400,23 +1433,9 @@
Current.reset(new CompileJobAction(Current.release(),
OI.CompilerOutputType,
previousBuildState));
+ currentDependsOnPCHIfPresent(PCH, Current, Actions);
AllModuleInputs.push_back(Current.get());
}
- if (PCH) {
- // FIXME: When we have a PCH job, it's officially owned by the Actions
- // array; but it's also a secondary input to each of the current
- // JobActions, which means that we need to flip the "owns inputs" bit
- // on the JobActions so they don't try to free it. That in turn means
- // we need to transfer ownership of all the JobActions' existing
- // inputs to the Actions array, since the JobActions either own or
- // don't own _all_ of their inputs. Ownership can't vary
- // input-by-input.
- auto *job = cast<JobAction>(Current.get());
- auto inputs = job->getInputs();
- Actions.append(inputs.begin(), inputs.end());
- job->setOwnsInputs(false);
- job->addInput(PCH);
- }
AllLinkerInputs.push_back(Current.release());
break;
}
@@ -1449,6 +1468,7 @@
case types::TY_ClangModuleFile:
case types::TY_SwiftDeps:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_PCH:
case types::TY_ImportedModules:
case types::TY_TBD:
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index d54e990..9032dc3 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -231,6 +231,13 @@
case types::TY_TBD:
FrontendModeOption = "-emit-tbd";
break;
+
+ // BEGIN APPLE-ONLY OUTPUT TYPES
+ case types::TY_IndexData:
+ FrontendModeOption = "-typecheck";
+ break;
+ // END APPLE-ONLY OUTPUT TYPES
+
case types::TY_Remapping:
FrontendModeOption = "-update-code";
break;
@@ -311,6 +318,12 @@
break;
}
case OutputInfo::Mode::SingleCompile: {
+ if (context.Output.getPrimaryOutputType() == types::TY_IndexData) {
+ if (Arg *A = context.Args.getLastArg(options::OPT_index_file_path)) {
+ Arguments.push_back("-primary-file");
+ Arguments.push_back(A->getValue());
+ }
+ }
if (context.Args.hasArg(options::OPT_driver_use_filelists) ||
context.InputActions.size() > TOO_MANY_FILES) {
Arguments.push_back("-filelist");
@@ -456,6 +469,11 @@
if (context.Args.hasArg(options::OPT_embed_bitcode_marker))
Arguments.push_back("-embed-bitcode-marker");
+ if (context.Args.hasArg(options::OPT_index_store_path)) {
+ context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
+ Arguments.push_back("-index-system-modules");
+ }
+
return II;
}
@@ -541,6 +559,7 @@
case types::TY_SIL:
case types::TY_SIB:
case types::TY_PCH:
+ case types::TY_IndexData:
llvm_unreachable("Cannot be output from backend job");
case types::TY_Swift:
case types::TY_dSYM:
@@ -824,6 +843,7 @@
Arguments);
addInputsOfType(Arguments, context.InputActions, types::TY_ObjCHeader);
+ context.Args.AddLastArg(Arguments, options::OPT_index_store_path);
if (job.isPersistentPCH()) {
Arguments.push_back("-emit-pch");
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index e6b87da..d0b60bc 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -92,6 +92,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
return false;
case types::TY_INVALID:
llvm_unreachable("Invalid type ID.");
@@ -128,6 +129,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_ModuleTrace:
return false;
case types::TY_INVALID:
@@ -165,6 +167,7 @@
case types::TY_SwiftDeps:
case types::TY_Nothing:
case types::TY_Remapping:
+ case types::TY_IndexData:
case types::TY_ModuleTrace:
return false;
case types::TY_INVALID:
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 1f60276..a4f5d26 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -169,6 +169,11 @@
Opts.GroupInfoPath = A->getValue();
}
+ if (const Arg *A = Args.getLastArg(OPT_index_store_path)) {
+ Opts.IndexStorePath = A->getValue();
+ }
+ Opts.IndexSystemModules |= Args.hasArg(OPT_index_system_modules);
+
Opts.EmitVerboseSIL |= Args.hasArg(OPT_emit_verbose_sil);
Opts.EmitSortedSIL |= Args.hasArg(OPT_emit_sorted_sil);
@@ -1143,6 +1148,9 @@
if (const Arg *A = Args.getLastArg(OPT_target_cpu))
Opts.TargetCPU = A->getValue();
+ if (const Arg *A = Args.getLastArg(OPT_index_store_path))
+ Opts.IndexStorePath = A->getValue();
+
for (const Arg *A : make_range(Args.filtered_begin(OPT_Xcc),
Args.filtered_end())) {
Opts.ExtraArgs.push_back(A->getValue());
diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp
index 0704189..7075aa6 100644
--- a/lib/Frontend/Frontend.cpp
+++ b/lib/Frontend/Frontend.cpp
@@ -97,6 +97,12 @@
if (!Invocation.getFrontendOptions().ModuleDocOutputPath.empty())
Invocation.getLangOptions().AttachCommentsToDecls = true;
+ // If we are doing index-while-building, configure lexing and parsing to
+ // remember comments.
+ if (!Invocation.getFrontendOptions().IndexStorePath.empty()) {
+ Invocation.getLangOptions().AttachCommentsToDecls = true;
+ }
+
Context.reset(new ASTContext(Invocation.getLangOptions(),
Invocation.getSearchPathOptions(),
SourceMgr, Diagnostics));
diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt
index 1168a59..882b8ab 100644
--- a/lib/FrontendTool/CMakeLists.txt
+++ b/lib/FrontendTool/CMakeLists.txt
@@ -5,6 +5,7 @@
TBD.cpp
DEPENDS SwiftOptions
LINK_LIBRARIES
+ swiftIndex
swiftIDE
swiftTBDGen swiftIRGen swiftSIL swiftSILGen swiftSILOptimizer
swiftDemangling
diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp
index 45a5614..9e3d1de 100644
--- a/lib/FrontendTool/FrontendTool.cpp
+++ b/lib/FrontendTool/FrontendTool.cpp
@@ -48,6 +48,7 @@
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/Frontend/SerializedDiagnosticConsumer.h"
#include "swift/Immediate/Immediate.h"
+#include "swift/Index/IndexRecord.h"
#include "swift/Option/Options.h"
#include "swift/Migrator/FixitFilter.h"
#include "swift/Migrator/Migrator.h"
@@ -368,6 +369,10 @@
LLVM_BUILTIN_TRAP;
}
+static bool emitIndexData(SourceFile *PrimarySourceFile,
+ const CompilerInvocation &Invocation,
+ CompilerInstance &Instance);
+
static void countStatsPostSema(UnifiedStatsReporter &Stats,
CompilerInstance& Instance) {
auto &C = Stats.getFrontendCounters();
@@ -646,8 +651,16 @@
(void)emitLoadedModuleTrace(Context, *Instance.getDependencyTracker(),
opts);
- if (Context.hadError())
+ bool shouldIndex = !opts.IndexStorePath.empty();
+
+ if (Context.hadError()) {
+ if (shouldIndex) {
+ // Emit the index store data even if there were compiler errors.
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return true;
+ }
// FIXME: This is still a lousy approximation of whether the module file will
// be externally consumed.
@@ -661,6 +674,10 @@
if (!opts.ObjCHeaderOutputPath.empty())
return printAsObjC(opts.ObjCHeaderOutputPath, Instance.getMainModule(),
opts.ImplicitObjCHeaderPath, moduleIsPublic);
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return Context.hadError();
}
@@ -858,8 +875,13 @@
serialize(DC, serializationOpts, SM.get());
}
- if (Action == FrontendOptions::EmitModuleOnly)
+ if (Action == FrontendOptions::EmitModuleOnly) {
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
return Context.hadError();
+ }
}
assert(Action >= FrontendOptions::EmitSIL &&
@@ -918,6 +940,13 @@
&HashGlobal);
}
+ // Walk the AST for indexing after IR generation. Walking it before seems
+ // to cause miscompilation issues.
+ if (shouldIndex) {
+ if (emitIndexData(PrimarySourceFile, Invocation, Instance))
+ return true;
+ }
+
// Just because we had an AST error it doesn't mean we can't performLLVM.
bool HadError = Instance.getASTContext().hadError();
@@ -975,6 +1004,52 @@
opts.getSingleOutputFilename(), Stats) || HadError;
}
+static bool emitIndexData(SourceFile *PrimarySourceFile,
+ const CompilerInvocation &Invocation,
+ CompilerInstance &Instance) {
+ const FrontendOptions &opts = Invocation.getFrontendOptions();
+ assert(!opts.IndexStorePath.empty());
+ // FIXME: provide index unit token(s) explicitly and only use output file
+ // paths as a fallback.
+
+ bool isDebugCompilation;
+ switch (Invocation.getSILOptions().Optimization) {
+ case SILOptions::SILOptMode::NotSet:
+ case SILOptions::SILOptMode::None:
+ case SILOptions::SILOptMode::Debug:
+ isDebugCompilation = true;
+ break;
+ case SILOptions::SILOptMode::Optimize:
+ case SILOptions::SILOptMode::OptimizeUnchecked:
+ isDebugCompilation = false;
+ break;
+ }
+
+ if (PrimarySourceFile) {
+ if (index::indexAndRecord(
+ PrimarySourceFile, opts.getSingleOutputFilename(),
+ opts.IndexStorePath, opts.IndexSystemModules,
+ isDebugCompilation, Invocation.getTargetTriple(),
+ *Instance.getDependencyTracker())) {
+ return true;
+ }
+ } else {
+ StringRef moduleToken = opts.ModuleOutputPath;
+ if (moduleToken.empty())
+ moduleToken = opts.getSingleOutputFilename();
+
+ if (index::indexAndRecord(Instance.getMainModule(), opts.OutputFilenames,
+ moduleToken, opts.IndexStorePath,
+ opts.IndexSystemModules,
+ isDebugCompilation, Invocation.getTargetTriple(),
+ *Instance.getDependencyTracker())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Returns true if an error occurred.
static bool dumpAPI(ModuleDecl *Mod, StringRef OutDir) {
using namespace llvm::sys;
@@ -1231,6 +1306,7 @@
DependencyTracker depTracker;
if (!Invocation.getFrontendOptions().DependenciesFilePath.empty() ||
!Invocation.getFrontendOptions().ReferenceDependenciesFilePath.empty() ||
+ !Invocation.getFrontendOptions().IndexStorePath.empty() ||
!Invocation.getFrontendOptions().LoadedModuleTracePath.empty()) {
Instance->setDependencyTracker(&depTracker);
}
diff --git a/lib/IDE/SwiftSourceDocInfo.cpp b/lib/IDE/SwiftSourceDocInfo.cpp
index 5e6cfd0..b4af1ff 100644
--- a/lib/IDE/SwiftSourceDocInfo.cpp
+++ b/lib/IDE/SwiftSourceDocInfo.cpp
@@ -108,14 +108,6 @@
return false;
}
-bool SemaLocResolver::tryResolve(Expr *Exp) {
- if (!Exp->isImplicit() && Exp->getStartLoc() == LocToResolve) {
- SemaTok = { Exp };
- return true;
- }
- return false;
-}
-
bool SemaLocResolver::visitSubscriptReference(ValueDecl *D, CharSourceRange Range,
bool IsOpenBracket) {
// We should treat both open and close brackets equally
@@ -193,6 +185,10 @@
ContainerType = ME->getBase()->getType();
}
}
+
+ // Keep track of trailing expressions.
+ if (!E->isImplicit() && E->getStartLoc() == LocToResolve)
+ TrailingExprStack.push_back(E);
}
return true;
}
@@ -200,7 +196,12 @@
bool SemaLocResolver::walkToExprPost(Expr *E) {
if (isDone())
return false;
- return !tryResolve(E);
+ if (!TrailingExprStack.empty() && TrailingExprStack.back() == E) {
+ // We return the outtermost expression in the token info.
+ SemaTok = { TrailingExprStack.front() };
+ return false;
+ }
+ return true;
}
bool SemaLocResolver::visitCallArgName(Identifier Name, CharSourceRange Range,
diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp
index b936bf1..539141f 100644
--- a/lib/IRGen/IRGenModule.cpp
+++ b/lib/IRGen/IRGenModule.cpp
@@ -814,9 +814,11 @@
attrsUpdated = attrsUpdated.addAttribute(LLVMContext,
llvm::AttributeSet::FunctionIndex, "target-cpu", CPU);
- std::vector<std::string> &Features = ClangOpts.Features;
+ std::vector<std::string> Features = ClangOpts.Features;
if (!Features.empty()) {
SmallString<64> allFeatures;
+ // Sort so that the target features string is canonical.
+ std::sort(Features.begin(), Features.end());
interleave(Features, [&](const std::string &s) {
allFeatures.append(s);
}, [&]{
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index d91c5a8..47aee9a 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -1,6 +1,7 @@
add_swift_library(swiftIndex STATIC
Index.cpp
IndexDataConsumer.cpp
+ IndexRecord.cpp
IndexSymbol.cpp
LINK_LIBRARIES
swiftAST)
diff --git a/lib/Index/IndexRecord.cpp b/lib/Index/IndexRecord.cpp
new file mode 100644
index 0000000..91be812
--- /dev/null
+++ b/lib/Index/IndexRecord.cpp
@@ -0,0 +1,747 @@
+//===--- IndexRecord.cpp --------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
+// Licensed under Apache License v2.0 with Runtime Library Exception
+//
+// See http://swift.org/LICENSE.txt for license information
+// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
+//
+//===----------------------------------------------------------------------===//
+
+#include "swift/Index/IndexRecord.h"
+#include "swift/AST/ASTContext.h"
+#include "swift/AST/Decl.h"
+#include "swift/AST/Expr.h"
+#include "swift/AST/Module.h"
+#include "swift/AST/ParameterList.h"
+#include "swift/AST/Pattern.h"
+#include "swift/AST/Stmt.h"
+#include "swift/AST/Types.h"
+#include "swift/AST/DiagnosticsFrontend.h"
+#include "swift/AST/ModuleLoader.h"
+#include "swift/ClangImporter/ClangModule.h"
+#include "swift/Index/Index.h"
+#include "swift/Strings.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Index/IndexRecordWriter.h"
+#include "clang/Index/IndexUnitWriter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/Path.h"
+
+using namespace swift;
+using namespace swift::index;
+using clang::index::IndexUnitWriter;
+using clang::index::IndexRecordWriter;
+using clang::index::SymbolRole;
+using clang::index::SymbolRoleSet;
+
+//===----------------------------------------------------------------------===//
+// Index data collection and record writing
+//===----------------------------------------------------------------------===//
+
+namespace {
+class SymbolTracker {
+public:
+ struct SymbolRelation {
+ size_t symbolIndex;
+ SymbolRoleSet roles;
+
+ llvm::hash_code hash() const { return llvm::hash_combine(symbolIndex, roles); }
+ };
+ struct SymbolOccurrence {
+ size_t symbolIndex;
+ SymbolRoleSet roles;
+ unsigned line;
+ unsigned column;
+ SmallVector<SymbolRelation, 3> related;
+
+ llvm::hash_code hash() const {
+ auto hash = llvm::hash_combine(symbolIndex, roles, line, column);
+ for (auto &relation : related) {
+ hash = llvm::hash_combine(hash, relation.hash());
+ }
+ return hash;
+ }
+ };
+ struct Symbol {
+ StringRef name;
+ StringRef USR;
+ StringRef group;
+
+ SymbolInfo symInfo;
+ unsigned isTestCandidate : 1;
+
+ llvm::hash_code hash() const {
+ return llvm::hash_combine(
+ name, USR, group,
+ static_cast<unsigned>(symInfo.Kind),
+ static_cast<unsigned>(symInfo.SubKind),
+ symInfo.Properties, isTestCandidate);
+ }
+ };
+
+ Symbol *getSymbol(size_t index) {
+ assert(index < symbols.size());
+ return &symbols[index];
+ }
+
+ ArrayRef<SymbolOccurrence> getOccurrences() {
+ if (!sorted) {
+ std::stable_sort(occurrences.begin(), occurrences.end(),
+ [](const SymbolOccurrence &a, const SymbolOccurrence& b) {
+ if (a.line < b.line)
+ return true;
+ if (b.line < a.line)
+ return false;
+ return a.column < b.column;
+ });
+ sorted = true;
+ }
+ return occurrences;
+ }
+
+ size_t addSymbol(const IndexRelation &indexSym) {
+ auto pair = USRToSymbol.insert(std::make_pair(indexSym.USR.data(),
+ symbols.size()));
+ if (pair.second) {
+ Symbol symbol{indexSym.name,
+ indexSym.USR,
+ indexSym.group,
+ indexSym.symInfo,
+ 0};
+ recordHash = llvm::hash_combine(recordHash, symbol.hash());
+ symbols.push_back(std::move(symbol));
+ }
+
+ return pair.first->second;
+ }
+
+ void addOccurrence(const IndexSymbol &indexOccur) {
+ sorted = false;
+
+ SmallVector<SymbolRelation, 3> relations;
+ for(IndexRelation indexRel: indexOccur.Relations) {
+ relations.push_back({addSymbol(indexRel), indexRel.roles});
+ }
+
+ occurrences.push_back({/*symbolIndex=*/addSymbol(indexOccur),
+ indexOccur.roles,
+ indexOccur.line,
+ indexOccur.column,
+ std::move(relations)});
+
+ recordHash = llvm::hash_combine(recordHash, occurrences.back().hash());
+ }
+
+ llvm::hash_code hashRecord() const { return recordHash; }
+
+private:
+ llvm::DenseMap<const char *, size_t> USRToSymbol;
+ std::vector<Symbol> symbols;
+ std::vector<SymbolOccurrence> occurrences;
+ bool sorted = false;
+ llvm::hash_code recordHash = 0;
+};
+
+class IndexRecordingConsumer : public IndexDataConsumer {
+ SymbolTracker record;
+ // Keep a USR map to uniquely identify Decls.
+ // FIXME: if we just passed the original Decl * through we could use that,
+ // which would also let us avoid producing the USR/Name/etc. for decls unless
+ // we actually need it (once per Decl instead of once per occurrence).
+ std::vector<IndexSymbol> symbolStack;
+
+ std::function<void(SymbolTracker &)> onFinish;
+
+public:
+ IndexRecordingConsumer(std::function<void(SymbolTracker &)> onFinish)
+ : onFinish(std::move(onFinish)) {}
+
+ void failed(StringRef error) override {
+ // FIXME: expose errors?
+ }
+
+ bool recordHash(StringRef hash, bool isKnown) override { return true; }
+ bool startDependency(StringRef name, StringRef path, bool isClangModule,
+ bool isSystem, StringRef hash) override {
+ return true;
+ }
+ bool finishDependency(bool isClangModule) override { return true; }
+ Action startSourceEntity(const IndexSymbol &symbol) override {
+ symbolStack.push_back(symbol);
+ return Action::Continue;
+ }
+ bool finishSourceEntity(SymbolInfo sym, SymbolRoleSet roles) override {
+ IndexSymbol symbol = std::move(symbolStack.back());
+ symbolStack.pop_back();
+ assert(!symbol.USR.empty());
+ record.addOccurrence(symbol);
+ return true;
+ }
+
+ void finish() override { onFinish(record); }
+};
+
+class StdlibGroupsIndexRecordingConsumer : public IndexDataConsumer {
+ llvm::StringMap<std::unique_ptr<SymbolTracker>> TrackerByGroup;
+ // Keep a USR map to uniquely identify Decls.
+ // FIXME: if we just passed the original Decl * through we could use that,
+ // which would also let us avoid producing the USR/Name/etc. for decls unless
+ // we actually need it (once per Decl instead of once per occurrence).
+ std::vector<IndexSymbol> symbolStack;
+
+ std::function<bool(StringRef groupName, SymbolTracker &)> onFinish;
+
+public:
+ StdlibGroupsIndexRecordingConsumer(std::function<bool(StringRef groupName, SymbolTracker &)> onFinish)
+ : onFinish(std::move(onFinish)) {}
+
+ void failed(StringRef error) override {
+ // FIXME: expose errors?
+ }
+
+ bool recordHash(StringRef hash, bool isKnown) override { return true; }
+ bool startDependency(StringRef name, StringRef path, bool isClangModule,
+ bool isSystem, StringRef hash) override {
+ return true;
+ }
+ bool finishDependency(bool isClangModule) override { return true; }
+ Action startSourceEntity(const IndexSymbol &symbol) override {
+ symbolStack.push_back(symbol);
+ return Action::Continue;
+ }
+ bool finishSourceEntity(SymbolInfo sym, SymbolRoleSet roles) override {
+ IndexSymbol symbol = std::move(symbolStack.back());
+ symbolStack.pop_back();
+ assert(!symbol.USR.empty());
+ StringRef groupName = findGroupForSymbol(symbol);
+ auto &tracker = TrackerByGroup[groupName];
+ if (!tracker) {
+ tracker = llvm::make_unique<SymbolTracker>();
+ }
+ tracker->addOccurrence(symbol);
+ return true;
+ }
+
+ void finish() override {
+ for (auto &pair : TrackerByGroup) {
+ StringRef groupName = pair.first();
+ SymbolTracker &tracker = *pair.second;
+ bool cont = onFinish(groupName, tracker);
+ if (!cont)
+ break;
+ }
+ }
+
+private:
+ StringRef findGroupForSymbol(const IndexSymbol &sym);
+
+};
+} // end anonymous namespace
+
+static StringRef findGroupNameForDecl(const Decl *D) {
+ if (!D || isa<ModuleDecl>(D) || isa<TopLevelCodeDecl>(D))
+ return StringRef();
+
+ auto groupNameOpt = D->getGroupName();
+ if (groupNameOpt)
+ return *groupNameOpt;
+
+ return findGroupNameForDecl(D->getDeclContext()->getInnermostDeclarationDeclContext());
+}
+
+StringRef StdlibGroupsIndexRecordingConsumer::findGroupForSymbol(const IndexSymbol &sym) {
+ bool isDeclOrDef = sym.roles & ((SymbolRoleSet)SymbolRole::Declaration | (SymbolRoleSet)SymbolRole::Definition);
+ if (isDeclOrDef) {
+ if (!sym.group.empty())
+ return sym.group;
+ return findGroupNameForDecl(sym.decl);
+ }
+
+ for (auto &rel : sym.Relations) {
+ if (!rel.group.empty())
+ return rel.group;
+ if (rel.decl)
+ return findGroupNameForDecl(rel.decl);
+ }
+ llvm_unreachable("did not find group name for reference");
+}
+
+static bool writeRecord(SymbolTracker &record, std::string Filename,
+ std::string indexStorePath, DiagnosticEngine *diags,
+ std::string &outRecordFile) {
+ if (record.getOccurrences().empty()) {
+ outRecordFile = std::string();
+ return false;
+ }
+
+ IndexRecordWriter recordWriter(indexStorePath);
+ std::string error;
+ auto result = recordWriter.beginRecord(
+ Filename, record.hashRecord(), error, &outRecordFile);
+ switch (result) {
+ case IndexRecordWriter::Result::Failure:
+ diags->diagnose(SourceLoc(), diag::error_write_index_record, error);
+ return true;
+ case IndexRecordWriter::Result::AlreadyExists:
+ return false;
+ case IndexRecordWriter::Result::Success:
+ break;
+ }
+
+ for (auto &occurrence : record.getOccurrences()) {
+ SmallVector<clang::index::writer::SymbolRelation, 3> relations;
+ for(SymbolTracker::SymbolRelation symbolRelation: occurrence.related) {
+ relations.push_back({record.getSymbol(symbolRelation.symbolIndex), symbolRelation.roles});
+ }
+
+ recordWriter.addOccurrence(
+ record.getSymbol(occurrence.symbolIndex), occurrence.roles,
+ occurrence.line, occurrence.column, relations);
+ }
+
+ result = recordWriter.endRecord(error,
+ [&](clang::index::writer::OpaqueDecl opaqueSymbol,
+ SmallVectorImpl<char> &scratch) {
+ auto *symbol = static_cast<const SymbolTracker::Symbol *>(opaqueSymbol);
+ clang::index::writer::Symbol result;
+ result.SymInfo = symbol->symInfo;
+ result.Name = symbol->name;
+ result.USR = symbol->USR;
+ result.CodeGenName = ""; // FIXME
+ return result;
+ });
+
+ if (result == IndexRecordWriter::Result::Failure) {
+ diags->diagnose(SourceLoc(), diag::error_write_index_record, error);
+ return true;
+ }
+
+ return false;
+}
+
+static std::unique_ptr<IndexRecordingConsumer>
+makeRecordingConsumer(std::string Filename, std::string indexStorePath,
+ DiagnosticEngine *diags,
+ std::string *outRecordFile,
+ bool *outFailed) {
+ return llvm::make_unique<IndexRecordingConsumer>([=](SymbolTracker &record) {
+ *outFailed = writeRecord(record, Filename, indexStorePath, diags,
+ *outRecordFile);
+ });
+}
+
+static bool
+recordSourceFile(SourceFile *SF, StringRef indexStorePath,
+ DiagnosticEngine &diags,
+ llvm::function_ref<void(StringRef, StringRef)> callback) {
+ std::string recordFile;
+ bool failed = false;
+ auto consumer = makeRecordingConsumer(SF->getFilename(), indexStorePath,
+ &diags, &recordFile, &failed);
+ indexSourceFile(SF, /*Hash=*/"", *consumer);
+
+ if (!failed && !recordFile.empty())
+ callback(recordFile, SF->getFilename());
+ return failed;
+}
+
+//===----------------------------------------------------------------------===//
+// Index unit file writing
+//===----------------------------------------------------------------------===//
+
+// Used to get std::string pointers to pass as writer::OpaqueModule.
+namespace {
+class StringScratchSpace {
+ std::vector<const std::string *> StrsCreated;
+
+public:
+ const std::string *createString(StringRef str) {
+ auto *s = new std::string(str);
+ StrsCreated.push_back(s);
+ return s;
+ }
+
+ ~StringScratchSpace() {
+ for (auto *str : StrsCreated)
+ delete str;
+ }
+};
+}
+
+static clang::index::writer::ModuleInfo
+getModuleInfoFromOpaqueModule(clang::index::writer::OpaqueModule mod,
+ SmallVectorImpl<char> &Scratch) {
+ clang::index::writer::ModuleInfo info;
+ info.Name = *static_cast<const std::string*>(mod);
+ return info;
+}
+
+static bool
+emitDataForSwiftSerializedModule(ModuleDecl *module,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &parentUnitWriter);
+
+static void addModuleDependencies(ArrayRef<ModuleDecl::ImportedModule> imports,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &unitWriter,
+ StringScratchSpace &moduleNameScratch) {
+ auto &fileMgr = clangCI.getFileManager();
+
+ for (auto &import : imports) {
+ ModuleDecl *mod = import.second;
+ if (mod->getNameStr() == SWIFT_ONONE_SUPPORT)
+ continue; // ignore the Onone support library.
+ if (mod->isSwiftShimsModule())
+ continue;
+
+ for (auto *FU : mod->getFiles()) {
+ switch (FU->getKind()) {
+ case FileUnitKind::Source:
+ case FileUnitKind::Derived:
+ case FileUnitKind::Builtin:
+ break;
+ case FileUnitKind::SerializedAST:
+ case FileUnitKind::ClangModule: {
+ auto *LFU = cast<LoadedFile>(FU);
+ if (auto *F = fileMgr.getFile(LFU->getFilename())) {
+ std::string moduleName = mod->getNameStr();
+ bool withoutUnitName = true;
+ if (FU->getKind() == FileUnitKind::ClangModule) {
+ withoutUnitName = false;
+ auto clangModUnit = cast<ClangModuleUnit>(LFU);
+ if (auto clangMod = clangModUnit->getUnderlyingClangModule()) {
+ moduleName = clangMod->getTopLevelModuleName();
+ // FIXME: clang's -Rremarks do not seem to go through Swift's
+ // diagnostic emitter.
+ clang::index::emitIndexDataForModuleFile(clangMod,
+ clangCI, unitWriter);
+ }
+ } else {
+ // Serialized AST file.
+ // Only index system modules (essentially stdlib and overlays).
+ // We don't officially support binary swift modules, so normally
+ // the index data for user modules would get generated while
+ // building them.
+ if (mod->isSystemModule() && indexSystemModules) {
+ emitDataForSwiftSerializedModule(mod, indexStorePath,
+ indexSystemModules,
+ targetTriple, clangCI, diags,
+ unitWriter);
+ withoutUnitName = false;
+ }
+ }
+ clang::index::writer::OpaqueModule opaqMod =
+ moduleNameScratch.createString(moduleName);
+ unitWriter.addASTFileDependency(F, mod->isSystemModule(), opaqMod,
+ withoutUnitName);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/// \returns true if an error occurred.
+static bool
+emitDataForSwiftSerializedModule(ModuleDecl *module,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ StringRef targetTriple,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags,
+ IndexUnitWriter &parentUnitWriter) {
+ StringRef filename = module->getModuleFilename();
+ std::string moduleName = module->getNameStr();
+
+ std::string error;
+ auto isUptodateOpt = parentUnitWriter.isUnitUpToDateForOutputFile(/*FilePath=*/filename,
+ /*TimeCompareFilePath=*/filename, error);
+ if (!isUptodateOpt.hasValue()) {
+ diags.diagnose(SourceLoc(), diag::error_index_failed_status_check, error);
+ return true;
+ }
+ if (*isUptodateOpt)
+ return false;
+
+ // FIXME: Would be useful for testing if swift had clang's -Rremark system so
+ // we could output a remark here that we are going to create index data for
+ // a module file.
+
+ // Pairs of (recordFile, groupName).
+ std::vector<std::pair<std::string, std::string>> records;
+
+ if (!module->isStdlibModule()) {
+ std::string recordFile;
+ bool failed = false;
+ auto consumer = makeRecordingConsumer(filename, indexStorePath,
+ &diags, &recordFile, &failed);
+ indexModule(module, /*Hash=*/"", *consumer);
+
+ if (failed)
+ return true;
+
+ records.emplace_back(recordFile, moduleName);
+ } else {
+ // Record stdlib groups as if they were submodules.
+
+ auto makeSubmoduleNameFromGroupName = [](StringRef groupName, SmallString<128> &buf) {
+ buf += "Swift";
+ if (groupName.empty())
+ return;
+ buf += '.';
+ for (char ch : groupName) {
+ if (ch == '/')
+ buf += '.';
+ else if (ch == ' ' || ch == '-')
+ buf += '_';
+ else
+ buf += ch;
+ }
+ };
+ auto appendGroupNameForFilename = [](StringRef groupName, SmallString<256> &buf) {
+ if (groupName.empty())
+ return;
+ buf += '_';
+ for (char ch : groupName) {
+ if (ch == '/' || ch ==' ')
+ buf += '_';
+ else
+ buf += ch;
+ }
+ };
+
+ bool failed = false;
+ StdlibGroupsIndexRecordingConsumer groupIndexConsumer([&](StringRef groupName, SymbolTracker &tracker) -> bool {
+ SmallString<128> moduleName;
+ makeSubmoduleNameFromGroupName(groupName, moduleName);
+ SmallString<256> fileNameWithGroup = filename;
+ appendGroupNameForFilename(groupName, fileNameWithGroup);
+
+ std::string outRecordFile;
+ failed = failed || writeRecord(tracker, fileNameWithGroup.str(), indexStorePath, &diags, outRecordFile);
+ if (failed)
+ return false;
+ records.emplace_back(outRecordFile, moduleName.str());
+ return true;
+ });
+ indexModule(module, /*Hash=*/"", groupIndexConsumer);
+ if (failed)
+ return true;
+ }
+
+ auto &fileMgr = clangCI.getFileManager();
+ bool isSystem = module->isSystemModule();
+ // FIXME: Get real values for the following.
+ StringRef swiftVersion;
+ StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot;
+ std::string indexUnitToken = module->getModuleFilename();
+ // For indexing serialized modules 'debug compilation' is irrelevant, so
+ // set it to true by default.
+ bool isDebugCompilation = true;
+
+ IndexUnitWriter unitWriter(fileMgr, indexStorePath,
+ "swift", swiftVersion, indexUnitToken, moduleName,
+ /*MainFile=*/nullptr, isSystem, /*IsModuleUnit=*/true,
+ isDebugCompilation, targetTriple, sysrootPath, getModuleInfoFromOpaqueModule);
+
+ const clang::FileEntry *FE = fileMgr.getFile(filename);
+ bool isSystemModule = module->isSystemModule();
+ for (auto &pair : records) {
+ std::string &recordFile = pair.first;
+ std::string &groupName = pair.second;
+ if (recordFile.empty())
+ continue;
+ clang::index::writer::OpaqueModule mod = &groupName;
+ unitWriter.addRecordFile(recordFile, FE, isSystemModule, mod);
+ }
+
+ SmallVector<ModuleDecl::ImportedModule, 8> imports;
+ module->getImportedModules(imports, ModuleDecl::ImportFilter::All);
+ StringScratchSpace moduleNameScratch;
+ addModuleDependencies(imports, indexStorePath, indexSystemModules,
+ targetTriple, clangCI, diags, unitWriter, moduleNameScratch);
+
+ if (unitWriter.write(error)) {
+ diags.diagnose(SourceLoc(), diag::error_write_index_unit, error);
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+recordSourceFileUnit(SourceFile *primarySourceFile, StringRef indexUnitToken,
+ StringRef indexStorePath, bool indexSystemModules,
+ bool isDebugCompilation, StringRef targetTriple,
+ ArrayRef<const clang::FileEntry *> fileDependencies,
+ const clang::CompilerInstance &clangCI,
+ DiagnosticEngine &diags) {
+ auto &fileMgr = clangCI.getFileManager();
+ auto *module = primarySourceFile->getParentModule();
+ bool isSystem = module->isSystemModule();
+ auto *mainFile = fileMgr.getFile(primarySourceFile->getFilename());
+ // FIXME: Get real values for the following.
+ StringRef swiftVersion;
+ StringRef sysrootPath = clangCI.getHeaderSearchOpts().Sysroot;
+
+ IndexUnitWriter unitWriter(fileMgr, indexStorePath,
+ "swift", swiftVersion, indexUnitToken, module->getNameStr(),
+ mainFile, isSystem, /*isModuleUnit=*/false, isDebugCompilation,
+ targetTriple, sysrootPath, getModuleInfoFromOpaqueModule);
+
+ // Module dependencies.
+ SmallVector<ModuleDecl::ImportedModule, 8> imports;
+ primarySourceFile->getImportedModules(imports, ModuleDecl::ImportFilter::All);
+ StringScratchSpace moduleNameScratch;
+ addModuleDependencies(imports, indexStorePath, indexSystemModules,
+ targetTriple, clangCI, diags, unitWriter, moduleNameScratch);
+
+ // File dependencies.
+ for (auto *F : fileDependencies)
+ unitWriter.addFileDependency(F, /*FIXME:isSystem=*/false, /*Module=*/nullptr);
+
+ recordSourceFile(primarySourceFile, indexStorePath, diags,
+ [&](StringRef recordFile, StringRef filename) {
+ unitWriter.addRecordFile(recordFile, fileMgr.getFile(filename),
+ module->isSystemModule(), /*Module=*/nullptr);
+ });
+
+ std::string error;
+ if (unitWriter.write(error)) {
+ diags.diagnose(SourceLoc(), diag::error_write_index_unit, error);
+ return true;
+ }
+
+ return false;
+}
+
+// Not currently used, see related comments in the call sites.
+#if 0
+static void
+collectFileDependencies(llvm::SetVector<const clang::FileEntry *> &result,
+ const DependencyTracker &dependencyTracker,
+ ModuleDecl *module, clang::FileManager &fileMgr) {
+ for (auto *F : module->getFiles()) {
+ if (auto *SF = dyn_cast<SourceFile>(F)) {
+ if (auto *dep = fileMgr.getFile(SF->getFilename())) {
+ result.insert(dep);
+ }
+ }
+ }
+ for (StringRef filename : dependencyTracker.getDependencies()) {
+ if (auto *F = fileMgr.getFile(filename))
+ result.insert(F);
+ }
+}
+#endif
+
+//===----------------------------------------------------------------------===//
+// Indexing entry points
+//===----------------------------------------------------------------------===//
+
+bool index::indexAndRecord(SourceFile *primarySourceFile,
+ StringRef indexUnitToken,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker) {
+ auto &astContext = primarySourceFile->getASTContext();
+ auto &clangCI = astContext.getClangModuleLoader()->getClangInstance();
+ auto &diags = astContext.Diags;
+
+ std::string error;
+ if (IndexUnitWriter::initIndexDirectory(indexStorePath, error)) {
+ diags.diagnose(SourceLoc(), diag::error_create_index_dir, error);
+ return true;
+ }
+
+ llvm::SetVector<const clang::FileEntry *> fileDependencies;
+ // FIXME: This is not desirable because:
+ // 1. It picks shim header files as file dependencies
+ // 2. Having all the other swift files of the module as file dependencies ends
+ // up making all of them associated with all the other files as main files.
+ // It's better to associate each swift file with the unit that recorded it
+ // as the main one.
+ // Keeping the code in case we want to revisit.
+#if 0
+ auto *module = primarySourceFile->getParentModule();
+ collectFileDependencies(fileDependencies, dependencyTracker, module, fileMgr);
+#endif
+
+ return recordSourceFileUnit(primarySourceFile, indexUnitToken,
+ indexStorePath, indexSystemModules,
+ isDebugCompilation, targetTriple,
+ fileDependencies.getArrayRef(),
+ clangCI, diags);
+}
+
+bool index::indexAndRecord(ModuleDecl *module,
+ ArrayRef<std::string> indexUnitTokens,
+ StringRef moduleUnitToken,
+ StringRef indexStorePath,
+ bool indexSystemModules,
+ bool isDebugCompilation,
+ StringRef targetTriple,
+ const DependencyTracker &dependencyTracker) {
+ auto &astContext = module->getASTContext();
+ auto &clangCI = astContext.getClangModuleLoader()->getClangInstance();
+ auto &diags = astContext.Diags;
+
+ std::string error;
+ if (IndexUnitWriter::initIndexDirectory(indexStorePath, error)) {
+ diags.diagnose(SourceLoc(), diag::error_create_index_dir, error);
+ return true;
+ }
+
+ // Add the current module's source files to the dependencies.
+ llvm::SetVector<const clang::FileEntry *> fileDependencies;
+ // FIXME: This is not desirable because:
+ // 1. It picks shim header files as file dependencies
+ // 2. Having all the other swift files of the module as file dependencies ends
+ // up making all of them associated with all the other files as main files.
+ // It's better to associate each swift file with the unit that recorded it
+ // as the main one.
+ // Keeping the code in case we want to revisit.
+#if 0
+ collectFileDependencies(fileDependencies, dependencyTracker, module, fileMgr);
+#endif
+
+ // Write a unit for each source file.
+ unsigned unitIndex = 0;
+ for (auto *F : module->getFiles()) {
+ if (auto *SF = dyn_cast<SourceFile>(F)) {
+ if (unitIndex == indexUnitTokens.size()) {
+ diags.diagnose(SourceLoc(), diag::error_index_inputs_more_than_outputs);
+ return true;
+ }
+ if (recordSourceFileUnit(SF, indexUnitTokens[unitIndex],
+ indexStorePath, indexSystemModules,
+ isDebugCompilation, targetTriple,
+ fileDependencies.getArrayRef(),
+ clangCI, diags))
+ return true;
+ unitIndex += 1;
+ }
+ }
+
+ // In the case where inputs are swift modules, like in the merge-module step,
+ // ignore the inputs; associated unit files for the modules' source inputs
+ // should have been generated at swift module creation time.
+
+ return false;
+}
diff --git a/lib/Migrator/TupleSplatMigratorPass.cpp b/lib/Migrator/TupleSplatMigratorPass.cpp
index 8c77492..360cbe4 100644
--- a/lib/Migrator/TupleSplatMigratorPass.cpp
+++ b/lib/Migrator/TupleSplatMigratorPass.cpp
@@ -88,13 +88,7 @@
FunctionType *FuncTy = FC->getType()->getAs<FunctionType>();
- unsigned NativeArity = 0;
- if (isa<ParenType>(FuncTy->getInput().getPointer())) {
- NativeArity = 1;
- } else if (auto TT = FuncTy->getInput()->getAs<TupleType>()) {
- NativeArity = TT->getNumElements();
- }
-
+ unsigned NativeArity = FuncTy->getParams().size();
unsigned ClosureArity = Closure->getParameters()->size();
if (NativeArity <= ClosureArity)
return false;
@@ -149,10 +143,10 @@
auto fnTy = E->getFn()->getType()->getAs<FunctionType>();
if (!fnTy)
return false;
- auto parenT = dyn_cast<ParenType>(fnTy->getInput().getPointer());
- if (!parenT)
+ if (!(fnTy->getParams().size() == 1 &&
+ fnTy->getParams().front().getLabel().empty()))
return false;
- auto inp = dyn_cast<TupleType>(parenT->getUnderlyingType().getPointer());
+ auto inp = fnTy->getParams().front().getType()->getAs<TupleType>();
if (!inp)
return false;
if (inp->getNumElements() != 0)
diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp
index 096c24d..5f23538 100644
--- a/lib/PrintAsObjC/PrintAsObjC.cpp
+++ b/lib/PrintAsObjC/PrintAsObjC.cpp
@@ -1719,7 +1719,7 @@
os << ")(";
Type paramsTy = FT->getInput();
if (auto tupleTy = paramsTy->getAs<TupleType>()) {
- if (tupleTy->getNumElements() == 0) {
+ if (FT->getParams().empty()) {
os << "void";
} else {
interleave(tupleTy->getElements(),
diff --git a/lib/SIL/SILOwnershipVerifier.cpp b/lib/SIL/SILOwnershipVerifier.cpp
index f41ffbb..8b445f6 100644
--- a/lib/SIL/SILOwnershipVerifier.cpp
+++ b/lib/SIL/SILOwnershipVerifier.cpp
@@ -824,7 +824,10 @@
case ParameterConvention::Indirect_InoutAliasable:
llvm_unreachable("Illegal convention for callee");
case ParameterConvention::Direct_Unowned:
- return {compatibleWithOwnership(ValueOwnershipKind::Trivial), false};
+ if (isAddressOrTrivialType())
+ return {compatibleWithOwnership(ValueOwnershipKind::Trivial), false};
+ // We accept unowned, owned, and guaranteed in unowned positions.
+ return {true, false};
case ParameterConvention::Direct_Owned:
return {compatibleWithOwnership(ValueOwnershipKind::Owned), true};
case ParameterConvention::Direct_Guaranteed:
@@ -1884,21 +1887,29 @@
});
}
- // Make sure that we do not have any lifetime ending uses left to visit. If we
- // do, then these non lifetime ending uses must be outside of our "alive"
- // blocks implying a use-after free.
+ // Make sure that we do not have any lifetime ending uses left to visit that
+ // are not transitively unreachable blocks. If we do, then these non lifetime
+ // ending uses must be outside of our "alive" blocks implying a use-after
+ // free.
if (!BlocksWithNonLifetimeEndingUses.empty()) {
- return handleError([&] {
- llvm::errs() << "Function: '" << Value->getFunction()->getName() << "'\n"
- << "Found use after free due to unvisited non lifetime "
- "ending uses?!\n"
- << "Value: " << *Value << " Remaining Users:\n";
- for (auto &Pair : BlocksWithNonLifetimeEndingUses) {
- llvm::errs() << "User:" << *Pair.second << "Block: bb"
- << Pair.first->getDebugID() << "\n";
+ for (auto &Pair : BlocksWithNonLifetimeEndingUses) {
+ if (TUB.isUnreachable(Pair.first)) {
+ continue;
}
- llvm::errs() << "\n";
- });
+
+ return handleError([&] {
+ llvm::errs() << "Function: '" << Value->getFunction()->getName()
+ << "'\n"
+ << "Found use after free due to unvisited non lifetime "
+ "ending uses?!\n"
+ << "Value: " << *Value << " Remaining Users:\n";
+ for (auto &Pair : BlocksWithNonLifetimeEndingUses) {
+ llvm::errs() << "User:" << *Pair.second << "Block: bb"
+ << Pair.first->getDebugID() << "\n";
+ }
+ llvm::errs() << "\n";
+ });
+ }
}
return true;
diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp
index 8da0b68..b0eb301 100644
--- a/lib/SILGen/SILGenApply.cpp
+++ b/lib/SILGen/SILGenApply.cpp
@@ -160,6 +160,30 @@
return selfValue;
}
+/// We return the casted value and the borrowed value so we can input the
+/// end_borrow.
+///
+/// TODO: Once end_borrow's 2nd value is eliminated, this should return just a
+/// SILValue.
+static std::pair<SILValue, SILValue> castToOriginalSelfType(SILGenBuilder &builder,
+ SILLocation loc,
+ SILValue selfValue) {
+ SILValue originalSelfValue = getOriginalSelfValue(selfValue);
+ SILType originalSelfType = originalSelfValue->getType();
+
+ // If we have a metatype, then we just return the original self value since
+ // metatypes are trivial, so we can avoid ownership concerns.
+ if (originalSelfType.getSwiftRValueType()->is<AnyMetatypeType>()) {
+ assert(originalSelfType.isTrivial(builder.getModule()) && "Metatypes should always be trivial");
+ return {originalSelfValue, SILValue()};
+ }
+
+ // Otherwise, we have a non-metatype. Use an unchecked_ref_cast.
+ SILValue borrowedValue = builder.createBeginBorrow(loc, selfValue);
+ SILValue castValue = builder.createUncheckedRefCast(loc, borrowedValue, originalSelfType);
+ return {castValue, borrowedValue};
+}
+
namespace {
/// Abstractly represents a callee, which may be a constant or function value,
@@ -301,7 +325,6 @@
SILDeclRef c,
SubstitutionList subs,
SILLocation l) {
- selfValue = getOriginalSelfValue(selfValue);
auto formalType = getConstantFormalInterfaceType(SGF, c);
return Callee(Kind::SuperMethod, SGF, selfValue, c,
formalType, formalType, subs, l);
@@ -450,14 +473,19 @@
case Kind::SuperMethod: {
assert(!constant->isCurried);
+ SILValue castValue, borrowedValue;
+ std::tie(castValue, borrowedValue) = castToOriginalSelfType(SGF.B, Loc, SelfValue);
+
auto base = SGF.SGM.Types.getOverriddenVTableEntry(*constant);
auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo(*constant, base);
- auto methodVal = SGF.B.createSuperMethod(Loc,
- SelfValue,
+ auto methodVal = SGF.B.createSuperMethod(Loc, castValue,
*constant,
constantInfo.getSILType(),
/*volatile*/
constant->isForeign);
+ if (borrowedValue) {
+ SGF.B.createEndBorrow(Loc, borrowedValue, SelfValue);
+ }
mv = ManagedValue::forUnmanaged(methodVal);
break;
}
@@ -4316,15 +4344,17 @@
auto loc = uncurriedLoc.getValue();
auto subs = callee.getSubstitutions();
auto upcastedSelf = uncurriedArgs.back();
- auto upcastedSelfValue = upcastedSelf.getValue();
- auto self = getOriginalSelfValue(upcastedSelfValue);
+ SILValue castValue, borrowedValue;
+ std::tie(castValue, borrowedValue) = castToOriginalSelfType(SGF.B, loc, upcastedSelf.getValue());
auto constantInfo = SGF.getConstantInfo(callee.getMethodName());
auto functionTy = constantInfo.getSILType();
SILValue superMethodVal =
- SGF.B.createSuperMethod(loc, self, constant, functionTy,
+ SGF.B.createSuperMethod(loc, castValue, constant, functionTy,
/*volatile*/
constant.isForeign);
-
+ if (borrowedValue) {
+ SGF.B.createEndBorrow(loc, borrowedValue, upcastedSelf.getValue());
+ }
auto closureTy = SILGenBuilder::getPartialApplyResultType(
constantInfo.getSILType(), 1, SGF.B.getModule(), subs,
ParameterConvention::Direct_Owned);
diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp
index 70ab7b2..cb3ace4 100644
--- a/lib/Sema/CSGen.cpp
+++ b/lib/Sema/CSGen.cpp
@@ -696,8 +696,7 @@
auto fTy = VD->getInterfaceType()->getAs<AnyFunctionType>();
assert(fTy && "attempting to count parameters of a non-function type");
- auto inputTy = fTy->getInput();
- size_t nOperands = getOperandCount(inputTy);
+ size_t nOperands = fTy->getParams().size();
size_t nNoDefault = 0;
if (auto AFD = dyn_cast<AbstractFunctionDecl>(VD)) {
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index 0fb3173..4b96e41 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -132,9 +132,10 @@
assert(basePA && "Missing potential archetype for base");
// Retrieve the potential archetype for the nested type.
- auto nestedPA = basePA->getNestedType(ref->getIdentifier(),
- ArchetypeResolutionKind::WellFormed,
- Builder);
+ auto nestedPA =
+ basePA->getNestedType(ref->getIdentifier(),
+ ArchetypeResolutionKind::CompleteWellFormed,
+ Builder);
// If there was no such nested type, produce an error.
if (!nestedPA) {
diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp
index 7c2324a..eb63213 100644
--- a/lib/TBDGen/TBDGen.cpp
+++ b/lib/TBDGen/TBDGen.cpp
@@ -44,13 +44,15 @@
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, bool checkSILOnly = true);
+ void addSymbol(SILDeclRef declRef);
void addSymbol(LinkEntity entity) {
auto linkage =
@@ -85,8 +87,8 @@
addMembers(ED->getMembers());
else if (auto NTD = dyn_cast<NominalTypeDecl>(D))
addMembers(NTD->getMembers());
- else if (auto VD = dyn_cast<VarDecl>(D))
- VD->getAllAccessorFunctions(members);
+ else if (auto ASD = dyn_cast<AbstractStorageDecl>(D))
+ ASD->getAllAccessorFunctions(members);
for (auto member : members) {
ASTVisitor::visit(member);
@@ -103,12 +105,6 @@
// any information here is encoded elsewhere
}
- void visitSubscriptDecl(SubscriptDecl *SD) {
- // Any getters and setters etc. exist as independent FuncDecls in the AST,
- // so get processed elsewhere; subscripts don't have any symbols other than
- // these.
- }
-
void visitNominalTypeDecl(NominalTypeDecl *NTD);
void visitClassDecl(ClassDecl *CD);
@@ -117,6 +113,8 @@
void visitProtocolDecl(ProtocolDecl *PD);
+ void visitAbstractStorageDecl(AbstractStorageDecl *ASD);
+
void visitVarDecl(VarDecl *VD);
void visitDecl(Decl *D) { visitMembers(D); }
@@ -138,13 +136,13 @@
auto declRef =
SILDeclRef(var, SILDeclRef::Kind::StoredPropertyInitializer);
// Stored property initializers for public properties are currently
- // public, even when the initializer is marked as SIL only (transparent).
- addSymbol(declRef, /*checkSILOnly=*/false);
+ // public.
+ addSymbol(declRef);
}
}
}
-void TBDGenVisitor::addSymbol(SILDeclRef declRef, bool checkSILOnly) {
+void TBDGenVisitor::addSymbol(SILDeclRef declRef) {
bool isPrivate = !hasPublicVisibility(declRef.getLinkage(ForDefinition));
// Even private methods of open classes (specifically, private methods that
// are in the vtable) have public symbols, because external subclasses
@@ -155,7 +153,6 @@
// unconditionally, even if they're theoretically SIL only.
if (isPrivate) {
isPrivate = false;
- checkSILOnly = false;
}
break;
case SubclassScope::Internal:
@@ -165,10 +162,9 @@
if (isPrivate)
return;
- // (Most) transparent things don't exist, even if they're public.
- // FIXME: isTransparent should really be "is SIL only".
- if (checkSILOnly && declRef.isTransparent())
- return;
+ // FIXME: this includes too many symbols. There are some that are considered
+ // SIL-only, but it isn't obvious how to determine this (e.g. it seems that
+ // many, but not all, transparent functions result in object-file symbols)
addSymbol(declRef.mangle());
}
@@ -256,6 +252,14 @@
}
void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
+ if (auto FD = dyn_cast<FuncDecl>(AFD)) {
+ // Accessors also appear nested inside the storage decl, which we treat as
+ // the canonical location, so skip if we've got an accessor that isn't
+ // inside the var decl.
+ if (FD->getAccessorStorageDecl() && !InsideAbstractStorageDecl)
+ return;
+ }
+
// Default arguments (of public functions) are public symbols, as the default
// values are computed at the call site.
auto index = 0;
@@ -275,25 +279,27 @@
visitValueDecl(AFD);
}
+void TBDGenVisitor::visitAbstractStorageDecl(AbstractStorageDecl *ASD) {
+ assert(!InsideAbstractStorageDecl &&
+ "unexpected nesting of abstract storage decls");
+ InsideAbstractStorageDecl = true;
+ visitMembers(ASD);
+ InsideAbstractStorageDecl = false;
+}
void TBDGenVisitor::visitVarDecl(VarDecl *VD) {
- if (isPrivateDecl(VD))
- return;
-
// statically/globally stored variables have some special handling.
if (VD->hasStorage() && isGlobalOrStaticVar(VD)) {
// The actual variable has a symbol.
Mangle::ASTMangler mangler;
addSymbol(mangler.mangleEntity(VD, false));
- // Variables in the main file don't get accessors, despite otherwise looking
- // like globals.
- if (!FileHasEntryPoint)
+ // Top-level variables (*not* statics) in the main file don't get accessors,
+ // despite otherwise looking like globals.
+ if (!FileHasEntryPoint || VD->isStatic())
addSymbol(SILDeclRef(VD, SILDeclRef::Kind::GlobalAccessor));
-
- // In this case, the members of the VarDecl don't also appear as top-level
- // decls, so we need to explicitly walk them.
- visitMembers(VD);
}
+
+ visitAbstractStorageDecl(VD);
}
void TBDGenVisitor::visitNominalTypeDecl(NominalTypeDecl *NTD) {
diff --git a/stdlib/public/core/CMakeLists.txt b/stdlib/public/core/CMakeLists.txt
index 4e8683b..005e0bf 100644
--- a/stdlib/public/core/CMakeLists.txt
+++ b/stdlib/public/core/CMakeLists.txt
@@ -55,6 +55,7 @@
ErrorType.swift
Existential.swift
Filter.swift.gyb
+ FixedArray.swift.gyb
FlatMap.swift
Flatten.swift.gyb
FloatingPoint.swift.gyb
diff --git a/stdlib/public/core/FixedArray.swift.gyb b/stdlib/public/core/FixedArray.swift.gyb
new file mode 100644
index 0000000..4fa02db
--- /dev/null
+++ b/stdlib/public/core/FixedArray.swift.gyb
@@ -0,0 +1,113 @@
+//===--- FixedArray.swift.gyb ---------------------------------*- swift -*-===//
+//
+// 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 helper struct to provide fixed-sized array like functionality
+//
+//===----------------------------------------------------------------------===//
+
+%{
+ # The sizes to generate code for.
+ sizes = [16]
+}%
+
+% for N in sizes:
+
+internal struct _FixedArray${N}<T> {
+ // ABI TODO: The has assumptions about tuple layout in the ABI, namely that
+ // they are laid out contiguously and individually addressable (i.e. strided).
+ //
+ internal var storage: (
+ // A ${N}-wide tuple of type T
+% for i in range(0, N-1):
+ T,
+% end
+ T
+ )
+
+ static var _arraySize : Int { return ${N} }
+}
+
+extension _FixedArray${N} : RandomAccessCollection, MutableCollection {
+ internal typealias Index = Int
+ internal typealias IndexDistance = Int
+
+ internal var startIndex : Index {
+ return 0
+ }
+
+ internal var endIndex : Index {
+ return _FixedArray${N}._arraySize
+ }
+
+ internal var count : IndexDistance { return _FixedArray${N}._arraySize }
+
+ internal subscript(i: Index) -> T {
+ @_versioned
+ @inline(__always)
+ get {
+ var copy = storage
+ let res: T = withUnsafeBytes(of: ©) {
+ (rawPtr : UnsafeRawBufferPointer) -> T in
+ let stride = MemoryLayout<T>.stride
+ _sanityCheck(rawPtr.count == ${N}*stride, "layout mismatch?")
+ let bufPtr = UnsafeBufferPointer(
+ start: rawPtr.baseAddress!.assumingMemoryBound(to: T.self),
+ count: count)
+ return bufPtr[i]
+ }
+ return res
+ }
+ @_versioned
+ @inline(__always)
+ set {
+ withUnsafeBytes(of: &storage) {
+ (rawPtr : UnsafeRawBufferPointer) -> () in
+ let rawPtr = UnsafeMutableRawBufferPointer(mutating: rawPtr)
+ let stride = MemoryLayout<T>.stride
+ _sanityCheck(rawPtr.count == ${N}*stride, "layout mismatch?")
+ let bufPtr = UnsafeMutableBufferPointer(
+ start: rawPtr.baseAddress!.assumingMemoryBound(to: T.self),
+ count: count)
+ bufPtr[i] = newValue
+ }
+ }
+ }
+
+ @_versioned
+ @inline(__always)
+ internal func index(after i: Index) -> Index {
+ return i+1
+ }
+
+ @_versioned
+ @inline(__always)
+ internal func index(before i: Index) -> Index {
+ return i-1
+ }
+
+ // TODO: Any customization hooks it's profitable to override, e.g. append?
+
+}
+
+extension _FixedArray${N} where T: IntegerLiteralConvertible {
+ @inline(__always)
+ internal init(allZeros:()) {
+ self.storage = (
+% for i in range(0, N-1):
+ 0,
+% end
+ 0
+ )
+ }
+}
+
+% end
diff --git a/stdlib/public/core/GroupInfo.json b/stdlib/public/core/GroupInfo.json
index c4c41db..f816522 100644
--- a/stdlib/public/core/GroupInfo.json
+++ b/stdlib/public/core/GroupInfo.json
@@ -92,6 +92,7 @@
"Arrays.swift",
"CocoaArray.swift",
"ContiguousArrayBuffer.swift",
+ "FixedArray.swift",
"SliceBuffer.swift",
"SwiftNativeNSArray.swift"],
"HashedCollections": [
diff --git a/stdlib/public/core/StringCharacterView.swift b/stdlib/public/core/StringCharacterView.swift
index debf0ba..13169af 100644
--- a/stdlib/public/core/StringCharacterView.swift
+++ b/stdlib/public/core/StringCharacterView.swift
@@ -15,8 +15,8 @@
//
//===----------------------------------------------------------------------===//
-// FIXME(ABI)#70 : The character string view should have a custom iterator type to
-// allow performance optimizations of linear traversals.
+// FIXME(ABI)#70 : The character string view should have a custom iterator type
+// to allow performance optimizations of linear traversals.
/// CR and LF are common special cases in grapheme breaking logic
@_versioned internal var _CR: UInt8 { return 0x0d }
@@ -102,7 +102,8 @@
/// of the string.
///
/// var str = "All this happened, more or less."
- /// let afterSpace = str.withMutableCharacters { chars -> String.CharacterView in
+ /// let afterSpace = str.withMutableCharacters {
+ /// chars -> String.CharacterView in
/// if let i = chars.index(of: " ") {
/// let result = chars[chars.index(after: i)...]
/// chars.removeSubrange(i...)
@@ -364,128 +365,130 @@
internal func _measureExtendedGraphemeClusterForward(
from start: UnicodeScalarView.Index
) -> Int {
- let end = unicodeScalars.endIndex
- if start == end {
+ let startPosition = start._position
+ let endPosition = unicodeScalars.endIndex._position
+
+ // No more graphemes
+ if startPosition == endPosition {
return 0
}
- // Our relative position (offset). If our _core is not a substring, this is
- // the same as start._position.
- let relativeOffset = start._position - _coreOffset
+ // Last code unit means final grapheme length of 1
+ if startPosition == endPosition - 1 {
+ return 1
+ }
+
+ // Our relative offset from the _StringCore's baseAddress pointer. If our
+ // _core is not a substring, this is the same as start._position. Otherwise,
+ // it is the code unit relative offset into the substring and not the
+ // absolute offset into the outer string.
+ let startOffset = startPosition - _coreOffset
// Grapheme breaking is much simpler if known ASCII
if _core.isASCII {
_onFastPath() // Please aggressively inline
let asciiBuffer = _core.asciiBuffer._unsafelyUnwrappedUnchecked
+ _sanityCheck(startOffset+1 < asciiBuffer.endIndex,
+ "Already checked for last code unit")
// With the exception of CR-LF, ASCII graphemes are single-scalar. Check
// for that one exception.
if _slowPath(
- asciiBuffer[relativeOffset] == _CR &&
- relativeOffset+1 < asciiBuffer.endIndex &&
- asciiBuffer[relativeOffset+1] == _LF
+ asciiBuffer[startOffset] == _CR &&
+ asciiBuffer[startOffset+1] == _LF
) {
return 2
}
return 1
- } else {
- // TODO: Check for (potentially non-contiguous) ASCII NSStrings,
- // especially small tagged pointers.
}
- let startIndexUTF16 = start._position
-
- // Last scalar is its own grapheme
- if (startIndexUTF16+1 == end._position) {
+ // Perform a quick single-code-unit grapheme check.
+ if _fastPath(String.CharacterView._quickCheckGraphemeBreakBetween(
+ _core[startOffset],
+ _core[startOffset+1])
+ ) {
return 1
}
- // Perform a quick single-code-unit grapheme check
- if _core._baseAddress != nil {
- if String.CharacterView._quickCheckGraphemeBreakBetween(
- _core._nthContiguous(relativeOffset),
- _core._nthContiguous(relativeOffset+1)
- ) {
- return 1
- }
- } else {
- // TODO: Check for (potentially non-contiguous) UTF16 NSStrings,
- // especially small tagged pointers
- }
- return _measureExtendedGraphemeClusterForwardSlow(
- relativeOffset: relativeOffset,
- start: start,
- end: end,
- startIndexUTF16: startIndexUTF16
- )
+ return _measureExtendedGraphemeClusterForwardSlow(startOffset: startOffset)
}
@inline(never)
@_versioned
func _measureExtendedGraphemeClusterForwardSlow(
- relativeOffset: Int,
- start: String.UnicodeScalarView.Index,
- end: String.UnicodeScalarView.Index,
- startIndexUTF16: Int
+ startOffset: Int
) -> Int {
- if _core._baseAddress != nil {
+ let endOffset = unicodeScalars.endIndex._position - _coreOffset
+ let numCodeUnits = endOffset - startOffset
+ _sanityCheck(numCodeUnits >= 2, "should have at least two code units")
+
+ // The vast majority of time, we can get a pointer and a length directly
+ if _fastPath(_core._baseAddress != nil) {
_onFastPath() // Please aggressively inline
let breakIterator = _ThreadLocalStorage.getUBreakIterator(for: _core)
- let ubrkFollowing = __swift_stdlib_ubrk_following(
- breakIterator, Int32(relativeOffset)
+ let ubrkFollowingOffset = __swift_stdlib_ubrk_following(
+ breakIterator, Int32(startOffset)
)
// ubrk_following may return UBRK_DONE (-1). Treat that as the rest of the
// string.
- let nextPosition =
- ubrkFollowing == -1 ? end._position : Int(ubrkFollowing)
- return nextPosition - relativeOffset
- } else {
- // TODO: See if we can get fast character contents.
+ if _slowPath(ubrkFollowingOffset == -1) {
+ return numCodeUnits
+ }
+ _sanityCheck(startOffset != Int(ubrkFollowingOffset),
+ "zero-sized grapheme?")
+ return Int(ubrkFollowingOffset) - startOffset
}
- // FIXME: Need to handle the general case correctly with Unicode 9+
- // semantics, as opposed to this legacy Unicode 8 path. This gets hit for
- // e.g. non-contiguous NSStrings. In such cases, there may be an alternative
- // CFString API available, or worst case we can map over it via UTextFuncs.
-
- return legacyGraphemeForward(
- start: start, end: end, startIndexUTF16: startIndexUTF16
- )
- }
-
- @inline(never)
- func legacyGraphemeForward(
- start: UnicodeScalarView.Index,
- end: UnicodeScalarView.Index,
- startIndexUTF16: Int
- ) -> Int {
- var start = start
- let graphemeClusterBreakProperty =
- _UnicodeGraphemeClusterBreakPropertyTrie()
- let segmenter = _UnicodeExtendedGraphemeClusterSegmenter()
-
- var gcb0 = graphemeClusterBreakProperty.getPropertyRawValue(
- unicodeScalars[start].value)
- unicodeScalars.formIndex(after: &start)
-
- while start != end {
- // FIXME(performance): consider removing this "fast path". A branch
- // that is hard to predict could be worse for performance than a few
- // loads from cache to fetch the property 'gcb1'.
- if segmenter.isBoundaryAfter(gcb0) {
- break
- }
- let gcb1 = graphemeClusterBreakProperty.getPropertyRawValue(
- unicodeScalars[start].value)
- if segmenter.isBoundary(gcb0, gcb1) {
- break
- }
- gcb0 = gcb1
- unicodeScalars.formIndex(after: &start)
+ // We have a non-contiguous string. Pull out some code units into a fixed
+ // array and try to perform grapheme breaking on that. If even that's not
+ // sufficient (i.e. very pathological) then copy into an Array.
+ var codeUnitBuffer = _FixedArray16<UInt16>(allZeros:())
+ let maxBufferCount = codeUnitBuffer.count
+ let bufferCount = Swift.min(maxBufferCount, numCodeUnits)
+ for i in 0..<bufferCount {
+ codeUnitBuffer[i] = _core[startOffset+i]
}
-
- return start._position - startIndexUTF16
+
+ return withUnsafeBytes(of: &codeUnitBuffer.storage) {
+ (rawPtr : UnsafeRawBufferPointer) -> Int in
+ let bufPtr = UnsafeBufferPointer(
+ start: rawPtr.baseAddress!.assumingMemoryBound(to: UInt16.self),
+ count: bufferCount)
+
+ let breakIterator = _ThreadLocalStorage.getUBreakIterator(for: bufPtr)
+ let ubrkFollowingOffset = __swift_stdlib_ubrk_following(
+ breakIterator, Int32(0))
+
+ if _fastPath(
+ bufferCount < maxBufferCount ||
+ (ubrkFollowingOffset != -1 && ubrkFollowingOffset != maxBufferCount)
+ ) {
+ // The offset into our buffer *is* the distance.
+ _sanityCheck(ubrkFollowingOffset != 0, "zero-sized grapheme?")
+ return Int(ubrkFollowingOffset)
+ }
+
+ // Nuclear option: copy out the rest of the string into an array
+ var codeUnits = Array<UInt16>()
+ codeUnits.reserveCapacity(numCodeUnits)
+ for i in startOffset..<endOffset {
+ codeUnits.append(_core[i])
+ }
+ return codeUnits.withUnsafeBufferPointer { bufPtr -> Int in
+ let breakIterator = _ThreadLocalStorage.getUBreakIterator(for: bufPtr)
+ let ubrkFollowingOffset = __swift_stdlib_ubrk_following(
+ breakIterator, Int32(0)
+ )
+ // ubrk_following may return UBRK_DONE (-1). Treat that as the rest of
+ // the string.
+ if _slowPath(ubrkFollowingOffset == -1) {
+ return numCodeUnits
+ }
+ _sanityCheck(ubrkFollowingOffset != 0, "zero-sized grapheme?")
+ return Int(ubrkFollowingOffset)
+ }
+ }
}
// NOTE: Because this function is inlineable, it should contain only the fast
@@ -498,14 +501,25 @@
internal func _measureExtendedGraphemeClusterBackward(
from end: UnicodeScalarView.Index
) -> Int {
- let start = unicodeScalars.startIndex
- if start == end {
+ let startPosition = unicodeScalars.startIndex._position
+ let endPosition = end._position
+
+ // No more graphemes
+ if startPosition == endPosition {
return 0
}
- // The relative position (offset) to the last code unit.
- let lastOffset = end._position - _coreOffset - 1
- // The relative position (offset) that is one-past-the-last
+ // Last code unit means final grapheme length of 1
+ if startPosition == endPosition - 1 {
+ return 1
+ }
+
+ // The relative offset from the _StringCore's baseAddress pointer for the
+ // one-past-the-end and the last code unit under consideration. If our
+ // _core is not a substring, these are the same as positions. Otherwise,
+ // these are code unit relative offsets into the substring and not the
+ // absolute positions into the outer string.
+ let lastOffset = endPosition - _coreOffset - 1
let endOffset = lastOffset + 1
// Grapheme breaking is much simpler if known ASCII
@@ -513,15 +527,14 @@
_onFastPath() // Please aggressively inline
let asciiBuffer = _core.asciiBuffer._unsafelyUnwrappedUnchecked
_sanityCheck(
- lastOffset >= asciiBuffer.startIndex,
- "should of been caught in earlier start-of-scalars check")
+ lastOffset-1 >= asciiBuffer.startIndex,
+ "should of been caught in earlier trivially-sized checks")
// With the exception of CR-LF, ASCII graphemes are single-scalar. Check
// for that one exception.
if _slowPath(
- asciiBuffer[lastOffset] == _LF &&
- lastOffset-1 >= asciiBuffer.startIndex &&
- asciiBuffer[lastOffset-1] == _CR
+ asciiBuffer[lastOffset-1] == _CR &&
+ asciiBuffer[lastOffset] == _LF
) {
return 2
}
@@ -529,92 +542,94 @@
return 1
}
- let endIndexUTF16 = end._position
-
- // First scalar is its own grapheme
- if (endIndexUTF16-1 == start._position) {
+ // Perform a quick single-code-unit grapheme check
+ if _fastPath(String.CharacterView._quickCheckGraphemeBreakBetween(
+ _core[lastOffset-1], _core[lastOffset])
+ ) {
return 1
}
- // Perform a quick single-code-unit grapheme check
- if _core._baseAddress != nil {
- if String.CharacterView._quickCheckGraphemeBreakBetween(
- _core._nthContiguous(lastOffset-1),
- _core._nthContiguous(lastOffset)
- ) {
- return 1
- }
- }
- return _measureExtendedGraphemeClusterBackwardSlow(
- endOffset: endOffset, start: start, end: end, endIndexUTF16: endIndexUTF16
- )
+ return _measureExtendedGraphemeClusterBackwardSlow(endOffset: endOffset)
}
@inline(never)
@_versioned
func _measureExtendedGraphemeClusterBackwardSlow(
- endOffset: Int,
- start: String.UnicodeScalarView.Index,
- end: String.UnicodeScalarView.Index,
- endIndexUTF16: Int
+ endOffset: Int
) -> Int {
- if _core._baseAddress != nil {
- _onFastPath() // Please aggressively inline
- let breakIterator = _ThreadLocalStorage.getUBreakIterator(for: _core)
- let ubrkPreceding = __swift_stdlib_ubrk_preceding(
- breakIterator, Int32(endOffset)
- )
+ let startOffset = 0
+ let numCodeUnits = endOffset - startOffset
+ _sanityCheck(unicodeScalars.startIndex._position - _coreOffset == 0,
+ "position/offset mismatch in _StringCore as a substring")
+ _sanityCheck(numCodeUnits >= 2,
+ "should have at least two code units")
+
+ func measureFromUBreakOffset(_ ubrkOffset: Int32) -> Int {
// ubrk_following may return UBRK_DONE (-1). Treat that as the rest of the
// string.
- let priorPosition =
- ubrkPreceding == -1 ? start._position : Int(ubrkPreceding)
- return endOffset - priorPosition
- } else {
- // TODO: See if we can get fast character contents.
- }
-
- // FIXME: Need to handle the general case correctly with Unicode 9+
- // semantics, as opposed to this legacy Unicode 8 path. This gets hit for
- // e.g. non-contiguous NSStrings. In such cases, there may be an alternative
- // CFString API available, or worst case we can map over it via UTextFuncs.
-
- return legacyGraphemeBackward(
- start: start, end: end, endIndexUTF16: endIndexUTF16
- )
- }
-
- @inline(never)
- func legacyGraphemeBackward(
- start: UnicodeScalarView.Index,
- end: UnicodeScalarView.Index,
- endIndexUTF16: Int
- ) -> Int {
- let graphemeClusterBreakProperty =
- _UnicodeGraphemeClusterBreakPropertyTrie()
- let segmenter = _UnicodeExtendedGraphemeClusterSegmenter()
-
- var graphemeClusterStart = end
-
- unicodeScalars.formIndex(before: &graphemeClusterStart)
- var gcb0 = graphemeClusterBreakProperty.getPropertyRawValue(
- unicodeScalars[graphemeClusterStart].value)
-
- var graphemeClusterStartUTF16 = graphemeClusterStart._position
-
- while graphemeClusterStart != start {
- unicodeScalars.formIndex(before: &graphemeClusterStart)
- let gcb1 = graphemeClusterBreakProperty.getPropertyRawValue(
- unicodeScalars[graphemeClusterStart].value)
- if segmenter.isBoundary(gcb1, gcb0) {
- break
+ if _slowPath(ubrkOffset == -1) {
+ return numCodeUnits
}
- gcb0 = gcb1
- graphemeClusterStartUTF16 = graphemeClusterStart._position
+ _sanityCheck(endOffset > Int(ubrkOffset), "zero-sized grapheme?")
+ return endOffset - Int(ubrkOffset)
}
-
- return endIndexUTF16 - graphemeClusterStartUTF16
+
+ // The vast majority of time, we can get a pointer and a length directly
+ if _fastPath(_core._baseAddress != nil) {
+ _onFastPath() // Please aggressively inline
+ let breakIterator = _ThreadLocalStorage.getUBreakIterator(for: _core)
+ let ubrkPrecedingOffset = __swift_stdlib_ubrk_preceding(
+ breakIterator, Int32(endOffset)
+ )
+ return measureFromUBreakOffset(ubrkPrecedingOffset)
+ }
+
+ // We have a non-contiguous string. Pull out some code units into a fixed
+ // array and try to perform grapheme breaking on that. If even that's not
+ // sufficient (i.e. very pathological) then copy into an Array.
+ var codeUnitBuffer = _FixedArray16<UInt16>(allZeros:())
+ let maxBufferCount = codeUnitBuffer.count
+ let coreStartIdx = Swift.max(startOffset, endOffset - maxBufferCount)
+ let bufferCount = Swift.min(maxBufferCount, numCodeUnits)
+ for i in 0..<bufferCount {
+ codeUnitBuffer[i] = _core[coreStartIdx+i]
+ }
+
+ return withUnsafeBytes(of: &codeUnitBuffer.storage) {
+ (rawPtr : UnsafeRawBufferPointer) -> Int in
+ let bufPtr = UnsafeBufferPointer(
+ start: rawPtr.baseAddress!.assumingMemoryBound(to: UInt16.self),
+ count: bufferCount)
+
+ let breakIterator = _ThreadLocalStorage.getUBreakIterator(for: bufPtr)
+ let ubrkPrecedingOffset = __swift_stdlib_ubrk_preceding(
+ breakIterator, Int32(bufferCount)
+ )
+
+ if _fastPath(numCodeUnits < maxBufferCount || ubrkPrecedingOffset > 1) {
+ // There was a grapheme break within our buffer.
+ _sanityCheck(ubrkPrecedingOffset < bufferCount, "offset mismatch")
+ return bufferCount - Int(ubrkPrecedingOffset)
+ }
+
+ // Nuclear option: copy out the prefix of the string into an array
+ var codeUnits = Array<UInt16>()
+ codeUnits.reserveCapacity(numCodeUnits)
+ for i in startOffset..<endOffset {
+ codeUnits.append(_core[i])
+ }
+ return codeUnits.withUnsafeBufferPointer { bufPtr -> Int in
+ let breakIterator = _ThreadLocalStorage.getUBreakIterator(for: bufPtr)
+ let ubrkPrecedingOffset = __swift_stdlib_ubrk_preceding(
+ breakIterator, Int32(endOffset)
+ )
+ // No need to adjust ubrkPrecedingOffset as we copied the prefix: it is
+ // the position in the original string
+ return measureFromUBreakOffset(ubrkPrecedingOffset)
+ }
+ }
}
-
+
/// Accesses the character at the given position.
///
/// The following example searches a string's character view for a capital
diff --git a/stdlib/public/core/Substring.swift.gyb b/stdlib/public/core/Substring.swift.gyb
index 6add01c..8bb704f 100644
--- a/stdlib/public/core/Substring.swift.gyb
+++ b/stdlib/public/core/Substring.swift.gyb
@@ -283,8 +283,11 @@
let wholeCore = _slice._base._core
let subCore : _StringCore = wholeCore[
startIndex._base._position..<endIndex._base._position]
- // check that we haven't allocated a new buffer for the result
- _sanityCheck(subCore._owner === wholeCore._owner)
+ // Check that we haven't allocated a new buffer for the result, if we have
+ // contiguous storage.
+ _sanityCheck(
+ subCore._owner === wholeCore._owner || !wholeCore.hasContiguousStorage)
+
return String(subCore)
}
}
diff --git a/stdlib/public/core/ThreadLocalStorage.swift b/stdlib/public/core/ThreadLocalStorage.swift
index cb213d5..2c09ac3 100644
--- a/stdlib/public/core/ThreadLocalStorage.swift
+++ b/stdlib/public/core/ThreadLocalStorage.swift
@@ -74,20 +74,25 @@
}
// Retrieve our thread's local uBreakIterator and set it up for the given
- // StringCore. Checks our TLS cache to avoid excess text resetting.
+ // StringCore.
static internal func getUBreakIterator(
for core: _StringCore
) -> OpaquePointer {
+ _sanityCheck(core._owner != nil || core._baseAddress != nil,
+ "invalid StringCore")
+ let corePtr: UnsafeMutablePointer<UTF16.CodeUnit> = core.startUTF16
+ return getUBreakIterator(
+ for: UnsafeBufferPointer(start: corePtr, count: core.count))
+ }
+ static internal func getUBreakIterator(
+ for bufPtr: UnsafeBufferPointer<UTF16.CodeUnit>
+ ) -> OpaquePointer {
let tlsPtr = getPointer()
let brkIter = tlsPtr[0].uBreakIterator
- _sanityCheck(core._owner != nil || core._baseAddress != nil,
- "invalid StringCore")
-
var err = __swift_stdlib_U_ZERO_ERROR
- let corePtr: UnsafeMutablePointer<UTF16.CodeUnit>
- corePtr = core.startUTF16
- __swift_stdlib_ubrk_setText(brkIter, corePtr, Int32(core.count), &err)
+ __swift_stdlib_ubrk_setText(
+ brkIter, bufPtr.baseAddress!, Int32(bufPtr.count), &err)
_precondition(err.isSuccess, "unexpected ubrk_setUText failure")
return brkIter
diff --git a/test/Driver/bridging-pch.swift b/test/Driver/bridging-pch.swift
index bb3ac15..dbb4a28 100644
--- a/test/Driver/bridging-pch.swift
+++ b/test/Driver/bridging-pch.swift
@@ -32,6 +32,12 @@
// PERSISTENT-YESPCHACT: 2: input, "{{.*}}bridging-pch.swift", swift
// PERSISTENT-YESPCHACT: 3: compile, {2, 1}, none
+// RUN: %swiftc_driver -c -driver-print-actions -embed-bitcode -import-objc-header %S/Inputs/bridging-header.h -pch-output-dir %t/pch %s 2>&1 | %FileCheck %s -check-prefix=PERSISTENT-YESPCHACTBC
+// PERSISTENT-YESPCHACTBC: 0: input, "{{.*}}Inputs/bridging-header.h", objc-header
+// PERSISTENT-YESPCHACTBC: 1: generate-pch, {0}, none
+// PERSISTENT-YESPCHACTBC: 2: input, "{{.*}}bridging-pch.swift", swift
+// PERSISTENT-YESPCHACTBC: 3: compile, {2, 1}, llvm-bc
+
// RUN: %swiftc_driver -typecheck -disable-bridging-pch -driver-print-actions -import-objc-header %S/Inputs/bridging-header.h -pch-output-dir %t/pch %s 2>&1 | %FileCheck %s -check-prefix=NOPCHACT
// RUN: %swiftc_driver -typecheck -driver-print-jobs -import-objc-header %S/Inputs/bridging-header.h -pch-output-dir %t/pch -disable-bridging-pch %s 2>&1 | %FileCheck %s -check-prefix=PERSISTENT-DISABLED-YESPCHJOB
diff --git a/test/IRGen/objc_super.swift b/test/IRGen/objc_super.swift
index 1f380fd..40a52a6 100644
--- a/test/IRGen/objc_super.swift
+++ b/test/IRGen/objc_super.swift
@@ -74,7 +74,7 @@
class PartialApply : Gizmo {
// CHECK: define hidden swiftcc void @_T010objc_super12PartialApplyC4frobyyF([[PARTIAL_APPLY_CLASS]]* swiftself) {{.*}} {
override func frob() {
- // CHECK: call swiftcc void @_T010objc_super8acceptFnyyycF(i8* bitcast (void (%swift.refcounted*)* [[PARTIAL_FORWARDING_THUNK:@[A-Za-z0-9_]+]] to i8*), %swift.refcounted* %3)
+ // CHECK: call swiftcc void @_T010objc_super8acceptFnyyycF(i8* bitcast (void (%swift.refcounted*)* [[PARTIAL_FORWARDING_THUNK:@[A-Za-z0-9_]+]] to i8*), %swift.refcounted* %4)
acceptFn(super.frob)
}
// CHECK: }
diff --git a/test/IRGen/ordering_x86.sil b/test/IRGen/ordering_x86.sil
index ddae69d..c83e803 100644
--- a/test/IRGen/ordering_x86.sil
+++ b/test/IRGen/ordering_x86.sil
@@ -2,6 +2,7 @@
// RUN: %swift -target i386-apple-ios7.1 %s -module-name main -emit-ir -o - | %FileCheck %s
// RUN: %swift -target x86_64-apple-ios7.1 %s -module-name main -emit-ir -o - | %FileCheck %s
// RUN: %swift -target x86_64-unknown-linux-gnu -disable-objc-interop %s -module-name main -emit-ir -o - | %FileCheck %s
+// RUN: %swift -target x86_64-apple-macosx10.9 -module-name main %s -emit-ir -o - | %FileCheck %s --check-prefix=X86_64
// REQUIRES: CODEGENERATOR=X86
@@ -34,3 +35,10 @@
// CHECK: define{{( protected)?}} swiftcc void @foo
// CHECK: define{{( protected)?}} swiftcc void @bar
// CHECK: define{{( protected)?}} swiftcc void @baz
+
+// Make sure that the target features are ordered. We care because function
+// merging does not identify two otherwise identical functions as the same if
+// the order of features differs.
+
+// X86_64: define{{( protected)?}} swiftcc void @baz{{.*}}#0
+// X86_64: #0 = {{.*}}"target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+ssse3,+x87"
diff --git a/test/Index/Store/Inputs/ClangModuleA.h b/test/Index/Store/Inputs/ClangModuleA.h
new file mode 100644
index 0000000..ea06ce2
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleA.h
@@ -0,0 +1 @@
+void funcA(void);
diff --git a/test/Index/Store/Inputs/ClangModuleB.h b/test/Index/Store/Inputs/ClangModuleB.h
new file mode 100644
index 0000000..ce316e2
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleB.h
@@ -0,0 +1,2 @@
+@import ClangModuleA;
+void funcB(void);
diff --git a/test/Index/Store/Inputs/ClangModuleCSub1.h b/test/Index/Store/Inputs/ClangModuleCSub1.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleCSub1.h
diff --git a/test/Index/Store/Inputs/ClangModuleCSub2.h b/test/Index/Store/Inputs/ClangModuleCSub2.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Index/Store/Inputs/ClangModuleCSub2.h
diff --git a/test/Index/Store/Inputs/SwiftModuleA.swift b/test/Index/Store/Inputs/SwiftModuleA.swift
new file mode 100644
index 0000000..59e7758
--- /dev/null
+++ b/test/Index/Store/Inputs/SwiftModuleA.swift
@@ -0,0 +1 @@
+public func funcSwiftA() {}
diff --git a/test/Index/Store/Inputs/SwiftModuleB.swift b/test/Index/Store/Inputs/SwiftModuleB.swift
new file mode 100644
index 0000000..b12db68
--- /dev/null
+++ b/test/Index/Store/Inputs/SwiftModuleB.swift
@@ -0,0 +1,2 @@
+import SwiftModuleA
+public func funcSwiftB() { funcSwiftA() }
diff --git a/test/Index/Store/Inputs/bridge-head.h b/test/Index/Store/Inputs/bridge-head.h
new file mode 100644
index 0000000..b25d652
--- /dev/null
+++ b/test/Index/Store/Inputs/bridge-head.h
@@ -0,0 +1 @@
+#include "bridge-include.h"
diff --git a/test/Index/Store/Inputs/bridge-include.h b/test/Index/Store/Inputs/bridge-include.h
new file mode 100644
index 0000000..55a0722
--- /dev/null
+++ b/test/Index/Store/Inputs/bridge-include.h
@@ -0,0 +1,2 @@
+int includedFunc(int a);
+int MY_CONST = 2;
\ No newline at end of file
diff --git a/test/Index/Store/Inputs/module.modulemap b/test/Index/Store/Inputs/module.modulemap
new file mode 100644
index 0000000..a25324f
--- /dev/null
+++ b/test/Index/Store/Inputs/module.modulemap
@@ -0,0 +1,20 @@
+module ClangModuleA {
+ header "ClangModuleA.h"
+ export *
+}
+module ClangModuleB {
+ header "ClangModuleB.h"
+ export *
+}
+
+module ClangModuleC {
+ module Sub1 {
+ header "ClangModuleCSub1.h"
+ export *
+ }
+
+ module Sub2 {
+ header "ClangModuleCSub2.h"
+ export *
+ }
+}
diff --git a/test/Index/Store/driver-index.swift b/test/Index/Store/driver-index.swift
new file mode 100644
index 0000000..b8007d0
--- /dev/null
+++ b/test/Index/Store/driver-index.swift
@@ -0,0 +1,2 @@
+// RUN: %swiftc_driver -driver-print-jobs -index-file -index-file-path %s %S/Inputs/SwiftModuleA.swift %s -o %t.output_for_index -index-store-path %t.index_store -module-name driver_index 2>&1 | %FileCheck %s
+// CHECK: {{.*}}swift -frontend -typecheck {{.*}}-primary-file {{.*}}driver-index.swift {{.*}}SwiftModuleA.swift {{.*}}driver-index.swift {{.*}}-o {{.*}}.output_for_index {{.*}}-index-store-path {{.*}}.index_store -index-system-modules
diff --git a/test/Index/Store/output-failure.swift b/test/Index/Store/output-failure.swift
new file mode 100644
index 0000000..24167e3
--- /dev/null
+++ b/test/Index/Store/output-failure.swift
@@ -0,0 +1,41 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir %t/idx
+
+// Before indexing, do a dry-run to ensure any clang modules are cached. We
+// want to isolate the error that comes from swift's indexing support, not
+// any failures indexing a clang module.
+// RUN: %target-swift-frontend %s -typecheck
+
+// RUN: chmod -w %t/idx
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/dir.txt || chmod +w %t/idx
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx
+// RUN: %FileCheck %s -check-prefix=DIR_ERR < %t/dir.txt
+// DIR_ERR: error: creating index directory
+
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o
+// test -s %t/idx/*/units/oof.o*
+
+// RUN: chmod -w %t/idx/*/units
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/file.txt || chmod +w %t/idx/*/units
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx/*/units
+// RUN: %FileCheck %s -check-prefix=FILE_ERR < %t/file.txt
+// FILE_ERR: error: writing index unit file
+
+// RUN: rm -rf %t/idx/*/records/*
+// RUN: chmod -x %t/idx/*/records
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/record.txt || chmod +x %t/idx/*/records
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +x %t/idx/*/records
+// RUN: %FileCheck %s -check-prefix=RECORD_ERR < %t/record.txt
+// RECORD_ERR: error: writing index record file
+
+// RUN: rm -rf %t/idx/*/records/*
+// RUN: chmod -w %t/idx/*/records
+// RUN: not %target-swift-frontend -index-store-path %t/idx %s -typecheck -o %t/oof.o 2> %t/record2.txt || chmod +w %t/idx/*/records
+// This is not combined with the previous chmod because of pipefail mode.
+// RUN: chmod +w %t/idx/*/records
+// RUN: %FileCheck %s -check-prefix=RECORD_ERR < %t/record2.txt
+
+func foo() {}
diff --git a/test/Index/Store/record-comments.swift b/test/Index/Store/record-comments.swift
new file mode 100644
index 0000000..5d356f1
--- /dev/null
+++ b/test/Index/Store/record-comments.swift
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t.o -typecheck %s
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: record-comments.swift
+// CHECK: ------------
+// CHECK: comment-tag/Swift | <no-name> | t:this_is_a_tag | <no-cgname> | Def -
+// CHECK: comment-tag/Swift | <no-name> | t:and_another | <no-cgname> | Def -
+// CHECK: ------------
+
+/// Hello
+/// - Tag: this_is_a_tag
+/// - Tag: and_another
+func foo() {}
+// CHECK: [[@LINE-3]]:5 | comment-tag/Swift | t:this_is_a_tag | Def | rel: 0
+// CHECK: [[@LINE-3]]:5 | comment-tag/Swift | t:and_another | Def | rel: 0
+// CHECK: [[@LINE-3]]:6 | function/Swift |
diff --git a/test/Index/Store/record-dependency.swift b/test/Index/Store/record-dependency.swift
new file mode 100644
index 0000000..6c3777b
--- /dev/null
+++ b/test/Index/Store/record-dependency.swift
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// CHECK: DEPEND START
+// CHECK: Record | user | {{.*}}record-dependency.swift | record-dependency.swift-
+// CHECK: DEPEND END
+
+// RUN: echo 'func bar() {}' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx2 -emit-module -module-name main -emit-module-path %t/main.swiftmodule %s %t/s2.swift -o %t/file.o -o %t/s2.o
+// RUN: c-index-test core -print-unit %t/idx2 | %FileCheck %s -check-prefix=TWO_RECORDS
+// TWO_RECORDS: file.o-
+// TWO_RECORDS: DEPEND START
+// TWO_RECORDS: Record | user | {{.*}}record-dependency.swift | record-dependency.swift-
+// TWO_RECORDS: DEPEND END
+// TWO_RECORDS: s2.o-
+// TWO_RECORDS: DEPEND START
+// TWO_RECORDS: Record | user | {{.*}}s2.swift | s2.swift-
+// TWO_RECORDS: DEPEND END
+
+// XFAIL: linux
+
+func foo() {}
diff --git a/test/Index/Store/record-empty.swift b/test/Index/Store/record-empty.swift
new file mode 100644
index 0000000..c7bdd9e
--- /dev/null
+++ b/test/Index/Store/record-empty.swift
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck -primary-file %s
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// CHECK-NOT: Record{{.*}}record-empty
+
+// XFAIL: linux
diff --git a/test/Index/Store/record-hashing.swift b/test/Index/Store/record-hashing.swift
new file mode 100644
index 0000000..665d4a3
--- /dev/null
+++ b/test/Index/Store/record-hashing.swift
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: echo "func foo() {}" > %t/theinput.swift
+
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: ls %t/idx/*/records/* | grep "theinput.swift" | count 1
+// RUN: cp -r %t/idx %t/idx-orig
+
+// RUN: touch %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// No change in record.
+
+// RUN: echo '// Comment.' >> %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// No change in record.
+
+// RUN: echo 'func goo() {}' >> %t/theinput.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -typecheck %t/theinput.swift -o %t/s.o
+// RUN: not diff -r -u %t/idx/*/records %t/idx-orig/*/records
+// RUN: ls %t/idx/*/records/* | grep "theinput.swift" | count 2
+// Changed! Wrote a new record.
diff --git a/test/Index/Store/record-sourcefile.swift b/test/Index/Store/record-sourcefile.swift
new file mode 100644
index 0000000..129f7cc
--- /dev/null
+++ b/test/Index/Store/record-sourcefile.swift
@@ -0,0 +1,155 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx1 -o %t/file.o -typecheck %s
+// RUN: %target-swift-frontend -index-store-path %t/idx2 -o %t/file.o -typecheck -primary-file %s
+// RUN: c-index-test core -print-record %t/idx1 | %FileCheck %s
+// RUN: c-index-test core -print-record %t/idx2 | %FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: record-sourcefile.swift
+// CHECK: ------------
+// CHECK: struct/Swift | S1 | s:4file2S1V | <no-cgname> | Def,Ref,RelCont -
+// CHECK: instance-method/acc-get/Swift | getter:property | s:4file2S1V8propertySifg | <no-cgname> | Def,Ref,Call,Impl,RelChild,RelRec,RelCall,RelAcc,RelCont -
+// CHECK: instance-property/Swift | property | [[property_USR:s:4file2S1V8propertySiv]] | <no-cgname> | Def,Ref,Read,RelChild,RelCont -
+// CHECK: static-method/acc-get/Swift | getter:staticProperty | s:4file2S1V14staticPropertySifg | <no-cgname> | Def,Ref,Call,Impl,RelChild,RelRec,RelCall,RelAcc,RelCont -
+// CHECK: static-property/Swift | staticProperty | s:{{.*}} | <no-cgname> | Def,Ref,Read,RelChild,RelCont -
+// CHECK: instance-property/Swift | computedPropertyGetSet | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: struct/Swift | Int | s:Si | <no-cgname> | Ref -
+// CHECK: instance-method/acc-get/Swift | getter:computedPropertyGetSet | s:4file2S1V22computedPropertyGetSetSifg | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-set/Swift | setter:computedPropertyGetSet | s:4file2S1V22computedPropertyGetSetSifs | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-property/Swift | computedPropertyWillDid | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-willset/Swift | willSet:computedPropertyWillDid | s:4file2S1V23computedPropertyWillDidSifw | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-didset/Swift | didSet:computedPropertyWillDid | s:4file2S1V23computedPropertyWillDidSifW | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-property/Swift | computedPropertyAddressor | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-addr/Swift | <no-name> | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/acc-mutaddr/Swift | <no-name> | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: static-method/Swift | staticMethod() | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-property/subscript/Swift | subscript(_:) | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: instance-method/acc-get/Swift | getter:subscript(_:) | s:{{.*}} | <no-cgname> | Def,RelChild,RelAcc -
+// CHECK: protocol/Swift | P1 | s:{{.*}} | <no-cgname> | Def -
+// CHECK: type-alias/associated-type/Swift | AT | s:{{.*}} | <no-cgname> | Def,Ref,RelChild -
+// CHECK: type-alias/Swift | TA | s:{{.*}} | <no-cgname> | Def,RelChild -
+// CHECK: class/Swift | C1 | s:{{.*}} | <no-cgname> | Def,Ref,RelBase,RelCont -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,Ref,Call,Dyn,RelChild,RelRec,RelCall,RelCont -
+// CHECK: class/Swift | C2 | s:{{.*}} | <no-cgname> | Def -
+// CHECK: instance-method/Swift | method() | s:{{.*}} | <no-cgname> | Def,Dyn,RelChild,RelOver -
+// CHECK: function/Swift | takeC1(x:) | s:{{.*}} | <no-cgname> | Def -
+// CHECK: instance-method(test)/Swift | testFoo() | s:{{.*}} | <no-cgname> | Def,Dyn,RelChild -
+// CHECK: ------------
+
+// CHECK: [[@LINE+1]]:8 | struct/Swift | [[S1_USR:s:.*]] | Def | rel: 0
+struct S1 {
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[property_USR]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ let property = 1
+// CHECK: [[@LINE+2]]:14 | static-property/Swift | [[staticProperty_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ static let staticProperty = 2
+
+// CHECK: [[@LINE+3]]:7 | instance-property/Swift | [[computedPropertyGetSet_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+// CHECK: [[@LINE+1]]:31 | struct/Swift | s:Si | Ref | rel: 0
+ var computedPropertyGetSet: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-get/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyGetSet_USR]]
+ get { return 1 }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-set/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyGetSet_USR]]
+ set { }
+ }
+
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[computedPropertyWillDid_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ var computedPropertyWillDid: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-willset/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyWillDid_USR]]
+ willSet { }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-didset/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyWillDid_USR]]
+ didSet { }
+ }
+
+// CHECK: [[@LINE+2]]:7 | instance-property/Swift | [[computedPropertyAddressor_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ var computedPropertyAddressor: Int {
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-addr/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyAddressor_USR]]
+ unsafeAddress { }
+// CHECK: [[@LINE+2]]:5 | instance-method/acc-mutaddr/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[computedPropertyAddressor_USR]]
+ unsafeMutableAddress { }
+ }
+
+// CHECK: [[@LINE+2]]:8 | instance-method/Swift | [[method_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ func method() {
+ _ = self
+// CHECK: [[@LINE+4]]:9 | instance-method/acc-get/Swift | s:{{.*}} | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[method_USR]]
+// CHECK-NEXT: RelRec | [[S1_USR]]
+// CHECK: [[@LINE+1]]:9 | instance-property/Swift | s:{{.*}} | Ref,Read,RelCont | rel: 1
+ _ = property
+ }
+
+// CHECK: [[@LINE+2]]:15 | static-method/Swift | [[staticMethod_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+ static func staticMethod() {
+// CHECK: [[@LINE+5]]:9 | struct/Swift | s:{{.*}} | Ref,RelCont | rel: 1
+// CHECK: [[@LINE+4]]:12 | static-method/acc-get/Swift | s:{{.*}} | Ref,Call,Impl,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[staticMethod_USR]]
+// CHECK-NEXT: RelRec | [[S1_USR]]
+// CHECK: [[@LINE+1]]:12 | static-property/Swift | s:{{.*}} | Ref,Read,RelCont | rel: 1
+ _ = S1.staticProperty
+ }
+
+// CHECK: [[@LINE+4]]:3 | instance-property/subscript/Swift | [[S1_subscript_USR:s:.*]] | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[S1_USR]]
+// CHECK: [[@LINE+2]]:28 | instance-method/acc-get/Swift | s:{{.*}} | Def,RelChild,RelAcc | rel: 1
+// CHECK-NEXT: RelChild,RelAcc | [[S1_subscript_USR]]
+ subscript(x: Int) -> Int { return 1 }
+}
+
+// CHECK: [[@LINE+1]]:10 | protocol/Swift | [[P1_USR:s:.*]] | Def | rel: 0
+protocol P1 {
+// CHECK: [[@LINE+2]]:18 | type-alias/associated-type/Swift | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[P1_USR]]
+ associatedtype AT
+// CHECK: [[@LINE+3]]:13 | type-alias/Swift | s:{{.*}} | Def,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[P1_USR]]
+// CHECK: [[@LINE+1]]:18 | type-alias/associated-type/Swift | s:{{.*}} | Ref | rel: 0
+ typealias TA = AT
+}
+
+// CHECK: [[@LINE+1]]:7 | class/Swift | [[C1_USR:s:.*]] | Def | rel: 0
+class C1 {
+// CHECK: [[@LINE+2]]:8 | instance-method/Swift | [[C1_foo_USR:s:.*]] | Def,Dyn,RelChild | rel: 1
+// CHECK-NEXT: RelChild | [[C1_USR]]
+ func method() {}
+}
+// CHECK: [[@LINE+3]]:7 | class/Swift | [[C2_USR:s:.*]] | Def | rel: 0
+// CHECK: [[@LINE+2]]:12 | class/Swift | [[C1_USR]] | Ref,RelBase | rel: 1
+// CHECK-NEXT: RelBase | [[C2_USR]]
+class C2 : C1 {
+// CHECK: [[@LINE+3]]:17 | instance-method/Swift | s:{{.*}} | Def,Dyn,RelChild,RelOver | rel: 2
+// CHECK-NEXT: RelOver | [[C1_foo_USR]]
+// CHECK-NEXT: RelChild | [[C2_USR]]
+ override func method() {}
+}
+
+// CHECK: [[@LINE+2]]:6 | function/Swift | [[takeC1_USR:s:.*]] | Def | rel: 0
+// CHECK: [[@LINE+1]]:16 | class/Swift | s:{{.*}} | Ref,RelCont | rel: 1
+func takeC1(x: C1) {
+// CHECK: [[@LINE+3]]:5 | instance-method/Swift | s:{{.*}} | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2
+// CHECK-NEXT: RelCall,RelCont | [[takeC1_USR]]
+// CHECK-NEXT: RelRec | [[C1_USR]]
+ x.method()
+}
+
+func test1() {}
+class XCTestCase {}
+class MyTestCase: XCTestCase {
+// CHECK: [[@LINE+2]]:8 | instance-method(test)/Swift | s:{{.*}} | Def,Dyn,RelChild | rel: 1
+// CHECK-NEXT: RelChild | s:4file10MyTestCaseC
+ func testFoo() { test1() }
+}
diff --git a/test/Index/Store/record-with-compile-error.swift b/test/Index/Store/record-with-compile-error.swift
new file mode 100644
index 0000000..0cb017d
--- /dev/null
+++ b/test/Index/Store/record-with-compile-error.swift
@@ -0,0 +1,12 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -o %t/file.o -typecheck %s -verify
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s
+
+// CHECK: function/Swift | test1() | [[TEST1_FUNC:.*]] | <no-cgname> | Def
+// CHECK: [[@LINE+1]]:6 | function/Swift | [[TEST1_FUNC]]
+func test1() {
+ unresolved() // expected-error {{use of unresolved identifier}}
+}
diff --git a/test/Index/Store/unit-from-compile.swift b/test/Index/Store/unit-from-compile.swift
new file mode 100644
index 0000000..2ddfb6e
--- /dev/null
+++ b/test/Index/Store/unit-from-compile.swift
@@ -0,0 +1,24 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend -c -index-store-path %t/idx %s -o %t/file1.o -module-name some_module_test
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+// RUN: %target-swift-frontend -c -index-store-path %t/idx_opt %s -o %t/file1.o -module-name some_module_test -O
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=OPT
+
+// CHECK: file1.o
+// CHECK: provider: swift
+// CHECK: is-system: 0
+// CHECK: is-module: 0
+// CHECK: module-name: some_module_test
+// CHECK: has-main: 1
+// CHECK: main-path: {{.*}}/unit-from-compile.swift
+// CHECK: out-file: {{.*}}/file1.o
+// CHECK: is-debug: 1
+
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}/Swift.swiftmodule |
+// CHECK: DEPEND END (1)
+
+// OPT: is-debug: 1
diff --git a/test/Index/Store/unit-multiple-sourcefiles.swift b/test/Index/Store/unit-multiple-sourcefiles.swift
new file mode 100644
index 0000000..a35350b
--- /dev/null
+++ b/test/Index/Store/unit-multiple-sourcefiles.swift
@@ -0,0 +1,33 @@
+// XFAIL: linux
+
+//===--- Building source files separately with a module merge at the end
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s1.swift %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %t/s1.swift %t/s2.swift -o %t/s1.o -c -module-name main -emit-module -emit-module-path %t/s1.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swift -primary-file %t/s2.swift -o %t/s2.o -c -module-name main -emit-module -emit-module-path %t/s2.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swiftmodule %t/s2.swiftmodule -emit-module -o %t/main.swiftmodule -module-name main
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+//===--- Building source files together (e.g. WMO)
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s1.swift %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %t/s1.swift %t/s2.swift -o %t/s1.o -o %t/s2.o -c -module-name main -emit-module -emit-module-path %t/main.swiftmodule
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+// CHECK-NOT: main.swiftmodule-{{[A-Z0-9]*}}
+
+// CHECK: s1.o-{{[A-Z0-9]*}}
+// CHECK: --------
+// CHECK: out-file: {{.*}}s1.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: s2.o-{{[A-Z0-9]*}}
+// CHECK: --------
+// CHECK: out-file: {{.*}}s2.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
diff --git a/test/Index/Store/unit-one-file-multi-file-invocation.swift b/test/Index/Store/unit-one-file-multi-file-invocation.swift
new file mode 100644
index 0000000..65d08c0
--- /dev/null
+++ b/test/Index/Store/unit-one-file-multi-file-invocation.swift
@@ -0,0 +1,23 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %swiftc_driver -index-file -index-file-path %s %s %S/Inputs/SwiftModuleA.swift -module-name unit_one_test -o %t.output_for_index -index-store-path %t/idx
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=UNIT
+
+// UNIT-NOT: SwiftShims
+
+// UNIT: [[SWIFT:Swift.swiftmodule-[A-Z0-9]*]]
+// UNIT: DEPEND START
+// UNIT: Record | system | Swift.Math.Floating | {{.*}}Swift.swiftmodule | Swift.swiftmodule_Math_Floating-{{.*}}
+// UNIT: Record | system | Swift.String | {{.*}}Swift.swiftmodule | Swift.swiftmodule_String-{{.*}}
+// UNIT: DEPEND END
+
+// UNIT: unit-one-file-multi-file-invocation{{.*}}.output_for_index
+// UNIT: DEPEND START
+// UNIT: Unit | system |{{.*}}/Swift.swiftmodule | [[SWIFT]]
+// UNIT: Record | user |{{.*}}/unit-one-file-multi-file-invocation.swift |
+// UNIT: DEPEND END (2)
+
+func test1() {
+ funcSwiftA()
+}
diff --git a/test/Index/Store/unit-one-sourcefile.swift b/test/Index/Store/unit-one-sourcefile.swift
new file mode 100644
index 0000000..d0acc59
--- /dev/null
+++ b/test/Index/Store/unit-one-sourcefile.swift
@@ -0,0 +1,29 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -o %t/file1.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s %t/s2.swift -o %t/file1.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: touch %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s -primary-file %t/s2.swift -o %t/file2.o -typecheck
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE2
+
+// FILE1: file1.o-{{[A-Z0-9]*}}
+// FILE1: --------
+// FILE1: out-file: {{.*}}file1.o
+// FILE1: DEPEND START
+// FILE1: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE1: DEPEND END
+
+// FILE2: file2.o-{{[A-Z0-9]*}}
+// FILE2: --------
+// FILE2: out-file: {{.*}}file2.o
+// FILE2: DEPEND START
+// FILE2: Unit | system | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE2: DEPEND END
diff --git a/test/Index/Store/unit-pcm-dependency.swift b/test/Index/Store/unit-pcm-dependency.swift
new file mode 100644
index 0000000..c9721ba
--- /dev/null
+++ b/test/Index/Store/unit-pcm-dependency.swift
@@ -0,0 +1,79 @@
+// RUN: rm -rf %t
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s -o %t/s1.o -I %S/Inputs -typecheck -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// If the module cache already exists, the pcm gets indexed.
+// RUN: rm -rf %t/idx
+// RUN: %target-swift-frontend -index-store-path %t/idx -primary-file %s -o %t/s1.o -I %S/Inputs -typecheck -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s -check-prefix=FILE1
+
+// FIXME: index the bridging header!
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: echo 'import ClangModuleA' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s %t/s2.swift -o %t/s1.o -o %t/s2.o -I %S/Inputs -c -emit-module -module-name main -emit-module-path %t/main.swiftmodule -module-cache-path %t/mcp
+// RUN: c-index-test core -print-unit %t/idx > %t/both.txt
+// RUN: %FileCheck %s -check-prefix=FILE1 < %t/both.txt
+// RUN: %FileCheck %s -check-prefix=FILE2 < %t/both.txt
+
+
+// XFAIL: linux
+
+import ClangModuleB
+import ClangModuleC.Sub1
+import ClangModuleC.Sub2
+
+func test() {
+ funcA()
+ funcB()
+}
+
+// FILE1: ClangModuleA-
+// FILE1: --------
+// FILE1: is-system: 0
+// FILE1: has-main: 0
+// FILE1: DEPEND START
+// FILE1: Record | user | {{.*}}ClangModuleA.h | ClangModuleA.h-
+// FILE1: DEPEND END
+
+// FILE1: ClangModuleB-
+// FILE1: --------
+// FILE1: is-system: 0
+// FILE1: has-main: 0
+// FILE1: DEPEND START
+// FILE1: Unit | user | ClangModuleA | {{.*}}ClangModuleA-{{.*}}.pcm | ClangModuleA-{{.*}}.pcm-
+// FILE1: Record | user | {{.*}}ClangModuleB.h | ClangModuleB.h-
+// FILE1: DEPEND END
+
+// FILE1: s1.o-
+// FILE1: --------
+// FILE1: has-main: 1
+// FILE1: DEPEND START
+// FILE1-NOT: ClangModuleA.h
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Unit | system | Swift | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Unit | user | ClangModuleB | {{.*}}ClangModuleB-{{[A-Z0-9]*}}.pcm | ClangModuleB-{{[A-Z0-9]*}}.pcm-
+// FILE1: Unit | user | ClangModuleC | {{.*}}ClangModuleC-{{[A-Z0-9]*}}.pcm | ClangModuleC-{{[A-Z0-9]*}}.pcm-
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: Record | user | {{.*}}unit-pcm-dependency.swift | unit-pcm-dependency.swift-
+// FILE1-NOT: Unit |{{.*}}ClangModuleA
+// FILE1: DEPEND END (4)
+
+// FILE2-NOT: main.swiftmodule-
+
+// FILE2: s2.o-
+// FILE2: --------
+// FILE2: has-main: 1
+// FILE2: out-file: {{.*}}s2.o
+// FILE2: DEPEND START
+// FILE2-NOT: ClangModuleB.h
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: Unit | system | Swift | {{.*}}Swift.swiftmodule | | {{[0-9]*$}}
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: Unit | user | ClangModuleA | {{.*}}ClangModuleA-{{[A-Z0-9]*}}.pcm | ClangModuleA-{{[A-Z0-9]*}}.pcm-
+// FILE2-NOT: Unit |{{.*}}ClangModuleB
+// FILE2-NOT: Record
+// FILE2: DEPEND END
diff --git a/test/Index/Store/unit-swiftmodule-dependency.swift b/test/Index/Store/unit-swiftmodule-dependency.swift
new file mode 100644
index 0000000..df54f92
--- /dev/null
+++ b/test/Index/Store/unit-swiftmodule-dependency.swift
@@ -0,0 +1,57 @@
+// RUN: rm -rf %t && mkdir %t
+
+// RUN: %target-swift-frontend -index-store-path %t/idx %S/Inputs/SwiftModuleA.swift -emit-module -o %t/SwiftModuleA.swiftmodule
+// RUN: %target-swift-frontend -index-store-path %t/idx %S/Inputs/SwiftModuleB.swift -emit-module -o %t/SwiftModuleB.swiftmodule -I %t
+
+// RUN: echo 'import SwiftModuleA' > %t/s2.swift
+// RUN: %target-swift-frontend -index-store-path %t/idx %s %t/s2.swift -c -o %t/s1.o -o %t/s2.o -I %t -emit-module -module-name main -emit-module-path %t/main.swiftmodule
+
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s
+
+// XFAIL: linux
+
+import SwiftModuleA
+import SwiftModuleB
+
+func test() {
+ funcSwiftA()
+ funcSwiftB()
+}
+
+// CHECK: [[MODA:SwiftModuleA.swiftmodule-[A-Z0-9]*]]
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/SwiftModuleA.swiftmodule
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: [[MODB:SwiftModuleB.swiftmodule-[A-Z0-9]*]]
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/SwiftModuleB.swiftmodule
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK-NOT: main.swiftmodule-
+
+// CHECK: s1.o-
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/s1.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleB | {{.*}}/SwiftModuleB.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
+
+// CHECK: s2.o-
+// CHECK: --------
+// CHECK: has-main: 1
+// CHECK: out-file: {{.*}}/s2.o
+// CHECK: DEPEND START
+// CHECK: Unit | system | Swift | {{.*}}/Swift.swiftmodule | | {{[0-9]*$}}
+// CHECK: Unit | user | SwiftModuleA | {{.*}}/SwiftModuleA.swiftmodule | | {{[0-9]*$}}
+// CHECK: DEPEND END
diff --git a/test/Index/Store/unit-with-bridging-header.swift b/test/Index/Store/unit-with-bridging-header.swift
new file mode 100644
index 0000000..f335802
--- /dev/null
+++ b/test/Index/Store/unit-with-bridging-header.swift
@@ -0,0 +1,49 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-pch -index-store-path %t/idx -o %t/bridge-head.pch %S/Inputs/bridge-head.h
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %t/bridge-head.pch -primary-file %s -o %t/s1.o -index-store-path %t/idx
+// RUN: c-index-test core -print-record %t/idx | %FileCheck %s --check-prefix=PCH-RECORD
+// RUN: c-index-test core -print-unit %t/idx | %FileCheck %s --check-prefix=PCH-UNIT
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck -import-objc-header %S/Inputs/bridge-head.h -primary-file %s -o %t/s1.o -index-store-path %t/idx2
+// RUN: c-index-test core -print-unit %t/idx2 | %FileCheck --check-prefix=TEXTUAL-UNIT %s
+
+// PCH-RECORD: bridge-include.h
+// PCH-RECORD: ------------
+// PCH-RECORD: function/C | includedFunc | {{.*}} | <no-cgname> | Decl -
+// PCH-RECORD: variable/C | MY_CONST | {{.*}} | <no-cgname> | Def -
+// PCH-RECORD: ------------
+// PCH-RECORD: 1:5 | function/C | {{.*}} | Decl | rel: 0
+// PCH-RECORD: 2:5 | variable/C | {{.*}} | Def | rel: 0
+
+// PCH-UNIT: bridge-head.pch-
+// PCH-UNIT: --------
+// PCH-UNIT: has-main: 0
+// PCH-UNIT: DEPEND START
+// PCH-UNIT: Record | user | {{.*}}bridge-include.h | bridge-include.h-
+// PCH-UNIT: File | user | {{.*}}bridge-head.h |
+// PCH-UNIT: File | user | {{.*}}module.modulemap |
+// PCH-UNIT: DEPEND END (3)
+// PCH-UNIT: INCLUDE START
+// PCH-UNIT: {{.*}}bridge-head.h:1 | {{.*}}bridge-include.h
+// PCH-UNIT: INCLUDE END (1)
+
+// PCH-UNIT: s1.o-
+// PCH-UNIT: --------
+// PCH-UNIT: has-main: 1
+// PCH-UNIT: DEPEND START
+// PCH-UNIT: Unit | system | {{.*}}Swift.swiftmodule |
+// PCH-UNIT: Unit | user | {{.*}}bridge-head.pch | bridge-head.pch-
+// PCH-UNIT: Record | user | {{.*}}unit-with-bridging-header.swift | unit-with-bridging-header.swift-
+// PCH-UNIT: DEPEND END (3)
+
+// TEXTUAL-UNIT: s1.o-
+// TEXTUAL-UNIT: --------
+// TEXTUAL-UNIT: has-main: 1
+// TEXTUAL-UNIT: DEPEND START
+// TEXTUAL-UNIT: Unit | system | {{.*}}Swift.swiftmodule |
+// TEXTUAL-UNIT: Record | user | {{.*}}unit-with-bridging-header.swift | unit-with-bridging-header.swift-
+// TEXTUAL-UNIT: DEPEND END (2)
+
+func test() {}
diff --git a/test/SIL/ownership-verifier/unreachable_code.sil b/test/SIL/ownership-verifier/unreachable_code.sil
index fbe963d..4d88955 100644
--- a/test/SIL/ownership-verifier/unreachable_code.sil
+++ b/test/SIL/ownership-verifier/unreachable_code.sil
@@ -128,3 +128,22 @@
%9999 = tuple()
return %9999 : $()
}
+
+sil @test7 : $@convention(thin) (@owned Builtin.NativeObject) -> () {
+bb0(%0 : @owned $Builtin.NativeObject):
+ %1 = begin_borrow %0 : $Builtin.NativeObject
+ cond_br undef, bb1, bb2
+
+bb1:
+ end_borrow %1 from %0 : $Builtin.NativeObject, $Builtin.NativeObject
+ destroy_value %0 : $Builtin.NativeObject
+ %9999 = tuple()
+ return %9999 : $()
+
+bb2:
+ end_borrow %1 from %0 : $Builtin.NativeObject, $Builtin.NativeObject
+ br bb3
+
+bb3:
+ unreachable
+}
diff --git a/test/SIL/ownership-verifier/use_verifier.sil b/test/SIL/ownership-verifier/use_verifier.sil
index 72d95b6..e5b1249 100644
--- a/test/SIL/ownership-verifier/use_verifier.sil
+++ b/test/SIL/ownership-verifier/use_verifier.sil
@@ -334,6 +334,14 @@
return %9999 : $()
}
+sil @block_invoke_test : $@convention(thin) (@owned @convention(block) () -> ()) -> () {
+bb0(%0 : @owned $@convention(block) () -> ()):
+ apply %0() : $@convention(block) () -> ()
+ destroy_value %0 : $@convention(block) () -> ()
+ %9999 = tuple()
+ return %9999 : $()
+}
+
//////////////////////
// Terminator Tests //
//////////////////////
diff --git a/test/SILGen/constrained_extensions.swift b/test/SILGen/constrained_extensions.swift
index 61aa4ea..eebc9aa 100644
--- a/test/SILGen/constrained_extensions.swift
+++ b/test/SILGen/constrained_extensions.swift
@@ -1,6 +1,6 @@
// RUN: %target-swift-frontend -emit-silgen -primary-file %s | %FileCheck %s
-// RUN: %target-swift-frontend -emit-sil -O -primary-file %s
-// RUN: %target-swift-frontend -emit-ir -primary-file %s
+// RUN: %target-swift-frontend -emit-sil -O -primary-file %s > /dev/null
+// RUN: %target-swift-frontend -emit-ir -primary-file %s > /dev/null
extension Array where Element == Int {
// CHECK-LABEL: sil @_T0Sa22constrained_extensionsSiRszlESaySiGyt1x_tcfC : $@convention(method) (@thin Array<Int>.Type) -> @owned Array<Int>
diff --git a/test/SILGen/dynamic.swift b/test/SILGen/dynamic.swift
index ee06b36..dac47a9 100644
--- a/test/SILGen/dynamic.swift
+++ b/test/SILGen/dynamic.swift
@@ -456,7 +456,10 @@
// CHECK: [[BORROWED_VALUE:%.*]] = begin_borrow [[VALUE]]
// CHECK: [[VALUE_COPY:%.*]] = copy_value [[BORROWED_VALUE]]
// CHECK: [[CASTED_VALUE_COPY:%.*]] = upcast [[VALUE_COPY]]
- // CHECK: [[SUPER:%.*]] = super_method [volatile] [[VALUE_COPY]] : $Sub, #Base.x!getter.1.foreign : (Base) -> () -> Bool, $@convention(objc_method) (Base) -> ObjCBool
+ // CHECK: [[BORROWED_CASTED_VALUE_COPY:%.*]] = begin_borrow [[CASTED_VALUE_COPY]]
+ // CHECK: [[DOWNCAST_FOR_SUPERMETHOD:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_VALUE_COPY]]
+ // CHECK: [[SUPER:%.*]] = super_method [volatile] [[DOWNCAST_FOR_SUPERMETHOD]] : $Sub, #Base.x!getter.1.foreign : (Base) -> () -> Bool, $@convention(objc_method) (Base) -> ObjCBool
+ // CHECK: end_borrow [[BORROWED_CASTED_VALUE_COPY]] from [[CASTED_VALUE_COPY]]
// CHECK: = apply [[SUPER]]([[CASTED_VALUE_COPY]])
// CHECK: destroy_value [[VALUE_COPY]]
// CHECK: end_borrow [[BORROWED_VALUE]] from [[VALUE]]
diff --git a/test/SILGen/foreign_errors.swift b/test/SILGen/foreign_errors.swift
index ca6afb7..e2039f5 100644
--- a/test/SILGen/foreign_errors.swift
+++ b/test/SILGen/foreign_errors.swift
@@ -198,7 +198,10 @@
// CHECK: store [[ARG2]] to [init] [[PB]]
// CHECK: [[T0:%.*]] = load [take] [[PB]]
// CHECK-NEXT: [[T1:%.*]] = upcast [[T0]] : $VeryErrorProne to $ErrorProne
-// CHECK-NEXT: [[T2:%.*]] = super_method [volatile] [[T0]] : $VeryErrorProne, #ErrorProne.init!initializer.1.foreign : (ErrorProne.Type) -> (Any?) throws -> ErrorProne, $@convention(objc_method) (Optional<AnyObject>, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @owned ErrorProne) -> @owned Optional<ErrorProne>
+// CHECK-NEXT: [[BORROWED_T1:%.*]] = begin_borrow [[T1]]
+// CHECK-NEXT: [[DOWNCAST_BORROWED_T1:%.*]] = unchecked_ref_cast [[BORROWED_T1]] : $ErrorProne to $VeryErrorProne
+// CHECK-NEXT: [[T2:%.*]] = super_method [volatile] [[DOWNCAST_BORROWED_T1]] : $VeryErrorProne, #ErrorProne.init!initializer.1.foreign : (ErrorProne.Type) -> (Any?) throws -> ErrorProne, $@convention(objc_method) (Optional<AnyObject>, Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>, @owned ErrorProne) -> @owned Optional<ErrorProne>
+// CHECK: end_borrow [[BORROWED_T1]] from [[T1]]
// CHECK: [[BORROWED_ARG1:%.*]] = begin_borrow [[ARG1]]
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[BORROWED_ARG1]]
// CHECK-NOT: [[BOX]]{{^[0-9]}}
diff --git a/test/SILGen/objc_dealloc.swift b/test/SILGen/objc_dealloc.swift
index b39d862..5130986 100644
--- a/test/SILGen/objc_dealloc.swift
+++ b/test/SILGen/objc_dealloc.swift
@@ -20,10 +20,16 @@
// CHECK-LABEL: sil hidden @_T012objc_dealloc10SwiftGizmoC{{[_0-9a-zA-Z]*}}fc
// CHECK: bb0([[SELF_PARAM:%[0-9]+]] : $SwiftGizmo):
override init() {
- // CHECK: [[SELF_UNINIT:%[0-9]+]] = mark_uninitialized [derivedselfonly]
+ // CHECK: [[SELF_BOX:%.*]] = alloc_box ${ var SwiftGizmo }, let, name "self"
+ // CHECK: [[SELF_UNINIT:%.*]] = mark_uninitialized [derivedselfonly] [[SELF_BOX]] : ${ var SwiftGizmo }
+ // CHECK: [[SELF_ADDR:%.*]] = project_box [[SELF_UNINIT]]
// CHECK-NOT: ref_element_addr
- // CHECK: upcast
- // CHECK-NEXT: super_method
+ // CHECK: [[SELF:%.*]] = load [take] [[SELF_ADDR]]
+ // CHECK-NEXT: [[UPCAST_SELF:%.*]] = upcast [[SELF]] : $SwiftGizmo to $Gizmo
+ // CHECK-NEXT: [[BORROWED_UPCAST_SELF:%.*]] = begin_borrow [[UPCAST_SELF]]
+ // CHECK-NEXT: [[DOWNCAST_BORROWED_UPCAST_SELF:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF]] : $Gizmo to $SwiftGizmo
+ // CHECK-NEXT: super_method [volatile] [[DOWNCAST_BORROWED_UPCAST_SELF]] : $SwiftGizmo
+ // CHECK-NEXT: end_borrow [[BORROWED_UPCAST_SELF]] from [[UPCAST_SELF]]
// CHECK: return
super.init()
}
diff --git a/test/SILGen/objc_extensions.swift b/test/SILGen/objc_extensions.swift
index 0b263c0..4319b3b 100644
--- a/test/SILGen/objc_extensions.swift
+++ b/test/SILGen/objc_extensions.swift
@@ -30,7 +30,10 @@
// CHECK: bb0([[SELF:%.*]] : $Sub):
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[SELF_COPY_CAST:%.*]] = upcast [[SELF_COPY]] : $Sub to $Base
- // CHECK: [[SUPER_METHOD:%.*]] = super_method [volatile] [[SELF_COPY]] : $Sub, #Base.prop!getter.1.foreign
+ // CHECK: [[BORROWED_SELF_COPY_CAST:%.*]] = begin_borrow [[SELF_COPY_CAST]]
+ // CHECK: [[CAST_BACK:%.*]] = unchecked_ref_cast [[BORROWED_SELF_COPY_CAST]] : $Base to $Sub
+ // CHECK: [[SUPER_METHOD:%.*]] = super_method [volatile] [[CAST_BACK]] : $Sub, #Base.prop!getter.1.foreign
+ // CHECK: end_borrow [[BORROWED_SELF_COPY_CAST]] from [[SELF_COPY_CAST]]
// CHECK: [[RESULT:%.*]] = apply [[SUPER_METHOD]]([[SELF_COPY_CAST]])
// CHECK: bb3(
// CHECK: destroy_value [[SELF_COPY]]
@@ -61,7 +64,10 @@
// CHECK: bb0([[NEW_VALUE:%.*]] : $Optional<String>, [[SELF:%.*]] : $Sub):
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[UPCAST_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $Sub to $Base
- // CHECK: [[GET_SUPER_METHOD:%.*]] = super_method [volatile] [[SELF_COPY]] : $Sub, #Base.prop!getter.1.foreign : (Base) -> () -> String!, $@convention(objc_method) (Base) -> @autoreleased Optional<NSString>
+ // CHECK: [[BORROWED_UPCAST_SELF_COPY:%.*]] = begin_borrow [[UPCAST_SELF_COPY]]
+ // CHECK: [[CAST_BACK:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY]] : $Base to $Sub
+ // CHECK: [[GET_SUPER_METHOD:%.*]] = super_method [volatile] [[CAST_BACK]] : $Sub, #Base.prop!getter.1.foreign : (Base) -> () -> String!, $@convention(objc_method) (Base) -> @autoreleased Optional<NSString>
+ // CHECK: end_borrow [[BORROWED_UPCAST_SELF_COPY]] from [[UPCAST_SELF_COPY]]
// CHECK: [[OLD_NSSTRING:%.*]] = apply [[GET_SUPER_METHOD]]([[UPCAST_SELF_COPY]])
// CHECK: bb3([[OLD_NSSTRING_BRIDGED:%.*]] : $Optional<String>):
@@ -71,7 +77,10 @@
// CHECK: [[UPCAST_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $Sub to $Base
// CHECK: [[BORROWED_NEW_VALUE:%.*]] = begin_borrow [[NEW_VALUE]]
// CHECK: [[NEW_VALUE_COPY:%.*]] = copy_value [[BORROWED_NEW_VALUE]]
- // CHECK: [[SET_SUPER_METHOD:%.*]] = super_method [volatile] [[SELF_COPY]] : $Sub, #Base.prop!setter.1.foreign : (Base) -> (String!) -> (), $@convention(objc_method) (Optional<NSString>, Base) -> ()
+ // CHECK: [[BORROWED_SELF_COPY_FOR_SUPERREF:%.*]] = begin_borrow [[UPCAST_SELF_COPY]]
+ // CHECK: [[SUPERREF_DOWNCAST:%.*]] = unchecked_ref_cast [[BORROWED_SELF_COPY_FOR_SUPERREF]] : $Base to $Sub
+ // CHECK: [[SET_SUPER_METHOD:%.*]] = super_method [volatile] [[SUPERREF_DOWNCAST]] : $Sub, #Base.prop!setter.1.foreign : (Base) -> (String!) -> (), $@convention(objc_method) (Optional<NSString>, Base) -> ()
+ // CHECK: end_borrow [[BORROWED_SELF_COPY_FOR_SUPERREF]] from [[UPCAST_SELF_COPY]]
// CHECK: switch_enum [[NEW_VALUE_COPY]] : $Optional<String>, case #Optional.some!enumelt.1: [[SOME_BB:bb[0-9]+]], case #Optional.none!enumelt: [[NONE_BB:bb[0-9]+]]
//
// CHECK: bb4([[OLD_STRING:%.*]] : $String):
@@ -130,7 +139,11 @@
// CHECK-LABEL: sil hidden @_T015objc_extensions03SubC0C14objCBaseMethodyyF
// CHECK: bb0([[SELF:%.*]] : $SubSub):
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
- // CHECK: super_method [volatile] [[SELF_COPY]] : $SubSub, #Sub.objCBaseMethod!1.foreign : (Sub) -> () -> (), $@convention(objc_method) (Sub) -> ()
+ // CHECK: [[UPCAST_SELF_COPY:%.*]] = upcast [[SELF_COPY]] : $SubSub to $Sub
+ // CHECK: [[BORROWED_UPCAST_SELF_COPY:%.*]] = begin_borrow [[UPCAST_SELF_COPY]]
+ // CHECK: [[DOWNCAST:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY]] : $Sub to $SubSub
+ // CHECK: super_method [volatile] [[DOWNCAST]] : $SubSub, #Sub.objCBaseMethod!1.foreign : (Sub) -> () -> (), $@convention(objc_method) (Sub) -> ()
+ // CHECK: end_borrow [[BORROWED_UPCAST_SELF_COPY]] from [[UPCAST_SELF_COPY]]
// CHECK: } // end sil function '_T015objc_extensions03SubC0C14objCBaseMethodyyF'
override func objCBaseMethod() {
super.objCBaseMethod()
@@ -141,9 +154,18 @@
// CHECK-LABEL: sil hidden @_T015objc_extensions03SubC0C9otherPropSSfs
// CHECK: bb0([[NEW_VALUE:%.*]] : $String, [[SELF:%.*]] : $SubSub):
// CHECK: [[SELF_COPY_1:%.*]] = copy_value [[SELF]]
- // CHECK: = super_method [volatile] [[SELF_COPY_1]] : $SubSub, #Sub.otherProp!getter.1.foreign
+ // CHECK: [[UPCAST_SELF_COPY_1:%.*]] = upcast [[SELF_COPY_1]] : $SubSub to $Sub
+ // CHECK: [[BORROWED_UPCAST_SELF_COPY_1:%.*]] = begin_borrow [[UPCAST_SELF_COPY_1]]
+ // CHECK: [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_1:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY_1]] : $Sub to $SubSub
+ // CHECK: = super_method [volatile] [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_1]] : $SubSub, #Sub.otherProp!getter.1.foreign
+ // CHECK: end_borrow [[BORROWED_UPCAST_SELF_COPY_1]] from [[UPCAST_SELF_COPY_1]]
+
// CHECK: [[SELF_COPY_2:%.*]] = copy_value [[SELF]]
- // CHECK: = super_method [volatile] [[SELF_COPY_2]] : $SubSub, #Sub.otherProp!setter.1.foreign
+ // CHECK: [[UPCAST_SELF_COPY_2:%.*]] = upcast [[SELF_COPY_2]] : $SubSub to $Sub
+ // CHECK: [[BORROWED_UPCAST_SELF_COPY_2:%.*]] = begin_borrow [[UPCAST_SELF_COPY_2]]
+ // CHECK: [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_2:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_SELF_COPY_2]] : $Sub to $SubSub
+ // CHECK: = super_method [volatile] [[DOWNCAST_BORROWED_UPCAST_SELF_COPY_2]] : $SubSub, #Sub.otherProp!setter.1.foreign
+ // CHECK: end_borrow [[BORROWED_UPCAST_SELF_COPY_2]] from [[UPCAST_SELF_COPY_2]]
// CHECK: } // end sil function '_T015objc_extensions03SubC0C9otherPropSSfs'
override var otherProp: String {
didSet {
diff --git a/test/SILGen/objc_thunks.swift b/test/SILGen/objc_thunks.swift
index 0cd4eb9..f6a58f9 100644
--- a/test/SILGen/objc_thunks.swift
+++ b/test/SILGen/objc_thunks.swift
@@ -312,7 +312,10 @@
// CHECK: [[MARKED_SELF_BOX:%[0-9]+]] = mark_uninitialized [derivedself] [[SELF_BOX]]
// CHECK: [[PB_BOX:%.*]] = project_box [[MARKED_SELF_BOX]]
// CHECK: [[GIZMO:%[0-9]+]] = upcast [[SELF:%[0-9]+]] : $Hoozit to $Gizmo
- // CHECK: [[SUPERMETHOD:%[0-9]+]] = super_method [volatile] [[SELF]] : $Hoozit, #Gizmo.init!initializer.1.foreign : (Gizmo.Type) -> (Int) -> Gizmo!, $@convention(objc_method) (Int, @owned Gizmo) -> @owned Optional<Gizmo>
+ // CHECK: [[BORROWED_GIZMO:%.*]] = begin_borrow [[GIZMO]]
+ // CHECK: [[CAST_BORROWED_GIZMO:%.*]] = unchecked_ref_cast [[BORROWED_GIZMO]] : $Gizmo to $Hoozit
+ // CHECK: [[SUPERMETHOD:%[0-9]+]] = super_method [volatile] [[CAST_BORROWED_GIZMO]] : $Hoozit, #Gizmo.init!initializer.1.foreign : (Gizmo.Type) -> (Int) -> Gizmo!, $@convention(objc_method) (Int, @owned Gizmo) -> @owned Optional<Gizmo>
+ // CHECK-NEXT: end_borrow [[BORROWED_GIZMO]] from [[GIZMO]]
// CHECK-NEXT: [[SELF_REPLACED:%[0-9]+]] = apply [[SUPERMETHOD]](%0, [[X:%[0-9]+]]) : $@convention(objc_method) (Int, @owned Gizmo) -> @owned Optional<Gizmo>
// CHECK-NOT: unconditional_checked_cast downcast [[SELF_REPLACED]] : $Gizmo to $Hoozit
// CHECK: unchecked_ref_cast
diff --git a/test/SILGen/partial_apply_super.swift b/test/SILGen/partial_apply_super.swift
index fa193b1..c1d460f 100644
--- a/test/SILGen/partial_apply_super.swift
+++ b/test/SILGen/partial_apply_super.swift
@@ -110,7 +110,10 @@
// CHECK: [[DOFOO:%[0-9]+]] = function_ref @_T019partial_apply_super5doFooyyycF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[SELF_COPY]] : $ChildToFixedOutsideParent to $OutsideParent
- // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[SELF_COPY]] : $ChildToFixedOutsideParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> ()
+ // CHECK: [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+ // CHECK: [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+ // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $ChildToFixedOutsideParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> ()
+ // CHECK: end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
// CHECK: [[PARTIAL_APPLY:%[0-9]+]] = partial_apply [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed OutsideParent) -> ()
// CHECK: apply [[DOFOO]]([[PARTIAL_APPLY]]) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: } // end sil function '_T019partial_apply_super25ChildToFixedOutsideParentC6methodyyF'
@@ -135,7 +138,10 @@
// CHECK: [[DOFOO:%[0-9]+]] = function_ref @_T019partial_apply_super5doFooyyycF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[SELF_COPY]] : $ChildToResilientOutsideParent to $ResilientOutsideParent
- // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[SELF_COPY]] : $ChildToResilientOutsideParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
+ // CHECK: [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+ // CHECK: [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+ // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $ChildToResilientOutsideParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
+ // CHECK: end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
// CHECK: [[PARTIAL_APPLY:%[0-9]+]] = partial_apply [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
// CHECK: apply [[DOFOO]]([[PARTIAL_APPLY]]) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: } // end sil function '_T019partial_apply_super29ChildToResilientOutsideParentC6methodyyF'
@@ -160,7 +166,10 @@
// CHECK: [[DOFOO:%[0-9]+]] = function_ref @_T019partial_apply_super5doFooyyycF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[SELF_COPY]] : $GrandchildToFixedOutsideChild to $OutsideChild
- // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[SELF_COPY]] : $GrandchildToFixedOutsideChild, #OutsideChild.method!1 : (OutsideChild) -> () -> (), $@convention(method) (@guaranteed OutsideChild) -> ()
+ // CHECK: [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+ // CHECK: [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+ // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $GrandchildToFixedOutsideChild, #OutsideChild.method!1 : (OutsideChild) -> () -> (), $@convention(method) (@guaranteed OutsideChild) -> ()
+ // CHECK: end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
// CHECK: [[PARTIAL_APPLY:%[0-9]+]] = partial_apply [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed OutsideChild) -> ()
// CHECK: apply [[DOFOO]]([[PARTIAL_APPLY]]) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: } // end sil function '_T019partial_apply_super29GrandchildToFixedOutsideChildC6methodyyF'
@@ -185,7 +194,10 @@
// CHECK: [[DOFOO:%[0-9]+]] = function_ref @_T019partial_apply_super5doFooyyycF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[SELF_COPY]] : $GrandchildToResilientOutsideChild to $ResilientOutsideChild
- // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[SELF_COPY]] : $GrandchildToResilientOutsideChild, #ResilientOutsideChild.method!1 : (ResilientOutsideChild) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideChild) -> ()
+ // CHECK: [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+ // CHECK: [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+ // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $GrandchildToResilientOutsideChild, #ResilientOutsideChild.method!1 : (ResilientOutsideChild) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideChild) -> ()
+ // CHEC: end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
// CHECK: [[PARTIAL_APPLY:%[0-9]+]] = partial_apply [[SUPER_METHOD]]([[CASTED_SELF_COPY]]) : $@convention(method) (@guaranteed ResilientOutsideChild) -> ()
// CHECK: apply [[DOFOO]]([[PARTIAL_APPLY]]) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: } // end sil function '_T019partial_apply_super33GrandchildToResilientOutsideChildC6methodyyF'
@@ -210,7 +222,10 @@
// CHECK: [[DOFOO:%[0-9]+]] = function_ref @_T019partial_apply_super5doFooyyycF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[SELF_COPY]] : $GenericChildToFixedGenericOutsideParent<A> to $GenericOutsideParent<A>
- // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[SELF_COPY]] : $GenericChildToFixedGenericOutsideParent<A>, #GenericOutsideParent.method!1 : <A> (GenericOutsideParent<A>) -> () -> (), $@convention(method) <τ_0_0> (@guaranteed GenericOutsideParent<τ_0_0>) -> ()
+ // CHECK: [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+ // CHECK: [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+ // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $GenericChildToFixedGenericOutsideParent<A>, #GenericOutsideParent.method!1 : <A> (GenericOutsideParent<A>) -> () -> (), $@convention(method) <τ_0_0> (@guaranteed GenericOutsideParent<τ_0_0>) -> ()
+ // CHECK: end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
// CHECK: [[PARTIAL_APPLY:%[0-9]+]] = partial_apply [[SUPER_METHOD]]<A>([[CASTED_SELF_COPY]]) : $@convention(method) <τ_0_0> (@guaranteed GenericOutsideParent<τ_0_0>) -> ()
// CHECK: apply [[DOFOO]]([[PARTIAL_APPLY]]) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: } // end sil function '_T019partial_apply_super019GenericChildToFixedD13OutsideParentC6methodyyF'
@@ -235,7 +250,10 @@
// CHECK: [[DOFOO:%[0-9]+]] = function_ref @_T019partial_apply_super5doFooyyycF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
// CHECK: [[CASTED_SELF_COPY:%[0-9]+]] = upcast [[SELF_COPY]] : $GenericChildToResilientGenericOutsideParent<A> to $ResilientGenericOutsideParent<A>
- // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[SELF_COPY]] : $GenericChildToResilientGenericOutsideParent<A>, #ResilientGenericOutsideParent.method!1 : <A> (ResilientGenericOutsideParent<A>) -> () -> (), $@convention(method) <τ_0_0> (@guaranteed ResilientGenericOutsideParent<τ_0_0>) -> ()
+ // CHECK: [[BORROWED_CASTED_SELF_COPY:%.*]] = begin_borrow [[CASTED_SELF_COPY]]
+ // CHECK: [[DOWNCAST_BORROWED_CASTED_SELF_COPY:%.*]] = unchecked_ref_cast [[BORROWED_CASTED_SELF_COPY]]
+ // CHECK: [[SUPER_METHOD:%[0-9]+]] = super_method [[DOWNCAST_BORROWED_CASTED_SELF_COPY]] : $GenericChildToResilientGenericOutsideParent<A>, #ResilientGenericOutsideParent.method!1 : <A> (ResilientGenericOutsideParent<A>) -> () -> (), $@convention(method) <τ_0_0> (@guaranteed ResilientGenericOutsideParent<τ_0_0>) -> ()
+ // CHECK: end_borrow [[BORROWED_CASTED_SELF_COPY]] from [[CASTED_SELF_COPY]]
// CHECK: [[PARTIAL_APPLY:%[0-9]+]] = partial_apply [[SUPER_METHOD]]<A>([[CASTED_SELF_COPY]]) : $@convention(method) <τ_0_0> (@guaranteed ResilientGenericOutsideParent<τ_0_0>) -> ()
// CHECK: apply [[DOFOO]]([[PARTIAL_APPLY]]) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: } // end sil function '_T019partial_apply_super023GenericChildToResilientD13OutsideParentC6methodyyF'
diff --git a/test/SILGen/properties.swift b/test/SILGen/properties.swift
index 6017e2e..fa5a7a7 100644
--- a/test/SILGen/properties.swift
+++ b/test/SILGen/properties.swift
@@ -1156,7 +1156,10 @@
// CHECK: bb0([[SELF:%.*]] : $DerivedClassWithPublicProperty):
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]] : $DerivedClassWithPublicProperty
// CHECK-NEXT: [[SUPER:%.*]] = upcast [[SELF_COPY]] : $DerivedClassWithPublicProperty to $BaseClassWithInternalProperty
-// CHECK-NEXT: [[METHOD:%.*]] = super_method [[SELF_COPY]] : $DerivedClassWithPublicProperty, #BaseClassWithInternalProperty.x!getter.1 : (BaseClassWithInternalProperty) -> () -> (), $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
+// CHECK-NEXT: [[BORROWED_SUPER:%.*]] = begin_borrow [[SUPER]]
+// CHECK-NEXT: [[DOWNCAST_BORROWED_SUPER:%.*]] = unchecked_ref_cast [[BORROWED_SUPER]] : $BaseClassWithInternalProperty to $DerivedClassWithPublicProperty
+// CHECK-NEXT: [[METHOD:%.*]] = super_method [[DOWNCAST_BORROWED_SUPER]] : $DerivedClassWithPublicProperty, #BaseClassWithInternalProperty.x!getter.1 : (BaseClassWithInternalProperty) -> () -> (), $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
+// CHECK-NEXT: end_borrow [[BORROWED_SUPER]] from [[SUPER]]
// CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[SUPER]]) : $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
// CHECK-NEXT: destroy_value [[SUPER]] : $BaseClassWithInternalProperty
// CHECK: } // end sil function '_T010properties30DerivedClassWithPublicPropertyC1xytfg'
diff --git a/test/SILGen/super.swift b/test/SILGen/super.swift
index 17d7174..4b23295 100644
--- a/test/SILGen/super.swift
+++ b/test/SILGen/super.swift
@@ -86,7 +86,10 @@
// CHECK: bb0([[SELF:%.*]] : $ChildToResilientParent):
// CHECK: [[COPY_SELF:%.*]] = copy_value [[SELF]]
// CHECK: [[UPCAST_SELF:%.*]] = upcast [[COPY_SELF]]
- // CHECK: [[FUNC:%.*]] = super_method [[COPY_SELF]] : $ChildToResilientParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
+ // CHECK: [[BORROW_UPCAST_SELF:%.*]] = begin_borrow [[UPCAST_SELF]]
+ // CHECK: [[CAST_BORROW_BACK_TO_BASE:%.*]] = unchecked_ref_cast [[BORROW_UPCAST_SELF]]
+ // CHECK: [[FUNC:%.*]] = super_method [[CAST_BORROW_BACK_TO_BASE]] : $ChildToResilientParent, #ResilientOutsideParent.method!1 : (ResilientOutsideParent) -> () -> (), $@convention(method) (@guaranteed ResilientOutsideParent) -> ()
+ // CHECK: end_borrow [[BORROW_UPCAST_SELF]] from [[UPCAST_SELF]]
// CHECK: apply [[FUNC]]([[UPCAST_SELF]])
super.method()
}
@@ -121,7 +124,10 @@
// CHECK: bb0([[SELF:%.*]] : $ChildToFixedParent):
// CHECK: [[COPY_SELF:%.*]] = copy_value [[SELF]]
// CHECK: [[UPCAST_COPY_SELF:%.*]] = upcast [[COPY_SELF]]
- // CHECK: [[FUNC:%.*]] = super_method [[COPY_SELF]] : $ChildToFixedParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> ()
+ // CHECK: [[BORROWED_UPCAST_COPY_SELF:%.*]] = begin_borrow [[UPCAST_COPY_SELF]]
+ // CHECK: [[DOWNCAST_BORROWED_UPCAST_COPY_SELF:%.*]] = unchecked_ref_cast [[BORROWED_UPCAST_COPY_SELF]] : $OutsideParent to $ChildToFixedParent
+ // CHECK: [[FUNC:%.*]] = super_method [[DOWNCAST_BORROWED_UPCAST_COPY_SELF]] : $ChildToFixedParent, #OutsideParent.method!1 : (OutsideParent) -> () -> (), $@convention(method) (@guaranteed OutsideParent) -> ()
+ // CHECK: end_borrow [[BORROWED_UPCAST_COPY_SELF]] from [[UPCAST_COPY_SELF]]
// CHECK: apply [[FUNC]]([[UPCAST_COPY_SELF]])
super.method()
}
diff --git a/test/TBD/global.swift b/test/TBD/global.swift
index 183da4e..af400bf 100644
--- a/test/TBD/global.swift
+++ b/test/TBD/global.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=all %s
+// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=missing %s
public let publicLet: Int = 0
internal let internalLet: Int = 0
diff --git a/test/TBD/protocol.swift b/test/TBD/protocol.swift
index 72db323..e502486 100644
--- a/test/TBD/protocol.swift
+++ b/test/TBD/protocol.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=all %s
+// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=missing %s
public protocol Public {
func publicMethod()
diff --git a/test/TBD/struct.swift b/test/TBD/struct.swift
index d49156a..9bd42bb 100644
--- a/test/TBD/struct.swift
+++ b/test/TBD/struct.swift
@@ -1,4 +1,4 @@
-// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=all %s
+// RUN: %target-swift-frontend -emit-ir -o- -parse-as-library -module-name test -validate-tbd-against-ir=missing %s
public struct PublicNothing {}
diff --git a/test/stdlib/Inputs/NSSlowString/NSSlowString.h b/test/stdlib/Inputs/NSSlowString/NSSlowString.h
new file mode 100644
index 0000000..548939c
--- /dev/null
+++ b/test/stdlib/Inputs/NSSlowString/NSSlowString.h
@@ -0,0 +1,10 @@
+#import <Foundation/NSString.h>
+
+// An NSString whose _fastCharacterContents always returns nil
+@interface NSSlowString : NSString
+
+@property (nonatomic, strong) id myProperty;
+
+- (void *) _fastCharacterContents;
+
+@end
diff --git a/test/stdlib/Inputs/NSSlowString/NSSlowString.m b/test/stdlib/Inputs/NSSlowString/NSSlowString.m
new file mode 100644
index 0000000..5f38447
--- /dev/null
+++ b/test/stdlib/Inputs/NSSlowString/NSSlowString.m
@@ -0,0 +1,37 @@
+#import "NSSlowString.h"
+
+
+@interface NSSlowString ()
+
+@property (nonatomic, strong) NSString *stringHolder;
+
+@end
+
+@implementation NSSlowString
+
+- (instancetype)initWithString:(NSString *)name {
+ self = [super init];
+ if (self == nil) {
+ return nil;
+ }
+ self.stringHolder = name;
+ return self;
+}
+
+- (NSUInteger)length {
+ return self.stringHolder.length;
+}
+
+- (id)copy {
+ return self;
+}
+
+- (unichar)characterAtIndex:(NSUInteger)index {
+ return [self.stringHolder characterAtIndex:index];
+}
+
+- (void *) _fastCharacterContents {
+ return nil;
+}
+
+@end
\ No newline at end of file
diff --git a/test/stdlib/Inputs/NSSlowString/module.map b/test/stdlib/Inputs/NSSlowString/module.map
new file mode 100644
index 0000000..60ce0d3
--- /dev/null
+++ b/test/stdlib/Inputs/NSSlowString/module.map
@@ -0,0 +1,3 @@
+module NSSlowString {
+ header "NSSlowString.h"
+}
diff --git a/test/stdlib/NSSlowString.swift b/test/stdlib/NSSlowString.swift
new file mode 100644
index 0000000..5c649bd
--- /dev/null
+++ b/test/stdlib/NSSlowString.swift
@@ -0,0 +1,79 @@
+// RUN: mkdir -p %t
+// RUN: %target-clang -fobjc-arc %S/Inputs/NSSlowString/NSSlowString.m -c -o %t/NSSlowString.o
+// RUN: %target-build-swift -I %S/Inputs/NSSlowString/ %t/NSSlowString.o %s -o %t/a.out
+// RUN: %target-run %t/a.out
+
+// REQUIRES: executable_test
+// REQUIRES: objc_interop
+
+import Foundation
+import NSSlowString
+import Swift
+
+import StdlibUnittest
+
+let tests = TestSuite("NonContiguousStrings")
+
+// Perform expected test checks
+func checkSingleForm<S: StringProtocol>(
+ _ s: S, expectedCount: Int, expectedCodeUnitCount: Int?
+) {
+ expectEqual(expectedCount, Int(s.count))
+ if let cuCount = expectedCodeUnitCount {
+ expectEqual(cuCount, Int(s.utf16.count))
+ }
+
+ // Now check various reversed properties
+ let reversedCharacters = Array<Character>(s.reversed())
+
+ expectEqual(Int(s.count), reversedCharacters.count)
+ expectEqualSequence(s.reversed(), reversedCharacters)
+ expectEqual(String(s), String(reversedCharacters.reversed()))
+}
+func check(
+ _ s: String, expectedCount count: Int, expectedCodeUnitCount cuCount: Int
+) {
+ checkSingleForm(s, expectedCount: count, expectedCodeUnitCount: cuCount)
+
+ // Substring tests
+ checkSingleForm(s[...], expectedCount: count, expectedCodeUnitCount: cuCount)
+ checkSingleForm(s.dropFirst(), expectedCount: count-1, expectedCodeUnitCount: nil)
+ checkSingleForm(s.dropLast(), expectedCount: count-1, expectedCodeUnitCount: nil)
+ checkSingleForm(s.dropLast().dropFirst(), expectedCount: count-2, expectedCodeUnitCount: nil)
+}
+
+tests.test("Unicode 9 grapheme breaking") {
+
+ // Test string lengths that correspond to smaller than our fixed size code
+ // unit buffer, larger than it, and exactly it.
+ let strSmall = NSSlowString(string: "aππ©π©π§π¦")
+ let strBig = NSSlowString(string: "abcdefgππ©π©π§π¦")
+ let strJustRight = NSSlowString(string: "abcππ©π©π§π¦")
+ check(strSmall as String, expectedCount: 3, expectedCodeUnitCount: 14)
+ check(strBig as String, expectedCount: 9, expectedCodeUnitCount: 20)
+ check(strJustRight as String, expectedCount: 5, expectedCodeUnitCount: 16)
+}
+
+tests.test("Zalgo") {
+ // Check that we handle absurdly long graphemes
+ var zalgo = "aπ©π©π§π¦c"
+ for combo in 0x300...0x36f {
+ zalgo.append(String(UnicodeScalar(combo)!))
+ }
+ check(
+ NSSlowString(string: zalgo) as String,
+ expectedCount: 3,
+ expectedCodeUnitCount: 125
+ )
+
+ // Check for interspersed zalgo and emoji
+ var megaZalgo = zalgo + zalgo + zalgo + zalgo
+ check(
+ NSSlowString(string: megaZalgo) as String,
+ expectedCount: megaZalgo.count,
+ expectedCodeUnitCount: megaZalgo.utf16.count
+ )
+}
+
+runAllTests()
+
diff --git a/test/stdlib/NewString.swift b/test/stdlib/NewString.swift
index ec4c586..da620a5 100644
--- a/test/stdlib/NewString.swift
+++ b/test/stdlib/NewString.swift
@@ -129,6 +129,8 @@
var nsASCII = NSString(utf8String: "foobar")!
// CHECK-NEXT: has UTF-16: false
print("has UTF-16: \(CFStringGetCharactersPtr(unsafeBitCast(nsASCII, to: CFString.self)) != nil)")
+ print("has ASCII pointer: \(CFStringGetCStringPtr(unsafeBitCast(nsASCII, to: CFString.self), 0x0600) != nil)")
+ print("has ASCII pointer: \(CFStringGetCStringPtr(unsafeBitCast(nsASCII, to: CFString.self), 0x08000100) != nil)")
// CHECK: --- ASCII basic round-tripping ---
print("--- ASCII basic round-tripping ---")
diff --git a/validation-test/stdlib/Lazy.swift.gyb b/validation-test/stdlib/Lazy.swift.gyb
index 1c8f6bd..b91833b 100644
--- a/validation-test/stdlib/Lazy.swift.gyb
+++ b/validation-test/stdlib/Lazy.swift.gyb
@@ -12,7 +12,6 @@
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test
-// REQUIRES: radar_31897334
import StdlibUnittest
import StdlibCollectionUnittest
@@ -276,7 +275,10 @@
.forEach(in: [-1 ..< -1, -1..<0, -1..<1, 0..<1, 1..<1] as [Range<Int>]) {
r in
var c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
${operation}
}
@@ -296,7 +298,10 @@
]) {
(i, offset) in
let c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
_ = c.index(i, offsetBy: offset)
}
@@ -313,7 +318,10 @@
]) {
(i, offset, limit) in
let c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
_ = c.index(i, offsetBy: offset, limitedBy: limit)
}
@@ -340,7 +348,10 @@
]) {
(start, end) in
let c = EmptyCollection<OpaqueValue<Int>>()
- expectCrashLater()
+ // Access is guarded by a _debugPrecondition in EmptyCollection
+ if _isDebugAssertConfiguration() {
+ expectCrashLater()
+ }
_ = c.distance(from: start, to: end)
}