From aa874ab2417a1a9b2dc68bb132b47f7e19d99acf Mon Sep 17 00:00:00 2001 From: Vassil Vassilev <v.g.vassilev@gmail.com> Date: Mon, 27 Mar 2023 19:43:33 +0000 Subject: [PATCH] [cxxmodules] Implement a module attribute 'optional' to allow missing headers. This deals with the fact that our modulemaps include headers which can vary across library versions and that attribute is a way to express this. --- interpreter/cling/include/cling/std.modulemap | 4 ++-- .../src/tools/clang/include/clang/Basic/Module.h | 3 +++ .../src/tools/clang/include/clang/Lex/ModuleMap.h | 5 ++++- .../llvm/src/tools/clang/lib/Basic/Module.cpp | 3 ++- .../llvm/src/tools/clang/lib/Lex/ModuleMap.cpp | 15 ++++++++++++++- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/interpreter/cling/include/cling/std.modulemap b/interpreter/cling/include/cling/std.modulemap index d5bb22388e1..6f150355d8a 100644 --- a/interpreter/cling/include/cling/std.modulemap +++ b/interpreter/cling/include/cling/std.modulemap @@ -429,8 +429,8 @@ module "std" [system] { export * header "bits/basic_ios.h" } - module "bits/chrono.h" { - requires cplusplus20 + module "bits/chrono.h" [optional] { + requires cplusplus17 export * header "bits/chrono.h" } diff --git a/interpreter/llvm/src/tools/clang/include/clang/Basic/Module.h b/interpreter/llvm/src/tools/clang/include/clang/Basic/Module.h index 3476b05d2e9..f62e657fef7 100644 --- a/interpreter/llvm/src/tools/clang/include/clang/Basic/Module.h +++ b/interpreter/llvm/src/tools/clang/include/clang/Basic/Module.h @@ -303,6 +303,9 @@ public: /// and headers from used modules. unsigned NoUndeclaredIncludes : 1; + /// Whether the submodule is allowed to have missing headers. + unsigned IsOptional: 1; + /// Whether this module came from a "private" module map, found next /// to a regular (public) module map. unsigned ModuleMapIsPrivate : 1; diff --git a/interpreter/llvm/src/tools/clang/include/clang/Lex/ModuleMap.h b/interpreter/llvm/src/tools/clang/include/clang/Lex/ModuleMap.h index 41f85a1f572..26ed708c49e 100644 --- a/interpreter/llvm/src/tools/clang/include/clang/Lex/ModuleMap.h +++ b/interpreter/llvm/src/tools/clang/include/clang/Lex/ModuleMap.h @@ -241,9 +241,12 @@ private: /// and headers from used modules. unsigned NoUndeclaredIncludes : 1; + /// Whether we can have a submodule with missing header files. + unsigned IsOptional : 1; + Attributes() : IsSystem(false), IsExternC(false), IsExhaustive(false), - NoUndeclaredIncludes(false) {} + NoUndeclaredIncludes(false), IsOptional(false) {} }; /// A directory for which framework modules can be inferred. diff --git a/interpreter/llvm/src/tools/clang/lib/Basic/Module.cpp b/interpreter/llvm/src/tools/clang/lib/Basic/Module.cpp index 07ee82ceb60..ff91ddcc880 100644 --- a/interpreter/llvm/src/tools/clang/lib/Basic/Module.cpp +++ b/interpreter/llvm/src/tools/clang/lib/Basic/Module.cpp @@ -43,7 +43,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, IsSystem(false), IsExternC(false), IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false), InferExportWildcard(false), ConfigMacrosExhaustive(false), - NoUndeclaredIncludes(false), ModuleMapIsPrivate(false), + NoUndeclaredIncludes(false), IsOptional(false), ModuleMapIsPrivate(false), NameVisibility(Hidden) { if (Parent) { IsAvailable = Parent->isAvailable(); @@ -51,6 +51,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, IsSystem = Parent->IsSystem; IsExternC = Parent->IsExternC; NoUndeclaredIncludes = Parent->NoUndeclaredIncludes; + IsOptional = Parent->IsOptional; ModuleMapIsPrivate = Parent->ModuleMapIsPrivate; Parent->SubModuleIndex[Name] = Parent->SubModules.size(); diff --git a/interpreter/llvm/src/tools/clang/lib/Lex/ModuleMap.cpp b/interpreter/llvm/src/tools/clang/lib/Lex/ModuleMap.cpp index f9af7c2a24f..7feb88508b9 100644 --- a/interpreter/llvm/src/tools/clang/lib/Lex/ModuleMap.cpp +++ b/interpreter/llvm/src/tools/clang/lib/Lex/ModuleMap.cpp @@ -274,6 +274,8 @@ void ModuleMap::resolveHeader(Module *Mod, // this was supposed to modularize the builtin header alone. } else if (Header.Kind == Module::HK_Excluded) { // Ignore missing excluded header files. They're optional anyway. + } else if (Mod->IsOptional) { + // Optional submodules can have missing headers. } else { // If we find a module that has a missing header, we mark this module as // unavailable and store the header directive for displaying diagnostics. @@ -1037,6 +1039,7 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir, Result->IsExternC |= Attrs.IsExternC; Result->ConfigMacrosExhaustive |= Attrs.IsExhaustive; Result->NoUndeclaredIncludes |= Attrs.NoUndeclaredIncludes; + Result->IsOptional |= Attrs.IsOptional; Result->Directory = FrameworkDir; // Chop off the first framework bit, as that is implied. @@ -1749,7 +1752,10 @@ namespace { AT_exhaustive, /// The 'no_undeclared_includes' attribute. - AT_no_undeclared_includes + AT_no_undeclared_includes, + + /// The 'optional' attribute. + AT_optional }; } // namespace @@ -2005,6 +2011,8 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule->IsSystem = true; if (Attrs.IsExternC) ActiveModule->IsExternC = true; + if (Attrs.IsOptional) + ActiveModule->IsOptional = true; if (Attrs.NoUndeclaredIncludes || (!ActiveModule->Parent && ModuleName == "Darwin")) ActiveModule->NoUndeclaredIncludes = true; @@ -2905,6 +2913,7 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { .Case("exhaustive", AT_exhaustive) .Case("extern_c", AT_extern_c) .Case("no_undeclared_includes", AT_no_undeclared_includes) + .Case("optional", AT_optional) .Case("system", AT_system) .Default(AT_unknown); switch (Attribute) { @@ -2928,6 +2937,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { case AT_no_undeclared_includes: Attrs.NoUndeclaredIncludes = true; break; + + case AT_optional: + Attrs.IsOptional = true; + break; } consumeToken(); -- GitLab