Skip to content

Commit 973ec11

Browse files
committed
Auto merge of #140592 - cuviper:beta-next, r=cuviper
[beta] backports - Don't allow flattened format_args in const. #139624 - set subsections_via_symbols for ld64 helper sections #139752 - Fix detection of `main` function if there are expressions around it #140220 - rustdoc: Fix doctest heuristic for main fn wrapping #140420 - extend the list of registered dylibs on `test::prepare_cargo_test` #140563 r? cuviper
2 parents 9d6fe3d + 260fcc6 commit 973ec11

16 files changed

+274
-62
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,12 @@ fn add_linked_symbol_object(
20112011
file.set_mangling(object::write::Mangling::None);
20122012
}
20132013

2014+
if file.format() == object::BinaryFormat::MachO {
2015+
// Divide up the sections into sub-sections via symbols for dead code stripping.
2016+
// Without this flag, unused `#[no_mangle]` or `#[used]` cannot be discard on MachO targets.
2017+
file.set_subsections_via_symbols();
2018+
}
2019+
20142020
// ld64 requires a relocation to load undefined symbols, see below.
20152021
// Not strictly needed if linking with lld, but might as well do it there too.
20162022
let ld64_section_helper = if file.format() == object::BinaryFormat::MachO {

library/core/src/fmt/rt.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,15 @@ impl Argument<'_> {
205205
/// let f = format_args!("{}", "a");
206206
/// println!("{f}");
207207
/// ```
208+
///
209+
/// This function should _not_ be const, to make sure we don't accept
210+
/// format_args!() and panic!() with arguments in const, even when not evaluated:
211+
///
212+
/// ```compile_fail,E0015
213+
/// const _: () = if false { panic!("a {}", "a") };
214+
/// ```
208215
#[inline]
209-
pub const fn none() -> [Self; 0] {
216+
pub fn none() -> [Self; 0] {
210217
[]
211218
}
212219
}

src/bootstrap/src/core/build_steps/test.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2570,9 +2570,9 @@ fn prepare_cargo_test(
25702570
// We skip everything on Miri as then this overwrites the libdir set up
25712571
// by `Cargo::new` and that actually makes things go wrong.
25722572
if builder.kind != Kind::Miri {
2573-
let mut dylib_path = dylib_path();
2574-
dylib_path.insert(0, PathBuf::from(&*builder.sysroot_target_libdir(compiler, target)));
2575-
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
2573+
let mut dylib_paths = builder.rustc_lib_paths(compiler);
2574+
dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, target)));
2575+
helpers::add_dylib_path(dylib_paths, &mut cargo);
25762576
}
25772577

25782578
if builder.remote_tested(target) {

src/librustdoc/doctest/make.rs

+38-30
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
301301

302302
let filename = FileName::anon_source_code(&wrapped_source);
303303

304-
// Any errors in parsing should also appear when the doctest is compiled for real, so just
305-
// send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
306304
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
307305
let fallback_bundle = rustc_errors::fallback_fluent_bundle(
308306
rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
@@ -311,7 +309,8 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
311309
info.supports_color =
312310
HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle.clone())
313311
.supports_color();
314-
312+
// Any errors in parsing should also appear when the doctest is compiled for real, so just
313+
// send all the errors that the parser emits directly into a `Sink` instead of stderr.
315314
let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
316315

317316
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
@@ -339,9 +338,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
339338
*prev_span_hi = hi;
340339
}
341340

342-
// Recurse through functions body. It is necessary because the doctest source code is
343-
// wrapped in a function to limit the number of AST errors. If we don't recurse into
344-
// functions, we would thing all top-level items (so basically nothing).
345341
fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) -> bool {
346342
let mut is_extern_crate = false;
347343
if !info.has_global_allocator
@@ -351,8 +347,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
351347
}
352348
match item.kind {
353349
ast::ItemKind::Fn(_) if !info.has_main_fn => {
354-
// We only push if it's the top item because otherwise, we would duplicate
355-
// its content since the top-level item was already added.
356350
if item.ident.name == sym::main {
357351
info.has_main_fn = true;
358352
}
@@ -411,37 +405,46 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
411405
push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi);
412406
}
413407
}
408+
let mut has_non_items = false;
414409
for stmt in &body.stmts {
415410
let mut is_extern_crate = false;
416411
match stmt.kind {
417412
StmtKind::Item(ref item) => {
418-
is_extern_crate = check_item(&item, &mut info, crate_name);
419-
}
420-
StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => {
421-
reset_error_count(&psess);
422-
return Err(());
413+
is_extern_crate = check_item(item, &mut info, crate_name);
423414
}
424-
StmtKind::MacCall(ref mac_call) if !info.has_main_fn => {
425-
let mut iter = mac_call.mac.args.tokens.iter();
426-
427-
while let Some(token) = iter.next() {
428-
if let TokenTree::Token(token, _) = token
429-
&& let TokenKind::Ident(name, _) = token.kind
430-
&& name == kw::Fn
431-
&& let Some(TokenTree::Token(fn_token, _)) = iter.peek()
432-
&& let TokenKind::Ident(fn_name, _) = fn_token.kind
433-
&& fn_name == sym::main
434-
&& let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = {
435-
iter.next();
436-
iter.peek()
415+
// We assume that the macro calls will expand to item(s) even though they could
416+
// expand to statements and expressions.
417+
StmtKind::MacCall(ref mac_call) => {
418+
if !info.has_main_fn {
419+
// For backward compatibility, we look for the token sequence `fn main(…)`
420+
// in the macro input (!) to crudely detect main functions "masked by a
421+
// wrapper macro". For the record, this is a horrible heuristic!
422+
// See <https://github.com/rust-lang/rust/issues/56898>.
423+
let mut iter = mac_call.mac.args.tokens.iter();
424+
while let Some(token) = iter.next() {
425+
if let TokenTree::Token(token, _) = token
426+
&& let TokenKind::Ident(kw::Fn, _) = token.kind
427+
&& let Some(TokenTree::Token(ident, _)) = iter.peek()
428+
&& let TokenKind::Ident(sym::main, _) = ident.kind
429+
&& let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, _)) = {
430+
iter.next();
431+
iter.peek()
432+
}
433+
{
434+
info.has_main_fn = true;
435+
break;
437436
}
438-
{
439-
info.has_main_fn = true;
440-
break;
441437
}
442438
}
443439
}
444-
_ => {}
440+
StmtKind::Expr(ref expr) => {
441+
if matches!(expr.kind, ast::ExprKind::Err(_)) {
442+
reset_error_count(&psess);
443+
return Err(());
444+
}
445+
has_non_items = true;
446+
}
447+
StmtKind::Let(_) | StmtKind::Semi(_) | StmtKind::Empty => has_non_items = true,
445448
}
446449

447450
// Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to
@@ -466,6 +469,11 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
466469
push_to_s(&mut info.crates, source, span, &mut prev_span_hi);
467470
}
468471
}
472+
if has_non_items {
473+
// FIXME: if `info.has_main_fn` is `true`, emit a warning here to mention that
474+
// this code will not be called.
475+
info.has_main_fn = false;
476+
}
469477
Ok(info)
470478
}
471479
Err(e) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fn item() {}

tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
//@ compile-flags:--test
55
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
66
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
7-
//@ failure-status: 101
7+
//@ check-pass
88

99
/// <https://github.com/rust-lang/rust/issues/91014>
1010
///
1111
/// ```rust
12-
/// struct S {}; // unexpected semicolon after struct def
12+
/// struct S {};
1313
///
1414
/// fn main() {
1515
/// assert_eq!(0, 1);
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,6 @@
11

22
running 1 test
3-
test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... FAILED
3+
test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... ok
44

5-
failures:
6-
7-
---- $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) stdout ----
8-
error: expected item, found `;`
9-
--> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12
10-
|
11-
LL | struct S {}; // unexpected semicolon after struct def
12-
| ^
13-
|
14-
= help: braced struct declarations are not followed by a semicolon
15-
help: remove this semicolon
16-
|
17-
LL - struct S {}; // unexpected semicolon after struct def
18-
LL + struct S {} // unexpected semicolon after struct def
19-
|
20-
21-
error: aborting due to 1 previous error
22-
23-
Couldn't compile the test.
24-
25-
failures:
26-
$DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11)
27-
28-
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
5+
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
296

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
running 4 tests
3+
test $DIR/main-alongside-macro-calls.rs - (line 19) ... ok
4+
test $DIR/main-alongside-macro-calls.rs - (line 24) ... ok
5+
test $DIR/main-alongside-macro-calls.rs - (line 28) ... FAILED
6+
test $DIR/main-alongside-macro-calls.rs - (line 33) ... FAILED
7+
8+
failures:
9+
10+
---- $DIR/main-alongside-macro-calls.rs - (line 28) stdout ----
11+
error: macros that expand to items must be delimited with braces or followed by a semicolon
12+
--> $DIR/main-alongside-macro-calls.rs:30:1
13+
|
14+
LL | println!();
15+
| ^^^^^^^^^^
16+
|
17+
= note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
18+
19+
error: macro expansion ignores `{` and any tokens following
20+
--> $SRC_DIR/std/src/macros.rs:LL:COL
21+
|
22+
::: $DIR/main-alongside-macro-calls.rs:30:1
23+
|
24+
LL | println!();
25+
| ---------- caused by the macro expansion here
26+
|
27+
= note: the usage of `print!` is likely invalid in item context
28+
29+
error: aborting due to 2 previous errors
30+
31+
Couldn't compile the test.
32+
---- $DIR/main-alongside-macro-calls.rs - (line 33) stdout ----
33+
error: macros that expand to items must be delimited with braces or followed by a semicolon
34+
--> $DIR/main-alongside-macro-calls.rs:34:1
35+
|
36+
LL | println!();
37+
| ^^^^^^^^^^
38+
|
39+
= note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
40+
41+
error: macro expansion ignores `{` and any tokens following
42+
--> $SRC_DIR/std/src/macros.rs:LL:COL
43+
|
44+
::: $DIR/main-alongside-macro-calls.rs:34:1
45+
|
46+
LL | println!();
47+
| ---------- caused by the macro expansion here
48+
|
49+
= note: the usage of `print!` is likely invalid in item context
50+
51+
error: aborting due to 2 previous errors
52+
53+
Couldn't compile the test.
54+
55+
failures:
56+
$DIR/main-alongside-macro-calls.rs - (line 28)
57+
$DIR/main-alongside-macro-calls.rs - (line 33)
58+
59+
test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
60+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
running 4 tests
3+
test $DIR/main-alongside-macro-calls.rs - (line 19) ... ok
4+
test $DIR/main-alongside-macro-calls.rs - (line 24) ... ok
5+
test $DIR/main-alongside-macro-calls.rs - (line 28) - compile fail ... ok
6+
test $DIR/main-alongside-macro-calls.rs - (line 33) - compile fail ... ok
7+
8+
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
9+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// This test ensures that if there is are any macro calls alongside a `main` function,
2+
// it will indeed consider the `main` function as the program entry point and *won't*
3+
// generate its own `main` function to wrap everything even though macro calls are
4+
// valid in statement contexts, too, and could just as well expand to statements or
5+
// expressions (we don't perform any macro expansion to find `main`, see also
6+
// <https://github.com/rust-lang/rust/issues/57415>).
7+
//
8+
// See <./main-alongside-stmts.rs> for comparison.
9+
//
10+
//@ compile-flags:--test --test-args --test-threads=1
11+
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
12+
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
13+
//@ revisions: pass fail
14+
//@[pass] check-pass
15+
//@[fail] failure-status: 101
16+
17+
// Regression test for <https://github.com/rust-lang/rust/pull/140220#issuecomment-2831872920>:
18+
19+
//! ```
20+
//! fn main() {}
21+
//! include!("./auxiliary/items.rs");
22+
//! ```
23+
//!
24+
//! ```
25+
//! include!("./auxiliary/items.rs");
26+
//! fn main() {}
27+
//! ```
28+
29+
// Regression test for <https://github.com/rust-lang/rust/issues/140412>:
30+
// We test the "same" thing twice: Once via `compile_fail` to more closely mirror the reported
31+
// regression and once without it to make sure that it leads to the expected rustc errors,
32+
// namely `println!(…)` not being valid in item contexts.
33+
34+
#![cfg_attr(pass, doc = " ```compile_fail")]
35+
#![cfg_attr(fail, doc = " ```")]
36+
//! fn main() {}
37+
//! println!();
38+
//! ```
39+
//!
40+
#![cfg_attr(pass, doc = " ```compile_fail")]
41+
#![cfg_attr(fail, doc = " ```")]
42+
//! println!();
43+
//! fn main() {}
44+
//! ```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// This test ensures that if there is are any statements alongside a `main` function,
2+
// it will not consider the `main` function as the program entry point but instead
3+
// will generate its own `main` function to wrap everything as it needs to reside in a
4+
// module where only *items* are permitted syntactically.
5+
//
6+
// See <./main-alongside-macro-calls.rs> for comparison.
7+
//
8+
// This is a regression test for:
9+
// * <https://github.com/rust-lang/rust/issues/140162>
10+
// * <https://github.com/rust-lang/rust/issues/139651>
11+
//
12+
//@ compile-flags:--test --test-args --test-threads=1
13+
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
14+
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
15+
//@ check-pass
16+
17+
//! ```
18+
//! # if cfg!(miri) { return; }
19+
//! use std::ops::Deref;
20+
//!
21+
//! fn main() {
22+
//! assert!(false);
23+
//! }
24+
//! ```
25+
//!
26+
//! ```
27+
//! let x = 2;
28+
//! assert_eq!(x, 2);
29+
//!
30+
//! fn main() {
31+
//! assert!(false);
32+
//! }
33+
//! ```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
running 2 tests
3+
test $DIR/main-alongside-stmts.rs - (line 17) ... ok
4+
test $DIR/main-alongside-stmts.rs - (line 26) ... ok
5+
6+
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
7+

tests/ui/consts/const-eval/format.rs

+5
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,9 @@ const fn print() {
99
//~| ERROR cannot call non-const function `_print` in constant functions
1010
}
1111

12+
const fn format_args() {
13+
format_args!("{}", 0);
14+
//~^ ERROR cannot call non-const formatting macro in constant functions
15+
}
16+
1217
fn main() {}

tests/ui/consts/const-eval/format.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ LL | println!("{:?}", 0);
2424
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
2525
= note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
2626

27-
error: aborting due to 3 previous errors
27+
error[E0015]: cannot call non-const formatting macro in constant functions
28+
--> $DIR/format.rs:13:5
29+
|
30+
LL | format_args!("{}", 0);
31+
| ^^^^^^^^^^^^^^^^^^^^^
32+
|
33+
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
34+
35+
error: aborting due to 4 previous errors
2836

2937
For more information about this error, try `rustc --explain E0015`.

0 commit comments

Comments
 (0)