forked from OSchip/llvm-project
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. llvm-svn: 145665
This commit is contained in:
parent
4e3a11ba57
commit
2b82c2a59e
|
@ -399,6 +399,12 @@ def err_mmap_umbrella_header_submodule : Error<
|
|||
"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 "
|
||||
|
|
|
@ -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 @@ namespace clang {
|
|||
|
||||
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 @@ public:
|
|||
///\ 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)
|
||||
|
|
|
@ -57,6 +57,22 @@ class ModuleMap {
|
|||
|
||||
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 @@ public:
|
|||
///
|
||||
/// \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 @@ public:
|
|||
/// \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.
|
||||
///
|
||||
|
|
|
@ -993,6 +993,9 @@ public:
|
|||
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);
|
||||
|
|
|
@ -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 @@ Module *ModuleMap::findModule(StringRef Name) {
|
|||
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 @@ void ModuleMap::dump() {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ namespace clang {
|
|||
HeaderKeyword,
|
||||
Identifier,
|
||||
ExplicitKeyword,
|
||||
ExportKeyword,
|
||||
FrameworkKeyword,
|
||||
ModuleKeyword,
|
||||
Period,
|
||||
UmbrellaKeyword,
|
||||
Star,
|
||||
StringLiteral,
|
||||
LBrace,
|
||||
RBrace
|
||||
|
@ -247,6 +319,7 @@ namespace clang {
|
|||
void parseModuleDecl();
|
||||
void parseUmbrellaDecl();
|
||||
void parseHeaderDecl();
|
||||
void parseExportDecl();
|
||||
|
||||
public:
|
||||
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
|
||||
|
@ -283,6 +356,7 @@ retry:
|
|||
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 @@ retry:
|
|||
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 @@ void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
|
|||
/// 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 @@ void ModuleMapParser::parseModuleDecl() {
|
|||
parseModuleDecl();
|
||||
break;
|
||||
|
||||
case MMToken::ExportKeyword:
|
||||
parseExportDecl();
|
||||
break;
|
||||
|
||||
case MMToken::HeaderKeyword:
|
||||
parseHeaderDecl();
|
||||
break;
|
||||
|
@ -464,7 +551,7 @@ void ModuleMapParser::parseModuleDecl() {
|
|||
case MMToken::UmbrellaKeyword:
|
||||
parseUmbrellaDecl();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
|
||||
consumeToken();
|
||||
|
@ -625,6 +712,52 @@ void ModuleMapParser::parseHeaderDecl() {
|
|||
}
|
||||
}
|
||||
|
||||
/// \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 @@ bool ModuleMapParser::parseModuleMapFile() {
|
|||
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);
|
||||
|
|
|
@ -369,7 +369,12 @@ void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok,
|
|||
Tok.setLiteralData(DestPtr);
|
||||
}
|
||||
|
||||
|
||||
Module *Preprocessor::getCurrentModule() {
|
||||
if (getLangOptions().CurrentModule.empty())
|
||||
return 0;
|
||||
|
||||
return getHeaderSearchInfo().getModule(getLangOptions().CurrentModule);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessor Initialization Methods
|
||||
|
|
|
@ -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 @@ void Sema::ActOnEndOfTranslationUnit() {
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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" }
|
||||
|
|
Loading…
Reference in New Issue