[cfe-commits] r145665 - in /cfe/trunk: include/clang/Basic/DiagnosticLexKinds.td include/clang/Basic/Module.h include/clang/Lex/ModuleMap.h include/clang/Lex/Preprocessor.h lib/Lex/ModuleMap.cpp lib/Lex/Preprocessor.cpp lib/Sema/Sema.cpp test/Modules/Inputs/module.map
Douglas Gregor
dgregor at apple.com
Thu Dec 1 17:47:07 PST 2011
Author: dgregor
Date: Thu Dec 1 19:47:07 2011
New Revision: 145665
URL: http://llvm.org/viewvc/llvm-project?rev=145665&view=rev
Log:
Implementing parsing and resolution of module export declarations
within module maps, which will (eventually) be used to re-export a
module from another module. There are still some pieces missing,
however.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
cfe/trunk/include/clang/Basic/Module.h
cfe/trunk/include/clang/Lex/ModuleMap.h
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Lex/ModuleMap.cpp
cfe/trunk/lib/Lex/Preprocessor.cpp
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/test/Modules/Inputs/module.map
Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Thu Dec 1 19:47:07 2011
@@ -399,6 +399,12 @@
"submodule '%0' can not have an umbrella header">;
def err_mmap_umbrella_clash : Error<
"umbrella header for module '%0' already covers this directory">;
+def err_mmap_export_module_id : Error<
+ "expected an exported module name or '*'">;
+def err_mmap_missing_module_unqualified : Error<
+ "no module named '%0' visible from '%1'">;
+def err_mmap_missing_module_qualified : Error<
+ "no module named '%0' in '%1'">;
def warn_auto_module_import : Warning<
"treating #%select{include|import|include_next|__include_macros}0 as an "
Modified: cfe/trunk/include/clang/Basic/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Module.h (original)
+++ cfe/trunk/include/clang/Basic/Module.h Thu Dec 1 19:47:07 2011
@@ -15,10 +15,12 @@
#define LLVM_CLANG_BASIC_MODULE_H
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <string>
+#include <utility>
namespace llvm {
class raw_ostream;
@@ -28,6 +30,10 @@
class FileEntry;
+/// \brief Describes the name of a module.
+typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
+ ModuleId;
+
/// \brief Describes a module or submodule.
class Module {
public:
@@ -73,6 +79,33 @@
///\ brief The visibility of names within this particular module.
NameVisibilityKind NameVisibility;
+ /// \brief Describes an exported module.
+ ///
+ /// The pointer is the module being re-exported, while the bit will be true
+ /// to indicate that this is a wildcard export.
+ typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl;
+
+ /// \brief The set of export declarations.
+ llvm::SmallVector<ExportDecl, 2> Exports;
+
+ /// \brief Describes an exported module 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;
+
+ /// \brief The name of the module.
+ ModuleId Id;
+
+ /// \brief Whether this export declaration ends in a wildcard, indicating
+ /// that all of its submodules should be exported (rather than the named
+ /// module itself).
+ bool Wildcard;
+ };
+
+ /// \brief The set of export declarations that have yet to be resolved.
+ llvm::SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
+
/// \brief Construct a top-level module.
explicit Module(StringRef Name, SourceLocation DefinitionLoc,
bool IsFramework)
Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Thu Dec 1 19:47:07 2011
@@ -57,6 +57,22 @@
friend class ModuleMapParser;
+ /// \brief Resolve the given export declaration into an actual export
+ /// declaration.
+ ///
+ /// \param Mod The module in which we're resolving the export declaration.
+ ///
+ /// \param Unresolved The export declaration to resolve.
+ ///
+ /// \param Complain Whether this routine should complain about unresolvable
+ /// exports.
+ ///
+ /// \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);
+
public:
/// \brief Construct a new module map.
///
@@ -86,6 +102,28 @@
///
/// \returns The named module, if known; otherwise, returns null.
Module *findModule(StringRef Name);
+
+ /// \brief Retrieve a module with the given name using lexical name lookup,
+ /// starting at the given context.
+ ///
+ /// \param The name of the module to look up.
+ ///
+ /// \param Context The module context, from which we will perform lexical
+ /// name lookup.
+ ///
+ /// \returns The named module, if known; otherwise, returns null.
+ Module *lookupModuleUnqualified(StringRef Name, Module *Context);
+
+ /// \brief Retrieve a module with the given name within the given context,
+ /// using direct (qualified) name lookup.
+ ///
+ /// \param The name of the module to look up.
+ ///
+ /// \param Context The module for which we will look for a submodule. If
+ /// null, we will look for a top-level module.
+ ///
+ /// \returns The named submodule, if known; otherwose, returns null.
+ Module *lookupModuleQualified(StringRef Name, Module *Context);
/// \brief Find a new module or submodule, or create it if it does not already
/// exist.
@@ -118,7 +156,17 @@
/// \returns The file entry for the module map file containing the given
/// module, or NULL if the module definition was inferred.
const FileEntry *getContainingModuleMapFile(Module *Module);
-
+
+ /// \brief Resolve all of the unresolved exports in the given module.
+ ///
+ /// \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 resolveExports(Module *Mod, bool Complain);
+
/// \brief Parse the given module map file, and record any modules we
/// encounter.
///
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Thu Dec 1 19:47:07 2011
@@ -993,6 +993,9 @@
unsigned getCounterValue() const { return CounterValue; }
void setCounterValue(unsigned V) { CounterValue = V; }
+ /// \brief Retrieves the module that we're currently building, if any.
+ Module *getCurrentModule();
+
/// AllocateMacroInfo - Allocate a new MacroInfo object with the provide
/// SourceLocation.
MacroInfo *AllocateMacroInfo(SourceLocation L);
Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Dec 1 19:47:07 2011
@@ -27,6 +27,41 @@
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
+Module::ExportDecl
+ModuleMap::resolveExport(Module *Mod,
+ const Module::UnresolvedExportDecl &Unresolved,
+ bool Complain) {
+ // Find the starting module.
+ Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
+ if (!Context) {
+ if (Complain)
+ Diags->Report(Unresolved.Id[0].second,
+ diag::err_mmap_missing_module_unqualified)
+ << Unresolved.Id[0].first << Mod->getFullModuleName();
+
+ return Module::ExportDecl();
+ }
+
+ // Dig into the module path.
+ for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) {
+ Module *Sub = lookupModuleQualified(Unresolved.Id[I].first,
+ Context);
+ if (!Sub) {
+ if (Complain)
+ Diags->Report(Unresolved.Id[I].second,
+ diag::err_mmap_missing_module_qualified)
+ << Unresolved.Id[I].first << Context->getFullModuleName()
+ << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second);
+
+ return Module::ExportDecl();
+ }
+
+ Context = Sub;
+ }
+
+ return Module::ExportDecl(Context, Unresolved.Wildcard);
+}
+
ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC) {
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = llvm::IntrusiveRefCntPtr<DiagnosticsEngine>(
@@ -97,6 +132,26 @@
return 0;
}
+Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
+ for(; Context; Context = Context->Parent) {
+ if (Module *Sub = lookupModuleQualified(Name, Context))
+ return Sub;
+ }
+
+ return findModule(Name);
+}
+
+Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) {
+ if (!Context)
+ return findModule(Name);
+
+ llvm::StringMap<Module *>::iterator Sub = Context->SubModules.find(Name);
+ if (Sub != Context->SubModules.end())
+ return Sub->getValue();
+
+ return 0;
+}
+
std::pair<Module *, bool>
ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
bool IsExplicit) {
@@ -169,6 +224,20 @@
}
}
+bool ModuleMap::resolveExports(Module *Mod, 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())
+ Mod->Exports.push_back(Export);
+ else
+ HadError = true;
+ }
+ Mod->UnresolvedExports.clear();
+ return HadError;
+}
+
//----------------------------------------------------------------------------//
// Module map file parser
//----------------------------------------------------------------------------//
@@ -181,9 +250,12 @@
HeaderKeyword,
Identifier,
ExplicitKeyword,
+ ExportKeyword,
FrameworkKeyword,
ModuleKeyword,
+ Period,
UmbrellaKeyword,
+ Star,
StringLiteral,
LBrace,
RBrace
@@ -247,6 +319,7 @@
void parseModuleDecl();
void parseUmbrellaDecl();
void parseHeaderDecl();
+ void parseExportDecl();
public:
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
@@ -283,6 +356,7 @@
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
.Case("header", MMToken::HeaderKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
+ .Case("export", MMToken::ExportKeyword)
.Case("framework", MMToken::FrameworkKeyword)
.Case("module", MMToken::ModuleKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
@@ -297,10 +371,18 @@
Tok.Kind = MMToken::LBrace;
break;
+ case tok::period:
+ Tok.Kind = MMToken::Period;
+ break;
+
case tok::r_brace:
Tok.Kind = MMToken::RBrace;
break;
+ case tok::star:
+ Tok.Kind = MMToken::Star;
+ break;
+
case tok::string_literal: {
// Parse the string literal.
LangOptions LangOpts;
@@ -373,6 +455,7 @@
/// umbrella-declaration
/// header-declaration
/// 'explicit'[opt] module-declaration
+/// export-declaration
void ModuleMapParser::parseModuleDecl() {
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
Tok.is(MMToken::FrameworkKeyword));
@@ -457,6 +540,10 @@
parseModuleDecl();
break;
+ case MMToken::ExportKeyword:
+ parseExportDecl();
+ break;
+
case MMToken::HeaderKeyword:
parseHeaderDecl();
break;
@@ -464,7 +551,7 @@
case MMToken::UmbrellaKeyword:
parseUmbrellaDecl();
break;
-
+
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
consumeToken();
@@ -625,6 +712,52 @@
}
}
+/// \brief Parse a module export declaration.
+///
+/// export-declaration:
+/// 'export' wildcard-module-id
+///
+/// wildcard-module-id:
+/// identifier
+/// '*'
+/// identifier '.' wildcard-module-id
+void ModuleMapParser::parseExportDecl() {
+ assert(Tok.is(MMToken::ExportKeyword));
+ SourceLocation ExportLoc = consumeToken();
+
+ // Parse the module-id with an optional wildcard at the end.
+ ModuleId ParsedModuleId;
+ bool Wildcard = false;
+ do {
+ if (Tok.is(MMToken::Identifier)) {
+ ParsedModuleId.push_back(std::make_pair(Tok.getString(),
+ Tok.getLocation()));
+ consumeToken();
+
+ if (Tok.is(MMToken::Period)) {
+ consumeToken();
+ continue;
+ }
+
+ break;
+ }
+
+ if(Tok.is(MMToken::Star)) {
+ Wildcard = true;
+ break;
+ }
+
+ Diags.Report(Tok.getLocation(), diag::err_mmap_export_module_id);
+ HadError = true;
+ return;
+ } while (true);
+
+ Module::UnresolvedExportDecl Unresolved = {
+ ExportLoc, ParsedModuleId, Wildcard
+ };
+ ActiveModule->UnresolvedExports.push_back(Unresolved);
+}
+
/// \brief Parse a module map file.
///
/// module-map-file:
@@ -641,10 +774,13 @@
break;
case MMToken::ExplicitKeyword:
+ case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
case MMToken::LBrace:
+ case MMToken::Period:
case MMToken::RBrace:
+ case MMToken::Star:
case MMToken::StringLiteral:
case MMToken::UmbrellaKeyword:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Thu Dec 1 19:47:07 2011
@@ -369,7 +369,12 @@
Tok.setLiteralData(DestPtr);
}
-
+Module *Preprocessor::getCurrentModule() {
+ if (getLangOptions().CurrentModule.empty())
+ return 0;
+
+ return getHeaderSearchInfo().getModule(getLangOptions().CurrentModule);
+}
//===----------------------------------------------------------------------===//
// Preprocessor Initialization Methods
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Thu Dec 1 19:47:07 2011
@@ -33,11 +33,11 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
-
using namespace clang;
using namespace sema;
@@ -484,6 +484,32 @@
}
if (TUKind == TU_Module) {
+ // If we are building a module, resolve all of the exported declarations
+ // now.
+ if (Module *CurrentModule = PP.getCurrentModule()) {
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+
+ llvm::SmallVector<Module *, 2> Stack;
+ Stack.push_back(CurrentModule);
+ while (!Stack.empty()) {
+ Module *Mod = Stack.back();
+ Stack.pop_back();
+
+ // Resolve the exported declarations.
+ // FIXME: Actually complain, once we figure out how to teach the
+ // diagnostic client to deal with complains in the module map at this
+ // point.
+ ModMap.resolveExports(Mod, /*Complain=*/false);
+
+ // Queue the submodules, so their exports will also be resolved.
+ for (llvm::StringMap<Module *>::iterator Sub = Mod->SubModules.begin(),
+ SubEnd = Mod->SubModules.end();
+ Sub != SubEnd; ++Sub) {
+ Stack.push_back(Sub->getValue());
+ }
+ }
+ }
+
// Modules don't need any of the checking below.
TUScope = 0;
return;
Modified: cfe/trunk/test/Modules/Inputs/module.map
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=145665&r1=145664&r2=145665&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/module.map (original)
+++ cfe/trunk/test/Modules/Inputs/module.map Thu Dec 1 19:47:07 2011
@@ -1,7 +1,17 @@
module diamond_top { header "diamond_top.h" }
-module diamond_left { header "diamond_left.h" }
-module diamond_right { header "diamond_right.h" }
-module diamond_bottom { header "diamond_bottom.h" }
+module diamond_left {
+ header "diamond_left.h"
+ export diamond_top
+}
+module diamond_right {
+ header "diamond_right.h"
+ export diamond_top
+}
+module diamond_bottom {
+ header "diamond_bottom.h"
+ export diamond_left
+ export diamond_right
+}
module irgen { header "irgen.h" }
module lookup_left_objc { header "lookup_left.h" }
module lookup_right_objc { header "lookup_right.h" }
More information about the cfe-commits
mailing list