Hi rsmith, doug.gregor, chandlerc,
I have picked up this patch form Lawrence
(http://llvm-reviews.chandlerc.com/D1063) and only did minor changes.
Hopefully, I can pick up the original spot in the review queue ;-).
>From the original change description (updated as appropriate):
This patch adds a check that ensures that modules only use modules they have so
declared.
USER INTERFACE
Add a statement on intended module use to the module.map grammar. This
statement is modeled on the existing export statement.
use wildcard-module-id
This enforcement is off by default, but may be turned on with the new option
-fmodules-decluse.
When enforcing the module semantics, we also need to consider a source file
part of a module. This is achieved with a compiler option
-fmodule-source-for=<module-id>.
The compiler at present only applies restrictions to the module directly being
built. To add indirect checks, use the option -fmodules-indirect-check. This
indirect flag is also applied to private header use.
IMPLEMENTATION
The module checking is done from within Preprocessor::LookupFile, and the code
there has been refactored.
The -fmodule-source-for=<module-id> value is stored in ModuleMap::SourceModule.
The type ExportDecl in Module has been generalized to WildModuleRef, likewise
UnresolvedExportDecl to UnresolvedWildModuleRef. There has been refactoring to
avoid duplicate code in using these types.
MISSING
This patch is missing serialization of 'use' declarations, for which I need
some feedback. See the FIXME comments.
The error messages from module compilations are suppressed, which makes
diagnosing issues tough.
http://llvm-reviews.chandlerc.com/D1546
Files:
docs/Modules.rst
include/clang/Basic/DiagnosticLexKinds.td
include/clang/Basic/LangOptions.def
include/clang/Basic/LangOptions.h
include/clang/Basic/Module.h
include/clang/Driver/Options.td
include/clang/Lex/ModuleMap.h
include/clang/Lex/Preprocessor.h
lib/Basic/Module.cpp
lib/Driver/Tools.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Lex/HeaderSearch.cpp
lib/Lex/ModuleMap.cpp
lib/Lex/PPDirectives.cpp
lib/Sema/Sema.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Modules/Inputs/declare-use/a.h
test/Modules/Inputs/declare-use/b.h
test/Modules/Inputs/declare-use/c.h
test/Modules/Inputs/declare-use/d.h
test/Modules/Inputs/declare-use/e.h
test/Modules/Inputs/declare-use/f.h
test/Modules/Inputs/declare-use/g.h
test/Modules/Inputs/declare-use/g1.h
test/Modules/Inputs/declare-use/h.h
test/Modules/Inputs/declare-use/h1.h
test/Modules/Inputs/declare-use/module.map
test/Modules/declare-use1.cpp
test/Modules/declare-use2.cpp
Index: docs/Modules.rst
===================================================================
--- docs/Modules.rst
+++ docs/Modules.rst
@@ -188,6 +188,17 @@
``-module-file-info <module file name>``
Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with.
+``-fmodules-decluse``
+ Enable checking of module ``use`` declarations.
+
+``-fmodules-source-for=module-id``
+ Consider a source file as a part of the given module.
+
+``-fmodules-indirect-check``
+ Extend checking of module imports and includes to indirect uses of modules.
+
+
+
Module Map Language
===================
@@ -238,6 +249,7 @@
``conflict`` ``framework`` ``requires``
``exclude`` ``header`` ``private``
``explicit`` ``link`` ``umbrella``
+ ``use``
Module map file
---------------
@@ -291,6 +303,7 @@
*umbrella-dir-declaration*
*submodule-declaration*
*export-declaration*
+ *use-declaration*
*link-declaration*
*config-macros-declaration*
*conflict-declaration*
@@ -529,6 +542,36 @@
compatibility for programs that rely on transitive inclusion (i.e.,
all of them).
+Use declaration
+~~~~~~~~~~~~~~~
+A *use-declaration* specifies one of the other modules that the module is allowed to use. An import or include not matching one of these is rejected when the option *-fmodules-decluse*.
+
+.. parsed-literal::
+
+ *use-declaration*:
+ ``use`` *wildcard-module-id*
+
+**Example**:: In the following example, use of A from C is not declared, so will trigger a warning.
+
+.. parsed-literal::
+
+ module A {
+ header "a.h"
+ }
+
+ module B {
+ header "b.h"
+ }
+
+ module C {
+ header "c.h"
+ use B
+ }
+
+When compiling a source file that implements a module, use the option ``-fmodule-source-for=``module-id to indicate that the source file is logically part of that module.
+
+The compiler at present only applies restrictions to the module directly being built. To add indirect checks, use the option ``-fmodules-indirect-check``.
+
Link declaration
~~~~~~~~~~~~~~~~
A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.
Index: include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- include/clang/Basic/DiagnosticLexKinds.td
+++ include/clang/Basic/DiagnosticLexKinds.td
@@ -538,8 +538,8 @@
"umbrella directory '%0' not found">;
def err_mmap_umbrella_clash : Error<
"umbrella for module '%0' already covers this directory">;
-def err_mmap_export_module_id : Error<
- "expected an exported module name or '*'">;
+def err_mmap_module_id : Error<
+ "expected a module name or '*'">;
def err_mmap_expected_library_name : Error<
"expected %select{library|framework}0 name as a string">;
def err_mmap_config_macro_submodule : Error<
@@ -594,7 +594,9 @@
"expected a module name in '__building_module' expression">;
def error_use_of_private_header_outside_module : Error<
"use of private header from outside its module: '%0'">;
-
+def error_undeclared_use_of_module : Error<
+ "use of a module not declared used: '%0'">;
+
def warn_header_guard : Warning<
"%0 is used as a header guard here, followed by #define of a different macro">,
InGroup<DiagGroup<"header-guard">>;
Index: include/clang/Basic/LangOptions.def
===================================================================
--- include/clang/Basic/LangOptions.def
+++ include/clang/Basic/LangOptions.def
@@ -94,6 +94,8 @@
LANGOPT(MathErrno , 1, 1, "errno support for math functions")
BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time")
LANGOPT(Modules , 1, 0, "modules extension to C")
+LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses")
+LANGOPT(ModulesIndirectCheck , 1, 0, "check indirect uses of modules")
LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
Index: include/clang/Basic/LangOptions.h
===================================================================
--- include/clang/Basic/LangOptions.h
+++ include/clang/Basic/LangOptions.h
@@ -80,6 +80,9 @@
/// \brief The name of the current module.
std::string CurrentModule;
+ /// \brief The module for which the translation unit is a source.
+ std::string ModuleSourceFor;
+
/// \brief Options for parsing comments.
CommentOptions CommentOpts;
Index: include/clang/Basic/Module.h
===================================================================
--- include/clang/Basic/Module.h
+++ include/clang/Basic/Module.h
@@ -155,21 +155,23 @@
/// \brief The set of modules imported by this module, and on which this
/// module depends.
SmallVector<Module *, 2> Imports;
-
- /// \brief Describes an exported module.
+
+ /// \brief Describes a wildcard module reference.
///
- /// The pointer is the module being re-exported, while the bit will be true
+ /// The pointer is the module being referenced, while the bit will be true
/// to indicate that this is a wildcard export.
- typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl;
+ typedef llvm::PointerIntPair<Module *, 1, bool> WildModuleRef;
/// \brief The set of export declarations.
- SmallVector<ExportDecl, 2> Exports;
+ SmallVector<WildModuleRef, 2> Exports;
- /// \brief Describes an exported module that has not yet been resolved
+ /// \brief Describes an wildcard module reference
+ /// that has not yet been resolved
/// (perhaps because the module it refers to has not yet been loaded).
- struct UnresolvedExportDecl {
- /// \brief The location of the 'export' keyword in the module map file.
- SourceLocation ExportLoc;
+ struct UnresolvedWildModuleRef {
+ /// \brief The location of the 'export' or 'use' keyword
+ /// in the module map file.
+ SourceLocation KeyLoc;
/// \brief The name of the module.
ModuleId Id;
@@ -181,7 +183,13 @@
};
/// \brief The set of export declarations that have yet to be resolved.
- SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
+ SmallVector<UnresolvedWildModuleRef, 2> UnresolvedExports;
+
+ /// \brief The set of uses declarations.
+ SmallVector<WildModuleRef, 2> DirectUses;
+
+ /// \brief The set of export declarations that have yet to be resolved.
+ SmallVector<UnresolvedWildModuleRef, 2> UnresolvedDirectUses;
/// \brief A library or framework to link against when an entity from this
/// module is used.
@@ -392,10 +400,33 @@
/// \brief Returns the exported modules based on the wildcard restrictions.
void getExportedModules(SmallVectorImpl<Module *> &Exported) const;
+ /// \brief Returns the used modules based on the wildcard restrictions.
+ void getUsedModules(SmallVectorImpl<Module *> &Used) const;
+
static StringRef getModuleInputBufferName() {
return "<module-includes>";
}
+private:
+ /// \brief For this module,
+ /// print module map line that uses resolved wildcards to the given stream.
+ ///
+ void printWildcardRefs(
+ raw_ostream &OS,
+ unsigned Indent,
+ const char *Keyword,
+ const SmallVectorImpl<WildModuleRef> &Refs) const;
+
+ /// \brief For this module,
+ /// print module map line that uses unresolved wildcards to the given stream.
+ ///
+ void printWildcardRefs(
+ raw_ostream &OS,
+ unsigned Indent,
+ const char *Keyword,
+ const SmallVectorImpl<UnresolvedWildModuleRef> &Refs) const;
+
+public:
/// \brief Print the module map for this module to the given stream.
///
void print(raw_ostream &OS, unsigned Indent = 0) const;
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td
+++ include/clang/Driver/Options.td
@@ -567,6 +567,15 @@
HelpText<"Read module maps to understand the structure of library headers">;
def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Ignore the definition of the given macro when building and loading modules">;
+def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>,
+ Flags<[DriverOption,CC1Option]>,
+ HelpText<"Require declaration of modules used within a module">;
+def fmodules_indirect_check : Flag <["-"], "fmodules-indirect-check">,
+ Group<f_Group>, Flags<[DriverOption,CC1Option]>,
+ HelpText<"Check indirect uses of modules for correctness.">;
+def fmodule_source_for : Joined<["-"], "fmodule-source-for=">, Group<i_Group>,
+ Flags<[DriverOption,CC1Option]>, MetaVarName<"<module-id>">,
+ HelpText<"Specify that the current source file is source for the module-id">;
def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
@@ -627,6 +636,10 @@
Flags<[DriverOption]>;
def fno_module_maps : Flag <["-"], "fno-module-maps">, Group<f_Group>,
Flags<[DriverOption]>;
+def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group<f_Group>,
+ Flags<[DriverOption]>;
+def fno_modules_indirect_check : Flag <["-"], "fno-modules-indirect-check">,
+ Group<f_Group>, Flags<[DriverOption]>;
def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group<f_Group>;
def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>;
def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group<f_Group>;
Index: include/clang/Lex/ModuleMap.h
===================================================================
--- include/clang/Lex/ModuleMap.h
+++ include/clang/Lex/ModuleMap.h
@@ -55,6 +55,12 @@
// The module that we are building; related to \c LangOptions::CurrentModule.
Module *CompilingModule;
+public:
+ // The module that the .cc source file is associated with.
+ Module *SourceModule;
+ std::string SourceModuleName;
+
+private:
/// \brief The top-level modules that are known.
llvm::StringMap<Module *> Modules;
@@ -151,9 +157,10 @@
///
/// \returns The resolved export declaration, which will have a NULL pointer
/// if the export could not be resolved.
- Module::ExportDecl
- resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved,
- bool Complain) const;
+ Module::WildModuleRef
+ resolveWildRef(Module *Mod,
+ const Module::UnresolvedWildModuleRef &Unresolved,
+ bool Complain) const;
/// \brief Resolve the given module id to an actual module.
///
@@ -289,6 +296,20 @@
/// module, or NULL if the module definition was inferred.
const FileEntry *getContainingModuleMapFile(Module *Module) const;
+ /// \brief Resolve all of the unresolved wildcards.
+ ///
+ /// \param Mod The module whose exports should be resolved.
+ ///
+ /// \param Complain Whether to emit diagnostics for failures.
+ ///
+ /// \returns true if any errors were encountered while resolving exports,
+ /// false otherwise.
+ bool resolveWildcards(
+ Module *Mod,
+ SmallVectorImpl<Module::UnresolvedWildModuleRef> &Unresolved,
+ SmallVectorImpl<Module::WildModuleRef> &Resolved,
+ bool Complain);
+
/// \brief Resolve all of the unresolved exports in the given module.
///
/// \param Mod The module whose exports should be resolved.
@@ -299,6 +320,16 @@
/// false otherwise.
bool resolveExports(Module *Mod, bool Complain);
+ /// \brief Resolve all of the unresolved uses in the given module.
+ ///
+ /// \param Mod The module whose uses should be resolved.
+ ///
+ /// \param Complain Whether to emit diagnostics for failures.
+ ///
+ /// \returns true if any errors were encountered while resolving uses,
+ /// false otherwise.
+ bool resolveUses(Module *Mod, bool Complain);
+
/// \brief Resolve all of the unresolved conflicts in the given module.
///
/// \param Mod The module whose conflicts should be resolved.
Index: include/clang/Lex/Preprocessor.h
===================================================================
--- include/clang/Lex/Preprocessor.h
+++ include/clang/Lex/Preprocessor.h
@@ -1445,6 +1445,31 @@
void HandleImportDirective(SourceLocation HashLoc, Token &Tok);
void HandleMicrosoftImportDirective(Token &Tok);
+ // Module inclusion testing.
+ /// \brief Find the module for the source or header file that \p FilenameLoc
+ /// points to.
+ Module *getModuleForLocation(SourceLocation FilenameLoc);
+
+ /// \brief Verify that a private header is included only from within its
+ /// module.
+ bool violatesPrivateInclude(Module *RequestingModule,
+ const FileEntry *IncFileEnt,
+ ModuleMap::ModuleHeaderRole Role,
+ Module *RequestedModule);
+
+ /// \brief Verify that a module includes headers only from modules that it
+ /// has declared that it uses.
+ bool violatesUseDeclarations(Module *RequestingModule,
+ Module *RequestedModule);
+
+ /// \brief Verify that it is legal for the source file that \p FilenameLoc
+ /// points to to include the file \p Filename.
+ ///
+ /// Tries to reuse \p IncFileEnt and \p SuggestedModule.
+ void verifyModuleInclude(SourceLocation FilenameLoc, StringRef Filename,
+ const FileEntry *IncFileEnt,
+ ModuleMap::KnownHeader *SuggestedModule);
+
// Macro handling.
void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
void HandleUndefDirective(Token &Tok);
Index: lib/Basic/Module.cpp
===================================================================
--- lib/Basic/Module.cpp
+++ lib/Basic/Module.cpp
@@ -260,6 +260,55 @@
}
}
+void Module::getUsedModules(SmallVectorImpl<Module *> &Used) const {
+ for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) {
+ Module *Mod = DirectUses[I].getPointer();
+ if (!DirectUses[I].getInt()) {
+ // Oputput a named module directly; no wildcards involved.
+ Used.push_back(Mod);
+ }
+ }
+ // FIXME: Add handling of wildcard module specifications.
+}
+
+void Module::printWildcardRefs(
+ raw_ostream &OS,
+ unsigned Indent,
+ const char *Keyword,
+ const SmallVectorImpl<WildModuleRef> &Refs) const {
+ for (unsigned I = 0, N = Refs.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << Keyword << " ";
+ if (Module *Restriction = Refs[I].getPointer()) {
+ OS << Restriction->getFullModuleName();
+ if (Refs[I].getInt())
+ OS << ".*";
+ } else {
+ OS << "*";
+ }
+ OS << "\n";
+ }
+}
+
+void Module::printWildcardRefs(
+ raw_ostream &OS,
+ unsigned Indent,
+ const char *Keyword,
+ const SmallVectorImpl<UnresolvedWildModuleRef> &Refs) const {
+ for (unsigned I = 0, N = Refs.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << Keyword << " ";
+ printModuleId(OS, Refs[I].Id);
+ if (Refs[I].Wildcard) {
+ if (Refs[I].Id.empty())
+ OS << "*";
+ else
+ OS << ".*";
+ }
+ OS << "\n";
+ }
+}
+
void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.indent(Indent);
if (IsFramework)
@@ -336,31 +385,13 @@
MI != MIEnd; ++MI)
(*MI)->print(OS, Indent + 2);
- for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
- OS.indent(Indent + 2);
- OS << "export ";
- if (Module *Restriction = Exports[I].getPointer()) {
- OS << Restriction->getFullModuleName();
- if (Exports[I].getInt())
- OS << ".*";
- } else {
- OS << "*";
- }
- OS << "\n";
- }
+ printWildcardRefs(OS, Indent, "export", Exports);
- for (unsigned I = 0, N = UnresolvedExports.size(); I != N; ++I) {
- OS.indent(Indent + 2);
- OS << "export ";
- printModuleId(OS, UnresolvedExports[I].Id);
- if (UnresolvedExports[I].Wildcard) {
- if (UnresolvedExports[I].Id.empty())
- OS << "*";
- else
- OS << ".*";
- }
- OS << "\n";
- }
+ printWildcardRefs(OS, Indent, "export", UnresolvedExports);
+
+ printWildcardRefs(OS, Indent, "use", DirectUses);
+
+ printWildcardRefs(OS, Indent, "use", UnresolvedDirectUses);
for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) {
OS.indent(Indent + 2);
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -3008,6 +3008,28 @@
CmdArgs.push_back("-fmodule-maps");
}
+ // -fmodule-decluse checks that modules used are declared so (off by default).
+ if (Args.hasFlag(options::OPT_fmodules_decluse,
+ options::OPT_fno_modules_decluse,
+ false)) {
+ CmdArgs.push_back("-fmodule-decluse");
+ }
+
+ // -fmodule-indirect-check extends module checking to indirect uses
+ // (off by default).
+ if (Args.hasFlag(options::OPT_fmodules_indirect_check,
+ options::OPT_fno_modules_indirect_check,
+ false)) {
+ CmdArgs.push_back("-fmodule-indirect-check");
+ }
+
+ // -fmodule-source-for enables specifing that a source file is part of a
+ // module. (none by default).
+ if (Arg *A = Args.getLastArg(options::OPT_fmodule_source_for)) {
+ CmdArgs.push_back("-fmodule-source-for");
+ CmdArgs.push_back(A->getValue());
+ }
+
// If a module path was provided, pass it along. Otherwise, use a temporary
// directory.
if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) {
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -1274,6 +1274,9 @@
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Modules = Args.hasArg(OPT_fmodules);
+ Opts.ModulesDeclUse = Args.hasArg(OPT_fmodules_decluse);
+ Opts.ModulesIndirectCheck = Args.hasArg(OPT_fmodules_indirect_check);
+ Opts.ModuleSourceFor = Args.getLastArgValue(OPT_fmodule_source_for);
Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
Index: lib/Lex/HeaderSearch.cpp
===================================================================
--- lib/Lex/HeaderSearch.cpp
+++ lib/Lex/HeaderSearch.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/Capacity.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#if defined(LLVM_ON_UNIX)
#include <limits.h>
Index: lib/Lex/ModuleMap.cpp
===================================================================
--- lib/Lex/ModuleMap.cpp
+++ lib/Lex/ModuleMap.cpp
@@ -35,22 +35,22 @@
#endif
using namespace clang;
-Module::ExportDecl
-ModuleMap::resolveExport(Module *Mod,
- const Module::UnresolvedExportDecl &Unresolved,
- bool Complain) const {
+Module::WildModuleRef
+ModuleMap::resolveWildRef(Module *Mod,
+ const Module::UnresolvedWildModuleRef &Unresolved,
+ bool Complain) const {
// We may have just a wildcard.
if (Unresolved.Id.empty()) {
assert(Unresolved.Wildcard && "Invalid unresolved export");
- return Module::ExportDecl(0, true);
+ return Module::WildModuleRef(0, true);
}
// Resolve the module-id.
Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain);
if (!Context)
- return Module::ExportDecl();
+ return Module::WildModuleRef();
- return Module::ExportDecl(Context, Unresolved.Wildcard);
+ return Module::WildModuleRef(Context, Unresolved.Wildcard);
}
Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
@@ -240,7 +240,7 @@
// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
- Result->Exports.push_back(Module::ExportDecl(0, true));
+ Result->Exports.push_back(Module::WildModuleRef(0, true));
}
// Infer a submodule with the same name as this header file.
@@ -254,7 +254,7 @@
// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
- Result->Exports.push_back(Module::ExportDecl(0, true));
+ Result->Exports.push_back(Module::WildModuleRef(0, true));
} else {
// Record each of the directories we stepped through as being part of
// the module we found, since the umbrella header covers them all.
@@ -387,6 +387,10 @@
// Create a new module with this name.
Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
IsExplicit);
+ if (LangOpts.ModuleSourceFor == Name) {
+ SourceModule = Result;
+ SourceModuleName = Name;
+ }
if (!Parent) {
Modules[Name] = Result;
if (!LangOpts.CurrentModule.empty() && !CompilingModule &&
@@ -518,6 +522,10 @@
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
/*IsFramework=*/true, /*IsExplicit=*/false);
+ if (LangOpts.ModuleSourceFor == ModuleName) {
+ SourceModule = Result;
+ SourceModuleName = ModuleName;
+ }
if (IsSystem)
Result->IsSystem = IsSystem;
@@ -530,7 +538,7 @@
UmbrellaDirs[UmbrellaHeader->getDir()] = Result;
// export *
- Result->Exports.push_back(Module::ExportDecl(0, true));
+ Result->Exports.push_back(Module::WildModuleRef(0, true));
// module * { export * }
Result->InferSubmodules = true;
@@ -641,20 +649,32 @@
}
}
-bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
+bool ModuleMap::resolveWildcards(
+ Module *Mod,
+ SmallVectorImpl<Module::UnresolvedWildModuleRef> &Unresolved,
+ SmallVectorImpl<Module::WildModuleRef> &Resolved,
+ bool Complain) {
bool HadError = false;
- for (unsigned I = 0, N = Mod->UnresolvedExports.size(); I != N; ++I) {
- Module::ExportDecl Export = resolveExport(Mod, Mod->UnresolvedExports[I],
- Complain);
- if (Export.getPointer() || Export.getInt())
- Mod->Exports.push_back(Export);
+ for (unsigned I = 0, N = Unresolved.size(); I != N; ++I) {
+ Module::WildModuleRef Output = resolveWildRef(Mod, Unresolved[I], Complain);
+ if (Output.getPointer() || Output.getInt())
+ Resolved.push_back(Output);
else
HadError = true;
}
- Mod->UnresolvedExports.clear();
+ Unresolved.clear();
return HadError;
}
+bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
+ return resolveWildcards(Mod, Mod->UnresolvedExports, Mod->Exports, Complain);
+}
+
+bool ModuleMap::resolveUses(Module *Mod, bool Complain) {
+ return resolveWildcards(Mod, Mod->UnresolvedDirectUses, Mod->DirectUses,
+ Complain);
+}
+
bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
bool HadError = false;
for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
@@ -728,6 +748,7 @@
Period,
PrivateKeyword,
UmbrellaKeyword,
+ UseKeyword,
RequiresKeyword,
Star,
StringLiteral,
@@ -818,7 +839,11 @@
void parseHeaderDecl(clang::MMToken::TokenKind,
SourceLocation LeadingLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
+ void parseWildcardID(
+ SourceLocation KeywordLoc,
+ SmallVectorImpl<Module::UnresolvedWildModuleRef> &AllUnresolved);
void parseExportDecl();
+ void parseUseDecl();
void parseLinkDecl();
void parseConfigMacros();
void parseConflict();
@@ -872,6 +897,7 @@
.Case("private", MMToken::PrivateKeyword)
.Case("requires", MMToken::RequiresKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
+ .Case("use", MMToken::UseKeyword)
.Default(MMToken::Identifier);
break;
@@ -1201,6 +1227,10 @@
case MMToken::ExportKeyword:
parseExportDecl();
break;
+
+ case MMToken::UseKeyword:
+ parseUseDecl();
+ break;
case MMToken::RequiresKeyword:
parseRequiresDecl();
@@ -1509,15 +1539,21 @@
///
/// export-declaration:
/// 'export' wildcard-module-id
+void ModuleMapParser::parseExportDecl() {
+ assert(Tok.is(MMToken::ExportKeyword));
+ SourceLocation ExportLoc = consumeToken();
+ parseWildcardID(ExportLoc, ActiveModule->UnresolvedExports);
+}
+
+/// \brief Parse a module wildcard id.
///
/// wildcard-module-id:
/// identifier
/// '*'
/// identifier '.' wildcard-module-id
-void ModuleMapParser::parseExportDecl() {
- assert(Tok.is(MMToken::ExportKeyword));
- SourceLocation ExportLoc = consumeToken();
-
+void ModuleMapParser::parseWildcardID(
+ SourceLocation KeywordLoc,
+ SmallVectorImpl<Module::UnresolvedWildModuleRef> &AllUnresolved) {
// Parse the module-id with an optional wildcard at the end.
ModuleId ParsedModuleId;
bool Wildcard = false;
@@ -1541,15 +1577,25 @@
break;
}
- Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
+ Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
HadError = true;
return;
} while (true);
- Module::UnresolvedExportDecl Unresolved = {
- ExportLoc, ParsedModuleId, Wildcard
+ Module::UnresolvedWildModuleRef Unresolved = {
+ KeywordLoc, ParsedModuleId, Wildcard
};
- ActiveModule->UnresolvedExports.push_back(Unresolved);
+ AllUnresolved.push_back(Unresolved);
+}
+
+/// \brief Parse a module uses declaration.
+///
+/// uses-declaration:
+/// 'uses' wildcard-module-id
+void ModuleMapParser::parseUseDecl() {
+ assert(Tok.is(MMToken::UseKeyword));
+ SourceLocation UseLoc = consumeToken();
+ parseWildcardID(UseLoc, ActiveModule->UnresolvedDirectUses);
}
/// \brief Parse a link declaration.
@@ -1948,6 +1994,7 @@
case MMToken::Star:
case MMToken::StringLiteral:
case MMToken::UmbrellaKeyword:
+ case MMToken::UseKeyword:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
HadError = true;
consumeToken();
Index: lib/Lex/PPDirectives.cpp
===================================================================
--- lib/Lex/PPDirectives.cpp
+++ lib/Lex/PPDirectives.cpp
@@ -532,6 +532,88 @@
}
}
+Module *Preprocessor::getModuleForLocation(SourceLocation FilenameLoc) {
+ ModuleMap &ModMap = HeaderInfo.getModuleMap();
+ if (SourceMgr.isInMainFile(FilenameLoc)) {
+ if (Module *CurMod = getCurrentModule())
+ return CurMod; // Compiling a module.
+ return HeaderInfo.getModuleMap().SourceModule; // Compiling a source.
+ }
+ // Try to determine the module of the include directive.
+ FileID IDOfIncl = SourceMgr.getFileID(FilenameLoc);
+ if (const FileEntry *EntryOfIncl = SourceMgr.getFileEntryForID(IDOfIncl)) {
+ // The include comes from a file.
+ return ModMap.findModuleForHeader(EntryOfIncl).getModule();
+ } else {
+ // The include does not come from a file,
+ // so it is probably a module compilation.
+ return getCurrentModule();
+ }
+}
+
+bool Preprocessor::violatesPrivateInclude(
+ Module *RequestingModule,
+ const FileEntry *IncFileEnt,
+ ModuleMap::ModuleHeaderRole Role,
+ Module *RequestedModule) {
+ #ifndef NDEBUG
+ // Check for consistency between the module header role
+ // as obtained from the lookup and as obtained from the module.
+ // This check is not cheap, so enable it only for debugging.
+ SmallVectorImpl<const FileEntry *> &PvtHdrs
+ = RequestedModule->PrivateHeaders;
+ SmallVectorImpl<const FileEntry *>::iterator Look
+ = std::find(PvtHdrs.begin(), PvtHdrs.end(), IncFileEnt);
+ bool IsPrivate = Look != PvtHdrs.end();
+ assert((IsPrivate && Role == ModuleMap::PrivateHeader)
+ || (!IsPrivate && Role != ModuleMap::PrivateHeader));
+ #endif
+ return Role == ModuleMap::PrivateHeader &&
+ RequestedModule->getTopLevelModule() != RequestingModule;
+}
+
+bool Preprocessor::violatesUseDeclarations(
+ Module *RequestingModule,
+ Module *RequestedModule) {
+ ModuleMap &ModMap = HeaderInfo.getModuleMap();
+ ModMap.resolveUses(RequestingModule, /*Complain=*/false);
+ SmallVector<Module*, 4> AllowedUses;
+ RequestingModule->getUsedModules(AllowedUses);
+ SmallVectorImpl<Module*>::iterator Declared
+ = std::find(AllowedUses.begin(), AllowedUses.end(), RequestedModule);
+ return Declared == AllowedUses.end();
+}
+
+void Preprocessor::verifyModuleInclude(
+ SourceLocation FilenameLoc,
+ StringRef Filename,
+ const FileEntry *IncFileEnt,
+ ModuleMap::KnownHeader *SuggestedModule) {
+ Module *RequestingModule = getModuleForLocation(FilenameLoc);
+ Module *RequestedModule = SuggestedModule->getModule();
+ if (!RequestedModule)
+ RequestedModule = HeaderInfo.findModuleForHeader(IncFileEnt).getModule();
+
+ if (RequestingModule == RequestedModule)
+ return; // No faults wihin a module, or between files both not in modules.
+
+ if (RequestingModule != HeaderInfo.getModuleMap().SourceModule &&
+ !getLangOpts().ModulesIndirectCheck)
+ return; // No errors for indirect modules.
+ // This may be a bit of a problem for modules with no source files.
+
+ if (RequestedModule &&
+ violatesPrivateInclude(RequestingModule, IncFileEnt,
+ SuggestedModule->getRole(), RequestedModule))
+ Diag(FilenameLoc, diag::error_use_of_private_header_outside_module)
+ << Filename;
+
+ if (RequestingModule && getLangOpts().ModulesDeclUse &&
+ violatesUseDeclarations(RequestingModule, RequestedModule))
+ Diag(FilenameLoc, diag::error_undeclared_use_of_module)
+ << Filename;
+}
+
const FileEntry *Preprocessor::LookupFile(
SourceLocation FilenameLoc,
StringRef Filename,
@@ -567,29 +649,8 @@
Filename, isAngled, FromDir, CurDir, CurFileEnt,
SearchPath, RelativePath, SuggestedModule, SkipCache);
if (FE) {
- if (SuggestedModule) {
- Module *RequestedModule = SuggestedModule->getModule();
- if (RequestedModule) {
- ModuleMap::ModuleHeaderRole Role = SuggestedModule->getRole();
- #ifndef NDEBUG
- // Check for consistency between the module header role
- // as obtained from the lookup and as obtained from the module.
- // This check is not cheap, so enable it only for debugging.
- SmallVectorImpl<const FileEntry *> &PvtHdrs
- = RequestedModule->PrivateHeaders;
- SmallVectorImpl<const FileEntry *>::iterator Look
- = std::find(PvtHdrs.begin(), PvtHdrs.end(), FE);
- bool IsPrivate = Look != PvtHdrs.end();
- assert((IsPrivate && Role == ModuleMap::PrivateHeader)
- || (!IsPrivate && Role != ModuleMap::PrivateHeader));
- #endif
- if (Role == ModuleMap::PrivateHeader) {
- if (RequestedModule->getTopLevelModule() != getCurrentModule())
- Diag(FilenameLoc, diag::error_use_of_private_header_outside_module)
- << Filename;
- }
- }
- }
+ if (SuggestedModule)
+ verifyModuleInclude(FilenameLoc, Filename, FE, SuggestedModule);
return FE;
}
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -637,6 +637,7 @@
// diagnostic client to deal with complaints in the module map at this
// point.
ModMap.resolveExports(Mod, /*Complain=*/false);
+ ModMap.resolveUses(Mod, /*Complain=*/false);
ModMap.resolveConflicts(Mod, /*Complain=*/false);
// Queue the submodules, so their exports will also be resolved.
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -3023,11 +3023,13 @@
case UnresolvedModuleRef::Export:
if (ResolvedMod || Unresolved.IsWildcard)
Unresolved.Mod->Exports.push_back(
- Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ Module::WildModuleRef(ResolvedMod, Unresolved.IsWildcard));
continue;
}
}
UnresolvedModuleRefs.clear();
+
+ //FIXME: How do we load the 'use'd modules? They may not be submodules.
InitializeContext();
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -2423,6 +2423,8 @@
Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
}
+ //FIXME: How do we emit the 'use'd modules? They may not be submodules.
+
// Emit the link libraries.
for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) {
Record.clear();
Index: test/Modules/Inputs/declare-use/a.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/a.h
@@ -0,0 +1,4 @@
+#ifndef A_H
+#define A_H
+const int a = 2;
+#endif
Index: test/Modules/Inputs/declare-use/b.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/b.h
@@ -0,0 +1,4 @@
+#ifndef B_H
+#define B_H
+const int b = 3;
+#endif
Index: test/Modules/Inputs/declare-use/c.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/c.h
@@ -0,0 +1,6 @@
+#ifndef C_H
+#define C_H
+#include "a.h"
+#include "b.h"
+const int c = a+b;
+#endif
Index: test/Modules/Inputs/declare-use/d.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/d.h
@@ -0,0 +1,6 @@
+#ifndef D_H
+#define D_H
+#include "a.h"
+#include "b.h"
+const int d = a+b;
+#endif
Index: test/Modules/Inputs/declare-use/e.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/e.h
@@ -0,0 +1,6 @@
+#ifndef E_H
+#define E_H
+#include "a.h"
+#include "b.h"
+const int e = a*b;
+#endif
Index: test/Modules/Inputs/declare-use/f.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/f.h
@@ -0,0 +1,6 @@
+#ifndef F_H
+#define F_H
+#include "a.h"
+#include "b.h"
+const int f = a+b;
+#endif
Index: test/Modules/Inputs/declare-use/g.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/g.h
@@ -0,0 +1,6 @@
+#ifndef G_H
+#define G_H
+#include "c.h"
+#include "g1.h"
+const int g1 = aux_g*c*7;
+#endif
Index: test/Modules/Inputs/declare-use/g1.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/g1.h
@@ -0,0 +1 @@
+int aux_g = 11;
Index: test/Modules/Inputs/declare-use/h.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/h.h
@@ -0,0 +1,7 @@
+#ifndef H_H
+#define H_H
+#include "c.h"
+#include "d.h" // expected-error {{use of a header from a module not declared used}}
+#include "h1.h"
+const int h1 = aux_h*c*7*d;
+#endif
Index: test/Modules/Inputs/declare-use/h1.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/h1.h
@@ -0,0 +1 @@
+int aux_h = 13;
Index: test/Modules/Inputs/declare-use/module.map
===================================================================
--- /dev/null
+++ test/Modules/Inputs/declare-use/module.map
@@ -0,0 +1,43 @@
+module A {
+ header "a.h"
+}
+
+module B {
+ header "b.h"
+}
+
+module C {
+ header "c.h"
+ use A
+}
+
+module D {
+ header "d.h"
+ use A
+}
+
+module E {
+ header "e.h"
+ use A
+ use B
+}
+
+module F {
+ header "f.h"
+ use A
+ use B
+}
+
+module G {
+ header "g.h"
+ header "g1.h"
+ use C
+ use E
+}
+
+module H {
+ header "h.h"
+ header "h1.h"
+ use C
+ use E
+}
Index: test/Modules/declare-use1.cpp
===================================================================
--- /dev/null
+++ test/Modules/declare-use1.cpp
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-source-for=G -I %S/Inputs/declare-use %s -verify
+
+#include "g.h"
+#include "e.h"
+#include "f.h" // expected-error {{use of a module not declared used}}
+const int g2 = g1+e+f;
Index: test/Modules/declare-use2.cpp
===================================================================
--- /dev/null
+++ test/Modules/declare-use2.cpp
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-source-for=H -I %S/Inputs/declare-use %s -verify
+
+#include "h.h" // expected-error {{could not build module}}
+#include "e.h"
+#include "f.h"
+const int h2 = h1+e+f;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits