[clang] 0a088ea - Improve diagnostics for missing import / #include of module.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 28 18:41:33 PDT 2020


Author: Richard Smith
Date: 2020-04-28T18:41:14-07:00
New Revision: 0a088ead85fae11bb41d8a93ebe213db5554f087

URL: https://github.com/llvm/llvm-project/commit/0a088ead85fae11bb41d8a93ebe213db5554f087
DIFF: https://github.com/llvm/llvm-project/commit/0a088ead85fae11bb41d8a93ebe213db5554f087.diff

LOG: Improve diagnostics for missing import / #include of module.

Fix a few bugs where we would fail to properly determine header to
module correspondence when determining whether to suggest a #include or
import, and suggest a #include more often in language modes where there
is no import syntax. Generally, if the target is in a header with
include guards or #pragma once, we should suggest either #including or
importing that header, and not importing a module that happens to
textually include it.

In passing, improve the notes we attach to the corresponding
diagnostics: calling an entity that we couldn't see "previous" is
confusing.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Lex/HeaderSearch.h
    clang/include/clang/Lex/ModuleMap.h
    clang/include/clang/Lex/Preprocessor.h
    clang/lib/Lex/HeaderSearch.cpp
    clang/lib/Lex/ModuleMap.cpp
    clang/lib/Lex/PPDirectives.cpp
    clang/lib/Sema/SemaLookup.cpp
    clang/lib/Serialization/ASTWriter.cpp
    clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
    clang/test/CXX/module/module.unit/p8.cpp
    clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp
    clang/test/Modules/auto-module-import.m
    clang/test/Modules/cxx-templates.cpp
    clang/test/Modules/decldef.m
    clang/test/Modules/decldef.mm
    clang/test/Modules/diagnose-missing-import.m
    clang/test/Modules/interface-diagnose-missing-import.m
    clang/test/Modules/ms-enums.cpp
    clang/test/Modules/no-module-map.cpp
    clang/test/Modules/normal-module-map.cpp
    clang/test/Modules/stddef.c
    clang/test/Modules/subframeworks.m
    clang/test/Modules/submodule-visibility-cycles.cpp
    clang/test/Modules/submodule-visibility.cpp
    clang/test/Modules/submodules-merge-defs.cpp
    clang/test/Modules/submodules.cpp
    clang/test/Modules/suggest-include.cpp
    clang/test/Modules/tag-injection.c
    clang/test/Modules/tag-injection.cpp
    clang/test/Modules/template-default-args.cpp
    clang/test/Modules/undefined-type-fixit1.cpp
    clang/test/Modules/visibility-in-instantiation.cpp
    clang/test/SemaCXX/compare-modules-cxx2a.cpp
    clang/test/SemaCXX/modules-ts.cppm
    clang/tools/libclang/Indexing.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c0316f5d7834..9bf63307a4ed 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10298,11 +10298,6 @@ def err_module_unimported_use : Error<
   "explicit specialization|partial specialization}0 of %1 must be imported "
   "from module '%2' before it is required">;
 def err_module_unimported_use_header : Error<
-  "missing '#include %3'; "
-  "%select{declaration|definition|default argument|"
-  "explicit specialization|partial specialization}0 of %1 must be imported "
-  "from module '%2' before it is required">;
-def err_module_unimported_use_global_module_fragment : Error<
   "%select{missing '#include'|missing '#include %3'}2; "
   "%select{||default argument of |explicit specialization of |"
   "partial specialization of }0%1 must be "
@@ -10312,6 +10307,10 @@ def err_module_unimported_use_multiple : Error<
   "%select{declaration|definition|default argument|"
   "explicit specialization|partial specialization}0 of %1 must be imported "
   "from one of the following modules before it is required:%2">;
+def note_unreachable_entity : Note<
+  "%select{declaration|definition|default argument declared|"
+  "explicit specialization declared|partial specialization declared}0 here "
+  "is not %select{visible|reachable|reachable|reachable|reachable|reachable}0">;
 def ext_module_import_in_extern_c : ExtWarn<
   "import of C++ module '%0' appears within extern \"C\" language linkage "
   "specification">, DefaultError,

diff  --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h
index b3113372a1d3..28c57dbe3b8e 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -476,6 +476,13 @@ class HeaderSearch {
   /// This routine does not consider the effect of \#import
   bool isFileMultipleIncludeGuarded(const FileEntry *File);
 
+  /// Determine whether the given file is known to have ever been \#imported
+  /// (or if it has been \#included and we've encountered a \#pragma once).
+  bool hasFileBeenImported(const FileEntry *File) {
+    const HeaderFileInfo *FI = getExistingFileInfo(File);
+    return FI && FI->isImport;
+  }
+
   /// This method returns a HeaderMap for the specified
   /// FileEntry, uniquing them through the 'HeaderMaps' datastructure.
   const HeaderMap *CreateHeaderMap(const FileEntry *FE);
@@ -559,6 +566,12 @@ class HeaderSearch {
   ModuleMap::KnownHeader findModuleForHeader(const FileEntry *File,
                                              bool AllowTextual = false) const;
 
+  /// Retrieve all the modules corresponding to the given file.
+  ///
+  /// \ref findModuleForHeader should typically be used instead of this.
+  ArrayRef<ModuleMap::KnownHeader>
+  findAllModulesForHeader(const FileEntry *File) const;
+
   /// Read the contents of the given module map file.
   ///
   /// \param File The module map file.

diff  --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h
index 454fb3e01c88..805cc1f5017b 100644
--- a/clang/include/clang/Lex/ModuleMap.h
+++ b/clang/include/clang/Lex/ModuleMap.h
@@ -419,7 +419,10 @@ class ModuleMap {
     Callbacks.push_back(std::move(Callback));
   }
 
-  /// Retrieve the module that owns the given header file, if any.
+  /// Retrieve the module that owns the given header file, if any. Note that
+  /// this does not implicitly load module maps, except for builtin headers,
+  /// and does not consult the external source. (Those checks are the
+  /// responsibility of \ref HeaderSearch.)
   ///
   /// \param File The header file that is likely to be included.
   ///
@@ -433,13 +436,19 @@ class ModuleMap {
   KnownHeader findModuleForHeader(const FileEntry *File,
                                   bool AllowTextual = false);
 
-  /// Retrieve all the modules that contain the given header file. This
-  /// may not include umbrella modules, nor information from external sources,
-  /// if they have not yet been inferred / loaded.
+  /// Retrieve all the modules that contain the given header file. Note that
+  /// this does not implicitly load module maps, except for builtin headers,
+  /// and does not consult the external source. (Those checks are the
+  /// responsibility of \ref HeaderSearch.)
   ///
   /// Typically, \ref findModuleForHeader should be used instead, as it picks
   /// the preferred module for the header.
-  ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File) const;
+  ArrayRef<KnownHeader> findAllModulesForHeader(const FileEntry *File);
+
+  /// Like \ref findAllModulesForHeader, but do not attempt to infer module
+  /// ownership from umbrella headers if we've not already done so.
+  ArrayRef<KnownHeader>
+  findResolvedModulesForHeader(const FileEntry *File) const;
 
   /// Resolve all lazy header directives for the specified file.
   ///

diff  --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 61e5974c1f0d..7d358bded6e7 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -2278,20 +2278,22 @@ class Preprocessor {
   /// into a module, or is outside any module, returns nullptr.
   Module *getModuleForLocation(SourceLocation Loc);
 
-  /// We want to produce a diagnostic at location IncLoc concerning a
-  /// missing module import.
-  ///
-  /// \param IncLoc The location at which the missing import was detected.
-  /// \param M The desired module.
-  /// \param MLoc A location within the desired module at which some desired
-  ///        effect occurred (eg, where a desired entity was declared).
-  ///
-  /// \return A file that can be #included to import a module containing MLoc.
-  ///         Null if no such file could be determined or if a #include is not
-  ///         appropriate.
-  const FileEntry *getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
-                                                          Module *M,
-                                                          SourceLocation MLoc);
+  /// We want to produce a diagnostic at location IncLoc concerning an
+  /// unreachable effect at location MLoc (eg, where a desired entity was
+  /// declared or defined). Determine whether the right way to make MLoc
+  /// reachable is by #include, and if so, what header should be included.
+  ///
+  /// This is not necessarily fast, and might load unexpected module maps, so
+  /// should only be called by code that intends to produce an error.
+  ///
+  /// \param IncLoc The location at which the missing effect was detected.
+  /// \param MLoc A location within an unimported module at which the desired
+  ///        effect occurred.
+  /// \return A file that can be #included to provide the desired effect. Null
+  ///         if no such file could be determined or if a #include is not
+  ///         appropriate (eg, if a module should be imported instead).
+  const FileEntry *getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+                                                    SourceLocation MLoc);
 
   bool isRecordingPreamble() const {
     return PreambleConditionalStack.isRecording();

diff  --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 1199f75f8a3c..3ac1df1740c8 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1219,9 +1219,11 @@ HeaderSearch::getExistingFileInfo(const FileEntry *FE,
 }
 
 bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
-  // Check if we've ever seen this file as a header.
+  // Check if we've entered this file and found an include guard or #pragma
+  // once. Note that we dor't check for #import, because that's not a property
+  // of the file itself.
   if (auto *HFI = getExistingFileInfo(File))
-    return HFI->isPragmaOnce || HFI->isImport || HFI->ControllingMacro ||
+    return HFI->isPragmaOnce || HFI->ControllingMacro ||
            HFI->ControllingMacroID;
   return false;
 }
@@ -1399,6 +1401,16 @@ HeaderSearch::findModuleForHeader(const FileEntry *File,
   return ModMap.findModuleForHeader(File, AllowTextual);
 }
 
+ArrayRef<ModuleMap::KnownHeader>
+HeaderSearch::findAllModulesForHeader(const FileEntry *File) const {
+  if (ExternalSource) {
+    // Make sure the external source has handled header info about this file,
+    // which includes whether the file is part of a module.
+    (void)getExistingFileInfo(File);
+  }
+  return ModMap.findAllModulesForHeader(File);
+}
+
 static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
                           Module *RequestingModule,
                           ModuleMap::KnownHeader *SuggestedModule) {

diff  --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index 4f7d5ab137e6..85bf93ac9949 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -662,7 +662,20 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
 }
 
 ArrayRef<ModuleMap::KnownHeader>
-ModuleMap::findAllModulesForHeader(const FileEntry *File) const {
+ModuleMap::findAllModulesForHeader(const FileEntry *File) {
+  HeadersMap::iterator Known = findKnownHeader(File);
+  if (Known != Headers.end())
+    return Known->second;
+
+  if (findOrCreateModuleForHeaderInUmbrellaDir(File))
+    return Headers.find(File)->second;
+
+  return None;
+}
+
+ArrayRef<ModuleMap::KnownHeader>
+ModuleMap::findResolvedModulesForHeader(const FileEntry *File) const {
+  // FIXME: Is this necessary?
   resolveHeaderDirectives(File);
   auto It = Headers.find(File);
   if (It == Headers.end())

diff  --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index d8041aef08ac..03bd36bfe267 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -646,24 +646,8 @@ Module *Preprocessor::getModuleForLocation(SourceLocation Loc) {
 }
 
 const FileEntry *
-Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
-                                                     Module *M,
-                                                     SourceLocation Loc) {
-  assert(M && "no module to include");
-
-  // If the context is the global module fragment of some module, we never
-  // want to return that file; instead, we want the innermost include-guarded
-  // header that it included.
-  bool InGlobalModuleFragment = M->Kind == Module::GlobalModuleFragment;
-
-  // If we have a module import syntax, we shouldn't include a header to
-  // make a particular module visible.
-  if ((getLangOpts().ObjC || getLangOpts().CPlusPlusModules ||
-       getLangOpts().ModulesTS) &&
-      !InGlobalModuleFragment)
-    return nullptr;
-
-  Module *TopM = M->getTopLevelModule();
+Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+                                               SourceLocation Loc) {
   Module *IncM = getModuleForLocation(IncLoc);
 
   // Walk up through the include stack, looking through textual headers of M
@@ -677,37 +661,50 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
     if (!FE)
       break;
 
-    if (InGlobalModuleFragment) {
-      if (getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE))
-        return FE;
-      Loc = SM.getIncludeLoc(ID);
-      continue;
-    }
-
-    bool InTextualHeader = false;
-    for (auto Header : HeaderInfo.getModuleMap().findAllModulesForHeader(FE)) {
-      if (!Header.getModule()->isSubModuleOf(TopM))
-        continue;
-
-      if (!(Header.getRole() & ModuleMap::TextualHeader)) {
-        // If this is an accessible, non-textual header of M's top-level module
-        // that transitively includes the given location and makes the
-        // corresponding module visible, this is the thing to #include.
-        if (Header.isAccessibleFrom(IncM))
-          return FE;
+    // We want to find all possible modules that might contain this header, so
+    // search all enclosing directories for module maps and load them.
+    HeaderInfo.hasModuleMap(FE->getName(), /*Root*/ nullptr,
+                            SourceMgr.isInSystemHeader(Loc));
 
+    bool InPrivateHeader = false;
+    for (auto Header : HeaderInfo.findAllModulesForHeader(FE)) {
+      if (!Header.isAccessibleFrom(IncM)) {
         // It's in a private header; we can't #include it.
         // FIXME: If there's a public header in some module that re-exports it,
         // then we could suggest including that, but it's not clear that's the
         // expected way to make this entity visible.
+        InPrivateHeader = true;
         continue;
       }
 
-      InTextualHeader = true;
+      // We'll suggest including textual headers below if they're
+      // include-guarded.
+      if (Header.getRole() & ModuleMap::TextualHeader)
+        continue;
+
+      // If we have a module import syntax, we shouldn't include a header to
+      // make a particular module visible. Let the caller know they should
+      // suggest an import instead.
+      if (getLangOpts().ObjC || getLangOpts().CPlusPlusModules ||
+          getLangOpts().ModulesTS)
+        return nullptr;
+
+      // If this is an accessible, non-textual header of M's top-level module
+      // that transitively includes the given location and makes the
+      // corresponding module visible, this is the thing to #include.
+      return FE;
     }
 
-    if (!InTextualHeader)
-      break;
+    // FIXME: If we're bailing out due to a private header, we shouldn't suggest
+    // an import either.
+    if (InPrivateHeader)
+      return nullptr;
+
+    // If the header is includable and has an include guard, assume the
+    // intended way to expose its contents is by #include, not by importing a
+    // module that transitively includes it.
+    if (getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE))
+      return FE;
 
     Loc = SM.getIncludeLoc(ID);
   }

diff  --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 08d29fa51e6e..aa83f82a1ce8 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -5350,9 +5350,8 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
 
 /// Get a "quoted.h" or <angled.h> include path to use in a diagnostic
 /// suggesting the addition of a #include of the specified file.
-static std::string getIncludeStringForHeader(Preprocessor &PP,
-                                             const FileEntry *E,
-                                             llvm::StringRef IncludingFile) {
+static std::string getHeaderNameForHeader(Preprocessor &PP, const FileEntry *E,
+                                          llvm::StringRef IncludingFile) {
   bool IsSystem = false;
   auto Path = PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(
       E, IncludingFile, &IsSystem);
@@ -5366,25 +5365,10 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
   assert(!Modules.empty());
 
   auto NotePrevious = [&] {
-    unsigned DiagID;
-    switch (MIK) {
-    case MissingImportKind::Declaration:
-      DiagID = diag::note_previous_declaration;
-      break;
-    case MissingImportKind::Definition:
-      DiagID = diag::note_previous_definition;
-      break;
-    case MissingImportKind::DefaultArgument:
-      DiagID = diag::note_default_argument_declared_here;
-      break;
-    case MissingImportKind::ExplicitSpecialization:
-      DiagID = diag::note_explicit_specialization_declared_here;
-      break;
-    case MissingImportKind::PartialSpecialization:
-      DiagID = diag::note_partial_specialization_declared_here;
-      break;
-    }
-    Diag(DeclLoc, DiagID);
+    // FIXME: Suppress the note backtrace even under
+    // -fdiagnostics-show-note-include-stack. We don't care how this
+    // declaration was previously reached.
+    Diag(DeclLoc, diag::note_unreachable_entity) << (int)MIK;
   };
 
   // Weed out duplicates from module list.
@@ -5397,26 +5381,24 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
       UniqueModules.push_back(M);
   }
 
-  llvm::StringRef IncludingFile;
-  if (const FileEntry *FE =
-          SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc)))
-    IncludingFile = FE->tryGetRealPathName();
+  // Try to find a suitable header-name to #include.
+  std::string HeaderName;
+  if (const FileEntry *Header =
+          PP.getHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) {
+    if (const FileEntry *FE =
+            SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc)))
+      HeaderName = getHeaderNameForHeader(PP, Header, FE->tryGetRealPathName());
+  }
 
-  if (UniqueModules.empty()) {
-    // All candidates were global module fragments. Try to suggest a #include.
-    const FileEntry *E =
-        PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, Modules[0], DeclLoc);
+  // If we have a #include we should suggest, or if all definition locations
+  // were in global module fragments, don't suggest an import.
+  if (!HeaderName.empty() || UniqueModules.empty()) {
     // FIXME: Find a smart place to suggest inserting a #include, and add
     // a FixItHint there.
-    Diag(UseLoc, diag::err_module_unimported_use_global_module_fragment)
-        << (int)MIK << Decl << !!E
-        << (E ? getIncludeStringForHeader(PP, E, IncludingFile) : "");
-    // Produce a "previous" note if it will point to a header rather than some
-    // random global module fragment.
-    // FIXME: Suppress the note backtrace even under
-    // -fdiagnostics-show-note-include-stack.
-    if (E)
-      NotePrevious();
+    Diag(UseLoc, diag::err_module_unimported_use_header)
+        << (int)MIK << Decl << !HeaderName.empty() << HeaderName;
+    // Produce a note showing where the entity was declared.
+    NotePrevious();
     if (Recover)
       createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]);
     return;
@@ -5438,16 +5420,6 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
 
     Diag(UseLoc, diag::err_module_unimported_use_multiple)
       << (int)MIK << Decl << ModuleList;
-  } else if (const FileEntry *E = PP.getModuleHeaderToIncludeForDiagnostics(
-                 UseLoc, Modules[0], DeclLoc)) {
-    // The right way to make the declaration visible is to include a header;
-    // suggest doing so.
-    //
-    // FIXME: Find a smart place to suggest inserting a #include, and add
-    // a FixItHint there.
-    Diag(UseLoc, diag::err_module_unimported_use_header)
-        << (int)MIK << Decl << Modules[0]->getFullModuleName()
-        << getIncludeStringForHeader(PP, E, IncludingFile);
   } else {
     // FIXME: Add a FixItHint that imports the corresponding module.
     Diag(UseLoc, diag::err_module_unimported_use)

diff  --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 03121515a5cc..748ac06c5643 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -1812,7 +1812,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
       Filename, File->getSize(), getTimestampForOutput(File)
     };
     HeaderFileInfoTrait::data_type Data = {
-      *HFI, HS.getModuleMap().findAllModulesForHeader(File), {}
+      *HFI, HS.getModuleMap().findResolvedModulesForHeader(File), {}
     };
     Generator.insert(Key, Data, GeneratorTrait);
     ++NumHeaderSearchEntries;

diff  --git a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
index 55c5ce6c4cbe..79529c6c0fc0 100644
--- a/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
+++ b/clang/test/CXX/basic/basic.scope/basic.scope.namespace/p2.cpp
@@ -11,6 +11,8 @@
 #ifdef INTERFACE
 module;
 #include "foo.h"
+// FIXME: The following need to be moved to a header file. The global module
+// fragment is only permitted to contain preprocessor directives.
 int global_module_fragment;
 export module A;
 export int exported;
@@ -28,12 +30,13 @@ module;
 
 void test_early() {
   in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}}
-  // expected-note@*{{previous}}
+  // expected-note@*{{not visible}}
 
   global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}}
+  // expected-note at p2.cpp:16 {{not visible}}
 
   exported = 1; // expected-error {{must be imported from module 'A'}}
-  // expected-note at p2.cpp:16 {{previous}}
+  // expected-note at p2.cpp:18 {{not visible}}
 
   not_exported = 1; // expected-error {{undeclared identifier}}
 
@@ -52,16 +55,17 @@ import A;
 
 void test_late() {
   in_header = 1; // expected-error {{missing '#include "foo.h"'; 'in_header' must be declared before it is used}}
-  // expected-note@*{{previous}}
+  // expected-note@*{{not visible}}
 
   global_module_fragment = 1; // expected-error {{missing '#include'; 'global_module_fragment' must be declared before it is used}}
+  // expected-note at p2.cpp:16 {{not visible}}
 
   exported = 1;
 
   not_exported = 1;
 #ifndef IMPLEMENTATION
   // expected-error at -2 {{undeclared identifier 'not_exported'; did you mean 'exported'}}
-  // expected-note at p2.cpp:16 {{declared here}}
+  // expected-note at p2.cpp:18 {{declared here}}
 #endif
 
   internal = 1;

diff  --git a/clang/test/CXX/module/module.unit/p8.cpp b/clang/test/CXX/module/module.unit/p8.cpp
index aad65272f0d6..a4a85d0bf91f 100644
--- a/clang/test/CXX/module/module.unit/p8.cpp
+++ b/clang/test/CXX/module/module.unit/p8.cpp
@@ -36,5 +36,5 @@ export module foo:bar; // expected-error {{not yet supported}} expected-error {{
 int k = n;
 #ifndef IMPORTED
 // expected-error at -2 {{declaration of 'n' must be imported from module 'foo' before it is required}}
-// expected-note@* {{previous}}
+// expected-note@* {{not visible}}
 #endif

diff  --git a/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp
index 15900c1f6a3a..70b553f1ff74 100644
--- a/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp
+++ b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp
@@ -23,7 +23,7 @@ module MODULE_NAME;
 int use_1 = a;
 #if !MODULE_X
 // expected-error at -2 {{declaration of 'a' must be imported from module 'x' before it is required}}
-// expected-note at x.cppm:1 {{here}}
+// expected-note at x.cppm:1 {{not visible}}
 #endif
 
 import x;
@@ -32,7 +32,7 @@ int use_2 = b; // ok
 
 // There is no relation between module x and module x.y.
 int use_3 = c; // expected-error {{declaration of 'c' must be imported from module 'x.y'}}
-               // expected-note at x.y.cppm:1 {{here}}
+               // expected-note at x.y.cppm:1 {{not visible}}
 
 import x [[]];
 import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}}

diff  --git a/clang/test/Modules/auto-module-import.m b/clang/test/Modules/auto-module-import.m
index f6127adcbd89..7b90e867d437 100644
--- a/clang/test/Modules/auto-module-import.m
+++ b/clang/test/Modules/auto-module-import.m
@@ -18,7 +18,7 @@
 
 #ifdef ERRORS
 Module *mod; // expected-error{{declaration of 'Module' must be imported from module 'Module' before it is required}}
-// expected-note at Inputs/Module.framework/Headers/Module.h:15 {{previous}}
+// expected-note at Inputs/Module.framework/Headers/Module.h:15 {{not visible}}
 #else
 #import <AlsoDependsOnModule/AlsoDependsOnModule.h> // expected-warning{{treating #import as an import of module 'AlsoDependsOnModule'}}
 #endif
@@ -29,7 +29,7 @@
 void testSubframeworkOther() {
 #ifdef ERRORS
   double *sfo1 = sub_framework_other; // expected-error{{declaration of 'sub_framework_other' must be imported from module 'DependsOnModule.SubFramework.Other'}}
-  // expected-note at Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h:15 {{previous}}
+  // expected-note at Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/Other.h:15 {{not visible}}
 #endif
 }
 
@@ -73,7 +73,7 @@ void testModuleSubFrameworkAgain() {
 int getNoUmbrellaAPrivate() { return no_umbrella_A_private; }
 
 int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{declaration of 'no_umbrella_B_private' must be imported from module 'NoUmbrella.Private.B_Private'}}
-// expected-note at Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h:1 {{previous}}
+// expected-note at Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h:1 {{not visible}}
 
 // Test inclusion of headers that are under an umbrella directory but
 // not actually part of the module.

diff  --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index c085eb5f676c..5bb3ca338051 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -83,7 +83,7 @@ void g() {
   // a big spew of errors here.
   //
   // expected-error at Inputs/cxx-templates-a.h:19 {{definition of 'DefinedInBImpl' must be imported}}
-  // expected-note at Inputs/cxx-templates-b-impl.h:1 +{{definition is here}}
+  // expected-note at Inputs/cxx-templates-b-impl.h:1 +{{definition here is not reachable}}
   // expected-error at Inputs/cxx-templates-a.h:19 +{{}}
   // expected-error at Inputs/cxx-templates-a.h:20 +{{}}
   PerformDelayedLookup(defined_in_b_impl); // expected-note {{in instantiation of}}
@@ -106,8 +106,8 @@ void g() {
   TemplateInstantiationVisibility<char[1]> tiv1;
   TemplateInstantiationVisibility<char[2]> tiv2;
   TemplateInstantiationVisibility<char[3]> tiv3; // expected-error 5{{must be imported from module 'cxx_templates_b_impl'}}
-  // expected-note at cxx-templates-b-impl.h:10 3{{explicit specialization declared here}}
-  // expected-note at cxx-templates-b-impl.h:10 2{{previous definition is here}}
+  // expected-note at cxx-templates-b-impl.h:10 3{{explicit specialization declared here is not reachable}}
+  // expected-note at cxx-templates-b-impl.h:10 2{{definition here is not reachable}}
   TemplateInstantiationVisibility<char[4]> tiv4;
 
   int &p = WithPartialSpecializationUse().f();

diff  --git a/clang/test/Modules/decldef.m b/clang/test/Modules/decldef.m
index 784743ff6e79..1fb9bdf58455 100644
--- a/clang/test/Modules/decldef.m
+++ b/clang/test/Modules/decldef.m
@@ -2,7 +2,7 @@
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_EARLY
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
 
-// expected-note at Inputs/def.h:5 {{previous}}
+// expected-note at Inputs/def.h:5 {{here}}
 
 @class Def;
 Def *def;
@@ -16,7 +16,7 @@
 // expected-error at -2{{must use 'struct' tag to refer to type 'B'}}
 #else
 // expected-error at -4{{declaration of 'B' must be imported from module 'decldef.Decl' before it is required}}
-// expected-note at Inputs/decl.h:2 {{previous}}
+// expected-note at Inputs/decl.h:2 {{not visible}}
 #endif
 @import decldef.Decl;
 

diff  --git a/clang/test/Modules/decldef.mm b/clang/test/Modules/decldef.mm
index ab271fc2ba95..e8f070b51159 100644
--- a/clang/test/Modules/decldef.mm
+++ b/clang/test/Modules/decldef.mm
@@ -4,9 +4,9 @@
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_3 -DUSE_4
 // RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify -DUSE_4
 
-// expected-note at Inputs/def.h:5 0-1{{previous}}
-// expected-note at Inputs/def.h:16 0-1{{previous}}
-// expected-note at Inputs/def-include.h:11 0-1{{previous}}
+// expected-note at Inputs/def.h:5 0-1{{here}}
+// expected-note at Inputs/def.h:16 0-1{{here}}
+// expected-note at Inputs/def-include.h:11 0-1{{here}}
 
 @class Def;
 Def *def;

diff  --git a/clang/test/Modules/diagnose-missing-import.m b/clang/test/Modules/diagnose-missing-import.m
index e0c0457e6357..2c67e01944a9 100644
--- a/clang/test/Modules/diagnose-missing-import.m
+++ b/clang/test/Modules/diagnose-missing-import.m
@@ -8,7 +8,7 @@ void foo() {
   XYZLogEvent(xyzRiskyCloseOpenParam, xyzRiskyCloseOpenParam); // expected-error {{implicit declaration of function 'XYZLogEvent'}} expected-error {{declaration of 'XYZLogEvent' must be imported}} expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}} expected-error {{declaration of 'xyzRiskyCloseOpenParam' must be imported from module 'NCI.A'}}
 }
 
-// expected-note at Inputs/diagnose-missing-import/a.h:5 {{previous declaration is here}}
-// expected-note at Inputs/diagnose-missing-import/a.h:5 {{previous declaration is here}}
-// expected-note at Inputs/diagnose-missing-import/a.h:6 {{previous declaration is here}}
+// expected-note at Inputs/diagnose-missing-import/a.h:5 {{declaration here is not visible}}
+// expected-note at Inputs/diagnose-missing-import/a.h:5 {{declaration here is not visible}}
+// expected-note at Inputs/diagnose-missing-import/a.h:6 {{declaration here is not visible}}
 

diff  --git a/clang/test/Modules/interface-diagnose-missing-import.m b/clang/test/Modules/interface-diagnose-missing-import.m
index 5bbac3642300..c455b1501c9c 100644
--- a/clang/test/Modules/interface-diagnose-missing-import.m
+++ b/clang/test/Modules/interface-diagnose-missing-import.m
@@ -8,4 +8,4 @@ @interface Buggy
 @interface Buggy (MyExt) // expected-error {{definition of 'Buggy' must be imported from module 'Foo' before it is required}}
 @end
 
-// expected-note at Foo/RandoPriv.h:3{{previous definition is here}}
+// expected-note at Foo/RandoPriv.h:3{{definition here is not reachable}}

diff  --git a/clang/test/Modules/ms-enums.cpp b/clang/test/Modules/ms-enums.cpp
index b3a377c6fa63..da75d152ffa4 100644
--- a/clang/test/Modules/ms-enums.cpp
+++ b/clang/test/Modules/ms-enums.cpp
@@ -2,8 +2,8 @@
 // RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fms-compatibility -x c++ -std=c++20 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/ms-enums %s -verify -fno-modules-error-recovery
 
 #include "B.h"
-// expected-note at A.h:1 {{previous declaration is here}}
-// expected-note at A.h:1 2 {{previous definition is here}}
+// expected-note at A.h:1 {{declaration here is not visible}}
+// expected-note at A.h:1 2{{definition here is not reachable}}
 
 fwd_enum gv_enum; // expected-error {{must be imported}}
 

diff  --git a/clang/test/Modules/no-module-map.cpp b/clang/test/Modules/no-module-map.cpp
index 46ca38af7eed..81533417e856 100644
--- a/clang/test/Modules/no-module-map.cpp
+++ b/clang/test/Modules/no-module-map.cpp
@@ -30,7 +30,7 @@
 #error A_H should not be defined
 #endif
 // expected-error at +3 {{must be imported from}}
-// expected-note@* {{previous declaration}}
+// expected-note@* {{declaration}}
 #endif
 void use_a() { a(); }
 
@@ -43,6 +43,6 @@ void use_a() { a(); }
 #error B_H should not be defined
 #endif
 // expected-error at +3 {{must be imported from}}
-// expected-note@* {{previous declaration}}
+// expected-note@* {{declaration}}
 #endif
 void use_b() { b(); }

diff  --git a/clang/test/Modules/normal-module-map.cpp b/clang/test/Modules/normal-module-map.cpp
index 5db1f3f33e94..6b8befb77293 100644
--- a/clang/test/Modules/normal-module-map.cpp
+++ b/clang/test/Modules/normal-module-map.cpp
@@ -25,7 +25,7 @@ int testNestedUmbrellaA() {
 int testNestedUmbrellaBFail() {
   return nested_umbrella_b;
   // expected-error at -1{{declaration of 'nested_umbrella_b' must be imported from module 'nested_umbrella.b' before it is required}}
-  // expected-note at Inputs/normal-module-map/nested_umbrella/b.h:1{{previous}}
+  // expected-note at Inputs/normal-module-map/nested_umbrella/b.h:1{{here}}
 }
 
 @import nested_umbrella.b;

diff  --git a/clang/test/Modules/stddef.c b/clang/test/Modules/stddef.c
index 16de854563fc..c33f3643112b 100644
--- a/clang/test/Modules/stddef.c
+++ b/clang/test/Modules/stddef.c
@@ -5,8 +5,8 @@
 
 ptr
diff _t pdt;
 
-size_t st; // expected-error {{must be imported}}
-// expected-note at stddef.h:* {{previous}}
+size_t st; // expected-error {{missing '#include "include_again.h"'; 'size_t' must be declared before it is used}}
+// expected-note at stddef.h:* {{here}}
 
 #include "include_again.h"
 

diff  --git a/clang/test/Modules/subframeworks.m b/clang/test/Modules/subframeworks.m
index ce35415717d2..c4cf85a2babf 100644
--- a/clang/test/Modules/subframeworks.m
+++ b/clang/test/Modules/subframeworks.m
@@ -6,7 +6,7 @@
 
 void testSubFramework() {
   float *sf1 = sub_framework; // expected-error{{declaration of 'sub_framework' must be imported from module 'DependsOnModule.SubFramework' before it is required}}
-  // expected-note at Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h:2 {{previous}}
+  // expected-note at Inputs/DependsOnModule.framework/Frameworks/SubFramework.framework/Headers/SubFramework.h:2 {{here}}
 }
 
 @import DependsOnModule.SubFramework;

diff  --git a/clang/test/Modules/submodule-visibility-cycles.cpp b/clang/test/Modules/submodule-visibility-cycles.cpp
index a01fe562b14f..4fecdb98abd1 100644
--- a/clang/test/Modules/submodule-visibility-cycles.cpp
+++ b/clang/test/Modules/submodule-visibility-cycles.cpp
@@ -3,7 +3,7 @@
 
 #include "cycle1.h"
 C1 c1;
-C2 c2; // expected-error {{must be imported}}
+C2 c2; // expected-error {{missing '#include "cycle2.h"'; 'C2' must be declared}}
 // expected-note at cycle2.h:6 {{here}}
 
 #include "cycle2.h"

diff  --git a/clang/test/Modules/submodule-visibility.cpp b/clang/test/Modules/submodule-visibility.cpp
index 4c066e6ab9b0..cae18d41ad7b 100644
--- a/clang/test/Modules/submodule-visibility.cpp
+++ b/clang/test/Modules/submodule-visibility.cpp
@@ -22,7 +22,7 @@
 // The use of -fmodule-name=x causes us to textually include the above headers.
 // The submodule visibility rules are still applied in this case.
 //
-// expected-error at b.h:1 {{declaration of 'n' must be imported from module 'x.a'}}
+// expected-error at b.h:1 {{missing '#include "a.h"'; 'n' must be declared}}
 // expected-note at a.h:1 {{here}}
 #endif
 

diff  --git a/clang/test/Modules/submodules-merge-defs.cpp b/clang/test/Modules/submodules-merge-defs.cpp
index 9e1ac6ceef28..777fe6936a43 100644
--- a/clang/test/Modules/submodules-merge-defs.cpp
+++ b/clang/test/Modules/submodules-merge-defs.cpp
@@ -15,67 +15,55 @@
 #endif
 
 A pre_a;
-#ifdef IMPORT_USE_2
-// expected-error-re at -2 {{must be imported from one of {{.*}}stuff.use{{.*}}stuff.use-2}}
-#elif EARLY_INDIRECT_INCLUDE
-// expected-error at -4 {{must be imported from module 'merged-defs'}}
-#else
-// expected-error at -6 {{must be imported from module 'stuff.use'}}
-#endif
+// expected-error-re at -1 {{missing '#include "{{.*}}-defs.h"'; 'A' must be declared}}
 // expected-note at defs.h:1 +{{here}}
 extern class A pre_a2;
-int pre_use_a = use_a(pre_a2); // expected-error 2{{'A' must be imported}} expected-error {{'use_a' must be imported}}
+int pre_use_a = use_a(pre_a2); // expected-error 2{{'A' must be defined}} expected-error {{'use_a' must be declared}}
 // expected-note at defs.h:2 +{{here}}
 
-B::Inner2 pre_bi; // expected-error +{{must be imported}}
+B::Inner2 pre_bi; // expected-error +{{must be declared}} expected-error +{{must be defined}}
 // expected-note at defs.h:4 +{{here}}
 // expected-note at defs.h:17 +{{here}}
-void pre_bfi(B b) { // expected-error +{{must be imported}}
+void pre_bfi(B b) { // expected-error +{{must be declared}}
   b.f<int>();
 }
 
-C_Base<1> pre_cb1; // expected-error +{{must be imported}}
+C_Base<1> pre_cb1; // expected-error +{{must be declared}} expected-error +{{must be defined}}
 // expected-note at defs.h:23 +{{here}}
-C1 pre_c1; // expected-error +{{must be imported}}
+C1 pre_c1; // expected-error +{{must be declared}}
 // expected-note at defs.h:25 +{{here}}
-C2 pre_c2; // expected-error +{{must be imported}}
+C2 pre_c2; // expected-error +{{must be declared}}
 // expected-note at defs.h:26 +{{here}}
 
-D::X pre_dx; // expected-error +{{must be imported}}
+D::X pre_dx; // expected-error +{{must be declared}} expected-error +{{must be defined}}
 // expected-note at defs.h:28 +{{here}}
 // expected-note at defs.h:29 +{{here}}
 int pre_use_dx = use_dx(pre_dx); // ignored; pre_dx is invalid
 
-int pre_e = E(0); // expected-error {{must be imported}}
+int pre_e = E(0); // expected-error {{must be declared}}
 // expected-note at defs.h:32 +{{here}}
 
-int pre_ff = F<int>().f(); // expected-error +{{must be imported}}
-int pre_fg = F<int>().g<int>(); // expected-error +{{must be imported}}
+int pre_ff = F<int>().f(); // expected-error +{{must be declared}}
+int pre_fg = F<int>().g<int>(); // expected-error +{{must be declared}}
 // expected-note at defs.h:34 +{{here}}
 
-G::A pre_ga // expected-error +{{must be imported}}
-  = G::a; // expected-error +{{must be imported}}
+G::A pre_ga // expected-error +{{must be declared}}
+  = G::a; // expected-error +{{must be declared}}
 // expected-note at defs.h:49 +{{here}}
 // expected-note at defs.h:50 +{{here}}
-decltype(G::h) pre_gh = G::h; // expected-error +{{must be imported}}
+decltype(G::h) pre_gh = G::h; // expected-error +{{must be declared}} expected-error +{{must be defined}}
 // expected-note at defs.h:51 +{{here}}
 
-int pre_h = H(); // expected-error +{{must be imported}}
+int pre_h = H(); // expected-error +{{must be declared}}
 // expected-note at defs.h:56 +{{here}}
-using pre_i = I<>; // expected-error +{{must be imported}}
+using pre_i = I<>; // expected-error +{{must be declared}} expected-error +{{default argument of 'I' must be defined}}
 // expected-note at defs.h:57 +{{here}}
 
-J<> pre_j; // expected-error {{declaration of 'J' must be imported}}
-#ifdef IMPORT_USE_2
-// expected-error-re at -2 {{default argument of 'J' must be imported from one of {{.*}}stuff.use-2{{.*}}stuff.use}}
-#elif EARLY_INDIRECT_INCLUDE
-// expected-error at -4 {{default argument of 'J' must be imported from module 'merged-defs'}}
-#else
-// expected-error at -6 {{default argument of 'J' must be imported from module 'stuff.use'}}
-#endif
+J<> pre_j; // expected-error {{'J' must be declared}}
+// expected-error-re at -1 {{missing '#include "{{.*}}.h"'; default argument of 'J' must be defined before it is used}}
 // expected-note at defs.h:58 +{{here}}
 
-ScopedEnum pre_scopedenum; // expected-error {{must be imported}}
+ScopedEnum pre_scopedenum; // expected-error {{must be declared}}
 // expected-note at defs.h:105 0-1{{here}}
 // expected-note at defs.h:106 0-1{{here}}
 enum ScopedEnum : int;

diff  --git a/clang/test/Modules/submodules.cpp b/clang/test/Modules/submodules.cpp
index a3dde23cb5b5..e4a31db0e533 100644
--- a/clang/test/Modules/submodules.cpp
+++ b/clang/test/Modules/submodules.cpp
@@ -8,8 +8,8 @@ vector<int> vi;
 
 // Note: remove_reference is not visible yet.
 remove_reference<int&>::type *int_ptr = 0; // expected-error{{declaration of 'remove_reference' must be imported from module 'std.type_traits' before it is required}}
-// expected-note at Inputs/submodules/type_traits.h:2{{previous}}
-// expected-note at Inputs/submodules/hash_map.h:1{{previous}}
+// expected-note at Inputs/submodules/type_traits.h:2{{not visible}}
+// expected-note at Inputs/submodules/hash_map.h:1{{not visible}}
 
 @import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
 

diff  --git a/clang/test/Modules/suggest-include.cpp b/clang/test/Modules/suggest-include.cpp
index e10c3f38aba2..1e53ef05d5f8 100644
--- a/clang/test/Modules/suggest-include.cpp
+++ b/clang/test/Modules/suggest-include.cpp
@@ -3,23 +3,25 @@
 
 #include "empty.h" // import the module file
 
-// expected-note at usetextual1.h:2 {{previous}}
-// expected-note at textual2.h:1 {{previous}}
-// expected-note at textual3.h:1 {{previous}}
-// expected-note at textual4.h:1 {{previous}}
-// expected-note at textual5.h:1 {{previous}}
-// expected-note at private1.h:1 {{previous}}
-// expected-note at private2.h:1 {{previous}}
-// expected-note at private3.h:1 {{previous}}
+// expected-note at usetextual1.h:2 {{here}}
+// expected-note at textual2.h:1 {{here}}
+// expected-note at textual3.h:1 {{here}}
+// expected-note at textual4.h:1 {{here}}
+// expected-note at textual5.h:1 {{here}}
+// expected-note at private1.h:1 {{here}}
+// expected-note at private2.h:1 {{here}}
+// expected-note at private3.h:1 {{here}}
 
 void f() {
   (void)::usetextual1; // expected-error {{missing '#include "usetextual1.h"'}}
   (void)::usetextual2; // expected-error {{missing '#include "usetextual2.h"'}}
   (void)::textual3; // expected-error-re {{{{^}}missing '#include "usetextual3.h"'}}
-  // Don't suggest a #include that includes the entity via a path that leaves
-  // the module. In that case we can't be sure that we've picked the right header.
-  (void)::textual4; // expected-error-re {{{{^}}declaration of 'textual4'}}
-  (void)::textual5; // expected-error-re {{{{^}}declaration of 'textual5'}}
+  // If the declaration is in an include-guarded header, make sure we suggest
+  // including that rather than importing a module. In this case, there could
+  // be more than one module, and the module name we picked is almost certainly
+  // wrong.
+  (void)::textual4; // expected-error {{missing '#include "usetextual4.h"'; 'textual4' must be declared before it is used}}
+  (void)::textual5; // expected-error {{missing '#include "usetextual5.h"'; 'textual5' must be declared before it is used}}
 
   // Don't suggest #including a private header.
   // FIXME: We could suggest including "useprivate1.h" here, as it's the only

diff  --git a/clang/test/Modules/tag-injection.c b/clang/test/Modules/tag-injection.c
index 5bb15477e2e2..727616f5d862 100644
--- a/clang/test/Modules/tag-injection.c
+++ b/clang/test/Modules/tag-injection.c
@@ -14,5 +14,5 @@ void f(struct a *p);
 // "compatible types" rule.
 void g(struct b *p);
 
-struct b b; // expected-error {{definition of 'b' must be imported from module 'X.b' before it is required}}
+struct b b; // expected-error {{'b' must be defined before it is used}}
 // expected-note at b.h:1 {{here}}

diff  --git a/clang/test/Modules/tag-injection.cpp b/clang/test/Modules/tag-injection.cpp
index e55598b06202..dca520e921a1 100644
--- a/clang/test/Modules/tag-injection.cpp
+++ b/clang/test/Modules/tag-injection.cpp
@@ -21,5 +21,5 @@ namespace N {
   };
 }
 
-X x; // expected-error {{definition of 'X' must be imported from module 'X.b' before it is required}}
+X x; // expected-error {{'X' must be defined before it is used}}
 // expected-note at b.h:1 {{here}}

diff  --git a/clang/test/Modules/template-default-args.cpp b/clang/test/Modules/template-default-args.cpp
index c51cb2840884..85b2a18d9e50 100644
--- a/clang/test/Modules/template-default-args.cpp
+++ b/clang/test/Modules/template-default-args.cpp
@@ -37,10 +37,10 @@ extern C<> c;
 D<> d;
 E<> e;
 F<> f;
-G<> g; // expected-error {{default argument of 'G' must be imported from module 'X.A' before it is required}}
-// expected-note at a.h:7 {{default argument declared here}}
-H<> h; // expected-error {{default argument of 'H' must be imported from module 'X.A' before it is required}}
-// expected-note at a.h:8 {{default argument declared here}}
+G<> g; // expected-error {{missing '#include "a.h"'; default argument of 'G' must be defined before it is used}}
+// expected-note at a.h:7 {{default argument declared here is not reachable}}
+H<> h; // expected-error {{missing '#include "a.h"'; default argument of 'H' must be defined before it is used}}
+// expected-note at a.h:8 {{default argument declared here is not reachable}}
 I<> i;
 L<> *l;
 END

diff  --git a/clang/test/Modules/undefined-type-fixit1.cpp b/clang/test/Modules/undefined-type-fixit1.cpp
index 3b7345710726..8cb8a3c55de5 100644
--- a/clang/test/Modules/undefined-type-fixit1.cpp
+++ b/clang/test/Modules/undefined-type-fixit1.cpp
@@ -5,8 +5,8 @@
 #include "public2.h"
 #include "public2sub.h"
 
-use_this1 client_variable1; // expected-error{{declaration of 'use_this1' must be imported from module 'public1' before it is required}}
+use_this1 client_variable1; // expected-error{{'use_this1' must be declared}}
 use_this2 client_variable2;
 use_this2sub client_variable2sub;
 
-// expected-note at Inputs/undefined-type-fixit/public1.h:4 {{previous declaration is here}}
+// expected-note at Inputs/undefined-type-fixit/public1.h:4 {{declaration here is not visible}}

diff  --git a/clang/test/Modules/visibility-in-instantiation.cpp b/clang/test/Modules/visibility-in-instantiation.cpp
index 8689758a42ba..81ddfd6baaf3 100644
--- a/clang/test/Modules/visibility-in-instantiation.cpp
+++ b/clang/test/Modules/visibility-in-instantiation.cpp
@@ -47,5 +47,5 @@ void g() {
 
   ST<int>::f(); // expected-error {{must be imported from module 'M.B'}}
   foo(X<int>()); // expected-error {{must be imported from module 'M.C'}}
-  // expected-note@* 2{{previous declaration is here}}
+  // expected-note@* 2{{declaration here is not visible}}
 }

diff  --git a/clang/test/SemaCXX/compare-modules-cxx2a.cpp b/clang/test/SemaCXX/compare-modules-cxx2a.cpp
index fa9180024351..afbcce1b0c00 100644
--- a/clang/test/SemaCXX/compare-modules-cxx2a.cpp
+++ b/clang/test/SemaCXX/compare-modules-cxx2a.cpp
@@ -22,12 +22,12 @@ auto va = A() <=> A(); // expected-note {{required here}}
 
 #pragma clang module import compare.other
 
-// expected-note at std-compare.h:* 2+{{previous definition}}
+// expected-note at std-compare.h:* 2+{{not reachable}}
 
-void b() { void(0 <=> 0); } // expected-error 1+{{definition of 'strong_ordering' must be imported}}
+void b() { void(0 <=> 0); } // expected-error 1+{{missing '#include "std-compare.h"'; 'strong_ordering' must be defined}}
 
 struct B {
-  CC operator<=>(const B&) const = default; // expected-error 1+{{definition of 'strong_ordering' must be imported}}
+  CC operator<=>(const B&) const = default; // expected-error 1+{{missing '#include "std-compare.h"'; 'strong_ordering' must be defined}}
 };
 auto vb = B() <=> B(); // expected-note {{required here}}
 

diff  --git a/clang/test/SemaCXX/modules-ts.cppm b/clang/test/SemaCXX/modules-ts.cppm
index 1081995c586f..ae15c0825d1a 100644
--- a/clang/test/SemaCXX/modules-ts.cppm
+++ b/clang/test/SemaCXX/modules-ts.cppm
@@ -43,7 +43,7 @@ namespace N {
 export struct T {} t;
 #elif TEST == 3
 int use_a = a; // expected-error {{declaration of 'a' must be imported from module 'foo' before it is required}}
-// expected-note at -13 {{previous}}
+// expected-note at -13 {{declaration here is not visible}}
 
 #undef foo
 import foo;

diff  --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp
index 05852f3e2bfc..f0303fdcd825 100644
--- a/clang/tools/libclang/Indexing.cpp
+++ b/clang/tools/libclang/Indexing.cpp
@@ -227,7 +227,8 @@ class ParsedSrcLocationsTracker {
   }
 
   bool isParsedOnceInclude(const FileEntry *FE) {
-    return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE);
+    return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE) ||
+           PP.getHeaderSearchInfo().hasFileBeenImported(FE);
   }
 };
 


        


More information about the cfe-commits mailing list