Deprecate `pyo3::ffi::c_str!`
(Followup to #5531)
This is no longer needed on MSRV 1.83, as c"" literals are now available on all supported Rust versions.
I had a look at replacing current calls and for many uses within pyo3 itself, c"" literals can't be used because the the macro is being passed the output of a different macro (eg c_str!(file!())) or a token inside a macro expansion (eg c_str!($doc)). Would the aim to be replace these with the expansion of the c_str macro or to keep c_str around but make it internal only (most uses are in tests and macros)?
Hmm, that's a great question. I was imagining we would move the c_str! macro into our implementation details for those few cases.
But now I look at those cases, it seems somewhat reasonable for users to want this macro still for similar cases. Should we just keep it around? Maybe we can document examples of where it's a reasonable alternative to c"" literals, instead of mentioning MSRV in its doc.
(Aside, looking at the implementation, I think it currently implements a runtime panic rather than a const-eval failure if used in the wrong position, we might want to add a UI test to check that evaluating let x = c_str!("fo\0o") leads to a compile failure, and adjust the implementation accordingly?)
For let x = ... it's currently a runtime panic but a compile time error for const X = ... and static X = .... How would you cause it to be a compile time error for let?
Something like
macro_rules! c_str {
($s:expr) => {
const { $crate::_cstr_from_utf8_with_nul_checked(concat!($s, "\0")) }
};
}
works but feels a bit hacky and the error message isn't as good as it could be with a reference to main::{constant#0}
Compile error
error[E0080]: evaluation panicked: string contains nul bytes
--> src/main.rs:6:13
|
6 | let _ = c_str!("foo\0bar");
| ^^^^^^^^^^^^^^^^^^ evaluation of `main::{constant#0}` failed inside this call
|
note: inside `_cstr_from_utf8_with_nul_checked`
--> /tmp/pyo3/pyo3-ffi/src/lib.rs:382:19
|
382 | Err(_) => panic!("string contains nul bytes"),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the failure occurred here
note: erroneous constant encountered
--> src/main.rs:6:13
|
6 | let _ = c_str!("foo\0bar");
| ^^^^^^^^^^^^^^^^^^
|
= note: this note originates in the macro `c_str` (in Nightly builds, run with -Z macro-backtrace for more info)
Inlining the helper function improves it a bit but it still feels like there has to be a better way I'm not seeing.
Maybe something like this?
macro_rules! c_str {
($s:expr) => {{
const VALUE: &::std::ffi::CStr =
$crate::_cstr_from_utf8_with_nul_checked(concat!($s, "\0"));
VALUE
}};
}
leads to
error[E0080]: evaluation panicked: string contains nul bytes
--> pyo3-ffi/src/lib.rs:372:13
|
372 | $crate::_cstr_from_utf8_with_nul_checked(concat!($s, "\0"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `X::VALUE` failed inside this call
...
377 | const X: &std::ffi::CStr = c_str!("\0");
| ------------ in this macro invocation
which at least has X::VALUE as the name of the temporary constant.