diff options
-rw-r--r-- | include/clang/Driver/Options.td | 2 | ||||
-rw-r--r-- | include/clang/Lex/HeaderSearchOptions.h | 10 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 3 | ||||
-rw-r--r-- | lib/Frontend/CompilerInstance.cpp | 30 | ||||
-rw-r--r-- | lib/Frontend/CompilerInvocation.cpp | 24 | ||||
-rw-r--r-- | test/Modules/ignored_macros.m | 24 |
6 files changed, 87 insertions, 6 deletions
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 35ea80307c..ae0ae84e17 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -501,6 +501,8 @@ def fmodules_autolink : Flag <["-"], "fmodules-autolink">, Group<f_Group>, Flags HelpText<"Enable autolinking of the libraries for imported modules">; def fno_modules_autolink : Flag <["-"], "fno-modules-autolink">, Group<f_Group>, HelpText<"Disable autolinking of the libraries for imported modules">; +def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Ignore the definition of the given macro when building and loading modules">; def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>; def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>; diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h index 8fecd65726..c45884360d 100644 --- a/include/clang/Lex/HeaderSearchOptions.h +++ b/include/clang/Lex/HeaderSearchOptions.h @@ -12,7 +12,9 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" +#include <string> #include <vector> namespace clang { @@ -86,13 +88,17 @@ public: /// \brief The directory used for the module cache. std::string ModuleCachePath; - + /// \brief Whether we should disable the use of the hash string within the /// module cache. /// /// Note: Only used for testing! unsigned DisableModuleHash : 1; - + + /// \brief The set of macro names that should be ignored for the purposes + /// of computing the module hash. + llvm::SetVector<std::string> ModulesIgnoreMacros; + /// Include the compiler builtin includes. unsigned UseBuiltinIncludes : 1; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 71e50a5c9e..7932ba2827 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -428,6 +428,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, CmdArgs.push_back("-fmodule-cache-path"); CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache)); } + + // Pass through all -fmodules-ignore-macro arguments. + Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); // Parse additional include paths from environment variables. // FIXME: We should probably sink the logic for handling these from the diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index b6115ec6ff..356bf3171c 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -743,6 +743,28 @@ static void doCompileMapModule(void *UserData) { Data.Instance.ExecuteAction(Data.CreateModuleAction); } +namespace { + /// \brief Function object that checks with the given macro definition should + /// be removed, because it is one of the ignored macros. + class RemoveIgnoredMacro { + const HeaderSearchOptions &HSOpts; + + public: + explicit RemoveIgnoredMacro(const HeaderSearchOptions &HSOpts) + : HSOpts(HSOpts) { } + + bool operator()(const std::pair<std::string, bool> &def) const { + // Dig out the macro name. + StringRef MacroName = def.first; + StringRef::size_type EqPos = MacroName.find('='); + if (EqPos != StringRef::npos) + MacroName = MacroName.substr(0, EqPos); + + return HSOpts.ModulesIgnoreMacros.count(MacroName) > 0; + } + }; +} + /// \brief Compile a module file for the given module, using the options /// provided by the importing compiler instance. static void compileModule(CompilerInstance &ImportingInstance, @@ -779,6 +801,14 @@ static void compileModule(CompilerInstance &ImportingInstance, Invocation->getLangOpts()->resetNonModularOptions(); PPOpts.resetNonModularOptions(); + // Remove any macro definitions that are explicitly ignored by the module. + // They aren't supposed to affect how the module is built anyway. + const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts(); + PPOpts.Macros.erase(std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(), + RemoveIgnoredMacro(HSOpts)), + PPOpts.Macros.end()); + + // Note the name of the module we're building. Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName(); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index a4597fd84d..34496ede26 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -813,7 +813,13 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); - + + for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + Opts.ModulesIgnoreMacros.insert(A->getValue()); + } + // Add -I..., -F..., and -index-header-map options in order. bool IsIndexHeaderMap = false; for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F, @@ -1600,6 +1606,7 @@ std::string CompilerInvocation::getModuleHash() const { // Extend the signature with preprocessor options. const PreprocessorOptions &ppOpts = getPreprocessorOpts(); + const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); std::vector<StringRef> MacroDefs; @@ -1607,11 +1614,24 @@ std::string CompilerInvocation::getModuleHash() const { I = getPreprocessorOpts().Macros.begin(), IEnd = getPreprocessorOpts().Macros.end(); I != IEnd; ++I) { + // If we're supposed to ignore this macro for the purposes of modules, + // don't put it into the hash. + if (!hsOpts.ModulesIgnoreMacros.empty()) { + // Dig out the macro name. + StringRef MacroName = I->first; + StringRef::size_type EqPos = MacroName.find('='); + if (EqPos != StringRef::npos) + MacroName = MacroName.substr(0, EqPos); + + // Check whether we're ignoring this macro. + if (hsOpts.ModulesIgnoreMacros.count(MacroName)) + continue; + } + code = hash_combine(code, I->first, I->second); } // Extend the signature with the sysroot. - const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes, hsOpts.UseStandardSystemIncludes, hsOpts.UseStandardCXXIncludes, diff --git a/test/Modules/ignored_macros.m b/test/Modules/ignored_macros.m index 1f9c27c2a3..3d5f359b31 100644 --- a/test/Modules/ignored_macros.m +++ b/test/Modules/ignored_macros.m @@ -1,15 +1,31 @@ -// First trial: pass -DIGNORED=1 to both. It should be ignored in both +// First trial: pass -DIGNORED=1 to both. This should obviously work. // RUN: rm -rf %t.modules // RUN: %clang_cc1 -fmodule-cache-path %t.modules -DIGNORED=1 -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify // RUN: %clang_cc1 -fmodule-cache-path %t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch %s -verify -// Second trial: pass -DIGNORED=1 only to the second invocation. +// Second trial: pass -DIGNORED=1 only to the second invocation. We +// should detect the failure. +// // RUN: rm -rf %t.modules // RUN: %clang_cc1 -fmodule-cache-path %t.modules -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify // RUN: not %clang_cc1 -fmodule-cache-path %t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch %s > %t.err 2>&1 // RUN: FileCheck -check-prefix=CHECK-CONFLICT %s < %t.err // CHECK-CONFLICT: module 'ignored_macros' found in both +// Third trial: pass -DIGNORED=1 only to the second invocation, but +// make it ignored. There should be no failure, IGNORED is defined in +// the translation unit but not the module. +// RUN: rm -rf %t.modules +// RUN: %clang_cc1 -fmodule-cache-path %t.modules -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify +// RUN: %clang_cc1 -fmodule-cache-path %t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch -fmodules-ignore-macro=IGNORED %s -verify + +// Fourth trial: pass -DIGNORED=1 and -fmodules-ignore-macro=IGNORED +// to both invocations, so modules will be built without the IGNORED +// macro. +// RUN: rm -rf %t.modules +// RUN: %clang_cc1 -fmodule-cache-path %t.modules -DIGNORED=1 -fmodules-ignore-macro=IGNORED -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify +// RUN: %clang_cc1 -fmodule-cache-path %t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch -fmodules-ignore-macro=IGNORED -DNO_IGNORED_ANYWHERE -fmodules-ignore-macro=NO_IGNORED_ANYWHERE %s -verify + // expected-no-diagnostics #ifndef HEADER @@ -20,3 +36,7 @@ @import ignored_macros; struct Point p; + +#ifdef NO_IGNORED_ANYWHERE +void *has_ignored(int, int, int); +#endif |