Merge pull request #18712 from xedin/fix-asan-failure-in-cs
[ConstraintSystem] Don't try to eagerly deallocate fixes
diff --git a/.flake8 b/.flake8
index 1657767..d3728e2 100644
--- a/.flake8
+++ b/.flake8
@@ -23,6 +23,7 @@
./utils/recursive-lipo,
./utils/round-trip-syntax-test,
./utils/rth,
+ ./utils/run-remote,
./utils/run-test,
./utils/scale-test,
./utils/submit-benchmark-results,
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
index 1309040..5adc020 100644
--- a/CODE_OWNERS.TXT
+++ b/CODE_OWNERS.TXT
@@ -20,7 +20,7 @@
N: Erik Eckstein
E: eeckstein@apple.com
G: eeckstein
-D: SILOptimizer
+D: SILOptimizer, Swift Benchmark Suite
N: Xi Ge
E: xi_ge@apple.com
@@ -42,11 +42,6 @@
G: akyrtzi
D: IDE, Index, SourceKit, swift-ide-test
-N: Luke Larson
-E: llarson@apple.com
-G: lplarson
-D: Swift Benchmark Suite
-
N: John McCall
E: rjmccall@apple.com
G: rjmccall
diff --git a/README.md b/README.md
index 133c3b5..cb893db 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@
|**[Ubuntu 16.04 ](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/ppc64le_ubuntu_16_04.json)** | PPC64LE |[![Build Status](https://ci-external.swift.org/job/oss-swift-4.1-RA-linux-ubuntu-16.04-ppc64le/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-4.1-RA-linux-ubuntu-16.04-ppc64le)|
|**[Ubuntu 16.04 ](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/aarch64_ubuntu_16.04.json)** | AArch64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-aarch64/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-aarch64)|
|**[Ubuntu 16.04 (Android)](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_ubuntu_16_04_LTS_android.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-android/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-linux-ubuntu-16.04-android)|
+|**[macOS 10.13 (TensorFlow)](https://github.com/apple/swift-community-hosted-continuous-integration/blob/master/nodes/x86_64_macos_high_sierra_tensorflow.json)** | x86_64 |[![Build Status](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow/lastCompletedBuild/badge/icon)](https://ci-external.swift.org/job/oss-swift-RA-macOS-tensorflow)|
**Welcome to Swift!**
diff --git a/benchmark/scripts/bench_code_size.py b/benchmark/scripts/bench_code_size.py
index 42e987d..0ed8a16 100755
--- a/benchmark/scripts/bench_code_size.py
+++ b/benchmark/scripts/bench_code_size.py
@@ -30,13 +30,17 @@
argparser = argparse.ArgumentParser()
argparser.add_argument(
'-O', action='append_const', const='O', dest='opt_levels',
- help='test -O benchmarks')
+ help='report code size of -O benchmarks')
argparser.add_argument(
'-Osize', action='append_const', const='Osize', dest='opt_levels',
- help='test -Osize benchmarks')
+ help='report code size of -Osize benchmarks')
argparser.add_argument(
'-Onone', action='append_const', const='Onone', dest='opt_levels',
- help='test -Onone benchmarks')
+ help='report code size of -Onone benchmarks')
+ argparser.add_argument(
+ '-swiftlibs', action='append_const', const='swiftlibs',
+ dest='opt_levels',
+ help='report code size of swift dylibs')
argparser.add_argument(
'oldbuilddir', nargs=1, type=str,
help='old benchmark build directory')
@@ -62,10 +66,13 @@
old_logf = open(log_filename(old_dir), 'w')
new_logf = open(log_filename(new_dir), 'w')
- files = glob.glob(os.path.join(old_dir, opt_level + '-*' + platform + '*',
- '*.o'))
- files += glob.glob(os.path.join(old_dir, 'lib', 'swift', platform,
- '*.dylib'))
+ if opt_level == 'swiftlibs':
+ files = glob.glob(os.path.join(old_dir, 'lib', 'swift', platform,
+ '*.dylib'))
+ else:
+ files = glob.glob(os.path.join(old_dir,
+ opt_level + '-*' + platform + '*',
+ '*.o'))
idx = 1
for oldfile in files:
diff --git a/benchmark/scripts/compare_perf_tests.py b/benchmark/scripts/compare_perf_tests.py
index 4243dee..2865df5 100755
--- a/benchmark/scripts/compare_perf_tests.py
+++ b/benchmark/scripts/compare_perf_tests.py
@@ -220,11 +220,13 @@
`values()` into report table. Supported formats are: `markdown` (used for
displaying benchmark results on GitHub), `git` and `html`.
"""
- def __init__(self, comparator, old_branch, new_branch, changes_only):
+ def __init__(self, comparator, old_branch, new_branch, changes_only,
+ single_table=False):
self.comparator = comparator
self.old_branch = old_branch
self.new_branch = new_branch
self.changes_only = changes_only
+ self.single_table = single_table
MARKDOWN_DETAIL = """
<details {3}>
@@ -266,6 +268,7 @@
def _formatted_text(self, ROW, HEADER_SEPARATOR, DETAIL):
widths = self._column_widths()
+ self.header_printed = False
def justify_columns(contents):
return tuple([c.ljust(w) for w, c in zip(widths, contents)])
@@ -285,12 +288,24 @@
row(format_columns(result_comparison.values(), is_strong))
for result_comparison in results
]
- return ('' if not rows else
- DETAIL.format(*[
- title, len(results),
- (header(results[0].header) + ''.join(rows)),
- ('open' if is_open else '')
- ]))
+ if not rows:
+ return ''
+
+ if self.single_table:
+ t = ''
+ if not self.header_printed:
+ t += header(results[0].header)
+ self.header_printed = True
+ t += row(('**' + title + '**', '', '', '', ''))
+ t += ''.join(rows)
+ return t
+
+ return DETAIL.format(
+ *[
+ title, len(results),
+ (header(results[0].header) + ''.join(rows)),
+ ('open' if is_open else '')
+ ])
return ''.join([
# FIXME print self.old_branch, self.new_branch
@@ -393,6 +408,10 @@
parser.add_argument('--output', help='Output file name')
parser.add_argument('--changes-only',
help='Output only affected tests', action='store_true')
+ parser.add_argument(
+ '--single-table',
+ help='Combine data in a single table in git and markdown formats',
+ action='store_true')
parser.add_argument('--new-branch',
help='Name of the new branch', default='NEW_MIN')
parser.add_argument('--old-branch',
@@ -408,7 +427,7 @@
comparator = TestComparator(args.old_file, args.new_file,
args.delta_threshold)
formatter = ReportFormatter(comparator, args.old_branch, args.new_branch,
- args.changes_only)
+ args.changes_only, args.single_table)
formats = {
'markdown': formatter.markdown,
'git': formatter.git,
diff --git a/docs/SIL.rst b/docs/SIL.rst
index 8fed6d4..347e697 100644
--- a/docs/SIL.rst
+++ b/docs/SIL.rst
@@ -4714,7 +4714,9 @@
````````````````
::
- sil-instruction ::= 'convert_function' sil-operand 'to' sil-type
+ sil-instruction ::= 'convert_function' sil-operand 'to'
+ ('[' 'without_actually_escaping' ']')?
+ sil-type
%1 = convert_function %0 : $T -> U to $T' -> U'
// %0 must be of a function type $T -> U ABI-compatible with $T' -> U'
@@ -4744,6 +4746,18 @@
convert from an escaping to a ``@noescape`` thick function type use
``convert_escape_to_noescape``.
+With the ``without_actually_escaping`` attribute, the
+``convert_function`` may be used to convert a non-escaping closure
+into an escaping function type. This attribute must be present
+whenever the closure operand has an unboxed capture (via
+@inout_aliasable) *and* the resulting function type is escaping. (This
+only happens as a result of withoutActuallyEscaping()). If the
+attribute is present then the resulting function type must be
+escaping, but the operand's function type may or may not be
+@noescape. Note that a non-escaping closure may have unboxed captured
+even though its SIL function type is "escaping".
+
+
convert_escape_to_noescape
```````````````````````````
::
diff --git a/docs/Testing.md b/docs/Testing.md
index 4ee3dfd..7e8c7da 100644
--- a/docs/Testing.md
+++ b/docs/Testing.md
@@ -80,7 +80,7 @@
useful features, like timing tests and providing a timeout. Check these features
out with ``lit.py -h``. We document some of the more useful ones below:
-##### Extra lit.py invocation options
+##### Standard lit.py invocation options
* ``-s`` reduces the amount of output that lit shows.
* ``-v`` causes a test's commandline and output to be printed if the test fails.
@@ -100,6 +100,9 @@
running a single test (in seconds). 0 (the default means no time limit.
* ``--max-failures=<MAXFAILURES>`` stops execution after ``MAXFAILURES`` number
of failures.
+
+##### Swift-specific testing options
+
* ``--param gmalloc`` will run all tests under Guard Malloc (macOS only). See
``man libgmalloc`` for more information.
* ``--param swift-version=<MAJOR>`` overrides the default Swift language
@@ -111,6 +114,22 @@
mentioned above. Again, it's best to get the invocation from the existing
build system targets and modify it rather than constructing it yourself.
+##### Remote testing options
+
+* ``--param remote_run_host=[USER@]<HOST>[:PORT]`` causes execution tests that
+ would normally be run on the host (via the ``%target-run`` substitutions
+ described below) to be run over SSH on another machine instead, using the
+ `remote-run` tool in the `utils` directory. Requires that `remote_run_tmpdir`
+ also be provided.
+* ``--param remote_run_tmpdir=<PATH>`` specifies the scratch directory to be
+ used on the remote machine when testing with `remote_run_host`.
+* ``--param remote_run_identity=<FILE>`` provides an SSH private key to be used
+ when testing with `remote_run_host`. (`remote-run` does not support
+ passwords.)
+* ``--param remote_run_skip_upload_stdlib`` assumes that the standard library
+ binaries have already been uploaded to `remote_run_tmpdir` and are up to date.
+ This is meant for repeat runs and probably shouldn't be used in automation.
+
#### CMake
Although it is not recommended for day-to-day contributions, it is also
diff --git a/include/swift/AST/GenericSignature.h b/include/swift/AST/GenericSignature.h
index 3009fdc..47b4198 100644
--- a/include/swift/AST/GenericSignature.h
+++ b/include/swift/AST/GenericSignature.h
@@ -72,13 +72,15 @@
typedef std::pair<Type, ProtocolDecl *> Entry;
private:
- llvm::SmallVector<Entry, 2> path;
+ ArrayRef<Entry> path;
+
+ ConformanceAccessPath(ArrayRef<Entry> path) : path(path) {}
friend class GenericSignature;
public:
- typedef llvm::SmallVector<Entry, 2>::const_iterator iterator;
- typedef llvm::SmallVector<Entry, 2>::const_iterator const_iterator;
+ typedef const Entry *const_iterator;
+ typedef const_iterator iterator;
const_iterator begin() const { return path.begin(); }
const_iterator end() const { return path.end(); }
@@ -133,6 +135,13 @@
/// Retrieve the generic signature builder for the given generic signature.
GenericSignatureBuilder *getGenericSignatureBuilder();
+ void buildConformanceAccessPath(
+ SmallVectorImpl<ConformanceAccessPath::Entry> &path,
+ ArrayRef<Requirement> reqs,
+ const void /*GenericSignatureBuilder::RequirementSource*/ *source,
+ ProtocolDecl *conformingProto, Type rootType,
+ ProtocolDecl *requirementSignatureProto);
+
friend class ArchetypeType;
public:
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index dced5ea..160d1d5 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -22,6 +22,7 @@
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticEngine.h"
+#include "swift/AST/GenericSignature.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/ProtocolConformanceRef.h"
#include "swift/AST/Types.h"
@@ -45,7 +46,6 @@
class DeclContext;
class DependentMemberType;
class GenericParamList;
-class GenericSignature;
class GenericSignatureBuilder;
class GenericTypeParamType;
class LazyResolver;
@@ -278,6 +278,10 @@
/// Cached nested-type information, which contains the best declaration
/// for a given name.
llvm::SmallDenseMap<Identifier, CachedNestedType> nestedTypeNameCache;
+
+ /// Cached access paths.
+ llvm::SmallDenseMap<const ProtocolDecl *, ConformanceAccessPath, 8>
+ conformanceAccessPathCache;
};
friend class RequirementSource;
diff --git a/include/swift/Basic/OwnedString.h b/include/swift/Basic/OwnedString.h
index e7bb761c..ef2b0be 100644
--- a/include/swift/Basic/OwnedString.h
+++ b/include/swift/Basic/OwnedString.h
@@ -22,117 +22,89 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/TrailingObjects.h"
using llvm::StringRef;
namespace swift {
-enum class StringOwnership {
- /// An OwnedString holds a weak reference to the underlying string storage
- /// and will never attempt to free it.
- Unowned,
-
- /// An OwnedString has its own copy of the underlying string storage and
- /// will free the storage upon its destruction.
- Copied,
-};
-
/// Holds a string - either statically allocated or dynamically allocated
/// and owned by this type.
class OwnedString {
- const char *Data;
- size_t Length;
- StringOwnership Ownership = StringOwnership::Unowned;
-
- void release() {
- if (Ownership == StringOwnership::Copied)
- free(const_cast<char *>(Data));
- }
-
- void initialize(const char* Data, size_t Length, StringOwnership Ownership) {
- this->Length = Length;
- this->Ownership = Ownership;
- if (Ownership == StringOwnership::Copied && Data) {
- char *substring = static_cast<char *>(malloc(Length + 1));
- assert(substring && "expected successful malloc of copy");
-
- memcpy(substring, Data, Length);
- substring[Length] = '\0';
-
- this->Data = substring;
+ /// An owner that keeps the buffer of a ref counted \c OwnedString alive.
+ class TextOwner final : public llvm::ThreadSafeRefCountedBase<TextOwner>,
+ public llvm::TrailingObjects<TextOwner, char> {
+ TextOwner(StringRef Text) {
+ std::uninitialized_copy(Text.begin(), Text.end(),
+ getTrailingObjects<char>());
}
- else
- this->Data = Data;
- }
- OwnedString(const char* Data, size_t Length, StringOwnership Ownership) {
- initialize(Data, Length, Ownership);
- }
+
+ public:
+ static TextOwner *make(StringRef Text) {
+ auto size = totalSizeToAlloc<char>(Text.size());
+ void *data = ::operator new(size);
+ return new (data) TextOwner(Text);
+ }
+
+ const char *getText() const { return getTrailingObjects<char>(); }
+ };
+
+ /// The text this owned string represents
+ StringRef Text;
+
+ /// In case of a ref counted string an owner that keeps the buffer \c Text
+ /// references alive.
+ llvm::IntrusiveRefCntPtr<TextOwner> OwnedPtr;
+
+ OwnedString(StringRef Text, llvm::IntrusiveRefCntPtr<TextOwner> OwnedPtr)
+ : Text(Text), OwnedPtr(OwnedPtr) {}
+
public:
- OwnedString(): OwnedString(nullptr, 0, StringOwnership::Unowned) {}
+ OwnedString() : OwnedString(/*Text=*/StringRef(), /*OwnedPtr=*/nullptr) {}
- OwnedString(const char *Data, size_t Length):
- OwnedString(Data, Length, StringOwnership::Copied) {}
+ /// Create a ref counted \c OwnedString that is initialized with the text of
+ /// the given \c StringRef.
+ OwnedString(StringRef Str) : OwnedString(makeRefCounted(Str)) {}
- OwnedString(StringRef Str) : OwnedString(Str.data(), Str.size()) {}
+ /// Create a ref counted \c OwnedString that is initialized with the text of
+ /// the given buffer.
+ OwnedString(const char *Str) : OwnedString(StringRef(Str)) {}
- OwnedString(const char *Data) : OwnedString(StringRef(Data)) {}
-
- OwnedString(const OwnedString &Other):
- OwnedString(Other.Data, Other.Length, Other.Ownership) {}
-
- OwnedString(OwnedString &&Other): Data(Other.Data), Length(Other.Length),
- Ownership(Other.Ownership) {
- Other.Data = nullptr;
- Other.Ownership = StringOwnership::Unowned;
+ /// Create an \c OwnedString that references the given string. The
+ /// \c OwnedString will not take ownership of that buffer and will assume that
+ /// the buffer outlives its lifetime.
+ static OwnedString makeUnowned(StringRef Str) {
+ return OwnedString(Str, /*OwnedPtr=*/nullptr);
}
- OwnedString& operator=(const OwnedString &Other) {
- if (&Other != this) {
- release();
- initialize(Other.Data, Other.Length, Other.Ownership);
+ /// Create an \c OwnedString that keeps its contents in a reference counted
+ /// buffer. The contents of \p Str will be copied initially and are allowed to
+ /// be disposed after the \c OwnedString has been created.
+ static OwnedString makeRefCounted(StringRef Str) {
+ if (Str.empty()) {
+ // Copying an empty string doesn't make sense. Just create an unowned
+ // string that points to the empty string.
+ return makeUnowned(Str);
+ } else {
+ llvm::IntrusiveRefCntPtr<TextOwner> OwnedPtr(TextOwner::make(Str));
+ return OwnedString(StringRef(OwnedPtr->getText(), Str.size()),
+ std::move(OwnedPtr));
}
- return *this;
- }
-
- OwnedString& operator=(OwnedString &&Other) {
- if (&Other != this) {
- release();
- this->Data = Other.Data;
- this->Length = Other.Length;
- this->Ownership = Other.Ownership;
- Other.Ownership = StringOwnership::Unowned;
- Other.Data = nullptr;
- }
- return *this;
- }
-
- OwnedString copy() const {
- return OwnedString(Data, Length, StringOwnership::Copied);
}
/// Returns the length of the string in bytes.
- size_t size() const {
- return Length;
- }
+ size_t size() const { return Text.size(); }
/// Returns true if the length is 0.
- bool empty() const {
- return Length == 0;
- }
+ bool empty() const { return size() == 0; }
/// Returns a StringRef to the underlying data. No copy is made and no
/// ownership changes take place.
- StringRef str() const {
- return StringRef { Data, Length };
- }
+ StringRef str() const { return Text; }
bool operator==(const OwnedString &Right) const {
return str() == Right.str();
}
-
- ~OwnedString() {
- release();
- }
};
} // end namespace swift
diff --git a/include/swift/SIL/InstructionUtils.h b/include/swift/SIL/InstructionUtils.h
index 5d8891d9..9d15354 100644
--- a/include/swift/SIL/InstructionUtils.h
+++ b/include/swift/SIL/InstructionUtils.h
@@ -86,6 +86,9 @@
/// copies the value of its first operand, possibly changing its type or
/// ownership state, but otherwise having no effect.
///
+/// The returned instruction may have additional "incidental" operands;
+/// mark_dependence for example.
+///
/// This is useful for checking all users of a value to verify that the value is
/// only used in recognizable patterns without otherwise "escaping". These are
/// instructions that the use-visitor can recurse into. Note that the value's
diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h
index 568bc9d..901d95b 100644
--- a/include/swift/SIL/SILBuilder.h
+++ b/include/swift/SIL/SILBuilder.h
@@ -886,9 +886,11 @@
}
ConvertFunctionInst *createConvertFunction(SILLocation Loc, SILValue Op,
- SILType Ty) {
- return insert(ConvertFunctionInst::create(
- getSILDebugLocation(Loc), Op, Ty, getFunction(), C.OpenedArchetypes));
+ SILType Ty,
+ bool WithoutActuallyEscaping) {
+ return insert(ConvertFunctionInst::create(getSILDebugLocation(Loc), Op, Ty,
+ getFunction(), C.OpenedArchetypes,
+ WithoutActuallyEscaping));
}
ConvertEscapeToNoEscapeInst *
diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h
index f12e147..f67aee9 100644
--- a/include/swift/SIL/SILCloner.h
+++ b/include/swift/SIL/SILCloner.h
@@ -1020,10 +1020,10 @@
void
SILCloner<ImplClass>::visitConvertFunctionInst(ConvertFunctionInst *Inst) {
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
- doPostProcess(Inst,
- getBuilder().createConvertFunction(getOpLocation(Inst->getLoc()),
- getOpValue(Inst->getOperand()),
- getOpType(Inst->getType())));
+ doPostProcess(
+ Inst, getBuilder().createConvertFunction(
+ getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()),
+ getOpType(Inst->getType()), Inst->withoutActuallyEscaping()));
}
template <typename ImplClass>
diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h
index a6b46e4..fa30426 100644
--- a/include/swift/SIL/SILFunction.h
+++ b/include/swift/SIL/SILFunction.h
@@ -231,6 +231,14 @@
/// serialization.
bool WasDeserializedCanonical = false;
+ /// True if this is a reabstraction thunk of escaping function type whose
+ /// single argument is a potentially non-escaping closure. This is an escape
+ /// hatch to allow non-escaping functions to be stored or passed as an
+ /// argument with escaping function type. The thunk argument's function type
+ /// is not necessarily @noescape. The only relevant aspect of the argument is
+ /// that it may have unboxed capture (i.e. @inout_aliasable parameters).
+ bool IsWithoutActuallyEscapingThunk = false;
+
static void
validateSubclassScope(SubclassScope scope, IsThunk_t isThunk,
const GenericSpecializationInformation *genericInfo) {
@@ -385,6 +393,18 @@
WasDeserializedCanonical = val;
}
+ /// Returns true if this is a reabstraction thunk of escaping function type
+ /// whose single argument is a potentially non-escaping closure. i.e. the
+ /// thunks' function argument may itself have @inout_aliasable parameters.
+ bool isWithoutActuallyEscapingThunk() const {
+ return IsWithoutActuallyEscapingThunk;
+ }
+
+ void setWithoutActuallyEscapingThunk(bool val = true) {
+ assert(!val || isThunk() == IsReabstractionThunk);
+ IsWithoutActuallyEscapingThunk = val;
+ }
+
/// Returns the calling convention used by this entry point.
SILFunctionTypeRepresentation getRepresentation() const {
return getLoweredFunctionType()->getRepresentation();
diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h
index 4965463..d5cc78b 100644
--- a/include/swift/SIL/SILInstruction.h
+++ b/include/swift/SIL/SILInstruction.h
@@ -3957,9 +3957,12 @@
friend SILBuilder;
ConvertFunctionInst(SILDebugLocation DebugLoc, SILValue Operand,
- ArrayRef<SILValue> TypeDependentOperands, SILType Ty)
+ ArrayRef<SILValue> TypeDependentOperands, SILType Ty,
+ bool WithoutActuallyEscaping)
: UnaryInstructionWithTypeDependentOperandsBase(
DebugLoc, Operand, TypeDependentOperands, Ty) {
+ SILInstruction::Bits.ConvertFunctionInst.WithoutActuallyEscaping =
+ WithoutActuallyEscaping;
assert((Operand->getType().castTo<SILFunctionType>()->isNoEscape() ==
Ty.castTo<SILFunctionType>()->isNoEscape() ||
Ty.castTo<SILFunctionType>()->getRepresentation() !=
@@ -3967,9 +3970,24 @@
"Change of escapeness is not ABI compatible");
}
- static ConvertFunctionInst *
- create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty,
- SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);
+ static ConvertFunctionInst *create(SILDebugLocation DebugLoc,
+ SILValue Operand, SILType Ty,
+ SILFunction &F,
+ SILOpenedArchetypesState &OpenedArchetypes,
+ bool WithoutActuallyEscaping);
+
+public:
+ /// Returns `true` if this converts a non-escaping closure into an escaping
+ /// function type. `True` must be returned whenever the closure operand has an
+ /// unboxed capture (via @inout_aliasable) *and* the resulting function type
+ /// is escaping. (This only happens as a result of
+ /// withoutActuallyEscaping()). If `true` is returned, then the resulting
+ /// function type must be escaping, but the operand's function type may or may
+ /// not be @noescape. Note that a non-escaping closure may have unboxed
+ /// captured even though its SIL function type is "escaping".
+ bool withoutActuallyEscaping() const {
+ return SILInstruction::Bits.ConvertFunctionInst.WithoutActuallyEscaping;
+ }
};
/// ConvertEscapeToNoEscapeInst - Change the type of a escaping function value
diff --git a/include/swift/SIL/SILNode.h b/include/swift/SIL/SILNode.h
index b483cf0..feaa596 100644
--- a/include/swift/SIL/SILNode.h
+++ b/include/swift/SIL/SILNode.h
@@ -315,7 +315,8 @@
IsInvariant : 1
);
- UIWTDOB_BITFIELD_EMPTY(ConvertFunctionInst, ConversionInst);
+ UIWTDOB_BITFIELD(ConvertFunctionInst, ConversionInst, 1,
+ WithoutActuallyEscaping : 1);
UIWTDOB_BITFIELD_EMPTY(PointerToThinFunctionInst, ConversionInst);
UIWTDOB_BITFIELD_EMPTY(UnconditionalCheckedCastInst, ConversionInst);
UIWTDOB_BITFIELD_EMPTY(UpcastInst, ConversionInst);
diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h
index 162f7ba..de4741d 100644
--- a/include/swift/Serialization/ModuleFormat.h
+++ b/include/swift/Serialization/ModuleFormat.h
@@ -55,7 +55,7 @@
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
-const uint16_t VERSION_MINOR = 435; // Last change: serialize new-style function parameters
+const uint16_t VERSION_MINOR = 436; // Last change: without_actually_escaping.
using DeclIDField = BCFixed<31>;
diff --git a/include/swift/Syntax/RawSyntax.h b/include/swift/Syntax/RawSyntax.h
index 6ff2d92..b6e2c19 100644
--- a/include/swift/Syntax/RawSyntax.h
+++ b/include/swift/Syntax/RawSyntax.h
@@ -404,12 +404,17 @@
return static_cast<tok>(Bits.Token.TokenKind);
}
- /// Return the text of the token.
- StringRef getTokenText() const {
+ /// Return the text of the token as an \c OwnedString. Keeping a reference to
+ /// this string will keep it alive even if the syntax node gets freed.
+ OwnedString getOwnedTokenText() const {
assert(isToken());
- return getTrailingObjects<OwnedString>()->str();
+ return *getTrailingObjects<OwnedString>();
}
+ /// Return the text of the token as a reference. The referenced buffer may
+ /// disappear when the syntax node gets freed.
+ StringRef getTokenText() const { return getOwnedTokenText().str(); }
+
/// Return the leading trivia list of the token.
ArrayRef<TriviaPiece> getLeadingTrivia() const {
assert(isToken());
@@ -434,7 +439,7 @@
/// trivia instead.
RC<RawSyntax>
withLeadingTrivia(ArrayRef<TriviaPiece> NewLeadingTrivia) const {
- return make(getTokenKind(), getTokenText(), NewLeadingTrivia,
+ return make(getTokenKind(), getOwnedTokenText(), NewLeadingTrivia,
getTrailingTrivia(), getPresence());
}
@@ -446,7 +451,7 @@
/// trivia instead.
RC<RawSyntax>
withTrailingTrivia(ArrayRef<TriviaPiece> NewTrailingTrivia) const {
- return make(getTokenKind(), getTokenText(), getLeadingTrivia(),
+ return make(getTokenKind(), getOwnedTokenText(), getLeadingTrivia(),
NewTrailingTrivia, getPresence());
}
diff --git a/include/swift/Syntax/Serialization/SyntaxDeserialization.h b/include/swift/Syntax/Serialization/SyntaxDeserialization.h
index 166517e..4db404d 100644
--- a/include/swift/Syntax/Serialization/SyntaxDeserialization.h
+++ b/include/swift/Syntax/Serialization/SyntaxDeserialization.h
@@ -162,9 +162,9 @@
StringRef nodeIdString;
in.mapRequired("id", nodeIdString);
unsigned nodeId = std::atoi(nodeIdString.data());
- value =
- swift::RawSyntax::make(tokenKind, text, leadingTrivia, trailingTrivia,
- presence, /*Arena=*/nullptr, nodeId);
+ value = swift::RawSyntax::make(
+ tokenKind, swift::OwnedString::makeRefCounted(text), leadingTrivia,
+ trailingTrivia, presence, /*Arena=*/nullptr, nodeId);
} else {
swift::SyntaxKind kind;
in.mapRequired("kind", kind);
diff --git a/include/swift/Syntax/Trivia.h.gyb b/include/swift/Syntax/Trivia.h.gyb
index fd5348f..28fae87 100644
--- a/include/swift/Syntax/Trivia.h.gyb
+++ b/include/swift/Syntax/Trivia.h.gyb
@@ -496,7 +496,8 @@
% else:
StringRef text;
in.mapRequired("value", text);
- return swift::syntax::TriviaPiece(kind, text);
+ return swift::syntax::TriviaPiece(
+ kind, swift::OwnedString::makeRefCounted(text));
% end
break;
}
diff --git a/lib/AST/GenericSignature.cpp b/lib/AST/GenericSignature.cpp
index 53e7699..884ef0c 100644
--- a/lib/AST/GenericSignature.cpp
+++ b/lib/AST/GenericSignature.cpp
@@ -817,9 +817,147 @@
return bestSource;
}
-ConformanceAccessPath GenericSignature::getConformanceAccessPath(
- Type type,
- ProtocolDecl *protocol) {
+void GenericSignature::buildConformanceAccessPath(
+ SmallVectorImpl<ConformanceAccessPath::Entry> &path,
+ ArrayRef<Requirement> reqs, const void *opaqueSource,
+ ProtocolDecl *conformingProto, Type rootType,
+ ProtocolDecl *requirementSignatureProto) {
+ auto *source = reinterpret_cast<const RequirementSource *>(opaqueSource);
+ // Each protocol requirement is a step along the path.
+ if (source->isProtocolRequirement()) {
+ // If we're expanding for a protocol that had no requirement signature
+ // and have hit the penultimate step, this is the last step
+ // that would occur in the requirement signature.
+ Optional<GenericSignatureBuilder> replacementBuilder;
+ if (!source->parent->parent && requirementSignatureProto) {
+ // If we have a requirement signature now, we're done.
+ if (source->usesRequirementSignature) {
+ Type subjectType = source->getStoredType()->getCanonicalType();
+ path.push_back({subjectType, conformingProto});
+ return;
+ }
+
+ // The generic signature builder we're using for this protocol
+ // wasn't built from its own requirement signature, so we can't
+ // trust it. Make sure we have a requirement signature, then build
+ // a new generic signature builder.
+ // FIXME: It would be better if we could replace the canonical generic
+ // signature builder with the rebuilt one.
+ if (!requirementSignatureProto->isRequirementSignatureComputed())
+ requirementSignatureProto->computeRequirementSignature();
+ assert(requirementSignatureProto->isRequirementSignatureComputed());
+
+ replacementBuilder.emplace(getASTContext());
+ replacementBuilder->addGenericSignature(
+ requirementSignatureProto->getGenericSignature());
+ replacementBuilder->processDelayedRequirements();
+ }
+
+ // Follow the rest of the path to derive the conformance into which
+ // this particular protocol requirement step would look.
+ auto inProtocol = source->getProtocolDecl();
+ buildConformanceAccessPath(path, reqs, source->parent, inProtocol, rootType,
+ requirementSignatureProto);
+ assert(path.back().second == inProtocol &&
+ "path produces incorrect conformance");
+
+ // If this step was computed via the requirement signature, add it
+ // directly.
+ if (source->usesRequirementSignature) {
+ // Add this step along the path, which involves looking for the
+ // conformance we want (\c conformingProto) within the protocol
+ // described by this source.
+
+ // Canonicalize the subject type within the protocol's generic
+ // signature.
+ Type subjectType = source->getStoredType();
+ subjectType = inProtocol->getGenericSignature()
+ ->getCanonicalTypeInContext(subjectType);
+
+ assert(hasConformanceInSignature(inProtocol->getRequirementSignature(),
+ subjectType, conformingProto) &&
+ "missing explicit conformance in requirement signature");
+
+ // Record this step.
+ path.push_back({subjectType, conformingProto});
+ return;
+ }
+
+ // Get the generic signature builder for the protocol.
+ // Get a generic signature for the protocol's signature.
+ auto inProtoSig = inProtocol->getGenericSignature();
+ auto &inProtoSigBuilder =
+ replacementBuilder ? *replacementBuilder
+ : *inProtoSig->getGenericSignatureBuilder();
+
+ // Retrieve the stored type, but erase all of the specific associated
+ // type declarations; we don't want any details of the enclosing context
+ // to sneak in here.
+ Type storedType = eraseAssociatedTypes(source->getStoredType());
+
+ // Dig out the potential archetype for this stored type.
+ auto equivClass =
+ inProtoSigBuilder.resolveEquivalenceClass(
+ storedType,
+ ArchetypeResolutionKind::CompleteWellFormed);
+
+ // Find the conformance of this potential archetype to the protocol in
+ // question.
+ auto conforms = equivClass->conformsTo.find(conformingProto);
+ assert(conforms != equivClass->conformsTo.end());
+
+ // Compute the root type, canonicalizing it w.r.t. the protocol context.
+ auto conformsSource = getBestRequirementSource(conforms->second);
+ assert(conformsSource != source || !requirementSignatureProto);
+ Type localRootType = conformsSource->getRootType();
+ localRootType = inProtoSig->getCanonicalTypeInContext(localRootType);
+
+ // Build the path according to the requirement signature.
+ buildConformanceAccessPath(path, inProtocol->getRequirementSignature(),
+ conformsSource, conformingProto, localRootType,
+ inProtocol);
+
+ // We're done.
+ return;
+ }
+
+ // If we have a superclass or concrete requirement, the conformance
+ // we need is stored in it.
+ if (source->kind == RequirementSource::Superclass ||
+ source->kind == RequirementSource::Concrete) {
+ auto conformance = source->getProtocolConformance();
+ (void)conformance;
+ assert(conformance.getRequirement() == conformingProto);
+ path.push_back({source->getAffectedType(), conformingProto});
+ return;
+ }
+
+ // If we still have a parent, keep going.
+ if (source->parent) {
+ buildConformanceAccessPath(path, reqs, source->parent, conformingProto,
+ rootType, requirementSignatureProto);
+ return;
+ }
+
+ // We are at an explicit or inferred requirement.
+ assert(source->kind == RequirementSource::Explicit ||
+ source->kind == RequirementSource::Inferred);
+
+ // Skip trivial path elements. These occur when querying a requirement
+ // signature.
+ if (!path.empty() && conformingProto == path.back().second &&
+ rootType->isEqual(conformingProto->getSelfInterfaceType()))
+ return;
+
+ assert(hasConformanceInSignature(reqs, rootType, conformingProto) &&
+ "missing explicit conformance in signature");
+
+ // Add the root of the path, which starts at this explicit requirement.
+ path.push_back({rootType, conformingProto});
+}
+
+ConformanceAccessPath
+GenericSignature::getConformanceAccessPath(Type type, ProtocolDecl *protocol) {
assert(type->isTypeParameter() && "not a type parameter");
// Resolve this type to a potential archetype.
@@ -829,163 +967,28 @@
type,
ArchetypeResolutionKind::CompleteWellFormed);
+ auto cached = equivClass->conformanceAccessPathCache.find(protocol);
+ if (cached != equivClass->conformanceAccessPathCache.end())
+ return cached->second;
+
// Dig out the conformance of this type to the given protocol, because we
// want its requirement source.
auto conforms = equivClass->conformsTo.find(protocol);
assert(conforms != equivClass->conformsTo.end());
- // Follow the requirement source to form the conformance access path.
- typedef GenericSignatureBuilder::RequirementSource RequirementSource;
- ConformanceAccessPath path;
-
- // Local function to construct the conformance access path from the
- // requirement.
- std::function<void(ArrayRef<Requirement>, const RequirementSource *,
- ProtocolDecl *, Type, ProtocolDecl *)> buildPath;
- buildPath = [&](ArrayRef<Requirement> reqs, const RequirementSource *source,
- ProtocolDecl *conformingProto, Type rootType,
- ProtocolDecl *requirementSignatureProto) {
- // Each protocol requirement is a step along the path.
- if (source->isProtocolRequirement()) {
- // If we're expanding for a protocol that had no requirement signature
- // and have hit the penultimate step, this is the last step
- // that would occur in the requirement signature.
- Optional<GenericSignatureBuilder> replacementBuilder;
- if (!source->parent->parent && requirementSignatureProto) {
- // If we have a requirement signature now, we're done.
- if (source->usesRequirementSignature) {
- Type subjectType = source->getStoredType()->getCanonicalType();
- path.path.push_back({subjectType, conformingProto});
- return;
- }
-
- // The generic signature builder we're using for this protocol
- // wasn't built from its own requirement signature, so we can't
- // trust it. Make sure we have a requirement signature, then build
- // a new generic signature builder.
- // FIXME: It would be better if we could replace the canonical generic
- // signature builder with the rebuilt one.
- if (!requirementSignatureProto->isRequirementSignatureComputed())
- requirementSignatureProto->computeRequirementSignature();
- assert(requirementSignatureProto->isRequirementSignatureComputed());
-
- replacementBuilder.emplace(getASTContext());
- replacementBuilder->addGenericSignature(
- requirementSignatureProto->getGenericSignature());
- replacementBuilder->processDelayedRequirements();
- }
-
- // Follow the rest of the path to derive the conformance into which
- // this particular protocol requirement step would look.
- auto inProtocol = source->getProtocolDecl();
- buildPath(reqs, source->parent, inProtocol, rootType,
- requirementSignatureProto);
- assert(path.path.back().second == inProtocol &&
- "path produces incorrect conformance");
-
- // If this step was computed via the requirement signature, add it
- // directly.
- if (source->usesRequirementSignature) {
- // Add this step along the path, which involves looking for the
- // conformance we want (\c conformingProto) within the protocol
- // described by this source.
-
- // Canonicalize the subject type within the protocol's generic
- // signature.
- Type subjectType = source->getStoredType();
- subjectType = inProtocol->getGenericSignature()
- ->getCanonicalTypeInContext(subjectType);
-
- assert(hasConformanceInSignature(inProtocol->getRequirementSignature(),
- subjectType, conformingProto) &&
- "missing explicit conformance in requirement signature");
-
- // Record this step.
- path.path.push_back({subjectType, conformingProto});
- return;
- }
-
- // Get the generic signature builder for the protocol.
- // Get a generic signature for the protocol's signature.
- auto inProtoSig = inProtocol->getGenericSignature();
- auto &inProtoSigBuilder =
- replacementBuilder ? *replacementBuilder
- : *inProtoSig->getGenericSignatureBuilder();
-
- // Retrieve the stored type, but erase all of the specific associated
- // type declarations; we don't want any details of the enclosing context
- // to sneak in here.
- Type storedType = eraseAssociatedTypes(source->getStoredType());
-
- // Dig out the potential archetype for this stored type.
- auto equivClass =
- inProtoSigBuilder.resolveEquivalenceClass(
- storedType,
- ArchetypeResolutionKind::CompleteWellFormed);
-
- // Find the conformance of this potential archetype to the protocol in
- // question.
- auto conforms = equivClass->conformsTo.find(conformingProto);
- assert(conforms != equivClass->conformsTo.end());
-
- // Compute the root type, canonicalizing it w.r.t. the protocol context.
- auto conformsSource = getBestRequirementSource(conforms->second);
- assert(conformsSource != source || !requirementSignatureProto);
- Type localRootType = conformsSource->getRootType();
- localRootType = inProtoSig->getCanonicalTypeInContext(localRootType);
-
- // Build the path according to the requirement signature.
- buildPath(inProtocol->getRequirementSignature(), conformsSource,
- conformingProto, localRootType, inProtocol);
-
- // We're done.
- return;
- }
-
- // If we have a superclass or concrete requirement, the conformance
- // we need is stored in it.
- if (source->kind == RequirementSource::Superclass ||
- source->kind == RequirementSource::Concrete) {
- auto conformance = source->getProtocolConformance();
- (void)conformance;
- assert(conformance.getRequirement() == conformingProto);
- path.path.push_back({source->getAffectedType(), conformingProto});
- return;
- }
-
- // If we still have a parent, keep going.
- if (source->parent) {
- buildPath(reqs, source->parent, conformingProto, rootType,
- requirementSignatureProto);
- return;
- }
-
- // We are at an explicit or inferred requirement.
- assert(source->kind == RequirementSource::Explicit ||
- source->kind == RequirementSource::Inferred);
-
- // Skip trivial path elements. These occur when querying a requirement
- // signature.
- if (!path.path.empty() && conformingProto == path.path.back().second &&
- rootType->isEqual(conformingProto->getSelfInterfaceType()))
- return;
-
- assert(hasConformanceInSignature(reqs, rootType, conformingProto) &&
- "missing explicit conformance in signature");
-
- // Add the root of the path, which starts at this explicit requirement.
- path.path.push_back({rootType, conformingProto});
- };
-
// Canonicalize the root type.
auto source = getBestRequirementSource(conforms->second);
Type rootType = source->getRootType()->getCanonicalType(this);
// Build the path.
- buildPath(getRequirements(), source, protocol, rootType, nullptr);
+ SmallVector<ConformanceAccessPath::Entry, 2> path;
+ buildConformanceAccessPath(path, getRequirements(), source, protocol,
+ rootType, nullptr);
// Return the path; we're done!
- return path;
+ ConformanceAccessPath result(getASTContext().AllocateCopy(path));
+ equivClass->conformanceAccessPathCache.insert({protocol, result});
+ return result;
}
unsigned GenericParamKey::findIndexIn(
diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp
index c9a78be..e3c7b0d 100644
--- a/lib/IRGen/GenValueWitness.cpp
+++ b/lib/IRGen/GenValueWitness.cpp
@@ -983,18 +983,28 @@
if (auto nom = type->getAnyNominal()) {
// TODO: Generic metadata patterns relative-reference their VWT, which won't
- // work if it's in a different module without supporting indirection through
- // the GOT.
+ // work if the VWT is in a different module without supporting indirection
+ // through the GOT.
if (nom->isGenericContext())
return nullptr;
- // TODO: Enums need additional value witnesses for their tag manipulation.
- if (isa<EnumDecl>(nom))
- return nullptr;
+ // TODO: Non-C enums have extra inhabitants and also need additional value
+ // witnesses for their tag manipulation (except when they're empty, in
+ // which case values never exist to witness).
+ if (auto enumDecl = dyn_cast<EnumDecl>(nom))
+ if (!enumDecl->isObjC() && !type->isUninhabited())
+ return nullptr;
}
-
+
+ auto &C = IGM.Context;
+
type = getFormalTypeInContext(type);
auto &ti = IGM.getTypeInfoForUnlowered(AbstractionPattern::getOpaque(), type);
+
+ // Empty types can use empty tuple witnesses.
+ if (ti.isKnownEmpty(ResilienceExpansion::Maximal))
+ return IGM.getAddrOfValueWitnessTable(TupleType::getEmpty(C));
+
// We only have witnesses for fixed type info.
auto *fixedTI = dyn_cast<FixedTypeInfo>(&ti);
if (!fixedTI)
@@ -1003,7 +1013,6 @@
CanType witnessSurrogate;
// Handle common POD type layouts.
- auto &C = type->getASTContext();
ReferenceCounting refCounting;
if (fixedTI->isPOD(ResilienceExpansion::Maximal)
&& fixedTI->getFixedExtraInhabitantCount(IGM) == 0) {
diff --git a/lib/IRGen/LoadableByAddress.cpp b/lib/IRGen/LoadableByAddress.cpp
index 963dc00..e4e80c9 100644
--- a/lib/IRGen/LoadableByAddress.cpp
+++ b/lib/IRGen/LoadableByAddress.cpp
@@ -2609,7 +2609,8 @@
case SILInstructionKind::ConvertFunctionInst: {
auto instr = cast<ConvertFunctionInst>(convInstr);
newInstr = convBuilder.createConvertFunction(
- instr->getLoc(), instr->getOperand(), newType);
+ instr->getLoc(), instr->getOperand(), newType,
+ instr->withoutActuallyEscaping());
break;
}
case SILInstructionKind::ConvertEscapeToNoEscapeInst: {
diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp
index 82e0341..b43573f 100644
--- a/lib/Parse/Lexer.cpp
+++ b/lib/Parse/Lexer.cpp
@@ -2182,7 +2182,8 @@
size_t BOMLen = ContentStart - BufferStart;
assert(BOMLen == 3 && "UTF-8 BOM is 3 bytes");
// Add UTF-8 BOM to LeadingTrivia.
- LeadingTrivia.push_back(TriviaPiece::garbageText({CurPtr, BOMLen}));
+ auto Text = OwnedString::makeRefCounted(StringRef(CurPtr, BOMLen));
+ LeadingTrivia.push_back(TriviaPiece::garbageText(Text));
CurPtr += BOMLen;
}
NextToken.setAtStartOfLine(true);
@@ -2407,18 +2408,18 @@
bool isDocComment = CurPtr[1] == '/';
skipSlashSlashComment(/*EatNewline=*/false);
size_t Length = CurPtr - TriviaStart;
- Pieces.push_back(isDocComment
- ? TriviaPiece::docLineComment({TriviaStart, Length})
- : TriviaPiece::lineComment({TriviaStart, Length}));
+ auto Text = OwnedString::makeRefCounted(StringRef(TriviaStart, Length));
+ Pieces.push_back(isDocComment ? TriviaPiece::docLineComment(Text)
+ : TriviaPiece::lineComment(Text));
goto Restart;
} else if (*CurPtr == '*') {
// '/* ... */' comment.
bool isDocComment = CurPtr[1] == '*';
skipSlashStarComment();
size_t Length = CurPtr - TriviaStart;
- Pieces.push_back(isDocComment
- ? TriviaPiece::docBlockComment({TriviaStart, Length})
- : TriviaPiece::blockComment({TriviaStart, Length}));
+ auto Text = OwnedString::makeRefCounted(StringRef(TriviaStart, Length));
+ Pieces.push_back(isDocComment ? TriviaPiece::docBlockComment(Text)
+ : TriviaPiece::blockComment(Text));
goto Restart;
}
break;
@@ -2430,7 +2431,8 @@
diagnose(TriviaStart, diag::lex_hashbang_not_allowed);
skipHashbang(/*EatNewline=*/false);
size_t Length = CurPtr - TriviaStart;
- Pieces.push_back(TriviaPiece::garbageText({TriviaStart, Length}));
+ auto Text = OwnedString::makeRefCounted(StringRef(TriviaStart, Length));
+ Pieces.push_back(TriviaPiece::garbageText(Text));
goto Restart;
}
break;
@@ -2439,7 +2441,8 @@
if (tryLexConflictMarker(/*EatNewline=*/false)) {
// Conflict marker.
size_t Length = CurPtr - TriviaStart;
- Pieces.push_back(TriviaPiece::garbageText({TriviaStart, Length}));
+ auto Text = OwnedString::makeRefCounted(StringRef(TriviaStart, Length));
+ Pieces.push_back(TriviaPiece::garbageText(Text));
goto Restart;
}
break;
@@ -2448,7 +2451,8 @@
case NulCharacterKind::Embedded: {
diagnoseEmbeddedNul(Diags, CurPtr - 1);
size_t Length = CurPtr - TriviaStart;
- Pieces.push_back(TriviaPiece::garbageText({TriviaStart, Length}));
+ auto Text = OwnedString::makeRefCounted(StringRef(TriviaStart, Length));
+ Pieces.push_back(TriviaPiece::garbageText(Text));
goto Restart;
}
case NulCharacterKind::CodeCompletion:
@@ -2494,7 +2498,8 @@
}
size_t Length = CurPtr - TriviaStart;
- Pieces.push_back(TriviaPiece::garbageText({TriviaStart, Length}));
+ auto Text = OwnedString::makeRefCounted(StringRef(TriviaStart, Length));
+ Pieces.push_back(TriviaPiece::garbageText(Text));
goto Restart;
}
// Reset the cursor.
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index dfdd6e0..65b762de 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -312,15 +312,15 @@
syntax::AbsolutePosition RunningPos;
tokenize(
- LangOpts, SM, BufferID, Offset, EndOffset,
- Diags,
+ LangOpts, SM, BufferID, Offset, EndOffset, Diags,
CommentRetentionMode::AttachToNextToken, TriviaRetentionMode::WithTrivia,
/*TokenizeInterpolatedString=*/false,
/*SplitTokens=*/ArrayRef<Token>(),
[&](const Token &Tok, const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia) {
+ auto Text = OwnedString::makeRefCounted(Tok.getText());
auto ThisToken =
- RawSyntax::make(Tok.getKind(), Tok.getText(), LeadingTrivia.Pieces,
+ RawSyntax::make(Tok.getKind(), Text, LeadingTrivia.Pieces,
TrailingTrivia.Pieces, SourcePresence::Present);
auto ThisTokenPos = ThisToken->accumulateAbsolutePosition(RunningPos);
@@ -1016,6 +1016,13 @@
Opts.CollectParsedToken,
Opts.BuildSyntaxTree)) {
}
+
+ ~Implementation() {
+ // We need to delete the parser before the context so that it can finalize
+ // its SourceFileSyntax while it is still alive
+ TheParser.reset();
+ delete &Ctx;
+ }
};
ParserUnit::ParserUnit(SourceManager &SM, unsigned BufferID)
diff --git a/lib/Parse/SyntaxParsingContext.cpp b/lib/Parse/SyntaxParsingContext.cpp
index 8a5214e..34c8c5b 100644
--- a/lib/Parse/SyntaxParsingContext.cpp
+++ b/lib/Parse/SyntaxParsingContext.cpp
@@ -163,9 +163,9 @@
return;
auto &Arena = getArena();
- addRawSyntax(RawSyntax::getToken(Arena, Tok.getKind(), Tok.getText(),
- LeadingTrivia.Pieces,
- TrailingTrivia.Pieces));
+ auto Text = OwnedString::makeRefCounted(Tok.getText());
+ addRawSyntax(RawSyntax::getToken(
+ Arena, Tok.getKind(), Text, LeadingTrivia.Pieces, TrailingTrivia.Pieces));
}
/// Add Syntax to the parts.
@@ -313,7 +313,7 @@
}
if (!EOFToken)
- EOFToken = RawSyntax::missing(tok::eof, "");
+ EOFToken = RawSyntax::missing(tok::eof, OwnedString::makeUnowned(""));
auto newRaw = SyntaxFactory::createRaw(
SyntaxKind::SourceFile,
@@ -352,7 +352,8 @@
return;
if (Text.empty())
Text = getTokenText(Kind);
- getStorage().push_back(RawSyntax::missing(Kind, Text));
+ auto OwnedText = OwnedString::makeRefCounted(Text);
+ getStorage().push_back(RawSyntax::missing(Kind, OwnedText));
}
void SyntaxParsingContext::synthesize(SyntaxKind Kind) {
diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp
index 5167087..81745a9 100644
--- a/lib/ParseSIL/ParseSIL.cpp
+++ b/lib/ParseSIL/ParseSIL.cpp
@@ -886,6 +886,7 @@
Inline_t *inlineStrategy,
OptimizationMode *optimizationMode,
bool *isLet, bool *isWeakLinked,
+ bool *isWithoutActuallyEscapingThunk,
SmallVectorImpl<std::string> *Semantics,
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs,
ValueDecl **ClangDecl,
@@ -914,6 +915,9 @@
*isThunk = IsSignatureOptimizedThunk;
else if (isThunk && SP.P.Tok.getText() == "reabstraction_thunk")
*isThunk = IsReabstractionThunk;
+ else if (isWithoutActuallyEscapingThunk
+ && SP.P.Tok.getText() == "without_actually_escaping")
+ *isWithoutActuallyEscapingThunk = true;
else if (isGlobalInit && SP.P.Tok.getText() == "global_init")
*isGlobalInit = true;
else if (isWeakLinked && SP.P.Tok.getText() == "_weakLinked")
@@ -2976,6 +2980,7 @@
SourceLoc ToLoc;
bool not_guaranteed = false;
bool escaped = false;
+ bool without_actually_escaping = false;
if (Opcode == SILInstructionKind::ConvertEscapeToNoEscapeInst) {
StringRef attrName;
if (parseSILOptional(attrName, *this)) {
@@ -2989,17 +2994,26 @@
if (parseSILOptional(escaped, *this, "escaped"))
return true;
}
- if (parseTypedValueRef(Val, B) ||
- parseSILIdentifier(ToToken, ToLoc,
- diag::expected_tok_in_sil_instr, "to") ||
- parseSILType(Ty) ||
- parseSILDebugLocation(InstLoc, B))
+ if (parseTypedValueRef(Val, B)
+ || parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
+ "to"))
return true;
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
+ if (Opcode == SILInstructionKind::ConvertFunctionInst) {
+ StringRef attrName;
+ if (parseSILOptional(attrName, *this)) {
+ if (attrName.equals("without_actually_escaping"))
+ without_actually_escaping = true;
+ else
+ return true;
+ }
+ }
+ if (parseSILType(Ty) || parseSILDebugLocation(InstLoc, B))
+ return true;
switch (Opcode) {
default: llvm_unreachable("Out of sync with parent switch");
@@ -3019,7 +3033,8 @@
ResultVal = B.createUpcast(InstLoc, Val, Ty);
break;
case SILInstructionKind::ConvertFunctionInst:
- ResultVal = B.createConvertFunction(InstLoc, Val, Ty);
+ ResultVal =
+ B.createConvertFunction(InstLoc, Val, Ty, without_actually_escaping);
break;
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
ResultVal = B.createConvertEscapeToNoEscape(InstLoc, Val, Ty, escaped,
@@ -5186,6 +5201,7 @@
bool isCanonical = false;
IsThunk_t isThunk = IsNotThunk;
bool isGlobalInit = false, isWeakLinked = false;
+ bool isWithoutActuallyEscapingThunk = false;
Inline_t inlineStrategy = InlineDefault;
OptimizationMode optimizationMode = OptimizationMode::NotSet;
SmallVector<std::string, 1> Semantics;
@@ -5196,7 +5212,8 @@
parseDeclSILOptional(&isTransparent, &isSerialized, &isCanonical,
&isThunk, &isGlobalInit,
&inlineStrategy, &optimizationMode, nullptr,
- &isWeakLinked, &Semantics, &SpecAttrs,
+ &isWeakLinked, &isWithoutActuallyEscapingThunk,
+ &Semantics, &SpecAttrs,
&ClangDecl, &MRK, FunctionState) ||
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
P.parseIdentifier(FnName, FnNameLoc, diag::expected_sil_function_name) ||
@@ -5224,6 +5241,8 @@
FunctionState.F->setThunk(IsThunk_t(isThunk));
FunctionState.F->setGlobalInit(isGlobalInit);
FunctionState.F->setWeakLinked(isWeakLinked);
+ FunctionState.F->setWithoutActuallyEscapingThunk(
+ isWithoutActuallyEscapingThunk);
FunctionState.F->setInlineStrategy(inlineStrategy);
FunctionState.F->setOptimizationMode(optimizationMode);
FunctionState.F->setEffectsKind(MRK);
@@ -5403,7 +5422,7 @@
if (parseSILLinkage(GlobalLinkage, P) ||
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, &isLet, nullptr, nullptr, nullptr,
- nullptr, nullptr, State) ||
+ nullptr, nullptr, nullptr, State) ||
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
P.parseIdentifier(GlobalName, NameLoc, diag::expected_sil_value_name) ||
P.parseToken(tok::colon, diag::expected_sil_type))
@@ -5451,7 +5470,7 @@
IsSerialized_t Serialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, SP))
+ nullptr, nullptr, nullptr, SP))
return true;
ValueDecl *VD;
@@ -5519,7 +5538,7 @@
IsSerialized_t Serialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, VTableState))
+ nullptr, nullptr, nullptr, VTableState))
return true;
// Parse the class name.
@@ -5869,7 +5888,7 @@
IsSerialized_t isSerialized = IsNotSerialized;
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, WitnessState))
+ nullptr, nullptr, nullptr, WitnessState))
return true;
Scope S(&P, ScopeKind::TopLevel);
diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp
index 988670a..760d59a 100644
--- a/lib/SIL/SILInstructions.cpp
+++ b/lib/SIL/SILInstructions.cpp
@@ -1971,10 +1971,9 @@
TypeDependentOperands, Ty);
}
-ConvertFunctionInst *
-ConvertFunctionInst::create(SILDebugLocation DebugLoc, SILValue Operand,
- SILType Ty, SILFunction &F,
- SILOpenedArchetypesState &OpenedArchetypes) {
+ConvertFunctionInst *ConvertFunctionInst::create(
+ SILDebugLocation DebugLoc, SILValue Operand, SILType Ty, SILFunction &F,
+ SILOpenedArchetypesState &OpenedArchetypes, bool WithoutActuallyEscaping) {
SILModule &Mod = F.getModule();
SmallVector<SILValue, 8> TypeDependentOperands;
collectTypeDependentOperands(TypeDependentOperands, OpenedArchetypes, F,
@@ -1982,8 +1981,8 @@
unsigned size =
totalSizeToAlloc<swift::Operand>(1 + TypeDependentOperands.size());
void *Buffer = Mod.allocateInst(size, alignof(ConvertFunctionInst));
- auto *CFI = ::new (Buffer)
- ConvertFunctionInst(DebugLoc, Operand, TypeDependentOperands, Ty);
+ auto *CFI = ::new (Buffer) ConvertFunctionInst(
+ DebugLoc, Operand, TypeDependentOperands, Ty, WithoutActuallyEscaping);
// If we do not have lowered SIL, make sure that are not performing
// ABI-incompatible conversions.
//
diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp
index a6a973d..b87ca29 100644
--- a/lib/SIL/SILPrinter.cpp
+++ b/lib/SIL/SILPrinter.cpp
@@ -1424,7 +1424,10 @@
}
void visitConvertFunctionInst(ConvertFunctionInst *CI) {
- printUncheckedConversionInst(CI, CI->getOperand());
+ *this << getIDAndType(CI->getOperand()) << " to ";
+ if (CI->withoutActuallyEscaping())
+ *this << "[without_actually_escaping] ";
+ *this << CI->getType();
}
void visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *CI) {
*this << (CI->isLifetimeGuaranteed() ? "" : "[not_guaranteed] ")
@@ -2299,6 +2302,8 @@
break;
case IsReabstractionThunk: OS << "[reabstraction_thunk] "; break;
}
+ if (isWithoutActuallyEscapingThunk())
+ OS << "[without_actually_escaping] ";
if (isGlobalInit())
OS << "[global_init] ";
diff --git a/lib/SILGen/SILGenBuilder.cpp b/lib/SILGen/SILGenBuilder.cpp
index 294cb17..35f3ff7 100644
--- a/lib/SILGen/SILGenBuilder.cpp
+++ b/lib/SILGen/SILGenBuilder.cpp
@@ -207,12 +207,13 @@
return getSILGenFunction().emitManagedRValueWithCleanup(result);
}
-ManagedValue SILGenBuilder::createConvertFunction(SILLocation loc,
- ManagedValue fn,
- SILType resultTy) {
+ManagedValue
+SILGenBuilder::createConvertFunction(SILLocation loc, ManagedValue fn,
+ SILType resultTy,
+ bool withoutActuallyEscaping) {
CleanupCloner cloner(*this, fn);
- SILValue result =
- createConvertFunction(loc, fn.forward(getSILGenFunction()), resultTy);
+ SILValue result = SILBuilder::createConvertFunction(
+ loc, fn.forward(getSILGenFunction()), resultTy, withoutActuallyEscaping);
return cloner.clone(result);
}
diff --git a/lib/SILGen/SILGenBuilder.h b/lib/SILGen/SILGenBuilder.h
index b62e64d..5530833 100644
--- a/lib/SILGen/SILGenBuilder.h
+++ b/lib/SILGen/SILGenBuilder.h
@@ -365,7 +365,8 @@
using SILBuilder::createConvertFunction;
ManagedValue createConvertFunction(SILLocation loc, ManagedValue fn,
- SILType resultTy);
+ SILType resultTy,
+ bool WithoutActuallyEscaping = false);
using SILBuilder::createConvertEscapeToNoEscape;
ManagedValue
diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp
index d8507e1..f125508 100644
--- a/lib/SILGen/SILGenExpr.cpp
+++ b/lib/SILGen/SILGenExpr.cpp
@@ -1703,9 +1703,8 @@
assert(result.getType() == loweredResultTy);
if (loweredResultTy != loweredDestTy) {
- result = ManagedValue::forUnmanaged(
- SGF.B.createConvertFunction(e, result.getUnmanagedValue(),
- loweredDestTy));
+ assert(!result.hasCleanup());
+ result = SGF.B.createConvertFunction(e, result, loweredDestTy);
}
break;
@@ -1958,9 +1957,9 @@
CanAnyFunctionType destTy
= cast<AnyFunctionType>(e->getType()->getCanonicalType());
SILType resultType = SGF.getLoweredType(destTy);
- SILValue result = SGF.B.createConvertFunction(e,
- original.forward(SGF),
- resultType);
+ SILValue result =
+ SGF.B.createConvertFunction(e, original.forward(SGF), resultType,
+ /*Withoutactuallyescaping=*/false);
return RValue(SGF, e, SGF.emitManagedRValueWithCleanup(result));
}
@@ -5279,7 +5278,8 @@
if (silFnTy->getExtInfo().getRepresentation() !=
SILFunctionTypeRepresentation::Thick) {
auto escapingClosure =
- SGF.B.createConvertFunction(E, functionValue, escapingFnTy);
+ SGF.B.createConvertFunction(E, functionValue, escapingFnTy,
+ /*WithoutActuallyEscaping=*/true);
return visitSubExpr(escapingClosure, true /*isClosureConsumable*/);
}
diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp
index e885b2e..48ae9fc 100644
--- a/lib/SILGen/SILGenPoly.cpp
+++ b/lib/SILGen/SILGenPoly.cpp
@@ -3017,10 +3017,12 @@
thunkType, noEscapingFnTy, escapingFnTy, F.isSerialized());
if (thunk->empty()) {
+ thunk->setWithoutActuallyEscapingThunk();
thunk->setGenericEnvironment(genericEnv);
SILGenFunction thunkSGF(SGM, *thunk, FunctionDC);
buildWithoutActuallyEscapingThunkBody(thunkSGF);
}
+ assert(thunk->isWithoutActuallyEscapingThunk());
CanSILFunctionType substFnTy = thunkType;
// Use the subsitution map in the context of the current function.
diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
index 54bd1d2..bce8321 100644
--- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
+++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp
@@ -670,7 +670,8 @@
calleeValue = cloneCalleeConversion(CFI->getOperand(), NewClosure, Builder,
NeedsRelease);
return Builder.createConvertFunction(CallSiteDesc.getLoc(), calleeValue,
- CFI->getType());
+ CFI->getType(),
+ CFI->withoutActuallyEscaping());
}
if (auto *PAI = dyn_cast<PartialApplyInst>(calleeValue)) {
diff --git a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
index e28a724..a27d611 100644
--- a/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
+++ b/lib/SILOptimizer/Mandatory/DiagnoseStaticExclusivity.cpp
@@ -967,12 +967,24 @@
if (isIncidentalUse(user) || onlyAffectsRefCount(user))
return;
+ // Before checking conversions in general below (getSingleValueCopyOrCast),
+ // check for convert_function to [without_actually_escaping]. Assume such
+ // conversion are not actually escaping without following their uses.
+ if (auto *CFI = dyn_cast<ConvertFunctionInst>(user)) {
+ if (CFI->withoutActuallyEscaping())
+ return;
+ }
+
// Look through copies, borrows, and conversions.
//
// Note: This handles ConversionInst, which already includes everything in
// swift::stripConvertFunctions.
if (SingleValueInstruction *copy = getSingleValueCopyOrCast(user)) {
- followUses(copy);
+ // Only follow the copied operand. Other operands are incidental,
+ // as in the second operand of mark_dependence.
+ if (oper->getOperandNumber() == 0)
+ followUses(copy);
+
return;
}
@@ -1017,6 +1029,10 @@
}
break;
+ case SILInstructionKind::IsEscapingClosureInst:
+ // May be generated by withoutActuallyEscaping.
+ return;
+
case SILInstructionKind::PartialApplyInst: {
// Recurse through partial_apply to handle special cases before handling
// ApplySites in general below.
@@ -1036,7 +1052,10 @@
// thunk as "escaping", but as long as the thunk is only used as a
// '@noescape" type then it is safe.
if (isPartialApplyOfReabstractionThunk(PAI)) {
- followUses(PAI);
+ // Don't follow thunks that were generated by withoutActuallyEscaping.
+ SILFunction *thunkDef = PAI->getReferencedFunction();
+ if (!thunkDef->isWithoutActuallyEscapingThunk())
+ followUses(PAI);
return;
}
// Handle this use like a normal applied argument.
diff --git a/lib/SILOptimizer/Utils/Local.cpp b/lib/SILOptimizer/Utils/Local.cpp
index 17fe8f3..2c2ffb4 100644
--- a/lib/SILOptimizer/Utils/Local.cpp
+++ b/lib/SILOptimizer/Utils/Local.cpp
@@ -585,7 +585,8 @@
"Swift thick functions that differ in escapeness are not ABI "
"compatible");
// Insert convert_function.
- return B->createConvertFunction(Loc, Value, DestTy);
+ return B->createConvertFunction(Loc, Value, DestTy,
+ /*WithoutActuallyEscaping=*/false);
}
}
diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp
index f3d1d93..980a6b1 100644
--- a/lib/Serialization/DeserializeSIL.cpp
+++ b/lib/Serialization/DeserializeSIL.cpp
@@ -463,15 +463,16 @@
DeclID clangNodeOwnerID;
TypeID funcTyID;
GenericEnvironmentID genericEnvID;
- unsigned rawLinkage, isTransparent, isSerialized, isThunk, isGlobal,
- inlineStrategy, optimizationMode, effect, numSpecAttrs,
- hasQualifiedOwnership, isWeakLinked;
+ unsigned rawLinkage, isTransparent, isSerialized, isThunk,
+ isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
+ optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
+ isWeakLinked;
ArrayRef<uint64_t> SemanticsIDs;
- SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isSerialized,
- isThunk, isGlobal, inlineStrategy,
- optimizationMode, effect, numSpecAttrs,
- hasQualifiedOwnership, isWeakLinked, funcTyID,
- genericEnvID, clangNodeOwnerID, SemanticsIDs);
+ SILFunctionLayout::readRecord(
+ scratch, rawLinkage, isTransparent, isSerialized, isThunk,
+ isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
+ optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
+ isWeakLinked, funcTyID, genericEnvID, clangNodeOwnerID, SemanticsIDs);
if (funcTyID == 0) {
LLVM_DEBUG(llvm::dbgs() << "SILFunction typeID is 0.\n");
@@ -556,6 +557,7 @@
fn->setTransparent(IsTransparent_t(isTransparent == 1));
fn->setSerialized(IsSerialized_t(isSerialized));
fn->setThunk(IsThunk_t(isThunk));
+ fn->setWithoutActuallyEscapingThunk(bool(isWithoutactuallyEscapingThunk));
fn->setInlineStrategy(Inline_t(inlineStrategy));
fn->setGlobalInit(isGlobal == 1);
fn->setEffectsKind(EffectsKind(effect));
@@ -1132,7 +1134,6 @@
ONEOPERAND_ONETYPE_INST(ObjCToThickMetatype)
ONEOPERAND_ONETYPE_INST(ObjCMetatypeToObject)
ONEOPERAND_ONETYPE_INST(ObjCExistentialMetatypeToObject)
- ONEOPERAND_ONETYPE_INST(ConvertFunction)
ONEOPERAND_ONETYPE_INST(ThinFunctionToPointer)
ONEOPERAND_ONETYPE_INST(PointerToThinFunction)
ONEOPERAND_ONETYPE_INST(ProjectBlockStorage)
@@ -1161,7 +1162,18 @@
isLifetimeGuaranteed);
break;
}
-
+ case SILInstructionKind::ConvertFunctionInst: {
+ assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND
+ && "Layout should be OneTypeOneOperand.");
+ bool withoutActuallyEscaping = Attr & 0x01;
+ ResultVal = Builder.createConvertFunction(
+ Loc,
+ getLocalValue(ValID, getSILType(MF->getType(TyID2),
+ (SILValueCategory)TyCategory2)),
+ getSILType(MF->getType(TyID), (SILValueCategory)TyCategory),
+ withoutActuallyEscaping);
+ break;
+ }
case SILInstructionKind::PointerToAddressInst: {
assert(RecordKind == SIL_ONE_TYPE_ONE_OPERAND &&
"Layout should be OneTypeOneOperand.");
@@ -2480,15 +2492,16 @@
DeclID clangOwnerID;
TypeID funcTyID;
GenericEnvironmentID genericEnvID;
- unsigned rawLinkage, isTransparent, isSerialized, isThunk, isGlobal,
- inlineStrategy, optimizationMode, effect, numSpecAttrs,
- hasQualifiedOwnership, isWeakLinked;
+ unsigned rawLinkage, isTransparent, isSerialized, isThunk,
+ isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
+ optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
+ isWeakLinked;
ArrayRef<uint64_t> SemanticsIDs;
- SILFunctionLayout::readRecord(scratch, rawLinkage, isTransparent, isSerialized,
- isThunk, isGlobal, inlineStrategy,
- optimizationMode, effect, numSpecAttrs,
- hasQualifiedOwnership, isWeakLinked, funcTyID,
- genericEnvID, clangOwnerID, SemanticsIDs);
+ SILFunctionLayout::readRecord(
+ scratch, rawLinkage, isTransparent, isSerialized, isThunk,
+ isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy,
+ optimizationMode, effect, numSpecAttrs, hasQualifiedOwnership,
+ isWeakLinked, funcTyID, genericEnvID, clangOwnerID, SemanticsIDs);
auto linkage = fromStableSILLinkage(rawLinkage);
if (!linkage) {
LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h
index fcec9e8..0375fca 100644
--- a/lib/Serialization/SILFormat.h
+++ b/lib/Serialization/SILFormat.h
@@ -288,6 +288,7 @@
BCFixed<1>, // transparent
BCFixed<2>, // serialized
BCFixed<2>, // thunks: signature optimized/reabstraction
+ BCFixed<1>, // without_actually_escaping
BCFixed<1>, // global_init
BCFixed<2>, // inlineStrategy
BCFixed<2>, // optimizationMode
diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp
index 9bb3055..60c48bc 100644
--- a/lib/Serialization/SerializeSIL.cpp
+++ b/lib/Serialization/SerializeSIL.cpp
@@ -242,7 +242,7 @@
void writeIndexTables();
void writeConversionLikeInstruction(const SingleValueInstruction *I,
- bool guaranteed, bool escaped);
+ unsigned attrs);
void writeOneTypeLayout(SILInstructionKind valueKind, SILType type);
void writeOneTypeOneOperandLayout(SILInstructionKind valueKind,
unsigned attrs,
@@ -399,9 +399,9 @@
SILFunctionLayout::emitRecord(
Out, ScratchRecord, abbrCode, toStableSILLinkage(Linkage),
(unsigned)F.isTransparent(), (unsigned)F.isSerialized(),
- (unsigned)F.isThunk(), (unsigned)F.isGlobalInit(),
- (unsigned)F.getInlineStrategy(), (unsigned)F.getOptimizationMode(),
- (unsigned)F.getEffectsKind(),
+ (unsigned)F.isThunk(), (unsigned)F.isWithoutActuallyEscapingThunk(),
+ (unsigned)F.isGlobalInit(), (unsigned)F.getInlineStrategy(),
+ (unsigned)F.getOptimizationMode(), (unsigned)F.getEffectsKind(),
(unsigned)numSpecAttrs, (unsigned)F.hasQualifiedOwnership(),
F.isWeakLinked(), FnID, genericEnvID, clangNodeOwnerID, SemanticsIDs);
@@ -591,11 +591,10 @@
/// Write an instruction that looks exactly like a conversion: all
/// important information is encoded in the operand and the result type.
void SILSerializer::writeConversionLikeInstruction(
- const SingleValueInstruction *I, bool guaranteed, bool escaped) {
+ const SingleValueInstruction *I, unsigned attrs) {
assert(I->getNumOperands() - I->getTypeDependentOperands().size() == 1);
- writeOneTypeOneOperandLayout(I->getKind(),
- (guaranteed ? 1 : 0) | (escaped ? 2 : 0),
- I->getType(), I->getOperand(0));
+ writeOneTypeOneOperandLayout(I->getKind(), attrs, I->getType(),
+ I->getOperand(0));
}
void
@@ -1471,14 +1470,18 @@
case SILInstructionKind::ObjCMetatypeToObjectInst:
case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
case SILInstructionKind::ProjectBlockStorageInst: {
- bool guaranteed = false;
- bool escaped = false;
+ unsigned attrs = 0;
if (SI.getKind() == SILInstructionKind::ConvertEscapeToNoEscapeInst) {
- escaped = cast<ConvertEscapeToNoEscapeInst>(SI).isEscapedByUser();
- guaranteed = cast<ConvertEscapeToNoEscapeInst>(SI).isLifetimeGuaranteed();
+ if (cast<ConvertEscapeToNoEscapeInst>(SI).isLifetimeGuaranteed())
+ attrs |= 0x01;
+ if (cast<ConvertEscapeToNoEscapeInst>(SI).isEscapedByUser())
+ attrs |= 0x02;
}
- writeConversionLikeInstruction(cast<SingleValueInstruction>(&SI),
- guaranteed, escaped);
+ if (SI.getKind() == SILInstructionKind::ConvertFunctionInst) {
+ if (cast<ConvertFunctionInst>(SI).withoutActuallyEscaping())
+ attrs |= 0x01;
+ }
+ writeConversionLikeInstruction(cast<SingleValueInstruction>(&SI), attrs);
break;
}
case SILInstructionKind::PointerToAddressInst: {
diff --git a/lib/Syntax/SyntaxArena.cpp b/lib/Syntax/SyntaxArena.cpp
index 65e5902..9efcf2f 100644
--- a/lib/Syntax/SyntaxArena.cpp
+++ b/lib/Syntax/SyntaxArena.cpp
@@ -75,16 +75,16 @@
friend llvm::FoldingSetTrait<RawSyntaxCacheNode>;
/// Associated RawSyntax.
- RawSyntax *Obj;
+ RC<RawSyntax> Obj;
/// FoldingSet node identifier of the associated RawSyntax.
llvm::FoldingSetNodeIDRef IDRef;
public:
- RawSyntaxCacheNode(RawSyntax *Obj, const llvm::FoldingSetNodeIDRef IDRef)
+ RawSyntaxCacheNode(RC<RawSyntax> Obj, const llvm::FoldingSetNodeIDRef IDRef)
: Obj(Obj), IDRef(IDRef) {}
/// Retrieve assciated RawSyntax.
- RawSyntax *get() { return Obj; }
+ RC<RawSyntax> get() { return Obj; }
// Only allow allocation of Node using the allocator in SyntaxArena.
void *operator new(size_t Bytes, SyntaxArena &Arena,
@@ -156,7 +156,7 @@
auto Raw = RawSyntax::make(TokKind, Text, LeadingTrivia, TrailingTrivia,
SourcePresence::Present, &Arena);
auto IDRef = ID.Intern(Arena.getAllocator());
- auto CacheNode = new (Arena) RawSyntaxCacheNode(Raw.get(), IDRef);
+ auto CacheNode = new (Arena) RawSyntaxCacheNode(Raw, IDRef);
CachedTokens.InsertNode(CacheNode, insertPos);
return Raw;
}
diff --git a/lib/Syntax/SyntaxFactory.cpp.gyb b/lib/Syntax/SyntaxFactory.cpp.gyb
index 9a5ce1c..74b5d26 100644
--- a/lib/Syntax/SyntaxFactory.cpp.gyb
+++ b/lib/Syntax/SyntaxFactory.cpp.gyb
@@ -233,7 +233,8 @@
SyntaxFactory::make${token.name}Keyword(const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia,
SyntaxArena *Arena) {
- return makeToken(tok::${token.kind}, "${token.text}",
+ return makeToken(tok::${token.kind},
+ OwnedString::makeUnowned("${token.text}"),
LeadingTrivia, TrailingTrivia,
SourcePresence::Present, Arena);
}
@@ -242,7 +243,8 @@
SyntaxFactory::make${token.name}Token(const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia,
SyntaxArena *Arena) {
- return makeToken(tok::${token.kind}, "${token.text}",
+ return makeToken(tok::${token.kind},
+ OwnedString::makeUnowned("${token.text}"),
LeadingTrivia, TrailingTrivia,
SourcePresence::Present, Arena);
}
@@ -303,30 +305,35 @@
TypeSyntax SyntaxFactory::makeAnyTypeIdentifier(const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia,
SyntaxArena *Arena) {
- return makeTypeIdentifier("Any", LeadingTrivia, TrailingTrivia, Arena);
+ return makeTypeIdentifier(OwnedString::makeUnowned("Any"), LeadingTrivia,
+ TrailingTrivia, Arena);
}
TypeSyntax SyntaxFactory::makeSelfTypeIdentifier(const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia,
SyntaxArena *Arena) {
- return makeTypeIdentifier("Self", LeadingTrivia, TrailingTrivia, Arena);
+ return makeTypeIdentifier(OwnedString::makeUnowned("Self"),
+ LeadingTrivia, TrailingTrivia, Arena);
}
TokenSyntax SyntaxFactory::makeTypeToken(const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia,
SyntaxArena *Arena) {
- return makeIdentifier("Type", LeadingTrivia, TrailingTrivia, Arena);
+ return makeIdentifier(OwnedString::makeUnowned("Type"),
+ LeadingTrivia, TrailingTrivia, Arena);
}
TokenSyntax SyntaxFactory::makeProtocolToken(const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia,
SyntaxArena *Arena) {
- return makeIdentifier("Protocol", LeadingTrivia, TrailingTrivia, Arena);
+ return makeIdentifier(OwnedString::makeUnowned("Protocol"),
+ LeadingTrivia, TrailingTrivia, Arena);
}
TokenSyntax SyntaxFactory::makeEqualityOperator(const Trivia &LeadingTrivia,
const Trivia &TrailingTrivia,
SyntaxArena *Arena) {
- return makeToken(tok::oper_binary_spaced, "==", LeadingTrivia, TrailingTrivia,
- SourcePresence::Present, Arena);
+ return makeToken(tok::oper_binary_spaced, OwnedString::makeUnowned("=="),
+ LeadingTrivia, TrailingTrivia, SourcePresence::Present,
+ Arena);
}
diff --git a/test/Constraints/diagnostics.swift b/test/Constraints/diagnostics.swift
index 42ae96e..f90fd8d 100644
--- a/test/Constraints/diagnostics.swift
+++ b/test/Constraints/diagnostics.swift
@@ -658,7 +658,7 @@
struct UnaryOp {}
_ = -UnaryOp() // expected-error {{unary operator '-' cannot be applied to an operand of type 'UnaryOp'}}
-// expected-note@-1 {{overloads for '-' exist with these partially matching parameter lists: (Float), (Double), (Float80)}}
+// expected-note@-1 {{overloads for '-' exist with these partially matching parameter lists: (Float), (Double)}}
// <rdar://problem/23433271> Swift compiler segfault in failure diagnosis
diff --git a/test/IRGen/empty_enum.swift b/test/IRGen/empty_enum.swift
new file mode 100644
index 0000000..8553135
--- /dev/null
+++ b/test/IRGen/empty_enum.swift
@@ -0,0 +1,6 @@
+// RUN: %target-swift-frontend -primary-file %s -emit-ir | %FileCheck %s
+
+// CHECK: @"$S10empty_enum6JamaisOMf" =
+// CHECK-SAME: @"$SytWV"
+
+enum Jamais {}
diff --git a/test/IRGen/objc_ns_enum.swift b/test/IRGen/objc_ns_enum.swift
index e9ad416..6c32906 100644
--- a/test/IRGen/objc_ns_enum.swift
+++ b/test/IRGen/objc_ns_enum.swift
@@ -8,9 +8,9 @@
import Foundation
import gizmo
-// CHECK: @"$SSo16NSRuncingOptionsVWV" = linkonce_odr hidden constant
// CHECK: @"$SSo16NSRuncingOptionsVMn" = linkonce_odr hidden constant
// CHECK: @"$SSo16NSRuncingOptionsVN" = linkonce_odr hidden constant
+// CHECK-SAME: @"$SBi{{[0-9]+}}_WV"
// CHECK: @"$SSo16NSRuncingOptionsVSQSCMc" = linkonce_odr hidden constant %swift.protocol_conformance_descriptor { {{.*}}@"$SSo16NSRuncingOptionsVSQSCWa
// CHECK: @"$SSo28NeverActuallyMentionedByNameVSQSCWp" = linkonce_odr hidden constant
diff --git a/test/SIL/Parser/without_actually_escaping.sil b/test/SIL/Parser/without_actually_escaping.sil
new file mode 100644
index 0000000..2758e05
--- /dev/null
+++ b/test/SIL/Parser/without_actually_escaping.sil
@@ -0,0 +1,32 @@
+// RUN: %target-sil-opt %s | %FileCheck %s
+
+// thunk for @escaping @callee_guaranteed () -> ()
+// Check that the [without_actually_escaping] thunk attribute is parsed and printed.
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @testWithoutActuallyEscapingThunk : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @testWithoutActuallyEscapingThunk : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
+ %1 = apply %0() : $@callee_guaranteed () -> ()
+ return %1 : $()
+}
+
+// Check that the convert_function [without_actually_escaping] attribute is parsed and printed.
+// CHECK-LABEL: sil hidden @testWithoutActuallyEscapingBlock : $@convention(thin) (@guaranteed @convention(block) @noescape () -> ()) -> () {
+// CHECK: convert_function %0 : $@convention(block) @noescape () -> () to [without_actually_escaping] $@convention(block) () -> ()
+sil hidden @testWithoutActuallyEscapingBlock : $@convention(thin) (@guaranteed @convention(block) @noescape () -> ()) -> () {
+bb0(%0 : @guaranteed $@convention(block) @noescape () -> ()):
+ %cvt = convert_function %0 : $@convention(block) @noescape () -> () to [without_actually_escaping] $@convention(block) () -> ()
+ %f = function_ref @closure1 : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
+ %call = apply %f(%cvt) : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
+ destroy_value %cvt : $@convention(block) () -> ()
+ %v = tuple ()
+ return %v : $()
+}
+
+// closure #1 in testBlock(block:)
+sil private @closure1 : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> () {
+bb0(%0 : @guaranteed $@convention(block) () -> ()):
+ %call = apply %0() : $@convention(block) () -> ()
+ %v = tuple ()
+ return %v : $()
+}
+
diff --git a/test/SIL/Serialization/without_actually_escaping.sil b/test/SIL/Serialization/without_actually_escaping.sil
new file mode 100644
index 0000000..77af896
--- /dev/null
+++ b/test/SIL/Serialization/without_actually_escaping.sil
@@ -0,0 +1,36 @@
+// First parse this and then emit a *.sib. Then read in the *.sib, then recreate
+// RUN: %empty-directory(%t)
+// RUN: %target-sil-opt %s -emit-sib -o %t/tmp.sib -module-name without_actually_escaping
+// RUN: %target-sil-opt %t/tmp.sib -o %t/tmp.2.sib -module-name without_actually_escaping
+// RUN: %target-sil-opt %t/tmp.2.sib -module-name without_actually_escaping | %FileCheck %s
+
+// thunk for @escaping @callee_guaranteed () -> ()
+// Check that the [without_actually_escaping] thunk attribute is parsed and printed.
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @f1_testWithoutActuallyEscapingThunk : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @f1_testWithoutActuallyEscapingThunk : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
+ %1 = apply %0() : $@callee_guaranteed () -> ()
+ return %1 : $()
+}
+
+// Check that the convert_function [without_actually_escaping] attribute is parsed and printed.
+// CHECK-LABEL: sil hidden @f2_testWithoutActuallyEscapingBlock : $@convention(thin) (@guaranteed @convention(block) @noescape () -> ()) -> () {
+// CHECK: convert_function %0 : $@convention(block) @noescape () -> () to [without_actually_escaping] $@convention(block) () -> ()
+sil hidden @f2_testWithoutActuallyEscapingBlock : $@convention(thin) (@guaranteed @convention(block) @noescape () -> ()) -> () {
+bb0(%0 : @guaranteed $@convention(block) @noescape () -> ()):
+ %cvt = convert_function %0 : $@convention(block) @noescape () -> () to [without_actually_escaping] $@convention(block) () -> ()
+ %f = function_ref @closure1 : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
+ %call = apply %f(%cvt) : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
+ destroy_value %cvt : $@convention(block) () -> ()
+ %v = tuple ()
+ return %v : $()
+}
+
+// closure #1 in testBlock(block:)
+sil private @closure1 : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> () {
+bb0(%0 : @guaranteed $@convention(block) () -> ()):
+ %call = apply %0() : $@convention(block) () -> ()
+ %v = tuple ()
+ return %v : $()
+}
+
diff --git a/test/SILGen/without_actually_escaping.swift b/test/SILGen/without_actually_escaping.swift
index 3e00ff0..78372c4 100644
--- a/test/SILGen/without_actually_escaping.swift
+++ b/test/SILGen/without_actually_escaping.swift
@@ -6,8 +6,9 @@
// CHECK-LABEL: sil hidden @$S25without_actually_escaping9letEscape1fyycyyXE_tF
func letEscape(f: () -> ()) -> () -> () {
// CHECK: bb0([[ARG:%.*]] : @trivial $@noescape @callee_guaranteed () -> ()):
+ // CHECK: [[THUNK:%.*]] = function_ref @$SIg_Ieg_TR : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> ()
// TODO: Use a canary wrapper instead of just copying the nonescaping value
- // CHECK: [[ESCAPABLE_COPY:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[ARG]])
+ // CHECK: [[ESCAPABLE_COPY:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[ARG]])
// CHECK: [[MD_ESCAPABLE_COPY:%.*]] = mark_dependence [[ESCAPABLE_COPY]]
// CHECK: [[BORROW_MD_ESCAPABLE_COPY:%.*]] = begin_borrow [[MD_ESCAPABLE_COPY]]
// CHECK: [[SUB_CLOSURE:%.*]] = function_ref @
@@ -17,6 +18,9 @@
return withoutActuallyEscaping(f) { return $0 }
}
+// thunk for @callee_guaranteed () -> ()
+// The thunk must be [without_actually_escaping].
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @$SIg_Ieg_TR : $@convention(thin) (@noescape @callee_guaranteed () -> ()) -> () {
// CHECK-LABEL: sil hidden @$S25without_actually_escaping14letEscapeThrow1fyycyycyKXE_tKF
// CHECK: bb0([[ARG:%.*]] : @trivial $@noescape @callee_guaranteed () -> (@owned @callee_guaranteed () -> (), @error Error)):
@@ -44,6 +48,10 @@
return try withoutActuallyEscaping(f) { return try $0() }
}
+// thunk for @callee_guaranteed () -> (@owned @escaping @callee_guaranteed () -> (), @error @owned Error)
+// The thunk must be [without_actually_escaping].
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @$SIeg_s5Error_pIgozo_Ieg_sAA_pIegozo_TR : $@convention(thin) (@noescape @callee_guaranteed () -> (@owned @callee_guaranteed () -> (), @error Error)) -> (@owned @callee_guaranteed () -> (), @error Error) {
+
// We used to crash on this example because we would use the wrong substitution
// map.
struct DontCrash {
diff --git a/test/SILGen/without_actually_escaping_block.swift b/test/SILGen/without_actually_escaping_block.swift
index 8001c52..be7c5ae 100644
--- a/test/SILGen/without_actually_escaping_block.swift
+++ b/test/SILGen/without_actually_escaping_block.swift
@@ -13,7 +13,7 @@
// CHECK: [[C1:%.*]] = copy_block [[ARG]]
// CHECK: [[B1:%.*]] = begin_borrow [[C1]]
// CHECK: [[C2:%.*]] = copy_value [[B1]]
-// CHECK: [[CVT:%.*]] = convert_function [[C2]] : $@convention(block) @noescape () -> () to $@convention(block) () -> ()
+// CHECK: [[CVT:%.*]] = convert_function [[C2]] : $@convention(block) @noescape () -> () to [without_actually_escaping] $@convention(block) () -> ()
// CHECK: [[B2:%.*]] = begin_borrow [[CVT]]
// CHECK: [[FN:%.*]] = function_ref @$S25without_actually_escaping9testBlock5blockyyyXB_tFyyyXBXEfU_
// CHECK: apply [[FN]]([[B2]])
diff --git a/test/SILOptimizer/exclusivity_static_diagnostics.sil b/test/SILOptimizer/exclusivity_static_diagnostics.sil
index d2c1b5b..7259184 100644
--- a/test/SILOptimizer/exclusivity_static_diagnostics.sil
+++ b/test/SILOptimizer/exclusivity_static_diagnostics.sil
@@ -1285,3 +1285,116 @@
%v = tuple ()
return %v : $()
}
+
+// -----------------------------------------------------------------------------
+// Test withoutActuallyEscaping thunk.
+// <rdar://problem/43059088> Assertion in DiagnoseStaticExclusivity
+// Noescape closure verification should not assert.
+
+sil @takeEscapingClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
+
+sil private @nestedInWithoutActuallyEscapingVerify : $@convention(thin) (@inout_aliasable Int) -> () {
+bb0(%0 : @trivial $*Int):
+ %a = begin_access [modify] [unknown] %0 : $*Int
+ end_access %a : $*Int
+ %v = tuple ()
+ return %v : $()
+}
+
+// CHECK-LABEL: sil hidden @testWithoutActuallyEscapingVerify : $@convention(thin) (@inout Int) -> () {
+sil hidden @testWithoutActuallyEscapingVerify : $@convention(thin) (@inout Int) -> () {
+bb0(%0 : @trivial $*Int):
+ %2 = function_ref @nestedInWithoutActuallyEscapingVerify : $@convention(thin) (@inout_aliasable Int) -> ()
+ %3 = partial_apply [callee_guaranteed] %2(%0) : $@convention(thin) (@inout_aliasable Int) -> ()
+
+ %4 = function_ref @thunkForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
+ %5 = partial_apply [callee_guaranteed] %4(%3) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
+ %6 = mark_dependence %5 : $@callee_guaranteed () -> () on %3 : $@callee_guaranteed () -> ()
+
+ %8 = function_ref @closureForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
+ %9 = apply %8(%6) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
+ %10 = is_escaping_closure %6 : $@callee_guaranteed () -> ()
+ cond_fail %10 : $Builtin.Int1
+ destroy_value %6 : $@callee_guaranteed () -> ()
+ %14 = tuple ()
+ return %14 : $()
+}
+
+// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @thunkForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+sil shared [transparent] [serializable] [reabstraction_thunk] [without_actually_escaping] @thunkForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
+ %1 = apply %0() : $@callee_guaranteed () -> ()
+ return %1 : $()
+}
+
+sil private @closureForWithoutActuallyEscapingVerify : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
+bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
+ %2 = function_ref @takeEscapingClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
+ %3 = apply %2(%0) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
+ %4 = tuple ()
+ return %4 : $()
+}
+
+// -----------------------------------------------------------------------------
+// Test withoutActuallyEscaping convert_function.
+// <rdar://problem/43059088> Assertion in DiagnoseStaticExclusivity
+// Noescape closure verification should not assert.
+
+// CHECK-LABEL: sil hidden @testWithoutActuallyEscapingBlockVerify : $@convention(thin) (Int) -> () {
+// CHECK: convert_function %{{.*}} : $@convention(block) () -> () to [without_actually_escaping] $@convention(block) () -> ()
+sil hidden @testWithoutActuallyEscapingBlockVerify : $@convention(thin) (Int) -> () {
+bb0(%0 : @trivial $Int):
+ %box = alloc_box ${ var Int }, var, name "localVal"
+ %projbox = project_box %box : ${ var Int }, 0
+ store %0 to [trivial] %projbox : $*Int
+ %closureF = function_ref @testWithoutActuallyEscapingBlockVerifyClosure : $@convention(thin) (@inout_aliasable Int) -> ()
+ %closure = partial_apply [callee_guaranteed] %closureF(%projbox) : $@convention(thin) (@inout_aliasable Int) -> ()
+ %block = alloc_stack $@block_storage @callee_guaranteed () -> ()
+ %blockproj = project_block_storage %block : $*@block_storage @callee_guaranteed () -> ()
+ store %closure to [init] %blockproj : $*@callee_guaranteed () -> ()
+ // function_ref thunk for @escaping @callee_guaranteed () -> ()
+ %thunkF = function_ref @$SIeg_IeyB_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> ()
+ %initblock = init_block_storage_header %block : $*@block_storage @callee_guaranteed () -> (), invoke %thunkF : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> (), type $@convention(block) () -> ()
+ destroy_addr %blockproj : $*@callee_guaranteed () -> ()
+ dealloc_stack %block : $*@block_storage @callee_guaranteed () -> ()
+ %borrow = begin_borrow %initblock : $@convention(block) () -> ()
+ %copy = copy_value %borrow : $@convention(block) () -> ()
+ %escapingF = convert_function %copy : $@convention(block) () -> () to [without_actually_escaping] $@convention(block) () -> ()
+ %clauseF = function_ref @testWithoutActuallyEscapingBlockVerifyClause : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
+ %call = apply %clauseF(%escapingF) : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> ()
+ destroy_value %escapingF : $@convention(block) () -> ()
+ end_borrow %borrow from %initblock : $@convention(block) () -> (), $@convention(block) () -> ()
+ destroy_value %initblock : $@convention(block) () -> ()
+ destroy_value %box : ${ var Int }
+ %v = tuple ()
+ return %v : $()
+}
+
+sil @testWithoutActuallyEscapingBlockVerifyClosure : $@convention(thin) (@inout_aliasable Int) -> ()
+
+// thunk for @escaping @callee_guaranteed () -> ()
+sil shared [transparent] [serializable] [reabstraction_thunk] @$SIeg_IeyB_TR : $@convention(c) (@inout_aliasable @block_storage @callee_guaranteed () -> ()) -> () {
+// %0
+bb0(%0 : @trivial $*@block_storage @callee_guaranteed () -> ()):
+ %1 = project_block_storage %0 : $*@block_storage @callee_guaranteed () -> ()
+ %2 = load [copy] %1 : $*@callee_guaranteed () -> ()
+ %3 = begin_borrow %2 : $@callee_guaranteed () -> ()
+ %4 = apply %3() : $@callee_guaranteed () -> ()
+ end_borrow %3 from %2 : $@callee_guaranteed () -> (), $@callee_guaranteed () -> ()
+ %6 = tuple ()
+ destroy_value %2 : $@callee_guaranteed () -> ()
+ return %6 : $()
+} // end sil function '$SIeg_IeyB_TR'
+
+sil private @testWithoutActuallyEscapingBlockVerifyClause : $@convention(thin) (@guaranteed @convention(block) () -> ()) -> () {
+bb0(%0 : @guaranteed $@convention(block) () -> ()):
+ %1 = copy_block %0 : $@convention(block) () -> ()
+ %3 = begin_borrow %1 : $@convention(block) () -> ()
+ %4 = copy_value %3 : $@convention(block) () -> ()
+ %5 = apply %4() : $@convention(block) () -> ()
+ destroy_value %4 : $@convention(block) () -> ()
+ end_borrow %3 from %1 : $@convention(block) () -> (), $@convention(block) () -> ()
+ destroy_value %1 : $@convention(block) () -> ()
+ %v = tuple ()
+ return %v : $()
+}
diff --git a/test/api-digester/Outputs/cake-abi.json b/test/api-digester/Outputs/cake-abi.json
new file mode 100644
index 0000000..3a068eb
--- /dev/null
+++ b/test/api-digester/Outputs/cake-abi.json
@@ -0,0 +1,729 @@
+{
+ "kind": "Root",
+ "name": "TopLevel",
+ "printedName": "TopLevel",
+ "children": [
+ {
+ "kind": "TypeDecl",
+ "name": "P1",
+ "printedName": "P1",
+ "declKind": "Protocol",
+ "usr": "s:4cake2P1P",
+ "location": "",
+ "moduleName": "cake"
+ },
+ {
+ "kind": "TypeDecl",
+ "name": "P2",
+ "printedName": "P2",
+ "declKind": "Protocol",
+ "usr": "s:4cake2P2P",
+ "location": "",
+ "moduleName": "cake"
+ },
+ {
+ "kind": "TypeDecl",
+ "name": "S1",
+ "printedName": "S1",
+ "declKind": "Struct",
+ "usr": "s:4cake2S1V",
+ "location": "",
+ "moduleName": "cake",
+ "conformingProtocols": [
+ "P1",
+ "P2"
+ ],
+ "declAttributes": [
+ "FixedLayout"
+ ],
+ "children": [
+ {
+ "kind": "Function",
+ "name": "foo1",
+ "printedName": "foo1()",
+ "declKind": "Func",
+ "usr": "s:4cake2S1V4foo1yyFZ",
+ "location": "",
+ "moduleName": "cake",
+ "static": true,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "foo2",
+ "printedName": "foo2()",
+ "declKind": "Func",
+ "usr": "s:4cake2S1V4foo2yyF",
+ "location": "",
+ "moduleName": "cake",
+ "mutating": true,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "foo6",
+ "printedName": "foo6()",
+ "declKind": "Func",
+ "usr": "s:4cake2S1V4foo6yyF",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ },
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init()",
+ "declKind": "Constructor",
+ "usr": "s:4cake2S1VACycfc",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "S1",
+ "printedName": "S1",
+ "usr": "s:4cake2S1V"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "TypeDecl",
+ "name": "C0",
+ "printedName": "C0",
+ "declKind": "Class",
+ "usr": "s:4cake2C0C",
+ "location": "",
+ "moduleName": "cake",
+ "genericSig": "<τ_0_0, τ_0_1, τ_0_2>",
+ "children": [
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init()",
+ "declKind": "Constructor",
+ "usr": "s:4cake2C0CACyxq_q0_Gycfc",
+ "location": "",
+ "moduleName": "cake",
+ "genericSig": "<τ_0_0, τ_0_1, τ_0_2>",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "C0",
+ "printedName": "C0<τ_0_0, τ_0_1, τ_0_2>",
+ "usr": "s:4cake2C0C",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "GenericTypeParam",
+ "printedName": "τ_0_0"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "GenericTypeParam",
+ "printedName": "τ_0_1"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "GenericTypeParam",
+ "printedName": "τ_0_2"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "conditionalFooExt",
+ "printedName": "conditionalFooExt()",
+ "declKind": "Func",
+ "usr": "s:4cake2C0CA2A2S1VRszAERs_AERs0_rlE17conditionalFooExtyyF",
+ "location": "",
+ "moduleName": "cake",
+ "genericSig": "<τ_0_0, τ_0_1, τ_0_2 where τ_0_0 == S1, τ_0_1 == S1, τ_0_2 == S1>",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "unconditionalFooExt",
+ "printedName": "unconditionalFooExt()",
+ "declKind": "Func",
+ "usr": "s:4cake2C0C19unconditionalFooExtyyF",
+ "location": "",
+ "moduleName": "cake",
+ "genericSig": "<τ_0_0, τ_0_1, τ_0_2>",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "TypeDecl",
+ "name": "C1",
+ "printedName": "C1",
+ "declKind": "Class",
+ "usr": "s:4cake2C1C",
+ "location": "",
+ "moduleName": "cake",
+ "superclassUsr": "s:4cake2C0C",
+ "children": [
+ {
+ "kind": "Function",
+ "name": "foo1",
+ "printedName": "foo1()",
+ "declKind": "Func",
+ "usr": "s:4cake2C1C4foo1yyFZ",
+ "location": "",
+ "moduleName": "cake",
+ "static": true,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ },
+ {
+ "kind": "Var",
+ "name": "Ins",
+ "printedName": "Ins",
+ "declKind": "Var",
+ "usr": "s:4cake2C1C3InsACSgXwvp",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "HasInitialValue",
+ "ReferenceOwnership"
+ ],
+ "ownership": 1,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "WeakStorage",
+ "printedName": "Optional<C1>"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake2C1C3InsACSgXwvg",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Optional",
+ "printedName": "Optional<C1>",
+ "usr": "s:Sq",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "C1",
+ "printedName": "C1",
+ "usr": "s:4cake2C1C"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Setter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake2C1C3InsACSgXwvs",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Optional",
+ "printedName": "Optional<C1>",
+ "usr": "s:Sq",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "C1",
+ "printedName": "C1",
+ "usr": "s:4cake2C1C"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Var",
+ "name": "Ins2",
+ "printedName": "Ins2",
+ "declKind": "Var",
+ "usr": "s:4cake2C1C4Ins2ACXovp",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "HasInitialValue",
+ "ReferenceOwnership"
+ ],
+ "ownership": 2,
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "UnownedStorage",
+ "printedName": "C1"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake2C1C4Ins2ACXovg",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "C1",
+ "printedName": "C1",
+ "usr": "s:4cake2C1C"
+ }
+ ]
+ },
+ {
+ "kind": "Setter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake2C1C4Ins2ACXovs",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "Transparent"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "C1",
+ "printedName": "C1",
+ "usr": "s:4cake2C1C"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init()",
+ "declKind": "Constructor",
+ "usr": "s:4cake2C1CACycfc",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "C1",
+ "printedName": "C1",
+ "usr": "s:4cake2C1C"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "foo1",
+ "printedName": "foo1(_:b:)",
+ "declKind": "Func",
+ "usr": "s:4cake4foo1_1bySi_AA2S1VtF",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "hasDefaultArg": true,
+ "usr": "s:Si"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "S1",
+ "printedName": "S1",
+ "usr": "s:4cake2S1V"
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "foo2",
+ "printedName": "foo2(_:b:)",
+ "declKind": "Func",
+ "usr": "s:4cake4foo2_1bySi_AA2S1VtF",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "hasDefaultArg": true,
+ "usr": "s:Si"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "S1",
+ "printedName": "S1",
+ "usr": "s:4cake2S1V"
+ }
+ ]
+ },
+ {
+ "kind": "TypeDecl",
+ "name": "Number",
+ "printedName": "Number",
+ "declKind": "Enum",
+ "usr": "s:4cake6NumberO",
+ "location": "",
+ "moduleName": "cake",
+ "conformingProtocols": [
+ "Equatable",
+ "Hashable",
+ "RawRepresentable"
+ ],
+ "enumRawTypeName": "Int",
+ "children": [
+ {
+ "kind": "Var",
+ "name": "one",
+ "printedName": "one",
+ "declKind": "EnumElement",
+ "usr": "s:4cake6NumberO3oneyA2CmF",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeFunc",
+ "name": "Function",
+ "printedName": "(Number.Type) -> Number",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Number",
+ "printedName": "Number",
+ "usr": "s:4cake6NumberO"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Metatype",
+ "printedName": "Number.Type",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Number",
+ "printedName": "Number",
+ "usr": "s:4cake6NumberO"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "TypeAlias",
+ "name": "RawValue",
+ "printedName": "RawValue",
+ "declKind": "TypeAlias",
+ "usr": "s:4cake6NumberO8RawValuea",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Var",
+ "name": "hashValue",
+ "printedName": "hashValue",
+ "declKind": "Var",
+ "usr": "s:4cake6NumberO9hashValueSivp",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake6NumberO9hashValueSivg",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "hash",
+ "printedName": "hash(into:)",
+ "declKind": "Func",
+ "usr": "s:4cake6NumberO4hash4intoys6HasherVz_tF",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Hasher",
+ "printedName": "Hasher",
+ "usr": "s:s6HasherV"
+ }
+ ]
+ },
+ {
+ "kind": "Constructor",
+ "name": "init",
+ "printedName": "init(rawValue:)",
+ "declKind": "Constructor",
+ "usr": "s:4cake6NumberO8rawValueACSgSi_tcfc",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "Inlinable"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Optional",
+ "printedName": "Optional<Number>",
+ "usr": "s:Sq",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Number",
+ "printedName": "Number",
+ "usr": "s:4cake6NumberO"
+ }
+ ]
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ },
+ {
+ "kind": "Var",
+ "name": "rawValue",
+ "printedName": "rawValue",
+ "declKind": "Var",
+ "usr": "s:4cake6NumberO8rawValueSivp",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "Getter",
+ "name": "_",
+ "printedName": "_()",
+ "declKind": "Accessor",
+ "usr": "s:4cake6NumberO8rawValueSivg",
+ "location": "",
+ "moduleName": "cake",
+ "declAttributes": [
+ "Inlinable"
+ ],
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "Function",
+ "name": "foo3",
+ "printedName": "foo3(_:)",
+ "declKind": "Func",
+ "usr": "s:4cake4foo3yySDySiSSGF",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "Dictionary",
+ "printedName": "Dictionary<Int, String>",
+ "usr": "s:SD",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Int",
+ "printedName": "Int",
+ "usr": "s:Si"
+ },
+ {
+ "kind": "TypeNominal",
+ "name": "String",
+ "printedName": "String",
+ "usr": "s:SS"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "kind": "TypeDecl",
+ "name": "Int",
+ "printedName": "Int",
+ "declKind": "Struct",
+ "usr": "s:Si",
+ "location": "",
+ "moduleName": "Swift",
+ "conformingProtocols": [
+ "Comparable",
+ "SignedInteger",
+ "_ExpressibleByBuiltinIntegerLiteral",
+ "BinaryInteger",
+ "LosslessStringConvertible",
+ "SignedNumeric",
+ "Numeric",
+ "CustomStringConvertible",
+ "Strideable",
+ "ExpressibleByIntegerLiteral",
+ "FixedWidthInteger",
+ "Encodable",
+ "Decodable",
+ "Hashable",
+ "Equatable",
+ "_HasCustomAnyHashableRepresentation",
+ "CustomReflectable",
+ "_CustomPlaygroundQuickLookable",
+ "MirrorPath",
+ "CVarArg"
+ ],
+ "declAttributes": [
+ "FixedLayout"
+ ],
+ "children": [
+ {
+ "kind": "Function",
+ "name": "foo",
+ "printedName": "foo()",
+ "declKind": "Func",
+ "usr": "s:Si4cakeE3fooyyF",
+ "location": "",
+ "moduleName": "cake",
+ "children": [
+ {
+ "kind": "TypeNominal",
+ "name": "Void",
+ "printedName": "()"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/test/api-digester/dump-module.swift b/test/api-digester/dump-module.swift
index 4732f1c..e88d93a 100644
--- a/test/api-digester/dump-module.swift
+++ b/test/api-digester/dump-module.swift
@@ -4,8 +4,12 @@
// RUN: %swift -emit-module -o %t.mod/cake.swiftmodule %S/Inputs/cake.swift -parse-as-library
// RUN: %api-digester -dump-sdk -module cake -o %t.dump.json -module-cache-path %t.module-cache -sdk %t.sdk -I %t.mod
// RUN: diff -u %S/Outputs/cake.json %t.dump.json
+// RUN: %api-digester -dump-sdk -module cake -o %t.dump.json -module-cache-path %t.module-cache -sdk %t.sdk -I %t.mod -abi
+// RUN: diff -u %S/Outputs/cake-abi.json %t.dump.json
// RUN: %api-digester -diagnose-sdk --input-paths %t.dump.json -input-paths %S/Outputs/cake.json
// Round-trip testing:
// RUN: %api-digester -deserialize-sdk --input-paths %S/Outputs/cake.json -o %t.dump.json
// RUN: diff -u %S/Outputs/cake.json %t.dump.json
+// RUN: %api-digester -deserialize-sdk --input-paths %S/Outputs/cake-abi.json -o %t.dump.json
+// RUN: diff -u %S/Outputs/cake-abi.json %t.dump.json
diff --git a/test/lit.cfg b/test/lit.cfg
index 1aabb68..935d310 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -940,6 +940,50 @@
'appletvsimulator': SIMULATOR_ENV_PREFIX
}
TARGET_ENV_PREFIX = ENV_VAR_PREFIXES.get(config.target_sdk_name, "")
+
+if not config.target_run and 'remote_run_host' in lit_config.params:
+ if 'remote_run_tmpdir' not in lit_config.params:
+ lit_config.fatal("'remote_run_host' provided, but no "
+ "'remote_run_tmpdir'")
+
+ remote_run_host = lit_config.params['remote_run_host']
+ remote_tmp_dir = lit_config.params['remote_run_tmpdir']
+ remote_lib_dir = os.path.join(remote_tmp_dir, 'stdlib')
+ if 'remote_run_identity' in lit_config.params:
+ identity_args = ['-i', lit_config.params['remote_run_identity']]
+ else:
+ identity_args = []
+
+ if 'remote_run_skip_upload_stdlib' not in lit_config.params:
+ lit_config.note(
+ "Uploading dylibs to {0} on {1}".format(remote_lib_dir,
+ remote_run_host))
+ sdk_lib_dir = os.path.join(test_resource_dir, config.target_sdk_name)
+ glob_pattern = os.path.join(sdk_lib_dir,
+ '*.' + config.target_dylib_extension)
+ libs = glob.glob(glob_pattern)
+ subprocess.check_call(
+ [
+ os.path.join(config.swift_utils, 'remote-run'),
+ '--remote-dir', remote_tmp_dir,
+ '--input-prefix', sdk_lib_dir,
+ '--remote-input-prefix', 'stdlib/'
+ ] + identity_args + [
+ remote_run_host,
+ '--',
+ 'true' # A dummy command that ignores its arguments.
+ ] + libs)
+
+ config.target_run = (
+ "/usr/bin/env "
+ "REMOTE_RUN_CHILD_DYLD_FALLBACK_LIBRARY_PATH='{0}' " # Apple option
+ "REMOTE_RUN_CHILD_LD_LIBRARY_PATH='{0}' " # Linux option
+ "%utils/remote-run --input-prefix %S --output-prefix %t "
+ "--remote-dir '{1}'%t {2} {3}".format(remote_lib_dir, remote_tmp_dir,
+ ' '.join(identity_args),
+ remote_run_host))
+ TARGET_ENV_PREFIX = 'REMOTE_RUN_CHILD_'
+
config.substitutions.append(('%env-', TARGET_ENV_PREFIX))
config.substitutions.append(("%target-sdk-name", config.target_sdk_name))
diff --git a/test/remote-run/Inputs/upload/1.txt b/test/remote-run/Inputs/upload/1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/remote-run/Inputs/upload/1.txt
diff --git a/test/remote-run/Inputs/upload/2.txt b/test/remote-run/Inputs/upload/2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/remote-run/Inputs/upload/2.txt
diff --git a/test/remote-run/Inputs/upload/BAD.txt b/test/remote-run/Inputs/upload/BAD.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/remote-run/Inputs/upload/BAD.txt
diff --git a/test/remote-run/download.test-sh b/test/remote-run/download.test-sh
new file mode 100644
index 0000000..78b6f99
--- /dev/null
+++ b/test/remote-run/download.test-sh
@@ -0,0 +1,14 @@
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t-REMOTE)
+RUN: %debug-remote-run --output-prefix %t touch %t/output
+RUN: ls %t/ | %FileCheck %s
+RUN: ls %t-REMOTE/output/ | %FileCheck %s
+
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t/nested)
+RUN: %empty-directory(%t-REMOTE)
+RUN: %debug-remote-run --output-prefix %t touch %t/nested/output
+RUN: ls %t/nested/ | %FileCheck %s
+RUN: ls %t-REMOTE/output/nested/ | %FileCheck %s
+
+CHECK: {{^output$}}
diff --git a/test/remote-run/dry-run-remote.test-sh b/test/remote-run/dry-run-remote.test-sh
new file mode 100644
index 0000000..020c3f3
--- /dev/null
+++ b/test/remote-run/dry-run-remote.test-sh
@@ -0,0 +1,25 @@
+RUN: %utils/remote-run -n --remote-dir /xyz-REMOTE --input-prefix %S/Inputs/ some_user@some_host ls %S/Inputs/upload/1.txt %S/Inputs/upload/2.txt 2>&1 >/dev/null | %FileCheck -check-prefix CHECK-INPUT %s
+
+CHECK-INPUT: /usr/bin/ssh -n some_user@some_host -- '/usr/bin/env' '/bin/mkdir' '-p' '{{.+}}-REMOTE/input/upload'
+CHECK-INPUT-NEXT: /usr/bin/sftp
+CHECK-INPUT-SAME: some_user@some_host
+CHECK-INPUT-DAG: -put '{{.+}}/Inputs/upload/1.txt' '/xyz-REMOTE/input/upload/1.txt'
+CHECK-INPUT-DAG: -put '{{.+}}/Inputs/upload/2.txt' '/xyz-REMOTE/input/upload/2.txt'
+CHECK-INPUT: /usr/bin/ssh -n some_user@some_host -- '/usr/bin/env' 'ls'
+
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t/nested)
+RUN: touch %t/nested/input %t/nested/BAD
+RUN: %utils/remote-run -n --remote-dir /xyz-REMOTE --output-prefix %t some_user@some_host cp %t/nested/input %t/nested/output 2>&1 >/dev/null | %FileCheck -check-prefix CHECK-OUTPUT %s
+
+CHECK-OUTPUT: /usr/bin/ssh -n some_user@some_host -- '/usr/bin/env' '/bin/mkdir' '-p' '{{.+}}-REMOTE/output/nested'
+CHECK-OUTPUT-NEXT: /usr/bin/sftp
+CHECK-OUTPUT-SAME: some_user@some_host
+CHECK-OUTPUT-DAG: -put '{{.+}}/nested/output' '/xyz-REMOTE/output/nested/output'
+CHECK-OUTPUT-DAG: -put '{{.+}}/nested/input' '/xyz-REMOTE/output/nested/input'
+CHECK-OUTPUT: /usr/bin/ssh -n some_user@some_host -- '/usr/bin/env' 'cp'
+CHECK-OUTPUT-NEXT: {{^}}/bin/mkdir -p {{.+}}/nested
+CHECK-OUTPUT-NEXT: /usr/bin/sftp
+CHECK-OUTPUT-SAME: some_user@some_host
+CHECK-OUTPUT-DAG: -get '/xyz-REMOTE/output/nested/output' '{{.+}}/nested/output'
+CHECK-OUTPUT-DAG: -get '/xyz-REMOTE/output/nested/input' '{{.+}}/nested/input'
diff --git a/test/remote-run/dry-run.test-sh b/test/remote-run/dry-run.test-sh
new file mode 100644
index 0000000..c8b47b1
--- /dev/null
+++ b/test/remote-run/dry-run.test-sh
@@ -0,0 +1,26 @@
+RUN: %empty-directory(%t)
+RUN: %debug-remote-run -n --input-prefix %S/Inputs/ ls %S/Inputs/upload/1.txt %S/Inputs/upload/2.txt 2>&1 >/dev/null | %FileCheck -check-prefix CHECK-INPUT %s
+RUN: test -z "`ls %t`"
+RUN: test ! -e %t-REMOTE
+
+CHECK-INPUT: /usr/bin/env /bin/mkdir -p {{.+}}-REMOTE/input/upload
+CHECK-INPUT-NEXT: /usr/bin/sftp
+CHECK-INPUT-DAG: -put '{{.+}}/Inputs/upload/1.txt' '{{.+}}-REMOTE/input/upload/1.txt'
+CHECK-INPUT-DAG: -put '{{.+}}/Inputs/upload/2.txt' '{{.+}}-REMOTE/input/upload/2.txt'
+CHECK-INPUT: /usr/bin/env ls
+
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t/nested)
+RUN: touch %t/nested/input %t/nested/BAD
+RUN: %debug-remote-run -n --output-prefix %t cp %t/nested/input %t/nested/output 2>&1 >/dev/null | %FileCheck -check-prefix CHECK-OUTPUT %s
+RUN: test ! -e %t-REMOTE
+
+CHECK-OUTPUT: /usr/bin/env /bin/mkdir -p {{.+}}-REMOTE/output/nested
+CHECK-OUTPUT-NEXT: /usr/bin/sftp
+CHECK-OUTPUT-DAG: -put '{{.+}}/nested/output' '{{.+}}-REMOTE/output/nested/output'
+CHECK-OUTPUT-DAG: -put '{{.+}}/nested/input' '{{.+}}-REMOTE/output/nested/input'
+CHECK-OUTPUT: /usr/bin/env cp
+CHECK-OUTPUT-NEXT: {{^}}/bin/mkdir -p {{.+}}/nested
+CHECK-OUTPUT-NEXT: /usr/bin/sftp
+CHECK-OUTPUT-DAG: -get '{{.+}}-REMOTE/output/nested/output' '{{.+}}/nested/output'
+CHECK-OUTPUT-DAG: -get '{{.+}}-REMOTE/output/nested/input' '{{.+}}/nested/input'
diff --git a/test/remote-run/env.test-sh b/test/remote-run/env.test-sh
new file mode 100644
index 0000000..e207dc7
--- /dev/null
+++ b/test/remote-run/env.test-sh
@@ -0,0 +1,6 @@
+RUN: env REMOTE_RUN_CHILD_FOO=foo REMOTE_RUN_CHILD_BAR=bar %debug-remote-run sh -c 'echo ":${FOO}:" ":${BAR}:"' | %FileCheck %s
+RUN: env REMOTE_RUN_CHILD_FOO=foo REMOTE_RUN_CHILD_BAR=bar %debug-remote-run -v sh -c 'echo ":${FOO}:" ":${BAR}:"' 2>&1 >/dev/null | %FileCheck -check-prefix VERBOSE %s
+
+CHECK: {{^:foo: :bar:$}}
+
+VERBOSE: /usr/bin/env FOO=foo BAR=bar sh -c echo ":${FOO}:" ":${BAR}:"
diff --git a/test/remote-run/exit-code.test-sh b/test/remote-run/exit-code.test-sh
new file mode 100644
index 0000000..7545d60
--- /dev/null
+++ b/test/remote-run/exit-code.test-sh
@@ -0,0 +1,3 @@
+RUN: not %debug-remote-run false >%t.txt 2>%t.errs.txt
+RUN: test -f %t.txt -a ! -s %t.txt
+RUN: test -f %t.errs.txt -a ! -s %t.errs.txt
diff --git a/test/remote-run/identity.test-sh b/test/remote-run/identity.test-sh
new file mode 100644
index 0000000..ff68b62
--- /dev/null
+++ b/test/remote-run/identity.test-sh
@@ -0,0 +1,38 @@
+RUN: %utils/remote-run -n --remote-dir /xyz-REMOTE -i spiderman --output-prefix %t some_user@some_host:12345 cp %t/nested/input %t/nested/output 2>&1 >/dev/null | %FileCheck %s
+
+CHECK: /usr/bin/ssh -n
+CHECK-DAG: -p 12345
+CHECK-DAG: -i spiderman
+CHECK-SAME: some_user@some_host -- '/usr/bin/env' '/bin/mkdir' '-p' '{{.+}}-REMOTE/output/nested'
+
+CHECK-NEXT: /usr/bin/sftp
+CHECK-DAG: -P 12345
+CHECK-DAG: -i spiderman
+CHECK-SAME: some_user@some_host
+CHECK-DAG: -put '{{.+}}/nested/output' '/xyz-REMOTE/output/nested/output'
+CHECK-DAG: -put '{{.+}}/nested/input' '/xyz-REMOTE/output/nested/input'
+
+CHECK: /usr/bin/ssh -n
+CHECK-DAG: -p 12345
+CHECK-DAG: -i spiderman
+CHECK-SAME: some_user@some_host -- '/usr/bin/env' 'cp'
+
+CHECK-NEXT: {{^}}/bin/mkdir -p {{.+}}/nested
+
+CHECK-NEXT: /usr/bin/sftp
+CHECK-DAG: -P 12345
+CHECK-DAG: -i spiderman
+CHECK-SAME: some_user@some_host
+CHECK-DAG: -get '/xyz-REMOTE/output/nested/output' '{{.+}}/nested/output'
+CHECK-DAG: -get '/xyz-REMOTE/output/nested/input' '{{.+}}/nested/input'
+
+# Make sure things work without a port.
+RUN: %utils/remote-run -n --remote-dir /xyz-REMOTE -i spiderman --output-prefix %t some_user@some_host cp %t/nested/input %t/nested/output 2>&1 >/dev/null | %FileCheck -check-prefix CHECK-PORTLESS %s
+
+CHECK-PORTLESS: /usr/bin/sftp
+CHECK-PORTLESS-SAME: -i spiderman
+CHECK-PORTLESS-SAME: some_user@some_host
+
+CHECK-PORTLESS: /usr/bin/ssh -n
+CHECK-PORTLESS-SAME: -i spiderman
+CHECK-PORTLESS-SAME: some_user@some_host -- '/usr/bin/env' 'cp'
diff --git a/test/remote-run/lit.local.cfg b/test/remote-run/lit.local.cfg
new file mode 100644
index 0000000..afc3094
--- /dev/null
+++ b/test/remote-run/lit.local.cfg
@@ -0,0 +1,5 @@
+# Make a local copy of the substitutions.
+config.substitutions = list(config.substitutions)
+
+config.substitutions.insert(0, ('%debug-remote-run',
+ '%utils/remote-run --debug-as-local --remote-dir %t-REMOTE') )
diff --git a/test/remote-run/port.test-sh b/test/remote-run/port.test-sh
new file mode 100644
index 0000000..2e6ebd2
--- /dev/null
+++ b/test/remote-run/port.test-sh
@@ -0,0 +1,15 @@
+RUN: %utils/remote-run -n --remote-dir /xyz-REMOTE --output-prefix %t some_user@some_host:12345 cp %t/nested/input %t/nested/output 2>&1 >/dev/null | %FileCheck %s
+
+CHECK: /usr/bin/ssh -n -p 12345 some_user@some_host -- '/usr/bin/env' '/bin/mkdir' '-p' '{{.+}}-REMOTE/output/nested'
+CHECK-NEXT: /usr/bin/sftp
+CHECK-SAME: -P 12345
+CHECK-SAME: some_user@some_host
+CHECK-DAG: -put '{{.+}}/nested/output' '/xyz-REMOTE/output/nested/output'
+CHECK-DAG: -put '{{.+}}/nested/input' '/xyz-REMOTE/output/nested/input'
+CHECK: /usr/bin/ssh -n -p 12345 some_user@some_host -- '/usr/bin/env' 'cp'
+CHECK-NEXT: {{^}}/bin/mkdir -p {{.+}}/nested
+CHECK-NEXT: /usr/bin/sftp
+CHECK-SAME: -P 12345
+CHECK-SAME: some_user@some_host
+CHECK-DAG: -get '/xyz-REMOTE/output/nested/output' '{{.+}}/nested/output'
+CHECK-DAG: -get '/xyz-REMOTE/output/nested/input' '{{.+}}/nested/input'
diff --git a/test/remote-run/run-only.test-sh b/test/remote-run/run-only.test-sh
new file mode 100644
index 0000000..db7186d
--- /dev/null
+++ b/test/remote-run/run-only.test-sh
@@ -0,0 +1,6 @@
+RUN: %debug-remote-run echo hello | %FileCheck %s
+RUN: %debug-remote-run -v echo hello 2>&1 >/dev/null | %FileCheck -check-prefix VERBOSE %s
+
+CHECK: {{^hello$}}
+
+VERBOSE: /usr/bin/env echo hello
diff --git a/test/remote-run/stderr.test-sh b/test/remote-run/stderr.test-sh
new file mode 100644
index 0000000..d18e5fa
--- /dev/null
+++ b/test/remote-run/stderr.test-sh
@@ -0,0 +1,15 @@
+RUN: %debug-remote-run sh -c "echo hello; echo goodbye >&2" > %t.stdout.txt 2> %t.stderr.txt
+RUN: %FileCheck -check-prefix CHECK-STDOUT %s < %t.stdout.txt
+RUN: %FileCheck -check-prefix CHECK-STDERR %s < %t.stderr.txt
+
+RUN: not %debug-remote-run sh -c "echo hello; echo goodbye >&2; false" > %t.stdout.txt 2> %t.stderr.txt
+RUN: %FileCheck -check-prefix CHECK-STDOUT %s < %t.stdout.txt
+RUN: %FileCheck -check-prefix CHECK-STDERR %s < %t.stderr.txt
+
+CHECK-STDOUT-NOT: goodbye
+CHECK-STDOUT: {{^hello$}}
+CHECK-STDOUT-NOT: goodbye
+
+CHECK-STDERR-NOT: hello
+CHECK-STDERR: {{^goodbye$}}
+CHECK-STDERR-NOT: hello
diff --git a/test/remote-run/upload-and-download.test-sh b/test/remote-run/upload-and-download.test-sh
new file mode 100644
index 0000000..0dc3c68
--- /dev/null
+++ b/test/remote-run/upload-and-download.test-sh
@@ -0,0 +1,54 @@
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t-REMOTE)
+RUN: touch %t/input %t/BAD
+RUN: %debug-remote-run --output-prefix %t cp %t/input %t/output
+RUN: ls %t/ | %FileCheck %s
+RUN: ls %t-REMOTE/output/ | %FileCheck -check-prefix CHECK-REMOTE %s
+
+CHECK: BAD
+CHECK-NEXT: {{^input$}}
+CHECK-NEXT: {{^output$}}
+
+CHECK-REMOTE-NOT: BAD
+CHECK-REMOTE: {{^input$}}
+CHECK-REMOTE-NEXT: {{^output$}}
+CHECK-REMOTE-NOT: BAD
+
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t/nested)
+RUN: %empty-directory(%t-REMOTE)
+RUN: touch %t/nested/input %t/nested/BAD
+RUN: %debug-remote-run --output-prefix %t cp %t/nested/input %t/nested/output
+RUN: ls %t/nested/ | %FileCheck %s
+RUN: ls %t-REMOTE/output/nested/ | %FileCheck -check-prefix CHECK-REMOTE %s
+
+RUN: %debug-remote-run -v --output-prefix %t cp %t/nested/input %t/nested/output 2>&1 >/dev/null | %FileCheck -check-prefix VERBOSE %s
+
+VERBOSE: /usr/bin/env /bin/mkdir -p {{.+}}-REMOTE/output/nested
+VERBOSE-NEXT: /usr/bin/sftp
+VERBOSE-DAG: -put '{{.+}}/nested/output' '{{.+}}-REMOTE/output/nested/output'
+VERBOSE-DAG: -put '{{.+}}/nested/input' '{{.+}}-REMOTE/output/nested/input'
+VERBOSE: /usr/bin/env cp
+VERBOSE-NEXT: {{^}}/bin/mkdir -p {{.+}}/nested
+VERBOSE-NEXT: /usr/bin/sftp
+VERBOSE-DAG: -get '{{.+}}-REMOTE/output/nested/output' '{{.+}}/nested/output'
+VERBOSE-DAG: -get '{{.+}}-REMOTE/output/nested/input' '{{.+}}/nested/input'
+
+RUN: %empty-directory(%t)
+RUN: touch %t/xyz-1before
+RUN: %debug-remote-run --output-prefix %t/xyz cp %t/xyz-1before %t/xyz-2after
+RUN: ls %t | %FileCheck -check-prefix CHECK-PREFIXED %s
+RUN: ls %t-REMOTE/ | %FileCheck -check-prefix CHECK-PREFIXED-REMOTE %s
+
+CHECK-PREFIXED: {{^xyz-1before$}}
+CHECK-PREFIXED: {{^xyz-2after$}}
+
+CHECK-PREFIXED-REMOTE: {{^output-1before$}}
+CHECK-PREFIXED-REMOTE: {{^output-2after$}}
+
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t-REMOTE)
+RUN: touch %t/input %t/BAD
+RUN: %debug-remote-run --output-prefix %t --remote-output-prefix custom-output cp %t/input %t/output
+RUN: ls %t/ | %FileCheck %s
+RUN: ls %t-REMOTE/custom-output/ | %FileCheck -check-prefix CHECK-REMOTE %s
diff --git a/test/remote-run/upload-stderr.test-sh b/test/remote-run/upload-stderr.test-sh
new file mode 100644
index 0000000..bd0bb5d
--- /dev/null
+++ b/test/remote-run/upload-stderr.test-sh
@@ -0,0 +1,6 @@
+RUN: %empty-directory(%t)
+RUN: %empty-directory(%t/REMOTE/input)
+RUN: chmod a-w %t/REMOTE/input
+RUN: %debug-remote-run --remote-dir %t/REMOTE --input-prefix %S/Inputs/upload/ true -- %S/Inputs/upload/1.txt 2>&1 | %FileCheck %s
+
+CHECK: Permission denied
diff --git a/test/remote-run/upload.test-sh b/test/remote-run/upload.test-sh
new file mode 100644
index 0000000..9e8397c
--- /dev/null
+++ b/test/remote-run/upload.test-sh
@@ -0,0 +1,37 @@
+RUN: %debug-remote-run --input-prefix %S/Inputs/upload/ ls %S/Inputs/upload/1.txt %S/Inputs/upload/2.txt | %FileCheck -check-prefix CHECK-REMOTE %s
+RUN: ls %t-REMOTE/input/ | %FileCheck %s
+
+RUN: %empty-directory(%t-REMOTE)
+RUN: %debug-remote-run --input-prefix %S/Inputs/ ls %S/Inputs/upload/1.txt %S/Inputs/upload/2.txt | %FileCheck -check-prefix CHECK-REMOTE-NESTED %s
+RUN: ls %t-REMOTE/input/upload/ | %FileCheck %s
+RUN: %debug-remote-run -v --input-prefix %S/Inputs/ ls %S/Inputs/upload/1.txt %S/Inputs/upload/2.txt 2>&1 >/dev/null | %FileCheck -check-prefix VERBOSE-NESTED %s
+
+RUN: %empty-directory(%t-REMOTE)
+RUN: %debug-remote-run --input-prefix %S/Inputs/upload/1 ls %S/Inputs/upload/1.txt | %FileCheck -check-prefix CHECK-REMOTE-SINGLE-FILE %s
+RUN: test -f %t-REMOTE/input.txt
+
+RUN: %empty-directory(%t-REMOTE)
+RUN: %debug-remote-run --input-prefix %S/Inputs/upload/ --remote-input-prefix custom-input ls %S/Inputs/upload/1.txt %S/Inputs/upload/2.txt | %FileCheck -check-prefix CHECK-REMOTE-CUSTOM %s
+RUN: ls %t-REMOTE/custom-input/ | %FileCheck %s
+
+CHECK-REMOTE: {{-REMOTE/input/1.txt$}}
+CHECK-REMOTE-NEXT: {{-REMOTE/input/2.txt$}}
+
+CHECK-REMOTE-NESTED: {{-REMOTE/input/upload/1.txt$}}
+CHECK-REMOTE-NESTED-NEXT: {{-REMOTE/input/upload/2.txt$}}
+
+CHECK-REMOTE-SINGLE-FILE: {{-REMOTE/input.txt$}}
+
+CHECK-REMOTE-CUSTOM: {{-REMOTE/custom-input/1.txt$}}
+CHECK-REMOTE-CUSTOM-NEXT: {{-REMOTE/custom-input/2.txt$}}
+
+CHECK-NOT: BAD
+CHECK: {{^1.txt$}}
+CHECK-NEXT: {{^2.txt$}}
+CHECK-NOT: BAD
+
+VERBOSE-NESTED: /usr/bin/env /bin/mkdir -p {{.+}}-REMOTE/input/upload
+VERBOSE-NESTED-NEXT: /usr/bin/sftp
+VERBOSE-NESTED-DAG: -put '{{.+}}/Inputs/upload/1.txt' '{{.+}}-REMOTE/input/upload/1.txt'
+VERBOSE-NESTED-DAG: -put '{{.+}}/Inputs/upload/2.txt' '{{.+}}-REMOTE/input/upload/2.txt'
+VERBOSE-NESTED: /usr/bin/env ls
diff --git a/tools/SourceKit/tools/swift-lang/CMakeLists.txt b/tools/SourceKit/tools/swift-lang/CMakeLists.txt
index bd7e3d6..5d92c12 100644
--- a/tools/SourceKit/tools/swift-lang/CMakeLists.txt
+++ b/tools/SourceKit/tools/swift-lang/CMakeLists.txt
@@ -2,10 +2,12 @@
set(EXTRA_COMPILE_FLAGS "-I" "${SOURCEKITD_SOURCE_DIR}/include/sourcekitd")
set(SOURCEKITD_LINK_LIBS sourcekitdInProc)
set(INSTALLED_COMP sourcekit-inproc)
+ set(DEPENDS_LIST "sourcekitd-test" "sourcekitdInProc")
else()
set(EXTRA_COMPILE_FLAGS "-F" "${SWIFT_LIBRARY_OUTPUT_INTDIR}")
set(SOURCEKITD_LINK_LIBS sourcekitd)
set(INSTALLED_COMP sourcekit-xpc-service)
+ set(DEPENDS_LIST "sourcekitd-test")
endif()
add_swift_library(swiftSwiftLang SHARED
@@ -16,7 +18,7 @@
SourceKitdUID.swift
UIDs.swift.gyb
- DEPENDS sourcekitd-test
+ DEPENDS ${DEPENDS_LIST}
PRIVATE_LINK_LIBRARIES ${SOURCEKITD_LINK_LIBS}
SWIFT_COMPILE_FLAGS ${EXTRA_COMPILE_FLAGS}
INSTALL_IN_COMPONENT ${INSTALLED_COMP}
diff --git a/tools/SwiftSyntax/AbsolutePosition.swift b/tools/SwiftSyntax/AbsolutePosition.swift
index 7b0f265..518a4b0 100644
--- a/tools/SwiftSyntax/AbsolutePosition.swift
+++ b/tools/SwiftSyntax/AbsolutePosition.swift
@@ -12,7 +12,7 @@
/// An absolute position in a source file as text - the absolute utf8Offset from
/// the start, line, and column.
-public final class AbsolutePosition {
+public struct AbsolutePosition {
public let utf8Offset: Int
public let line: Int
public let column: Int
diff --git a/tools/SwiftSyntax/SyntaxData.swift b/tools/SwiftSyntax/SyntaxData.swift
index 916d5f0..920b1c9 100644
--- a/tools/SwiftSyntax/SyntaxData.swift
+++ b/tools/SwiftSyntax/SyntaxData.swift
@@ -18,6 +18,15 @@
/// exposed to clients.
typealias NodeIdentifier = [Int]
+/// Box a value type into a reference type
+fileprivate class Box<T> {
+ let value: T
+
+ init(_ value: T) {
+ self.value = value
+ }
+}
+
/// SyntaxData is the underlying storage for each Syntax node.
/// It's modelled as an array that stores and caches a SyntaxData for each raw
/// syntax node in its layout. It is up to the specific Syntax nodes to maintain
@@ -38,7 +47,7 @@
let childCaches: [AtomicCache<SyntaxData>]
- let positionCache: AtomicCache<AbsolutePosition>
+ private let positionCache: AtomicCache<Box<AbsolutePosition>>
fileprivate func calculatePosition() -> AbsolutePosition {
guard let parent = parent else {
@@ -62,7 +71,7 @@
/// The position of the start of this node's leading trivia
var position: AbsolutePosition {
- return positionCache.value { return calculatePosition() }
+ return positionCache.value({ return Box(calculatePosition()) }).value
}
/// The position of the start of this node's content, skipping its trivia
@@ -93,7 +102,7 @@
self.indexInParent = indexInParent
self.parent = parent
self.childCaches = raw.layout.map { _ in AtomicCache<SyntaxData>() }
- self.positionCache = AtomicCache<AbsolutePosition>()
+ self.positionCache = AtomicCache<Box<AbsolutePosition>>()
}
/// The index path from this node to the root. This can be used to uniquely
diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp
index 1a747a6..e4be297 100644
--- a/tools/swift-api-digester/swift-api-digester.cpp
+++ b/tools/swift-api-digester/swift-api-digester.cpp
@@ -123,6 +123,9 @@
Verbose("v", llvm::cl::desc("Verbose"));
static llvm::cl::opt<bool>
+Abi("abi", llvm::cl::desc("Dumping ABI interface"), llvm::cl::init(false));
+
+static llvm::cl::opt<bool>
PrintModule("print-module", llvm::cl::desc("Print module names in diagnostics"));
static llvm::cl::opt<ActionType>
@@ -250,6 +253,7 @@
};
class SDKContext {
+ bool ABI;
llvm::StringSet<> TextData;
llvm::BumpPtrAllocator Allocator;
UpdatedNodesMap UpdateMap;
@@ -257,6 +261,7 @@
NodeMap RevertTypeAliasUpdateMap;
TypeMemberDiffVector TypeMemberDiffs;
public:
+ SDKContext(bool ABI): ABI(ABI) {}
llvm::BumpPtrAllocator &allocator() {
return Allocator;
}
@@ -275,6 +280,7 @@
TypeMemberDiffVector &getTypeMemberDiffs() {
return TypeMemberDiffs;
}
+ bool checkingABI() const { return ABI; }
};
// A node matcher will traverse two trees of SDKNode and find matched nodes
@@ -1341,6 +1347,18 @@
return ReferenceOwnership::Strong;
}
+// Get a requirement with all types canonicalized.
+Requirement getCanonicalRequirement(Requirement &Req) {
+ auto kind = Req.getKind();
+ if (kind == RequirementKind::Layout) {
+ return Requirement(kind, Req.getFirstType()->getCanonicalType(),
+ Req.getLayoutConstraint());
+ } else {
+ return Requirement(kind, Req.getFirstType()->getCanonicalType(),
+ Req.getSecondType()->getCanonicalType());
+ }
+}
+
static StringRef printGenericSignature(SDKContext &Ctx, ValueDecl *VD) {
llvm::SmallString<32> Result;
llvm::raw_svector_ostream OS(Result);
@@ -1355,7 +1373,10 @@
} else {
First = false;
}
- Req.print(OS, PrintOptions::printInterface());
+ if (Ctx.checkingABI())
+ getCanonicalRequirement(Req).print(OS, PrintOptions::printInterface());
+ else
+ Req.print(OS, PrintOptions::printInterface());
}
OS << ">";
return Ctx.buffer(OS.str());
@@ -1363,7 +1384,10 @@
if (auto *GC = VD->getAsGenericContext()) {
if (auto *Sig = GC->getGenericSignature()) {
- Sig->print(OS);
+ if (Ctx.checkingABI())
+ Sig->getCanonicalSignature()->print(OS);
+ else
+ Sig->print(OS);
return Ctx.buffer(OS.str());
}
}
@@ -1438,6 +1462,9 @@
// representing the return value type of a function decl.
static SDKNode *constructTypeNode(SDKContext &Ctx, Type T,
TypeInitInfo InitInfo = TypeInitInfo()) {
+ if (Ctx.checkingABI()) {
+ T = T->getCanonicalType();
+ }
SDKNode* Root = SDKNodeInitInfo(Ctx, T, InitInfo)
.createSDKNode(SDKNodeKind::TypeNominal);
@@ -3814,7 +3841,7 @@
llvm::errs() << RightPath << " does not exist\n";
return 1;
}
- SDKContext Ctx;
+ SDKContext Ctx(options::Abi);
SwiftDeclCollector LeftCollector(Ctx);
LeftCollector.deSerialize(LeftPath);
SwiftDeclCollector RightCollector(Ctx);
@@ -3866,7 +3893,7 @@
return 1;
}
llvm::errs() << "Diffing: " << LeftPath << " and " << RightPath << "\n";
- SDKContext Ctx;
+ SDKContext Ctx(options::Abi);
SwiftDeclCollector LeftCollector(Ctx);
LeftCollector.deSerialize(LeftPath);
SwiftDeclCollector RightCollector(Ctx);
@@ -3990,7 +4017,7 @@
Modules.push_back(M);
}
- SDKContext Ctx;
+ SDKContext Ctx(options::Abi);
for (auto M : Modules) {
SwiftDeclCollector Collector(Ctx);
SmallVector<Decl*, 256> Decls;
@@ -4047,7 +4074,7 @@
}
if (options::Verbose)
llvm::errs() << "Scanning symbols...\n";
- SDKContext SDKCtx;
+ SDKContext SDKCtx(options::Abi);
SwiftDeclCollector Collector(SDKCtx);
Collector.lookupVisibleDecls(Modules);
if (options::Verbose)
@@ -4202,7 +4229,7 @@
llvm::errs() << dumpPath << " does not exist\n";
return 1;
}
- SDKContext Ctx;
+ SDKContext Ctx(options::Abi);
SwiftDeclCollector Collector(Ctx);
Collector.deSerialize(dumpPath);
Collector.serialize(OutputPath);
@@ -4215,7 +4242,7 @@
llvm::errs() << dumpPath << " does not exist\n";
return 1;
}
- SDKContext Ctx;
+ SDKContext Ctx(options::Abi);
SwiftDeclCollector Collector(Ctx);
Collector.deSerialize(dumpPath);
struct FinderByLocation: SDKNodeVisitor {
diff --git a/unittests/Basic/OwnedStringTest.cpp b/unittests/Basic/OwnedStringTest.cpp
index c86fd9d..25ac1a6 100644
--- a/unittests/Basic/OwnedStringTest.cpp
+++ b/unittests/Basic/OwnedStringTest.cpp
@@ -18,177 +18,43 @@
TEST(OwnedStringTest, char_pointer_empty) {
const char *data = "";
const size_t length = strlen(data);
- OwnedString ownedString(data);
+ OwnedString ownedString = OwnedString::makeUnowned(data);
EXPECT_EQ(length, ownedString.size());
EXPECT_TRUE(ownedString.empty());
-
- OwnedString copy = ownedString.copy();
- EXPECT_EQ(length, copy.size());
- EXPECT_TRUE(copy.empty());
-
- StringRef str = copy.str();
- EXPECT_EQ("", str);
- EXPECT_EQ(length, str.size());
+ EXPECT_EQ(data, ownedString.str().data());
}
TEST(OwnedStringTest, char_pointer_non_empty) {
const char *data = "string";
const size_t length = strlen(data);
- OwnedString ownedString(data);
+ OwnedString ownedString = OwnedString::makeUnowned(data);
EXPECT_EQ(length, ownedString.size());
EXPECT_FALSE(ownedString.empty());
-
- OwnedString copy = ownedString.copy();
- EXPECT_EQ(length, copy.size());
- EXPECT_FALSE(copy.empty());
-
- StringRef str = copy.str();
- EXPECT_EQ("string", str);
- EXPECT_EQ(length, strlen(str.data()));
+ EXPECT_EQ(data, ownedString.str().data());
}
-TEST(OwnedStringTest, char_pointer_length_equal) {
- const char *data = "string";
+TEST(OwnedStringTest, ref_counted_copies_buffer) {
+ char *data = static_cast<char *>(malloc(6));
+ memcpy(data, "hello", 6);
size_t length = strlen(data);
- OwnedString ownedString(data, length);
- EXPECT_EQ(length, ownedString.size());
- EXPECT_FALSE(ownedString.empty());
+ OwnedString ownedString =
+ OwnedString::makeRefCounted(StringRef(data, length));
- OwnedString copy = ownedString.copy();
- EXPECT_EQ(length, copy.size());
- EXPECT_FALSE(copy.empty());
+ EXPECT_EQ(ownedString.str(), "hello");
+ EXPECT_NE(ownedString.str().data(), data);
- // Make sure we correctly copied the data and that it is null
- // terminated.
- StringRef str = copy.str();
- EXPECT_EQ("string", str);
- EXPECT_EQ(length, strlen(str.data()));
+ memcpy(data, "world", 6);
+
+ // Even if the original buffer changes, the string should stay the same
+ EXPECT_EQ(ownedString.str(), "hello");
}
-TEST(OwnedStringTest, char_pointer_length_nonzero) {
- const char *data = "string";
- const size_t length = 1;
- OwnedString ownedString(data, length);
+TEST(OwnedStringTest, ref_counted_assignment) {
+ OwnedString str = OwnedString::makeRefCounted("hello");
+ OwnedString copy = str;
- EXPECT_EQ(length, ownedString.size());
- EXPECT_FALSE(ownedString.empty());
-
- OwnedString copy = ownedString.copy();
- EXPECT_EQ(length, copy.size());
- EXPECT_FALSE(copy.empty());
-
- // Make sure we correctly copied the data and that it is null
- // terminated.
- StringRef str = copy.str();
- EXPECT_EQ("s", str);
- EXPECT_EQ(1UL, strlen(str.data()));
-}
-
-TEST(OwnedStringTest, char_pointer_length_zero) {
- const char *data = "string";
- const size_t length = 0;
- OwnedString ownedString(data, length);
-
- EXPECT_EQ(length, ownedString.size());
- EXPECT_TRUE(ownedString.empty());
-
- OwnedString copy = ownedString.copy();
- EXPECT_EQ(length, copy.size());
- EXPECT_TRUE(copy.empty());
-}
-
-TEST(OwnedStringTest, copy_original_new_different) {
- // Initialize a mutable string.
- const char *original = "string";
- const size_t length = strlen(original);
- char *data = static_cast<char *>(malloc(length + 1));
- memcpy(data, original, length);
- data[length] = '\0';
-
- // Create an OwnedString.
- OwnedString ownedString(data, length);
-
- EXPECT_EQ(length, ownedString.size());
- EXPECT_FALSE(ownedString.empty());
-
- // Copy the string
- OwnedString copy = ownedString.copy();
- EXPECT_EQ(length, copy.size());
- EXPECT_FALSE(copy.empty());
-
- // Make sure we correctly copied the data and that it is null
- // terminated.
- StringRef str = copy.str();
- EXPECT_EQ("string", str);
- EXPECT_EQ(length, strlen(str.data()));
-
- // Make sure updating the original pointer doesn't affect the copy.
- data[0] = 'a';
-
- EXPECT_EQ("string", str);
-}
-
-TEST(OwnedStringTest, copy_constructor_original_not_copy) {
- // Initialize a mutable string.
- const char *original = "string";
- const size_t length = strlen(original);
- char *data = static_cast<char *>(malloc(length + 1));
- memcpy(data, original, length);
- data[length] = '\0';
-
- // Create an OwnedString.
- OwnedString ownedString(data, length);
-
- EXPECT_EQ(length, ownedString.size());
- EXPECT_FALSE(ownedString.empty());
-
- // Copy the string
- OwnedString copy = OwnedString(ownedString);
- EXPECT_EQ(length, copy.size());
- EXPECT_FALSE(copy.empty());
-
- // Make sure we correctly copied the data and that it is null
- // terminated.
- StringRef str = copy.str();
- EXPECT_EQ("string", str);
- EXPECT_EQ(length, strlen(str.data()));
-
- // Make sure updating the original pointer doesn't affect the copy.
- data[0] = 'a';
-
- EXPECT_EQ("string", str);
-}
-
-TEST(OwnedStringTest, copy_constructor_original_copy) {
- // Initialize a mutable string.
- const char *original = "string";
- const size_t length = strlen(original);
- char *data = static_cast<char *>(malloc(length + 1));
- memcpy(data, original, length);
- data[length] = '\0';
-
- // Create an OwnedString.
- OwnedString ownedString(data, length);
-
- EXPECT_EQ(length, ownedString.size());
- EXPECT_FALSE(ownedString.empty());
-
- // Copy the string
- OwnedString copy = OwnedString(ownedString.copy());
- EXPECT_EQ(length, copy.size());
- EXPECT_FALSE(copy.empty());
-
- // Make sure we correctly copied the data and that it is null
- // terminated.
- StringRef str = copy.str();
- EXPECT_EQ("string", str);
- EXPECT_EQ(length, strlen(str.data()));
-
- // Make sure updating the original pointer doesn't affect the copy.
- data[0] = 'a';
-
- EXPECT_EQ("string", str);
+ EXPECT_EQ(str.str().data(), copy.str().data());
}
diff --git a/utils/build-script-impl b/utils/build-script-impl
index ac1f644..cc285f7 100755
--- a/utils/build-script-impl
+++ b/utils/build-script-impl
@@ -2823,7 +2823,7 @@
# Watchpoint testing is currently disabled: see rdar://38566150.
if [[ "$(true_false ${LLDB_TEST_SWIFT_ONLY})" == "TRUE" ]]; then
LLDB_TEST_SUBDIR_CLAUSE="--test-subdir lang/swift"
- LLDB_TEST_CATEGORIES="--skip-category=watchpoint --skip-category=dwo --skip-category=dsym --skip-category=gmodules -G swiftpr"
+ LLDB_TEST_CATEGORIES="--skip-category=watchpoint --skip-category=dwo --skip-category=dsym --skip-category=gmodules"
else
LLDB_TEST_SUBDIR_CLAUSE=""
LLDB_TEST_CATEGORIES="--skip-category=watchpoint"
diff --git a/utils/gyb_syntax_support/__init__.py b/utils/gyb_syntax_support/__init__.py
index 06b0237..8711463 100644
--- a/utils/gyb_syntax_support/__init__.py
+++ b/utils/gyb_syntax_support/__init__.py
@@ -34,7 +34,9 @@
token = child.main_token()
tok_kind = token.kind if token else "unknown"
tok_text = token.text if token else ""
- return 'RawSyntax::missing(tok::%s, "%s")' % (tok_kind, tok_text)
+ return \
+ 'RawSyntax::missing(tok::%s, OwnedString::makeUnowned("%s"))' % \
+ (tok_kind, tok_text)
else:
missing_kind = "Unknown" if child.syntax_kind == "Syntax" \
else child.syntax_kind
diff --git a/utils/remote-run b/utils/remote-run
new file mode 100755
index 0000000..5a9edf5
--- /dev/null
+++ b/utils/remote-run
@@ -0,0 +1,226 @@
+#!/usr/bin/env python
+# remote-run - Runs a command on another machine, for testing -----*- python -*-
+#
+# This source file is part of the Swift.org open source project
+#
+# Copyright (c) 2018 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
+#
+# ----------------------------------------------------------------------------
+
+from __future__ import print_function
+
+import argparse
+import os.path
+import subprocess
+import sys
+
+def quote(arg):
+ return repr(arg)
+
+class CommandRunner(object):
+ def __init__(self):
+ self.verbose = False
+ self.dry_run = False
+
+ @staticmethod
+ def _dirnames(files):
+ return list(set(os.path.dirname(f) for f in files))
+
+ def popen(self, command, **kwargs):
+ if self.verbose:
+ print(' '.join(command), file=sys.stderr)
+ if self.dry_run:
+ return None
+ return subprocess.Popen(command, **kwargs)
+
+ def send(self, local_to_remote_files):
+ # Prepare the remote directory structure.
+ # FIXME: This could be folded into the sftp connection below.
+ dirs_to_make = self._dirnames(local_to_remote_files.viewvalues())
+ self.run_remote(['/bin/mkdir', '-p'] + dirs_to_make)
+
+ # Send the local files.
+ sftp_commands = ("-put {0} {1}".format(quote(local_file),
+ quote(remote_file))
+ for local_file, remote_file
+ in local_to_remote_files.viewitems())
+ self.run_sftp(sftp_commands)
+
+ def fetch(self, local_to_remote_files):
+ # Prepare the local directory structure.
+ dirs_to_make = self._dirnames(local_to_remote_files.viewkeys())
+ mkdir_command = ['/bin/mkdir', '-p'] + dirs_to_make
+ if self.verbose:
+ print(' '.join(mkdir_command), file=sys.stderr)
+ if not self.dry_run:
+ subprocess.check_call(mkdir_command)
+
+ # Fetch the remote files.
+ sftp_commands = ("-get {0} {1}".format(quote(remote_file),
+ quote(local_file))
+ for local_file, remote_file
+ in local_to_remote_files.viewitems())
+ self.run_sftp(sftp_commands)
+
+ def run_remote(self, command, remote_env={}):
+ env_strings = ['{0}={1}'.format(k,v) for k,v in remote_env.viewitems()]
+ remote_invocation = self.remote_invocation(
+ ['/usr/bin/env'] + env_strings + command)
+ remote_proc = self.popen(remote_invocation, stdin=subprocess.PIPE,
+ stdout=None, stderr=None)
+ if self.dry_run:
+ return
+ _, _ = remote_proc.communicate()
+ if remote_proc.returncode:
+ # FIXME: We may still want to fetch the output files to see what
+ # went wrong.
+ sys.exit(remote_proc.returncode)
+
+ def run_sftp(self, commands):
+ sftp_proc = self.popen(self.sftp_invocation(), stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=None)
+ concatenated_commands = '\n'.join(commands)
+ if self.verbose:
+ print(concatenated_commands, file=sys.stderr)
+ if self.dry_run:
+ return
+ _, _ = sftp_proc.communicate(concatenated_commands)
+ if sftp_proc.returncode:
+ sys.exit(sftp_proc.returncode)
+
+class RemoteCommandRunner(CommandRunner):
+ def __init__(self, host, identity_path):
+ if ':' in host:
+ (self.remote_host, self.port) = host.rsplit(':', 1)
+ else:
+ self.remote_host = host
+ self.port = None
+ self.identity_path = identity_path
+
+ def common_options(self, port_flag):
+ port_option = [port_flag, self.port] if self.port else []
+ identity_option = (
+ ['-i', self.identity_path] if self.identity_path else [])
+ return port_option + identity_option
+
+ def remote_invocation(self, command):
+ return (['/usr/bin/ssh', '-n'] +
+ self.common_options(port_flag='-p') +
+ [self.remote_host, '--'] +
+ [quote(arg) for arg in command])
+
+ def sftp_invocation(self):
+ return (['/usr/bin/sftp', '-b', '-', '-q'] +
+ self.common_options(port_flag='-P') +
+ [self.remote_host])
+
+class LocalCommandRunner(CommandRunner):
+ def __init__(self):
+ self.cached_sftp_server_path = None
+
+ def sftp_server_path(self):
+ if not self.cached_sftp_server_path:
+ paths_to_try = ['/usr/libexec/sftp-server', '/usr/lib/sftp-server']
+ self.cached_sftp_server_path = next(
+ (path for path in paths_to_try if os.path.exists(path)),
+ paths_to_try[0])
+ return self.cached_sftp_server_path
+
+ def remote_invocation(self, command):
+ return command
+
+ def sftp_invocation(self):
+ return ['/usr/bin/sftp', '-b', '-', '-q', '-D', self.sftp_server_path()]
+
+def find_transfers(args, source_prefix, dest_prefix):
+ if source_prefix.endswith(os.path.sep):
+ source_prefix = source_prefix[:-len(os.path.sep)]
+ return dict((arg, dest_prefix + arg[len(source_prefix):])
+ for arg in args if arg.startswith(source_prefix))
+
+def collect_remote_env(local_env=os.environ, prefix='REMOTE_RUN_CHILD_'):
+ return dict((key[len(prefix):], value)
+ for key, value in local_env.items() if key.startswith(prefix))
+
+def main():
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
+ help='print commands as they are run')
+ parser.add_argument('-n', '--dry-run', action='store_true', dest='dry_run',
+ help="print the commands that would have been run, but "
+ "don't actually run them")
+
+ parser.add_argument('--remote-dir', required=True, metavar='PATH',
+ help='(required) a writable temporary path on the '
+ 'remote machine')
+ parser.add_argument('--input-prefix',
+ help='arguments matching this prefix will be uploaded')
+ parser.add_argument('--output-prefix',
+ help='arguments matching this prefix will be both '
+ 'uploaded and downloaded')
+ parser.add_argument('--remote-input-prefix', default='input',
+ help='input arguments use this prefix on the remote '
+ 'machine')
+ parser.add_argument('--remote-output-prefix', default='output',
+ help='output arguments use this prefix on the remote '
+ 'machine')
+
+ parser.add_argument('-i', '--identity', dest='identity', metavar='FILE',
+ help='an SSH identity file (private key) to use')
+ parser.add_argument('--debug-as-local', action='store_true',
+ help='run commands locally instead of over SSH, for '
+ 'debugging purposes. The "host" argument is '
+ 'omitted.')
+
+ parser.add_argument('host',
+ help='the host to connect to, in the form '
+ '[user@]host[:port]')
+ parser.add_argument('command', nargs=argparse.REMAINDER,
+ help='the command to run', metavar='command...')
+ args = parser.parse_args()
+
+ if args.debug_as_local:
+ runner = LocalCommandRunner()
+ args.command.insert(0, args.host)
+ del args.host
+ else:
+ runner = RemoteCommandRunner(args.host, args.identity)
+ runner.dry_run = args.dry_run
+ runner.verbose = args.verbose or args.dry_run
+
+ upload_files = dict()
+ download_files = dict()
+ if args.input_prefix:
+ remote_dir = os.path.join(args.remote_dir, args.remote_input_prefix)
+ input_files = find_transfers(args.command, args.input_prefix,
+ remote_dir)
+ assert not any(upload_files.has_key(f) for f in input_files)
+ upload_files.update(input_files)
+ if args.output_prefix:
+ remote_dir = os.path.join(args.remote_dir, args.remote_output_prefix)
+ test_files = find_transfers(args.command, args.output_prefix,
+ remote_dir)
+ assert not any(upload_files.has_key(f) for f in test_files)
+ upload_files.update(test_files)
+ assert not any(download_files.has_key(f) for f in test_files)
+ download_files.update(test_files)
+
+ if upload_files:
+ runner.send(upload_files)
+
+ remote_env = collect_remote_env()
+
+ translated_command = [upload_files.get(arg, download_files.get(arg, arg))
+ for arg in args.command]
+ runner.run_remote(translated_command, remote_env)
+
+ if download_files:
+ runner.fetch(download_files)
+
+if __name__ == "__main__":
+ main()
diff --git a/validation-test/Driver/batch_mode_overlong_argv.swift b/validation-test/Driver/batch_mode_overlong_argv.swift
index bffbcfe..6d4412f 100644
--- a/validation-test/Driver/batch_mode_overlong_argv.swift
+++ b/validation-test/Driver/batch_mode_overlong_argv.swift
@@ -1,109 +1,109 @@
// REQUIRES: OS=macosx
// REQUIRES: no_asan
// RUN: %empty-directory(%t)
-// RUN: touch %t/f_1_1.swift %t/f_1_2.swift %t/f_1_3.swift %t/f_1_4.swift %t/f_1_5.swift %t/f_1_6.swift %t/f_1_7.swift %t/f_1_8.swift %t/f_1_9.swift %t/f_1_10.swift
-// RUN: touch %t/f_2_1.swift %t/f_2_2.swift %t/f_2_3.swift %t/f_2_4.swift %t/f_2_5.swift %t/f_2_6.swift %t/f_2_7.swift %t/f_2_8.swift %t/f_2_9.swift %t/f_2_10.swift
-// RUN: touch %t/f_3_1.swift %t/f_3_2.swift %t/f_3_3.swift %t/f_3_4.swift %t/f_3_5.swift %t/f_3_6.swift %t/f_3_7.swift %t/f_3_8.swift %t/f_3_9.swift %t/f_3_10.swift
-// RUN: touch %t/f_4_1.swift %t/f_4_2.swift %t/f_4_3.swift %t/f_4_4.swift %t/f_4_5.swift %t/f_4_6.swift %t/f_4_7.swift %t/f_4_8.swift %t/f_4_9.swift %t/f_4_10.swift
-// RUN: touch %t/f_5_1.swift %t/f_5_2.swift %t/f_5_3.swift %t/f_5_4.swift %t/f_5_5.swift %t/f_5_6.swift %t/f_5_7.swift %t/f_5_8.swift %t/f_5_9.swift %t/f_5_10.swift
-// RUN: touch %t/f_6_1.swift %t/f_6_2.swift %t/f_6_3.swift %t/f_6_4.swift %t/f_6_5.swift %t/f_6_6.swift %t/f_6_7.swift %t/f_6_8.swift %t/f_6_9.swift %t/f_6_10.swift
-// RUN: touch %t/f_7_1.swift %t/f_7_2.swift %t/f_7_3.swift %t/f_7_4.swift %t/f_7_5.swift %t/f_7_6.swift %t/f_7_7.swift %t/f_7_8.swift %t/f_7_9.swift %t/f_7_10.swift
-// RUN: touch %t/f_8_1.swift %t/f_8_2.swift %t/f_8_3.swift %t/f_8_4.swift %t/f_8_5.swift %t/f_8_6.swift %t/f_8_7.swift %t/f_8_8.swift %t/f_8_9.swift %t/f_8_10.swift
-// RUN: touch %t/f_9_1.swift %t/f_9_2.swift %t/f_9_3.swift %t/f_9_4.swift %t/f_9_5.swift %t/f_9_6.swift %t/f_9_7.swift %t/f_9_8.swift %t/f_9_9.swift %t/f_9_10.swift
-// RUN: touch %t/f_10_1.swift %t/f_10_2.swift %t/f_10_3.swift %t/f_10_4.swift %t/f_10_5.swift %t/f_10_6.swift %t/f_10_7.swift %t/f_10_8.swift %t/f_10_9.swift %t/f_10_10.swift
-// RUN: touch %t/f_11_1.swift %t/f_11_2.swift %t/f_11_3.swift %t/f_11_4.swift %t/f_11_5.swift %t/f_11_6.swift %t/f_11_7.swift %t/f_11_8.swift %t/f_11_9.swift %t/f_11_10.swift
-// RUN: touch %t/f_12_1.swift %t/f_12_2.swift %t/f_12_3.swift %t/f_12_4.swift %t/f_12_5.swift %t/f_12_6.swift %t/f_12_7.swift %t/f_12_8.swift %t/f_12_9.swift %t/f_12_10.swift
-// RUN: touch %t/f_13_1.swift %t/f_13_2.swift %t/f_13_3.swift %t/f_13_4.swift %t/f_13_5.swift %t/f_13_6.swift %t/f_13_7.swift %t/f_13_8.swift %t/f_13_9.swift %t/f_13_10.swift
-// RUN: touch %t/f_14_1.swift %t/f_14_2.swift %t/f_14_3.swift %t/f_14_4.swift %t/f_14_5.swift %t/f_14_6.swift %t/f_14_7.swift %t/f_14_8.swift %t/f_14_9.swift %t/f_14_10.swift
-// RUN: touch %t/f_15_1.swift %t/f_15_2.swift %t/f_15_3.swift %t/f_15_4.swift %t/f_15_5.swift %t/f_15_6.swift %t/f_15_7.swift %t/f_15_8.swift %t/f_15_9.swift %t/f_15_10.swift
-// RUN: touch %t/f_16_1.swift %t/f_16_2.swift %t/f_16_3.swift %t/f_16_4.swift %t/f_16_5.swift %t/f_16_6.swift %t/f_16_7.swift %t/f_16_8.swift %t/f_16_9.swift %t/f_16_10.swift
-// RUN: touch %t/f_17_1.swift %t/f_17_2.swift %t/f_17_3.swift %t/f_17_4.swift %t/f_17_5.swift %t/f_17_6.swift %t/f_17_7.swift %t/f_17_8.swift %t/f_17_9.swift %t/f_17_10.swift
-// RUN: touch %t/f_18_1.swift %t/f_18_2.swift %t/f_18_3.swift %t/f_18_4.swift %t/f_18_5.swift %t/f_18_6.swift %t/f_18_7.swift %t/f_18_8.swift %t/f_18_9.swift %t/f_18_10.swift
-// RUN: touch %t/f_19_1.swift %t/f_19_2.swift %t/f_19_3.swift %t/f_19_4.swift %t/f_19_5.swift %t/f_19_6.swift %t/f_19_7.swift %t/f_19_8.swift %t/f_19_9.swift %t/f_19_10.swift
-// RUN: touch %t/f_20_1.swift %t/f_20_2.swift %t/f_20_3.swift %t/f_20_4.swift %t/f_20_5.swift %t/f_20_6.swift %t/f_20_7.swift %t/f_20_8.swift %t/f_20_9.swift %t/f_20_10.swift
-// RUN: touch %t/f_21_1.swift %t/f_21_2.swift %t/f_21_3.swift %t/f_21_4.swift %t/f_21_5.swift %t/f_21_6.swift %t/f_21_7.swift %t/f_21_8.swift %t/f_21_9.swift %t/f_21_10.swift
-// RUN: touch %t/f_22_1.swift %t/f_22_2.swift %t/f_22_3.swift %t/f_22_4.swift %t/f_22_5.swift %t/f_22_6.swift %t/f_22_7.swift %t/f_22_8.swift %t/f_22_9.swift %t/f_22_10.swift
-// RUN: touch %t/f_23_1.swift %t/f_23_2.swift %t/f_23_3.swift %t/f_23_4.swift %t/f_23_5.swift %t/f_23_6.swift %t/f_23_7.swift %t/f_23_8.swift %t/f_23_9.swift %t/f_23_10.swift
-// RUN: touch %t/f_24_1.swift %t/f_24_2.swift %t/f_24_3.swift %t/f_24_4.swift %t/f_24_5.swift %t/f_24_6.swift %t/f_24_7.swift %t/f_24_8.swift %t/f_24_9.swift %t/f_24_10.swift
-// RUN: touch %t/f_25_1.swift %t/f_25_2.swift %t/f_25_3.swift %t/f_25_4.swift %t/f_25_5.swift %t/f_25_6.swift %t/f_25_7.swift %t/f_25_8.swift %t/f_25_9.swift %t/f_25_10.swift
-// RUN: touch %t/f_26_1.swift %t/f_26_2.swift %t/f_26_3.swift %t/f_26_4.swift %t/f_26_5.swift %t/f_26_6.swift %t/f_26_7.swift %t/f_26_8.swift %t/f_26_9.swift %t/f_26_10.swift
-// RUN: touch %t/f_27_1.swift %t/f_27_2.swift %t/f_27_3.swift %t/f_27_4.swift %t/f_27_5.swift %t/f_27_6.swift %t/f_27_7.swift %t/f_27_8.swift %t/f_27_9.swift %t/f_27_10.swift
-// RUN: touch %t/f_28_1.swift %t/f_28_2.swift %t/f_28_3.swift %t/f_28_4.swift %t/f_28_5.swift %t/f_28_6.swift %t/f_28_7.swift %t/f_28_8.swift %t/f_28_9.swift %t/f_28_10.swift
-// RUN: touch %t/f_29_1.swift %t/f_29_2.swift %t/f_29_3.swift %t/f_29_4.swift %t/f_29_5.swift %t/f_29_6.swift %t/f_29_7.swift %t/f_29_8.swift %t/f_29_9.swift %t/f_29_10.swift
-// RUN: touch %t/f_30_1.swift %t/f_30_2.swift %t/f_30_3.swift %t/f_30_4.swift %t/f_30_5.swift %t/f_30_6.swift %t/f_30_7.swift %t/f_30_8.swift %t/f_30_9.swift %t/f_30_10.swift
-// RUN: touch %t/f_31_1.swift %t/f_31_2.swift %t/f_31_3.swift %t/f_31_4.swift %t/f_31_5.swift %t/f_31_6.swift %t/f_31_7.swift %t/f_31_8.swift %t/f_31_9.swift %t/f_31_10.swift
-// RUN: touch %t/f_32_1.swift %t/f_32_2.swift %t/f_32_3.swift %t/f_32_4.swift %t/f_32_5.swift %t/f_32_6.swift %t/f_32_7.swift %t/f_32_8.swift %t/f_32_9.swift %t/f_32_10.swift
-// RUN: touch %t/f_33_1.swift %t/f_33_2.swift %t/f_33_3.swift %t/f_33_4.swift %t/f_33_5.swift %t/f_33_6.swift %t/f_33_7.swift %t/f_33_8.swift %t/f_33_9.swift %t/f_33_10.swift
-// RUN: touch %t/f_34_1.swift %t/f_34_2.swift %t/f_34_3.swift %t/f_34_4.swift %t/f_34_5.swift %t/f_34_6.swift %t/f_34_7.swift %t/f_34_8.swift %t/f_34_9.swift %t/f_34_10.swift
-// RUN: touch %t/f_35_1.swift %t/f_35_2.swift %t/f_35_3.swift %t/f_35_4.swift %t/f_35_5.swift %t/f_35_6.swift %t/f_35_7.swift %t/f_35_8.swift %t/f_35_9.swift %t/f_35_10.swift
-// RUN: touch %t/f_36_1.swift %t/f_36_2.swift %t/f_36_3.swift %t/f_36_4.swift %t/f_36_5.swift %t/f_36_6.swift %t/f_36_7.swift %t/f_36_8.swift %t/f_36_9.swift %t/f_36_10.swift
-// RUN: touch %t/f_37_1.swift %t/f_37_2.swift %t/f_37_3.swift %t/f_37_4.swift %t/f_37_5.swift %t/f_37_6.swift %t/f_37_7.swift %t/f_37_8.swift %t/f_37_9.swift %t/f_37_10.swift
-// RUN: touch %t/f_38_1.swift %t/f_38_2.swift %t/f_38_3.swift %t/f_38_4.swift %t/f_38_5.swift %t/f_38_6.swift %t/f_38_7.swift %t/f_38_8.swift %t/f_38_9.swift %t/f_38_10.swift
-// RUN: touch %t/f_39_1.swift %t/f_39_2.swift %t/f_39_3.swift %t/f_39_4.swift %t/f_39_5.swift %t/f_39_6.swift %t/f_39_7.swift %t/f_39_8.swift %t/f_39_9.swift %t/f_39_10.swift
-// RUN: touch %t/f_40_1.swift %t/f_40_2.swift %t/f_40_3.swift %t/f_40_4.swift %t/f_40_5.swift %t/f_40_6.swift %t/f_40_7.swift %t/f_40_8.swift %t/f_40_9.swift %t/f_40_10.swift
-// RUN: touch %t/f_41_1.swift %t/f_41_2.swift %t/f_41_3.swift %t/f_41_4.swift %t/f_41_5.swift %t/f_41_6.swift %t/f_41_7.swift %t/f_41_8.swift %t/f_41_9.swift %t/f_41_10.swift
-// RUN: touch %t/f_42_1.swift %t/f_42_2.swift %t/f_42_3.swift %t/f_42_4.swift %t/f_42_5.swift %t/f_42_6.swift %t/f_42_7.swift %t/f_42_8.swift %t/f_42_9.swift %t/f_42_10.swift
-// RUN: touch %t/f_43_1.swift %t/f_43_2.swift %t/f_43_3.swift %t/f_43_4.swift %t/f_43_5.swift %t/f_43_6.swift %t/f_43_7.swift %t/f_43_8.swift %t/f_43_9.swift %t/f_43_10.swift
-// RUN: touch %t/f_44_1.swift %t/f_44_2.swift %t/f_44_3.swift %t/f_44_4.swift %t/f_44_5.swift %t/f_44_6.swift %t/f_44_7.swift %t/f_44_8.swift %t/f_44_9.swift %t/f_44_10.swift
-// RUN: touch %t/f_45_1.swift %t/f_45_2.swift %t/f_45_3.swift %t/f_45_4.swift %t/f_45_5.swift %t/f_45_6.swift %t/f_45_7.swift %t/f_45_8.swift %t/f_45_9.swift %t/f_45_10.swift
-// RUN: touch %t/f_46_1.swift %t/f_46_2.swift %t/f_46_3.swift %t/f_46_4.swift %t/f_46_5.swift %t/f_46_6.swift %t/f_46_7.swift %t/f_46_8.swift %t/f_46_9.swift %t/f_46_10.swift
-// RUN: touch %t/f_47_1.swift %t/f_47_2.swift %t/f_47_3.swift %t/f_47_4.swift %t/f_47_5.swift %t/f_47_6.swift %t/f_47_7.swift %t/f_47_8.swift %t/f_47_9.swift %t/f_47_10.swift
-// RUN: touch %t/f_48_1.swift %t/f_48_2.swift %t/f_48_3.swift %t/f_48_4.swift %t/f_48_5.swift %t/f_48_6.swift %t/f_48_7.swift %t/f_48_8.swift %t/f_48_9.swift %t/f_48_10.swift
-// RUN: touch %t/f_49_1.swift %t/f_49_2.swift %t/f_49_3.swift %t/f_49_4.swift %t/f_49_5.swift %t/f_49_6.swift %t/f_49_7.swift %t/f_49_8.swift %t/f_49_9.swift %t/f_49_10.swift
-// RUN: touch %t/f_50_1.swift %t/f_50_2.swift %t/f_50_3.swift %t/f_50_4.swift %t/f_50_5.swift %t/f_50_6.swift %t/f_50_7.swift %t/f_50_8.swift %t/f_50_9.swift %t/f_50_10.swift
-// RUN: touch %t/f_51_1.swift %t/f_51_2.swift %t/f_51_3.swift %t/f_51_4.swift %t/f_51_5.swift %t/f_51_6.swift %t/f_51_7.swift %t/f_51_8.swift %t/f_51_9.swift %t/f_51_10.swift
-// RUN: touch %t/f_52_1.swift %t/f_52_2.swift %t/f_52_3.swift %t/f_52_4.swift %t/f_52_5.swift %t/f_52_6.swift %t/f_52_7.swift %t/f_52_8.swift %t/f_52_9.swift %t/f_52_10.swift
-// RUN: touch %t/f_53_1.swift %t/f_53_2.swift %t/f_53_3.swift %t/f_53_4.swift %t/f_53_5.swift %t/f_53_6.swift %t/f_53_7.swift %t/f_53_8.swift %t/f_53_9.swift %t/f_53_10.swift
-// RUN: touch %t/f_54_1.swift %t/f_54_2.swift %t/f_54_3.swift %t/f_54_4.swift %t/f_54_5.swift %t/f_54_6.swift %t/f_54_7.swift %t/f_54_8.swift %t/f_54_9.swift %t/f_54_10.swift
-// RUN: touch %t/f_55_1.swift %t/f_55_2.swift %t/f_55_3.swift %t/f_55_4.swift %t/f_55_5.swift %t/f_55_6.swift %t/f_55_7.swift %t/f_55_8.swift %t/f_55_9.swift %t/f_55_10.swift
-// RUN: touch %t/f_56_1.swift %t/f_56_2.swift %t/f_56_3.swift %t/f_56_4.swift %t/f_56_5.swift %t/f_56_6.swift %t/f_56_7.swift %t/f_56_8.swift %t/f_56_9.swift %t/f_56_10.swift
-// RUN: touch %t/f_57_1.swift %t/f_57_2.swift %t/f_57_3.swift %t/f_57_4.swift %t/f_57_5.swift %t/f_57_6.swift %t/f_57_7.swift %t/f_57_8.swift %t/f_57_9.swift %t/f_57_10.swift
-// RUN: touch %t/f_58_1.swift %t/f_58_2.swift %t/f_58_3.swift %t/f_58_4.swift %t/f_58_5.swift %t/f_58_6.swift %t/f_58_7.swift %t/f_58_8.swift %t/f_58_9.swift %t/f_58_10.swift
-// RUN: touch %t/f_59_1.swift %t/f_59_2.swift %t/f_59_3.swift %t/f_59_4.swift %t/f_59_5.swift %t/f_59_6.swift %t/f_59_7.swift %t/f_59_8.swift %t/f_59_9.swift %t/f_59_10.swift
-// RUN: touch %t/f_60_1.swift %t/f_60_2.swift %t/f_60_3.swift %t/f_60_4.swift %t/f_60_5.swift %t/f_60_6.swift %t/f_60_7.swift %t/f_60_8.swift %t/f_60_9.swift %t/f_60_10.swift
-// RUN: touch %t/f_61_1.swift %t/f_61_2.swift %t/f_61_3.swift %t/f_61_4.swift %t/f_61_5.swift %t/f_61_6.swift %t/f_61_7.swift %t/f_61_8.swift %t/f_61_9.swift %t/f_61_10.swift
-// RUN: touch %t/f_62_1.swift %t/f_62_2.swift %t/f_62_3.swift %t/f_62_4.swift %t/f_62_5.swift %t/f_62_6.swift %t/f_62_7.swift %t/f_62_8.swift %t/f_62_9.swift %t/f_62_10.swift
-// RUN: touch %t/f_63_1.swift %t/f_63_2.swift %t/f_63_3.swift %t/f_63_4.swift %t/f_63_5.swift %t/f_63_6.swift %t/f_63_7.swift %t/f_63_8.swift %t/f_63_9.swift %t/f_63_10.swift
-// RUN: touch %t/f_64_1.swift %t/f_64_2.swift %t/f_64_3.swift %t/f_64_4.swift %t/f_64_5.swift %t/f_64_6.swift %t/f_64_7.swift %t/f_64_8.swift %t/f_64_9.swift %t/f_64_10.swift
-// RUN: touch %t/f_65_1.swift %t/f_65_2.swift %t/f_65_3.swift %t/f_65_4.swift %t/f_65_5.swift %t/f_65_6.swift %t/f_65_7.swift %t/f_65_8.swift %t/f_65_9.swift %t/f_65_10.swift
-// RUN: touch %t/f_66_1.swift %t/f_66_2.swift %t/f_66_3.swift %t/f_66_4.swift %t/f_66_5.swift %t/f_66_6.swift %t/f_66_7.swift %t/f_66_8.swift %t/f_66_9.swift %t/f_66_10.swift
-// RUN: touch %t/f_67_1.swift %t/f_67_2.swift %t/f_67_3.swift %t/f_67_4.swift %t/f_67_5.swift %t/f_67_6.swift %t/f_67_7.swift %t/f_67_8.swift %t/f_67_9.swift %t/f_67_10.swift
-// RUN: touch %t/f_68_1.swift %t/f_68_2.swift %t/f_68_3.swift %t/f_68_4.swift %t/f_68_5.swift %t/f_68_6.swift %t/f_68_7.swift %t/f_68_8.swift %t/f_68_9.swift %t/f_68_10.swift
-// RUN: touch %t/f_69_1.swift %t/f_69_2.swift %t/f_69_3.swift %t/f_69_4.swift %t/f_69_5.swift %t/f_69_6.swift %t/f_69_7.swift %t/f_69_8.swift %t/f_69_9.swift %t/f_69_10.swift
-// RUN: touch %t/f_70_1.swift %t/f_70_2.swift %t/f_70_3.swift %t/f_70_4.swift %t/f_70_5.swift %t/f_70_6.swift %t/f_70_7.swift %t/f_70_8.swift %t/f_70_9.swift %t/f_70_10.swift
-// RUN: touch %t/f_71_1.swift %t/f_71_2.swift %t/f_71_3.swift %t/f_71_4.swift %t/f_71_5.swift %t/f_71_6.swift %t/f_71_7.swift %t/f_71_8.swift %t/f_71_9.swift %t/f_71_10.swift
-// RUN: touch %t/f_72_1.swift %t/f_72_2.swift %t/f_72_3.swift %t/f_72_4.swift %t/f_72_5.swift %t/f_72_6.swift %t/f_72_7.swift %t/f_72_8.swift %t/f_72_9.swift %t/f_72_10.swift
-// RUN: touch %t/f_73_1.swift %t/f_73_2.swift %t/f_73_3.swift %t/f_73_4.swift %t/f_73_5.swift %t/f_73_6.swift %t/f_73_7.swift %t/f_73_8.swift %t/f_73_9.swift %t/f_73_10.swift
-// RUN: touch %t/f_74_1.swift %t/f_74_2.swift %t/f_74_3.swift %t/f_74_4.swift %t/f_74_5.swift %t/f_74_6.swift %t/f_74_7.swift %t/f_74_8.swift %t/f_74_9.swift %t/f_74_10.swift
-// RUN: touch %t/f_75_1.swift %t/f_75_2.swift %t/f_75_3.swift %t/f_75_4.swift %t/f_75_5.swift %t/f_75_6.swift %t/f_75_7.swift %t/f_75_8.swift %t/f_75_9.swift %t/f_75_10.swift
-// RUN: touch %t/f_76_1.swift %t/f_76_2.swift %t/f_76_3.swift %t/f_76_4.swift %t/f_76_5.swift %t/f_76_6.swift %t/f_76_7.swift %t/f_76_8.swift %t/f_76_9.swift %t/f_76_10.swift
-// RUN: touch %t/f_77_1.swift %t/f_77_2.swift %t/f_77_3.swift %t/f_77_4.swift %t/f_77_5.swift %t/f_77_6.swift %t/f_77_7.swift %t/f_77_8.swift %t/f_77_9.swift %t/f_77_10.swift
-// RUN: touch %t/f_78_1.swift %t/f_78_2.swift %t/f_78_3.swift %t/f_78_4.swift %t/f_78_5.swift %t/f_78_6.swift %t/f_78_7.swift %t/f_78_8.swift %t/f_78_9.swift %t/f_78_10.swift
-// RUN: touch %t/f_79_1.swift %t/f_79_2.swift %t/f_79_3.swift %t/f_79_4.swift %t/f_79_5.swift %t/f_79_6.swift %t/f_79_7.swift %t/f_79_8.swift %t/f_79_9.swift %t/f_79_10.swift
-// RUN: touch %t/f_80_1.swift %t/f_80_2.swift %t/f_80_3.swift %t/f_80_4.swift %t/f_80_5.swift %t/f_80_6.swift %t/f_80_7.swift %t/f_80_8.swift %t/f_80_9.swift %t/f_80_10.swift
-// RUN: touch %t/f_81_1.swift %t/f_81_2.swift %t/f_81_3.swift %t/f_81_4.swift %t/f_81_5.swift %t/f_81_6.swift %t/f_81_7.swift %t/f_81_8.swift %t/f_81_9.swift %t/f_81_10.swift
-// RUN: touch %t/f_82_1.swift %t/f_82_2.swift %t/f_82_3.swift %t/f_82_4.swift %t/f_82_5.swift %t/f_82_6.swift %t/f_82_7.swift %t/f_82_8.swift %t/f_82_9.swift %t/f_82_10.swift
-// RUN: touch %t/f_83_1.swift %t/f_83_2.swift %t/f_83_3.swift %t/f_83_4.swift %t/f_83_5.swift %t/f_83_6.swift %t/f_83_7.swift %t/f_83_8.swift %t/f_83_9.swift %t/f_83_10.swift
-// RUN: touch %t/f_84_1.swift %t/f_84_2.swift %t/f_84_3.swift %t/f_84_4.swift %t/f_84_5.swift %t/f_84_6.swift %t/f_84_7.swift %t/f_84_8.swift %t/f_84_9.swift %t/f_84_10.swift
-// RUN: touch %t/f_85_1.swift %t/f_85_2.swift %t/f_85_3.swift %t/f_85_4.swift %t/f_85_5.swift %t/f_85_6.swift %t/f_85_7.swift %t/f_85_8.swift %t/f_85_9.swift %t/f_85_10.swift
-// RUN: touch %t/f_86_1.swift %t/f_86_2.swift %t/f_86_3.swift %t/f_86_4.swift %t/f_86_5.swift %t/f_86_6.swift %t/f_86_7.swift %t/f_86_8.swift %t/f_86_9.swift %t/f_86_10.swift
-// RUN: touch %t/f_87_1.swift %t/f_87_2.swift %t/f_87_3.swift %t/f_87_4.swift %t/f_87_5.swift %t/f_87_6.swift %t/f_87_7.swift %t/f_87_8.swift %t/f_87_9.swift %t/f_87_10.swift
-// RUN: touch %t/f_88_1.swift %t/f_88_2.swift %t/f_88_3.swift %t/f_88_4.swift %t/f_88_5.swift %t/f_88_6.swift %t/f_88_7.swift %t/f_88_8.swift %t/f_88_9.swift %t/f_88_10.swift
-// RUN: touch %t/f_89_1.swift %t/f_89_2.swift %t/f_89_3.swift %t/f_89_4.swift %t/f_89_5.swift %t/f_89_6.swift %t/f_89_7.swift %t/f_89_8.swift %t/f_89_9.swift %t/f_89_10.swift
-// RUN: touch %t/f_90_1.swift %t/f_90_2.swift %t/f_90_3.swift %t/f_90_4.swift %t/f_90_5.swift %t/f_90_6.swift %t/f_90_7.swift %t/f_90_8.swift %t/f_90_9.swift %t/f_90_10.swift
-// RUN: touch %t/f_91_1.swift %t/f_91_2.swift %t/f_91_3.swift %t/f_91_4.swift %t/f_91_5.swift %t/f_91_6.swift %t/f_91_7.swift %t/f_91_8.swift %t/f_91_9.swift %t/f_91_10.swift
-// RUN: touch %t/f_92_1.swift %t/f_92_2.swift %t/f_92_3.swift %t/f_92_4.swift %t/f_92_5.swift %t/f_92_6.swift %t/f_92_7.swift %t/f_92_8.swift %t/f_92_9.swift %t/f_92_10.swift
-// RUN: touch %t/f_93_1.swift %t/f_93_2.swift %t/f_93_3.swift %t/f_93_4.swift %t/f_93_5.swift %t/f_93_6.swift %t/f_93_7.swift %t/f_93_8.swift %t/f_93_9.swift %t/f_93_10.swift
-// RUN: touch %t/f_94_1.swift %t/f_94_2.swift %t/f_94_3.swift %t/f_94_4.swift %t/f_94_5.swift %t/f_94_6.swift %t/f_94_7.swift %t/f_94_8.swift %t/f_94_9.swift %t/f_94_10.swift
-// RUN: touch %t/f_95_1.swift %t/f_95_2.swift %t/f_95_3.swift %t/f_95_4.swift %t/f_95_5.swift %t/f_95_6.swift %t/f_95_7.swift %t/f_95_8.swift %t/f_95_9.swift %t/f_95_10.swift
-// RUN: touch %t/f_96_1.swift %t/f_96_2.swift %t/f_96_3.swift %t/f_96_4.swift %t/f_96_5.swift %t/f_96_6.swift %t/f_96_7.swift %t/f_96_8.swift %t/f_96_9.swift %t/f_96_10.swift
-// RUN: touch %t/f_97_1.swift %t/f_97_2.swift %t/f_97_3.swift %t/f_97_4.swift %t/f_97_5.swift %t/f_97_6.swift %t/f_97_7.swift %t/f_97_8.swift %t/f_97_9.swift %t/f_97_10.swift
-// RUN: touch %t/f_98_1.swift %t/f_98_2.swift %t/f_98_3.swift %t/f_98_4.swift %t/f_98_5.swift %t/f_98_6.swift %t/f_98_7.swift %t/f_98_8.swift %t/f_98_9.swift %t/f_98_10.swift
-// RUN: touch %t/f_99_1.swift %t/f_99_2.swift %t/f_99_3.swift %t/f_99_4.swift %t/f_99_5.swift %t/f_99_6.swift %t/f_99_7.swift %t/f_99_8.swift %t/f_99_9.swift %t/f_99_10.swift
-// RUN: touch %t/f_100_1.swift %t/f_100_2.swift %t/f_100_3.swift %t/f_100_4.swift %t/f_100_5.swift %t/f_100_6.swift %t/f_100_7.swift %t/f_100_8.swift %t/f_100_9.swift %t/f_100_10.swift
-// RUN: mkdir -p %t/additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/
+// RUN: cd %t && touch ./f_1_1.swift ./f_1_2.swift ./f_1_3.swift ./f_1_4.swift ./f_1_5.swift ./f_1_6.swift ./f_1_7.swift ./f_1_8.swift ./f_1_9.swift ./f_1_10.swift
+// RUN: cd %t && touch ./f_2_1.swift ./f_2_2.swift ./f_2_3.swift ./f_2_4.swift ./f_2_5.swift ./f_2_6.swift ./f_2_7.swift ./f_2_8.swift ./f_2_9.swift ./f_2_10.swift
+// RUN: cd %t && touch ./f_3_1.swift ./f_3_2.swift ./f_3_3.swift ./f_3_4.swift ./f_3_5.swift ./f_3_6.swift ./f_3_7.swift ./f_3_8.swift ./f_3_9.swift ./f_3_10.swift
+// RUN: cd %t && touch ./f_4_1.swift ./f_4_2.swift ./f_4_3.swift ./f_4_4.swift ./f_4_5.swift ./f_4_6.swift ./f_4_7.swift ./f_4_8.swift ./f_4_9.swift ./f_4_10.swift
+// RUN: cd %t && touch ./f_5_1.swift ./f_5_2.swift ./f_5_3.swift ./f_5_4.swift ./f_5_5.swift ./f_5_6.swift ./f_5_7.swift ./f_5_8.swift ./f_5_9.swift ./f_5_10.swift
+// RUN: cd %t && touch ./f_6_1.swift ./f_6_2.swift ./f_6_3.swift ./f_6_4.swift ./f_6_5.swift ./f_6_6.swift ./f_6_7.swift ./f_6_8.swift ./f_6_9.swift ./f_6_10.swift
+// RUN: cd %t && touch ./f_7_1.swift ./f_7_2.swift ./f_7_3.swift ./f_7_4.swift ./f_7_5.swift ./f_7_6.swift ./f_7_7.swift ./f_7_8.swift ./f_7_9.swift ./f_7_10.swift
+// RUN: cd %t && touch ./f_8_1.swift ./f_8_2.swift ./f_8_3.swift ./f_8_4.swift ./f_8_5.swift ./f_8_6.swift ./f_8_7.swift ./f_8_8.swift ./f_8_9.swift ./f_8_10.swift
+// RUN: cd %t && touch ./f_9_1.swift ./f_9_2.swift ./f_9_3.swift ./f_9_4.swift ./f_9_5.swift ./f_9_6.swift ./f_9_7.swift ./f_9_8.swift ./f_9_9.swift ./f_9_10.swift
+// RUN: cd %t && touch ./f_10_1.swift ./f_10_2.swift ./f_10_3.swift ./f_10_4.swift ./f_10_5.swift ./f_10_6.swift ./f_10_7.swift ./f_10_8.swift ./f_10_9.swift ./f_10_10.swift
+// RUN: cd %t && touch ./f_11_1.swift ./f_11_2.swift ./f_11_3.swift ./f_11_4.swift ./f_11_5.swift ./f_11_6.swift ./f_11_7.swift ./f_11_8.swift ./f_11_9.swift ./f_11_10.swift
+// RUN: cd %t && touch ./f_12_1.swift ./f_12_2.swift ./f_12_3.swift ./f_12_4.swift ./f_12_5.swift ./f_12_6.swift ./f_12_7.swift ./f_12_8.swift ./f_12_9.swift ./f_12_10.swift
+// RUN: cd %t && touch ./f_13_1.swift ./f_13_2.swift ./f_13_3.swift ./f_13_4.swift ./f_13_5.swift ./f_13_6.swift ./f_13_7.swift ./f_13_8.swift ./f_13_9.swift ./f_13_10.swift
+// RUN: cd %t && touch ./f_14_1.swift ./f_14_2.swift ./f_14_3.swift ./f_14_4.swift ./f_14_5.swift ./f_14_6.swift ./f_14_7.swift ./f_14_8.swift ./f_14_9.swift ./f_14_10.swift
+// RUN: cd %t && touch ./f_15_1.swift ./f_15_2.swift ./f_15_3.swift ./f_15_4.swift ./f_15_5.swift ./f_15_6.swift ./f_15_7.swift ./f_15_8.swift ./f_15_9.swift ./f_15_10.swift
+// RUN: cd %t && touch ./f_16_1.swift ./f_16_2.swift ./f_16_3.swift ./f_16_4.swift ./f_16_5.swift ./f_16_6.swift ./f_16_7.swift ./f_16_8.swift ./f_16_9.swift ./f_16_10.swift
+// RUN: cd %t && touch ./f_17_1.swift ./f_17_2.swift ./f_17_3.swift ./f_17_4.swift ./f_17_5.swift ./f_17_6.swift ./f_17_7.swift ./f_17_8.swift ./f_17_9.swift ./f_17_10.swift
+// RUN: cd %t && touch ./f_18_1.swift ./f_18_2.swift ./f_18_3.swift ./f_18_4.swift ./f_18_5.swift ./f_18_6.swift ./f_18_7.swift ./f_18_8.swift ./f_18_9.swift ./f_18_10.swift
+// RUN: cd %t && touch ./f_19_1.swift ./f_19_2.swift ./f_19_3.swift ./f_19_4.swift ./f_19_5.swift ./f_19_6.swift ./f_19_7.swift ./f_19_8.swift ./f_19_9.swift ./f_19_10.swift
+// RUN: cd %t && touch ./f_20_1.swift ./f_20_2.swift ./f_20_3.swift ./f_20_4.swift ./f_20_5.swift ./f_20_6.swift ./f_20_7.swift ./f_20_8.swift ./f_20_9.swift ./f_20_10.swift
+// RUN: cd %t && touch ./f_21_1.swift ./f_21_2.swift ./f_21_3.swift ./f_21_4.swift ./f_21_5.swift ./f_21_6.swift ./f_21_7.swift ./f_21_8.swift ./f_21_9.swift ./f_21_10.swift
+// RUN: cd %t && touch ./f_22_1.swift ./f_22_2.swift ./f_22_3.swift ./f_22_4.swift ./f_22_5.swift ./f_22_6.swift ./f_22_7.swift ./f_22_8.swift ./f_22_9.swift ./f_22_10.swift
+// RUN: cd %t && touch ./f_23_1.swift ./f_23_2.swift ./f_23_3.swift ./f_23_4.swift ./f_23_5.swift ./f_23_6.swift ./f_23_7.swift ./f_23_8.swift ./f_23_9.swift ./f_23_10.swift
+// RUN: cd %t && touch ./f_24_1.swift ./f_24_2.swift ./f_24_3.swift ./f_24_4.swift ./f_24_5.swift ./f_24_6.swift ./f_24_7.swift ./f_24_8.swift ./f_24_9.swift ./f_24_10.swift
+// RUN: cd %t && touch ./f_25_1.swift ./f_25_2.swift ./f_25_3.swift ./f_25_4.swift ./f_25_5.swift ./f_25_6.swift ./f_25_7.swift ./f_25_8.swift ./f_25_9.swift ./f_25_10.swift
+// RUN: cd %t && touch ./f_26_1.swift ./f_26_2.swift ./f_26_3.swift ./f_26_4.swift ./f_26_5.swift ./f_26_6.swift ./f_26_7.swift ./f_26_8.swift ./f_26_9.swift ./f_26_10.swift
+// RUN: cd %t && touch ./f_27_1.swift ./f_27_2.swift ./f_27_3.swift ./f_27_4.swift ./f_27_5.swift ./f_27_6.swift ./f_27_7.swift ./f_27_8.swift ./f_27_9.swift ./f_27_10.swift
+// RUN: cd %t && touch ./f_28_1.swift ./f_28_2.swift ./f_28_3.swift ./f_28_4.swift ./f_28_5.swift ./f_28_6.swift ./f_28_7.swift ./f_28_8.swift ./f_28_9.swift ./f_28_10.swift
+// RUN: cd %t && touch ./f_29_1.swift ./f_29_2.swift ./f_29_3.swift ./f_29_4.swift ./f_29_5.swift ./f_29_6.swift ./f_29_7.swift ./f_29_8.swift ./f_29_9.swift ./f_29_10.swift
+// RUN: cd %t && touch ./f_30_1.swift ./f_30_2.swift ./f_30_3.swift ./f_30_4.swift ./f_30_5.swift ./f_30_6.swift ./f_30_7.swift ./f_30_8.swift ./f_30_9.swift ./f_30_10.swift
+// RUN: cd %t && touch ./f_31_1.swift ./f_31_2.swift ./f_31_3.swift ./f_31_4.swift ./f_31_5.swift ./f_31_6.swift ./f_31_7.swift ./f_31_8.swift ./f_31_9.swift ./f_31_10.swift
+// RUN: cd %t && touch ./f_32_1.swift ./f_32_2.swift ./f_32_3.swift ./f_32_4.swift ./f_32_5.swift ./f_32_6.swift ./f_32_7.swift ./f_32_8.swift ./f_32_9.swift ./f_32_10.swift
+// RUN: cd %t && touch ./f_33_1.swift ./f_33_2.swift ./f_33_3.swift ./f_33_4.swift ./f_33_5.swift ./f_33_6.swift ./f_33_7.swift ./f_33_8.swift ./f_33_9.swift ./f_33_10.swift
+// RUN: cd %t && touch ./f_34_1.swift ./f_34_2.swift ./f_34_3.swift ./f_34_4.swift ./f_34_5.swift ./f_34_6.swift ./f_34_7.swift ./f_34_8.swift ./f_34_9.swift ./f_34_10.swift
+// RUN: cd %t && touch ./f_35_1.swift ./f_35_2.swift ./f_35_3.swift ./f_35_4.swift ./f_35_5.swift ./f_35_6.swift ./f_35_7.swift ./f_35_8.swift ./f_35_9.swift ./f_35_10.swift
+// RUN: cd %t && touch ./f_36_1.swift ./f_36_2.swift ./f_36_3.swift ./f_36_4.swift ./f_36_5.swift ./f_36_6.swift ./f_36_7.swift ./f_36_8.swift ./f_36_9.swift ./f_36_10.swift
+// RUN: cd %t && touch ./f_37_1.swift ./f_37_2.swift ./f_37_3.swift ./f_37_4.swift ./f_37_5.swift ./f_37_6.swift ./f_37_7.swift ./f_37_8.swift ./f_37_9.swift ./f_37_10.swift
+// RUN: cd %t && touch ./f_38_1.swift ./f_38_2.swift ./f_38_3.swift ./f_38_4.swift ./f_38_5.swift ./f_38_6.swift ./f_38_7.swift ./f_38_8.swift ./f_38_9.swift ./f_38_10.swift
+// RUN: cd %t && touch ./f_39_1.swift ./f_39_2.swift ./f_39_3.swift ./f_39_4.swift ./f_39_5.swift ./f_39_6.swift ./f_39_7.swift ./f_39_8.swift ./f_39_9.swift ./f_39_10.swift
+// RUN: cd %t && touch ./f_40_1.swift ./f_40_2.swift ./f_40_3.swift ./f_40_4.swift ./f_40_5.swift ./f_40_6.swift ./f_40_7.swift ./f_40_8.swift ./f_40_9.swift ./f_40_10.swift
+// RUN: cd %t && touch ./f_41_1.swift ./f_41_2.swift ./f_41_3.swift ./f_41_4.swift ./f_41_5.swift ./f_41_6.swift ./f_41_7.swift ./f_41_8.swift ./f_41_9.swift ./f_41_10.swift
+// RUN: cd %t && touch ./f_42_1.swift ./f_42_2.swift ./f_42_3.swift ./f_42_4.swift ./f_42_5.swift ./f_42_6.swift ./f_42_7.swift ./f_42_8.swift ./f_42_9.swift ./f_42_10.swift
+// RUN: cd %t && touch ./f_43_1.swift ./f_43_2.swift ./f_43_3.swift ./f_43_4.swift ./f_43_5.swift ./f_43_6.swift ./f_43_7.swift ./f_43_8.swift ./f_43_9.swift ./f_43_10.swift
+// RUN: cd %t && touch ./f_44_1.swift ./f_44_2.swift ./f_44_3.swift ./f_44_4.swift ./f_44_5.swift ./f_44_6.swift ./f_44_7.swift ./f_44_8.swift ./f_44_9.swift ./f_44_10.swift
+// RUN: cd %t && touch ./f_45_1.swift ./f_45_2.swift ./f_45_3.swift ./f_45_4.swift ./f_45_5.swift ./f_45_6.swift ./f_45_7.swift ./f_45_8.swift ./f_45_9.swift ./f_45_10.swift
+// RUN: cd %t && touch ./f_46_1.swift ./f_46_2.swift ./f_46_3.swift ./f_46_4.swift ./f_46_5.swift ./f_46_6.swift ./f_46_7.swift ./f_46_8.swift ./f_46_9.swift ./f_46_10.swift
+// RUN: cd %t && touch ./f_47_1.swift ./f_47_2.swift ./f_47_3.swift ./f_47_4.swift ./f_47_5.swift ./f_47_6.swift ./f_47_7.swift ./f_47_8.swift ./f_47_9.swift ./f_47_10.swift
+// RUN: cd %t && touch ./f_48_1.swift ./f_48_2.swift ./f_48_3.swift ./f_48_4.swift ./f_48_5.swift ./f_48_6.swift ./f_48_7.swift ./f_48_8.swift ./f_48_9.swift ./f_48_10.swift
+// RUN: cd %t && touch ./f_49_1.swift ./f_49_2.swift ./f_49_3.swift ./f_49_4.swift ./f_49_5.swift ./f_49_6.swift ./f_49_7.swift ./f_49_8.swift ./f_49_9.swift ./f_49_10.swift
+// RUN: cd %t && touch ./f_50_1.swift ./f_50_2.swift ./f_50_3.swift ./f_50_4.swift ./f_50_5.swift ./f_50_6.swift ./f_50_7.swift ./f_50_8.swift ./f_50_9.swift ./f_50_10.swift
+// RUN: cd %t && touch ./f_51_1.swift ./f_51_2.swift ./f_51_3.swift ./f_51_4.swift ./f_51_5.swift ./f_51_6.swift ./f_51_7.swift ./f_51_8.swift ./f_51_9.swift ./f_51_10.swift
+// RUN: cd %t && touch ./f_52_1.swift ./f_52_2.swift ./f_52_3.swift ./f_52_4.swift ./f_52_5.swift ./f_52_6.swift ./f_52_7.swift ./f_52_8.swift ./f_52_9.swift ./f_52_10.swift
+// RUN: cd %t && touch ./f_53_1.swift ./f_53_2.swift ./f_53_3.swift ./f_53_4.swift ./f_53_5.swift ./f_53_6.swift ./f_53_7.swift ./f_53_8.swift ./f_53_9.swift ./f_53_10.swift
+// RUN: cd %t && touch ./f_54_1.swift ./f_54_2.swift ./f_54_3.swift ./f_54_4.swift ./f_54_5.swift ./f_54_6.swift ./f_54_7.swift ./f_54_8.swift ./f_54_9.swift ./f_54_10.swift
+// RUN: cd %t && touch ./f_55_1.swift ./f_55_2.swift ./f_55_3.swift ./f_55_4.swift ./f_55_5.swift ./f_55_6.swift ./f_55_7.swift ./f_55_8.swift ./f_55_9.swift ./f_55_10.swift
+// RUN: cd %t && touch ./f_56_1.swift ./f_56_2.swift ./f_56_3.swift ./f_56_4.swift ./f_56_5.swift ./f_56_6.swift ./f_56_7.swift ./f_56_8.swift ./f_56_9.swift ./f_56_10.swift
+// RUN: cd %t && touch ./f_57_1.swift ./f_57_2.swift ./f_57_3.swift ./f_57_4.swift ./f_57_5.swift ./f_57_6.swift ./f_57_7.swift ./f_57_8.swift ./f_57_9.swift ./f_57_10.swift
+// RUN: cd %t && touch ./f_58_1.swift ./f_58_2.swift ./f_58_3.swift ./f_58_4.swift ./f_58_5.swift ./f_58_6.swift ./f_58_7.swift ./f_58_8.swift ./f_58_9.swift ./f_58_10.swift
+// RUN: cd %t && touch ./f_59_1.swift ./f_59_2.swift ./f_59_3.swift ./f_59_4.swift ./f_59_5.swift ./f_59_6.swift ./f_59_7.swift ./f_59_8.swift ./f_59_9.swift ./f_59_10.swift
+// RUN: cd %t && touch ./f_60_1.swift ./f_60_2.swift ./f_60_3.swift ./f_60_4.swift ./f_60_5.swift ./f_60_6.swift ./f_60_7.swift ./f_60_8.swift ./f_60_9.swift ./f_60_10.swift
+// RUN: cd %t && touch ./f_61_1.swift ./f_61_2.swift ./f_61_3.swift ./f_61_4.swift ./f_61_5.swift ./f_61_6.swift ./f_61_7.swift ./f_61_8.swift ./f_61_9.swift ./f_61_10.swift
+// RUN: cd %t && touch ./f_62_1.swift ./f_62_2.swift ./f_62_3.swift ./f_62_4.swift ./f_62_5.swift ./f_62_6.swift ./f_62_7.swift ./f_62_8.swift ./f_62_9.swift ./f_62_10.swift
+// RUN: cd %t && touch ./f_63_1.swift ./f_63_2.swift ./f_63_3.swift ./f_63_4.swift ./f_63_5.swift ./f_63_6.swift ./f_63_7.swift ./f_63_8.swift ./f_63_9.swift ./f_63_10.swift
+// RUN: cd %t && touch ./f_64_1.swift ./f_64_2.swift ./f_64_3.swift ./f_64_4.swift ./f_64_5.swift ./f_64_6.swift ./f_64_7.swift ./f_64_8.swift ./f_64_9.swift ./f_64_10.swift
+// RUN: cd %t && touch ./f_65_1.swift ./f_65_2.swift ./f_65_3.swift ./f_65_4.swift ./f_65_5.swift ./f_65_6.swift ./f_65_7.swift ./f_65_8.swift ./f_65_9.swift ./f_65_10.swift
+// RUN: cd %t && touch ./f_66_1.swift ./f_66_2.swift ./f_66_3.swift ./f_66_4.swift ./f_66_5.swift ./f_66_6.swift ./f_66_7.swift ./f_66_8.swift ./f_66_9.swift ./f_66_10.swift
+// RUN: cd %t && touch ./f_67_1.swift ./f_67_2.swift ./f_67_3.swift ./f_67_4.swift ./f_67_5.swift ./f_67_6.swift ./f_67_7.swift ./f_67_8.swift ./f_67_9.swift ./f_67_10.swift
+// RUN: cd %t && touch ./f_68_1.swift ./f_68_2.swift ./f_68_3.swift ./f_68_4.swift ./f_68_5.swift ./f_68_6.swift ./f_68_7.swift ./f_68_8.swift ./f_68_9.swift ./f_68_10.swift
+// RUN: cd %t && touch ./f_69_1.swift ./f_69_2.swift ./f_69_3.swift ./f_69_4.swift ./f_69_5.swift ./f_69_6.swift ./f_69_7.swift ./f_69_8.swift ./f_69_9.swift ./f_69_10.swift
+// RUN: cd %t && touch ./f_70_1.swift ./f_70_2.swift ./f_70_3.swift ./f_70_4.swift ./f_70_5.swift ./f_70_6.swift ./f_70_7.swift ./f_70_8.swift ./f_70_9.swift ./f_70_10.swift
+// RUN: cd %t && touch ./f_71_1.swift ./f_71_2.swift ./f_71_3.swift ./f_71_4.swift ./f_71_5.swift ./f_71_6.swift ./f_71_7.swift ./f_71_8.swift ./f_71_9.swift ./f_71_10.swift
+// RUN: cd %t && touch ./f_72_1.swift ./f_72_2.swift ./f_72_3.swift ./f_72_4.swift ./f_72_5.swift ./f_72_6.swift ./f_72_7.swift ./f_72_8.swift ./f_72_9.swift ./f_72_10.swift
+// RUN: cd %t && touch ./f_73_1.swift ./f_73_2.swift ./f_73_3.swift ./f_73_4.swift ./f_73_5.swift ./f_73_6.swift ./f_73_7.swift ./f_73_8.swift ./f_73_9.swift ./f_73_10.swift
+// RUN: cd %t && touch ./f_74_1.swift ./f_74_2.swift ./f_74_3.swift ./f_74_4.swift ./f_74_5.swift ./f_74_6.swift ./f_74_7.swift ./f_74_8.swift ./f_74_9.swift ./f_74_10.swift
+// RUN: cd %t && touch ./f_75_1.swift ./f_75_2.swift ./f_75_3.swift ./f_75_4.swift ./f_75_5.swift ./f_75_6.swift ./f_75_7.swift ./f_75_8.swift ./f_75_9.swift ./f_75_10.swift
+// RUN: cd %t && touch ./f_76_1.swift ./f_76_2.swift ./f_76_3.swift ./f_76_4.swift ./f_76_5.swift ./f_76_6.swift ./f_76_7.swift ./f_76_8.swift ./f_76_9.swift ./f_76_10.swift
+// RUN: cd %t && touch ./f_77_1.swift ./f_77_2.swift ./f_77_3.swift ./f_77_4.swift ./f_77_5.swift ./f_77_6.swift ./f_77_7.swift ./f_77_8.swift ./f_77_9.swift ./f_77_10.swift
+// RUN: cd %t && touch ./f_78_1.swift ./f_78_2.swift ./f_78_3.swift ./f_78_4.swift ./f_78_5.swift ./f_78_6.swift ./f_78_7.swift ./f_78_8.swift ./f_78_9.swift ./f_78_10.swift
+// RUN: cd %t && touch ./f_79_1.swift ./f_79_2.swift ./f_79_3.swift ./f_79_4.swift ./f_79_5.swift ./f_79_6.swift ./f_79_7.swift ./f_79_8.swift ./f_79_9.swift ./f_79_10.swift
+// RUN: cd %t && touch ./f_80_1.swift ./f_80_2.swift ./f_80_3.swift ./f_80_4.swift ./f_80_5.swift ./f_80_6.swift ./f_80_7.swift ./f_80_8.swift ./f_80_9.swift ./f_80_10.swift
+// RUN: cd %t && touch ./f_81_1.swift ./f_81_2.swift ./f_81_3.swift ./f_81_4.swift ./f_81_5.swift ./f_81_6.swift ./f_81_7.swift ./f_81_8.swift ./f_81_9.swift ./f_81_10.swift
+// RUN: cd %t && touch ./f_82_1.swift ./f_82_2.swift ./f_82_3.swift ./f_82_4.swift ./f_82_5.swift ./f_82_6.swift ./f_82_7.swift ./f_82_8.swift ./f_82_9.swift ./f_82_10.swift
+// RUN: cd %t && touch ./f_83_1.swift ./f_83_2.swift ./f_83_3.swift ./f_83_4.swift ./f_83_5.swift ./f_83_6.swift ./f_83_7.swift ./f_83_8.swift ./f_83_9.swift ./f_83_10.swift
+// RUN: cd %t && touch ./f_84_1.swift ./f_84_2.swift ./f_84_3.swift ./f_84_4.swift ./f_84_5.swift ./f_84_6.swift ./f_84_7.swift ./f_84_8.swift ./f_84_9.swift ./f_84_10.swift
+// RUN: cd %t && touch ./f_85_1.swift ./f_85_2.swift ./f_85_3.swift ./f_85_4.swift ./f_85_5.swift ./f_85_6.swift ./f_85_7.swift ./f_85_8.swift ./f_85_9.swift ./f_85_10.swift
+// RUN: cd %t && touch ./f_86_1.swift ./f_86_2.swift ./f_86_3.swift ./f_86_4.swift ./f_86_5.swift ./f_86_6.swift ./f_86_7.swift ./f_86_8.swift ./f_86_9.swift ./f_86_10.swift
+// RUN: cd %t && touch ./f_87_1.swift ./f_87_2.swift ./f_87_3.swift ./f_87_4.swift ./f_87_5.swift ./f_87_6.swift ./f_87_7.swift ./f_87_8.swift ./f_87_9.swift ./f_87_10.swift
+// RUN: cd %t && touch ./f_88_1.swift ./f_88_2.swift ./f_88_3.swift ./f_88_4.swift ./f_88_5.swift ./f_88_6.swift ./f_88_7.swift ./f_88_8.swift ./f_88_9.swift ./f_88_10.swift
+// RUN: cd %t && touch ./f_89_1.swift ./f_89_2.swift ./f_89_3.swift ./f_89_4.swift ./f_89_5.swift ./f_89_6.swift ./f_89_7.swift ./f_89_8.swift ./f_89_9.swift ./f_89_10.swift
+// RUN: cd %t && touch ./f_90_1.swift ./f_90_2.swift ./f_90_3.swift ./f_90_4.swift ./f_90_5.swift ./f_90_6.swift ./f_90_7.swift ./f_90_8.swift ./f_90_9.swift ./f_90_10.swift
+// RUN: cd %t && touch ./f_91_1.swift ./f_91_2.swift ./f_91_3.swift ./f_91_4.swift ./f_91_5.swift ./f_91_6.swift ./f_91_7.swift ./f_91_8.swift ./f_91_9.swift ./f_91_10.swift
+// RUN: cd %t && touch ./f_92_1.swift ./f_92_2.swift ./f_92_3.swift ./f_92_4.swift ./f_92_5.swift ./f_92_6.swift ./f_92_7.swift ./f_92_8.swift ./f_92_9.swift ./f_92_10.swift
+// RUN: cd %t && touch ./f_93_1.swift ./f_93_2.swift ./f_93_3.swift ./f_93_4.swift ./f_93_5.swift ./f_93_6.swift ./f_93_7.swift ./f_93_8.swift ./f_93_9.swift ./f_93_10.swift
+// RUN: cd %t && touch ./f_94_1.swift ./f_94_2.swift ./f_94_3.swift ./f_94_4.swift ./f_94_5.swift ./f_94_6.swift ./f_94_7.swift ./f_94_8.swift ./f_94_9.swift ./f_94_10.swift
+// RUN: cd %t && touch ./f_95_1.swift ./f_95_2.swift ./f_95_3.swift ./f_95_4.swift ./f_95_5.swift ./f_95_6.swift ./f_95_7.swift ./f_95_8.swift ./f_95_9.swift ./f_95_10.swift
+// RUN: cd %t && touch ./f_96_1.swift ./f_96_2.swift ./f_96_3.swift ./f_96_4.swift ./f_96_5.swift ./f_96_6.swift ./f_96_7.swift ./f_96_8.swift ./f_96_9.swift ./f_96_10.swift
+// RUN: cd %t && touch ./f_97_1.swift ./f_97_2.swift ./f_97_3.swift ./f_97_4.swift ./f_97_5.swift ./f_97_6.swift ./f_97_7.swift ./f_97_8.swift ./f_97_9.swift ./f_97_10.swift
+// RUN: cd %t && touch ./f_98_1.swift ./f_98_2.swift ./f_98_3.swift ./f_98_4.swift ./f_98_5.swift ./f_98_6.swift ./f_98_7.swift ./f_98_8.swift ./f_98_9.swift ./f_98_10.swift
+// RUN: cd %t && touch ./f_99_1.swift ./f_99_2.swift ./f_99_3.swift ./f_99_4.swift ./f_99_5.swift ./f_99_6.swift ./f_99_7.swift ./f_99_8.swift ./f_99_9.swift ./f_99_10.swift
+// RUN: cd %t && touch ./f_100_1.swift ./f_100_2.swift ./f_100_3.swift ./f_100_4.swift ./f_100_5.swift ./f_100_6.swift ./f_100_7.swift ./f_100_8.swift ./f_100_9.swift ./f_100_10.swift
+// RUN: mkdir -p ./additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/
// Force the repartitioning:
-// RUN: %swiftc_driver -driver-show-job-lifecycle -driver-batch-size-limit 10000 -driver-force-one-batch-repartition -v -c -module-name foo -o %t/additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/foo.o -emit-module -serialize-diagnostics -emit-dependencies -j 1 -enable-batch-mode %t/f_*.swift >%t/out.txt 2>&1
+// RUN: cd %t && %swiftc_driver -driver-show-job-lifecycle -driver-batch-size-limit 10000 -driver-force-one-batch-repartition -v -c -module-name foo -o ./additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/foo.o -emit-module -serialize-diagnostics -emit-dependencies -j 1 -enable-batch-mode ./f_*.swift >./out.txt 2>&1
// RUN: %FileCheck %s <%t/out.txt
// CHECK-NOT: unable to execute command
// CHECK: Forming into 1 batches
@@ -113,9 +113,9 @@
// CHECK: Forming batch job from 500 constituents
//
// Try it without the force; supplementary output file maps should obviate the repartition:
-// RUN: %swiftc_driver -driver-show-job-lifecycle -driver-batch-size-limit 10000 -v -c -module-name foo -o %t/additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/foo.o -emit-module -serialize-diagnostics -emit-dependencies -j 1 -enable-batch-mode %t/f_*.swift >%t/out2.txt 2>&1
+// RUN: cd %t && %swiftc_driver -driver-show-job-lifecycle -driver-batch-size-limit 10000 -v -c -module-name foo -o ./additional/path/elements/often/make/filenames/longer/than/one/might/expect/especially/given/output/directories/deep/within/a/derived/data/folder/of/a/CI/machine/foo.o -emit-module -serialize-diagnostics -emit-dependencies -j 1 -enable-batch-mode ./f_*.swift >./out2.txt 2>&1
// RUN: %FileCheck %s <%t/out2.txt -check-prefix=NO-REPARTITION
-// CHECK-NOT: unable to execute command
+// NO-REPARTITION-NOT: unable to execute command
// NO-REPARTITION: Forming into 1 batches
// NO-REPARTITION: Forming batch job from 1000 constituents
// NO-REPARTITION-NOT: Forming into 2 batches