@@ -158,6 +158,8 @@ const char InvalidRecordKindError::ID = '\0';
158
158
void InvalidRecordKindError::anchor () {}
159
159
const char UnsafeDeserializationError::ID = ' \0 ' ;
160
160
void UnsafeDeserializationError::anchor () {}
161
+ const char ModularizationError::ID = ' \0 ' ;
162
+ void ModularizationError::anchor () {}
161
163
162
164
static llvm::Error consumeErrorIfXRefNonLoadedModule (llvm::Error &&error);
163
165
@@ -180,18 +182,108 @@ void ModuleFile::fatal(llvm::Error error) const {
180
182
Core->fatal (diagnoseFatal (std::move (error)));
181
183
}
182
184
185
+ SourceLoc ModuleFile::getSourceLoc () const {
186
+ auto &SourceMgr = getContext ().Diags .SourceMgr ;
187
+ auto filename = getModuleFilename ();
188
+ auto bufferID = SourceMgr.getIDForBufferIdentifier (filename);
189
+ if (!bufferID)
190
+ bufferID = SourceMgr.addMemBufferCopy (StringRef (), filename);
191
+ return SourceMgr.getLocForBufferStart (*bufferID);
192
+ }
193
+
194
+ void
195
+ ModularizationError::diagnose (const ModuleFile *MF,
196
+ DiagnosticBehavior limit) const {
197
+ auto &ctx = MF->getContext ();
198
+
199
+ auto diagnoseError = [&](Kind errorKind) {
200
+ switch (errorKind) {
201
+ case Kind::DeclMoved:
202
+ return ctx.Diags .diagnose (MF->getSourceLoc (), diag::modularization_issue_decl_moved,
203
+ declIsType, name, expectedModuleName,
204
+ foundModuleName);
205
+ case Kind::DeclKindChanged:
206
+ return
207
+ ctx.Diags .diagnose (MF->getSourceLoc (), diag::modularization_issue_decl_type_changed,
208
+ declIsType, name, expectedModuleName,
209
+ referencedFromModuleName, foundModuleName,
210
+ foundModuleName != expectedModuleName);
211
+ case Kind::DeclNotFound:
212
+ return ctx.Diags .diagnose (MF->getSourceLoc (), diag::modularization_issue_decl_not_found,
213
+ declIsType, name, expectedModuleName);
214
+ }
215
+ llvm_unreachable (" Unhandled ModularizationError::Kind in switch." );
216
+ };
217
+
218
+ auto inFlight = diagnoseError (errorKind);
219
+ inFlight.limitBehavior (limit);
220
+ inFlight.flush ();
221
+
222
+ // We could pass along the `path` information through notes.
223
+ // However, for a top-level decl a path would just duplicate the
224
+ // expected module name and the decl name from the diagnostic.
225
+ }
226
+
227
+ void TypeError::diagnose (const ModuleFile *MF) const {
228
+ MF->getContext ().Diags .diagnose (MF->getSourceLoc (),
229
+ diag::modularization_issue_side_effect_type_error,
230
+ name);
231
+ }
232
+
233
+ void ExtensionError::diagnose (const ModuleFile *MF) const {
234
+ MF->getContext ().Diags .diagnose (MF->getSourceLoc (),
235
+ diag::modularization_issue_side_effect_extension_error);
236
+ }
237
+
183
238
llvm::Error ModuleFile::diagnoseFatal (llvm::Error error) const {
184
- if (FileContext)
185
- getContext ().Diags .diagnose (SourceLoc (), diag::serialization_fatal,
186
- Core->Name );
239
+
240
+ auto &ctx = getContext ();
241
+ if (FileContext) {
242
+ if (ctx.LangOpts .EnableDeserializationRecovery ) {
243
+ // Attempt to report relevant errors as diagnostics.
244
+ // At this time, only ModularizationErrors are reported directly. They
245
+ // can get here either directly or as underlying causes to a TypeError or
246
+ // and ExtensionError.
247
+ auto handleModularizationError =
248
+ [&](const ModularizationError &modularError) -> llvm::Error {
249
+ modularError.diagnose (this );
250
+ return llvm::Error::success ();
251
+ };
252
+ error = llvm::handleErrors (std::move (error),
253
+ handleModularizationError,
254
+ [&](TypeError &typeError) -> llvm::Error {
255
+ if (typeError.diagnoseUnderlyingReason (handleModularizationError)) {
256
+ typeError.diagnose (this );
257
+ return llvm::Error::success ();
258
+ }
259
+ return llvm::make_error<TypeError>(std::move (typeError));
260
+ },
261
+ [&](ExtensionError &extError) -> llvm::Error {
262
+ if (extError.diagnoseUnderlyingReason (handleModularizationError)) {
263
+ extError.diagnose (this );
264
+ return llvm::Error::success ();
265
+ }
266
+ return llvm::make_error<ExtensionError>(std::move (extError));
267
+ });
268
+
269
+ // If no error is left, it was reported as a diagnostic. There's no
270
+ // need to crash.
271
+ if (!error)
272
+ return llvm::Error::success ();
273
+ }
274
+
275
+ // General deserialization failure message.
276
+ ctx.Diags .diagnose (getSourceLoc (), diag::serialization_fatal, Core->Name );
277
+ }
187
278
// Unless in the debugger, crash. ModuleFileSharedCore::fatal() calls abort().
188
279
// This allows aggregation of crash logs for compiler development, but in a
189
280
// long-running process like LLDB this is undesirable. Only abort() if not in
190
281
// the debugger.
191
- if (!getContext () .LangOpts .DebuggerSupport )
282
+ if (!ctx .LangOpts .DebuggerSupport )
192
283
Core->fatal (std::move (error));
193
284
194
- // Otherwise, augment the error with contextual information and pass it back.
285
+ // Otherwise, augment the error with contextual information at this point
286
+ // of failure and pass it back to be reported later.
195
287
std::string msg;
196
288
{
197
289
llvm::raw_string_ostream os (msg);
@@ -1860,18 +1952,21 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1860
1952
// is mostly for compiler engineers to understand a likely solution at a
1861
1953
// quick glance.
1862
1954
SmallVector<char , 64 > strScratch;
1863
- SmallVector<std::string, 2 > notes;
1864
- auto declName = getXRefDeclNameForError ();
1955
+
1956
+ auto errorKind = ModularizationError::Kind::DeclNotFound;
1957
+ Identifier foundIn;
1958
+ bool isType = false ;
1959
+
1865
1960
if (recordID == XREF_TYPE_PATH_PIECE ||
1866
1961
recordID == XREF_VALUE_PATH_PIECE) {
1867
1962
auto &ctx = getContext ();
1868
1963
for (auto nameAndModule : ctx.getLoadedModules ()) {
1869
- auto baseModule = nameAndModule.second ;
1964
+ auto otherModule = nameAndModule.second ;
1870
1965
1871
1966
IdentifierID IID;
1872
1967
IdentifierID privateDiscriminator = 0 ;
1873
1968
TypeID TID = 0 ;
1874
- bool isType = (recordID == XREF_TYPE_PATH_PIECE);
1969
+ isType = (recordID == XREF_TYPE_PATH_PIECE);
1875
1970
bool inProtocolExt = false ;
1876
1971
bool importedFromClang = false ;
1877
1972
bool isStatic = false ;
@@ -1895,10 +1990,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1895
1990
1896
1991
values.clear ();
1897
1992
if (privateDiscriminator) {
1898
- baseModule ->lookupMember (values, baseModule , name,
1993
+ otherModule ->lookupMember (values, otherModule , name,
1899
1994
getIdentifier (privateDiscriminator));
1900
1995
} else {
1901
- baseModule ->lookupQualified (baseModule , DeclNameRef (name),
1996
+ otherModule ->lookupQualified (otherModule , DeclNameRef (name),
1902
1997
NL_QualifiedDefault,
1903
1998
values);
1904
1999
}
@@ -1912,30 +2007,31 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
1912
2007
// Found a full match in a different module. It should be a different
1913
2008
// one because otherwise it would have succeeded on the first search.
1914
2009
// This is usually caused by the use of poorly modularized headers.
1915
- auto line = " There is a matching '" +
1916
- declName.getString (strScratch).str () +
1917
- " ' in module '" +
1918
- std::string (nameAndModule.first .str ()) +
1919
- " '. If this is imported from clang, please make sure " +
1920
- " the header is part of a single clang module." ;
1921
- notes.emplace_back (line);
2010
+ errorKind = ModularizationError::Kind::DeclMoved;
2011
+ foundIn = otherModule->getName ();
2012
+ break ;
1922
2013
} else if (hadAMatchBeforeFiltering) {
1923
2014
// Found a match that was filtered out. This may be from the same
1924
2015
// expected module if there's a type difference. This can be caused
1925
2016
// by the use of different Swift language versions between a library
1926
2017
// with serialized SIL and a client.
1927
- auto line = " '" +
1928
- declName.getString (strScratch).str () +
1929
- " ' in module '" +
1930
- std::string (nameAndModule.first .str ()) +
1931
- " ' was filtered out." ;
1932
- notes.emplace_back (line);
2018
+ errorKind = ModularizationError::Kind::DeclKindChanged;
2019
+ foundIn = otherModule->getName ();
2020
+ break ;
1933
2021
}
1934
2022
}
1935
2023
}
1936
2024
1937
- return llvm::make_error<XRefError>(" top-level value not found" , pathTrace,
1938
- declName, notes);
2025
+ auto declName = getXRefDeclNameForError ();
2026
+ auto expectedIn = baseModule->getName ();
2027
+ auto referencedFrom = getName ();
2028
+ return llvm::make_error<ModularizationError>(declName,
2029
+ isType,
2030
+ errorKind,
2031
+ expectedIn,
2032
+ referencedFrom,
2033
+ foundIn,
2034
+ pathTrace);
1939
2035
}
1940
2036
1941
2037
// Filters for values discovered in the remaining path pieces.
@@ -7340,7 +7436,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
7340
7436
// implementation-only import hiding types and decls.
7341
7437
// rdar://problem/60291019
7342
7438
if (error.isA <XRefNonLoadedModuleError>() ||
7343
- error.isA <UnsafeDeserializationError>()) {
7439
+ error.isA <UnsafeDeserializationError>() ||
7440
+ error.isA <ModularizationError>()) {
7344
7441
consumeError (std::move (error));
7345
7442
return llvm::Error::success ();
7346
7443
}
@@ -7353,7 +7450,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
7353
7450
auto *TE = static_cast <TypeError*>(errorInfo.get ());
7354
7451
7355
7452
if (TE->underlyingReasonIsA <XRefNonLoadedModuleError>() ||
7356
- TE->underlyingReasonIsA <UnsafeDeserializationError>()) {
7453
+ TE->underlyingReasonIsA <UnsafeDeserializationError>() ||
7454
+ TE->underlyingReasonIsA <ModularizationError>()) {
7357
7455
consumeError (std::move (errorInfo));
7358
7456
return llvm::Error::success ();
7359
7457
}
0 commit comments