-
Notifications
You must be signed in to change notification settings - Fork 258
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
[SUGGESTION] Improve in
parameter passing (restore old behavior, exclude problem cases only)
#666
Comments
Here's an example with the
Here's an example that should continue using a version of
|
in
optimization for class typesin
parameter passing (restore old behavior, exclude problem cases only)
The pedantic condition is cppfront/regression-tests/pure2-bugfix-for-non-local-function-expression.cpp2 Lines 5 to 7 in a92fdc8
|
Here's my proposed version of a template<class T, bool V = (requires { sizeof(T); })> constexpr bool is_complete{V};
template<typename T>
constexpr bool prefer_pass_by_value_optimized =
sizeof(T) <= 2*sizeof(void*)
&& std::is_trivially_copy_constructible_v<T>;
template<typename T>
requires std::is_array_v<T> || std::is_function_v<T>
constexpr bool prefer_pass_by_value_optimized<T> = false;
template<typename T>
requires is_complete<T>
using in_optimized =
std::conditional_t <
prefer_pass_by_value_optimized<T>,
T const,
T const&
>; Compared to
|
This can still result in a missed optimization due to a false positive.
The truth is that |
Afterwards, |
This might not be true anymore given that Working around such an issue might be another use case for |
AFAIK, optimizing shouldn't be a problem in modules. |
Let me clarify. Compiling an Why `in` parameters can generally be optimized in Cpp2 (from the opening comment):
This is because users can consume the interface without completing its types. However, we can still optimize
|
You can replace
So perhaps only pure Cpp2 |
There's been many changes since this issue was opened. -template<typename T>
-constexpr bool prefer_pass_by_value =
- sizeof(T) <= 2*sizeof(void*)
- && std::is_trivially_copy_constructible_v<T>;
-
-template<typename T>
- requires std::is_class_v<T> || std::is_union_v<T> || std::is_array_v<T> || std::is_function_v<T>
-constexpr bool prefer_pass_by_value<T> = false;
+template<class T, bool V = (requires { sizeof(T); })> constexpr bool is_complete{V};
+
+template<typename T>
+constexpr bool prefer_pass_by_value() {
+ if constexpr (std::is_array_v<T> || std::is_function_v<T>) {
+ return false;
+ } else {
+ static_assert(is_complete<T>, "an 'in' parameter must be a complete type - use 'in_ref' instead");
+ return sizeof(T) <= 2*sizeof(void*)
+ && std::is_trivially_copy_constructible_v<T>;
+ }
+}
template<typename T>
requires (!std::is_void_v<T>)
using in =
std::conditional_t <
- prefer_pass_by_value<T>,
+ prefer_pass_by_value<T>(),
T const,
T const&
>; |
@JohelEGP How does this not result in ODR violations because whether or not a type is complete is not a property of the type but whether or not you've seen the full definition or just a forward declaration? |
If ODR is an issue despite the +template<class T, bool V = (requires { sizeof(T); })> constexpr bool is_complete{V};
+
+template<typename T, bool IsComplete = is_complete<T>>
+constexpr bool assert_valid_in_type() {
+ static_assert(!std::is_void_v<T>, "a parameter type can't be 'void'");
+ static_assert(!std::is_void_v<T> && IsComplete, "an 'in' parameter must be a complete type - use 'in_ref' instead");
+ return !std::is_void_v<T> && IsComplete;
+}
+
template<typename T>
constexpr bool prefer_pass_by_value =
sizeof(T) <= 2*sizeof(void*)
&& std::is_trivially_copy_constructible_v<T>;
template<typename T>
- requires std::is_class_v<T> || std::is_union_v<T> || std::is_array_v<T> || std::is_function_v<T>
+ requires std::is_array_v<T> || std::is_function_v<T>
constexpr bool prefer_pass_by_value<T> = false;
template<typename T>
- requires (!std::is_void_v<T>)
+ requires assert_valid_in_type<T>()
using in =
std::conditional_t <
prefer_pass_by_value<T>,
T const,
T const&
>; |
Okay, so with this change:
Because f will fail to compile when it's incomplete, there is no possibility of an ODR violation. |
This is the case I'm referring to with the TU 1:
TU 2:
That gives I was thinking it made an actual
That won't happen with the later change, the TU 2 would just be an error. |
My latest suggestion makes the |
Yes, that's exactly what I'm saying. |
Restore
in
optimization for class typesAt first,
in
parameters were optimized for class types.Cppfront's optimization of
in
parameters was faithful toF.16: For “in” parameters, pass cheaply-copied types by value and others by reference to
const
.Then, #270 brought to light that the optimization didn't play well with Cpp2's order independence.
After #317, the net effect is that Cppfront never optimizes
in
parameters of class type.I still lament the fact that we lost this optimization to Cpp2 itself.
Similar to #317, here I propose to "improve
in
parameter passing (restore old behavior, exclude problem cases only)".#270 (comment) describes the general problem.
However, it generally doesn't apply to Cpp2.
Cpp2 generally requires parameters of complete type.
That's because most functions are initialized and will have a Cpp1 definition emitted.
So we can generally try to optimize
in
parameters of class types to pass-by-value.I'd love to have this optimization restored for the general case.
The conditions when applying
cpp2::in
is wrong are two only (AFAIK).in
argument passing to function that uses cpp2 user defined type failed with error #270.In the current source order,
it only applies to parameters of type that come later in source order.
An uninitialized
virtual this
function can have parameters of incomplete type.When declaring an
override this
orfinal this
function in a different TU,we can't know if its
in
parameters of class type had opted-into the optimization with the current Cppfront.I propose that we identify these conditions,
and only when at least one of these conditions is true,
do we continue emit a version of
cpp2::in
that doesn't optimize class types.Otherwise, we should emit a version of
cpp2::in
that does try to optimize class types.Identified problems:
This is evident with function types (e.g., see feat: support function types #526 (comment)).
With this suggestion, the effect would, once again, extend to optimized class types.
to determine that a parameter's type indeed names a type that shouldn't be optimized.
References:
in
argument passing to function that uses cpp2 user defined type failed with error #270.in
argument passing to function that uses cpp2 user defined type failed with error #270 (comment).cpp2::in
(restore old behavior, exclude problem cases only) #317.Related links:
Will your feature suggestion eliminate X% of security vulnerabilities of a given kind in current C++ code?
No.
Will your feature suggestion automate or eliminate X% of current C++ guidance literature?
Yes.
F.16: For “in” parameters, pass cheaply-copied types by value and others by reference to
const
.Describe alternatives you've considered.
None.
The text was updated successfully, but these errors were encountered: