Skip to content

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented Jul 13, 2025

Fixes #143009.
Fixes #143858.

Since it includes fixes from #143453, it's taking it over (commits 2, 3 and 4 are from #143453).

For --no-run, we forgot to check the "global" options in the 2024 edition, fixed in the first commit.

For should_panic fix, the exit code check has been fixed.

cc @TroyKomodo (thanks so much for providing such a complete test, made my life a lot easier!)
r? @notriddle

@rustbot rustbot added A-run-make Area: port run-make Makefiles to rmake.rs S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. labels Jul 13, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jul 13, 2025

This PR modifies run-make tests.

cc @jieyouxu

@rustbot

This comment has been minimized.

@purplesyringa
Copy link
Contributor

For should_panic fix, instead of checking the exit code, we directly wrap the doctest code with catch_unwind and if a panic happened, then we return success for the test, otherwise we display the appropriate error message.

I... do not see anything like that in the patch? There's two checks for exit code 101.

@GuillaumeGomez
Copy link
Member Author

GuillaumeGomez commented Jul 14, 2025

Woups, copied/pasted comment from original PR which was outdated after discussion with you (on the previous PR). ^^'

EDIT: Updated comment.

@purplesyringa
Copy link
Contributor

purplesyringa commented Jul 14, 2025

if langstr.should_panic {
    if out.status.code() == Some(101) {
        return Ok(());
    } else if out.status.success() {
        return Err(TestFailure::UnexpectedRunPass);
    }
}
if !out.status.success() {
    return Err(TestFailure::ExecutionFailure(out));
}

Do you think something like this would make sense, so that it's easier for the user to differentiate between aborts and panic-less success?

@GuillaumeGomez
Copy link
Member Author

TestFailure::UnexpectedRunPass displays "Test didn't panic, but it's marked `should_panic`.", which means we'd need to add a new case. Do you think it's necessary to differentiate between success and non-panic failures?

@purplesyringa
Copy link
Contributor

purplesyringa commented Jul 14, 2025

Wouldn't changing UnexpectedRunPass to spell "Test executable succeeded, but it's marked should_panic." (i.e. rolling back the change in this PR) work? After all, if the change was to let UnexpectedRunPass represent non-panicking failures, it won't be necessary if we just use ExecutionFailure for that.

@GuillaumeGomez
Copy link
Member Author

That wouldn't cover exit(1) anymore if we did so.

@purplesyringa
Copy link
Contributor

I've amended my comment a moment before you replied, apologies.

@GuillaumeGomez
Copy link
Member Author

GuillaumeGomez commented Jul 14, 2025

Replied too fast then. 😅

The message for ExecutionFailure is too general imo ("Test executable failed"). It doesn't help to understand should_panic didn't panic. I think once this PR is merged, you can send a new one to create a new variant in case it failed but didn't panic, like that we can have a message that is covering this case. What do you think?

@purplesyringa
Copy link
Contributor

purplesyringa commented Jul 14, 2025

The message for ExecutionFailure is too general imo ("Test executable failed"). It doesn't help to understand should_panic didn't panic.

I think we're talking past each other. I suggest that:

  • If the program didn't panic and exited with code 0, we keep using UnexpectedRunPass ("test didn't panic"). This is the main use case for should_panic and has a perfectly legible description.
  • If the program didn't panic and exited with a non-zero code, we use ExecutionFailure ("executable failed"). I believe that it's highly unlikely this failure mode of a should_panic test can be attributed to anything but UB or an abort, exactly like with non-should_panic tests, so I don't think it's necessary to specify that it's happened in a should_panic test specifically.

Wouldn't that work?

@GuillaumeGomez
Copy link
Member Author

I still think it's too general. For end users, should_panic means the execution is supposed to fail. However it might be confusing to get "executable failed" when it's exactly what's expected (well, except it was expecting a panic and it's different). Hence why I think the current message is better and why, if we go down this road, we should add a new case to handle this case instead of relying on the too generated ExecutionFailure.

@purplesyringa
Copy link
Contributor

That makes sense, yeah. Let's delay it until after this PR lands then.

@bors
Copy link
Collaborator

bors commented Jul 30, 2025

☔ The latest upstream changes (presumably #144692) made this pull request unmergeable. Please resolve the merge conflicts.

@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rustbot

This comment has been minimized.

samueltardieu added a commit to samueltardieu/rust that referenced this pull request Jul 31, 2025
…Amanieu

Make `libtest::ERROR_EXIT_CODE` const public to not redefine it in rustdoc

I think it's better to make this constant public so it can be used by crates using `libtest` as dependency.

As a side-note, I will update rust-lang#143900 to make use of this constant once this is current PR is merged.
@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Oct 7, 2025
@Zalathar
Copy link
Contributor

Zalathar commented Oct 7, 2025

@bors try jobs=x86_64-gnu-aux

rust-bors bot added a commit that referenced this pull request Oct 7, 2025
[rustdoc] Correctly handle `should_panic` doctest attribute and fix `--no-run` test flag on the 2024 edition

try-job: x86_64-gnu-aux
@rust-bors

This comment has been minimized.

@rust-bors
Copy link

rust-bors bot commented Oct 7, 2025

💔 Test for 75572d4 failed: CI. Failed jobs:

@GuillaumeGomez
Copy link
Member Author

Ah, this time a cargo test failed. Checking what's wrong.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez
Copy link
Member Author

@bors try jobs=x86_64-gnu-aux,test-various

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Oct 7, 2025
[rustdoc] Correctly handle `should_panic` doctest attribute and fix `--no-run` test flag on the 2024 edition

try-job: x86_64-gnu-aux
try-job: test-various
@rust-log-analyzer

This comment has been minimized.

@rust-bors
Copy link

rust-bors bot commented Oct 7, 2025

☀️ Try build successful (CI)
Build commit: 1514cdd (1514cddf55f57c7a67702bced791e2db666e031f, parent: 4a54b26d30dac43778afb0e503524b763fce0eee)

@GuillaumeGomez
Copy link
Member Author

This failure definitely illustrates why I should finish writing the lint in case the merged doctests failed compilation...

@GuillaumeGomez
Copy link
Member Author

@bors try jobs=x86_64-gnu-aux,test-various

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Oct 7, 2025
[rustdoc] Correctly handle `should_panic` doctest attribute and fix `--no-run` test flag on the 2024 edition

try-job: x86_64-gnu-aux
try-job: test-various
@rust-bors
Copy link

rust-bors bot commented Oct 7, 2025

☀️ Try build successful (CI)
Build commit: 7c0af15 (7c0af154b8a6f0d2bb19a467cc9916ce269f3613, parent: 4a54b26d30dac43778afb0e503524b763fce0eee)

Copy link
Member

@fmease fmease left a comment

Choose a reason for hiding this comment

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

Some suggestions and questions. As requested, feel free to r=me once they're all addressed in one way or another.

Although, I've got to admit that I feel slightly uneasy about some of these changes or rather the fact that this will ship "insta-stably". Anyhow, it's probably fine.

View changes since this review

Copy link
Member

Choose a reason for hiding this comment

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

Could you at least consolidate b001ba6 and 030b664?

Copy link
Member

Choose a reason for hiding this comment

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

While your PR is technically only fixing bugs, at least the should_panic changes are actually breaking changes (rustdoc never performed these checks before) as can be seen by the modifications that you had to do to the standard library.

Because of that I've now added relnotes, so users will at least kind of get to know what's up when their doctests "break" which will inevitably happen (I still don't know what the stability policies / guarantees are for rustdoc ^^' they seem to be laxer compared to the language ones).

&& (arch.starts_with("wasm") || os == Some("zkvm")) && os != Some("emscripten")
{
// We cannot correctly handle `should_panic` in some wasm targets so we exit early.
return (duration, Ok(()));
Copy link
Member

Choose a reason for hiding this comment

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

So this marks them as OK? Wouldn't it be more ideal to mark them as ignored (somehow)? Does that make any sense? I didn't have the time to refamiliarize myself with these parts of the doctest impl.

Copy link
Member Author

Choose a reason for hiding this comment

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

They are compiled, so it's not ignore but no_run instead. And just like libtest, no_run are not marked.

// (cfg!(target_family = "wasm") || cfg!(target_os = "zkvm"))
// && !cfg!(target_os = "emscripten")
// ```
&& let TargetTuple::TargetTuple(ref s) = rustdoc_options.target
Copy link
Member

@fmease fmease Oct 8, 2025

Choose a reason for hiding this comment

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

We both know that this check is super brittle and icky :D We can ignore that for now I guess ^^'

Okay, so I'm not super familiar with target specifications but ideally this would also handle TargetJson, right? The user may pass --target=custom.json which may specify the panic_strategy (IIUC if that's set to Some(Abort | ImmediateAbort) then that implies that unwinding panics are not supported?) as well as target_family and so on.

If what I write makes sense, could you at least leave a FIXME that we should somehow support TargetJson here, too?

Ideally, we would use some preexisting compiler API for querying this (one that provides a richer representation of the target), maybe there is one we could use?

Copy link
Member Author

Choose a reason for hiding this comment

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

We both know that this check is super brittle and icky :D We can ignore that for now I guess ^^'

Yes. T_T

Okay, so I'm not super familiar with target specifications but ideally this would also handle TargetJson, right? The user may pass --target=custom.json which may specify the panic_strategy (IIUC if that's set to Some(Abort | ImmediateAbort) then that implies that unwinding panics are not supported?) as well as target_family and so on.

If what I write makes sense, could you at least leave a FIXME that we should somehow support TargetJson here, too?

Yeah you're right, adding a FIXME.

Ideally, we would use some preexisting compiler API for querying this (one that provides a richer representation of the target), maybe there is one we could use?

Hopefully yes. I'll take time to investigate how to make this all clean afterwards. Adding FIXME comments.

// `ZX_TASK_RETCODE_EXCEPTION_KILL`.
#[cfg(target_os = "fuchsia")]
Some(ZX_TASK_RETCODE_EXCEPTION_KILL) => {}
_ => return (duration, Err(TestFailure::UnexpectedRunPass)),
Copy link
Member

Choose a reason for hiding this comment

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

Could you rename the variant UnexpectedRunPass to something more appropriate now that it's no longer only used for successful exits but also for "non-panicking" ones?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah good idea.

}
TestFailure::UnexpectedRunPass => {
eprint!("Test executable succeeded, but it's marked `should_panic`.");
eprint!("Test didn't panic, but it's marked `should_panic`.");
Copy link
Member

Choose a reason for hiding this comment

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

It might be worthwhile to print the actual exit code / signal here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea, adding a regression test as well.

Comment on lines 875 to 879
Some(test::ERROR_EXIT_CODE) => {}
#[cfg(windows)]
Some(STATUS_FAIL_FAST_EXCEPTION) => {}
#[cfg(unix)]
None if out.status.signal() == Some(SIGABRT) => {}
Copy link
Member

@fmease fmease Oct 8, 2025

Choose a reason for hiding this comment

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

I know that you've copied this from libtest since you've told me but I'm a bit unsure about accepting aborts unconditionally even if -Cpanic=unwind.

I wondering if it would be more correct to only accept these (SIGABRT, …) if -Cpanic=abort. Similarly, I'm wondering if under -Cpanic=abort an exit code of 101 would not be deemed acceptable for should_panic.

It's 3AM for me, so I can't really judge this right now. I'm just a bit uncomfortable with the idea of immediately shipping these changes given that the scope of this "bug fix" PR has grown in scope. It feels like there are open design questions, I could be wrong tho and I don't want to block this on an FCP.

Copy link
Member

@fmease fmease Oct 8, 2025

Choose a reason for hiding this comment

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

E.g., in the following examples, all tests pass IINM:

//@ compile-flags: --test -Cpanic=unwind

//! ```should_panic
//! std::process::abort();
//! ```
//@ compile-flags: --test -Cpanic=abort

//! ```should_panic
//! std::process::exit(101);
//! ```

Should they? Feels kinda weird to me tbh but maybe I'm the only one.

Should we document any of these details in the rustdoc book?

Copy link
Member

Choose a reason for hiding this comment

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

To be transparent, I don't know how libtest's --test -Cpanic=abort -Zpanic_abort_tests works under the hood & is supposed to work. It seems to be able to detect aborting panic!()s but also recognize that std::process::abort() is not a panic! No clue how it does that, I have no time to investigate rn.

Copy link
Member Author

Choose a reason for hiding this comment

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

I plan to use libtest directly after this PR is merged because this is a mess currently. ^^'

let duration = instant.elapsed();
if doctest.no_run {
return (duration, Ok(()));
} else if doctest.langstr.should_panic
Copy link
Member

@fmease fmease Oct 8, 2025

Choose a reason for hiding this comment

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

Should we leave a FIXME somewhere that we (probably) don't handle -Cpanic=immediate-abort correctly (very recently added)?

Maybe we do already? As I've PM'ed you, on master I actually get illegal instruction for panics under this new strategy and I don't know if that's intentional or not.

Copy link
Contributor

@lolbinarycat lolbinarycat Oct 8, 2025

Choose a reason for hiding this comment

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

I believe that's due to llvm lowering core::intrinsics::abort to ub2 which gets translated to an illegal instruction

#81895

@GuillaumeGomez
Copy link
Member Author

Let's go again then!

@bors r=fmease

@bors
Copy link
Collaborator

bors commented Oct 8, 2025

📌 Commit 6060bcc has been approved by fmease

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-run-make Area: port run-make Makefiles to rmake.rs relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rustdoc --no-run runs when --edition=2024 is provided should_panic in doctests accepts crashes, aborts, std::process::exit