@@ -158,6 +158,8 @@ const char InvalidRecordKindError::ID = '\0';
158158void InvalidRecordKindError::anchor () {}
159159const char UnsafeDeserializationError::ID = ' \0 ' ;
160160void UnsafeDeserializationError::anchor () {}
161+ const char ModularizationError::ID = ' \0 ' ;
162+ void ModularizationError::anchor () {}
161163
162164static llvm::Error consumeErrorIfXRefNonLoadedModule (llvm::Error &&error);
163165
@@ -180,18 +182,108 @@ void ModuleFile::fatal(llvm::Error error) const {
180182 Core->fatal (diagnoseFatal (std::move (error)));
181183}
182184
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+
183238llvm::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+ }
187278 // Unless in the debugger, crash. ModuleFileSharedCore::fatal() calls abort().
188279 // This allows aggregation of crash logs for compiler development, but in a
189280 // long-running process like LLDB this is undesirable. Only abort() if not in
190281 // the debugger.
191- if (!getContext () .LangOpts .DebuggerSupport )
282+ if (!ctx .LangOpts .DebuggerSupport )
192283 Core->fatal (std::move (error));
193284
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.
195287 std::string msg;
196288 {
197289 llvm::raw_string_ostream os (msg);
@@ -1860,18 +1952,21 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18601952 // is mostly for compiler engineers to understand a likely solution at a
18611953 // quick glance.
18621954 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+
18651960 if (recordID == XREF_TYPE_PATH_PIECE ||
18661961 recordID == XREF_VALUE_PATH_PIECE) {
18671962 auto &ctx = getContext ();
18681963 for (auto nameAndModule : ctx.getLoadedModules ()) {
1869- auto baseModule = nameAndModule.second ;
1964+ auto otherModule = nameAndModule.second ;
18701965
18711966 IdentifierID IID;
18721967 IdentifierID privateDiscriminator = 0 ;
18731968 TypeID TID = 0 ;
1874- bool isType = (recordID == XREF_TYPE_PATH_PIECE);
1969+ isType = (recordID == XREF_TYPE_PATH_PIECE);
18751970 bool inProtocolExt = false ;
18761971 bool importedFromClang = false ;
18771972 bool isStatic = false ;
@@ -1895,10 +1990,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18951990
18961991 values.clear ();
18971992 if (privateDiscriminator) {
1898- baseModule ->lookupMember (values, baseModule , name,
1993+ otherModule ->lookupMember (values, otherModule , name,
18991994 getIdentifier (privateDiscriminator));
19001995 } else {
1901- baseModule ->lookupQualified (baseModule , DeclNameRef (name),
1996+ otherModule ->lookupQualified (otherModule , DeclNameRef (name),
19021997 NL_QualifiedDefault,
19031998 values);
19041999 }
@@ -1912,30 +2007,31 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
19122007 // Found a full match in a different module. It should be a different
19132008 // one because otherwise it would have succeeded on the first search.
19142009 // 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 ;
19222013 } else if (hadAMatchBeforeFiltering) {
19232014 // Found a match that was filtered out. This may be from the same
19242015 // expected module if there's a type difference. This can be caused
19252016 // by the use of different Swift language versions between a library
19262017 // 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 ;
19332021 }
19342022 }
19352023 }
19362024
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);
19392035 }
19402036
19412037 // Filters for values discovered in the remaining path pieces.
@@ -7340,7 +7436,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
73407436 // implementation-only import hiding types and decls.
73417437 // rdar://problem/60291019
73427438 if (error.isA <XRefNonLoadedModuleError>() ||
7343- error.isA <UnsafeDeserializationError>()) {
7439+ error.isA <UnsafeDeserializationError>() ||
7440+ error.isA <ModularizationError>()) {
73447441 consumeError (std::move (error));
73457442 return llvm::Error::success ();
73467443 }
@@ -7353,7 +7450,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
73537450 auto *TE = static_cast <TypeError*>(errorInfo.get ());
73547451
73557452 if (TE->underlyingReasonIsA <XRefNonLoadedModuleError>() ||
7356- TE->underlyingReasonIsA <UnsafeDeserializationError>()) {
7453+ TE->underlyingReasonIsA <UnsafeDeserializationError>() ||
7454+ TE->underlyingReasonIsA <ModularizationError>()) {
73577455 consumeError (std::move (errorInfo));
73587456 return llvm::Error::success ();
73597457 }
0 commit comments