Skip to content

Commit a27fdad

Browse files
committed
Provide fallback SourceLoc for swiftinterface build errors
When a swiftinterface fails to build for any of various reasons, we try to diagnose the failure at the site of the `import` declaration. But if the import is implicitly added—which happens for many SDK modules, like the standard library and ClangImporter overlays—there is no source location for the import, so the error ends up being diagnosed at <unknown>:0. This causes a number of issues; most notably, Xcode doesn’t display the diagnostic as prominently as others. This change falls back to diagnosing the error at line 1, column 1 of the swiftinterface file itself. This is perhaps not an ideal location, and it won’t help with I/O errors where we can’t open the swiftinterface file (and therefore can’t diagnose an error in it), but it should improve the way we display most module interface building errors.
1 parent a7a5e34 commit a27fdad

File tree

3 files changed

+34
-21
lines changed

3 files changed

+34
-21
lines changed

lib/Frontend/ModuleInterfaceBuilder.cpp

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,11 @@ void ModuleInterfaceBuilder::configureSubInvocation(
137137
bool ModuleInterfaceBuilder::extractSwiftInterfaceVersionAndArgs(
138138
swift::version::Version &Vers, StringRef &CompilerVersion,
139139
llvm::StringSaver &SubArgSaver, SmallVectorImpl<const char *> &SubArgs) {
140+
llvm::vfs::FileSystem &fs = *sourceMgr.getFileSystem();
140141
auto FileOrError = swift::vfs::getFileOrSTDIN(fs, interfacePath);
141142
if (!FileOrError) {
143+
// Don't use this->diagnose() because it'll just try to re-open
144+
// interfacePath.
142145
diags.diagnose(diagnosticLoc, diag::error_open_input_file,
143146
interfacePath, FileOrError.getError().message());
144147
return true;
@@ -149,17 +152,16 @@ bool ModuleInterfaceBuilder::extractSwiftInterfaceVersionAndArgs(
149152
auto FlagRe = getSwiftInterfaceModuleFlagsRegex();
150153
SmallVector<StringRef, 1> VersMatches, FlagMatches, CompMatches;
151154
if (!VersRe.match(SB, &VersMatches)) {
152-
diags.diagnose(diagnosticLoc,
153-
diag::error_extracting_version_from_module_interface);
155+
diagnose(diag::error_extracting_version_from_module_interface);
154156
return true;
155157
}
156158
if (!FlagRe.match(SB, &FlagMatches)) {
157-
diags.diagnose(diagnosticLoc,
158-
diag::error_extracting_flags_from_module_interface);
159+
diagnose(diag::error_extracting_flags_from_module_interface);
159160
return true;
160161
}
161162
assert(VersMatches.size() == 2);
162163
assert(FlagMatches.size() == 2);
164+
// FIXME We should diagnose this at a location that makes sense:
163165
Vers = swift::version::Version(VersMatches[1], SourceLoc(), &diags);
164166
llvm::cl::TokenizeGNUCommandLine(FlagMatches[1], SubArgSaver, SubArgs);
165167

@@ -178,6 +180,8 @@ bool ModuleInterfaceBuilder::extractSwiftInterfaceVersionAndArgs(
178180
bool ModuleInterfaceBuilder::collectDepsForSerialization(
179181
CompilerInstance &SubInstance, SmallVectorImpl<FileDependency> &Deps,
180182
bool IsHashBased) {
183+
llvm::vfs::FileSystem &fs = *sourceMgr.getFileSystem();
184+
181185
auto &Opts = SubInstance.getASTContext().SearchPathOpts;
182186
SmallString<128> SDKPath(Opts.SDKPath);
183187
path::native(SDKPath);
@@ -267,6 +271,8 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
267271
llvm::RestorePrettyStackState(savedInnerPrettyStackState);
268272
};
269273

274+
llvm::vfs::FileSystem &fs = *sourceMgr.getFileSystem();
275+
270276
// Note that we don't assume cachePath is the same as the Clang
271277
// module cache path at this point.
272278
if (!moduleCachePath.empty())
@@ -296,9 +302,8 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
296302
// minor versions might be interesting for debugging, or special-casing a
297303
// compatible field variant.
298304
if (Vers.asMajorVersion() != InterfaceFormatVersion.asMajorVersion()) {
299-
diags.diagnose(diagnosticLoc,
300-
diag::unsupported_version_of_module_interface,
301-
interfacePath, Vers);
305+
diagnose(diag::unsupported_version_of_module_interface, interfacePath,
306+
Vers);
302307
SubError = true;
303308
return;
304309
}
@@ -313,8 +318,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
313318
auto DiagKind = diag::serialization_name_mismatch;
314319
if (subInvocation.getLangOptions().DebuggerSupport)
315320
DiagKind = diag::serialization_name_mismatch_repl;
316-
diags.diagnose(diagnosticLoc, DiagKind, subInvocation.getModuleName(),
317-
ExpectedModuleName);
321+
diagnose(DiagKind, subInvocation.getModuleName(), ExpectedModuleName);
318322
SubError = true;
319323
return;
320324
}
@@ -341,9 +345,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
341345
auto builtByCompiler =
342346
getSwiftInterfaceCompilerVersionForCurrentCompiler(
343347
SubInstance.getASTContext());
344-
diags.diagnose(diagnosticLoc, diag::module_interface_build_failed,
345-
moduleName, emittedByCompiler == builtByCompiler,
346-
emittedByCompiler, builtByCompiler);
348+
diagnose(diag::module_interface_build_failed, moduleName,
349+
emittedByCompiler == builtByCompiler, emittedByCompiler,
350+
builtByCompiler);
347351
}
348352
};
349353

@@ -439,8 +443,7 @@ bool ModuleInterfaceBuilder::buildSwiftModule(StringRef OutPath,
439443
// necessary for performance. Fallback to building the module in case of any lock
440444
// related errors.
441445
if (RemarkRebuild) {
442-
diags.diagnose(SourceLoc(), diag::interface_file_lock_failure,
443-
interfacePath);
446+
diagnose(diag::interface_file_lock_failure, interfacePath);
444447
}
445448
// Clear out any potential leftover.
446449
Locked.unsafeRemoveLockFile();
@@ -472,8 +475,7 @@ bool ModuleInterfaceBuilder::buildSwiftModule(StringRef OutPath,
472475
// another process to complete the build so swift does not do it done
473476
// twice. If case of timeout, build it ourselves.
474477
if (RemarkRebuild) {
475-
diags.diagnose(SourceLoc(), diag::interface_file_lock_timed_out,
476-
interfacePath);
478+
diagnose(diag::interface_file_lock_timed_out, interfacePath);
477479
}
478480
// Clear the lock file so that future invocations can make progress.
479481
Locked.unsafeRemoveLockFile();

lib/Frontend/ModuleInterfaceBuilder.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class SearchPathOptions;
3333
class DependencyTracker;
3434

3535
class ModuleInterfaceBuilder {
36-
llvm::vfs::FileSystem &fs;
36+
SourceManager &sourceMgr;
3737
DiagnosticEngine &diags;
3838
const StringRef interfacePath;
3939
const StringRef moduleName;
@@ -48,6 +48,19 @@ class ModuleInterfaceBuilder {
4848
CompilerInvocation subInvocation;
4949
SmallVector<StringRef, 3> extraDependencies;
5050

51+
/// Emit a diagnostic tied to this declaration.
52+
template<typename ...ArgTypes>
53+
InFlightDiagnostic diagnose(
54+
Diag<ArgTypes...> ID,
55+
typename detail::PassArgument<ArgTypes>::type... Args) const {
56+
SourceLoc loc = diagnosticLoc;
57+
if (loc.isInvalid()) {
58+
// Diagnose this inside the interface file, if possible.
59+
loc = sourceMgr.getLocFromExternalSource(interfacePath, 1, 1);
60+
}
61+
return diags.diagnose(loc, ID, std::move(Args)...);
62+
}
63+
5164
void configureSubInvocationInputsAndOutputs(StringRef OutPath);
5265

5366
void configureSubInvocation(const SearchPathOptions &SearchPathOpts,
@@ -86,7 +99,7 @@ class ModuleInterfaceBuilder {
8699
bool disableInterfaceFileLock = false,
87100
SourceLoc diagnosticLoc = SourceLoc(),
88101
DependencyTracker *tracker = nullptr)
89-
: fs(*sourceMgr.getFileSystem()), diags(diags),
102+
: sourceMgr(sourceMgr), diags(diags),
90103
interfacePath(interfacePath), moduleName(moduleName),
91104
moduleCachePath(moduleCachePath), prebuiltCachePath(prebuiltCachePath),
92105
serializeDependencyHashes(serializeDependencyHashes),

validation-test/ParseableInterface/failing-overlay.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,4 @@
33

44
import ImportsOverlay
55

6-
// FIXME: It would be better if this had a useful location, like inside the
7-
// C header that caused the importing of the overlay.
8-
// CHECK: <unknown>:0: error: failed to build module 'HasOverlay' from its module interface; the compiler that produced it, '(unspecified, file possibly handwritten)', may have used features that aren't supported by this compiler, '{{.*}}Swift version{{.*}}'
6+
// CHECK: HasOverlay.swiftinterface:1:1: error: failed to build module 'HasOverlay' from its module interface; the compiler that produced it, '(unspecified, file possibly handwritten)', may have used features that aren't supported by this compiler, '{{.*}}Swift version{{.*}}'

0 commit comments

Comments
 (0)