@@ -157,6 +157,8 @@ const char InvalidRecordKindError::ID = '\0';
157
157
void InvalidRecordKindError::anchor () {}
158
158
const char UnsafeDeserializationError::ID = ' \0 ' ;
159
159
void UnsafeDeserializationError::anchor () {}
160
+ const char ModularizationError::ID = ' \0 ' ;
161
+ void ModularizationError::anchor () {}
160
162
161
163
static llvm::Error consumeErrorIfXRefNonLoadedModule (llvm::Error &&error);
162
164
@@ -179,18 +181,92 @@ void ModuleFile::fatal(llvm::Error error) const {
179
181
Core->fatal (diagnoseFatal (std::move (error)));
180
182
}
181
183
184
+ void
185
+ ModularizationError::diagnose (ASTContext &ctx,
186
+ DiagnosticBehavior limit) const {
187
+ auto kindToDiagId = [&](Kind kind) {
188
+ switch (kind) {
189
+ case Kind::Moved:
190
+ return diag::modularization_issue_moved;
191
+ case Kind::TypeChanged:
192
+ return diag::modularization_issue_type_changed;
193
+ case Kind::NotFound:
194
+ return diag::modularization_issue_not_found;
195
+ }
196
+ llvm_unreachable (" Unhandled ModularizationError::Kind in switch." );
197
+ };
198
+
199
+ // We could pass along the `path` information through notes.
200
+ // However, for a top-level decl a path would just duplicate the
201
+ // expected module name and the decl name from the diagnostic.
202
+ auto inFlight =
203
+ ctx.Diags .diagnose (SourceLoc (), kindToDiagId (kind), name,
204
+ expectedModuleName, referencedFromModuleName,
205
+ foundModuleName);
206
+ inFlight.limitBehavior (limit);
207
+ }
208
+
209
+ void TypeError::diagnose (ASTContext &ctx) const {
210
+ ctx.Diags .diagnose (SourceLoc (),
211
+ diag::modularization_issue_effect_type_error,
212
+ name);
213
+ }
214
+
215
+ void ExtensionError::diagnose (ASTContext &ctx) const {
216
+ ctx.Diags .diagnose (SourceLoc (),
217
+ diag::modularization_issue_effect_extension_error);
218
+ }
219
+
182
220
llvm::Error ModuleFile::diagnoseFatal (llvm::Error error) const {
183
- if (FileContext)
184
- getContext ().Diags .diagnose (SourceLoc (), diag::serialization_fatal,
221
+
222
+ auto &ctx = getContext ();
223
+ if (FileContext) {
224
+ if (ctx.LangOpts .EnableDeserializationRecovery ) {
225
+ // Attempt to report relevant errors as diagnostics.
226
+ // At this time, only ModularizationErrors are reported directly. They
227
+ // can get here either directly or as underlying causes to a TypeError or
228
+ // and ExtensionError.
229
+ auto handleModularizationError =
230
+ [&](const ModularizationError &modularError) -> llvm::Error {
231
+ modularError.diagnose (ctx);
232
+ return llvm::Error::success ();
233
+ };
234
+ error = llvm::handleErrors (std::move (error),
235
+ handleModularizationError,
236
+ [&](TypeError &typeError) -> llvm::Error {
237
+ if (typeError.diagnoseUnderlyingReason (handleModularizationError)) {
238
+ typeError.diagnose (ctx);
239
+ return llvm::Error::success ();
240
+ }
241
+ return llvm::make_error<TypeError>(std::move (typeError));
242
+ },
243
+ [&](ExtensionError &extError) -> llvm::Error {
244
+ if (extError.diagnoseUnderlyingReason (handleModularizationError)) {
245
+ extError.diagnose (ctx);
246
+ return llvm::Error::success ();
247
+ }
248
+ return llvm::make_error<ExtensionError>(std::move (extError));
249
+ });
250
+
251
+ // If no error is left, it was reported as a diagnostic. There's no
252
+ // need to crash.
253
+ if (!error)
254
+ return llvm::Error::success ();
255
+ }
256
+
257
+ // General deserialization failure message.
258
+ ctx.Diags .diagnose (SourceLoc (), diag::serialization_fatal,
185
259
Core->Name );
260
+ }
186
261
// Unless in the debugger, crash. ModuleFileSharedCore::fatal() calls abort().
187
262
// This allows aggregation of crash logs for compiler development, but in a
188
263
// long-running process like LLDB this is undesirable. Only abort() if not in
189
264
// the debugger.
190
- if (!getContext () .LangOpts .DebuggerSupport )
265
+ if (!ctx .LangOpts .DebuggerSupport )
191
266
Core->fatal (std::move (error));
192
267
193
- // Otherwise, augment the error with contextual information and pass it back.
268
+ // Otherwise, augment the error with contextual information at this point
269
+ // of failure and pass it back to be reported later.
194
270
std::string msg;
195
271
{
196
272
llvm::raw_string_ostream os (msg);
@@ -1780,13 +1856,15 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1780
1856
// is mostly for compiler engineers to understand a likely solution at a
1781
1857
// quick glance.
1782
1858
SmallVector<char , 64 > strScratch;
1783
- SmallVector<std::string, 2 > notes;
1784
- auto declName = getXRefDeclNameForError ();
1859
+
1860
+ auto errorKind = ModularizationError::Kind::NotFound;
1861
+ Identifier foundIn;
1862
+
1785
1863
if (recordID == XREF_TYPE_PATH_PIECE ||
1786
1864
recordID == XREF_VALUE_PATH_PIECE) {
1787
1865
auto &ctx = getContext ();
1788
1866
for (auto nameAndModule : ctx.getLoadedModules ()) {
1789
- auto baseModule = nameAndModule.second ;
1867
+ auto otherModule = nameAndModule.second ;
1790
1868
1791
1869
IdentifierID IID;
1792
1870
IdentifierID privateDiscriminator = 0 ;
@@ -1815,10 +1893,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1815
1893
1816
1894
values.clear ();
1817
1895
if (privateDiscriminator) {
1818
- baseModule ->lookupMember (values, baseModule , name,
1896
+ otherModule ->lookupMember (values, otherModule , name,
1819
1897
getIdentifier (privateDiscriminator));
1820
1898
} else {
1821
- baseModule ->lookupQualified (baseModule , DeclNameRef (name),
1899
+ otherModule ->lookupQualified (otherModule , DeclNameRef (name),
1822
1900
NL_QualifiedDefault,
1823
1901
values);
1824
1902
}
@@ -1832,30 +1910,30 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1832
1910
// Found a full match in a different module. It should be a different
1833
1911
// one because otherwise it would have succeeded on the first search.
1834
1912
// This is usually caused by the use of poorly modularized headers.
1835
- auto line = " There is a matching '" +
1836
- declName.getString (strScratch).str () +
1837
- " ' in module '" +
1838
- std::string (nameAndModule.first .str ()) +
1839
- " '. If this is imported from clang, please make sure " +
1840
- " the header is part of a single clang module." ;
1841
- notes.emplace_back (line);
1913
+ errorKind = ModularizationError::Kind::Moved;
1914
+ foundIn = otherModule->getName ();
1915
+ break ;
1842
1916
} else if (hadAMatchBeforeFiltering) {
1843
1917
// Found a match that was filtered out. This may be from the same
1844
1918
// expected module if there's a type difference. This can be caused
1845
1919
// by the use of different Swift language versions between a library
1846
1920
// with serialized SIL and a client.
1847
- auto line = " '" +
1848
- declName.getString (strScratch).str () +
1849
- " ' in module '" +
1850
- std::string (nameAndModule.first .str ()) +
1851
- " ' was filtered out." ;
1852
- notes.emplace_back (line);
1921
+ errorKind = ModularizationError::Kind::TypeChanged;
1922
+ foundIn = otherModule->getName ();
1923
+ break ;
1853
1924
}
1854
1925
}
1855
1926
}
1856
1927
1857
- return llvm::make_error<XRefError>(" top-level value not found" , pathTrace,
1858
- declName, notes);
1928
+ auto declName = getXRefDeclNameForError ();
1929
+ auto expectedIn = baseModule->getName ();
1930
+ auto referencedFrom = getName ();
1931
+ return llvm::make_error<ModularizationError>(declName,
1932
+ errorKind,
1933
+ expectedIn,
1934
+ referencedFrom,
1935
+ foundIn,
1936
+ pathTrace);
1859
1937
}
1860
1938
1861
1939
// Filters for values discovered in the remaining path pieces.
@@ -7256,7 +7334,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
7256
7334
// implementation-only import hiding types and decls.
7257
7335
// rdar://problem/60291019
7258
7336
if (error.isA <XRefNonLoadedModuleError>() ||
7259
- error.isA <UnsafeDeserializationError>()) {
7337
+ error.isA <UnsafeDeserializationError>() ||
7338
+ error.isA <ModularizationError>()) {
7260
7339
consumeError (std::move (error));
7261
7340
return llvm::Error::success ();
7262
7341
}
@@ -7269,7 +7348,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
7269
7348
auto *TE = static_cast <TypeError*>(errorInfo.get ());
7270
7349
7271
7350
if (TE->underlyingReasonIsA <XRefNonLoadedModuleError>() ||
7272
- TE->underlyingReasonIsA <UnsafeDeserializationError>()) {
7351
+ TE->underlyingReasonIsA <UnsafeDeserializationError>() ||
7352
+ TE->underlyingReasonIsA <ModularizationError>()) {
7273
7353
consumeError (std::move (errorInfo));
7274
7354
return llvm::Error::success ();
7275
7355
}
0 commit comments