Skip to content

Tuple: Silence modernize-pass-by-value - #5646

Merged
WeiqunZhang merged 1 commit into
AMReX-Codes:developmentfrom
ax3l:topic-tuple-pass-by-value
Aug 26, 2026
Merged

WeiqunZhang merged 1 commit into
AMReX-Codes:developmentfrom
ax3l:topic-tuple-pass-by-value

Conversation

@ax3l

@ax3l ax3l commented Aug 25, 2026

Copy link
Copy Markdown
Member

Summary

clang-tidy's modernize-pass-by-value fires on detail::gpu_tuple_element's constructor and asks for the argument to be taken by value and moved. Following that advice would be a pessimization here. This adds a NOLINTNEXTLINE with the reasoning written down, because it is not obvious from the code.

Why by value is wrong here

The forwarding constructor immediately below already takes everything that can be deduced — lvalues and rvalues of T alike. The const-reference overload is reached only by arguments it cannot deduce, a braced initializer list above all:

struct P { int a, b; };

P p{1,2};
E<P> a(p);        // forwarding constructor
E<P> b(P{3,4});   // forwarding constructor
E<P> c({5,6});    // this one -- U cannot be deduced from a braced-init-list

(verified by instrumenting the two constructors and running the three cases)

So taking it by value would add a move for exactly the callers this overload exists to serve, and save a copy for nobody, since rvalues never reach it. Removing the overload instead is not an option either — the braced-init case would stop compiling.

Why it is showing up now

Nothing changed in AMReX_Tuple.H. The SIMD CI job runs clang-tidy over ccache misses, so which headers get linted depends on what was recompiled. A change to a widely included header — #5644 touches AMReX_Math.H — pulls AMReX_Tuple.H into the linted set and the finding appears. It is pre-existing on development and unrelated to that work, which is why it is split out here: this is a two-line comment change that can be reviewed on its own, and #5644 can rebase on it afterwards.

Testing

clang-tidy-21 --config-file=.clang-tidy --header-filter='.*AMReX.*'

over Tests/SIMD/main.cpp and Tests/Particles/ParticleReduceSIMD/main.cpp: modernize-pass-by-value findings across all AMReX headers go from 1 to 0, and this was the only one. AMReX_Tuple.H still compiles and behaves the same (amrex::makeTuple with scalar and aggregate members).

🤖 Generated with Claude Code

clang-tidy's modernize-pass-by-value wants this constructor to take its
argument by value and move it. Doing so would be a pessimization here, and
the reason is not obvious from the code, so record it.

The forwarding constructor right below already takes everything that can be
deduced, lvalues and rvalues of T alike:

  P p{1,2};
  E<P> a(p);        // forwarding constructor
  E<P> b(P{3,4});   // forwarding constructor
  E<P> c({5,6});    // this one -- U cannot be deduced from a braced list

So the const-reference overload is reached only by arguments the forwarding
constructor cannot deduce, a braced initializer list above all. Taking it by
value would add a move for exactly those callers and save a copy for nobody.

This surfaces in the SIMD CI job rather than the others because clang-tidy
runs on ccache misses, and a change to a widely included header is what makes
Tuple.H one of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread Src/Base/AMReX_Tuple.H
Comment on lines +32 to +37
// This overload is what catches arguments the forwarding constructor below
// cannot deduce, a braced initializer list above all. Everything else, both
// lvalues and rvalues of T, already goes there. Taking this one by value
// would therefore add a move for exactly those callers while saving a copy
// for nobody.
// NOLINTNEXTLINE(modernize-pass-by-value)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Open to either compact or explained version:

Suggested change
// This overload is what catches arguments the forwarding constructor below
// cannot deduce, a braced initializer list above all. Everything else, both
// lvalues and rvalues of T, already goes there. Taking this one by value
// would therefore add a move for exactly those callers while saving a copy
// for nobody.
// NOLINTNEXTLINE(modernize-pass-by-value)
// NOLINTNEXTLINE(modernize-pass-by-value)

@ax3l ax3l changed the title Tuple: explain why gpu_tuple_element takes T by const reference Tuple: Silence modernize-pass-by-value Aug 25, 2026
@ax3l ax3l added the warning label Aug 25, 2026
@ax3l
ax3l requested a review from WeiqunZhang August 25, 2026 21:04
@WeiqunZhang
WeiqunZhang merged commit 0642493 into AMReX-Codes:development Aug 26, 2026
75 checks passed
@ax3l
ax3l deleted the topic-tuple-pass-by-value branch September 2, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants