@@ -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
@@ -188,18 +190,99 @@ SourceLoc ModuleFile::getSourceLoc() const {
188190 return SourceMgr.getLocForBufferStart (*bufferID);
189191}
190192
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+
191237llvm::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+ }
195277 // Unless in the debugger, crash. ModuleFileSharedCore::fatal() calls abort().
196278 // This allows aggregation of crash logs for compiler development, but in a
197279 // long-running process like LLDB this is undesirable. Only abort() if not in
198280 // the debugger.
199- if (!getContext () .LangOpts .DebuggerSupport )
281+ if (!ctx .LangOpts .DebuggerSupport )
200282 Core->fatal (std::move (error));
201283
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.
203286 std::string msg;
204287 {
205288 llvm::raw_string_ostream os (msg);
@@ -1789,18 +1872,21 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
17891872 // is mostly for compiler engineers to understand a likely solution at a
17901873 // quick glance.
17911874 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+
17941880 if (recordID == XREF_TYPE_PATH_PIECE ||
17951881 recordID == XREF_VALUE_PATH_PIECE) {
17961882 auto &ctx = getContext ();
17971883 for (auto nameAndModule : ctx.getLoadedModules ()) {
1798- auto baseModule = nameAndModule.second ;
1884+ auto otherModule = nameAndModule.second ;
17991885
18001886 IdentifierID IID;
18011887 IdentifierID privateDiscriminator = 0 ;
18021888 TypeID TID = 0 ;
1803- bool isType = (recordID == XREF_TYPE_PATH_PIECE);
1889+ isType = (recordID == XREF_TYPE_PATH_PIECE);
18041890 bool inProtocolExt = false ;
18051891 bool importedFromClang = false ;
18061892 bool isStatic = false ;
@@ -1824,10 +1910,10 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18241910
18251911 values.clear ();
18261912 if (privateDiscriminator) {
1827- baseModule ->lookupMember (values, baseModule , name,
1913+ otherModule ->lookupMember (values, otherModule , name,
18281914 getIdentifier (privateDiscriminator));
18291915 } else {
1830- baseModule ->lookupQualified (baseModule , DeclNameRef (name),
1916+ otherModule ->lookupQualified (otherModule , DeclNameRef (name),
18311917 NL_QualifiedDefault,
18321918 values);
18331919 }
@@ -1841,30 +1927,31 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
18411927 // Found a full match in a different module. It should be a different
18421928 // one because otherwise it would have succeeded on the first search.
18431929 // 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 ;
18511933 } else if (hadAMatchBeforeFiltering) {
18521934 // Found a match that was filtered out. This may be from the same
18531935 // expected module if there's a type difference. This can be caused
18541936 // by the use of different Swift language versions between a library
18551937 // 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 ;
18621941 }
18631942 }
18641943 }
18651944
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);
18681955 }
18691956
18701957 // Filters for values discovered in the remaining path pieces.
@@ -7265,7 +7352,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
72657352 // implementation-only import hiding types and decls.
72667353 // rdar://problem/60291019
72677354 if (error.isA <XRefNonLoadedModuleError>() ||
7268- error.isA <UnsafeDeserializationError>()) {
7355+ error.isA <UnsafeDeserializationError>() ||
7356+ error.isA <ModularizationError>()) {
72697357 consumeError (std::move (error));
72707358 return llvm::Error::success ();
72717359 }
@@ -7278,7 +7366,8 @@ static llvm::Error consumeErrorIfXRefNonLoadedModule(llvm::Error &&error) {
72787366 auto *TE = static_cast <TypeError*>(errorInfo.get ());
72797367
72807368 if (TE->underlyingReasonIsA <XRefNonLoadedModuleError>() ||
7281- TE->underlyingReasonIsA <UnsafeDeserializationError>()) {
7369+ TE->underlyingReasonIsA <UnsafeDeserializationError>() ||
7370+ TE->underlyingReasonIsA <ModularizationError>()) {
72827371 consumeError (std::move (errorInfo));
72837372 return llvm::Error::success ();
72847373 }
0 commit comments