Compare commits

..
Author SHA1 Message Date
Niels Lohmann 11e75a5428 Cancel CI runs of merged and closed pull requests (#5748) 2026-10-01 10:53:10 +02:00
Niels Lohmann e400780533 Re-amalgamate single_include (#5745)
* Re-amalgamate single_include

#5737 changed 13 headers under include/ but merged without the matching
single_include/nlohmann/json.hpp update, so the amalgamated header still
had, among others, the GCC C++20 -Wignored-attributes pragma block and
the clang -Wdocumentation push/pop that #5737 removed, the forwarding
from_json tuple/array helpers it replaced with const references, and
lacked the output_adapter char_traits changes it added.

Regenerated with `make amalgamate` (astyle 3.4.13). The diff is exactly
`git diff b54ed188e e5a89d671 -- include/` (164+/95-); json_fwd.hpp and
json_literals.hpp were already up to date.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Run the amalgamation check on pushes to develop

#5737 was merged 39 seconds after its last push, while its own
check_amalgamation run was still queued (earlier runs had been
cancelled by the concurrency group), so the stale single_include
reached develop without any failing check.

Also run the check on pushes to develop, without cancelling in-progress
develop runs. The "save" job (PR number/author for the comment
workflow) only runs for pull requests, the checkout falls back to
github.sha, and comment_check_amalgamation.yml only comments for
PR-triggered runs, since push runs have no PR and no "pr" artifact.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-01 08:09:34 +02:00
7 changed files with 65 additions and 109 deletions
@@ -0,0 +1,53 @@
name: "Cancel runs of closed pull requests"
# The concurrency groups of the other workflows cancel superseded runs when a
# pull request gets new commits, but nothing stops the runs of its last commit
# once the pull request is merged or closed. They then keep the runners busy
# for hours while the queue of the open pull requests waits.
#
# pull_request_target is needed to get a token that can cancel runs for pull
# requests from forks. This is safe because the workflow never checks out or
# runs code from the pull request; it only calls the API.
on:
pull_request_target:
types: [closed]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
cancel:
permissions:
actions: write
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
with:
egress-policy: audit
- name: Cancel unfinished runs of the pull request's head commit
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
SELF: ${{ github.run_id }}
# only runs triggered by the pull request: when a branch is pushed to
# develop directly, its push runs share the head commit
run: |
gh api --paginate "repos/$GH_REPO/actions/runs?head_sha=$HEAD_SHA&per_page=100" \
--jq ".workflow_runs[]
| select(.status != \"completed\" and .id != $SELF)
| select(.event == \"pull_request\" or .event == \"pull_request_target\")
| \"\(.id) \(.name)\"" |
while read -r id name; do
echo "Cancelling run $id ($name)"
# a run may finish between listing and cancelling; that is not an error
gh run cancel "$id" || true
done
+10 -3
View File
@@ -2,16 +2,23 @@ name: "Check amalgamation"
on: on:
pull_request: pull_request:
# also check develop itself: a PR can be merged before its own run of this
# workflow completes (e.g. while it is still queued), leaving single_include
# stale on develop without any failing check
push:
branches:
- develop
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }} group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions: permissions:
contents: read contents: read
jobs: jobs:
save: save:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Harden Runner - name: Harden Runner
@@ -43,11 +50,11 @@ jobs:
with: with:
egress-policy: audit egress-policy: audit
- name: Checkout pull request - name: Checkout pull request or pushed commit
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
path: main path: main
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false persist-credentials: false
- name: Checkout tools - name: Checkout tools
@@ -10,7 +10,8 @@ permissions:
jobs: jobs:
comment: comment:
if: ${{ github.event.workflow_run.conclusion == 'failure' }} # push runs on develop have no PR to comment on (and no "pr" artifact)
if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: read contents: read
-12
View File
@@ -763,15 +763,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static_cast<void>(check_parents); static_cast<void>(check_parents);
} }
// GCC 13 to at least 15 report a false -Warray-bounds error when set_parents()
// is inlined at -O3 right after a non-container value was created: the analysis
// does not use m_type to rule out the object/array branches and checks
// the std::map access against the allocation of, e.g., a string.
// See https://github.com/nlohmann/json/issues/5742 and #4819.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
void set_parents() void set_parents()
{ {
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
@@ -808,9 +799,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
#endif #endif
} }
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
iterator set_parents(iterator it, std::ptrdiff_t count_set_parents) iterator set_parents(iterator it, std::ptrdiff_t count_set_parents)
{ {
-12
View File
@@ -27441,15 +27441,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
static_cast<void>(check_parents); static_cast<void>(check_parents);
} }
// GCC 13 to at least 15 report a false -Warray-bounds error when set_parents()
// is inlined at -O3 right after a non-container value was created: the analysis
// does not use m_type to rule out the object/array branches and checks
// the std::map access against the allocation of, e.g., a string.
// See https://github.com/nlohmann/json/issues/5742 and #4819.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
void set_parents() void set_parents()
{ {
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
@@ -27486,9 +27477,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
} }
#endif #endif
} }
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
iterator set_parents(iterator it, std::ptrdiff_t count_set_parents) iterator set_parents(iterator it, std::ptrdiff_t count_set_parents)
{ {
-5
View File
@@ -139,11 +139,6 @@ json_test_set_test_options(test-unicode4 TEST_PROPERTIES TIMEOUT 3000)
# only the #972 regression test needs thirdparty/fifo_map on its include path # only the #972 regression test needs thirdparty/fifo_map on its include path
json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include) json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include)
# GCC's false -Warray-bounds error with JSON_DIAGNOSTICS only shows up when optimizing (#5742)
json_test_set_test_options(test-diagnostics-optimized
COMPILE_OPTIONS $<$<CXX_COMPILER_ID:GNU>:-O3 -Werror=array-bounds>
)
############################################################################# #############################################################################
# add unit tests # add unit tests
############################################################################# #############################################################################
-76
View File
@@ -1,76 +0,0 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.12.0
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// Regression test for https://github.com/nlohmann/json/issues/5742: with
// JSON_DIAGNOSTICS, GCC (13 to at least 15) reports a false -Warray-bounds
// error in the inlined set_parents() at -O3. The warning depends on GCC's
// inlining decisions, so the sections cover patterns that trigger it on
// different GCC versions (#4819: GCC 13 and 14; #5742: GCC 14 and 15).
// On GCC, this file is compiled with -O3 -Werror=array-bounds (see
// tests/CMakeLists.txt), so the test fails to build if the warning returns.
#include "doctest_compatibility.h"
#ifdef JSON_DIAGNOSTICS
#undef JSON_DIAGNOSTICS
#endif
#define JSON_DIAGNOSTICS 1
#include <nlohmann/json.hpp>
using nlohmann::json;
#include <algorithm>
#include <iterator>
#include <utility>
#include <vector>
namespace
{
enum class diag_color
{
red,
green,
blue
};
void to_json(json& j, const diag_color& c)
{
static const std::pair<diag_color, json> m[] = // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
{
{diag_color::red, "r"},
{diag_color::green, "g"},
{diag_color::blue, "b"},
};
const auto* it = std::find_if(std::begin(m), std::end(m), [c](const std::pair<diag_color, json>& p)
{
return p.first == c;
});
j = it->second;
}
} // namespace
TEST_CASE("diagnostics with optimization")
{
SECTION("issue #4819 - object in vector")
{
std::vector<json> jsons{};
jsons.emplace_back(json({{"key", "value"}}));
CHECK(jsons.back()["key"] == "value");
}
SECTION("issue #5742 - string values from a static table")
{
json j = json::array();
j.push_back(diag_color::red);
j.push_back(diag_color::green);
j.push_back(diag_color::blue);
CHECK(j.dump() == R"(["r","g","b"])");
CHECK_THROWS_WITH_AS(j[1].get<int>(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error);
}
}