summaryrefslogtreecommitdiff
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
parentf8e2c06cea1548c437761cb65cfbf97d50a057a7 (diff)
downloadclang-906d66acc5cf2679453e10a4f0a67feedd765b21.tar.gz
clang-906d66acc5cf2679453e10a4f0a67feedd765b21.tar.bz2
clang-906d66acc5cf2679453e10a4f0a67feedd765b21.tar.xz
<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
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td5
-rw-r--r--include/clang/Basic/Module.h25
-rw-r--r--include/clang/Frontend/ASTUnit.h3
-rw-r--r--include/clang/Frontend/CompilerInstance.h3
-rw-r--r--include/clang/Lex/ModuleLoader.h3
-rw-r--r--include/clang/Lex/ModuleMap.h27
-rw-r--r--include/clang/Serialization/ASTBitCodes.h4
-rw-r--r--include/clang/Serialization/ASTReader.h26
-rw-r--r--lib/Basic/Module.cpp18
-rw-r--r--lib/Frontend/CompilerInstance.cpp10
-rw-r--r--lib/Lex/ModuleMap.cpp120
-rw-r--r--lib/Sema/Sema.cpp5
-rw-r--r--lib/Sema/SemaDecl.cpp3
-rw-r--r--lib/Serialization/ASTReader.cpp86
-rw-r--r--lib/Serialization/ASTWriter.cpp17
-rw-r--r--test/Modules/Inputs/Conflicts/conflict_a.h1
-rw-r--r--test/Modules/Inputs/Conflicts/conflict_b.h1
-rw-r--r--test/Modules/Inputs/Conflicts/module.map10
-rw-r--r--test/Modules/conflicts.m7
-rw-r--r--unittests/Basic/SourceManagerTest.cpp3
-rw-r--r--unittests/Lex/LexerTest.cpp3
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp3
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp3
25 files changed, 328 insertions, 63 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 9af83b10a7..4ddf2077e7 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -159,6 +159,7 @@ def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
+def ModuleConflict : DiagGroup<"module-conflict">;
def NullArithmetic : DiagGroup<"null-arithmetic">;
def NullCharacter : DiagGroup<"null-character">;
def NullDereference : DiagGroup<"null-dereference">;
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 80c52492f4..339788b75d 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -536,6 +536,10 @@ def err_mmap_config_macro_submodule : Error<
"configuration macros are only allowed on top-level modules">;
def err_mmap_expected_config_macro : Error<
"expected configuration macro name after ','">;
+def err_mmap_expected_conflicts_comma : Error<
+ "expected ',' after conflicting module name">;
+def err_mmap_expected_conflicts_message : Error<
+ "expected a message describing the conflict with '%0'">;
def err_mmap_missing_module_unqualified : Error<
"no module named '%0' visible from '%1'">;
def err_mmap_missing_module_qualified : Error<
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index bc5bd4e2ad..7137404a69 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -44,7 +44,10 @@ def warn_pch_different_branch : Error<
def err_pch_with_compiler_errors : Error<
"PCH file contains compiler errors">;
-
+def warn_module_conflict : Warning<
+ "module '%0' conflicts with already-imported module '%1': %2">,
+ InGroup<ModuleConflict>;
+
def err_pch_macro_def_undef : Error<
"macro '%0' was %select{defined|undef'd}1 in the precompiled header but "
"%select{undef'd|defined}1 on the command line">;
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 2add58019f..d2a43f0219 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -201,6 +201,31 @@ public:
/// (intentionally) change how this module is built.
std::vector<std::string> ConfigMacros;
+ /// \brief An unresolved conflict with another module.
+ struct UnresolvedConflict {
+ /// \brief The (unresolved) module id.
+ ModuleId Id;
+
+ /// \brief The message provided to the user when there is a conflict.
+ std::string Message;
+ };
+
+ /// \brief The list of conflicts for which the module-id has not yet been
+ /// resolved.
+ std::vector<UnresolvedConflict> UnresolvedConflicts;
+
+ /// \brief A conflict between two modules.
+ struct Conflict {
+ /// \brief The module that this module conflicts with.
+ Module *Other;
+
+ /// \brief The message provided to the user when there is a conflict.
+ std::string Message;
+ };
+
+ /// \brief The list of conflicts.
+ std::vector<Conflict> Conflicts;
+
/// \brief Construct a top-level module.
explicit Module(StringRef Name, SourceLocation DefinitionLoc,
bool IsFramework)
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 108114dd67..02c57d7472 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -843,7 +843,8 @@ public:
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) { }
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 273fcc1082..0d674629fd 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -663,7 +663,8 @@ public:
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc);
+ SourceLocation ImportLoc,
+ bool Complain);
};
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index 93e69a6eed..3acf9151bc 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -83,7 +83,8 @@ public:
/// \brief Make the given module visible.
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) = 0;
+ SourceLocation ImportLoc,
+ bool Complain) = 0;
};
}
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index cffa5b7b66..33c92f59a4 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -134,7 +134,20 @@ class ModuleMap {
Module::ExportDecl
resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved,
bool Complain) const;
-
+
+ /// \brief Resolve the given module id to an actual module.
+ ///
+ /// \param Id The module-id to resolve.
+ ///
+ /// \param Mod The module in which we're resolving the module-id.
+ ///
+ /// \param Complain Whether this routine should complain about unresolvable
+ /// module-ids.
+ ///
+ /// \returns The resolved module, or null if the module-id could not be
+ /// resolved.
+ Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const;
+
public:
/// \brief Construct a new module map.
///
@@ -265,7 +278,17 @@ public:
/// false otherwise.
bool resolveExports(Module *Mod, bool Complain);
- /// \brief Infers the (sub)module based on the given source location and
+ /// \brief Resolve all of the unresolved conflicts in the given module.
+ ///
+ /// \param Mod The module whose conflicts should be resolved.
+ ///
+ /// \param Complain Whether to emit diagnostics for failures.
+ ///
+ /// \returns true if any errors were encountered while resolving conflicts,
+ /// false otherwise.
+ bool resolveConflicts(Module *Mod, bool Complain);
+
+ /// \brief Infers the (sub)module based on the given source location and
/// source manager.
///
/// \param Loc The location within the source that we are querying, along
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 2669d8e6d7..85f88ad007 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -611,7 +611,9 @@ namespace clang {
/// \brief Specifies a library or framework to link against.
SUBMODULE_LINK_LIBRARY = 10,
/// \brief Specifies a configuration macro for this module.
- SUBMODULE_CONFIG_MACRO = 11
+ SUBMODULE_CONFIG_MACRO = 11,
+ /// \brief Specifies a conflict with another module.
+ SUBMODULE_CONFLICT = 12
};
/// \brief Record types used within a comments block.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 61a0cbebd7..9b4a5c04e4 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -520,27 +520,30 @@ private:
HiddenNamesMapType HiddenNamesMap;
- /// \brief A module import or export that hasn't yet been resolved.
- struct UnresolvedModuleImportExport {
+ /// \brief A module import, export, or conflict that hasn't yet been resolved.
+ struct UnresolvedModuleRef {
/// \brief The file in which this module resides.
ModuleFile *File;
/// \brief The module that is importing or exporting.
Module *Mod;
-
+
+ /// \brief The kind of module reference.
+ enum { Import, Export, Conflict } Kind;
+
/// \brief The local ID of the module that is being exported.
unsigned ID;
-
- /// \brief Whether this is an import (vs. an export).
- unsigned IsImport : 1;
-
+
/// \brief Whether this is a wildcard export.
unsigned IsWildcard : 1;
+
+ /// \brief String data.
+ StringRef String;
};
/// \brief The set of module imports and exports that still need to be
/// resolved.
- SmallVector<UnresolvedModuleImportExport, 2> UnresolvedModuleImportExports;
+ SmallVector<UnresolvedModuleRef, 2> UnresolvedModuleRefs;
/// \brief A vector containing selectors that have already been loaded.
///
@@ -1188,9 +1191,14 @@ public:
///
/// \param NameVisibility The level of visibility to give the names in the
/// module. Visibility can only be increased over time.
+ ///
+ /// \param ImportLoc The location at which the import occurs.
+ ///
+ /// \param Complain Whether to complain about conflicting module imports.
void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind NameVisibility,
- SourceLocation ImportLoc);
+ SourceLocation ImportLoc,
+ bool Complain);
/// \brief Make the names within this set of hidden names visible.
void makeNamesVisible(const HiddenNames &Names);
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 197c53fb14..13518cde66 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -347,6 +347,24 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
OS << "\"";
}
+ for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "conflict ";
+ printModuleId(OS, UnresolvedConflicts[I].Id);
+ OS << ", \"";
+ OS.write_escaped(UnresolvedConflicts[I].Message);
+ OS << "\"\n";
+ }
+
+ for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "conflict ";
+ OS << Conflicts[I].Other->getFullModuleName();
+ OS << ", \"";
+ OS.write_escaped(Conflicts[I].Message);
+ OS << "\"\n";
+ }
+
if (InferSubmodules) {
OS.indent(Indent + 2);
if (InferExplicitSubmodules)
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index a20e7d7ed0..633f3c5868 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -1007,7 +1007,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// Make the named module visible.
if (LastModuleImportResult)
ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility,
- ImportLoc);
+ ImportLoc, /*Complain=*/false);
return LastModuleImportResult;
}
@@ -1265,7 +1265,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
return ModuleLoadResult();
}
- ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc);
+ ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc,
+ /*Complain=*/true);
}
// Check for any configuration macros that have changed.
@@ -1294,7 +1295,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
void CompilerInstance::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc){
- ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc);
+ SourceLocation ImportLoc,
+ bool Complain){
+ ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain);
}
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:
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 4aeb511abd..8b17c123fd 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -634,11 +634,12 @@ void Sema::ActOnEndOfTranslationUnit() {
Module *Mod = Stack.back();
Stack.pop_back();
- // Resolve the exported declarations.
+ // Resolve the exported declarations and conflicts.
// FIXME: Actually complain, once we figure out how to teach the
- // diagnostic client to deal with complains in the module map at this
+ // diagnostic client to deal with complaints in the module map at this
// point.
ModMap.resolveExports(Mod, /*Complain=*/false);
+ ModMap.resolveConflicts(Mod, /*Complain=*/false);
// Queue the submodules, so their exports will also be resolved.
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1cffce0808..d046f642b2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -11826,7 +11826,8 @@ void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
Consumer.HandleImplicitImportDecl(ImportD);
// Make the module visible.
- PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc);
+ PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc,
+ /*Complain=*/false);
}
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 126770b5b8..29538a13ef 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2716,7 +2716,8 @@ void ASTReader::makeNamesVisible(const HiddenNames &Names) {
void ASTReader::makeModuleVisible(Module *Mod,
Module::NameVisibilityKind NameVisibility,
- SourceLocation ImportLoc) {
+ SourceLocation ImportLoc,
+ bool Complain) {
llvm::SmallPtrSet<Module *, 4> Visited;
SmallVector<Module *, 4> Stack;
Stack.push_back(Mod);
@@ -2764,6 +2765,20 @@ void ASTReader::makeModuleVisible(Module *Mod,
if (Visited.insert(Exported))
Stack.push_back(Exported);
}
+
+ // Detect any conflicts.
+ if (Complain) {
+ assert(ImportLoc.isValid() && "Missing import location");
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ if (Mod->Conflicts[I].Other->NameVisibility >= NameVisibility) {
+ Diag(ImportLoc, diag::warn_module_conflict)
+ << Mod->getFullModuleName()
+ << Mod->Conflicts[I].Other->getFullModuleName()
+ << Mod->Conflicts[I].Message;
+ // FIXME: Need note where the other module was imported.
+ }
+ }
+ }
}
}
@@ -2879,22 +2894,34 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
Id->second->setOutOfDate(true);
// Resolve any unresolved module exports.
- for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
- UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
+ for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) {
+ UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I];
SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
Module *ResolvedMod = getSubmodule(GlobalID);
-
- if (Unresolved.IsImport) {
+
+ switch (Unresolved.Kind) {
+ case UnresolvedModuleRef::Conflict:
+ if (ResolvedMod) {
+ Module::Conflict Conflict;
+ Conflict.Other = ResolvedMod;
+ Conflict.Message = Unresolved.String.str();
+ Unresolved.Mod->Conflicts.push_back(Conflict);
+ }
+ continue;
+
+ case UnresolvedModuleRef::Import:
if (ResolvedMod)
Unresolved.Mod->Imports.push_back(ResolvedMod);
continue;
- }
- if (ResolvedMod || Unresolved.IsWildcard)
- Unresolved.Mod->Exports.push_back(
- Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ case UnresolvedModuleRef::Export:
+ if (ResolvedMod || Unresolved.IsWildcard)
+ Unresolved.Mod->Exports.push_back(
+ Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ continue;
+ }
}
- UnresolvedModuleImportExports.clear();
+ UnresolvedModuleRefs.clear();
InitializeContext();
@@ -3196,7 +3223,8 @@ void ASTReader::InitializeContext() {
for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) {
if (Module *Imported = getSubmodule(ImportedModules[I]))
makeModuleVisible(Imported, Module::AllVisible,
- /*ImportLoc=*/SourceLocation());
+ /*ImportLoc=*/SourceLocation(),
+ /*Complain=*/false);
}
ImportedModules.clear();
}
@@ -3534,9 +3562,11 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
SubmodulesLoaded[GlobalIndex] = CurrentModule;
- // Clear out link libraries and config macros; the module file has them.
+ // Clear out data that will be replaced by what is the module file.
CurrentModule->LinkLibraries.clear();
CurrentModule->ConfigMacros.clear();
+ CurrentModule->UnresolvedConflicts.clear();
+ CurrentModule->Conflicts.clear();
break;
}
@@ -3660,13 +3690,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
break;
for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
- UnresolvedModuleImportExport Unresolved;
+ UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
Unresolved.Mod = CurrentModule;
Unresolved.ID = Record[Idx];
- Unresolved.IsImport = true;
+ Unresolved.Kind = UnresolvedModuleRef::Import;
Unresolved.IsWildcard = false;
- UnresolvedModuleImportExports.push_back(Unresolved);
+ UnresolvedModuleRefs.push_back(Unresolved);
}
break;
}
@@ -3681,13 +3711,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
break;
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
- UnresolvedModuleImportExport Unresolved;
+ UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
Unresolved.Mod = CurrentModule;
Unresolved.ID = Record[Idx];
- Unresolved.IsImport = false;
+ Unresolved.Kind = UnresolvedModuleRef::Export;
Unresolved.IsWildcard = Record[Idx + 1];
- UnresolvedModuleImportExports.push_back(Unresolved);
+ UnresolvedModuleRefs.push_back(Unresolved);
}
// Once we've loaded the set of exports, there's no reason to keep
@@ -3733,6 +3763,26 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
CurrentModule->ConfigMacros.push_back(Blob.str());
break;
+
+ case SUBMODULE_CONFLICT: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[0];
+ Unresolved.Kind = UnresolvedModuleRef::Conflict;
+ Unresolved.IsWildcard = false;
+ Unresolved.String = Blob;
+ UnresolvedModuleRefs.push_back(Unresolved);
+ break;
+ }
}
}
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index de5e6e0275..f0b12009fe 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -2180,6 +2180,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message
+ unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -2295,6 +2301,17 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Mod->LinkLibraries[I].Library);
}
+ // Emit the conflicts.
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFLICT);
+ unsigned OtherID = getSubmoduleID(Mod->Conflicts[I].Other);
+ assert(OtherID && "Unknown submodule!");
+ Record.push_back(OtherID);
+ Stream.EmitRecordWithBlob(ConflictAbbrev, Record,
+ Mod->Conflicts[I].Message);
+ }
+
// Emit the configuration macros.
for (unsigned I = 0, N = Mod->ConfigMacros.size(); I != N; ++I) {
Record.clear();
diff --git a/test/Modules/Inputs/Conflicts/conflict_a.h b/test/Modules/Inputs/Conflicts/conflict_a.h
new file mode 100644
index 0000000000..c16b5f5ef2
--- /dev/null
+++ b/test/Modules/Inputs/Conflicts/conflict_a.h
@@ -0,0 +1 @@
+int conflict_a;
diff --git a/test/Modules/Inputs/Conflicts/conflict_b.h b/test/Modules/Inputs/Conflicts/conflict_b.h
new file mode 100644
index 0000000000..4baf16f88e
--- /dev/null
+++ b/test/Modules/Inputs/Conflicts/conflict_b.h
@@ -0,0 +1 @@
+int conflict_b;
diff --git a/test/Modules/Inputs/Conflicts/module.map b/test/Modules/Inputs/Conflicts/module.map
new file mode 100644
index 0000000000..e6aafaccec
--- /dev/null
+++ b/test/Modules/Inputs/Conflicts/module.map
@@ -0,0 +1,10 @@
+module Conflicts {
+ explicit module A {
+ header "conflict_a.h"
+ conflict B, "we just don't like B"
+ }
+
+ module B {
+ header "conflict_b.h"
+ }
+}
diff --git a/test/Modules/conflicts.m b/test/Modules/conflicts.m
new file mode 100644
index 0000000000..2388e6f1d1
--- /dev/null
+++ b/test/Modules/conflicts.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -I %S/Inputs/Conflicts %s -verify
+
+@import Conflicts;
+
+@import Conflicts.A; // expected-warning{{module 'Conflicts.A' conflicts with already-imported module 'Conflicts.B': we just don't like B}}
+
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index 130ea0a5a8..3f09cbb0f9 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -61,7 +61,8 @@ class VoidModuleLoader : public ModuleLoader {
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) { }
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index 505be75ab4..c9b1840e1c 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -62,7 +62,8 @@ class VoidModuleLoader : public ModuleLoader {
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) { }
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
TEST_F(LexerTest, LexAPI) {
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index 13104cbc03..36bd5f9395 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -39,7 +39,8 @@ class VoidModuleLoader : public ModuleLoader {
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) { }
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
// Stub to collect data from InclusionDirective callbacks.
diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index 856a8ff26d..082eced2d8 100644
--- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -62,7 +62,8 @@ class VoidModuleLoader : public ModuleLoader {
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc) { }
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {