Addressed review comments as far as I could.
Hi rsmith, doug.gregor, chandlerc,
http://llvm-reviews.chandlerc.com/D1546
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D1546?vs=3895&id=4064#toc
Files:
docs/Modules.rst
include/clang/Basic/DiagnosticLexKinds.td
include/clang/Basic/LangOptions.def
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,14 @@
``-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.
+
+``-fmodule-name=module-id``
+ Consider a source file as a part of the given module.
+
+
+
Module Map Language
===================
@@ -238,6 +246,7 @@
``conflict`` ``framework`` ``requires``
``exclude`` ``header`` ``private``
``explicit`` ``link`` ``umbrella``
+ ``use``
Module map file
---------------
@@ -291,6 +300,7 @@
*umbrella-dir-declaration*
*submodule-declaration*
*export-declaration*
+ *use-declaration*
*link-declaration*
*config-macros-declaration*
*conflict-declaration*
@@ -529,6 +539,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,7 @@
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(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/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 use declarations.
+ SmallVector<WildModuleRef, 2> DirectUses;
+
+ /// \brief The set of use 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
@@ -559,6 +559,9 @@
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 fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
@@ -619,6 +622,8 @@
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_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
@@ -3019,6 +3019,13 @@
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");
+ }
+
// 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,7 @@
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.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.CurrentModule == 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.CurrentModule == 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,89 @@
}
}
+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)
+ 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;
+
+ // FIXME: Add support for FixIts in module map files and offer adding the
+ // required use declaration.
+ 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 +650,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 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-name=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-name=H -I %S/Inputs/declare-use %s -verify
+
+#include "h.h"
+#include "e.h"
+#include "f.h" // expected-error {{use of a module not declared used}}
+const int h2 = h1+e+f;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits