From 1e2cf0dd4bd7c76fc5a7862e42e2bac2da451fc7 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 31 Oct 2014 02:28:58 +0000 Subject: [PATCH] [modules] When a .pcm file is explicitly built separately from the translation unit, allow the -O settings of the two compilations to differ. llvm-svn: 220943 --- clang/include/clang/Basic/LangOptions.def | 57 ++++++++++++++++------- clang/include/clang/Serialization/ASTReader.h | 13 +++--- clang/lib/Frontend/ASTUnit.cpp | 4 +- clang/lib/Frontend/FrontendActions.cpp | 4 +- clang/lib/Serialization/ASTReader.cpp | 65 +++++++++++++++++++-------- clang/test/Modules/explicit-build-flags.cpp | 7 +++ 6 files changed, 108 insertions(+), 42 deletions(-) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index ec451e1..e3adaec 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -9,26 +9,40 @@ // // This file defines the language options. Users of this file must // define the LANGOPT macro to make use of this information. -// Optionally, the user may also define BENIGN_LANGOPT -// (for options that don't affect the construction of the AST in an -// incompatible way), ENUM_LANGOPT (for options that have enumeration, -// rather than unsigned, type), BENIGN_ENUM_LANGOPT (for benign -// options that have enumeration type), and VALUE_LANGOPT is a language option -// that describes a value rather than a flag. // +// Optionally, the user may also define: +// +// BENIGN_LANGOPT: for options that don't affect the construction of the AST in +// any way (that is, the value can be different between an implicit module +// and the user of that module). +// +// COMPATIBLE_LANGOPT: for options that affect the construction of the AST in +// a way that doesn't prevent interoperability (that is, the value can be +// different between an explicit module and the user of that module). +// +// ENUM_LANGOPT: for options that have enumeration, rather than unsigned, type. +// +// VALUE_LANGOPT: for options that describe a value rather than a flag. +// +// BENIGN_ENUM_LANGOPT, COMPATIBLE_ENUM_LANGOPT: combinations of the above. +// +// FIXME: Clients should be able to more easily select whether they want +// different levels of compatibility versus how to handle different kinds +// of option. //===----------------------------------------------------------------------===// + #ifndef LANGOPT # error Define the LANGOPT macro to handle language options #endif -#ifndef VALUE_LANGOPT -# define VALUE_LANGOPT(Name, Bits, Default, Description) \ +#ifndef COMPATIBLE_LANGOPT +# define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \ LANGOPT(Name, Bits, Default, Description) #endif #ifndef BENIGN_LANGOPT # define BENIGN_LANGOPT(Name, Bits, Default, Description) \ - LANGOPT(Name, Bits, Default, Description) + COMPATIBLE_LANGOPT(Name, Bits, Default, Description) #endif #ifndef ENUM_LANGOPT @@ -36,11 +50,22 @@ LANGOPT(Name, Bits, Default, Description) #endif +#ifndef COMPATIBLE_ENUM_LANGOPT +# define COMPATIBLE_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#endif + #ifndef BENIGN_ENUM_LANGOPT # define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - ENUM_LANGOPT(Name, Type, Bits, Default, Description) + COMPATIBLE_ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#endif + +#ifndef VALUE_LANGOPT +# define VALUE_LANGOPT(Name, Bits, Default, Description) \ + LANGOPT(Name, Bits, Default, Description) #endif +// FIXME: A lot of the BENIGN_ options should be COMPATIBLE_ instead. LANGOPT(C99 , 1, 0, "C99") LANGOPT(C11 , 1, 0, "C11") LANGOPT(MSVCCompat , 1, 0, "Microsoft Visual C++ full compatibility mode") @@ -102,8 +127,8 @@ LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses") LANGOPT(ModulesSearchAll , 1, 1, "search even non-imported modules to find unresolved references") LANGOPT(ModulesStrictDeclUse, 1, 0, "require declaration of module uses and all headers to be in modules") LANGOPT(ModulesErrorRecovery, 1, 1, "automatically import modules as needed when performing error recovery") -LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro") -LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro") +COMPATIBLE_LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro") +COMPATIBLE_LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro") LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)") VALUE_LANGOPT(PackStruct , 32, 0, "default struct packing maximum alignment") @@ -112,8 +137,8 @@ VALUE_LANGOPT(MaxTypeAlign , 32, 0, VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level") VALUE_LANGOPT(PIELevel , 2, 0, "__PIE__ level") LANGOPT(GNUInline , 1, 0, "GNU inline semantics") -LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro") -LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro") +COMPATIBLE_LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro") +COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro") LANGOPT(FastMath , 1, 0, "__FAST_MATH__ predefined macro") LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") @@ -192,8 +217,10 @@ LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling") LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST") #undef LANGOPT -#undef VALUE_LANGOPT +#undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT #undef ENUM_LANGOPT +#undef COMPATIBLE_ENUM_LANGOPT #undef BENIGN_ENUM_LANGOPT +#undef VALUE_LANGOPT diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 0891b55..447a6f4 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -115,7 +115,8 @@ public: /// /// \returns true to indicate the options are invalid or false otherwise. virtual bool ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) { + bool Complain, + bool AllowCompatibleDifferences) { return false; } @@ -219,7 +220,8 @@ public: bool ReadFullVersionInformation(StringRef FullVersion) override; void ReadModuleName(StringRef ModuleName) override; void ReadModuleMapFile(StringRef ModuleMapPath) override; - bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain) override; + bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, + bool AllowCompatibleDifferences) override; bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain) override; bool ReadDiagnosticOptions(IntrusiveRefCntPtr DiagOpts, @@ -251,8 +253,8 @@ public: PCHValidator(Preprocessor &PP, ASTReader &Reader) : PP(PP), Reader(Reader) {} - bool ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) override; + bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, + bool AllowCompatibleDifferences) override; bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain) override; bool ReadDiagnosticOptions(IntrusiveRefCntPtr DiagOpts, @@ -1149,7 +1151,8 @@ private: ASTReadResult ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities); static bool ParseLanguageOptions(const RecordData &Record, bool Complain, - ASTReaderListener &Listener); + ASTReaderListener &Listener, + bool AllowCompatibleDifferences); static bool ParseTargetOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener); static bool ParseDiagnosticOptions(const RecordData &Record, bool Complain, diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 1d8c6a1..bd81c0d 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -508,8 +508,8 @@ public: : PP(PP), Context(Context), LangOpt(LangOpt), TargetOpts(TargetOpts), Target(Target), Counter(Counter), InitializedLanguage(false) {} - bool ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) override { + bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, + bool AllowCompatibleDifferences) override { if (InitializedLanguage) return false; diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 6634e19..6a2ac60 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -431,8 +431,8 @@ namespace { Out.indent(2) << "Module map file: " << ModuleMapPath << "\n"; } - bool ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) override { + bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, + bool AllowCompatibleDifferences) override { Out.indent(2) << "Language options:\n"; #define LANGOPT(Name, Bits, Default, Description) \ DUMP_BOOLEAN(LangOpts.Name, Description); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 8fc6816..37a5ac1 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -80,10 +80,14 @@ void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) { First->ReadModuleMapFile(ModuleMapPath); Second->ReadModuleMapFile(ModuleMapPath); } -bool ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) { - return First->ReadLanguageOptions(LangOpts, Complain) || - Second->ReadLanguageOptions(LangOpts, Complain); +bool +ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain, + bool AllowCompatibleDifferences) { + return First->ReadLanguageOptions(LangOpts, Complain, + AllowCompatibleDifferences) || + Second->ReadLanguageOptions(LangOpts, Complain, + AllowCompatibleDifferences); } bool ChainedASTReaderListener::ReadTargetOptions(const TargetOptions &TargetOpts, @@ -155,11 +159,14 @@ ASTReaderListener::~ASTReaderListener() {} /// language options. /// /// \param Diags If non-NULL, diagnostics will be emitted via this engine. +/// \param AllowCompatibleDifferences If true, differences between compatible +/// language options will be permitted. /// /// \returns true if the languagae options mis-match, false otherwise. static bool checkLanguageOptions(const LangOptions &LangOpts, const LangOptions &ExistingLangOpts, - DiagnosticsEngine *Diags) { + DiagnosticsEngine *Diags, + bool AllowCompatibleDifferences = true) { #define LANGOPT(Name, Bits, Default, Description) \ if (ExistingLangOpts.Name != LangOpts.Name) { \ if (Diags) \ @@ -184,6 +191,14 @@ static bool checkLanguageOptions(const LangOptions &LangOpts, return true; \ } +#define COMPATIBLE_LANGOPT(Name, Bits, Default, Description) \ + if (!AllowCompatibleDifferences) \ + LANGOPT(Name, Bits, Default, Description) + +#define COMPATIBLE_ENUM_LANGOPT(Name, Bits, Default, Description) \ + if (!AllowCompatibleDifferences) \ + ENUM_LANGOPT(Name, Bits, Default, Description) + #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" @@ -278,10 +293,12 @@ static bool checkTargetOptions(const TargetOptions &TargetOpts, bool PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) { + bool Complain, + bool AllowCompatibleDifferences) { const LangOptions &ExistingLangOpts = PP.getLangOpts(); return checkLanguageOptions(LangOpts, ExistingLangOpts, - Complain? &Reader.Diags : nullptr); + Complain ? &Reader.Diags : nullptr, + AllowCompatibleDifferences); } bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, @@ -2261,6 +2278,12 @@ ASTReader::ReadControlBlock(ModuleFile &F, return Failure; } + // Should we allow the configuration of the module file to differ from the + // configuration of the current translation unit in a compatible way? + // + // FIXME: Allow this for files explicitly specified with -include-pch too. + bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule; + // Read all of the records and blocks in the control block. RecordData Record; unsigned NumInputs = 0; @@ -2415,8 +2438,10 @@ ASTReader::ReadControlBlock(ModuleFile &F, case LANGUAGE_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + // FIXME: The &F == *ModuleMgr.begin() check is wrong for modules. if (Listener && &F == *ModuleMgr.begin() && - ParseLanguageOptions(Record, Complain, *Listener) && + ParseLanguageOptions(Record, Complain, *Listener, + AllowCompatibleConfigurationMismatch) && !DisableValidation && !AllowConfigurationMismatch) return ConfigurationMismatch; break; @@ -2434,7 +2459,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, case DIAGNOSTIC_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate)==0; if (Listener && &F == *ModuleMgr.begin() && - F.Kind != MK_ExplicitModule && + !AllowCompatibleConfigurationMismatch && ParseDiagnosticOptions(Record, Complain, *Listener) && !DisableValidation) return OutOfDate; @@ -2444,7 +2469,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, case FILE_SYSTEM_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; if (Listener && &F == *ModuleMgr.begin() && - F.Kind != MK_ExplicitModule && + !AllowCompatibleConfigurationMismatch && ParseFileSystemOptions(Record, Complain, *Listener) && !DisableValidation && !AllowConfigurationMismatch) return ConfigurationMismatch; @@ -2454,7 +2479,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, case HEADER_SEARCH_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; if (Listener && &F == *ModuleMgr.begin() && - F.Kind != MK_ExplicitModule && + !AllowCompatibleConfigurationMismatch && ParseHeaderSearchOptions(Record, Complain, *Listener) && !DisableValidation && !AllowConfigurationMismatch) return ConfigurationMismatch; @@ -2464,7 +2489,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, case PREPROCESSOR_OPTIONS: { bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; if (Listener && &F == *ModuleMgr.begin() && - F.Kind != MK_ExplicitModule && + !AllowCompatibleConfigurationMismatch && ParsePreprocessorOptions(Record, Complain, *Listener, SuggestedPredefines) && !DisableValidation && !AllowConfigurationMismatch) @@ -4156,9 +4181,10 @@ namespace { { } - bool ReadLanguageOptions(const LangOptions &LangOpts, - bool Complain) override { - return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr); + bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain, + bool AllowCompatibleDifferences) override { + return checkLanguageOptions(ExistingLangOpts, LangOpts, nullptr, + AllowCompatibleDifferences); } bool ReadTargetOptions(const TargetOptions &TargetOpts, bool Complain) override { @@ -4256,7 +4282,8 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename, break; } case LANGUAGE_OPTIONS: - if (ParseLanguageOptions(Record, false, Listener)) + if (ParseLanguageOptions(Record, false, Listener, + /*AllowCompatibleConfigurationMismatch*/false)) return true; break; @@ -4612,7 +4639,8 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { /// \returns true if the listener deems the file unacceptable, false otherwise. bool ASTReader::ParseLanguageOptions(const RecordData &Record, bool Complain, - ASTReaderListener &Listener) { + ASTReaderListener &Listener, + bool AllowCompatibleDifferences) { LangOptions LangOpts; unsigned Idx = 0; #define LANGOPT(Name, Bits, Default, Description) \ @@ -4640,7 +4668,8 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record, } LangOpts.CommentOpts.ParseAllComments = Record[Idx++]; - return Listener.ReadLanguageOptions(LangOpts, Complain); + return Listener.ReadLanguageOptions(LangOpts, Complain, + AllowCompatibleDifferences); } bool ASTReader::ParseTargetOptions(const RecordData &Record, diff --git a/clang/test/Modules/explicit-build-flags.cpp b/clang/test/Modules/explicit-build-flags.cpp index bb5c416..c5c3df9 100644 --- a/clang/test/Modules/explicit-build-flags.cpp +++ b/clang/test/Modules/explicit-build-flags.cpp @@ -25,6 +25,13 @@ // Can use the module if -I flags change. // RUN: %clang_cc1 -fmodules -DBAR=2 -I. -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s +// Can use the module if -O flags change. +// RUN: %clang_cc1 -fmodules -DBAR=2 -Os -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp.pcm -verify -I%t %s +// +// RUN: %clang_cc1 -fmodules -DFOO=1 -O2 -x c++ -fmodule-name=tmp %t/map -emit-module -o %t/tmp-O2.pcm +// RUN: %clang_cc1 -fmodules -DBAR=2 -O0 -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp-O2.pcm -verify -I%t %s +// RUN: %clang_cc1 -fmodules -DBAR=2 -Os -x c++ -fmodule-map-file=%t/map -fmodule-file=%t/tmp-O2.pcm -verify -I%t %s + #include "tmp.h" // expected-no-diagnostics #ifndef BAR -- 2.7.4