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).
This commit is contained in:
Matthew Woehlke
2026-03-18 14:32:21 -04:00
parent d80a38e524
commit e74fbb3d44
21 changed files with 573 additions and 54 deletions
+10 -2
View File
@@ -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 <var-name>...])
block([SCOPE_FOR [DIAGNOSTICS] [POLICIES] [VARIABLES]]
[PROPAGATE <var-name>...])
<commands>
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
+4 -1
View File
@@ -6,7 +6,7 @@ Load and run CMake code from a file or module.
.. code-block:: cmake
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
[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.
+2
View File
@@ -185,6 +185,8 @@ add_library(
cmDependsJavaParserHelper.h
cmDependsCompiler.cxx
cmDependsCompiler.h
cmDiagnostics.h
cmDiagnostics.cxx
cmDocumentation.cxx
cmDocumentationFormatter.cxx
cmDyndepCollation.cxx
+12 -2
View File
@@ -25,7 +25,8 @@ namespace {
enum class ScopeType : std::uint8_t
{
VARIABLES,
POLICIES
POLICIES,
DIAGNOSTICS,
};
using ScopeSet = cm::enum_set<ScopeType>;
@@ -41,6 +42,7 @@ public:
private:
std::unique_ptr<cmMakefile::PolicyPushPop> PolicyScope;
std::unique_ptr<cmMakefile::VariablePushPop> VariableScope;
std::unique_ptr<cmMakefile::DiagnosticPushPop> 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<cmMakefile::VariablePushPop>(mf);
}
if (scopes.contains(ScopeType::DIAGNOSTICS)) {
this->DiagnosticScope = cm::make_unique<cmMakefile::DiagnosticPushPop>(mf);
}
}
class cmBlockFunctionBlocker : public cmFunctionBlocker
@@ -177,12 +182,17 @@ bool cmBlockCommand(std::vector<std::string> 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()) {
+48
View File
@@ -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 <cassert>
#include <map>
#include <utility>
#include <cmext/string_view>
#include "cmStringAlgorithms.h"
namespace {
cm::optional<cmDiagnostics::DiagnosticCategory> stringToCategory(
cm::string_view input)
{
using Map = std::map<cm::string_view, cmDiagnostics::DiagnosticCategory>;
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::DiagnosticCategory>
cmDiagnostics::GetDiagnosticCategory(cm::string_view name)
{
return stringToCategory(name);
}
+86
View File
@@ -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 <array>
#include <cstddef>
#include <cstdint>
#include <cm/optional>
#include <cm/string_view>
// 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, <default>, <parent>, <name>)`.
// 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<size_t>(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<DiagnosticCategory> GetDiagnosticCategory(
cm::string_view name);
/** Represent a set of diagnostic category actions. */
using DiagnosticMap = std::array<DiagnosticAction, CategoryCount>;
};
+2 -1
View File
@@ -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(
+4 -1
View File
@@ -10,6 +10,7 @@
#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmDiagnostics.h"
#include "cmExecutionStatus.h"
#include "cmFunctionBlocker.h"
#include "cmList.h"
@@ -47,6 +48,7 @@ public:
std::vector<std::string> Args;
std::vector<cmListFileFunction> 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<cmState::Command>(std::move(f),
+5 -1
View File
@@ -49,6 +49,7 @@ bool cmIncludeCommand(std::vector<std::string> 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<std::string> 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<std::string> 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()) {
+4 -1
View File
@@ -10,6 +10,7 @@
#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmDiagnostics.h"
#include "cmExecutionStatus.h"
#include "cmFunctionBlocker.h"
#include "cmList.h"
@@ -37,6 +38,7 @@ public:
std::vector<std::string> Args;
std::vector<cmListFileFunction> 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<cmListFileFunction> 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<cmState::Command>(std::move(f),
+115 -19
View File
@@ -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<DiagnosticCategory>(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()
+62 -9
View File
@@ -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<std::string> const& args,
cmExecutionStatus& status);
// Internal diagnostic stack management.
void PushDiagnostic(bool weak = false, cmDiagnostics::DiagnosticMap dm = {});
void PopDiagnostic();
friend bool cmCMakeDiagnosticCommand(std::vector<std::string> const& args,
cmExecutionStatus& status);
void PopSnapshot(bool reportError = true);
class IncludeScope;
friend class IncludeScope;
+4 -4
View File
@@ -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;
}
+24
View File
@@ -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<cmDefinitions>::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<cmDefinitions>::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<cmDefinitions>::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 };
}
+1
View File
@@ -288,6 +288,7 @@ private:
cmLinkedTree<std::string> ExecutionListFiles;
cmLinkedTree<cmStateDetail::DiagnosticStackEntry> DiagnosticStack;
cmLinkedTree<cmStateDetail::PolicyStackEntry> PolicyStack;
cmLinkedTree<cmStateDetail::SnapshotDataType> SnapshotData;
cmLinkedTree<cmDefinitions> VarTree;
+21
View File
@@ -11,6 +11,7 @@
#include <vector>
#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<cmStateDetail::PolicyStackEntry>::iterator Policies;
cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator PolicyRoot;
cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator PolicyScope;
cmLinkedTree<cmStateDetail::DiagnosticStackEntry>::iterator Diagnostics;
cmLinkedTree<cmStateDetail::DiagnosticStackEntry>::iterator DiagnosticRoot;
cmLinkedTree<cmStateDetail::DiagnosticStackEntry>::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;
+126
View File
@@ -4,6 +4,7 @@
#include "cmStateSnapshot.h"
#include <algorithm>
#include <array>
#include <cassert>
#include <set>
#include <string>
@@ -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<cmDiagnostics::DiagnosticCategory>(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<cmStateDetail::DiagnosticStackEntry>::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<cmStateDetail::BuildsystemDirectoryStateType>::iterator dir =
this->Position->BuildSystemDirectory;
while (true) {
assert(dir.IsValid());
cmLinkedTree<cmStateDetail::DiagnosticStackEntry>::iterator leaf =
dir->CurrentScope->Diagnostics;
cmLinkedTree<cmStateDetail::DiagnosticStackEntry>::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());
+29
View File
@@ -10,6 +10,7 @@
#include <cm/string_view>
#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;
};
@@ -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\)
@@ -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\)$
+1
View File
@@ -336,6 +336,7 @@ CMAKE_CXX_SOURCES="\
cmCxxModuleUsageEffects \
cmDefinePropertyCommand \
cmDefinitions \
cmDiagnostics \
cmDocumentationFormatter \
cmELF \
cmEnableLanguageCommand \