Rename IsMissingRequirement to IsUnimportable and set it for shadowed

modules too.

This more accurately reflects the semantics of this flag, as distinct
from "IsAvailable", which (in an explicit modules world) only describes
whether a module is buildable, not whether it's importable.
This commit is contained in:
Richard Smith 2020-04-17 16:23:41 -07:00
parent c8248dc3bb
commit fc76b4ad3d
5 changed files with 72 additions and 39 deletions
clang
include/clang/Basic
lib

View File

@ -207,8 +207,10 @@ public:
/// A module with the same name that shadows this module.
Module *ShadowingModule = nullptr;
/// Whether this module is missing a feature from \c Requirements.
unsigned IsMissingRequirement : 1;
/// Whether this module has declared itself unimportable, either because
/// it's missing a requirement from \p Requirements or because it's been
/// shadowed by another module.
unsigned IsUnimportable : 1;
/// Whether we tried and failed to load a module file for this module.
unsigned HasIncompatibleModuleFile : 1;
@ -384,6 +386,25 @@ public:
~Module();
/// Determine whether this module has been declared unimportable.
bool isUnimportable() const { return IsUnimportable; }
/// Determine whether this module has been declared unimportable.
///
/// \param LangOpts The language options used for the current
/// translation unit.
///
/// \param Target The target options used for the current translation unit.
///
/// \param Req If this module is unimportable because of a missing
/// requirement, this parameter will be set to one of the requirements that
/// is not met for use of this module.
///
/// \param ShadowingModule If this module is unimportable because it is
/// shadowed, this parameter will be set to the shadowing module.
bool isUnimportable(const LangOptions &LangOpts, const TargetInfo &Target,
Requirement &Req, Module *&ShadowingModule) const;
/// Determine whether this module is available for use within the
/// current translation unit.
bool isAvailable() const { return IsAvailable; }
@ -535,7 +556,7 @@ public:
const TargetInfo &Target);
/// Mark this module and all of its submodules as unavailable.
void markUnavailable(bool MissingRequirement = false);
void markUnavailable(bool Unimportable);
/// Find the submodule with the given name.
///

View File

@ -37,7 +37,7 @@ using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
bool IsFramework, bool IsExplicit, unsigned VisibilityID)
: Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
VisibilityID(VisibilityID), IsMissingRequirement(false),
VisibilityID(VisibilityID), IsUnimportable(false),
HasIncompatibleModuleFile(false), IsAvailable(true),
IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit),
IsSystem(false), IsExternC(false), IsInferred(false),
@ -46,17 +46,12 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
NoUndeclaredIncludes(false), ModuleMapIsPrivate(false),
HasUmbrellaDir(false), NameVisibility(Hidden) {
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
if (Parent->IsSystem)
IsSystem = true;
if (Parent->IsExternC)
IsExternC = true;
if (Parent->NoUndeclaredIncludes)
NoUndeclaredIncludes = true;
if (Parent->ModuleMapIsPrivate)
ModuleMapIsPrivate = true;
IsMissingRequirement = Parent->IsMissingRequirement;
IsAvailable = Parent->isAvailable();
IsUnimportable = Parent->isUnimportable();
IsSystem = Parent->IsSystem;
IsExternC = Parent->IsExternC;
NoUndeclaredIncludes = Parent->NoUndeclaredIncludes;
ModuleMapIsPrivate = Parent->ModuleMapIsPrivate;
Parent->SubModuleIndex[Name] = Parent->SubModules.size();
Parent->SubModules.push_back(this);
@ -132,6 +127,29 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
return HasFeature;
}
bool Module::isUnimportable(const LangOptions &LangOpts,
const TargetInfo &Target, Requirement &Req,
Module *&ShadowingModule) const {
if (!IsUnimportable)
return false;
for (const Module *Current = this; Current; Current = Current->Parent) {
if (Current->ShadowingModule) {
ShadowingModule = Current->ShadowingModule;
return true;
}
for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
if (hasFeature(Current->Requirements[I].first, LangOpts, Target) !=
Current->Requirements[I].second) {
Req = Current->Requirements[I];
return true;
}
}
}
llvm_unreachable("could not find a reason why module is unimportable");
}
bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
Requirement &Req,
UnresolvedHeaderDirective &MissingHeader,
@ -139,18 +157,12 @@ bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
if (IsAvailable)
return true;
if (isUnimportable(LangOpts, Target, Req, ShadowingModule))
return false;
// FIXME: All missing headers are listed on the top-level module. Should we
// just look there?
for (const Module *Current = this; Current; Current = Current->Parent) {
if (Current->ShadowingModule) {
ShadowingModule = Current->ShadowingModule;
return false;
}
for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
if (hasFeature(Current->Requirements[I].first, LangOpts, Target) !=
Current->Requirements[I].second) {
Req = Current->Requirements[I];
return false;
}
}
if (!Current->MissingHeaders.empty()) {
MissingHeader = Current->MissingHeaders.front();
return false;
@ -287,12 +299,12 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
if (hasFeature(Feature, LangOpts, Target) == RequiredState)
return;
markUnavailable(/*MissingRequirement*/true);
markUnavailable(/*Unimportable*/true);
}
void Module::markUnavailable(bool MissingRequirement) {
auto needUpdate = [MissingRequirement](Module *M) {
return M->IsAvailable || (!M->IsMissingRequirement && MissingRequirement);
void Module::markUnavailable(bool Unimportable) {
auto needUpdate = [Unimportable](Module *M) {
return M->IsAvailable || (!M->IsUnimportable && Unimportable);
};
if (!needUpdate(this))
@ -308,7 +320,7 @@ void Module::markUnavailable(bool MissingRequirement) {
continue;
Current->IsAvailable = false;
Current->IsMissingRequirement |= MissingRequirement;
Current->IsUnimportable |= Unimportable;
for (submodule_iterator Sub = Current->submodule_begin(),
SubEnd = Current->submodule_end();
Sub != SubEnd; ++Sub) {

View File

@ -1576,7 +1576,7 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
Stack.push_back(M);
while (!Stack.empty()) {
Module *Current = Stack.pop_back_val();
if (Current->IsMissingRequirement) continue;
if (Current->IsUnimportable) continue;
Current->IsAvailable = true;
Stack.insert(Stack.end(),
Current->submodule_begin(), Current->submodule_end());

View File

@ -282,7 +282,7 @@ void ModuleMap::resolveHeader(Module *Mod,
// resolved. (Such a module still can't be built though, except from
// preprocessed source.)
if (!Header.Size && !Header.ModTime)
Mod->markUnavailable();
Mod->markUnavailable(/*Unimportable=*/false);
}
}
@ -1094,7 +1094,7 @@ Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,
new Module(Name, SourceLocation(), /*Parent=*/nullptr, IsFramework,
/*IsExplicit=*/false, NumCreatedModules++);
Result->ShadowingModule = ShadowingModule;
Result->IsAvailable = false;
Result->markUnavailable(/*Unimportable*/true);
ModuleScopeIDs[Result] = CurrentModuleScopeID;
ShadowModules.push_back(Result);
@ -2096,9 +2096,9 @@ void ModuleMapParser::parseModuleDecl() {
// If the module meets all requirements but is still unavailable, mark the
// whole tree as unavailable to prevent it from building.
if (!ActiveModule->IsAvailable && !ActiveModule->IsMissingRequirement &&
if (!ActiveModule->IsAvailable && !ActiveModule->IsUnimportable &&
ActiveModule->Parent) {
ActiveModule->getTopLevelModule()->markUnavailable();
ActiveModule->getTopLevelModule()->markUnavailable(/*Unimportable=*/false);
ActiveModule->getTopLevelModule()->MissingHeaders.append(
ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end());
}

View File

@ -5539,9 +5539,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// imported module file.
CurrentModule->Requirements.clear();
CurrentModule->MissingHeaders.clear();
CurrentModule->IsMissingRequirement =
ParentModule && ParentModule->IsMissingRequirement;
CurrentModule->IsAvailable = !CurrentModule->IsMissingRequirement;
CurrentModule->IsUnimportable =
ParentModule && ParentModule->IsUnimportable;
CurrentModule->IsAvailable = !CurrentModule->IsUnimportable;
break;
}