[HeaderSearch] Fix processing #import-ed headers multiple times with modules enabled.

HeaderSearch was marking requested HeaderFileInfo as Resolved only based on
the presence of ExternalSource. As the result, using any module was enough
to set ExternalSource and headers unknown to this module would have
HeaderFileInfo with empty fields, including `isImport = 0`, `NumIncludes = 0`.
Such HeaderFileInfo was preserved without changes regardless of how the
header was used in other modules and caused incorrect result in
`HeaderSearch::ShouldEnterIncludeFile`.

Fix by marking HeaderFileInfo as Resolved only if ExternalSource knows
about this header.

rdar://problem/62126911

Reviewed By: bruno

Differential Revision: https://reviews.llvm.org/D80263
This commit is contained in:
Volodymyr Sapsai 2020-05-19 17:29:35 -07:00
parent ea9bf460a8
commit 7ac737e56b
8 changed files with 45 additions and 10 deletions

View File

@ -1167,12 +1167,12 @@ HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
HeaderFileInfo *HFI = &FileInfo[FE->getUID()];
// FIXME: Use a generation count to check whether this is really up to date.
if (ExternalSource && !HFI->Resolved) {
HFI->Resolved = true;
auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
HFI = &FileInfo[FE->getUID()];
if (ExternalHFI.External)
mergeHeaderFileInfo(*HFI, ExternalHFI);
if (ExternalHFI.IsValid) {
HFI->Resolved = true;
if (ExternalHFI.External)
mergeHeaderFileInfo(*HFI, ExternalHFI);
}
}
HFI->IsValid = true;
@ -1199,12 +1199,12 @@ HeaderSearch::getExistingFileInfo(const FileEntry *FE,
if (!WantExternal && (!HFI->IsValid || HFI->External))
return nullptr;
if (!HFI->Resolved) {
HFI->Resolved = true;
auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
HFI = &FileInfo[FE->getUID()];
if (ExternalHFI.External)
mergeHeaderFileInfo(*HFI, ExternalHFI);
if (ExternalHFI.IsValid) {
HFI->Resolved = true;
if (ExternalHFI.External)
mergeHeaderFileInfo(*HFI, ExternalHFI);
}
}
} else if (FE->getUID() >= FileInfo.size()) {
return nullptr;

View File

@ -0,0 +1,5 @@
// No header guards on purpose.
enum SomeSimpleEnum {
SomeSimpleEnumCase,
};

View File

@ -0,0 +1,4 @@
framework module ImportOnce {
umbrella header "ImportOnce.h"
export *
}

View File

@ -0,0 +1,2 @@
#import <Unrelated/Unrelated.h>
#import <ImportOnce/ImportOnce.h>

View File

@ -0,0 +1,4 @@
framework module IndirectImporter {
umbrella header "IndirectImporter.h"
export *
}

View File

@ -0,0 +1 @@
void foo(void);

View File

@ -0,0 +1,4 @@
framework module Unrelated {
umbrella header "Unrelated.h"
export *
}

View File

@ -0,0 +1,15 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fmodule-name=ImportOnce -fimplicit-module-maps -fmodules-cache-path=%t -F %S/Inputs/import-once %s
// Test #import-ed headers are processed only once, even without header guards.
// Dependency graph is
//
// Unrelated ImportOnce
// ^ ^ ^
// \ / |
// IndirectImporter |
// ^ |
// \ |
// import-once.m
#import <IndirectImporter/IndirectImporter.h>
#import <ImportOnce/ImportOnce.h>