<rdar://problem/12368093> Extend module maps with a 'conflict' declaration, and warn when a newly-imported module conflicts with an already-imported module.

llvm-svn: 177577
This commit is contained in:
Douglas Gregor 2013-03-20 21:10:35 +00:00
parent f83a664a40
commit fb9126578e
25 changed files with 328 additions and 63 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -843,7 +843,8 @@ public:
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc) { }
SourceLocation ImportLoc,
bool Complain) { }
};

View File

@ -663,7 +663,8 @@ public:
virtual void makeModuleVisible(Module *Mod,
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc);
SourceLocation ImportLoc,
bool Complain);
};

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

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

View File

@ -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:

View File

@ -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(),

View File

@ -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,

View File

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

View File

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

View File

@ -0,0 +1 @@
int conflict_a;

View File

@ -0,0 +1 @@
int conflict_b;

View File

@ -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"
}
}

View File

@ -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}}

View File

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

View File

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

View File

@ -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.

View File

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