Skip to content

build: opt-in C++20 (MINIO_CPP_STD=20) to unlock span/format/coroutines#237

Merged
harshavardhana merged 1 commit into
minio:mainfrom
jiuker:fix-issue-222
Jul 2, 2026
Merged

build: opt-in C++20 (MINIO_CPP_STD=20) to unlock span/format/coroutines#237
harshavardhana merged 1 commit into
minio:mainfrom
jiuker:fix-issue-222

Conversation

@jiuker

@jiuker jiuker commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

build: opt-in C++20 (MINIO_CPP_STD=20) to unlock span/format/coroutines
fix #222

## Problem

Default is \`MINIO_CPP_STD=17\` (\`CMakeLists.txt:54\`). That blocks several modernization wins:

- \`std::span<std::byte>\` for buffer params (replaces the \`char* buf; size_t size;\` pairs in \`args.h:162-183\`)
- \`std::format\` / \`std::to_chars\` ergonomics for hex/date formatting (see #219)
- Coroutine-ready awaitables in the async surface (see #217 Phase 2)
- \`std::ranges\` for any iterator-loop pipelines (low priority)

## Suggested approach

Don't force the upgrade — make it opt-in:

\`\`\`cmake
set(MINIO_CPP_STD "17" CACHE STRING "C++ standard (17 or 20)")
\`\`\`

Then guard the C++20-only paths with \`#if __cplusplus >= 202002L\` (the codebase already has one such guard at \`include/miniocpp/utils.h:173\` for \`operator<=>\`).

Public API stays C++17-compatible by default. C++20 builds get the extras.

## Impact

**Enabling change.** No perf/correctness improvement by itself — but unblocks #217 Phase 2, span-based buffer APIs, and potentially #222 (\`std::expected\` is C++23 but \`tl::expected\` is C++17 — so #222 doesn't strictly require this).

## Roadmap

Tier 3 item from the C++ modernization audit.

Summary by CodeRabbit

  • New Features
    • Added a more convenient way to create delete-object requests by passing an object name directly.
  • Chores
    • Expanded build and CI coverage to run across multiple C++ standard versions and platforms.

build: opt-in C++20 (MINIO_CPP_STD=20) to unlock span/format/coroutines
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR makes the C++ language standard configurable via a cached CMake variable MINIO_CPP_STD, extends the CI build matrix to test both C++17 and C++20 configurations across platforms, and adds a convenience constructor to DeleteObject.

Changes

C++ Standard Opt-in and CI Matrix

Layer / File(s) Summary
Cached build standard option
CMakeLists.txt
MINIO_CPP_STD is now set as a CACHE STRING variable with a description, persisting the selected standard across CMake re-configurations.
CI matrix and configure step wiring
.github/workflows/ci.yml
Build matrix entries add a cpp_std field (17/20) across Ubuntu (amd64/arm64), macOS, and Windows, and the CMake configure step passes -DMINIO_CPP_STD=${{matrix.config.cpp_std}}.
DeleteObject convenience constructor
include/miniocpp/types.h
Adds an explicit DeleteObject(std::string object_name) constructor that moves the argument into the name field.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

Not applicable — changes are configuration/build-matrix wiring and a small constructor addition, without multi-component runtime interaction flow.

Poem

A rabbit hops through matrix rows,
Seventeen and twenty, off it goes! 🐇
The cache now holds the standard tight,
One more constructor, clean and light,
Hop, build, test — all feels right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The added DeleteObject constructor is unrelated to the C++20 build-config work in #222. Move the DeleteObject constructor to a separate PR or justify it in the linked issue if it is intentionally part of this change.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is specific and accurately summarizes the main change: optional C++20 build support.
Linked Issues check ✅ Passed The build is now configurable for C++17/20 via MINIO_CPP_STD, matching the opt-in C++20 requirement in #222.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)

24-91: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Matrix duplication across cpp_std pairs.

Each C++20 entry duplicates all fields of its C++17 sibling except name, os/arch (where applicable) and cpp_std. Given the combos are selective (e.g., no macOS/Windows arm64 CXX20 variant), a full cross-product cpp_std: [17, 20] axis isn't directly applicable, but consider extracting shared fields via YAML anchors or a separate include: list to reduce duplication if the matrix grows further.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 24 - 91, The CI matrix in the workflow
duplicates nearly identical job definitions for each cpp_std variant, making it
harder to maintain as it grows. Refactor the strategy used in the matrix section
by reusing shared fields from the existing job entries (for example via YAML
anchors/aliases or a structured include-style list) so the Ubuntu/macOS/Windows
C++17 and C++20 variants stay easy to update while preserving the current
selective combinations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Line 145: The CMake invocation in the workflow’s run step is interpolating
matrix values directly into the shell command; switch this step to use env
indirection for the build type and C++ standard instead of embedding `${{
matrix.config.build_type }}` and `${{ matrix.config.cpp_std }}` inline. Update
the workflow job so the `cmake` step reads these values from environment
variables, keeping the command itself static and easier for static analysis to
verify.

In `@CMakeLists.txt`:
- Line 54: The MINIO_CPP_STD cache variable currently accepts any string, which
can let invalid values propagate into cxx_std_${MINIO_CPP_STD} and fail later
with a confusing error. Update the CMakeLists.txt configuration near
set(MINIO_CPP_STD) to validate the value immediately and constrain it to the
supported options only, using a clear fatal message if it is not one of the
allowed standards. Keep the check close to the existing MINIO_CPP_STD definition
so the behavior is easy to find and maintain.

---

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 24-91: The CI matrix in the workflow duplicates nearly identical
job definitions for each cpp_std variant, making it harder to maintain as it
grows. Refactor the strategy used in the matrix section by reusing shared fields
from the existing job entries (for example via YAML anchors/aliases or a
structured include-style list) so the Ubuntu/macOS/Windows C++17 and C++20
variants stay easy to update while preserving the current selective
combinations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c854c9aa-ee35-43be-9802-f56c9481aadc

📥 Commits

Reviewing files that changed from the base of the PR and between df9192d and 91b05bc.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • CMakeLists.txt
  • include/miniocpp/types.h

Comment thread .github/workflows/ci.yml
Comment thread CMakeLists.txt
@jiuker

jiuker commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Review Change Stack

📝 Walkthrough  📝 操作指南

Walkthrough

This PR makes the C++ language standard configurable via a cached CMake variable MINIO_CPP_STD, extends the CI build matrix to test both C++17 and C++20 configurations across platforms, and adds a convenience constructor to DeleteObject.

Changes

C++ Standard Opt-in and CI Matrix

Layer / File(s) Summary
Cached build standard option
CMakeLists.txt MINIO_CPP_STD is now set as a CACHE STRING variable with a description, persisting the selected standard across CMake re-configurations.
CI matrix and configure step wiring
.github/workflows/ci.yml Build matrix entries add a cpp_std field (17/20) across Ubuntu (amd64/arm64), macOS, and Windows, and the CMake configure step passes -DMINIO_CPP_STD=${{matrix.config.cpp_std}}.
DeleteObject convenience constructor
include/miniocpp/types.h Adds an explicit DeleteObject(std::string object_name) constructor that moves the argument into the name field.
Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

Not applicable — changes are configuration/build-matrix wiring and a small constructor addition, without multi-component runtime interaction flow.

Poem

A rabbit hops through matrix rows,
Seventeen and twenty, off it goes! 🐇
The cache now holds the standard tight,
One more constructor, clean and light,
Hop, build, test — all feels right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1
🚥 合并前检查 | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name  检查姓名 Status  状态 Explanation  解释 Resolution  决议
Out of Scope Changes check
超出范围变更检查 ⚠️ Warning   ⚠️ 警告 The added DeleteObject constructor is unrelated to the C++20 build-config work in #222.
新增的 DeleteObject 构造函数与 C++20 版本的 build-config 相关工作无关。 Move the DeleteObject constructor to a separate PR or justify it in the linked issue if it is intentionally part of this change.
将 DeleteObject 构造函数移到一个独立的 PR 中,或者如果它确实是此次变更的一部分,那么可以在相关的 issue 中对此进行说明。
✅ Passed checks (4 passed)
✅ 通过检查(4 次通过)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is specific and accurately summarizes the main change: optional C++20 build support.
Linked Issues check ✅ Passed The build is now configurable for C++17/20 via MINIO_CPP_STD, matching the opt-in C++20 requirement in #222.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.感谢您使用 CodeRabbit!对于开源项目来说,我们的服务是免费的;您的支持帮助我们不断成长。如果您喜欢我们的服务,请记得给我们点个赞哦。

❤️ Share  ❤️ 分享吧!

Comment @coderabbitai help to get the list of available commands.

jiuker@jiuker-PC:~/GolandProjects/minio-cpp$ cd /home/jiuker/GolandProjects/minio-cpp && cmake -S . -B build/Debug -DMINIO_CPP_STD=20 -DMINIO_CPP_TEST=ON 2>&1 | tail -5 && cmake --build build/Debug --target tests 2>&1 | tail -5
-- Configuring done (0.0s)
-- Generating done (0.1s)
-- Build files have been written to: /home/jiuker/GolandProjects/minio-cpp/build/Debug
/home/jiuker/GolandProjects/minio-cpp/include/miniocpp/types.h:354:8: note:   no known conversion for argument 1 from ‘std::__cxx11::basic_string<char>’ to ‘const minio::s3::DeleteObject&’
gmake[3]: *** [CMakeFiles/tests.dir/build.make:79:CMakeFiles/tests.dir/tests/tests.cc.o] 错误 1
gmake[2]: *** [CMakeFiles/Makefile2:1907:CMakeFiles/tests.dir/all] 错误 2
gmake[1]: *** [CMakeFiles/Makefile2:1914:CMakeFiles/tests.dir/rule] 错误 2
gmake: *** [Makefile:845:tests] 错误 2

@minio minio deleted a comment from coderabbitai Bot Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
fd -a types.h
echo "---- types.h DeleteObject struct ----"
rg -n "struct DeleteObject" -A 30 include/miniocpp/types.h
echo "---- tests.cc usage ----"
fd -a tests.cc
rg -n "DeleteObject" -B2 -A2 tests/tests.cc

Length of output: 2687


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "---- more context around tests.cc DeleteObject usages ----"
rg -n "DeleteObject" -B5 -A15 tests/tests.cc | head -100
echo "---- CMakeLists.txt cpp std section ----"
rg -n "MINIO_CPP_STD|CXX_STANDARD|Werror|pedantic" CMakeLists.txt

Length of output: 2739


🏁 Script executed:

#!/bin/bash
set -euo pipefail
which g++ clang++ 2>/dev/null || true
g++ --version 2>/dev/null | head -1 || true
cat > /tmp/repro.cpp << 'EOF'
`#include` <string>
`#include` <list>

struct DeleteObject {
  std::string name = {};
  std::string version_id = {};

  DeleteObject() = default;
  explicit DeleteObject(std::string object_name)
      : name(std::move(object_name)) {}
  ~DeleteObject() = default;
};

int main() {
  std::list<std::string> objects = {"a", "b"};
  std::list<DeleteObject> delete_objects;
  for (auto& object : objects) {
    delete_objects.push_back(DeleteObject{object});
  }
  return 0;
}
EOF
g++ -std=c++20 -Wall -Wextra /tmp/repro.cpp -o /tmp/repro 2>&1 || true
echo "---- c++17 ----"
g++ -std=c++17 -Wall -Wextra /tmp/repro.cpp -o /tmp/repro17 2>&1 || true

Length of output: 1012


@jiuker Thanks for the detailed repro log — this confirms the concern already flagged by the pre-merge check: the new DeleteObject(std::string object_name) constructor in include/miniocpp/types.h is unrelated to the C++20 opt-in work and it actually breaks the build.

Here's what's happening: before this PR, struct DeleteObject had no user-declared constructors, so it was an aggregate, and minio::s3::DeleteObject{object} in tests/tests.cc (Line 171) used aggregate initialization to set name directly from the string. Once you add DeleteObject() = default;, the new explicit DeleteObject(std::string object_name), and ~DeleteObject() = default;, the type is no longer an aggregate — so that same DeleteObject{object} expression now goes through constructor overload resolution instead, and the compiler ends up trying push_back(const DeleteObject&) with a std::string argument, which fails (hence the error at types.h:354, i.e. the struct DeleteObject definition). This isn't specific to MINIO_CPP_STD=20 — it would likely fail under 17 as well since the incompatibility comes from the constructor addition, not the standard flag. You can quickly confirm by building with the default MINIO_CPP_STD=17 and seeing the same error.

The cleanest fix is to update the call site in tests/tests.cc to construct DeleteObject directly instead of relying on braced copy-list-initialization:

for (auto& object : objects) {
  delete_objects.emplace_back(object);
}

emplace_back forwards the argument straight to the constructor (direct-initialization), avoiding the now-ambiguous/incompatible braced-init path entirely. Alternatively, delete_objects.push_back(minio::s3::DeleteObject(object)); (parentheses instead of braces) should also work.

Given this constructor addition is both out of scope for the C++20 opt-in change and is causing this build regression, I'd still recommend either dropping it from this PR (and fixing tests.cc separately if that helper is genuinely needed) or, if you want to keep it here, pairing it with the tests.cc fix above so the test suite builds cleanly under both standards.

Let me know if you'd like help wiring up the fix, or if you'd rather split the DeleteObject convenience constructor into its own PR.


✏️ Learnings added
Learnt from: jiuker
URL: https://github.com/minio/minio-cpp/pull/237

Timestamp: 2026-07-02T04:41:38.065Z
Learning: In minio-cpp's include/miniocpp/types.h, struct DeleteObject was an aggregate (no user-declared constructors) prior to PR `#237`. Adding a user-declared constructor (e.g. `explicit DeleteObject(std::string object_name)`) makes it no longer an aggregate, which breaks existing call sites like `minio::s3::DeleteObject{object}` in tests/tests.cc (used via `push_back`) since that relied on aggregate initialization. Such call sites need to be updated to direct-initialization (e.g. `emplace_back(object)` or `DeleteObject(object)` with parentheses) when constructors are added to previously-aggregate structs in this codebase.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline include/miniocpp/types.h --match DeleteObject --view expanded || true
printf '\n--- include/miniocpp/types.h (lines 340-365) ---\n'
sed -n '340,365p' include/miniocpp/types.h

printf '\n--- DeleteObject usages ---\n'
rg -n -C3 '\bDeleteObject\b|remove_objects|RemoveObjects' include tests .github CMakeLists.txt

Length of output: 12433


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- tests/tests.cc (lines 150-190) ---\n'
sed -n '150,190p' tests/tests.cc

printf '\n--- tests/tests.cc (lines 556-572) ---\n'
sed -n '556,572p' tests/tests.cc

printf '\n--- Search for likely string->DeleteObject call sites ---\n'
rg -n -C2 'DeleteObject|delete_objects|objects\.push_back|objects\.emplace_back|push_back\(object|push_back\(object_name|=\s*object_name|=\s*object\)' tests/tests.cc include

Length of output: 18909


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- Full repo search for DeleteObject usages ---\n'
rg -n -C2 '\bDeleteObject\b|push_back\(|emplace_back\(|objects\s*=|DeleteObject\s*\{' .

printf '\n--- Git diff for PR branch (relevant files) ---\n'
git diff -- include/miniocpp/types.h tests/tests.cc CMakeLists.txt .github/workflows/ci.yml || true

Length of output: 17163


@jiuker Thanks for the build log — this does point to a real compatibility issue around the new constructor.

From the current PR snapshot, include/miniocpp/types.h has:

  • Line 359: explicit DeleteObject(std::string object_name)

That means any existing code doing an implicit conversion, such as:

std::list<minio::s3::DeleteObject> objects;
objects.push_back(object_name);  // object_name is std::string

will fail with exactly the kind of diagnostic you pasted.

A couple of important notes from the repo state I checked:

  • tests/tests.cc already uses explicit construction on Line 171:
    delete_objects.push_back(minio::s3::DeleteObject{object});
  • examples/RemoveObjects.cc also constructs DeleteObject explicitly.

So the exact failing call site is not visible in the checked-in snapshot I inspected, but the regression mechanism is clear: adding explicit changed source compatibility for DeleteObject.

Two reasonable fixes:

// Option 1: keep the convenience behavior
DeleteObject(std::string object_name) : name(std::move(object_name)) {}

or, if you want to keep the constructor explicit, update all call sites to use direct construction:

objects.emplace_back(object_name);
// or
objects.push_back(minio::s3::DeleteObject{object_name});

So I’d revise my earlier assessment slightly: this constructor isn’t just “extra scope” — it also changes public API behavior and can break callers. If the goal of this PR is only the C++17/C++20 build toggle, the safest path is probably to drop this constructor from the PR. If you want to keep it, it should come with call-site updates and a compatibility check.


✏️ Learnings added
Learnt from: jiuker
URL: https://github.com/minio/minio-cpp/pull/237

Timestamp: 2026-07-02T04:42:26.648Z
Learning: In the minio-cpp repository, `minio::s3::DeleteObject` in `include/miniocpp/types.h` is a public type used by `RemoveObjects` flows, and making its `std::string` constructor `explicit` is source-breaking for callers that rely on implicit conversion such as `std::list<DeleteObject>::push_back(std::string)`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@jiuker jiuker requested a review from harshavardhana July 2, 2026 04:44
@harshavardhana harshavardhana merged commit 06271b2 into minio:main Jul 2, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build: opt-in C++20 (MINIO_CPP_STD=20) to unlock span/format/coroutines

2 participants