From e74fbb3d4476db81d4f1fd15ce55556200f00b61 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Fri, 13 Mar 2026 13:15:32 -0400 Subject: [PATCH] Diagnostics: Implement diagnostic stack Create a stack state for managing diagnostics. This will eventually replace some of the global state used for diagnostics, as well as providing a mechanism to add additional diagnostics. For now, this is only the stack manipulation with a bare minimum of interface logic (in particular, the `block` and `include` commands). Nothing actually looks at the diagnostic state yet, and the primary user interface does not yet exist (although there are some references to it already). --- Help/command/block.rst | 12 +- Help/command/include.rst | 5 +- Source/CMakeLists.txt | 2 + Source/cmBlockCommand.cxx | 14 +- Source/cmDiagnostics.cxx | 48 +++++++ Source/cmDiagnostics.h | 86 +++++++++++ Source/cmFindPackageCommand.cxx | 3 +- Source/cmFunctionCommand.cxx | 5 +- Source/cmIncludeCommand.cxx | 6 +- Source/cmMacroCommand.cxx | 5 +- Source/cmMakefile.cxx | 134 +++++++++++++++--- Source/cmMakefile.h | 71 ++++++++-- Source/cmPolicies.cxx | 8 +- Source/cmState.cxx | 24 ++++ Source/cmState.h | 1 + Source/cmStatePrivate.h | 21 +++ Source/cmStateSnapshot.cxx | 126 ++++++++++++++++ Source/cmStateSnapshot.h | 29 ++++ .../Policy/MinVersionLargerThanMax-stderr.txt | 2 +- .../RangeBad-stderr.txt | 24 ++-- bootstrap | 1 + 21 files changed, 573 insertions(+), 54 deletions(-) create mode 100644 Source/cmDiagnostics.cxx create mode 100644 Source/cmDiagnostics.h diff --git a/Help/command/block.rst b/Help/command/block.rst index 7b5b581312..abdbd370b0 100644 --- a/Help/command/block.rst +++ b/Help/command/block.rst @@ -7,7 +7,8 @@ Evaluate a group of commands with a dedicated variable and/or policy scope. .. code-block:: cmake - block([SCOPE_FOR [POLICIES] [VARIABLES]] [PROPAGATE ...]) + block([SCOPE_FOR [DIAGNOSTICS] [POLICIES] [VARIABLES]] + [PROPAGATE ...]) endblock() @@ -19,6 +20,13 @@ scopes created by the ``block()`` command are removed. ``SCOPE_FOR`` Specify which scopes must be created. + ``DIAGNOSTICS`` + .. versionadded:: 4.4 + + Create a new diagnostic scope. This is equivalent to + :command:`cmake_diagnostic(PUSH)` with an automatic + :command:`cmake_diagnostic(POP)` when leaving the block scope. + ``POLICIES`` Create a new policy scope. This is equivalent to :command:`cmake_policy(PUSH)` with an automatic @@ -31,7 +39,7 @@ scopes created by the ``block()`` command are removed. .. code-block:: cmake - block(SCOPE_FOR VARIABLES POLICIES) + block(SCOPE_FOR VARIABLES POLICIES DIAGNOSTICS) ``PROPAGATE`` When a variable scope is created by the :command:`block` command, this diff --git a/Help/command/include.rst b/Help/command/include.rst index 80968da7b8..9e87db0711 100644 --- a/Help/command/include.rst +++ b/Help/command/include.rst @@ -6,7 +6,7 @@ Load and run CMake code from a file or module. .. code-block:: cmake include( [OPTIONAL] [RESULT_VARIABLE ] - [NO_POLICY_SCOPE]) + [NO_POLICY_SCOPE] [NO_DIAGNOSTIC_SCOPE]) Loads and runs CMake code from the file given. Variable reads and writes access the scope of the caller (dynamic scoping). If ``OPTIONAL`` @@ -23,3 +23,6 @@ module directory, then first the CMake builtin module directory is searched and See the :command:`cmake_policy` command documentation for discussion of the ``NO_POLICY_SCOPE`` option. + +See the :command:`cmake_diagnostic` command documentation for discussion of the +``NO_DIAGNOSTIC_SCOPE`` option. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index f520816c9a..c8f91baefe 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -185,6 +185,8 @@ add_library( cmDependsJavaParserHelper.h cmDependsCompiler.cxx cmDependsCompiler.h + cmDiagnostics.h + cmDiagnostics.cxx cmDocumentation.cxx cmDocumentationFormatter.cxx cmDyndepCollation.cxx diff --git a/Source/cmBlockCommand.cxx b/Source/cmBlockCommand.cxx index de31848723..575efe646c 100644 --- a/Source/cmBlockCommand.cxx +++ b/Source/cmBlockCommand.cxx @@ -25,7 +25,8 @@ namespace { enum class ScopeType : std::uint8_t { VARIABLES, - POLICIES + POLICIES, + DIAGNOSTICS, }; using ScopeSet = cm::enum_set; @@ -41,6 +42,7 @@ public: private: std::unique_ptr PolicyScope; std::unique_ptr VariableScope; + std::unique_ptr DiagnosticScope; }; BlockScopePushPop::BlockScopePushPop(cmMakefile* mf, ScopeSet const& scopes) @@ -51,6 +53,9 @@ BlockScopePushPop::BlockScopePushPop(cmMakefile* mf, ScopeSet const& scopes) if (scopes.contains(ScopeType::VARIABLES)) { this->VariableScope = cm::make_unique(mf); } + if (scopes.contains(ScopeType::DIAGNOSTICS)) { + this->DiagnosticScope = cm::make_unique(mf); + } } class cmBlockFunctionBlocker : public cmFunctionBlocker @@ -177,12 +182,17 @@ bool cmBlockCommand(std::vector const& args, scopes.insert(ScopeType::POLICIES); continue; } + if (scope == "DIAGNOSTICS"_s) { + scopes.insert(ScopeType::DIAGNOSTICS); + continue; + } status.SetError(cmStrCat("SCOPE_FOR unsupported scope \"", scope, '"')); cmSystemTools::SetFatalErrorOccurred(); return false; } } else { - scopes = { ScopeType::VARIABLES, ScopeType::POLICIES }; + scopes = { ScopeType::VARIABLES, ScopeType::POLICIES, + ScopeType::DIAGNOSTICS }; } if (!scopes.contains(ScopeType::VARIABLES) && !parsedArgs.Propagate.empty()) { diff --git a/Source/cmDiagnostics.cxx b/Source/cmDiagnostics.cxx new file mode 100644 index 0000000000..9c0192b6b2 --- /dev/null +++ b/Source/cmDiagnostics.cxx @@ -0,0 +1,48 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ +#include "cmDiagnostics.h" + +#include +#include +#include + +#include + +#include "cmStringAlgorithms.h" + +namespace { +cm::optional stringToCategory( + cm::string_view input) +{ + using Map = std::map; + static Map const mapping = { +#define CATEGORY_MAP(C) { #C ""_s, cmDiagnostics::C }, + CM_FOR_EACH_DIAGNOSTIC_CATEGORY(CATEGORY_MAP) +#undef CATEGORY_MAP + }; + + assert(!input.empty()); + if (input.size() >= 4 && cmHasLiteralPrefix(input, "CMD_")) { + auto const i = mapping.find(input); + if (i != mapping.end()) { + return i->second; + } + } + + return cm::nullopt; +} +} + +#if __cplusplus < 201703L +// Prior to C++17, the compiler is unhappy if this member doesn't have explicit +// storage... and clang-tidy is unhappy if it does. +// NOLINTNEXTLINE(*-redundant-declaration) +constexpr cmDiagnostics::DiagnosticCategoryInformation + cmDiagnostics::CategoryInfo[cmDiagnostics::CategoryCount]; +#endif + +cm::optional +cmDiagnostics::GetDiagnosticCategory(cm::string_view name) +{ + return stringToCategory(name); +} diff --git a/Source/cmDiagnostics.h b/Source/cmDiagnostics.h new file mode 100644 index 0000000000..623b7d75d0 --- /dev/null +++ b/Source/cmDiagnostics.h @@ -0,0 +1,86 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include +#include +#include + +#include +#include + +// https://github.com/include-what-you-use/include-what-you-use/issues/1934 +// IWYU pragma: no_forward_declare cmDiagnostics::DiagnosticAction +// IWYU pragma: no_forward_declare cmDiagnostics::DiagnosticCategory + +// The list of diagnostic categories along with their associated data. +// Each entry is of the form `SELECT(ACTION, , , )`. +// Entries MUST appear in the order that a depth-first enumeration would +// produce. + +#define CM_FOR_EACH_DIAGNOSTIC_TABLE(ACTION, SELECT) \ + SELECT(ACTION, Warn, CMD_NONE, CMD_AUTHOR) \ + SELECT(ACTION, Warn, CMD_NONE, CMD_DEPRECATED) + +#define CM_SELECT_CATEGORY(F, D, P, C) F(C) +#define CM_FOR_EACH_DIAGNOSTIC_CATEGORY(ACTION) \ + CM_FOR_EACH_DIAGNOSTIC_TABLE(ACTION, CM_SELECT_CATEGORY) + +/** \class cmDiagnostic + * \brief Handles CMake diagnostic (warning) behavior + * + * See the cmake-diagnostics(7) manual for an overview of this class's purpose. + */ +class cmDiagnostics +{ +public: + /// Action to take when a diagnostic is triggered + enum DiagnosticAction : std::uint8_t + { + Undefined = 0, + Ignore, + Warn, + SendError, + FatalError, + }; + + /// Diagnostic category identifiers + enum DiagnosticCategory : unsigned + { + CMD_NONE, +#define DIAGNOSTIC_ENUM(CATEGORY) CATEGORY, + CM_FOR_EACH_DIAGNOSTIC_CATEGORY(DIAGNOSTIC_ENUM) +#undef DIAGNOSTIC_ENUM + + /** \brief Always the last entry. + * + * Used to determine the number of diagnostic categories. Also useful to + * avoid adding a comma the last diagnostic category when adding a new one. + */ + CMD_COUNT + }; + constexpr static size_t CategoryCount = static_cast(CMD_COUNT); + + struct DiagnosticCategoryInformation + { + DiagnosticCategory Parent; + DiagnosticAction DefaultAction; + }; + + constexpr static DiagnosticCategoryInformation + CategoryInfo[CategoryCount] = { + { CMD_NONE, Undefined }, // CMD_NONE +#define DIAGNOSTIC_CATEGORY_INFO(F, D, P, C) { P, D }, + CM_FOR_EACH_DIAGNOSTIC_TABLE(UNUSED, DIAGNOSTIC_CATEGORY_INFO) +#undef DIAGNOSTIC_CATEGORY_INFO + }; + + //! Convert a string category into an identifier + static cm::optional GetDiagnosticCategory( + cm::string_view name); + + /** Represent a set of diagnostic category actions. */ + using DiagnosticMap = std::array; +}; diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 564a1a7338..f109995659 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -2086,7 +2086,8 @@ bool cmFindPackageCommand::ReadListFile(std::string const& f, // This allows child snapshots to inherit the CAN_UNWIND state from us, we'll // reset it immediately after the dependent file is done this->Makefile->GetStateSnapshot().SetUnwindType(cmStateEnums::CAN_UNWIND); - bool result = this->Makefile->ReadDependentFile(f, ps); + bool const result = + this->Makefile->ReadDependentFile(f, ps, cm::DiagnosticScope::Local); this->Makefile->GetStateSnapshot().SetUnwindType(oldUnwind); this->Makefile->GetStateSnapshot().SetUnwindState( diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index a629438cac..60c3b90077 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -10,6 +10,7 @@ #include #include +#include "cmDiagnostics.h" #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" #include "cmList.h" @@ -47,6 +48,7 @@ public: std::vector Args; std::vector Functions; cmPolicies::PolicyMap Policies; + cmDiagnostics::DiagnosticMap Diagnostics; std::string FilePath; long Line; }; @@ -72,7 +74,7 @@ bool cmFunctionHelperCommand::operator()( } cmMakefile::FunctionPushPop functionScope(&makefile, this->FilePath, - this->Policies); + this->Policies, this->Diagnostics); // set the value of argc makefile.AddDefinition(ARGC, std::to_string(expandedArgs.size())); @@ -171,6 +173,7 @@ bool cmFunctionFunctionBlocker::Replay( f.FilePath = this->GetStartingContext().FilePath; f.Line = this->GetStartingContext().Line; mf.RecordPolicies(f.Policies); + mf.RecordDiagnostics(f.Diagnostics); return mf.GetState()->AddScriptedCommand( this->Args.front(), BT(std::move(f), diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index db1201f5e5..84a7034cb7 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -49,6 +49,7 @@ bool cmIncludeCommand(std::vector const& args, bool optional = false; cm::PolicyScope policyScope = cm::PolicyScope::Local; + cm::DiagnosticScope diagnosticScope = cm::DiagnosticScope::Local; std::string fname = args[0]; std::string resultVarName; @@ -73,6 +74,8 @@ bool cmIncludeCommand(std::vector const& args, } } else if (args[i] == "NO_POLICY_SCOPE") { policyScope = cm::PolicyScope::None; + } else if (args[i] == "NO_DIAGNOSTIC_SCOPE") { + diagnosticScope = cm::DiagnosticScope::None; } else if (i > 1) // compat.: in previous cmake versions the second // parameter was ignored if it wasn't "OPTIONAL" { @@ -161,7 +164,8 @@ bool cmIncludeCommand(std::vector const& args, } } - bool readit = status.GetMakefile().ReadDependentFile(listFile, policyScope); + bool const readit = status.GetMakefile().ReadDependentFile( + listFile, policyScope, diagnosticScope); // add the location of the included file if a result variable was given if (!resultVarName.empty()) { diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index c1506a47f4..f193bce148 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -10,6 +10,7 @@ #include #include +#include "cmDiagnostics.h" #include "cmExecutionStatus.h" #include "cmFunctionBlocker.h" #include "cmList.h" @@ -37,6 +38,7 @@ public: std::vector Args; std::vector Functions; cmPolicies::PolicyMap Policies; + cmDiagnostics::DiagnosticMap Diagnostics; std::string FilePath; }; @@ -61,7 +63,7 @@ bool cmMacroHelperCommand::operator()( } cmMakefile::MacroPushPop macroScope(&makefile, this->FilePath, - this->Policies); + this->Policies, this->Diagnostics); // set the value of argc std::string argcDef = std::to_string(expandedArgs.size()); @@ -175,6 +177,7 @@ bool cmMacroFunctionBlocker::Replay(std::vector functions, f.Functions = std::move(functions); f.FilePath = this->GetStartingContext().FilePath; mf.RecordPolicies(f.Policies); + mf.RecordDiagnostics(f.Diagnostics); return mf.GetState()->AddScriptedCommand( this->Args[0], BT(std::move(f), diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 9672fa019d..54742eab06 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -175,8 +175,9 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot( this->StateSnapshot); - // Enter a policy level for this directory. + // Enter a policy and diagnostic level for this directory. this->PushPolicy(); + this->PushDiagnostic(); // push empty loop block this->PushLoopBlockBarrier(); @@ -620,7 +621,8 @@ class cmMakefile::IncludeScope : public FileScopeBase { public: IncludeScope(cmMakefile* mf, std::string const& filenametoread, - cm::PolicyScope policyScope); + cm::PolicyScope policyScope, + cm::DiagnosticScope diagnosticScope); ~IncludeScope(); void Quiet() { this->ReportError = false; } @@ -629,14 +631,17 @@ public: private: cm::PolicyScope PolicyScope; + cm::DiagnosticScope DiagnosticScope; bool ReportError = true; }; cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf, std::string const& filenametoread, - cm::PolicyScope policyScope) + cm::PolicyScope policyScope, + cm::DiagnosticScope diagnosticScope) : FileScopeBase(mf) , PolicyScope(policyScope) + , DiagnosticScope(diagnosticScope) { this->Makefile->Backtrace = this->Makefile->Backtrace.Push( cmListFileContext::FromListFilePath(filenametoread)); @@ -649,12 +654,19 @@ cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf, if (this->PolicyScope == cm::PolicyScope::Local) { this->Makefile->PushPolicy(); } + if (this->DiagnosticScope == cm::DiagnosticScope::Local) { + this->Makefile->PushDiagnostic(); + } this->PushListFileVars(filenametoread); } cmMakefile::IncludeScope::~IncludeScope() { this->PopListFileVars(); + if (this->DiagnosticScope == cm::DiagnosticScope::Local) { + // Pop the scope we pushed for the script. + this->Makefile->PopDiagnostic(); + } if (this->PolicyScope == cm::PolicyScope::Local) { // Pop the scope we pushed for the script. this->Makefile->PopPolicy(); @@ -667,12 +679,13 @@ cmMakefile::IncludeScope::~IncludeScope() } bool cmMakefile::ReadDependentFile(std::string const& filename, - cm::PolicyScope policyScope) + cm::PolicyScope policyScope, + cm::DiagnosticScope diagnosticScope) { std::string filenametoread = cmSystemTools::CollapseFullPath( filename, this->GetCurrentSourceDirectory()); - IncludeScope incScope(this, filenametoread, policyScope); + IncludeScope incScope(this, filenametoread, policyScope, diagnosticScope); #ifdef CMake_ENABLE_DEBUGGER if (this->GetCMakeInstance()->GetDebugAdapter()) { @@ -1442,7 +1455,8 @@ void cmMakefile::SetExplicitlyGeneratesSbom(bool status) } void cmMakefile::PushFunctionScope(std::string const& fileName, - cmPolicies::PolicyMap const& pm) + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm) { this->StateSnapshot = this->GetState()->CreateFunctionCallSnapshot( this->StateSnapshot, fileName); @@ -1457,10 +1471,12 @@ void cmMakefile::PushFunctionScope(std::string const& fileName, this->PushFunctionBlockerBarrier(); this->PushPolicy(true, pm); + this->PushDiagnostic(true, dm); } void cmMakefile::PopFunctionScope(bool reportError) { + this->PopDiagnostic(); this->PopPolicy(); this->PopSnapshot(reportError); @@ -1475,7 +1491,8 @@ void cmMakefile::PopFunctionScope(bool reportError) } void cmMakefile::PushMacroScope(std::string const& fileName, - cmPolicies::PolicyMap const& pm) + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm) { this->StateSnapshot = this->GetState()->CreateMacroCallSnapshot(this->StateSnapshot, fileName); @@ -1484,10 +1501,12 @@ void cmMakefile::PushMacroScope(std::string const& fileName, this->PushFunctionBlockerBarrier(); this->PushPolicy(true, pm); + this->PushDiagnostic(true, dm); } void cmMakefile::PopMacroScope(bool reportError) { + this->PopDiagnostic(); this->PopPolicy(); this->PopSnapshot(reportError); @@ -4146,18 +4165,83 @@ void cmMakefile::PopPolicy() } } +cmDiagnostics::DiagnosticAction cmMakefile::GetDiagnosticAction( + cmDiagnostics::DiagnosticCategory category) const +{ + return this->StateSnapshot.GetDiagnostic(category); +} + +bool cmMakefile::SetDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive) +{ + this->StateSnapshot.SetDiagnostic(category, action, recursive); + return true; +} + +bool cmMakefile::PromoteDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive) +{ + this->StateSnapshot.PromoteDiagnostic(category, action, recursive); + return true; +} + +bool cmMakefile::DemoteDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive) +{ + this->StateSnapshot.DemoteDiagnostic(category, action, recursive); + return true; +} + +cmMakefile::DiagnosticPushPop::DiagnosticPushPop(cmMakefile* m) + : Makefile(m) +{ + this->Makefile->PushDiagnostic(); +} + +cmMakefile::DiagnosticPushPop::~DiagnosticPushPop() +{ + this->Makefile->PopDiagnostic(); +} + +void cmMakefile::PushDiagnostic(bool weak, cmDiagnostics::DiagnosticMap dm) +{ + this->StateSnapshot.PushDiagnostic(dm, weak); +} + +void cmMakefile::PopDiagnostic() +{ + if (!this->StateSnapshot.PopDiagnostic()) { + this->IssueMessage(MessageType::FATAL_ERROR, + "cmake_diagnostic POP without matching PUSH"); + } +} + void cmMakefile::PopSnapshot(bool reportError) { - // cmStateSnapshot manages nested policy scopes within it. + // cmStateSnapshot manages nested policy/diagnostic scopes within it. // Since the scope corresponding to the snapshot is closing, - // reject any still-open nested policy scopes with an error. - while (this->StateSnapshot.CanPopPolicyScope()) { - if (reportError) { - this->IssueMessage(MessageType::FATAL_ERROR, - "cmake_policy PUSH without matching POP"); - reportError = false; + // reject any still-open nested policy/diagnostic scopes with an error. + for (;;) { + if (this->StateSnapshot.CanPopPolicyScope()) { + if (reportError) { + this->IssueMessage(MessageType::FATAL_ERROR, + "cmake_policy PUSH without matching POP"); + reportError = false; + } + this->PopPolicy(); + } else if (this->StateSnapshot.CanPopDiagnosticScope()) { + if (reportError) { + this->IssueMessage(MessageType::FATAL_ERROR, + "cmake_diagnostic PUSH without matching POP"); + reportError = false; + } + this->PopDiagnostic(); + } else { + break; } - this->PopPolicy(); } this->StateSnapshot = this->GetState()->Pop(this->StateSnapshot); @@ -4209,12 +4293,23 @@ void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const } } +void cmMakefile::RecordDiagnostics(cmDiagnostics::DiagnosticMap& dm) const +{ + /* Record the setting of every diagnostic category. */ + using DiagnosticCategory = cmDiagnostics::DiagnosticCategory; + for (size_t n = 0; n < cmDiagnostics::CategoryCount; ++n) { + DiagnosticCategory dc = static_cast(n); + dm[dc] = this->GetDiagnosticAction(dc); + } +} + cmMakefile::FunctionPushPop::FunctionPushPop(cmMakefile* mf, std::string const& fileName, - cmPolicies::PolicyMap const& pm) + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm) : Makefile(mf) { - this->Makefile->PushFunctionScope(fileName, pm); + this->Makefile->PushFunctionScope(fileName, pm, dm); } cmMakefile::FunctionPushPop::~FunctionPushPop() @@ -4224,10 +4319,11 @@ cmMakefile::FunctionPushPop::~FunctionPushPop() cmMakefile::MacroPushPop::MacroPushPop(cmMakefile* mf, std::string const& fileName, - cmPolicies::PolicyMap const& pm) + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm) : Makefile(mf) { - this->Makefile->PushMacroScope(fileName, pm); + this->Makefile->PushMacroScope(fileName, pm, dm); } cmMakefile::MacroPushPop::~MacroPushPop() diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 942dce1849..dae1afbd5a 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -25,6 +25,7 @@ #include "cmAlgorithms.h" #include "cmCustomCommand.h" +#include "cmDiagnostics.h" #include "cmFindPackageStack.h" #include "cmFunctionBlocker.h" #include "cmListFileCache.h" @@ -70,6 +71,12 @@ enum class PolicyScope : bool None, Local, }; + +enum class DiagnosticScope : bool +{ + None, + Local, +}; } /** A type-safe wrapper for a string representing a directory id. */ @@ -116,8 +123,10 @@ public: bool ReadListFileAsString(std::string const& content, std::string const& virtualFileName); - bool ReadDependentFile(std::string const& filename, - cm::PolicyScope policyScope = cm::PolicyScope::None); + bool ReadDependentFile( + std::string const& filename, + cm::PolicyScope policyScope = cm::PolicyScope::None, + cm::DiagnosticScope DiagnosticScope = cm::DiagnosticScope::None); /** * Add a function blocker to this makefile @@ -399,6 +408,24 @@ public: void RecordPolicies(cmPolicies::PolicyMap& pm) const; //@} + //@{ + /** + * Set, Push, Pop diagnostics for CMake. + */ + bool SetDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive = false); + bool PromoteDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive = false); + bool DemoteDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive = false); + cmDiagnostics::DiagnosticAction GetDiagnosticAction( + cmDiagnostics::DiagnosticCategory category) const; + void RecordDiagnostics(cmDiagnostics::DiagnosticMap& dm) const; + //@} + /** Update CMAKE_PARENT_LIST_FILE based on CMP0198 policy status. */ void UpdateParentListFileVariable(); @@ -417,6 +444,21 @@ public: }; friend class PolicyPushPop; + /** Helper class to push and pop diagnostics automatically. */ + class DiagnosticPushPop + { + public: + DiagnosticPushPop(cmMakefile* m); + ~DiagnosticPushPop(); + + DiagnosticPushPop(DiagnosticPushPop const&) = delete; + DiagnosticPushPop& operator=(DiagnosticPushPop const&) = delete; + + private: + cmMakefile* Makefile; + }; + friend class DiagnosticPushPop; + /** Helper class to push and pop variables scopes automatically. */ class VariablePushPop { @@ -889,7 +931,8 @@ public: { public: FunctionPushPop(cmMakefile* mf, std::string const& fileName, - cmPolicies::PolicyMap const& pm); + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm); ~FunctionPushPop(); FunctionPushPop(FunctionPushPop const&) = delete; @@ -906,7 +949,8 @@ public: { public: MacroPushPop(cmMakefile* mf, std::string const& fileName, - cmPolicies::PolicyMap const& pm); + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm); ~MacroPushPop(); MacroPushPop(MacroPushPop const&) = delete; @@ -920,10 +964,12 @@ public: }; void PushFunctionScope(std::string const& fileName, - cmPolicies::PolicyMap const& pm); + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm); void PopFunctionScope(bool reportError); void PushMacroScope(std::string const& fileName, - cmPolicies::PolicyMap const& pm); + cmPolicies::PolicyMap const& pm, + cmDiagnostics::DiagnosticMap dm); void PopMacroScope(bool reportError); void PushScope(); void PopScope(); @@ -1213,12 +1259,19 @@ private: TargetMap ImportedTargets; // Internal policy stack management. - void PushPolicy(bool weak = false, - cmPolicies::PolicyMap const& pm = cmPolicies::PolicyMap()); + void PushPolicy(bool weak = false, cmPolicies::PolicyMap const& pm = {}); void PopPolicy(); - void PopSnapshot(bool reportError = true); friend bool cmCMakePolicyCommand(std::vector const& args, cmExecutionStatus& status); + + // Internal diagnostic stack management. + void PushDiagnostic(bool weak = false, cmDiagnostics::DiagnosticMap dm = {}); + void PopDiagnostic(); + friend bool cmCMakeDiagnosticCommand(std::vector const& args, + cmExecutionStatus& status); + + void PopSnapshot(bool reportError = true); + class IncludeScope; friend class IncludeScope; diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index 337f220059..0c308fb0e6 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -259,10 +259,10 @@ bool cmPolicies::ApplyPolicyVersion(cmMakefile* mf, minPatch > maxPatch) || (minMajor == maxMajor && minMinor == maxMinor && minPatch == maxPatch && minTweak > maxTweak)) { - mf->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("Policy VERSION range \"", version_min, "...", version_max, - "\" specifies a larger minimum than maximum.")); + mf->IssueMessage(MessageType::FATAL_ERROR, + cmStrCat("Policy VERSION range \"", version_min, "...", + version_max, + "\" specifies a later minimum than maximum.")); return false; } diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 32556507ae..b60fb4cd65 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -301,6 +301,13 @@ cmStateSnapshot cmState::Reset() assert(pos->Policies.IsValid()); assert(pos->PolicyRoot.IsValid()); + this->DiagnosticStack.Clear(); + pos->Diagnostics = this->DiagnosticStack.Root(); + pos->DiagnosticRoot = this->DiagnosticStack.Root(); + pos->DiagnosticScope = this->DiagnosticStack.Root(); + assert(pos->Diagnostics.IsValid()); + assert(pos->DiagnosticRoot.IsValid()); + { std::string srcDir = *cmDefinitions::Get("CMAKE_SOURCE_DIR", pos->Vars, pos->Root); @@ -886,6 +893,11 @@ cmStateSnapshot cmState::CreateBaseSnapshot() pos->PolicyScope = this->PolicyStack.Root(); assert(pos->Policies.IsValid()); assert(pos->PolicyRoot.IsValid()); + pos->Diagnostics = this->DiagnosticStack.Root(); + pos->DiagnosticRoot = this->DiagnosticStack.Root(); + pos->DiagnosticScope = this->DiagnosticStack.Root(); + assert(pos->Diagnostics.IsValid()); + assert(pos->DiagnosticRoot.IsValid()); pos->Vars = this->VarTree.Push(this->VarTree.Root()); assert(pos->Vars.IsValid()); pos->Parent = this->VarTree.Root(); @@ -913,6 +925,11 @@ cmStateSnapshot cmState::CreateBuildsystemDirectorySnapshot( pos->PolicyScope = originSnapshot.Position->Policies; assert(pos->Policies.IsValid()); assert(pos->PolicyRoot.IsValid()); + pos->Diagnostics = originSnapshot.Position->Diagnostics; + pos->DiagnosticRoot = originSnapshot.Position->Diagnostics; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; + assert(pos->Diagnostics.IsValid()); + assert(pos->DiagnosticRoot.IsValid()); cmLinkedTree::iterator origin = originSnapshot.Position->Vars; pos->Parent = origin; @@ -939,6 +956,7 @@ cmStateSnapshot cmState::CreateDeferCallSnapshot( assert(originSnapshot.Position->Vars.IsValid()); pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; return { this, pos }; } @@ -954,6 +972,7 @@ cmStateSnapshot cmState::CreateFunctionCallSnapshot( originSnapshot.Position->ExecutionListFile, fileName); pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; assert(originSnapshot.Position->Vars.IsValid()); cmLinkedTree::iterator origin = originSnapshot.Position->Vars; pos->Parent = origin; @@ -973,6 +992,7 @@ cmStateSnapshot cmState::CreateMacroCallSnapshot( assert(originSnapshot.Position->Vars.IsValid()); pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; return { this, pos }; } @@ -988,6 +1008,7 @@ cmStateSnapshot cmState::CreateIncludeFileSnapshot( assert(originSnapshot.Position->Vars.IsValid()); pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; return { this, pos }; } @@ -1001,6 +1022,7 @@ cmStateSnapshot cmState::CreateVariableScopeSnapshot( pos->Keep = false; pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; assert(originSnapshot.Position->Vars.IsValid()); cmLinkedTree::iterator origin = originSnapshot.Position->Vars; @@ -1021,6 +1043,7 @@ cmStateSnapshot cmState::CreateInlineListFileSnapshot( originSnapshot.Position->ExecutionListFile, fileName); pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; return { this, pos }; } @@ -1033,6 +1056,7 @@ cmStateSnapshot cmState::CreatePolicyScopeSnapshot( pos->Keep = false; pos->BuildSystemDirectory->CurrentScope = pos; pos->PolicyScope = originSnapshot.Position->Policies; + pos->DiagnosticScope = originSnapshot.Position->Diagnostics; return { this, pos }; } diff --git a/Source/cmState.h b/Source/cmState.h index 885ade5fc0..8dad6bd881 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -288,6 +288,7 @@ private: cmLinkedTree ExecutionListFiles; + cmLinkedTree DiagnosticStack; cmLinkedTree PolicyStack; cmLinkedTree SnapshotData; cmLinkedTree VarTree; diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h index 651d9935f8..3c7655ebee 100644 --- a/Source/cmStatePrivate.h +++ b/Source/cmStatePrivate.h @@ -11,6 +11,7 @@ #include #include "cmDefinitions.h" +#include "cmDiagnostics.h" #include "cmLinkedTree.h" #include "cmListFileCache.h" #include "cmPackageState.h" @@ -22,6 +23,7 @@ namespace cmStateDetail { struct BuildsystemDirectoryStateType; struct PolicyStackEntry; +struct DiagnosticStackEntry; extern std::string const PropertySentinel; } // namespace cmStateDetail @@ -32,6 +34,9 @@ struct cmStateDetail::SnapshotDataType cmLinkedTree::iterator Policies; cmLinkedTree::iterator PolicyRoot; cmLinkedTree::iterator PolicyScope; + cmLinkedTree::iterator Diagnostics; + cmLinkedTree::iterator DiagnosticRoot; + cmLinkedTree::iterator DiagnosticScope; cmStateEnums::SnapshotType SnapshotType; cmStateEnums::SnapshotUnwindType UnwindType = cmStateEnums::NO_UNWIND; cmStateEnums::SnapshotUnwindState UnwindState = cmStateEnums::NOT_UNWINDING; @@ -64,6 +69,22 @@ struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap bool Weak; }; +struct cmStateDetail::DiagnosticStackEntry + : public cmDiagnostics::DiagnosticMap +{ + using derived = cmDiagnostics::DiagnosticMap; + DiagnosticStackEntry(bool w = false) + : Weak(w) + { + } + DiagnosticStackEntry(derived d, bool w) + : derived(d) + , Weak(w) + { + } + bool Weak; +}; + struct cmStateDetail::BuildsystemDirectoryStateType { cmStateDetail::PositionType CurrentScope; diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx index 50fc8d1fa8..778569f7bc 100644 --- a/Source/cmStateSnapshot.cxx +++ b/Source/cmStateSnapshot.cxx @@ -4,6 +4,7 @@ #include "cmStateSnapshot.h" #include +#include #include #include #include @@ -224,6 +225,131 @@ cmPolicies::PolicyStatus cmStateSnapshot::GetPolicy(cmPolicies::PolicyID id, return status; } +void cmStateSnapshot::PushDiagnostic(cmDiagnostics::DiagnosticMap entry, + bool weak) +{ + cmStateDetail::PositionType pos = this->Position; + pos->Diagnostics = this->State->DiagnosticStack.Push( + pos->Diagnostics, cmStateDetail::DiagnosticStackEntry(entry, weak)); +} + +bool cmStateSnapshot::PopDiagnostic() +{ + cmStateDetail::PositionType pos = this->Position; + if (pos->Diagnostics == pos->DiagnosticScope) { + return false; + } + pos->Diagnostics = this->State->DiagnosticStack.Pop(pos->Diagnostics); + return true; +} + +bool cmStateSnapshot::CanPopDiagnosticScope() +{ + return this->Position->Diagnostics != this->Position->DiagnosticScope; +} + +void cmStateSnapshot::SetDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive) +{ + assert(action != cmDiagnostics::Undefined); + + auto function = [](cmDiagnostics::DiagnosticAction, + cmDiagnostics::DiagnosticAction) -> bool { return true; }; + + this->AlterDiagnostic(category, action, function, recursive); +} + +void cmStateSnapshot::PromoteDiagnostic( + cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, bool recursive) +{ + assert(action != cmDiagnostics::Undefined); + + auto function = [](cmDiagnostics::DiagnosticAction current, + cmDiagnostics::DiagnosticAction desired) -> bool { + return (current < desired); + }; + + this->AlterDiagnostic(category, action, function, recursive); +} + +void cmStateSnapshot::DemoteDiagnostic( + cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, bool recursive) +{ + assert(action != cmDiagnostics::Undefined); + + auto function = [](cmDiagnostics::DiagnosticAction current, + cmDiagnostics::DiagnosticAction desired) -> bool { + return (current > desired); + }; + + this->AlterDiagnostic(category, action, function, recursive); +} + +void cmStateSnapshot::AlterDiagnostic( + cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, AlterDiagnosticFunction function, + bool recursive) +{ + if (recursive) { + unsigned i = category; + for (;;) { + this->AlterDiagnostic(static_cast(i), + action, function, false); + if (++i >= cmDiagnostics::CategoryCount) { + break; + } + if (cmDiagnostics::CategoryInfo[i].Parent < category) { + break; + } + } + } else { + cmDiagnostics::DiagnosticAction const oldAction = + this->GetDiagnostic(category); + if (function(oldAction, action)) { + // Update the policy stack from the top to the top-most strong entry. + bool previous_was_weak = true; + for (cmLinkedTree::iterator dsi = + this->Position->Diagnostics; + previous_was_weak && dsi != this->Position->DiagnosticRoot; ++dsi) { + (*dsi)[category] = action; + previous_was_weak = dsi->Weak; + } + } + } +} + +cmDiagnostics::DiagnosticAction cmStateSnapshot::GetDiagnostic( + cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction defaultAction) const +{ + cmLinkedTree::iterator dir = + this->Position->BuildSystemDirectory; + + while (true) { + assert(dir.IsValid()); + cmLinkedTree::iterator leaf = + dir->CurrentScope->Diagnostics; + cmLinkedTree::iterator root = + dir->CurrentScope->DiagnosticRoot; + for (; leaf != root; ++leaf) { + cmDiagnostics::DiagnosticAction const action = (*leaf)[category]; + if (action != cmDiagnostics::Undefined) { + return action; + } + } + cmStateDetail::PositionType e = dir->CurrentScope; + cmStateDetail::PositionType p = e->DirectoryParent; + if (p == this->State->SnapshotData.Root()) { + break; + } + dir = p->BuildSystemDirectory; + } + return defaultAction; +} + cmValue cmStateSnapshot::GetDefinition(std::string const& name) const { assert(this->Position->Vars.IsValid()); diff --git a/Source/cmStateSnapshot.h b/Source/cmStateSnapshot.h index d181fadae0..d7f8bfc9af 100644 --- a/Source/cmStateSnapshot.h +++ b/Source/cmStateSnapshot.h @@ -10,6 +10,7 @@ #include +#include "cmDiagnostics.h" #include "cmPolicies.h" #include "cmStateTypes.h" #include "cmValue.h" @@ -57,6 +58,27 @@ public: bool PopPolicy(); bool CanPopPolicyScope(); + void SetDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, bool recursive); + void PromoteDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive); + void DemoteDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + bool recursive); + cmDiagnostics::DiagnosticAction GetDiagnostic( + cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction defaultAction) const; + cmDiagnostics::DiagnosticAction GetDiagnostic( + cmDiagnostics::DiagnosticCategory category) const + { + return this->GetDiagnostic( + category, cmDiagnostics::CategoryInfo[category].DefaultAction); + } + void PushDiagnostic(cmDiagnostics::DiagnosticMap entry, bool weak); + bool PopDiagnostic(); + bool CanPopDiagnosticScope(); + cmState* GetState() const; cmStateDirectory GetDirectory() const; @@ -89,6 +111,13 @@ private: void InitializeFromParent(); + using AlterDiagnosticFunction = + bool (*)(cmDiagnostics::DiagnosticAction current, + cmDiagnostics::DiagnosticAction desired); + void AlterDiagnostic(cmDiagnostics::DiagnosticCategory category, + cmDiagnostics::DiagnosticAction action, + AlterDiagnosticFunction function, bool recursive); + cmState* State; cmStateDetail::PositionType Position; }; diff --git a/Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt b/Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt index 1fe985d99e..3a74173ef7 100644 --- a/Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt +++ b/Tests/RunCMake/Policy/MinVersionLargerThanMax-stderr.txt @@ -1,4 +1,4 @@ CMake Error at MinVersionLargerThanMax\.cmake:[0-9]+ \(cmake_policy\): - Policy VERSION range "3\.12\.\.\.3\.8" specifies a larger minimum than maximum\. + Policy VERSION range "3\.12\.\.\.3\.8" specifies a later minimum than maximum\. Call Stack \(most recent call first\): CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt b/Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt index 2d7afc0c04..3d0c2f7194 100644 --- a/Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt +++ b/Tests/RunCMake/cmake_minimum_required/RangeBad-stderr.txt @@ -1,56 +1,56 @@ -^CMake Error at RangeBad\.cmake:1 \(cmake_minimum_required\): +^CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_minimum_required\): cmake_minimum_required VERSION "3\.11\.\.\." does not have a version on both sides of "\.\.\."\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:2 \(cmake_minimum_required\): +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_minimum_required\): cmake_minimum_required VERSION "\.\.\.3\.11" does not have a version on both sides of "\.\.\."\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:3 \(cmake_minimum_required\): +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_minimum_required\): cmake_minimum_required VERSION "\.\.\." does not have a version on both sides of "\.\.\."\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:4 \(cmake_minimum_required\): +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_minimum_required\): Invalid policy max version value "4"\. A numeric major\.minor\[\.patch\[\.tweak\]\] must be given\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:5 \(cmake_minimum_required\): - Policy VERSION range "3\.11\.\.\.3\.10" specifies a larger minimum than maximum\. +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_minimum_required\): + Policy VERSION range "3\.11\.\.\.3\.10" specifies a later minimum than maximum\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:6 \(cmake_policy\): +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_policy\): cmake_policy VERSION "3\.11\.\.\." does not have a version on both sides of "\.\.\."\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:7 \(cmake_policy\): +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_policy\): cmake_policy VERSION "\.\.\.3\.11" does not have a version on both sides of "\.\.\."\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:8 \(cmake_policy\): +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_policy\): cmake_policy VERSION "\.\.\." does not have a version on both sides of "\.\.\."\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:9 \(cmake_policy\): +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_policy\): Invalid policy max version value "4"\. A numeric major\.minor\[\.patch\[\.tweak\]\] must be given\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\) + -CMake Error at RangeBad\.cmake:10 \(cmake_policy\): - Policy VERSION range "3\.11\.\.\.3\.10" specifies a larger minimum than maximum\. +CMake Error at RangeBad\.cmake:[0-9]+ \(cmake_policy\): + Policy VERSION range "3\.11\.\.\.3\.10" specifies a later minimum than maximum\. Call Stack \(most recent call first\): CMakeLists\.txt:3 \(include\)$ diff --git a/bootstrap b/bootstrap index 48c6491dbf..023403c6d2 100755 --- a/bootstrap +++ b/bootstrap @@ -336,6 +336,7 @@ CMAKE_CXX_SOURCES="\ cmCxxModuleUsageEffects \ cmDefinePropertyCommand \ cmDefinitions \ + cmDiagnostics \ cmDocumentationFormatter \ cmELF \ cmEnableLanguageCommand \