Implement support for module requirements, which indicate the language
features needed for a particular module to be available. This allows mixed-language modules, where certain headers only work under some language variants (e.g., in C++, std.tuple might only be available in C++11 mode). llvm-svn: 147387
This commit is contained in:
@@ -13,7 +13,11 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "clang/Basic/Module.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
using namespace clang;
|
||||
|
||||
Module::~Module() {
|
||||
@@ -25,6 +29,36 @@ Module::~Module() {
|
||||
|
||||
}
|
||||
|
||||
/// \brief Determine whether a translation unit built using the current
|
||||
/// language options has the given feature.
|
||||
static bool hasFeature(StringRef Feature, const LangOptions &LangOpts) {
|
||||
return llvm::StringSwitch<bool>(Feature)
|
||||
.Case("blocks", LangOpts.Blocks)
|
||||
.Case("cplusplus", LangOpts.CPlusPlus)
|
||||
.Case("cplusplus11", LangOpts.CPlusPlus0x)
|
||||
.Case("objc", LangOpts.ObjC1)
|
||||
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
|
||||
.Default(false);
|
||||
}
|
||||
|
||||
bool
|
||||
Module::isAvailable(const LangOptions &LangOpts, StringRef &Feature) const {
|
||||
if (IsAvailable)
|
||||
return true;
|
||||
|
||||
for (const Module *Current = this; Current; Current = Current->Parent) {
|
||||
for (unsigned I = 0, N = Current->Requires.size(); I != N; ++I) {
|
||||
if (!hasFeature(Current->Requires[I], LangOpts)) {
|
||||
Feature = Current->Requires[I];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("could not find a reason why module is unavailable");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Module::isSubModuleOf(Module *Other) const {
|
||||
const Module *This = this;
|
||||
do {
|
||||
@@ -72,6 +106,35 @@ const DirectoryEntry *Module::getUmbrellaDir() const {
|
||||
return Umbrella.dyn_cast<const DirectoryEntry *>();
|
||||
}
|
||||
|
||||
void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts) {
|
||||
Requires.push_back(Feature);
|
||||
|
||||
// If this feature is currently available, we're done.
|
||||
if (hasFeature(Feature, LangOpts))
|
||||
return;
|
||||
|
||||
if (!IsAvailable)
|
||||
return;
|
||||
|
||||
llvm::SmallVector<Module *, 2> Stack;
|
||||
Stack.push_back(this);
|
||||
while (!Stack.empty()) {
|
||||
Module *Current = Stack.back();
|
||||
Stack.pop_back();
|
||||
|
||||
if (!Current->IsAvailable)
|
||||
continue;
|
||||
|
||||
Current->IsAvailable = false;
|
||||
for (llvm::StringMap<Module *>::iterator Sub = Current->SubModules.begin(),
|
||||
SubEnd = Current->SubModules.end();
|
||||
Sub != SubEnd; ++Sub) {
|
||||
if (Sub->second->IsAvailable)
|
||||
Stack.push_back(Sub->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
|
||||
for (unsigned I = 0, N = Id.size(); I != N; ++I) {
|
||||
if (I)
|
||||
@@ -87,6 +150,17 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
|
||||
if (IsExplicit)
|
||||
OS << "explicit ";
|
||||
OS << "module " << Name << " {\n";
|
||||
|
||||
if (!Requires.empty()) {
|
||||
OS.indent(Indent + 2);
|
||||
OS << "requires ";
|
||||
for (unsigned I = 0, N = Requires.size(); I != N; ++I) {
|
||||
if (I)
|
||||
OS << ", ";
|
||||
OS << Requires[I];
|
||||
}
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
if (const FileEntry *UmbrellaHeader = getUmbrellaHeader()) {
|
||||
OS.indent(Indent + 2);
|
||||
|
||||
Reference in New Issue
Block a user