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:
Douglas Gregor
2011-12-31 04:05:44 +00:00
parent 84a5dfdf72
commit 1fb5c3a63a
19 changed files with 385 additions and 36 deletions

View File

@@ -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);