aboutsummaryrefslogtreecommitdiff
path: root/lib/Lex
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2013-03-20 21:10:35 +0000
committerDouglas Gregor <dgregor@apple.com>2013-03-20 21:10:35 +0000
commit906d66acc5cf2679453e10a4f0a67feedd765b21 (patch)
tree8c31690c89bdf0b16fedd5a2db26c49048824559 /lib/Lex
parentf8e2c06cea1548c437761cb65cfbf97d50a057a7 (diff)
<rdar://problem/12368093> Extend module maps with a 'conflict' declaration, and warn when a newly-imported module conflicts with an already-imported module.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177577 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Lex')
-rw-r--r--lib/Lex/ModuleMap.cpp120
1 files changed, 102 insertions, 18 deletions
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 9cea5aace7..0c03201aa6 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -45,35 +45,42 @@ ModuleMap::resolveExport(Module *Mod,
return Module::ExportDecl(0, true);
}
+ // Resolve the module-id.
+ Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain);
+ if (!Context)
+ return Module::ExportDecl();
+
+ return Module::ExportDecl(Context, Unresolved.Wildcard);
+}
+
+Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
+ bool Complain) const {
// Find the starting module.
- Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
+ Module *Context = lookupModuleUnqualified(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();
+ Diags->Report(Id[0].second, diag::err_mmap_missing_module_unqualified)
+ << Id[0].first << Mod->getFullModuleName();
+
+ return 0;
}
// Dig into the module path.
- for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) {
- Module *Sub = lookupModuleQualified(Unresolved.Id[I].first,
- Context);
+ for (unsigned I = 1, N = Id.size(); I != N; ++I) {
+ Module *Sub = lookupModuleQualified(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();
+ Diags->Report(Id[I].second, diag::err_mmap_missing_module_qualified)
+ << Id[I].first << Context->getFullModuleName()
+ << SourceRange(Id[0].second, Id[I-1].second);
+
+ return 0;
}
-
+
Context = Sub;
}
-
- return Module::ExportDecl(Context, Unresolved.Wildcard);
+
+ return Context;
}
ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
@@ -603,6 +610,25 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
return HadError;
}
+bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
+ bool HadError = false;
+ for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
+ Module *OtherMod = resolveModuleId(Mod->UnresolvedConflicts[I].Id,
+ Mod, Complain);
+ if (!OtherMod) {
+ HadError = true;
+ continue;
+ }
+
+ Module::Conflict Conflict;
+ Conflict.Other = OtherMod;
+ Conflict.Message = Mod->UnresolvedConflicts[I].Message;
+ Mod->Conflicts.push_back(Conflict);
+ }
+ Mod->UnresolvedConflicts.clear();
+ return HadError;
+}
+
Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
if (Loc.isInvalid())
return 0;
@@ -644,6 +670,7 @@ namespace clang {
enum TokenKind {
Comma,
ConfigMacros,
+ Conflict,
EndOfFile,
HeaderKeyword,
Identifier,
@@ -744,6 +771,7 @@ namespace clang {
void parseExportDecl();
void parseLinkDecl();
void parseConfigMacros();
+ void parseConflict();
void parseInferredModuleDecl(bool Framework, bool Explicit);
bool parseOptionalAttributes(Attributes &Attrs);
@@ -782,6 +810,7 @@ retry:
Tok.StringLength = LToken.getLength();
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
.Case("config_macros", MMToken::ConfigMacros)
+ .Case("conflict", MMToken::Conflict)
.Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
@@ -1107,6 +1136,10 @@ void ModuleMapParser::parseModuleDecl() {
parseConfigMacros();
break;
+ case MMToken::Conflict:
+ parseConflict();
+ break;
+
case MMToken::ExplicitKeyword:
case MMToken::FrameworkKeyword:
case MMToken::ModuleKeyword:
@@ -1554,6 +1587,56 @@ void ModuleMapParser::parseConfigMacros() {
} while (true);
}
+/// \brief Format a module-id into a string.
+static std::string formatModuleId(const ModuleId &Id) {
+ std::string result;
+ {
+ llvm::raw_string_ostream OS(result);
+
+ for (unsigned I = 0, N = Id.size(); I != N; ++I) {
+ if (I)
+ OS << ".";
+ OS << Id[I].first;
+ }
+ }
+
+ return result;
+}
+
+/// \brief Parse a conflict declaration.
+///
+/// module-declaration:
+/// 'conflict' module-id ',' string-literal
+void ModuleMapParser::parseConflict() {
+ assert(Tok.is(MMToken::Conflict));
+ SourceLocation ConflictLoc = consumeToken();
+ Module::UnresolvedConflict Conflict;
+
+ // Parse the module-id.
+ if (parseModuleId(Conflict.Id))
+ return;
+
+ // Parse the ','.
+ if (!Tok.is(MMToken::Comma)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)
+ << SourceRange(ConflictLoc);
+ return;
+ }
+ consumeToken();
+
+ // Parse the message.
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)
+ << formatModuleId(Conflict.Id);
+ return;
+ }
+ Conflict.Message = Tok.getString().str();
+ consumeToken();
+
+ // Add this unresolved conflict.
+ ActiveModule->UnresolvedConflicts.push_back(Conflict);
+}
+
/// \brief Parse an inferred module declaration (wildcard modules).
///
/// module-declaration:
@@ -1801,6 +1884,7 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::Comma:
case MMToken::ConfigMacros:
+ case MMToken::Conflict:
case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword: