-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cleanup clang tidy #882
base: main
Are you sure you want to change the base?
Cleanup clang tidy #882
Conversation
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
…um degree Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
@@ -93,7 +93,10 @@ concept is_in_list_c = (std::same_as<std::remove_const_t<T>, Ts> || ...); | |||
|
|||
// functor to include all | |||
struct IncludeAll { | |||
template <class... T> constexpr bool operator()(T&&... /*ignored*/) const { return true; } | |||
template <class... T> constexpr bool operator()(T&&... ignored) const { | |||
((void)std::forward<T>(ignored), ...); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here and below: the capture is correct: this should work on any type and zero-copy, regardless of whether it is a value, an lvalue or a prvalue. However, there is nothing to forward to, so it must be a (void)
sink
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you doing this instead of the original? Have a unnamed argument will not trigger an unused argument warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After re-thinking about it, the original implementation is not correct. We do not do anything with the argument so it does not make sense to make it universal reference. Just define as unnamed const lvalue reference and throw them away.
((void)std::forward<T>(ignored), ...); | |
template <class... T> constexpr bool operator()(T const&... /*ignored*/) const { return true; } |
current_value(i) = scalar * new_value(i); // can't forward due to runtime element access | ||
} | ||
(void)std::forward<Proxy>(current_value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
runtime access; can't move in the for
loop. Therefore, either the sink
is necessary, or it is required to use (symbolically) for (i : {0, 1}) current_value(i) = a(i); std::forward<Proxy>(current_value)(2) = a(2)
but that is way more unreadable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see #882 (comment)
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Signed-off-by: Martijn Govers <[email protected]>
Quality Gate passedIssues Measures |
@@ -530,6 +530,7 @@ class Topology { | |||
coupling[topo_comp_i] = Idx2D{topo_idx, new_math_comp_i}; | |||
} | |||
} | |||
(void)std::forward<GetMathTopoComponent>(get_component_topo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this happening?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function captures get_component_topo
by perfect forwarding. It is not allowed by the standard to not forward a forwarded argument, or move a moved argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #882 (comment).
The argument get_component_topo
should be passed by value as lambdas.
@@ -138,6 +138,7 @@ template <rk2_tensor Matrix> class DenseLUFactor { | |||
throw SparseMatrixError{}; // can not specify error code | |||
} | |||
} | |||
(void)std::move(matrix); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function captures matrix
by prvalue. It is not allowed by the standard to not move a moved argument, or forward a forwarded argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean not allowed by standard? I do not think standard forbid you to capture a rvalue
but not to forward or move them. It is just a (possibly false) warning from clang-tidy
right?
@@ -167,6 +167,7 @@ inline void calculate_load_gen_result(IdxRange const& load_gens, Idx bus_number, | |||
} | |||
output.load_gen[load_gen].i = conj(output.load_gen[load_gen].s / output.u[bus_number]); | |||
} | |||
(void)std::forward<LoadGenFunc>(load_gen_func); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function captures load_gen_func
by perfect forwarding. It is not allowed by the standard to not forward a forwarded argument, or move a moved argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the other for file common_solver_functions.hpp
, the root cause is we define the argument for the lambda as LoadGenFunc&& load_gen_func
, which is not correct.
Lambdas in function argument should be passed by value unless there is a strong reason of not to do.
If we change that to LoadGenFunc load_gen_func
. The stuff will go away.
@@ -191,6 +192,7 @@ inline void calculate_pf_result(YBus<sym> const& y_bus, PowerFlowInput<sym> cons | |||
calculate_load_gen_result<sym>(load_gens, bus_number, input, output, load_gen_func); | |||
calculate_source_result<sym>(sources, bus_number, y_bus, input, output, load_gens); | |||
} | |||
(void)std::forward<LoadGenFunc>(load_gen_func); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function captures load_gen_func
by perfect forwarding. It is not allowed by the standard to not forward a forwarded argument, or move a moved argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #882 (comment)
@@ -29,6 +29,7 @@ inline void iterate_component_sequence(Func&& func, ForwardIterator begin, Forwa | |||
// get component directly using sequence id | |||
func(*it, sequence_idx[seq]); | |||
} | |||
(void)std::forward<Func>(func); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this function captures func
by perfect forwarding. It is not allowed by the standard to not forward a forwarded argument, or move a moved argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here for #882 (comment).
func
should be defined as pass by value in the function argument.
@@ -281,7 +281,7 @@ inline void add_diag(Eigen::ArrayBase<DerivedA>& x, Eigen::ArrayBase<DerivedB> c | |||
} | |||
template <rk2_tensor DerivedA, column_vector DerivedB> | |||
inline void add_diag(Eigen::ArrayBase<DerivedA>&& x, Eigen::ArrayBase<DerivedB> const& y) { | |||
x.matrix().diagonal() += y.matrix(); | |||
std::move(x).matrix().diagonal() += y.matrix(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is very strange
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not a perfect forwarding because it contains Eigen::ArrayBase<DerivedA>
(a deduced type) instead of template A
directly. Therefore, it creates a view by value, which is then passed into this function as an rvalue and therefore, it has to be moved.
Alternatively, we can decide to not capture by &&
but by value, but I don't know whether that is how Eigen
works, I would need to dig into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now this (and other places) is indeed a nasty one. EIGEN
uses expression template extensively, which is basically a (temporary) proxy object.
For this function, we have a rvalue
overload because the caller can do something like:
add_diag(real(complex_tensor), diag_value);
Where real(complex_tensor)
returns a temporary rvalue
of EIGEN
expression template, so the other lvalue
overload will not work. This is what I call the third use-case of rvalue
reference in the function argument: move
, forward
, and capture temporary mutable proxy object. The clang-tidy
does not correctly recognize the third use-case of rvalue
reference and raises a false warning.
We can silence the warning locally. We can also choose to define a named variable in all the caller side, so
auto& real_value_proxy = real(complex_tensor);
add_diag(real_value_proxy , diag_value);
Then we just need the lvalue
overload for the function. This also applies to other parts.
@@ -351,13 +351,14 @@ template <symmetry_tag sym, class Proxy> | |||
inline void update_real_value(RealValue<sym> const& new_value, Proxy&& current_value, double scalar) { | |||
if constexpr (is_symmetric_v<sym>) { | |||
if (!is_nan(new_value)) { | |||
current_value = scalar * new_value; | |||
std::forward<Proxy>(current_value) = scalar * new_value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also this seems to be very strange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is how a perfectly forwarded proxy works: the current_value
is either taken by &
or by &&
or by value depending on what the type in caller is, and then here it is called as
std::forward<Proxy>.operator=(scalar * new_value);
which can be rewritten as std::forward<Proxy>(current_value) = scalar * new_value;
This deliberately consumes the current_value
in the case of forwarding on a prvalue.
If we do not want to do perfect forwarding, can you please explain why we went for this solution in the first place here? I do understand that this implementation creates a modifiable view of the 3-phase tensor by value, while taking mutable reference for other objects, but it this really the way that Eigen
wants us to do it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see #882 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgovers please look very critically for artificial void
, move
, and forward
.
I strongly object the idea to use those artificially just to get clang-tidy
happy. If we have a considered choice to ignore the warning, we should either silence it globally or locally, or use an unnamed argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgovers please look very critically for artificial void, move, and forward.
I strongly object the idea to use those artificially just to get clang-tidy happy. If we have a considered choice to ignore the warning, we should either silence it globally or locally, or use an unnamed argument.
on the eigen things, we should really have a look whether this is the correct way to capture views on Eigen matrices. On the function versions, the standard tells us that we should use the if we really need to we should silence the warning locally, but i'm very hesitant to disable it on a global level because it usually really is a bug to forget a forward or move |
To summarize, there are two major things here:
|
Ensures
clang-tidy
runs on Visual Studio 2022 latest version.Relates to #267 .
Note: I had to go from
std::ranges::copy(foo, std::back_inserter(bar));
tobar.insert(bar.end(), foo.begin(), foo.end());
due to llvm/llvm-project#120151 . I prefer to keep using the former but I first wanted to do a full build