@@ -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
@@ -188,18 +190,99 @@ SourceLoc ModuleFile::getSourceLoc() const {
188
190
return SourceMgr.getLocForBufferStart (*bufferID);
189
191
}
190
192
193
+ void
194
+ ModularizationError::diagnose (const ModuleFile *MF,
195
+ DiagnosticBehavior limit) const {
196
+ auto &ctx = MF->getContext ();
197
+
198
+ auto diagnoseError = [&](Kind errorKind) {
199
+ switch (errorKind) {
200
+ case Kind::DeclMoved:
201
+ return ctx.Diags .diagnose (MF->getSourceLoc (), diag::modularization_issue_decl_moved,
202
+ declIsType, name, expectedModuleName,
203
+ foundModuleName);
204
+ case Kind::DeclKindChanged:
205
+ return
206
+ ctx.Diags .diagnose (MF->getSourceLoc (), diag::modularization_issue_decl_type_changed,
207
+ declIsType, name, expectedModuleName,
208
+ referencedFromModuleName, foundModuleName,
209
+ foundModuleName != expectedModuleName);
210
+ case Kind::DeclNotFound:
211
+ return ctx.Diags .diagnose (MF->getSourceLoc (), diag::modularization_issue_decl_not_found,
212
+ declIsType, name, expectedModuleName);
213
+ }
214
+ llvm_unreachable (" Unhandled ModularizationError::Kind in switch." );
215
+ };
216
+
217
+ auto inFlight = diagnoseError (errorKind);
218
+ inFlight.limitBehavior (limit);
219
+ inFlight.flush ();
220
+
221
+ // We could pass along the `path` information through notes.
222
+ // However, for a top-level decl a path would just duplicate the
223
+ // expected module name and the decl name from the diagnostic.
224
+ }
225
+
226
+ void TypeError::diagnose (const ModuleFile *MF) const {
227
+ MF->getContext ().Diags .diagnose (MF->getSourceLoc (),
228
+ diag::modularization_issue_side_effect_type_error,
229
+ name);
230
+ }
231
+
232
+ void ExtensionError::diagnose (const ModuleFile *MF) const {
233
+ MF->getContext ().Diags .diagnose (MF->getSourceLoc (),
234
+ diag::modularization_issue_side_effect_extension_error);
235
+ }
236
+
191
237
llvm::Error ModuleFile::diagnoseFatal (llvm::Error error) const {
192
- if (FileContext)
193
- getContext ().Diags .diagnose (SourceLoc (), diag::serialization_fatal,
194
- Core->Name );
238
+
239
+ auto &ctx = getContext ();
240
+ if (FileContext) {
241
+ if (ctx.LangOpts .EnableDeserializationRecovery ) {
242
+ // Attempt to report relevant errors as diagnostics.
243
+ // At this time, only ModularizationErrors are reported directly. They
244
+ // can get here either directly or as underlying causes to a TypeError or
245
+ // and ExtensionError.
246
+ auto handleModularizationError =
247
+ [&](const ModularizationError &modularError) -> llvm::Error {
248
+ modularError.diagnose (this );
249
+ return llvm::Error::success ();
250
+ };
251
+ error = llvm::handleErrors (std::move (error),
252
+ handleModularizationError,
253
+ [&](TypeError &typeError) -> llvm::Error {
254
+ if (typeError.diagnoseUnderlyingReason (handleModularizationError)) {
255
+ typeError.diagnose (this );
256
+ return llvm::Error::success ();
257
+ }
258
+ return llvm::make_error<TypeError>(std::move (typeError));
259
+ },
260
+ [&](ExtensionError &extError) -> llvm::Error {
261
+ if (extError.diagnoseUnderlyingReason (handleModularizationError)) {
262
+ extError.diagnose (this );
263
+ return llvm::Error::success ();
264
+ }
265
+ return llvm::make_error<ExtensionError>(std::move (extError));
266
+ });
267
+
268
+ // If no error is left, it was reported as a diagnostic. There's no
269
+ // need to crash.
270
+ if (!error)
271
+ return llvm::Error::success ();
272
+ }
273
+
274
+ // General deserialization failure message.
275
+ ctx.Diags .diagnose (getSourceLoc (), diag::serialization_fatal, Core->Name );
276
+ }
195
277
// Unless in the debugger, crash. ModuleFileSharedCore::fatal() calls abort().
196
278
// This allows aggregation of crash logs for compiler development, but in a
197
279
// long-running process like LLDB this is undesirable. Only abort() if not in
198
280
// the debugger.
199
- if (!getContext () .LangOpts .DebuggerSupport )
281
+ if (!ctx .LangOpts .DebuggerSupport )
200
282
Core->fatal (std::move (error));
201
283
202
- // Otherwise, augment the error with contextual information and pass it back.
284
+ // Otherwise, augment the error with contextual information at this point
285
+ // of failure and pass it back to be reported later.
203
286
std::string msg;
204
287
{
205
288
llvm::raw_string_ostream os (msg);
@@ -1789,18 +1872,21 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1789
1872
// is mostly for compiler engineers to understand a likely solution at a
1790
1873
// quick glance.
1791
1874
SmallVector<char , 64 > strScratch;
1792
- SmallVector<std::string, 2 > notes;
1793
- auto declName = getXRefDeclNameForError ();
1875
+
1876
+ auto errorKind = ModularizationError::Kind::DeclNotFound;
1877
+ Identifier foundIn;
1878
+ bool isType = false ;
1879
+
1794
1880
if (recordID == XREF_TYPE_PATH_PIECE ||
1795
1881
recordID == XREF_VALUE_PATH_PIECE) {
1796
1882
auto &ctx = getContext ();
1797
1883
for (auto nameAndModule : ctx.getLoadedModules ()) {
1798
- auto baseModule = nameAndModule.second ;
1884
+ auto otherModule = nameAndModule.second ;
1799
1885
1800
1886
IdentifierID IID;
1801
1887
IdentifierID privateDiscriminator = 0 ;
1802
1888
TypeID TID = 0 ;
1803
- bool isType = (recordID == XREF_TYPE_PATH_PIECE);
1889
+ isType = (recordID == XREF_TYPE_PATH_PIECE);
1804
1890
bool inProtocolExt = false ;
1805
1891
bool importedFromClang = false ;
1806
1892
bool isStatic = false ;
@@ -1824,10 +1910,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1824
1910
1825
1911
values.clear ();
1826
1912
if (privateDiscriminator) {
1827
- baseModule ->lookupMember (values, baseModule , name,
1913
+ otherModule ->lookupMember (values, otherModule , name,
1828
1914
getIdentifier (privateDiscriminator));
1829
1915
} else {
1830
- baseModule ->lookupQualified (baseModule , DeclNameRef (name),
1916
+ otherModule ->lookupQualified (otherModule , DeclNameRef (name),
1831
1917
NL_QualifiedDefault,
1832
1918
values);
1833
1919
}
@@ -1841,30 +1927,31 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1841
1927
// Found a full match in a different module. It should be a different
1842
1928
// one because otherwise it would have succeeded on the first search.
1843
1929
// This is usually caused by the use of poorly modularized headers.
1844
- auto line = " There is a matching '" +
1845
- declName.getString (strScratch).str () +
1846
- " ' in module '" +
1847
- std::string (nameAndModule.first .str ()) +
1848
- " '. If this is imported from clang, please make sure " +
1849
- " the header is part of a single clang module." ;
1850
- notes.emplace_back (line);
1930
+ errorKind = ModularizationError::Kind::DeclMoved;
1931
+ foundIn = otherModule->getName ();
1932
+ break ;
1851
1933
} else if (hadAMatchBeforeFiltering) {
1852
1934
// Found a match that was filtered out. This may be from the same
1853
1935
// expected module if there's a type difference. This can be caused
1854
1936
// by the use of different Swift language versions between a library
1855
1937
// with serialized SIL and a client.
1856
- auto line = " '" +
1857
- declName.getString (strScratch).str () +
1858
- " ' in module '" +
1859
- std::string (nameAndModule.first .str ()) +
1860
- " ' was filtered out." ;
1861
- notes.emplace_back (line);
1938
+ errorKind = ModularizationError::Kind::DeclKindChanged;
1939
+ foundIn = otherModule->getName ();
1940
+ break ;
1862
1941
}
1863
1942
}
1864
1943
}
1865
1944
1866
- return llvm::make_error<XRefError>(" top-level value not found" , pathTrace,
1867
- declName, notes);
1945
+ auto declName = getXRefDeclNameForError ();
1946
+ auto expectedIn = baseModule->getName ();
1947
+ auto referencedFrom = getName ();
1948
+ return llvm::make_error<ModularizationError>(declName,
1949
+ isType,
1950
+ errorKind,
1951
+ expectedIn,
1952
+ referencedFrom,
1953
+ foundIn,
1954
+ pathTrace);
1868
1955
}
1869
1956
1870
1957
// Filters for values discovered in the remaining path pieces.
@@ -7265,7 +7352,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
7265
7352
// implementation-only import hiding types and decls.
7266
7353
// rdar://problem/60291019
7267
7354
if (error.isA <XRefNonLoadedModuleError>() ||
7268
- error.isA <UnsafeDeserializationError>()) {
7355
+ error.isA <UnsafeDeserializationError>() ||
7356
+ error.isA <ModularizationError>()) {
7269
7357
consumeError (std::move (error));
7270
7358
return llvm::Error::success ();
7271
7359
}
@@ -7278,7 +7366,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
7278
7366
auto *TE = static_cast <TypeError*>(errorInfo.get ());
7279
7367
7280
7368
if (TE->underlyingReasonIsA <XRefNonLoadedModuleError>() ||
7281
- TE->underlyingReasonIsA <UnsafeDeserializationError>()) {
7369
+ TE->underlyingReasonIsA <UnsafeDeserializationError>() ||
7370
+ TE->underlyingReasonIsA <ModularizationError>()) {
7282
7371
consumeError (std::move (errorInfo));
7283
7372
return llvm::Error::success ();
7284
7373
}
0 commit comments