Open oli-obk opened 5 years ago
This function can change its output between rustc compilations
Can the output change between compiling a library crate, and a binary crate using that library? Or only when switching rustc versions?
Can the output change between compiling a library crate, and a binary crate using that library?
No, we're using global paths now.
Or only when switching rustc versions?
Yes, there needs to be a change in rustc that causes a change in output.
I might take a look at this. (I implemented the support for using the actual type_name
intrinsic in const fn
contexts, if you don't remember me, haha.)
I think we definitely know it works at compile time though, don't we? That's what this test I added at the time checks for.
Sorry it took me a bit to get to this. Just opened a PR.
How does this break referential transparency? I'd like to see that elaborated upon.
I might be wrong, but I think the first "checkbox" can be checked since my PR was merged?
@lfairy:
Personally, I disagree, but some people seem to think that despite the fact Rust has fully reified generics, it's somehow a "dangerous" concept for your "average Joe/Jane" to be able to access the (100%-guaranteed-correct) name of a generic parameter.
Something about "Java programmers I used to work with did Some Bad Thing and I don't want Rust programmers to also do Some Bad Thing".
I don't know anything about Java though so I'm probably not overly qualified to get too much into that.
Hi, is there a stabilization issue for this const
-ification?
This is the tracking issue, so it will get closed on stabilization. I don't know what the next steps for stabilizing it are though. The discussion around referential transparency needs to be had (although with specialization it'd become obsolete, because then we'd get this feature anyway, but in a less convenient way). I think posting use cases would be very helpful for the discussion. Since this works with feature gates, you can always show a use case with nightly.
Hi, certainly I can write about a use case that I am working on!
I'm part of the Embedded WG where I am currently working on an instrumentation/logging tool for embedded targets. Here, as you probably know, we have strict requirements on code size as the micro controllers have very little memory. And a huge hog of memory is when strings are placed in memory.
To this end I place formating strings and (I want) type strings in an INFO
linker section so they are available in the ELF but not loaded onto the target. That is the following code as an example:
// test1 is some variable
mylog::log!("Look what I got: {}", &test1);
//
// Expands to:
//
const fn get_type_str<T>(_: &T) -> &'static str {
// type_name needs to be a const fn for this to work
core::any::type_name::<T>()
}
// ugly hack to tranform `&'static str` -> `[u8; str.len()]`
union Transmute<T: Copy, U: Copy> {
from: T,
to: U,
}
const FMT: &'static str = "Look what I got: {}";
const TYP: &'static str = get_type_str(&test1);
// Transform string into byte arrays at compile time so
// they can be placed in a specific memory region
// Formating string placed in a specific linker section
#[link_section = ".some_info_section"]
static F: [u8; FMT.as_bytes().len()] = unsafe {
*Transmute::<*const [u8; FMT.len()], &[u8; FMT.as_bytes().len()]> {
from: FMT.as_ptr() as *const [u8; FMT.as_bytes().len()],
}
.to
};
// Type string placed in a specific linker section
#[link_section = ".some_info_section"]
static T: [u8; TYP.as_bytes().len()] = unsafe {
*Transmute::<*const [u8; TYP.len()], &[u8; TYP.as_bytes().len()]> {
from: TYP.as_ptr() as *const [u8; TYP.as_bytes().len()],
}
.to
};
// Here we send where the strings are stored in the ELF + the data to the host
write_frame_to_host(&F, &T, &test1)
Link script:
SECTIONS {
.some_info_section (INFO) :
{
*(.some_info_section .some_info_section.*);
}
}
By doing this the strings are available in the generated ELF but not loaded onto the target, and the type can be reconstructed through DWARF with help of the type string.
And with complex types the space used for the type is getting very large for example any type that uses GenericArray
(which we use extensively).
Currently the string is placed in .rodata
which means that the compiler fully knows that this is a static string, and I made an issue on how to control where strings are placed which can use a trick outlined in here: https://github.com/rust-lang/rust/issues/70239
However this trick only works if the string is available in const context.
This is why I am asking about stabilization here.
I would also like to get this stabilized and can present a use-case.
I'm working on firestorm: a low overhead intrusive flame graph profiler. I created firestorm
because existing solutions have too much overhead to be useful for Tree-Buf: the self-describing serialization system that produces files smaller than GZip faster than uncompressed formats.
Part of keeping the overhead of firestorm
low is to delay string formatting/allocation until outside of the profiled region. So, there is an enum that allows for arbitrary amounts of &'static str
to be concatenated. In order to keep the amount of data writing to a minimum during the execution of the profiled region, we only write &'static EventData
so that EventData
can be large. Supporting concatenation of fn name and struct name for a method is only possible if type_name
is a const fn
.
TLDR: I need this to be const fn
for performance.
To elaborate here's code I would like to have be able to compile:
#[macro_export]
macro_rules! profile_method {
($($t:tt)*) => {
let _firestorm_method_guard = {
const FIRESTORM_STRUCT_NAME: &'static str = ::std::any::type_name::<Self>();
let event_data: &'static _ = &$crate::internal::EventData::Start(
$crate::internal::Start::Method {
signature: stringify!($($t)*),
typ: FIRESTORM_STRUCT_NAME,
}
);
$crate::internal::start(event_data);
$crate::internal::SpanGuard
};
};
}
It seems there are at least 2 problems here though. First, is that type_name
is not a const fn. The second is that the compiler complains about the use of Self
as the generic for the const fn. I do not really understand why that's a problem when each monomorphized function could have its own value here.
@That3Percent I don't think the Self
part is something that can be solved at present, even if we stabilize type_name
. You can test this out by using nightly and activating the feature gate for const_type_name
@oli-obk Yes, you are right. Both issues would need to be resolved to support my use-case in the way that I would like.
I found a bug with type_name
: type_name
works in array lengths of arrays used in associated consts, even if it is type_name::<Self>
. This doesn't even work for size_of
. The bug is that type_name
just returns _
in that case:
If you comment out the first panic, you get the correct type name.
I found a bug with type_name: type_name works in array lengths of arrays used in associated consts, even if it is type_name::
. This doesn't even work for size_of. The bug is that typename just returns in that case:
This seems to be fixed now?
Has there been any progress on the stabilization of type_name
?
Ping again on the status of stabilization?
type_id
(https://github.com/rust-lang/rust/issues/77125) has a bunch of issues which is why its stabilization actually got reverted; not sure if those issues also apply to type_name
.
Would you believe I clicked the wrong link in Rustdoc? Sorry.
Is there any outlook on stabilization/progress towards it?
There's a rendering bug and a soundness bug that we need to fix before we can stabilize. Both are linked from the main post
There's a rendering bug and a soundness bug that we need to fix before we can stabilize. Both are linked from the main post
The soundness bug seems to have been fixed by now, and all other linked issues also seem to be fixed, is there any particular roadblock remaining?
With the recent const {}
stabilization, this would prove very useful in static assertion messages.
Are there more known roadblocks to const fn type_name<T>()
?
This is a tracking issue for making and stabilizing
type_name
asconst fn
. It is not clear whether this is sound. Needs some T-lang discussion probably, too.Steps needed:
const
and#[rustc_const_unstable(feature = "const_type_name")
to the function and add tests showing that it works at compile-time.type_name
, too