Skip to content
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

<format>: std::format should work for volatile arguments #2443

Closed
wants to merge 8 commits into from

Conversation

fsb4000
Copy link
Contributor

@fsb4000 fsb4000 commented Dec 21, 2021

Fixes #2427

@fsb4000 fsb4000 requested a review from a team as a code owner December 21, 2021 17:49
@CaseyCarter CaseyCarter added the bug Something isn't working label Dec 29, 2021
@StephanTLavavej StephanTLavavej added the format C++20/23 format label Jan 12, 2022
@CaseyCarter
Copy link
Contributor

I'm concerned this is not correctly handling reads from volatile objects - it's casting away volatile and using memcpy to copy byte-by-byte which is usually the wrong thing to do. This needs some thought.

@fsb4000
Copy link
Contributor Author

fsb4000 commented Jan 26, 2022

I saw Charlie had changed _Phony_basic_format_arg_constructor so it works with volatily types now, but _Store_impl still uses memcpy so I think this pull request is still needed.

@barcharcraz
Copy link
Member

It's not clear what a pull request to fix this could do without kinda breaking the spirit of volatile

@fsb4000
Copy link
Contributor Author

fsb4000 commented Feb 8, 2022

I agree that this is a little sloppy now because I started this PR before your PR was merged: #2323 and then I delete part of my PR.

https://stackoverflow.com/a/36729638

memcpy may copy in any order, read parts of the source multiple times

So now, the PR tries to avoid read the volatile variable multiple times as @CaseyCarter noticed.

We just do a copy, and the compiler knows how to work with volatile variables so it will touch the variable only once and then we pass reference to copy and memcpy could read the copy multiple times in any parts order.

Also I decided to keep the regression test from issue 2427.

At least that's my intention in this PR.

Copy link
Member

@barcharcraz barcharcraz left a comment

Choose a reason for hiding this comment

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

This now looks like an improvement over the current situation. Let's do it.

@barcharcraz barcharcraz removed their assignment Feb 17, 2022
Comment on lines +1571 to +1580
if constexpr (is_volatile_v<_Ty>) {
// _Erased_type is not a volatile type, so static_cast<_Erased_type> would cast away volatile
// _Store_impl uses memcpy for storing the value. We cannot use memcpy with volatile types.
// Because of the two reasons we have to make a temporary
static_assert(!is_volatile_v<_Erased_type>);
const _Erased_type _Temp = _Val;
_Store_impl<_Erased_type>(_Arg_index, _Arg_type, _Temp);
} else {
_Store_impl<_Erased_type>(_Arg_index, _Arg_type, static_cast<_Erased_type>(_Val));
}
Copy link
Member

Choose a reason for hiding this comment

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

While video reviewing this, @barcharcraz and @CaseyCarter helped me understand the history of this code and what the Standard says. After looking at this, we believe that volatile int is required to be ill-formed by the Standard, according to https://eel.is/c++draft/format.arg#4 . Specifically,

typename Context::template formatter_type<remove_cvref_t<T>>()
  .format(declval<T&>(), declval<Context&>())

will pass declval<volatile int&>() to formatter_type<int>, and that will attempt to bind .format()'s parameter const int& to the lvalue argument of type volatile int, and that is not allowed.

@barcharcraz says that after #2323, the example in #2427 will be accepted (with a technically-undefined memcpying from volatile), but the Standard says we should reject this, so the code needs to be changed. I'm not immediately sure what the best change would be, but static_assert(!is_volatile_v<remove_reference_t<_Ty>>) (warning: not compiled, I just typed that out) might be a minimal fix. @barcharcraz and @CaseyCarter can help investigate.

Copy link
Contributor

Choose a reason for hiding this comment

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

While it doesn't require library-defined formatter specializations to do so, I think the wording may allow a program-defined formatter specialization to accept volatile arguments. The stripping of volatile in [format.arg]/17.2 suggests to me that the drafters probably just didn't care enough to allow or forbid volatile.

@fsb4000
Copy link
Contributor Author

fsb4000 commented Feb 18, 2022

right solution: #2579

@fsb4000 fsb4000 closed this Feb 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working format C++20/23 format
Projects
None yet
Development

Successfully merging this pull request may close these issues.

<format>: volatile integral<T> compilation error
4 participants