[Driver] Make sure to rebuild dependents when a dirty file fails. (#3935)

Otherwise we get into a situation like this:

1. Change made to the interface of file A.swift that also causes an
   error in A.swift.
2. Fixing the error in A.swift does not affect A.swift's interface.
3. File B.swift that depends on A.swift is not rebuilt, since the most
   recent change to A.swift did not change its interface.

To fix this, mark downstream files as needing to be rebuilt even when
a compilation job fails with errors. Additionally, attempt to be extra
conservative when there's a crash.

rdar://problem/25405605
This commit is contained in:
Jordan Rose
2016-08-02 19:07:29 -07:00
committed by GitHub
parent 7383696dce
commit 848b3eb6a3
30 changed files with 533 additions and 79 deletions

View File

@@ -456,6 +456,70 @@ int Compilation::performJobsImpl() {
llvm::errs() << Output;
}
// In order to handle both old dependencies that have disappeared and new
// dependencies that have arisen, we need to reload the dependency file.
// Do this whether or not the build succeeded.
SmallVector<const Job *, 16> Dependents;
if (getIncrementalBuildEnabled()) {
const CommandOutput &Output = FinishedCmd->getOutput();
StringRef DependenciesFile =
Output.getAdditionalOutputForType(types::TY_SwiftDeps);
if (!DependenciesFile.empty() &&
(ReturnCode == EXIT_SUCCESS || ReturnCode == EXIT_FAILURE)) {
bool wasCascading = DepGraph.isMarked(FinishedCmd);
switch (DepGraph.loadFromPath(FinishedCmd, DependenciesFile)) {
case DependencyGraphImpl::LoadResult::HadError:
if (ReturnCode == EXIT_SUCCESS) {
disableIncrementalBuild();
for (const Job *Cmd : DeferredCommands)
scheduleCommandIfNecessaryAndPossible(Cmd);
DeferredCommands.clear();
Dependents.clear();
} // else, let the next build handle it.
break;
case DependencyGraphImpl::LoadResult::UpToDate:
if (!wasCascading)
break;
SWIFT_FALLTHROUGH;
case DependencyGraphImpl::LoadResult::AffectsDownstream:
llvm::errs() << "DOWNSTREAM " << ReturnCode << "\n";
DepGraph.markTransitive(Dependents, FinishedCmd);
break;
}
} else {
// If there's a crash, assume the worst.
switch (FinishedCmd->getCondition()) {
case Job::Condition::NewlyAdded:
// The job won't be treated as newly added next time. Conservatively
// mark it as affecting other jobs, because some of them may have
// completed already.
DepGraph.markTransitive(Dependents, FinishedCmd);
break;
case Job::Condition::Always:
// This applies to non-incremental tasks as well, but any incremental
// task that shows up here has already been marked.
break;
case Job::Condition::RunWithoutCascading:
// If this file changed, it might have been a non-cascading change and
// it might not. Unfortunately, the interface hash has been updated or
// compromised, so we don't actually know anymore; we have to
// conservatively assume the changes could affect other files.
DepGraph.markTransitive(Dependents, FinishedCmd);
break;
case Job::Condition::CheckDependencies:
// If the only reason we're running this is because something else
// changed, then we can trust the dependency graph as to whether it's
// a cascading or non-cascading change. That is, if whatever /caused/
// the error isn't supposed to affect other files, and whatever
// /fixes/ the error isn't supposed to affect other files, then
// there's no need to recompile any other inputs. If either of those
// are false, we /do/ need to recompile other inputs.
break;
}
}
}
if (ReturnCode != EXIT_SUCCESS) {
// The task failed, so return true without performing any further
// dependency analysis.
@@ -481,39 +545,10 @@ int Compilation::performJobsImpl() {
// might have been blocked.
markFinished(FinishedCmd);
// In order to handle both old dependencies that have disappeared and new
// dependencies that have arisen, we need to reload the dependency file.
if (getIncrementalBuildEnabled()) {
const CommandOutput &Output = FinishedCmd->getOutput();
StringRef DependenciesFile =
Output.getAdditionalOutputForType(types::TY_SwiftDeps);
if (!DependenciesFile.empty()) {
SmallVector<const Job *, 16> Dependents;
bool wasCascading = DepGraph.isMarked(FinishedCmd);
switch (DepGraph.loadFromPath(FinishedCmd, DependenciesFile)) {
case DependencyGraphImpl::LoadResult::HadError:
disableIncrementalBuild();
for (const Job *Cmd : DeferredCommands)
scheduleCommandIfNecessaryAndPossible(Cmd);
DeferredCommands.clear();
Dependents.clear();
break;
case DependencyGraphImpl::LoadResult::UpToDate:
if (!wasCascading)
break;
SWIFT_FALLTHROUGH;
case DependencyGraphImpl::LoadResult::AffectsDownstream:
DepGraph.markTransitive(Dependents, FinishedCmd);
break;
}
for (const Job *Cmd : Dependents) {
DeferredCommands.erase(Cmd);
noteBuilding(Cmd, "because of dependencies discovered later");
scheduleCommandIfNecessaryAndPossible(Cmd);
}
}
for (const Job *Cmd : Dependents) {
DeferredCommands.erase(Cmd);
noteBuilding(Cmd, "because of dependencies discovered later");
scheduleCommandIfNecessaryAndPossible(Cmd);
}
return TaskFinishedResponse::ContinueExecution;

View File

@@ -1604,36 +1604,40 @@ handleCompileJobCondition(Job *J, CompileJobAction::InputInfo inputInfo,
return;
}
if (!alwaysRebuildDependents) {
// Default all non-newly added files to being rebuilt without cascading.
J->setCondition(Job::Condition::RunWithoutCascading);
}
bool hasValidModTime = false;
llvm::sys::fs::file_status inputStatus;
if (llvm::sys::fs::status(input, inputStatus))
return;
J->setInputModTime(inputStatus.getLastModificationTime());
if (J->getInputModTime() != inputInfo.previousModTime)
return;
if (!llvm::sys::fs::status(input, inputStatus)) {
J->setInputModTime(inputStatus.getLastModificationTime());
hasValidModTime = true;
}
Job::Condition condition;
switch (inputInfo.status) {
case CompileJobAction::InputInfo::UpToDate:
if (!llvm::sys::fs::exists(J->getOutput().getPrimaryOutputFilename()))
if (!hasValidModTime || J->getInputModTime() != inputInfo.previousModTime) {
if (alwaysRebuildDependents ||
inputInfo.status == CompileJobAction::InputInfo::NeedsCascadingBuild) {
condition = Job::Condition::Always;
} else {
condition = Job::Condition::RunWithoutCascading;
else
condition = Job::Condition::CheckDependencies;
break;
case CompileJobAction::InputInfo::NeedsCascadingBuild:
condition = Job::Condition::Always;
break;
case CompileJobAction::InputInfo::NeedsNonCascadingBuild:
condition = Job::Condition::RunWithoutCascading;
break;
case CompileJobAction::InputInfo::NewlyAdded:
llvm_unreachable("handled above");
}
} else {
switch (inputInfo.status) {
case CompileJobAction::InputInfo::UpToDate:
if (!llvm::sys::fs::exists(J->getOutput().getPrimaryOutputFilename()))
condition = Job::Condition::RunWithoutCascading;
else
condition = Job::Condition::CheckDependencies;
break;
case CompileJobAction::InputInfo::NeedsCascadingBuild:
condition = Job::Condition::Always;
break;
case CompileJobAction::InputInfo::NeedsNonCascadingBuild:
condition = Job::Condition::RunWithoutCascading;
break;
case CompileJobAction::InputInfo::NewlyAdded:
llvm_unreachable("handled above");
}
}
J->setCondition(condition);
}

View File

@@ -0,0 +1,2 @@
# Dependencies after compilation:
provides-top-level: [a]

View File

@@ -0,0 +1,2 @@
# Dependencies after compilation:
depends-top-level: [a]

View File

@@ -0,0 +1,2 @@
# Dependencies after compilation:
depends-top-level: [!private a]

View File

@@ -0,0 +1,17 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./crash.swift": {
"object": "./crash.o",
"swift-dependencies": "./crash.swiftdeps"
},
"./other.swift": {
"object": "./other.o",
"swift-dependencies": "./other.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -0,0 +1,4 @@
# Dependencies after compilation:
provides-top-level: [bad]
interface-hash: "after"
garbage: ""

View File

@@ -0,0 +1,3 @@
# Dependencies before compilation:
provides-top-level: [bad]
interface-hash: "before"

View File

@@ -0,0 +1,3 @@
# Dependencies after compilation:
depends-top-level: [bad]
interface-hash: "after"

View File

@@ -0,0 +1,3 @@
# Dependencies before compilation:
depends-top-level: [bad]
interface-hash: "before"

View File

@@ -0,0 +1,3 @@
# Dependencies after compilation:
depends-top-level: [main]
interface-hash: "after"

View File

@@ -0,0 +1,3 @@
# Dependencies before compilation:
depends-top-level: [main]
interface-hash: "before"

View File

@@ -0,0 +1,3 @@
# Dependencies after compilation:
provides-top-level: [main]
interface-hash: "after"

View File

@@ -0,0 +1,3 @@
# Dependencies before compilation:
provides-top-level: [main]
interface-hash: "before"

View File

@@ -0,0 +1,21 @@
{
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps"
},
"./bad.swift": {
"object": "./bad.o",
"swift-dependencies": "./bad.swiftdeps"
},
"./depends-on-main.swift": {
"object": "./depends-on-main.o",
"swift-dependencies": "./depends-on-main.swiftdeps"
},
"./depends-on-bad.swift": {
"object": "./depends-on-bad.o",
"swift-dependencies": "./depends-on-bad.swiftdeps"
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -11,23 +11,38 @@
#
# ----------------------------------------------------------------------------
#
# Fails if the input file is named "bad.swift"; otherwise dispatches to
# update-dependencies.py.
# Fails if the input file is named "bad.swift" or "crash.swift"; otherwise
# dispatches to update-dependencies.py. "crash.swift" gives an exit code
# other than 1.
#
# ----------------------------------------------------------------------------
from __future__ import print_function
import os
import shutil
import sys
assert sys.argv[1] == '-frontend'
primaryFile = sys.argv[sys.argv.index('-primary-file') + 1]
if os.path.basename(primaryFile) == 'bad.swift':
if (os.path.basename(primaryFile) == 'bad.swift' or
os.path.basename(primaryFile) == 'crash.swift'):
print("Handled", os.path.basename(primaryFile))
sys.exit(1)
# Replace the dependencies file with the input file.
try:
depsFile = sys.argv[sys.argv.index(
'-emit-reference-dependencies-path') + 1]
shutil.copyfile(primaryFile, depsFile)
except ValueError:
pass
if os.path.basename(primaryFile) == 'bad.swift':
sys.exit(1)
else:
sys.exit(129)
dir = os.path.dirname(os.path.abspath(__file__))
execfile(os.path.join(dir, "update-dependencies.py"))

View File

@@ -1,12 +1,17 @@
// RUN: rm -rf %t && cp -r %S/Inputs/bindings-build-record/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC-INITIAL
// MUST-EXEC-NOT: warning
// MUST-EXEC: inputs: ["./main.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// MUST-EXEC: inputs: ["./other.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// MUST-EXEC: inputs: ["./yet-another.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// MUST-EXEC-INITIAL-NOT: warning
// MUST-EXEC-INITIAL: inputs: ["./main.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// MUST-EXEC-INITIAL: inputs: ["./other.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// MUST-EXEC-INITIAL: inputs: ["./yet-another.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// MUST-EXEC-ALL-NOT: warning
// MUST-EXEC-ALL: inputs: ["./main.swift"], output: {{[{].*[}]$}}
// MUST-EXEC-ALL: inputs: ["./other.swift"], output: {{[{].*[}]$}}
// MUST-EXEC-ALL: inputs: ["./yet-another.swift"], output: {{[{].*[}]$}}
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-use-frontend-path %S/Inputs/update-dependencies.py ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
@@ -19,28 +24,28 @@
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings -serialize-diagnostics ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -O -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -O -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC-ALL
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-use-frontend-path %S/Inputs/update-dependencies.py ./main.swift ./other.swift ./yet-another.swift -incremental -O -output-file-map %t/output.json
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -O -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -O -serialize-diagnostics -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -Onone -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -Onone -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC-ALL
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-use-frontend-path %S/Inputs/update-dependencies.py ./main.swift ./other.swift ./yet-another.swift -incremental -Onone -output-file-map %t/output.json
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -Onone -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC-ALL
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-use-frontend-path %S/Inputs/update-dependencies.py ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC-ALL
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-use-frontend-path %S/Inputs/update-dependencies.py ./main.swift ./other.swift ./yet-another.swift -incremental -I. -output-file-map %t/output.json
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -I/ -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -I/ -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC-ALL
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-use-frontend-path %S/Inputs/update-dependencies.py ./main.swift ./other.swift ./yet-another.swift -incremental -I. -I/ -output-file-map %t/output.json
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -I/ -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -DDEBUG -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -DDEBUG -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC-ALL
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-use-frontend-path %S/Inputs/update-dependencies.py ./main.swift ./other.swift ./yet-another.swift -incremental -I. -DDEBUG -output-file-map %t/output.json
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -I. -DDEBUG -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC
// RUN: cd %t && %swiftc_driver -c -module-name main -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -DDEBUG -I. -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=NO-EXEC

View File

@@ -37,10 +37,15 @@
// RUN: %S/Inputs/touch.py 443865900 %t/*
// RUN: cd %t && %swiftc_driver -driver-print-bindings ./main.swift ./other.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=FILE-REMOVED
// FILE-REMOVED: inputs: ["./main.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// FILE-REMOVED: inputs: ["./other.swift"], output: {{[{].*[}]}}, condition: run-without-cascading
// FILE-REMOVED: inputs: ["./main.swift"], output: {{[{].*[}]$}}
// FILE-REMOVED: inputs: ["./other.swift"], output: {{[{].*[}]$}}
// FILE-REMOVED-NOT: yet-another.swift
// RUN: echo '{version: "bogus", inputs: {"./main.swift": [443865900, 0], "./other.swift": !private [443865900, 0], "./yet-another.swift": !dirty [443865900, 0]}}' > %t/main~buildrecord.swiftdeps
// RUN: cd %t && %swiftc_driver -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=MUST-EXEC
// RUN: cd %t && %swiftc_driver -driver-print-bindings ./main.swift ./other.swift ./yet-another.swift -incremental -output-file-map %t/output.json 2>&1 | FileCheck %s -check-prefix=INVALID-RECORD
// INVALID-RECORD-NOT: warning
// INVALID-RECORD: inputs: ["./main.swift"], output: {{[{].*[}]$}}
// INVALID-RECORD: inputs: ["./other.swift"], output: {{[{].*[}]$}}
// INVALID-RECORD: inputs: ["./yet-another.swift"], output: {{[{].*[}]$}}

View File

@@ -0,0 +1,30 @@
/// crash ==> main | crash --> other
// RUN: rm -rf %t && cp -r %S/Inputs/crash-simple/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-INITIAL %s
// CHECK-INITIAL-NOT: warning
// CHECK-INITIAL: Handled main.swift
// CHECK-INITIAL: Handled other.swift
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift ./crash.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-ADDED %s
// RUN: FileCheck -check-prefix=CHECK-RECORD-ADDED %s < %t/main~buildrecord.swiftdeps
// CHECK-ADDED-NOT: Handled
// CHECK-ADDED: Handled crash.swift
// CHECK-ADDED-NOT: Handled
// CHECK-RECORD-ADDED-DAG: "./crash.swift": !dirty [
// CHECK-RECORD-ADDED-DAG: "./main.swift": [
// CHECK-RECORD-ADDED-DAG: "./other.swift": [
// RUN: rm -rf %t && cp -r %S/Inputs/crash-simple/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-INITIAL %s
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./crash.swift ./main.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-ADDED %s
// RUN: FileCheck -check-prefix=CHECK-RECORD-ADDED %s < %t/main~buildrecord.swiftdeps

View File

@@ -0,0 +1,44 @@
/// crash ==> main | crash --> other
// RUN: rm -rf %t && cp -r %S/Inputs/crash-simple/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck %s
// CHECK-NOT: warning
// CHECK: Handled main.swift
// CHECK: Handled crash.swift
// CHECK-NOT: Handled other.swift
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-BAD-ONLY %s
// CHECK-BAD-ONLY-NOT: warning
// CHECK-BAD-ONLY-NOT: Handled
// CHECK-BAD-ONLY: Handled crash.swift
// CHECK-BAD-ONLY-NOT: Handled
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-OKAY %s
// CHECK-OKAY: Handled main.swift
// CHECK-OKAY: Handled crash.swift
// CHECK-OKAY: Handled other.swift
// CHECK-OKAY-NOT: Handled
// RUN: touch -t 201401240006 %t/crash.swift
// RUN: rm %t/crash.swiftdeps
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck %s
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-OKAY-2 %s
// CHECK-OKAY-2: Handled crash.swift
// CHECK-OKAY-2: Handled other.swift
// CHECK-OKAY-2: Handled main.swift
// RUN: touch -t 201401240006 %t/main.swift
// RUN: rm %t/main.swiftdeps
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck %s
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-OKAY %s
// RUN: touch -t 201401240006 %t/other.swift
// RUN: rm %t/other.swiftdeps
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck %s

View File

@@ -0,0 +1,23 @@
/// crash ==> main | crash --> other
// RUN: rm -rf %t && cp -r %S/Inputs/crash-simple/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-FIRST %s
// CHECK-FIRST-NOT: warning
// CHECK-FIRST: Handled main.swift
// CHECK-FIRST: Handled crash.swift
// CHECK-FIRST: Handled other.swift
// RUN: touch -t 201401240006 %t/crash.swift
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./crash.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-SECOND %s
// RUN: FileCheck -check-prefix=CHECK-RECORD %s < %t/main~buildrecord.swiftdeps
// CHECK-SECOND: Handled crash.swift
// CHECK-SECOND-NOT: Handled main.swift
// CHECK-SECOND-NOT: Handled other.swift
// CHECK-RECORD-DAG: "./crash.swift": !dirty [
// CHECK-RECORD-DAG: "./main.swift": !dirty [
// CHECK-RECORD-DAG: "./other.swift": !private [

View File

@@ -0,0 +1,30 @@
/// bad ==> main | bad --> other
// RUN: rm -rf %t && cp -r %S/Inputs/fail-simple/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-INITIAL %s
// CHECK-INITIAL-NOT: warning
// CHECK-INITIAL: Handled main.swift
// CHECK-INITIAL: Handled other.swift
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift ./bad.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-ADDED %s
// RUN: FileCheck -check-prefix=CHECK-RECORD-ADDED %s < %t/main~buildrecord.swiftdeps
// CHECK-ADDED-NOT: Handled
// CHECK-ADDED: Handled bad.swift
// CHECK-ADDED-NOT: Handled
// CHECK-RECORD-ADDED-DAG: "./bad.swift": !dirty [
// CHECK-RECORD-ADDED-DAG: "./main.swift": [
// CHECK-RECORD-ADDED-DAG: "./other.swift": [
// RUN: rm -rf %t && cp -r %S/Inputs/fail-simple/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-INITIAL %s
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./bad.swift ./main.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-ADDED %s
// RUN: FileCheck -check-prefix=CHECK-RECORD-ADDED %s < %t/main~buildrecord.swiftdeps

View File

@@ -23,7 +23,7 @@
// CHECK-SECOND: Handled bad.swift
// CHECK-SECOND-NOT: Handled depends
// CHECK-RECORD-DAG: "./bad.swift": !private [
// CHECK-RECORD-DAG: "./bad.swift": !dirty [
// CHECK-RECORD-DAG: "./main.swift": [
// CHECK-RECORD-DAG: "./depends-on-main.swift": !dirty [
// CHECK-RECORD-DAG: "./depends-on-bad.swift": [

View File

@@ -9,19 +9,30 @@
// CHECK: Handled bad.swift
// CHECK-NOT: Handled other.swift
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./bad.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck %s
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./bad.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-BAD-ONLY %s
// CHECK-BAD-ONLY-NOT: warning
// CHECK-BAD-ONLY-NOT: Handled
// CHECK-BAD-ONLY: Handled bad.swift
// CHECK-BAD-ONLY-NOT: Handled
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./bad.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-OKAY %s
// CHECK-OKAY: Handled main.swift
// CHECK-OKAY: Handled bad.swift
// CHECK-OKAY: Handled other.swift
// CHECK-OKAY-NOT: Handled
// RUN: touch -t 201401240006 %t/bad.swift
// RUN: rm %t/bad.swiftdeps
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./bad.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck %s
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./bad.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-OKAY %s
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./bad.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-OKAY-2 %s
// CHECK-OKAY-2: Handled bad.swift
// CHECK-OKAY-2: Handled other.swift
// CHECK-OKAY-2: Handled main.swift
// RUN: touch -t 201401240006 %t/main.swift
// RUN: rm %t/main.swiftdeps
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental -driver-always-rebuild-dependents ./main.swift ./bad.swift ./other.swift -module-name main -j1 -v 2>&1 | FileCheck %s

View File

@@ -0,0 +1,47 @@
/// main ==> depends-on-main | bad ==> depends-on-bad
// RUN: rm -rf %t && cp -r %S/Inputs/fail-with-bad-deps/ %t
// RUN: touch -t 201401240005 %t/*
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental ./main.swift ./bad.swift ./depends-on-main.swift ./depends-on-bad.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-FIRST %s
// CHECK-FIRST-NOT: warning
// CHECK-FIRST: Handled main.swift
// CHECK-FIRST: Handled bad.swift
// CHECK-FIRST: Handled depends-on-main.swift
// CHECK-FIRST: Handled depends-on-bad.swift
// Reset the .swiftdeps files.
// RUN: cp -r %S/Inputs/fail-with-bad-deps/*.swiftdeps %t
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental ./main.swift ./bad.swift ./depends-on-main.swift ./depends-on-bad.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-NONE %s
// CHECK-NONE-NOT: Handled
// Reset the .swiftdeps files.
// RUN: cp -r %S/Inputs/fail-with-bad-deps/*.swiftdeps %t
// RUN: touch -t 201401240006 %t/bad.swift
// RUN: cd %t && %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies.py -output-file-map %t/output.json -incremental ./main.swift ./bad.swift ./depends-on-main.swift ./depends-on-bad.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-BUILD-ALL %s
// CHECK-BUILD-ALL-NOT: warning
// CHECK-BUILD-ALL: Handled bad.swift
// CHECK-BUILD-ALL-DAG: Handled main.swift
// CHECK-BUILD-ALL-DAG: Handled depends-on-main.swift
// CHECK-BUILD-ALL-DAG: Handled depends-on-bad.swift
// Reset the .swiftdeps files.
// RUN: cp -r %S/Inputs/fail-with-bad-deps/*.swiftdeps %t
// RUN: touch -t 201401240007 %t/bad.swift %t/main.swift
// RUN: cd %t && not %swiftc_driver -c -driver-use-frontend-path %S/Inputs/update-dependencies-bad.py -output-file-map %t/output.json -incremental ./main.swift ./bad.swift ./depends-on-main.swift ./depends-on-bad.swift -module-name main -j1 -v 2>&1 | FileCheck -check-prefix=CHECK-WITH-FAIL %s
// RUN: FileCheck -check-prefix=CHECK-RECORD %s < %t/main~buildrecord.swiftdeps
// CHECK-WITH-FAIL: Handled main.swift
// CHECK-WITH-FAIL-NOT: Handled depends
// CHECK-WITH-FAIL: Handled bad.swift
// CHECK-WITH-FAIL-NOT: Handled depends
// CHECK-RECORD-DAG: "./bad.swift": !private [
// CHECK-RECORD-DAG: "./main.swift": [
// CHECK-RECORD-DAG: "./depends-on-main.swift": !dirty [
// CHECK-RECORD-DAG: "./depends-on-bad.swift": [

View File

@@ -0,0 +1,13 @@
enum Foo {
case one
case two
}
func doSomething(_ value: Foo) {
switch value {
case .one:
print("Hello")
case .two:
print("Goodbye")
}
}

View File

@@ -0,0 +1,14 @@
enum Foo {
case one
case two
case three
}
func doSomething(_ value: Foo) {
switch value {
case .one:
print("Hello")
case .two:
print("Goodbye")
}
}

View File

@@ -0,0 +1,15 @@
enum Foo {
case one
case two
case three
}
func doSomething(_ value: Foo) {
switch value {
case .one:
print("Hello")
case .two:
print("Goodbye")
case .three: break
}
}

View File

@@ -0,0 +1,13 @@
{
"./helper.swift": {
"object": "./helper.o",
"swift-dependencies": "./helper.swiftdeps",
},
"./main.swift": {
"object": "./main.o",
"swift-dependencies": "./main.swiftdeps",
},
"": {
"swift-dependencies": "./main~buildrecord.swiftdeps"
}
}

View File

@@ -0,0 +1,81 @@
// RUN: rm -rf %t && mkdir %t
// RUN: cp %s %t/main.swift
// RUN: cp %S/Inputs/rdar25405605/helper-1.swift %t/helper.swift
// RUN: touch -t 201401240005 %t/*.swift
// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar25405605/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | FileCheck -check-prefix=CHECK-1 %s
// CHECK-1-NOT: warning
// CHECK-1: {{^{$}}
// CHECK-1: "kind": "began"
// CHECK-1: "name": "compile"
// CHECK-1: ".\/main.swift"
// CHECK-1: {{^}$}}
// CHECK-1: {{^{$}}
// CHECK-1: "kind": "began"
// CHECK-1: "name": "compile"
// CHECK-1: ".\/helper.swift"
// CHECK-1: {{^}$}}
// RUN: ls %t/ | FileCheck -check-prefix=CHECK-LS %s
// CHECK-LS-DAG: main.o
// CHECK-LS-DAG: helper.o
// RUN: cd %t && %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar25405605/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | FileCheck -check-prefix=CHECK-1-SKIPPED %s
// CHECK-1-SKIPPED-NOT: warning
// CHECK-1-SKIPPED: {{^{$}}
// CHECK-1-SKIPPED: "kind": "skipped"
// CHECK-1-SKIPPED: "name": "compile"
// CHECK-1-SKIPPED: ".\/main.swift"
// CHECK-1-SKIPPED: {{^}$}}
// CHECK-1-SKIPPED: {{^{$}}
// CHECK-1-SKIPPED: "kind": "skipped"
// CHECK-1-SKIPPED: "name": "compile"
// CHECK-1-SKIPPED: ".\/helper.swift"
// CHECK-1-SKIPPED: {{^}$}}
// RUN: cp %S/Inputs/rdar25405605/helper-2.swift %t/helper.swift
// RUN: touch -t 201401240006 %t/helper.swift
// RUN: cd %t && not %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar25405605/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | FileCheck -check-prefix=CHECK-2 %s
// CHECK-2-NOT: warning
// CHECK-2: {{^{$}}
// CHECK-2: "kind": "began"
// CHECK-2: "name": "compile"
// CHECK-2: ".\/helper.swift"
// CHECK-2: {{^}$}}
// CHECK-2: {{^{$}}
// CHECK-2: "kind": "skipped"
// CHECK-2: "name": "compile"
// CHECK-2: ".\/main.swift"
// CHECK-2: {{^}$}}
// RUN: cp %S/Inputs/rdar25405605/helper-3.swift %t/helper.swift
// RUN: touch -t 201401240007 %t/helper.swift
// RUN: cd %t && not %target-build-swift -c -incremental -output-file-map %S/Inputs/rdar25405605/output.json -parse-as-library ./main.swift ./helper.swift -parseable-output -j1 -module-name main 2>&1 | FileCheck -check-prefix=CHECK-3 %s
// CHECK-3-NOT: warning
// CHECK-3: {{^{$}}
// CHECK-3: "kind": "began"
// CHECK-3: "name": "compile"
// CHECK-3: ".\/helper.swift"
// CHECK-3: {{^}$}}
// CHECK-3: {{^{$}}
// CHECK-3: "kind": "began"
// CHECK-3: "name": "compile"
// CHECK-3: ".\/main.swift"
// CHECK-3: {{^}$}}
func foo(_ value: Foo) -> Bool {
switch value {
case .one: return true
case .two: return false
}
}