-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Tracking issue for making dbg!(x)
work in const fn
#58278
Comments
To the extend that |
|
So, does this proposal involve making |
(depending on the answer to @SimonSapin's question -- if the answer is "yes" then the following is moot): cc @eternaleye -- Do you think there's any problem wrt. soundness of |
Depends on how you're using it. Consider const fn foo(u: u32) -> u32 { dbg!(u * 2) } If you call that function in runtime code fn main() {
foo(42);
} you get a runtime print of but if you call that function in a const context type Foo = [u8; foo(42)]; then you get a compile-time print of the sort
|
@Centril Yeah, the usual framing of debug logging to make it pure is that it's a noop or identity function that happens to be a convenient thing for a debugger or runtime to instrument, along the lines of Here, |
@eternaleye Bummer, so I believe we have 3 options then?
|
My preference would be towards (2) where EDIT: To expand, the idea that a Even supposing that there was a theoretically correct way to have a |
I don't know what 3. is, but I think we should have The documentation of
and
It does not talk about how it actually ends up getting that information to stderr. The I'm imagining the following table as the four things we want to do, and they would be perfectly covered by just
As stated above, we already have such an effect, and an accepted RFC for it. I don't see how debugging is any different. I understand that there's a purity-theoretical point speaking against it, but purity of const fn is already not happening at runtime the moment you allow generic const fn with trait bounds. At run-time those trait bounds will not require const trait impls, so the actual trait impls can do anything they can at runtime without restrictions. |
The printing will either happen at compile-time (if you used the For no_std situations it's not an issue, because |
I don't think the issue is changing
There's no problem with panics from
Yes but you would require that when |
Can you elaborate on the non-determinism that you refer to? Is it about the |
Wait what? The RFC says nothing about allowing that...
That's not the issue for the reason you say.
When you say #[unstable(feature = "print_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "0")]
#[doc(hidden)]
#[cfg(not(test))]
pub fn _eprint(args: fmt::Arguments) {
print_to(args, &LOCAL_STDERR, stderr, "stderr");
}
/// Write `args` to output stream `local_s` if possible, `global_s`
/// otherwise. `label` identifies the stream in a panic message.
///
/// This function is used to print error messages, so it takes extra
/// care to avoid causing a panic when `local_stream` is unusable.
/// For instance, if the TLS key for the local stream is
/// already destroyed, or if the local stream is locked by another
/// thread, it will just fall back to the global stream.
///
/// However, if the actual I/O causes an error, this function does panic.
fn print_to<T>(
args: fmt::Arguments,
local_s: &'static LocalKey<RefCell<Option<Box<dyn Write+Send>>>>,
global_s: fn() -> T,
label: &str,
)
where
T: Write,
{
let result = local_s.try_with(|s| {
if let Ok(mut borrowed) = s.try_borrow_mut() {
if let Some(w) = borrowed.as_mut() {
return w.write_fmt(args);
}
}
global_s().write_fmt(args)
}).unwrap_or_else(|_| {
global_s().write_fmt(args)
});
if let Err(e) = result {
panic!("failed printing to {}: {}", label, e);
}
} Now someone may either overwrite |
As an example: trait Foo {
fn foo(&self);
}
struct A;
struct B;
impl const Foo for A {
fn foo(&self) {}
}
impl Foo for B {
fn foo(&self) {
// Open file handles and network handles and compute some random numbers
}
}
const fn bar<T: Foo>(t: &T) {
t.foo();
}
const X: () = bar(&B); // not legal
const Y: () = bar(&A); // legal
fn main() {
bar(&B); // legal
bar(&A); // legal
} You can extend this to
So the nondeterminism that can happen is that |
Oh that's fine... that's just the essence of effect polymorphism... However: const fn bar() { B.foo(); } // Nope. or with extensions: const fn bar<T: const Foo>(t: &T) { t.foo(); }
fn main() { bar(&B) } // Nope.
Yep; especially without involving any |
I hit this today! I wanted to debug a run-time call of a function that also happened to also be called at compile-time, and got an error message about function pointers not being allowed in In this case, having |
Implementing a nop- |
I'd love a dbg! that worked in no_std contexts as well (but perhaps that should have a different tracking issue...) |
Where would the output go? By definition a
|
I get that, but panic prints out to the screen in a no_std context so there's room for some quality of life special cases. If there's really no std out and I'm run inside a keyboard then I totally get that dbg!() can be a no-op (or could goto a hook that people provide like global alloc?), but if I'm running no_std tests for example it's kinda annoying that I have to import the log crate to print some debug. I'd like my no_std cake and be able to see lines of dbg too (where appropriate). no_std devs like nice things too. |
Does it really? To what screen? Or do you mean compile-time panics in If you do mean run-time panics, yes discussing that somewhere else would be more appropriate. We can’t add compile-time-only |
I guess rust’s test runner must add it’s own panic handler and that’s how
it writes to std out. If we had a dbg_handler fn then libtest could
implement that. But you’re right I can’t see that that would be relevant to
a const eval dbg().
…On Sun, 11 Jul 2021 at 13:33, Simon Sapin ***@***.***> wrote:
I get that, but panic prints out to the screen in a no_std context
Does it really? To what screen?
Or do you mean compile-time panics in const contexts? (Since that’s what
this issue is about.) Because for run-time panics, a no_std must define a
#[panic_handler] function
<https://doc.rust-lang.org/nomicon/panic-handler.html>. If there’s a
screen that you want panic info printed to, this handler is where you write
code to make it happen. There might or might not be a screen or serial port
or debugger, but the core crate can make no assumptions about how to talk
to them.
If you do mean run-time panics, yes discussing that somewhere else would
be more appropriate.
We can’t add compile-time-only no_std support for dbg! since a const fn
function can also be called with non-constant parameters at run-time.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#58278 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGEJCBCFAWWYXHHBGJHNWLTXGFSLANCNFSM4GVMBYLQ>
.
|
The Line 63 in e9a387d
So the test runner is not a |
Firstly thank you for your patience!
I think what I should be arguing for (assuming this isn’t already the case)
is for there to be a #[cfgif not(feature=“no_std”)] in the definition of
dbg! so that they don’t do anything if compiled in a no_std context but if
the code is compiled in a std context then they do the standard print.
But this relies on there being a std or no_std feature defined which alas
are not defined. (I would honestly love for std or no_std to be defined as
a feature- it would make things simpler).
…On Sun, 11 Jul 2021 at 17:41, Simon Sapin ***@***.***> wrote:
The test crate depends on std:
https://github.com/rust-lang/rust/blob/e9a387d6cf5961a7f2dcb671da3147bd413355c4/library/test/src/lib.rs#L63
So the test runner is not a no_std *application*, even if some of the
*crates* involved (like the one being tested) are no_std. If std is
anywhere in the dependency graph then its #[panic_handler]
<https://github.com/rust-lang/rust/blob/53cb7b09b00cbea8754ffb78e7e3cb521cb8af4b/library/std/src/panicking.rs#L441>
is used and you don’t need to (and can’t) define another one.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#58278 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGEJCCPE5VNWWVUFGAMIMTTXHCR3ANCNFSM4GVMBYLQ>
.
|
So, I thought of a way this could work and started writing up an RFC, but then realised that most of this is kind of out of my league since I don't know nearly as much about compiler internals. Essentially, the idea is we'd add separate
The definition of One big benefit of these is it'd help with tooling to let people search for explicit cases of debug printing without having to use the extra stuff printed by Could also help replace existing proposals like const FYI: () = {
if !cfg!(debug_assertions) {
dbgprintln!("This code is terrible and probably shouldn't be run in production.");
}
}; Like I said, I have absolutely not enough compiler internals knowledge to actually write an RFC for this, but would be willing to elaborate more on the specifics for anyone who does want to write an RFC. This feels like the only appropriate way to make |
We can't change macro expansion depending on whether we are in a const context or not. I'd also prefer to generate the same MIR in constcontexts and outside, as oyjeteise it gets very hard to do stability checking for const things (we may accidentally stabilize things or allow things that are semver hazards). |
Isn't that how panics work today, though? Or am I misunderstanding how panics are done? |
panics in CTFE use the same machinery as panics at runtime. CTFE just sees the panic functions and runs its own logic at that point. The panic functions are basically intrinsics |
(Tagging as "design concerns" only because it sounds like this still needs some design work, not just implementation work.) |
There's no reason that the internal Maybe we wouldn't want to hook |
We should make
dbg!(expr)
work inconst fn
by using somelang_item
that is on the body of a function that contains the contents ofdbg!(...)
. We also need to make it work with inlining.This sorta needs
impl const Debug
to work, but in the meantime we can just dump the miri state something something, @oli-obk can fill in...The text was updated successfully, but these errors were encountered: