diff options
author | Douglas Gregor <dgregor@apple.com> | 2013-03-20 00:22:05 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2013-03-20 00:22:05 +0000 |
commit | 63a726870b486e0470c3a4b11cf62bab8be00b73 (patch) | |
tree | 59a81fd634baac897c49f1dbf639ad69ec7af55d /lib/Frontend | |
parent | 8a40cc6f9cba0aaa1aac477e2b4c4605629dc587 (diff) |
<rdar://problem/10796651> Introduce configuration macros into module maps.
Configuration macros are macros that are intended to alter how a
module works, such that we need to build different module variants
for different values of these macros. A module can declare its
configuration macros, in which case we will complain if the definition
of a configation macro on the command line (or lack thereof) differs
from the current preprocessor state at the point where the module is
imported. This should eliminate some surprises when enabling modules,
because "#define CONFIG_MACRO ..." followed by "#include
<module/header.h>" would silently ignore the CONFIG_MACRO setting. At
least it will no longer be silent about it.
Configuration macros are eventually intended to help reduce the number
of module variants that need to be built. When the list of
configuration macros for a module is exhaustive, we only need to
consider the settings for those macros when building/finding the
module, which can help isolate modules for various project-specific -D
flags that should never affect how modules are build (but currently do).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177466 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Frontend')
-rw-r--r-- | lib/Frontend/CompilerInstance.cpp | 99 |
1 files changed, 98 insertions, 1 deletions
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index d5c1a27ec8..a20e7d7ed0 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -905,6 +905,96 @@ static void compileModule(CompilerInstance &ImportingInstance, } } +/// \brief Diagnose differences between the current definition of the given +/// configuration macro and the definition provided on the command line. +static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro, + Module *Mod, SourceLocation ImportLoc) { + IdentifierInfo *Id = PP.getIdentifierInfo(ConfigMacro); + SourceManager &SourceMgr = PP.getSourceManager(); + + // If this identifier has never had a macro definition, then it could + // not have changed. + if (!Id->hadMacroDefinition()) + return; + + // If this identifier does not currently have a macro definition, + // check whether it had one on the command line. + if (!Id->hasMacroDefinition()) { + MacroDirective *UndefMD = PP.getMacroDirectiveHistory(Id); + for (MacroDirective *MD = UndefMD; MD; MD = MD->getPrevious()) { + + FileID FID = SourceMgr.getFileID(MD->getLocation()); + if (FID.isInvalid()) + continue; + + const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(FID); + if (!Buffer) + continue; + + // We only care about the predefines buffer. + if (!StringRef(Buffer->getBufferIdentifier()).equals("<built-in>")) + continue; + + // This macro was defined on the command line, then #undef'd later. + // Complain. + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << true << ConfigMacro << Mod->getFullModuleName(); + if (UndefMD->getUndefLoc().isValid()) + PP.Diag(UndefMD->getUndefLoc(), diag::note_module_def_undef_here) + << true; + return; + } + + // Okay: no definition in the predefines buffer. + return; + } + + // This identifier has a macro definition. Check whether we had a definition + // on the command line. + MacroDirective *DefMD = PP.getMacroDirective(Id); + MacroDirective *PredefinedMD = 0; + for (MacroDirective *MD = DefMD; MD; MD = MD->getPrevious()) { + FileID FID = SourceMgr.getFileID(MD->getLocation()); + if (FID.isInvalid()) + continue; + + const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(FID); + if (!Buffer) + continue; + + // We only care about the predefines buffer. + if (!StringRef(Buffer->getBufferIdentifier()).equals("<built-in>")) + continue; + + PredefinedMD = MD; + break; + } + + // If there was no definition for this macro in the predefines buffer, + // complain. + if (!PredefinedMD || + (!PredefinedMD->getLocation().isValid() && + PredefinedMD->getUndefLoc().isValid())) { + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << false << ConfigMacro << Mod->getFullModuleName(); + PP.Diag(DefMD->getLocation(), diag::note_module_def_undef_here) + << false; + return; + } + + // If the current macro definition is the same as the predefined macro + // definition, it's okay. + if (DefMD == PredefinedMD || + DefMD->getInfo()->isIdenticalTo(*PredefinedMD->getInfo(), PP)) + return; + + // The macro definitions differ. + PP.Diag(ImportLoc, diag::warn_module_config_macro_undef) + << false << ConfigMacro << Mod->getFullModuleName(); + PP.Diag(DefMD->getLocation(), diag::note_module_def_undef_here) + << false; +} + ModuleLoadResult CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleIdPath Path, @@ -1177,7 +1267,14 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc); } - + + // Check for any configuration macros that have changed. + clang::Module *TopModule = Module->getTopLevelModule(); + for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) { + checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I], + Module, ImportLoc); + } + // If this module import was due to an inclusion directive, create an // implicit import declaration to capture it in the AST. if (IsInclusionDirective && hasASTContext()) { |