@@ -157,6 +157,8 @@ const char InvalidRecordKindError::ID = '\0';
157157void InvalidRecordKindError::anchor () {}
158158const char UnsafeDeserializationError::ID = ' \0 ' ;
159159void UnsafeDeserializationError::anchor () {}
160+ const char ModularizationError::ID = ' \0 ' ;
161+ void ModularizationError::anchor () {}
160162
161163static llvm::Error consumeErrorIfXRefNonLoadedModule (llvm::Error &&error);
162164
@@ -179,18 +181,92 @@ void ModuleFile::fatal(llvm::Error error) const {
179181 Core->fatal (diagnoseFatal (std::move (error)));
180182}
181183
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+
182220llvm::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,
185259 Core->Name );
260+ }
186261 // Unless in the debugger, crash. ModuleFileSharedCore::fatal() calls abort().
187262 // This allows aggregation of crash logs for compiler development, but in a
188263 // long-running process like LLDB this is undesirable. Only abort() if not in
189264 // the debugger.
190- if (!getContext () .LangOpts .DebuggerSupport )
265+ if (!ctx .LangOpts .DebuggerSupport )
191266 Core->fatal (std::move (error));
192267
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.
194270 std::string msg;
195271 {
196272 llvm::raw_string_ostream os (msg);
@@ -1780,13 +1856,15 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
17801856 // is mostly for compiler engineers to understand a likely solution at a
17811857 // quick glance.
17821858 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+
17851863 if (recordID == XREF_TYPE_PATH_PIECE ||
17861864 recordID == XREF_VALUE_PATH_PIECE) {
17871865 auto &ctx = getContext ();
17881866 for (auto nameAndModule : ctx.getLoadedModules ()) {
1789- auto baseModule = nameAndModule.second ;
1867+ auto otherModule = nameAndModule.second ;
17901868
17911869 IdentifierID IID;
17921870 IdentifierID privateDiscriminator = 0 ;
@@ -1815,10 +1893,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18151893
18161894 values.clear ();
18171895 if (privateDiscriminator) {
1818- baseModule ->lookupMember (values, baseModule , name,
1896+ otherModule ->lookupMember (values, otherModule , name,
18191897 getIdentifier (privateDiscriminator));
18201898 } else {
1821- baseModule ->lookupQualified (baseModule , DeclNameRef (name),
1899+ otherModule ->lookupQualified (otherModule , DeclNameRef (name),
18221900 NL_QualifiedDefault,
18231901 values);
18241902 }
@@ -1832,30 +1910,30 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18321910 // Found a full match in a different module. It should be a different
18331911 // one because otherwise it would have succeeded on the first search.
18341912 // 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 ;
18421916 } else if (hadAMatchBeforeFiltering) {
18431917 // Found a match that was filtered out. This may be from the same
18441918 // expected module if there's a type difference. This can be caused
18451919 // by the use of different Swift language versions between a library
18461920 // 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 ;
18531924 }
18541925 }
18551926 }
18561927
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);
18591937 }
18601938
18611939 // Filters for values discovered in the remaining path pieces.
@@ -7256,7 +7334,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
72567334 // implementation-only import hiding types and decls.
72577335 // rdar://problem/60291019
72587336 if (error.isA <XRefNonLoadedModuleError>() ||
7259- error.isA <UnsafeDeserializationError>()) {
7337+ error.isA <UnsafeDeserializationError>() ||
7338+ error.isA <ModularizationError>()) {
72607339 consumeError (std::move (error));
72617340 return llvm::Error::success ();
72627341 }
@@ -7269,7 +7348,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
72697348 auto *TE = static_cast <TypeError*>(errorInfo.get ());
72707349
72717350 if (TE->underlyingReasonIsA <XRefNonLoadedModuleError>() ||
7272- TE->underlyingReasonIsA <UnsafeDeserializationError>()) {
7351+ TE->underlyingReasonIsA <UnsafeDeserializationError>() ||
7352+ TE->underlyingReasonIsA <ModularizationError>()) {
72737353 consumeError (std::move (errorInfo));
72747354 return llvm::Error::success ();
72757355 }
0 commit comments