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