diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 72c4492d465d8..72fd56fb5bd71 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -500,7 +500,7 @@ # building without optimizations takes much longer than optimizing. Further, some platforms # fail to build without this optimization (c.f. #65352). # The valid options are: -# true - Enable optimizations. +# true - Enable optimizations (same as 3). # false - Disable optimizations. # 0 - Disable optimizations. # 1 - Basic optimizations. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 5c8c51c8bbcc2..0ceda2201344e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -1,7 +1,7 @@ #![allow(rustc::bad_opt_access)] -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use std::num::NonZero; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::atomic::AtomicBool; use rustc_abi::Align; @@ -89,8 +89,8 @@ where S: Into, I: IntoIterator, { - let locations: BTreeSet = - locations.into_iter().map(|s| CanonicalizedPath::new(Path::new(&s.into()))).collect(); + let locations = + locations.into_iter().map(|s| CanonicalizedPath::new(PathBuf::from(s.into()))).collect(); ExternEntry { location: ExternLocation::ExactPaths(locations), diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e65f4beab2411..41b43f6479867 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -948,7 +948,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,compile_fail,edition2021 /// #[no_mangle] /// const FOO: i32 = 5; /// ``` diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index f1dc420aa3c92..7f4789ad0d9b8 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -41,7 +41,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,compile_fail,edition2021 /// # #![deny(impl_trait_overcaptures)] /// # use std::fmt::Display; /// let mut x = vec![]; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 17d501c5730b8..03b8112938cff 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1424,7 +1424,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,compile_fail,edition2021 /// macro_rules! foo { /// () => {}; /// ($name) => { }; @@ -4128,7 +4128,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust,compile_fail + /// ```rust,compile_fail,edition2021 /// #![deny(dependency_on_unit_never_type_fallback)] /// fn main() { /// if true { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 43955cc23a9e9..e2d36f6a4e2ff 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2323,14 +2323,13 @@ pub fn parse_externs( let ExternOpt { crate_name: name, path, options } = split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit()); - let path = path.map(|p| CanonicalizedPath::new(p.as_path())); - let entry = externs.entry(name.to_owned()); use std::collections::btree_map::Entry; let entry = if let Some(path) = path { // --extern prelude_name=some_file.rlib + let path = CanonicalizedPath::new(path); match entry { Entry::Vacant(vacant) => { let files = BTreeSet::from_iter(iter::once(path)); diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 2243e831b66ec..e9ddd66b5e8b3 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::OnceLock; use rustc_data_structures::profiling::VerboseTimingGuard; @@ -104,8 +104,8 @@ pub struct CanonicalizedPath { } impl CanonicalizedPath { - pub fn new(path: &Path) -> Self { - Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() } + pub fn new(path: PathBuf) -> Self { + Self { canonicalized: try_canonicalize(&path).ok(), original: path } } pub fn canonicalized(&self) -> &PathBuf { diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index d5b19470e318b..2d05be5181105 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -818,6 +818,7 @@ impl From>> for CString { } } +#[stable(feature = "c_string_from_str", since = "1.85.0")] impl FromStr for CString { type Err = NulError; @@ -830,6 +831,7 @@ impl FromStr for CString { } } +#[stable(feature = "c_string_from_str", since = "1.85.0")] impl TryFrom for String { type Error = IntoStringError; diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs index 695d7ad07cf76..05a2763a22596 100644 --- a/library/alloc/src/ffi/mod.rs +++ b/library/alloc/src/ffi/mod.rs @@ -87,5 +87,5 @@ pub use self::c_str::CString; #[stable(feature = "alloc_c_string", since = "1.64.0")] pub use self::c_str::{FromVecWithNulError, IntoStringError, NulError}; -#[unstable(feature = "c_str_module", issue = "112134")] +#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")] pub mod c_str; diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 85e87445a1b43..ac07c645c0195 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -79,8 +79,9 @@ use crate::{fmt, ops, slice, str}; /// /// fn my_string_safe() -> String { /// let cstr = unsafe { CStr::from_ptr(my_string()) }; -/// // Get copy-on-write Cow<'_, str>, then guarantee a freshly-owned String allocation -/// String::from_utf8_lossy(cstr.to_bytes()).to_string() +/// // Get a copy-on-write Cow<'_, str>, then extract the +/// // allocated String (or allocate a fresh one if needed). +/// cstr.to_string_lossy().into_owned() /// } /// /// println!("string: {}", my_string_safe()); diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 9bae5fd466a18..c9c73a25d899e 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -20,7 +20,7 @@ pub use self::c_str::FromBytesUntilNulError; pub use self::c_str::FromBytesWithNulError; use crate::fmt; -#[unstable(feature = "c_str_module", issue = "112134")] +#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")] pub mod c_str; #[unstable( diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index cc12cd9c35601..a6522659620a0 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -271,7 +271,7 @@ impl Peekable { /// assert_eq!(iter.next_if(|&x| x == 0), Some(0)); /// // The next item returned is now 1, so `next_if` will return `None`. /// assert_eq!(iter.next_if(|&x| x == 0), None); - /// // `next_if` saves the value of the next item if it was not equal to `expected`. + /// // `next_if` retains the next item if the predicate evaluates to `false` for it. /// assert_eq!(iter.next(), Some(1)); /// ``` /// @@ -304,9 +304,9 @@ impl Peekable { /// let mut iter = (0..5).peekable(); /// // The first item of the iterator is 0; consume it. /// assert_eq!(iter.next_if_eq(&0), Some(0)); - /// // The next item returned is now 1, so `next_if` will return `None`. + /// // The next item returned is now 1, so `next_if_eq` will return `None`. /// assert_eq!(iter.next_if_eq(&0), None); - /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`. + /// // `next_if_eq` retains the next item if it was not equal to `expected`. /// assert_eq!(iter.next(), Some(1)); /// ``` #[stable(feature = "peekable_next_if", since = "1.51.0")] diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 79b4953fcc11a..fe35bfdbdf71c 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2115,7 +2115,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "str_trim"] pub fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) + self.trim_matches(char::is_whitespace) } /// Returns a string slice with leading whitespace removed. @@ -2154,7 +2154,7 @@ impl str { #[stable(feature = "trim_direction", since = "1.30.0")] #[rustc_diagnostic_item = "str_trim_start"] pub fn trim_start(&self) -> &str { - self.trim_start_matches(|c: char| c.is_whitespace()) + self.trim_start_matches(char::is_whitespace) } /// Returns a string slice with trailing whitespace removed. @@ -2193,7 +2193,7 @@ impl str { #[stable(feature = "trim_direction", since = "1.30.0")] #[rustc_diagnostic_item = "str_trim_end"] pub fn trim_end(&self) -> &str { - self.trim_end_matches(|c: char| c.is_whitespace()) + self.trim_end_matches(char::is_whitespace) } /// Returns a string slice with leading whitespace removed. diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index d34e3ca00b9fe..bd9446f5aba51 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -161,7 +161,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[unstable(feature = "c_str_module", issue = "112134")] +#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")] pub mod c_str; #[stable(feature = "core_c_void", since = "1.30.0")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f77bf92a806e3..3c22b8a5589e7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -329,7 +329,6 @@ #![feature(array_chunks)] #![feature(bstr)] #![feature(bstr_internals)] -#![feature(c_str_module)] #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(core_intrinsics)] diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index d5c965f7053e0..4194abc8d5742 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -407,17 +407,27 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { is_extern_crate = check_item(&item, &mut info, crate_name); } - StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => { - reset_error_count(&psess); - return Err(()); + StmtKind::Expr(ref expr) => { + if matches!(expr.kind, ast::ExprKind::Err(_)) { + reset_error_count(&psess); + return Err(()); + } + has_non_items = true; } - StmtKind::MacCall(ref mac_call) if !info.has_main_fn => { + // We assume that the macro calls will expand to item(s) even though they could + // expand to statements and expressions. And the simple fact that we're trying + // to retrieve a `main` function inside it is a terrible idea. + StmtKind::MacCall(ref mac_call) => { + if info.has_main_fn { + continue; + } let mut iter = mac_call.mac.args.tokens.iter(); while let Some(token) = iter.next() { @@ -437,7 +447,9 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result {} + _ => { + has_non_items = true; + } } // Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to @@ -462,6 +474,11 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 9fd33e23204e7..d6c69d39e17ff 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -444,21 +444,15 @@ impl<'a> LintExtractor<'a> { fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; let mut cmd = Command::new(self.rustc_path); - if options.contains(&"edition2024") { - cmd.arg("--edition=2024"); - cmd.arg("-Zunstable-options"); - } else if options.contains(&"edition2021") { - cmd.arg("--edition=2021"); - } else if options.contains(&"edition2018") { - cmd.arg("--edition=2018"); - } else if options.contains(&"edition2015") { - cmd.arg("--edition=2015"); - } else if options.contains(&"edition") { - panic!("lint-docs: unknown edition"); - } else { + let edition = options + .iter() + .filter_map(|opt| opt.strip_prefix("edition")) + .next() // defaults to latest edition - cmd.arg("--edition=2021"); - } + .unwrap_or("2024"); + cmd.arg(format!("--edition={edition}")); + // Just in case this is an unstable edition. + cmd.arg("-Zunstable-options"); cmd.arg("--error-format=json"); cmd.arg("--target").arg(self.rustc_target); if let Some(target_linker) = self.rustc_linker { diff --git a/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs b/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs new file mode 100644 index 0000000000000..ed7584b742533 --- /dev/null +++ b/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs @@ -0,0 +1 @@ +use std::string::String; diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs index 508faadcf6729..ca5dd78746789 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.rs @@ -4,12 +4,12 @@ //@ compile-flags:--test //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ failure-status: 101 +//@ check-pass /// /// /// ```rust -/// struct S {}; // unexpected semicolon after struct def +/// struct S {}; /// /// fn main() { /// assert_eq!(0, 1); diff --git a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout index 9eb8b391e7809..1068b98cb0fbb 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-extra-semicolon-on-item.stdout @@ -1,29 +1,6 @@ running 1 test -test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... FAILED +test $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) ... ok -failures: - ----- $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) stdout ---- -error: expected item, found `;` - --> $DIR/failed-doctest-extra-semicolon-on-item.rs:12:12 - | -LL | struct S {}; // unexpected semicolon after struct def - | ^ - | - = help: braced struct declarations are not followed by a semicolon -help: remove this semicolon - | -LL - struct S {}; // unexpected semicolon after struct def -LL + struct S {} // unexpected semicolon after struct def - | - -error: aborting due to 1 previous error - -Couldn't compile the test. - -failures: - $DIR/failed-doctest-extra-semicolon-on-item.rs - m (line 11) - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/doctest/macro-after-main.rs b/tests/rustdoc-ui/doctest/macro-after-main.rs new file mode 100644 index 0000000000000..0a42343f1c272 --- /dev/null +++ b/tests/rustdoc-ui/doctest/macro-after-main.rs @@ -0,0 +1,16 @@ +// This test checks a corner case where the macro calls used to be skipped, +// making them considered as statement, and therefore some cases where +// `include!` macro was then put into a function body, making the doctest +// compilation fail. + +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + +//! ``` +//! include!("./auxiliary/macro-after-main.rs"); +//! +//! fn main() {} +//! eprintln!(); +//! ``` diff --git a/tests/rustdoc-ui/doctest/macro-after-main.stdout b/tests/rustdoc-ui/doctest/macro-after-main.stdout new file mode 100644 index 0000000000000..72ffe2b5a27c5 --- /dev/null +++ b/tests/rustdoc-ui/doctest/macro-after-main.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/macro-after-main.rs - (line 11) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs new file mode 100644 index 0000000000000..ee2299c0fd87e --- /dev/null +++ b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs @@ -0,0 +1,22 @@ +// This test ensures that if there is an expression alongside a `main` +// function, it will not consider the entire code to be part of the `main` +// function and will generate its own function to wrap everything. +// +// This is a regression test for: +// * +// * +//@ compile-flags:--test +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + +#![crate_name = "foo"] + +//! ``` +//! # if cfg!(miri) { return; } +//! use std::ops::Deref; +//! +//! fn main() { +//! println!("Hi!"); +//! } +//! ``` diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout new file mode 100644 index 0000000000000..90d7c3546bf10 --- /dev/null +++ b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/test-main-alongside-exprs.rs - (line 15) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +