From 65e131e322d8e7e385fb74a99ff090312388edcf Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 29 Dec 2020 11:39:30 -0500 Subject: [PATCH 01/73] Prepare 1.50 beta --- src/ci/run.sh | 2 +- src/stage0.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index 181a7fcb73266..8681f84f6ab0a 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -63,7 +63,7 @@ fi # # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. -export RUST_RELEASE_CHANNEL=nightly +export RUST_RELEASE_CHANNEL=beta # Always set the release channel for bootstrap; this is normally not important (i.e., only dist # builds would seem to matter) but in practice bootstrap wants to know whether we're targeting diff --git a/src/stage0.txt b/src/stage0.txt index 6e05b66c3fe4a..2e32d7f62f5c0 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,14 +12,14 @@ # stable release's version number. `date` is the date where the release we're # bootstrapping off was released. -date: 2020-11-18 -rustc: beta +date: 2020-12-29 +rustc: 1.49.0 # We use a nightly rustfmt to format the source because it solves some # bootstrapping issues with use of new syntax in this repo. If you're looking at # the beta/stable branch, this key should be omitted, as we don't want to depend # on rustfmt from nightly there. -rustfmt: nightly-2020-11-19 +#rustfmt: nightly-2020-11-19 # When making a stable release the process currently looks like: # @@ -39,4 +39,4 @@ rustfmt: nightly-2020-11-19 # looking at a beta source tarball and it's uncommented we'll shortly comment it # out. -#dev: 1 +dev: 1 From d17ca57176d00a36d4e68e6613c35153643e9f1d Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 6 Oct 2020 22:36:12 -0400 Subject: [PATCH 02/73] Update fulldeps test --- .../ui-fulldeps/session-derive-errors.stderr | 47 +++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr index c1be151f1c1ce..303268fae27a1 100644 --- a/src/test/ui-fulldeps/session-derive-errors.stderr +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -1,25 +1,20 @@ error: `#[derive(SessionDiagnostic)]` can only be used on structs --> $DIR/session-derive-errors.rs:28:1 | -LL | / #[error = "E0123"] -LL | | -LL | | enum SessionDiagnosticOnEnum { -LL | | Foo, -LL | | Bar, -LL | | } - | |_^ +LL | #[error = "E0123"] + | ^ error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute --> $DIR/session-derive-errors.rs:37:1 | LL | #[label = "This is in the wrong place"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute --> $DIR/session-derive-errors.rs:44:5 | LL | #[suggestion = "this is the wrong kind of attribute"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error: `error` specified multiple times --> $DIR/session-derive-errors.rs:52:11 @@ -37,7 +32,7 @@ error: `code` not specified --> $DIR/session-derive-errors.rs:67:1 | LL | struct ErrorCodeNotProvided {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ | = help: use the [code = "..."] attribute to set this diagnostic's error code @@ -45,13 +40,13 @@ error: the `#[message = "..."]` attribute can only be applied to fields of type --> $DIR/session-derive-errors.rs:95:5 | LL | #[message = "this message is applied to a String field"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error: `name` doesn't refer to a field on this type --> $DIR/session-derive-errors.rs:102:1 | LL | #[message = "This error has a field, and references {name}"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ error: invalid format string: expected `'}'` but string was terminated --> $DIR/session-derive-errors.rs:110:1 @@ -77,59 +72,53 @@ error: The `#[label = ...]` attribute can only be applied to fields of type Span --> $DIR/session-derive-errors.rs:138:5 | LL | #[label = "See here"] - | ^^^^^^^^^^^^^^^^^^^^^ + | ^ error: `nonsense` is not a valid key for `#[suggestion(...)]` --> $DIR/session-derive-errors.rs:163:18 | LL | #[suggestion(nonsense = "This is nonsense")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ error: `msg` is not a valid key for `#[suggestion(...)]` --> $DIR/session-derive-errors.rs:171:18 | LL | #[suggestion(msg = "This is a suggestion")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ error: missing suggestion message --> $DIR/session-derive-errors.rs:179:7 | LL | #[suggestion(code = "This is suggested code")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: provide a suggestion message using #[suggestion(message = "...")] error: wrong field type for suggestion --> $DIR/session-derive-errors.rs:194:5 | -LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] -LL | | -LL | | suggestion: Applicability, - | |_____________________________^ +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ | = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability) error: type of field annotated with `#[suggestion(...)]` contains more than one Span --> $DIR/session-derive-errors.rs:209:5 | -LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] -LL | | -LL | | suggestion: (Span, Span, Applicability), - | |___________________________________________^ +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability --> $DIR/session-derive-errors.rs:217:5 | -LL | / #[suggestion(message = "This is a message", code = "This is suggested code")] -LL | | -LL | | suggestion: (Applicability, Applicability, Span), - | |____________________________________________________^ +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ error: invalid annotation list `#[label(...)]` --> $DIR/session-derive-errors.rs:225:7 | LL | #[label("wrong kind of annotation for label")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^ error: aborting due to 18 previous errors From 57950a20840d43bec9e331be3cfc6f7c3a52673a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 17 Nov 2020 16:00:41 -0500 Subject: [PATCH 03/73] Ignore failures of RLS on aarch64 Windows --- src/bootstrap/dist.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 0a79d09b27fed..0745260e7e702 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1021,7 +1021,13 @@ impl Step for Rls { let rls = builder .ensure(tool::Rls { compiler, target, extra_features: Vec::new() }) .or_else(|| { - missing_tool("RLS", builder.build.config.missing_tools); + // We ignore failure on aarch64 Windows because RLS currently + // fails to build, due to winapi 0.2 not supporting aarch64. + missing_tool( + "RLS", + builder.build.config.missing_tools + || (target.triple.contains("aarch64") && target.triple.contains("windows")), + ); None })?; From 483c1a83ca7cf53fd8f3432edb32cbe70ba39d45 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 29 Dec 2020 15:18:40 -0500 Subject: [PATCH 04/73] Permit unstable features during PGO benchmarks --- src/ci/pgo.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh index 13b8ca91f890f..10f2cd825fafe 100755 --- a/src/ci/pgo.sh +++ b/src/ci/pgo.sh @@ -2,6 +2,8 @@ set -euxo pipefail +export RUSTC_BOOTSTRAP=1 + rm -rf /tmp/rustc-pgo python2.7 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \ From bfceef0cb462d209b641cb8e202afda5b3ea33ec Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 31 Dec 2020 09:48:36 -0500 Subject: [PATCH 05/73] Bootstrap from released compiler --- src/stage0.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stage0.txt b/src/stage0.txt index 2e32d7f62f5c0..831a4a506793e 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # stable release's version number. `date` is the date where the release we're # bootstrapping off was released. -date: 2020-12-29 +date: 2020-12-31 rustc: 1.49.0 # We use a nightly rustfmt to format the source because it solves some @@ -39,4 +39,4 @@ rustc: 1.49.0 # looking at a beta source tarball and it's uncommented we'll shortly comment it # out. -dev: 1 +#dev: 1 From 48233acf2a0f2787d5c2e9adbb6bad87be25b2f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Dec 2020 00:39:09 +0100 Subject: [PATCH 06/73] de-stabilize unsized raw ptr methods for Weak --- library/alloc/src/rc.rs | 4 +++- library/alloc/src/rc/tests.rs | 24 ------------------------ library/alloc/src/sync.rs | 4 +++- library/alloc/src/sync/tests.rs | 24 ------------------------ 4 files changed, 6 insertions(+), 50 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index a96be57143d38..73d12f0a5f45d 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1749,7 +1749,7 @@ struct WeakInner<'a> { strong: &'a Cell, } -impl Weak { +impl Weak { /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, @@ -1882,7 +1882,9 @@ impl Weak { // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } } } +} +impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. /// diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index bb5c3f4f90433..2d183a8c88c64 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -208,30 +208,6 @@ fn into_from_weak_raw() { } } -#[test] -fn test_into_from_weak_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let arc: Rc = Rc::from("foo"); - let weak: Weak = Rc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert!(weak.ptr_eq(&weak2)); - - let arc: Rc = Rc::new(123); - let weak: Weak = Rc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert!(weak.ptr_eq(&weak2)); -} - #[test] fn get_mut() { let mut x = Rc::new(3); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 9d478a302e96c..53ba9c283ae23 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1535,7 +1535,7 @@ struct WeakInner<'a> { strong: &'a atomic::AtomicUsize, } -impl Weak { +impl Weak { /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, @@ -1668,7 +1668,9 @@ impl Weak { // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } } } +} +impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Arc`], delaying /// dropping of the inner value if successful. /// diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 77f328d48f94d..e8e1e66da5ed4 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -158,30 +158,6 @@ fn into_from_weak_raw() { } } -#[test] -fn test_into_from_weak_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let arc: Arc = Arc::from("foo"); - let weak: Weak = Arc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert!(weak.ptr_eq(&weak2)); - - let arc: Arc = Arc::new(123); - let weak: Weak = Arc::downgrade(&arc); - - let ptr = Weak::into_raw(weak.clone()); - let weak2 = unsafe { Weak::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert!(weak.ptr_eq(&weak2)); -} - #[test] fn test_cowarc_clone_make_mut() { let mut cow0 = Arc::new(75); From 31d03c4cc54f51dae5cbba4b9d5d899d0e30b036 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 26 Dec 2020 17:15:20 -0500 Subject: [PATCH 07/73] Use package name for top-level directory in bare tarballs This fixes a bug introduced by #79788. --- src/bootstrap/tarball.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 5d73a655427b2..32c8e791bfc6b 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -241,10 +241,16 @@ impl<'a> Tarball<'a> { } pub(crate) fn bare(self) -> PathBuf { + // Bare tarballs should have the top level directory match the package + // name, not "image". We rename the image directory just before passing + // into rust-installer. + let dest = self.temp_dir.join(self.package_name()); + t!(std::fs::rename(&self.image_dir, &dest)); + self.run(|this, cmd| { cmd.arg("tarball") .arg("--input") - .arg(&this.image_dir) + .arg(&dest) .arg("--output") .arg(crate::dist::distdir(this.builder).join(this.package_name())); }) From 8da279982cf26f25f7cbcfd11cb32719cc39f99e Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 20 Dec 2020 18:11:11 +0000 Subject: [PATCH 08/73] Make recursion limit fatal in project This avoid the hang/oom from #79714 --- compiler/rustc_trait_selection/src/traits/project.rs | 9 ++++++++- src/test/ui/issues/issue-23122-2.stderr | 3 +-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a11499e43209f..7fa070caa2758 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -734,7 +734,14 @@ fn project_type<'cx, 'tcx>( if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); + match selcx.query_mode() { + super::TraitQueryMode::Standard => { + selcx.infcx().report_overflow_error(&obligation, true); + } + super::TraitQueryMode::Canonical => { + return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); + } + } } let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index ce3bffe602ca0..ff7e884ea6f83 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,11 +1,10 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) - = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to previous error From 89164cdff6a55a7e31041ac0b30988e840e3b6e9 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 20 Dec 2020 18:13:05 +0000 Subject: [PATCH 09/73] Prevent caching projections in the case of cycles When normalizing a projection which results in a cycle, we would cache the result of `project_type` without the nested obligations (because they're not needed for inference). This would result in the nested obligations only being handled once in fulfill, which would avoid the cycle error. Fixes #79714, a regresion from #79305 caused by the removal of `get_paranoid_cache_value_obligation`. --- compiler/rustc_infer/src/traits/project.rs | 16 +++++++- .../src/traits/project.rs | 14 ++++--- .../src/traits/select/mod.rs | 4 ++ .../defaults-cyclic-fail-1.rs | 4 +- .../defaults-cyclic-fail-1.stderr | 10 ++--- .../defaults-cyclic-fail-2.rs | 4 +- .../defaults-cyclic-fail-2.stderr | 10 ++--- .../ui/associated-types/impl-wf-cycle-1.rs | 29 ++++++++++++++ .../associated-types/impl-wf-cycle-1.stderr | 39 +++++++++++++++++++ .../ui/associated-types/impl-wf-cycle-2.rs | 16 ++++++++ .../associated-types/impl-wf-cycle-2.stderr | 25 ++++++++++++ 11 files changed, 150 insertions(+), 21 deletions(-) create mode 100644 src/test/ui/associated-types/impl-wf-cycle-1.rs create mode 100644 src/test/ui/associated-types/impl-wf-cycle-1.stderr create mode 100644 src/test/ui/associated-types/impl-wf-cycle-2.rs create mode 100644 src/test/ui/associated-types/impl-wf-cycle-2.stderr diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs index 65284bcee912c..33bddf1dedc1b 100644 --- a/compiler/rustc_infer/src/traits/project.rs +++ b/compiler/rustc_infer/src/traits/project.rs @@ -90,6 +90,7 @@ impl ProjectionCacheKey<'tcx> { pub enum ProjectionCacheEntry<'tcx> { InProgress, Ambiguous, + Recur, Error, NormalizedTy(NormalizedTy<'tcx>), } @@ -143,7 +144,12 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value ); - let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value)); + let mut map = self.map(); + if let Some(ProjectionCacheEntry::Recur) = map.get(&key) { + debug!("Not overwriting Recur"); + return; + } + let fresh_key = map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); assert!(!fresh_key, "never started projecting `{:?}`", key); } @@ -197,6 +203,14 @@ impl<'tcx> ProjectionCache<'_, 'tcx> { assert!(!fresh, "never started projecting `{:?}`", key); } + /// Indicates that while trying to normalize `key`, `key` was required to + /// be normalized again. Selection or evaluation should eventually report + /// an error here. + pub fn recur(&mut self, key: ProjectionCacheKey<'tcx>) { + let fresh = self.map().insert(key, ProjectionCacheEntry::Recur); + assert!(!fresh, "never started projecting `{:?}`", key); + } + /// Indicates that trying to normalize `key` resulted in /// error. pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7fa070caa2758..fa0526445c194 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -496,12 +496,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( return Ok(None); } Err(ProjectionCacheEntry::InProgress) => { - // If while normalized A::B, we are asked to normalize - // A::B, just return A::B itself. This is a conservative - // answer, in the sense that A::B *is* clearly equivalent - // to A::B, though there may be a better value we can - // find. - // Under lazy normalization, this can arise when // bootstrapping. That is, imagine an environment with a // where-clause like `A::B == u32`. Now, if we are asked @@ -512,6 +506,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( debug!("found cache entry: in-progress"); + // Cache that normalizing this projection resulted in a cycle. This + // should ensure that, unless this happens within a snapshot that's + // rolled back, fulfillment or evaluation will notice the cycle. + + infcx.inner.borrow_mut().projection_cache().recur(cache_key); + return Err(InProgress); + } + Err(ProjectionCacheEntry::Recur) => { return Err(InProgress); } Err(ProjectionCacheEntry::NormalizedTy(ty)) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f1c86eab0956e..a8f81445b0397 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -291,6 +291,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } + pub(super) fn query_mode(&self) -> TraitQueryMode { + self.query_mode + } + /////////////////////////////////////////////////////////////////////////// // Selection // diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs index afb2b3df716eb..61ef013236e8d 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-1.rs +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.rs @@ -24,13 +24,13 @@ impl Tr for u32 { // ...but not in an impl that redefines one of the types. impl Tr for bool { type A = Box; - //~^ ERROR type mismatch resolving `::B == _` + //~^ ERROR overflow evaluating the requirement `::B == _` } // (the error is shown twice for some reason) impl Tr for usize { type B = &'static Self::A; - //~^ ERROR type mismatch resolving `::A == _` + //~^ ERROR overflow evaluating the requirement `::A == _` } fn main() { diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr index ae7150d47ca99..5e98520b41187 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr +++ b/src/test/ui/associated-types/defaults-cyclic-fail-1.stderr @@ -1,15 +1,15 @@ -error[E0271]: type mismatch resolving `::B == _` +error[E0275]: overflow evaluating the requirement `::B == _` --> $DIR/defaults-cyclic-fail-1.rs:26:5 | LL | type A = Box; - | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0271]: type mismatch resolving `::A == _` +error[E0275]: overflow evaluating the requirement `::A == _` --> $DIR/defaults-cyclic-fail-1.rs:32:5 | LL | type B = &'static Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs index ba4bb0d5a296b..e91c9f2d29a82 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-2.rs +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.rs @@ -25,13 +25,13 @@ impl Tr for u32 { impl Tr for bool { type A = Box; - //~^ ERROR type mismatch resolving `::B == _` + //~^ ERROR overflow evaluating the requirement `::B == _` } // (the error is shown twice for some reason) impl Tr for usize { type B = &'static Self::A; - //~^ ERROR type mismatch resolving `::A == _` + //~^ ERROR overflow evaluating the requirement `::A == _` } fn main() { diff --git a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr index 0dfbac2dec5d5..c538805f85821 100644 --- a/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr +++ b/src/test/ui/associated-types/defaults-cyclic-fail-2.stderr @@ -1,15 +1,15 @@ -error[E0271]: type mismatch resolving `::B == _` +error[E0275]: overflow evaluating the requirement `::B == _` --> $DIR/defaults-cyclic-fail-2.rs:27:5 | LL | type A = Box; - | ^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0271]: type mismatch resolving `::A == _` +error[E0275]: overflow evaluating the requirement `::A == _` --> $DIR/defaults-cyclic-fail-2.rs:33:5 | LL | type B = &'static Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.rs b/src/test/ui/associated-types/impl-wf-cycle-1.rs new file mode 100644 index 0000000000000..ba074210a2b5f --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-1.rs @@ -0,0 +1,29 @@ +// Regression test for #79714 + +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for (T,) +where + Self::A: Baz, + Self::B: Fiz, +{ + type A = (); + //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` + type B = bool; + //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +} +//~^^^^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` + +fn main() { + let x: <(_,) as Grault>::A = (); +} diff --git a/src/test/ui/associated-types/impl-wf-cycle-1.stderr b/src/test/ui/associated-types/impl-wf-cycle-1.stderr new file mode 100644 index 0000000000000..82328048c99a3 --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-1.stderr @@ -0,0 +1,39 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-1.rs:15:1 + | +LL | / impl Grault for (T,) +LL | | where +LL | | Self::A: Baz, +LL | | Self::B: Fiz, +... | +LL | | +LL | | } + | |_^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-1.rs:20:5 + | +LL | type A = (); + | ^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-1.rs:22:5 + | +LL | type B = bool; + | ^^^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + = note: 1 redundant requirements hidden + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.rs b/src/test/ui/associated-types/impl-wf-cycle-2.rs new file mode 100644 index 0000000000000..6fccc54f229ae --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-2.rs @@ -0,0 +1,16 @@ +// Regression test for #79714 + +trait Grault { + type A; +} + +impl Grault for (T,) +where + Self::A: Copy, +{ + type A = (); + //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +} +//~^^^^^^^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` + +fn main() {} diff --git a/src/test/ui/associated-types/impl-wf-cycle-2.stderr b/src/test/ui/associated-types/impl-wf-cycle-2.stderr new file mode 100644 index 0000000000000..5cd18a33adf37 --- /dev/null +++ b/src/test/ui/associated-types/impl-wf-cycle-2.stderr @@ -0,0 +1,25 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-2.rs:7:1 + | +LL | / impl Grault for (T,) +LL | | where +LL | | Self::A: Copy, +LL | | { +LL | | type A = (); +LL | | +LL | | } + | |_^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-2.rs:11:5 + | +LL | type A = (); + | ^^^^^^^^^^^^ + | + = note: required because of the requirements on the impl of `Grault` for `(T,)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0275`. From 914bed4bd5edad4004168f43da45d46c7461e931 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 12 Jan 2021 21:52:29 -0800 Subject: [PATCH 10/73] [beta] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 75d5d8cffe346..1a8df6a5196e4 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 75d5d8cffe3464631f82dcd3c470b78dc1dda8bb +Subproject commit 1a8df6a5196e4cad9a3956867e7e928f2bfaaba4 From 78cd953e6ae72c92d20660f18c4339f6c809cac1 Mon Sep 17 00:00:00 2001 From: Caleb Cartwright Date: Tue, 19 Jan 2021 18:56:24 -0600 Subject: [PATCH 11/73] update RLS and rustfmt --- src/tools/rls | 2 +- src/tools/rustfmt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rls b/src/tools/rls index 2cf84baa5e3c5..585cab26ca17f 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 2cf84baa5e3c55ac02f42919e67440acb5417125 +Subproject commit 585cab26ca17f23035de054a325b9dd62ae0e738 diff --git a/src/tools/rustfmt b/src/tools/rustfmt index acd94866fd0ff..8c6769d72de01 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit acd94866fd0ff5eacb7e184ae21c19e5440fc5fb +Subproject commit 8c6769d72de01034cf342aa141846d49cc637a4d From 59b6b1101fee97ece51ab7b91036e15b0188463b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 07:27:03 -0500 Subject: [PATCH 12/73] Fix handling of malicious Readers in read_to_end --- library/std/src/io/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index dfbf6c3f24443..202889018c595 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -391,7 +391,14 @@ where ret = Ok(g.len - start_len); break; } - Ok(n) => g.len += n, + Ok(n) => { + // We can't let g.len overflow which would result in the vec shrinking when the function returns. In + // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. + // The minimal check would just be a checked_add, but this assert is a bit more precise and should be + // just about the same cost. + assert!(n <= g.buf.len() - g.len); + g.len += n; + } Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => { ret = Err(e); From 2fe7ddc3f8e7507af5ae0f29bfaf23a43b419004 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 07:48:24 -0500 Subject: [PATCH 13/73] clean up control flow --- library/std/src/io/mod.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 202889018c595..64601cde01df9 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -367,7 +367,6 @@ where { let start_len = buf.len(); let mut g = Guard { len: buf.len(), buf }; - let ret; loop { if g.len == g.buf.len() { unsafe { @@ -387,10 +386,7 @@ where } match r.read(&mut g.buf[g.len..]) { - Ok(0) => { - ret = Ok(g.len - start_len); - break; - } + Ok(0) => return Ok(g.len - start_len), Ok(n) => { // We can't let g.len overflow which would result in the vec shrinking when the function returns. In // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. @@ -400,14 +396,9 @@ where g.len += n; } Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } + Err(e) => return Err(e), } } - - ret } pub(crate) fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result From e73125e9e8457747084ca520192a8e7990441269 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 17:13:50 -0500 Subject: [PATCH 14/73] make check a bit more clear --- library/std/src/io/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 64601cde01df9..57b78be618983 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -385,14 +385,15 @@ where } } - match r.read(&mut g.buf[g.len..]) { + let buf = &mut g.buf[g.len..]; + match r.read(buf) { Ok(0) => return Ok(g.len - start_len), Ok(n) => { // We can't let g.len overflow which would result in the vec shrinking when the function returns. In // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. // The minimal check would just be a checked_add, but this assert is a bit more precise and should be // just about the same cost. - assert!(n <= g.buf.len() - g.len); + assert!(n <= buf.len()); g.len += n; } Err(ref e) if e.kind() == ErrorKind::Interrupted => {} From 2eef2e24bac35abd705131dd3f1c2ce23cf41c94 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2021 17:16:44 -0500 Subject: [PATCH 15/73] clarify docs a bit --- library/std/src/io/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 57b78be618983..30d80b76ab7ca 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -389,10 +389,9 @@ where match r.read(buf) { Ok(0) => return Ok(g.len - start_len), Ok(n) => { - // We can't let g.len overflow which would result in the vec shrinking when the function returns. In - // particular, that could break read_to_string if the shortened buffer doesn't end on a UTF-8 boundary. - // The minimal check would just be a checked_add, but this assert is a bit more precise and should be - // just about the same cost. + // We can't allow bogus values from read. If it is too large, the returned vec could have its length + // set past its capacity, or if it overflows the vec could be shortened which could create an invalid + // string if this is called via read_to_string. assert!(n <= buf.len()); g.len += n; } From 44a1f09985e9d99bfce1e73e0f1e43066999092d Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Dec 2020 16:05:57 +0100 Subject: [PATCH 16/73] bootstrap: extract from any compression algorithm during distcheck --- src/bootstrap/test.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index b99692e8ba5b8..1b9523426e735 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1968,7 +1968,7 @@ impl Step for Distcheck { builder.ensure(dist::Src); let mut cmd = Command::new("tar"); - cmd.arg("-xzf") + cmd.arg("-xf") .arg(builder.ensure(dist::PlainSourceTarball)) .arg("--strip-components=1") .current_dir(&dir); @@ -1992,10 +1992,7 @@ impl Step for Distcheck { t!(fs::create_dir_all(&dir)); let mut cmd = Command::new("tar"); - cmd.arg("-xzf") - .arg(builder.ensure(dist::Src)) - .arg("--strip-components=1") - .current_dir(&dir); + cmd.arg("-xf").arg(builder.ensure(dist::Src)).arg("--strip-components=1").current_dir(&dir); builder.run(&mut cmd); let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); From 4e4636d9d4ee5eff7a758be1dd8d2c4456b043ee Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Dec 2020 12:10:31 +0100 Subject: [PATCH 17/73] bootstrap: never delete the tarball temporary directory Files in the temporary directory are used by ./x.py install. --- src/bootstrap/dist.rs | 4 ++-- src/bootstrap/tarball.rs | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 0745260e7e702..997587fe35eba 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1322,8 +1322,8 @@ impl Step for Extended { tarballs.push(mingw_installer.unwrap()); } - let mut tarball = Tarball::new(builder, "rust", &target.triple); - let work = tarball.persist_work_dir(); + let tarball = Tarball::new(builder, "rust", &target.triple); + let work = tarball.work_dir(); tarball.combine(&tarballs); let tmp = tmpdir(builder).join("combined-tarball"); diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 32c8e791bfc6b..688cc0fb8c95a 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -97,7 +97,6 @@ pub(crate) struct Tarball<'a> { include_target_in_component_name: bool, is_preview: bool, - delete_temp_dir: bool, } impl<'a> Tarball<'a> { @@ -136,7 +135,6 @@ impl<'a> Tarball<'a> { include_target_in_component_name: false, is_preview: false, - delete_temp_dir: true, } } @@ -198,8 +196,7 @@ impl<'a> Tarball<'a> { self.builder.cp_r(src.as_ref(), &dest); } - pub(crate) fn persist_work_dir(&mut self) -> PathBuf { - self.delete_temp_dir = false; + pub(crate) fn work_dir(&self) -> PathBuf { self.temp_dir.clone() } @@ -295,9 +292,6 @@ impl<'a> Tarball<'a> { build_cli(&self, &mut cmd); cmd.arg("--work-dir").arg(&self.temp_dir); self.builder.run(&mut cmd); - if self.delete_temp_dir { - t!(std::fs::remove_dir_all(&self.temp_dir)); - } crate::dist::distdir(self.builder).join(format!("{}.tar.gz", package_name)) } From 14fa72673435d9591e41f6d42298a8a4b3588baf Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Dec 2020 12:20:13 +0100 Subject: [PATCH 18/73] bootstrap: change the dist outputs to GeneratedTarball The struct will allow to store more context on the generated tarballs. --- src/bootstrap/dist.rs | 76 ++++++++++++++++++++-------------------- src/bootstrap/tarball.rs | 29 ++++++++++----- src/bootstrap/test.rs | 7 ++-- 3 files changed, 64 insertions(+), 48 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 997587fe35eba..947ac6f1ee0eb 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -19,7 +19,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; use crate::config::TargetSelection; -use crate::tarball::{OverlayKind, Tarball}; +use crate::tarball::{GeneratedTarball, OverlayKind, Tarball}; use crate::tool::{self, Tool}; use crate::util::{exe, is_dylib, timeit}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; @@ -51,7 +51,7 @@ pub struct Docs { } impl Step for Docs { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -63,7 +63,7 @@ impl Step for Docs { } /// Builds the `rust-docs` installer component. - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; if !builder.config.docs { return None; @@ -86,7 +86,7 @@ pub struct RustcDocs { } impl Step for RustcDocs { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -98,7 +98,7 @@ impl Step for RustcDocs { } /// Builds the `rustc-docs` installer component. - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; if !builder.config.compiler_docs { return None; @@ -267,7 +267,7 @@ pub struct Mingw { } impl Step for Mingw { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -282,7 +282,7 @@ impl Step for Mingw { /// /// This contains all the bits and pieces to run the MinGW Windows targets /// without any extra installed software (e.g., we bundle gcc, libraries, etc). - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; if !host.contains("pc-windows-gnu") { return None; @@ -307,7 +307,7 @@ pub struct Rustc { } impl Step for Rustc { - type Output = PathBuf; + type Output = GeneratedTarball; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -321,7 +321,7 @@ impl Step for Rustc { } /// Creates the `rustc` installer component. - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> GeneratedTarball { let compiler = self.compiler; let host = self.compiler.host; @@ -555,7 +555,7 @@ pub struct Std { } impl Step for Std { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -573,7 +573,7 @@ impl Step for Std { }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; @@ -601,7 +601,7 @@ pub struct RustcDev { } impl Step for RustcDev { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -620,7 +620,7 @@ impl Step for RustcDev { }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; if skip_host_target_lib(builder, compiler) { @@ -660,7 +660,7 @@ pub struct Analysis { } impl Step for Analysis { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -683,7 +683,7 @@ impl Step for Analysis { } /// Creates a tarball of save-analysis metadata, if available. - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); @@ -796,7 +796,7 @@ pub struct Src; impl Step for Src { /// The output path of the src installer tarball - type Output = PathBuf; + type Output = GeneratedTarball; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -809,7 +809,7 @@ impl Step for Src { } /// Creates the `rust-src` installer component - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> GeneratedTarball { let tarball = Tarball::new_targetless(builder, "rust-src"); // A lot of tools expect the rust-src component to be entirely in this directory, so if you @@ -848,7 +848,7 @@ pub struct PlainSourceTarball; impl Step for PlainSourceTarball { /// Produces the location of the tarball generated - type Output = PathBuf; + type Output = GeneratedTarball; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -862,7 +862,7 @@ impl Step for PlainSourceTarball { } /// Creates the plain source tarball - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> GeneratedTarball { let tarball = Tarball::new(builder, "rustc", "src"); let plain_dst_src = tarball.image_dir(); @@ -941,7 +941,7 @@ pub struct Cargo { } impl Step for Cargo { - type Output = PathBuf; + type Output = GeneratedTarball; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -959,7 +959,7 @@ impl Step for Cargo { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> GeneratedTarball { let compiler = self.compiler; let target = self.target; @@ -995,7 +995,7 @@ pub struct Rls { } impl Step for Rls { - type Output = Option; + type Output = Option; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1013,7 +1013,7 @@ impl Step for Rls { }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); @@ -1047,7 +1047,7 @@ pub struct RustAnalyzer { } impl Step for RustAnalyzer { - type Output = Option; + type Output = Option; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1065,7 +1065,7 @@ impl Step for RustAnalyzer { }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); @@ -1096,7 +1096,7 @@ pub struct Clippy { } impl Step for Clippy { - type Output = PathBuf; + type Output = GeneratedTarball; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1114,7 +1114,7 @@ impl Step for Clippy { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> GeneratedTarball { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); @@ -1146,7 +1146,7 @@ pub struct Miri { } impl Step for Miri { - type Output = Option; + type Output = Option; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1164,7 +1164,7 @@ impl Step for Miri { }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; assert!(builder.config.extended); @@ -1199,7 +1199,7 @@ pub struct Rustfmt { } impl Step for Rustfmt { - type Output = Option; + type Output = Option; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1217,7 +1217,7 @@ impl Step for Rustfmt { }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let compiler = self.compiler; let target = self.target; @@ -1876,7 +1876,7 @@ pub struct LlvmTools { } impl Step for LlvmTools { - type Output = Option; + type Output = Option; const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -1887,7 +1887,7 @@ impl Step for LlvmTools { run.builder.ensure(LlvmTools { target: run.target }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let target = self.target; assert!(builder.config.extended); @@ -1930,7 +1930,7 @@ pub struct RustDev { } impl Step for RustDev { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -1942,7 +1942,7 @@ impl Step for RustDev { run.builder.ensure(RustDev { target: run.target }); } - fn run(self, builder: &Builder<'_>) -> Option { + fn run(self, builder: &Builder<'_>) -> Option { let target = self.target; /* run only if llvm-config isn't used */ @@ -1995,7 +1995,7 @@ pub struct BuildManifest { } impl Step for BuildManifest { - type Output = PathBuf; + type Output = GeneratedTarball; const DEFAULT: bool = false; const ONLY_HOSTS: bool = true; @@ -2007,7 +2007,7 @@ impl Step for BuildManifest { run.builder.ensure(BuildManifest { target: run.target }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> GeneratedTarball { let build_manifest = builder.tool_exe(Tool::BuildManifest); let tarball = Tarball::new(builder, "build-manifest", &self.target.triple); @@ -2027,7 +2027,7 @@ pub struct ReproducibleArtifacts { } impl Step for ReproducibleArtifacts { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 688cc0fb8c95a..482ca40c5c1ff 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -200,7 +200,7 @@ impl<'a> Tarball<'a> { self.temp_dir.clone() } - pub(crate) fn generate(self) -> PathBuf { + pub(crate) fn generate(self) -> GeneratedTarball { let mut component_name = self.component.clone(); if self.is_preview { component_name.push_str("-preview"); @@ -224,20 +224,20 @@ impl<'a> Tarball<'a> { }) } - pub(crate) fn combine(self, tarballs: &[PathBuf]) { - let mut input_tarballs = tarballs[0].as_os_str().to_os_string(); + pub(crate) fn combine(self, tarballs: &[GeneratedTarball]) -> GeneratedTarball { + let mut input_tarballs = tarballs[0].path.as_os_str().to_os_string(); for tarball in &tarballs[1..] { input_tarballs.push(","); - input_tarballs.push(tarball); + input_tarballs.push(&tarball.path); } self.run(|this, cmd| { cmd.arg("combine").arg("--input-tarballs").arg(input_tarballs); this.non_bare_args(cmd); - }); + }) } - pub(crate) fn bare(self) -> PathBuf { + pub(crate) fn bare(self) -> GeneratedTarball { // Bare tarballs should have the top level directory match the package // name, not "image". We rename the image directory just before passing // into rust-installer. @@ -273,7 +273,7 @@ impl<'a> Tarball<'a> { .arg(crate::dist::distdir(self.builder)); } - fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> PathBuf { + fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTarball { t!(std::fs::create_dir_all(&self.overlay_dir)); self.builder.create(&self.overlay_dir.join("version"), &self.overlay.version(self.builder)); if let Some(sha) = self.builder.rust_sha() { @@ -293,6 +293,19 @@ impl<'a> Tarball<'a> { cmd.arg("--work-dir").arg(&self.temp_dir); self.builder.run(&mut cmd); - crate::dist::distdir(self.builder).join(format!("{}.tar.gz", package_name)) + GeneratedTarball { + path: crate::dist::distdir(self.builder).join(format!("{}.tar.gz", package_name)), + } + } +} + +#[derive(Debug, Clone)] +pub struct GeneratedTarball { + path: PathBuf, +} + +impl GeneratedTarball { + pub(crate) fn tarball(&self) -> &Path { + &self.path } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 1b9523426e735..ce4274fa22e0d 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1969,7 +1969,7 @@ impl Step for Distcheck { let mut cmd = Command::new("tar"); cmd.arg("-xf") - .arg(builder.ensure(dist::PlainSourceTarball)) + .arg(builder.ensure(dist::PlainSourceTarball).tarball()) .arg("--strip-components=1") .current_dir(&dir); builder.run(&mut cmd); @@ -1992,7 +1992,10 @@ impl Step for Distcheck { t!(fs::create_dir_all(&dir)); let mut cmd = Command::new("tar"); - cmd.arg("-xf").arg(builder.ensure(dist::Src)).arg("--strip-components=1").current_dir(&dir); + cmd.arg("-xf") + .arg(builder.ensure(dist::Src).tarball()) + .arg("--strip-components=1") + .current_dir(&dir); builder.run(&mut cmd); let toml = dir.join("rust-src/lib/rustlib/src/rust/library/std/Cargo.toml"); From 13cd7680eccb3fb485e1018b9cb10b60866819a1 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 30 Dec 2020 14:00:24 +0100 Subject: [PATCH 19/73] bootstrap: use the correct paths during ./x.py install --- src/bootstrap/dist.rs | 4 +- src/bootstrap/install.rs | 106 ++++++++++++--------------------------- src/bootstrap/tarball.rs | 16 ++++-- 3 files changed, 45 insertions(+), 81 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 947ac6f1ee0eb..871a175091319 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1323,10 +1323,10 @@ impl Step for Extended { } let tarball = Tarball::new(builder, "rust", &target.triple); - let work = tarball.work_dir(); - tarball.combine(&tarballs); + let generated = tarball.combine(&tarballs); let tmp = tmpdir(builder).join("combined-tarball"); + let work = generated.work_dir(); let mut license = String::new(); license += &builder.read(&builder.src.join("COPYRIGHT")); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 8f2b128b3688e..96164947943ba 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -10,60 +10,19 @@ use std::process::Command; use build_helper::t; -use crate::dist::{self, pkgname, sanitize_sh, tmpdir}; +use crate::dist::{self, sanitize_sh}; +use crate::tarball::GeneratedTarball; use crate::Compiler; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::config::{Config, TargetSelection}; -pub fn install_docs(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "docs", "rust-docs", stage, Some(host)); -} - -pub fn install_std(builder: &Builder<'_>, stage: u32, target: TargetSelection) { - install_sh(builder, "std", "rust-std", stage, Some(target)); -} - -pub fn install_cargo(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "cargo", "cargo", stage, Some(host)); -} - -pub fn install_rls(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "rls", "rls", stage, Some(host)); -} - -pub fn install_rust_analyzer(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "rust-analyzer", "rust-analyzer", stage, Some(host)); -} - -pub fn install_clippy(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "clippy", "clippy", stage, Some(host)); -} -pub fn install_miri(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "miri", "miri", stage, Some(host)); -} - -pub fn install_rustfmt(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "rustfmt", "rustfmt", stage, Some(host)); -} - -pub fn install_analysis(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "analysis", "rust-analysis", stage, Some(host)); -} - -pub fn install_src(builder: &Builder<'_>, stage: u32) { - install_sh(builder, "src", "rust-src", stage, None); -} -pub fn install_rustc(builder: &Builder<'_>, stage: u32, host: TargetSelection) { - install_sh(builder, "rustc", "rustc", stage, Some(host)); -} - fn install_sh( builder: &Builder<'_>, package: &str, - name: &str, stage: u32, host: Option, + tarball: &GeneratedTarball, ) { builder.info(&format!("Install {} stage{} ({:?})", package, stage, host)); @@ -108,15 +67,10 @@ fn install_sh( let empty_dir = builder.out.join("tmp/empty_dir"); t!(fs::create_dir_all(&empty_dir)); - let package_name = if let Some(host) = host { - format!("{}-{}", pkgname(builder, name), host.triple) - } else { - pkgname(builder, name) - }; let mut cmd = Command::new("sh"); cmd.current_dir(&empty_dir) - .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh"))) + .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"))) .arg(format!("--prefix={}", sanitize_sh(&prefix))) .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir))) .arg(format!("--datadir={}", sanitize_sh(&datadir))) @@ -191,25 +145,25 @@ macro_rules! install { install!((self, builder, _config), Docs, "src/doc", _config.docs, only_hosts: false, { - builder.ensure(dist::Docs { host: self.target }); - install_docs(builder, self.compiler.stage, self.target); + let tarball = builder.ensure(dist::Docs { host: self.target }).expect("missing docs"); + install_sh(builder, "docs", self.compiler.stage, Some(self.target), &tarball); }; Std, "library/std", true, only_hosts: false, { for target in &builder.targets { - builder.ensure(dist::Std { + let tarball = builder.ensure(dist::Std { compiler: self.compiler, target: *target - }); - install_std(builder, self.compiler.stage, *target); + }).expect("missing std"); + install_sh(builder, "std", self.compiler.stage, Some(*target), &tarball); } }; Cargo, "cargo", Self::should_build(_config), only_hosts: true, { - builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target }); - install_cargo(builder, self.compiler.stage, self.target); + let tarball = builder.ensure(dist::Cargo { compiler: self.compiler, target: self.target }); + install_sh(builder, "cargo", self.compiler.stage, Some(self.target), &tarball); }; Rls, "rls", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }).is_some() { - install_rls(builder, self.compiler.stage, self.target); + if let Some(tarball) = builder.ensure(dist::Rls { compiler: self.compiler, target: self.target }) { + install_sh(builder, "rls", self.compiler.stage, Some(self.target), &tarball); } else { builder.info( &format!("skipping Install RLS stage{} ({})", self.compiler.stage, self.target), @@ -217,16 +171,18 @@ install!((self, builder, _config), } }; RustAnalyzer, "rust-analyzer", Self::should_build(_config), only_hosts: true, { - builder.ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target }); - install_rust_analyzer(builder, self.compiler.stage, self.target); + let tarball = builder + .ensure(dist::RustAnalyzer { compiler: self.compiler, target: self.target }) + .expect("missing rust-analyzer"); + install_sh(builder, "rust-analyzer", self.compiler.stage, Some(self.target), &tarball); }; Clippy, "clippy", Self::should_build(_config), only_hosts: true, { - builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target }); - install_clippy(builder, self.compiler.stage, self.target); + let tarball = builder.ensure(dist::Clippy { compiler: self.compiler, target: self.target }); + install_sh(builder, "clippy", self.compiler.stage, Some(self.target), &tarball); }; Miri, "miri", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }).is_some() { - install_miri(builder, self.compiler.stage, self.target); + if let Some(tarball) = builder.ensure(dist::Miri { compiler: self.compiler, target: self.target }) { + install_sh(builder, "miri", self.compiler.stage, Some(self.target), &tarball); } else { builder.info( &format!("skipping Install miri stage{} ({})", self.compiler.stage, self.target), @@ -234,11 +190,11 @@ install!((self, builder, _config), } }; Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, { - if builder.ensure(dist::Rustfmt { + if let Some(tarball) = builder.ensure(dist::Rustfmt { compiler: self.compiler, target: self.target - }).is_some() { - install_rustfmt(builder, self.compiler.stage, self.target); + }) { + install_sh(builder, "rustfmt", self.compiler.stage, Some(self.target), &tarball); } else { builder.info( &format!("skipping Install Rustfmt stage{} ({})", self.compiler.stage, self.target), @@ -246,20 +202,20 @@ install!((self, builder, _config), } }; Analysis, "analysis", Self::should_build(_config), only_hosts: false, { - builder.ensure(dist::Analysis { + let tarball = builder.ensure(dist::Analysis { // Find the actual compiler (handling the full bootstrap option) which // produced the save-analysis data because that data isn't copied // through the sysroot uplifting. compiler: builder.compiler_for(builder.top_stage, builder.config.build, self.target), target: self.target - }); - install_analysis(builder, self.compiler.stage, self.target); + }).expect("missing analysis"); + install_sh(builder, "analysis", self.compiler.stage, Some(self.target), &tarball); }; Rustc, "src/librustc", true, only_hosts: true, { - builder.ensure(dist::Rustc { + let tarball = builder.ensure(dist::Rustc { compiler: builder.compiler(builder.top_stage, self.target), }); - install_rustc(builder, self.compiler.stage, self.target); + install_sh(builder, "rustc", self.compiler.stage, Some(self.target), &tarball); }; ); @@ -284,7 +240,7 @@ impl Step for Src { } fn run(self, builder: &Builder<'_>) { - builder.ensure(dist::Src); - install_src(builder, self.stage); + let tarball = builder.ensure(dist::Src); + install_sh(builder, "src", self.stage, None, &tarball); } } diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 482ca40c5c1ff..9cfe12359dc25 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -196,10 +196,6 @@ impl<'a> Tarball<'a> { self.builder.cp_r(src.as_ref(), &dest); } - pub(crate) fn work_dir(&self) -> PathBuf { - self.temp_dir.clone() - } - pub(crate) fn generate(self) -> GeneratedTarball { let mut component_name = self.component.clone(); if self.is_preview { @@ -295,6 +291,8 @@ impl<'a> Tarball<'a> { GeneratedTarball { path: crate::dist::distdir(self.builder).join(format!("{}.tar.gz", package_name)), + decompressed_output: self.temp_dir.join(package_name), + work: self.temp_dir, } } } @@ -302,10 +300,20 @@ impl<'a> Tarball<'a> { #[derive(Debug, Clone)] pub struct GeneratedTarball { path: PathBuf, + decompressed_output: PathBuf, + work: PathBuf, } impl GeneratedTarball { pub(crate) fn tarball(&self) -> &Path { &self.path } + + pub(crate) fn decompressed_output(&self) -> &Path { + &self.decompressed_output + } + + pub(crate) fn work_dir(&self) -> &Path { + &self.work + } } From 4050e2796e1cf3ba53dfd2c2fd095d29e43652b6 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Thu, 7 Jan 2021 19:59:24 +0100 Subject: [PATCH 20/73] bootstrap: fix x.py install not working with relative prefix --- src/bootstrap/install.rs | 99 ++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 96164947943ba..fd0acc3a919b0 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -5,7 +5,7 @@ use std::env; use std::fs; -use std::path::{Component, Path, PathBuf}; +use std::path::{Component, PathBuf}; use std::process::Command; use build_helper::t; @@ -26,74 +26,63 @@ fn install_sh( ) { builder.info(&format!("Install {} stage{} ({:?})", package, stage, host)); - let prefix_default = PathBuf::from("/usr/local"); - let sysconfdir_default = PathBuf::from("/etc"); - let datadir_default = PathBuf::from("share"); - let docdir_default = datadir_default.join("doc/rust"); - let libdir_default = PathBuf::from("lib"); - let mandir_default = datadir_default.join("man"); - let prefix = builder.config.prefix.as_ref().unwrap_or(&prefix_default); - let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); - let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default); - let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default); - let bindir = &builder.config.bindir; - let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default); - let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default); - - let sysconfdir = prefix.join(sysconfdir); - let datadir = prefix.join(datadir); - let docdir = prefix.join(docdir); - let bindir = prefix.join(bindir); - let libdir = prefix.join(libdir); - let mandir = prefix.join(mandir); - - let destdir = env::var_os("DESTDIR").map(PathBuf::from); - - let prefix = add_destdir(&prefix, &destdir); - let sysconfdir = add_destdir(&sysconfdir, &destdir); - let datadir = add_destdir(&datadir, &destdir); - let docdir = add_destdir(&docdir, &destdir); - let bindir = add_destdir(&bindir, &destdir); - let libdir = add_destdir(&libdir, &destdir); - let mandir = add_destdir(&mandir, &destdir); - - let prefix = { - fs::create_dir_all(&prefix) - .unwrap_or_else(|err| panic!("could not create {}: {}", prefix.display(), err)); - fs::canonicalize(&prefix) - .unwrap_or_else(|err| panic!("could not canonicalize {}: {}", prefix.display(), err)) - }; + let prefix = default_path(&builder.config.prefix, "/usr/local"); + let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); + let datadir = prefix.join(default_path(&builder.config.datadir, "share")); + let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc")); + let mandir = prefix.join(default_path(&builder.config.mandir, "share/man")); + let libdir = prefix.join(default_path(&builder.config.libdir, "lib")); + let bindir = prefix.join(&builder.config.bindir); // Default in config.rs let empty_dir = builder.out.join("tmp/empty_dir"); - t!(fs::create_dir_all(&empty_dir)); let mut cmd = Command::new("sh"); cmd.current_dir(&empty_dir) .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"))) - .arg(format!("--prefix={}", sanitize_sh(&prefix))) - .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir))) - .arg(format!("--datadir={}", sanitize_sh(&datadir))) - .arg(format!("--docdir={}", sanitize_sh(&docdir))) - .arg(format!("--bindir={}", sanitize_sh(&bindir))) - .arg(format!("--libdir={}", sanitize_sh(&libdir))) - .arg(format!("--mandir={}", sanitize_sh(&mandir))) + .arg(format!("--prefix={}", prepare_dir(prefix))) + .arg(format!("--sysconfdir={}", prepare_dir(sysconfdir))) + .arg(format!("--datadir={}", prepare_dir(datadir))) + .arg(format!("--docdir={}", prepare_dir(docdir))) + .arg(format!("--bindir={}", prepare_dir(bindir))) + .arg(format!("--libdir={}", prepare_dir(libdir))) + .arg(format!("--mandir={}", prepare_dir(mandir))) .arg("--disable-ldconfig"); builder.run(&mut cmd); t!(fs::remove_dir_all(&empty_dir)); } -fn add_destdir(path: &Path, destdir: &Option) -> PathBuf { - let mut ret = match *destdir { - Some(ref dest) => dest.clone(), - None => return path.to_path_buf(), - }; - for part in path.components() { - if let Component::Normal(s) = part { - ret.push(s) +fn default_path(config: &Option, default: &str) -> PathBuf { + PathBuf::from(config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))) +} + +fn prepare_dir(mut path: PathBuf) -> String { + // The DESTDIR environment variable is a standard way to install software in a subdirectory + // while keeping the original directory structure, even if the prefix or other directories + // contain absolute paths. + // + // More information on the environment variable is available here: + // https://www.gnu.org/prep/standards/html_node/DESTDIR.html + if let Some(destdir) = env::var_os("DESTDIR").map(PathBuf::from) { + let without_destdir = path.clone(); + path = destdir; + // Custom .join() which ignores disk roots. + for part in without_destdir.components() { + if let Component::Normal(s) = part { + path.push(s) + } } } - ret + + // The installation command is not executed from the current directory, but from a temporary + // directory. To prevent relative paths from breaking this converts relative paths to absolute + // paths. std::fs::canonicalize is not used as that requires the path to actually be present. + if path.is_relative() { + path = std::env::current_dir().expect("failed to get the current directory").join(path); + assert!(path.is_absolute(), "could not make the path relative"); + } + + sanitize_sh(&path) } macro_rules! install { From 96a00a96bdbac954ea3bd39cbade4b02b30c1986 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 4 Jan 2021 07:18:37 -0800 Subject: [PATCH 21/73] Update mdbook --- Cargo.lock | 4 ++-- src/tools/rustbook/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4676e4127e83c..89ac858a61bf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1973,9 +1973,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff" +checksum = "21251d3eb9ca5e8ac5b73384ddaa483a9bbc7d7dcd656b1fa8f266634810334a" dependencies = [ "ammonia", "anyhow", diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 99310157a64fe..8e17f2919082b 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -10,6 +10,6 @@ clap = "2.25.0" env_logger = "0.7.1" [dependencies.mdbook] -version = "0.4.3" +version = "0.4.5" default-features = false features = ["search"] From 5a4852a113b234cb682ade697745320a77288363 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Dec 2020 11:48:12 -0800 Subject: [PATCH 22/73] rustdoc: Render visibilities succinctly --- src/librustdoc/clean/mod.rs | 4 +-- src/librustdoc/html/format.rs | 13 ++++++++-- src/librustdoc/html/render/mod.rs | 43 ++++++++++++++++++------------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dd96178cdb700..24c689012b031 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2315,14 +2315,14 @@ impl Clean for (&hir::MacroDef<'_>, Option) { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", - vis.print_with_space(cx.tcx), + vis.print_with_space(cx.tcx, item.hir_id.owner), name, matchers.iter().map(|span| span.to_src(cx)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", - vis.print_with_space(cx.tcx), + vis.print_with_space(cx.tcx, item.hir_id.owner), name, matchers .iter() diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7b0b219570b98..bd5f5a3c6cc88 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -12,7 +12,7 @@ use std::fmt; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; use rustc_target::spec::abi::Abi; use crate::clean::{self, PrimitiveType}; @@ -1085,12 +1085,21 @@ impl Function<'_> { } impl clean::Visibility { - crate fn print_with_space<'tcx>(self, tcx: TyCtxt<'tcx>) -> impl fmt::Display + 'tcx { + crate fn print_with_space<'tcx>( + self, + tcx: TyCtxt<'tcx>, + item_did: LocalDefId, + ) -> impl fmt::Display + 'tcx { use rustc_span::symbol::kw; display_fn(move |f| match self { clean::Public => f.write_str("pub "), clean::Inherited => Ok(()), + clean::Visibility::Restricted(did) + if did.index == tcx.parent_module_from_def_id(item_did).local_def_index => + { + Ok(()) + } clean::Visibility::Restricted(did) if did.index == CRATE_DEF_INDEX => { write!(f, "pub(crate) ") } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 185df60735fd4..0ae32f4d27d20 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2157,14 +2157,14 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl Some(ref src) => write!( w, "{}extern crate {} as {};", - myitem.visibility.print_with_space(cx.tcx()), + myitem.visibility.print_with_space(cx.tcx(), myitem.def_id.expect_local()), anchor(myitem.def_id, &*src.as_str()), name ), None => write!( w, "{}extern crate {};", - myitem.visibility.print_with_space(cx.tcx()), + myitem.visibility.print_with_space(cx.tcx(), myitem.def_id.expect_local()), anchor(myitem.def_id, &*name.as_str()) ), } @@ -2175,7 +2175,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl write!( w, "{}{}", - myitem.visibility.print_with_space(cx.tcx()), + myitem.visibility.print_with_space(cx.tcx(), myitem.def_id.expect_local()), import.print() ); } @@ -2392,7 +2392,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean:: write!( w, "{vis}const {name}: {typ}", - vis = it.visibility.print_with_space(cx.tcx()), + vis = it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), name = it.name.as_ref().unwrap(), typ = c.type_.print(), ); @@ -2426,7 +2426,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St write!( w, "{vis}static {mutability}{name}: {typ}", - vis = it.visibility.print_with_space(cx.tcx()), + vis = it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), typ = s.type_.print() @@ -2437,7 +2437,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { let header_len = format!( "{}{}{}{}{:#}fn {}{:#}", - it.visibility.print_with_space(cx.tcx()), + it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), f.header.constness.print_with_space(), f.header.asyncness.print_with_space(), f.header.unsafety.print_with_space(), @@ -2452,7 +2452,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: w, "{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{spotlight}{where_clause}", - vis = it.visibility.print_with_space(cx.tcx()), + vis = it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), constness = f.header.constness.print_with_space(), asyncness = f.header.asyncness.print_with_space(), unsafety = f.header.unsafety.print_with_space(), @@ -2578,7 +2578,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra write!( w, "{}{}{}trait {}{}{}", - it.visibility.print_with_space(cx.tcx()), + it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), t.unsafety.print_with_space(), if t.is_auto { "auto " } else { "" }, it.name.as_ref().unwrap(), @@ -2896,7 +2896,7 @@ fn assoc_const( w, "{}{}const {}: {}", extra, - it.visibility.print_with_space(cx.tcx()), + it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), naive_assoc_href(it, link), it.name.as_ref().unwrap(), ty.print() @@ -3015,7 +3015,7 @@ fn render_assoc_item( }; let mut header_len = format!( "{}{}{}{}{}{:#}fn {}{:#}", - meth.visibility.print_with_space(cx.tcx()), + meth.visibility.print_with_space(cx.tcx(), meth.def_id.expect_local()), header.constness.print_with_space(), header.asyncness.print_with_space(), header.unsafety.print_with_space(), @@ -3037,7 +3037,7 @@ fn render_assoc_item( "{}{}{}{}{}{}{}fn {name}\ {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, - meth.visibility.print_with_space(cx.tcx()), + meth.visibility.print_with_space(cx.tcx(), meth.def_id.expect_local()), header.constness.print_with_space(), header.asyncness.print_with_space(), header.unsafety.print_with_space(), @@ -3189,7 +3189,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum write!( w, "{}enum {}{}{}", - it.visibility.print_with_space(cx.tcx()), + it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), it.name.as_ref().unwrap(), e.generics.print(), WhereClause { gens: &e.generics, indent: 0, end_newline: true } @@ -3364,7 +3364,7 @@ fn render_struct( write!( w, "{}{}{}", - it.visibility.print_with_space(cx.tcx()), + it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), if structhead { "struct " } else { "" }, it.name.as_ref().unwrap() ); @@ -3384,7 +3384,7 @@ fn render_struct( w, "\n{} {}{}: {},", tab, - field.visibility.print_with_space(cx.tcx()), + field.visibility.print_with_space(cx.tcx(), field.def_id.expect_local()), field.name.as_ref().unwrap(), ty.print() ); @@ -3413,7 +3413,14 @@ fn render_struct( match field.kind { clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"), clean::StructFieldItem(ref ty) => { - write!(w, "{}{}", field.visibility.print_with_space(cx.tcx()), ty.print()) + write!( + w, + "{}{}", + field + .visibility + .print_with_space(cx.tcx(), field.def_id.expect_local()), + ty.print() + ) } _ => unreachable!(), } @@ -3446,7 +3453,7 @@ fn render_union( write!( w, "{}{}{}", - it.visibility.print_with_space(cx.tcx()), + it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), if structhead { "union " } else { "" }, it.name.as_ref().unwrap() ); @@ -3461,7 +3468,7 @@ fn render_union( write!( w, " {}{}: {},\n{}", - field.visibility.print_with_space(cx.tcx()), + field.visibility.print_with_space(cx.tcx(), field.def_id.expect_local()), field.name.as_ref().unwrap(), ty.print(), tab @@ -4100,7 +4107,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache: write!( w, " {}type {};\n}}", - it.visibility.print_with_space(cx.tcx()), + it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), it.name.as_ref().unwrap(), ); From 9c4494c60d247c12a064ae55775317f702b6a72c Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Dec 2020 15:38:46 -0800 Subject: [PATCH 23/73] Fix bugs; fix and add tests --- src/librustdoc/clean/mod.rs | 10 +++- src/librustdoc/clean/utils.rs | 24 +++++++- src/librustdoc/html/format.rs | 56 ++++++++++--------- src/librustdoc/html/render/mod.rs | 38 ++++++------- .../passes/collect_intra_doc_links.rs | 22 +------- src/test/rustdoc/decl_macro_priv.rs | 2 +- src/test/rustdoc/pub-restricted.rs | 32 +++++------ src/test/rustdoc/visibility.rs | 13 +++++ 8 files changed, 110 insertions(+), 87 deletions(-) create mode 100644 src/test/rustdoc/visibility.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 24c689012b031..33a891da7464e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2315,14 +2315,20 @@ impl Clean for (&hir::MacroDef<'_>, Option) { if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", - vis.print_with_space(cx.tcx, item.hir_id.owner), + vis.print_with_space( + cx.tcx, + cx.tcx.hir().local_def_id(item.hir_id).to_def_id() + ), name, matchers.iter().map(|span| span.to_src(cx)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", - vis.print_with_space(cx.tcx, item.hir_id.owner), + vis.print_with_space( + cx.tcx, + cx.tcx.hir().local_def_id(item.hir_id).to_def_id() + ), name, matchers .iter() diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 270321aaa1188..fe1b58164474a 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; @@ -624,3 +624,25 @@ where *cx.impl_trait_bounds.borrow_mut() = old_bounds; r } + +crate fn find_closest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + let mut current = def_id; + // The immediate parent might not always be a module. + // Find the first parent which is. + loop { + if let Some(parent) = tcx.parent(current) { + if tcx.def_kind(parent) == DefKind::Mod { + break Some(parent); + } + current = parent; + } else { + debug!( + "{:?} has no parent (kind={:?}, original was {:?})", + current, + tcx.def_kind(current), + def_id + ); + break None; + } + } +} diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index bd5f5a3c6cc88..6a611ccf58ec0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -12,10 +12,10 @@ use std::fmt; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; +use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_target::spec::abi::Abi; -use crate::clean::{self, PrimitiveType}; +use crate::clean::{self, utils::find_closest_parent_module, PrimitiveType}; use crate::formats::cache::cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; @@ -1088,38 +1088,40 @@ impl clean::Visibility { crate fn print_with_space<'tcx>( self, tcx: TyCtxt<'tcx>, - item_did: LocalDefId, + item_did: DefId, ) -> impl fmt::Display + 'tcx { use rustc_span::symbol::kw; display_fn(move |f| match self { clean::Public => f.write_str("pub "), clean::Inherited => Ok(()), - clean::Visibility::Restricted(did) - if did.index == tcx.parent_module_from_def_id(item_did).local_def_index => - { - Ok(()) - } - clean::Visibility::Restricted(did) if did.index == CRATE_DEF_INDEX => { - write!(f, "pub(crate) ") - } - clean::Visibility::Restricted(did) => { - f.write_str("pub(")?; - let path = tcx.def_path(did); - debug!("path={:?}", path); - let first_name = - path.data[0].data.get_opt_name().expect("modules are always named"); - if path.data.len() != 1 || (first_name != kw::SelfLower && first_name != kw::Super) - { - f.write_str("in ")?; - } - // modified from `resolved_path()` to work with `DefPathData` - let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); - for seg in &path.data[..path.data.len() - 1] { - write!(f, "{}::", seg.data.get_opt_name().unwrap())?; + + clean::Visibility::Restricted(vis_did) => { + if find_closest_parent_module(tcx, item_did) == Some(vis_did) { + // `pub(in foo)` where `foo` is the parent module + // is the same as no visibility modifier + Ok(()) + } else if vis_did.index == CRATE_DEF_INDEX { + write!(f, "pub(crate) ") + } else { + f.write_str("pub(")?; + let path = tcx.def_path(vis_did); + debug!("path={:?}", path); + let first_name = + path.data[0].data.get_opt_name().expect("modules are always named"); + if path.data.len() != 1 + || (first_name != kw::SelfLower && first_name != kw::Super) + { + f.write_str("in ")?; + } + // modified from `resolved_path()` to work with `DefPathData` + let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); + for seg in &path.data[..path.data.len() - 1] { + write!(f, "{}::", seg.data.get_opt_name().unwrap())?; + } + let path = anchor(vis_did, &last_name.as_str()).to_string(); + write!(f, "{}) ", path) } - let path = anchor(did, &last_name.as_str()).to_string(); - write!(f, "{}) ", path) } }) } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 0ae32f4d27d20..be2275aa7a7a4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2157,14 +2157,14 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl Some(ref src) => write!( w, "{}extern crate {} as {};", - myitem.visibility.print_with_space(cx.tcx(), myitem.def_id.expect_local()), + myitem.visibility.print_with_space(cx.tcx(), myitem.def_id), anchor(myitem.def_id, &*src.as_str()), name ), None => write!( w, "{}extern crate {};", - myitem.visibility.print_with_space(cx.tcx(), myitem.def_id.expect_local()), + myitem.visibility.print_with_space(cx.tcx(), myitem.def_id), anchor(myitem.def_id, &*name.as_str()) ), } @@ -2175,7 +2175,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl write!( w, "{}{}", - myitem.visibility.print_with_space(cx.tcx(), myitem.def_id.expect_local()), + myitem.visibility.print_with_space(cx.tcx(), myitem.def_id), import.print() ); } @@ -2392,7 +2392,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean:: write!( w, "{vis}const {name}: {typ}", - vis = it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + vis = it.visibility.print_with_space(cx.tcx(), it.def_id), name = it.name.as_ref().unwrap(), typ = c.type_.print(), ); @@ -2426,7 +2426,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St write!( w, "{vis}static {mutability}{name}: {typ}", - vis = it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + vis = it.visibility.print_with_space(cx.tcx(), it.def_id), mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), typ = s.type_.print() @@ -2437,7 +2437,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { let header_len = format!( "{}{}{}{}{:#}fn {}{:#}", - it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + it.visibility.print_with_space(cx.tcx(), it.def_id), f.header.constness.print_with_space(), f.header.asyncness.print_with_space(), f.header.unsafety.print_with_space(), @@ -2452,7 +2452,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean:: w, "{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{spotlight}{where_clause}", - vis = it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + vis = it.visibility.print_with_space(cx.tcx(), it.def_id), constness = f.header.constness.print_with_space(), asyncness = f.header.asyncness.print_with_space(), unsafety = f.header.unsafety.print_with_space(), @@ -2578,7 +2578,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra write!( w, "{}{}{}trait {}{}{}", - it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + it.visibility.print_with_space(cx.tcx(), it.def_id), t.unsafety.print_with_space(), if t.is_auto { "auto " } else { "" }, it.name.as_ref().unwrap(), @@ -2896,7 +2896,7 @@ fn assoc_const( w, "{}{}const {}: {}", extra, - it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + it.visibility.print_with_space(cx.tcx(), it.def_id), naive_assoc_href(it, link), it.name.as_ref().unwrap(), ty.print() @@ -3015,7 +3015,7 @@ fn render_assoc_item( }; let mut header_len = format!( "{}{}{}{}{}{:#}fn {}{:#}", - meth.visibility.print_with_space(cx.tcx(), meth.def_id.expect_local()), + meth.visibility.print_with_space(cx.tcx(), meth.def_id), header.constness.print_with_space(), header.asyncness.print_with_space(), header.unsafety.print_with_space(), @@ -3037,7 +3037,7 @@ fn render_assoc_item( "{}{}{}{}{}{}{}fn {name}\ {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, - meth.visibility.print_with_space(cx.tcx(), meth.def_id.expect_local()), + meth.visibility.print_with_space(cx.tcx(), meth.def_id), header.constness.print_with_space(), header.asyncness.print_with_space(), header.unsafety.print_with_space(), @@ -3189,7 +3189,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum write!( w, "{}enum {}{}{}", - it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + it.visibility.print_with_space(cx.tcx(), it.def_id), it.name.as_ref().unwrap(), e.generics.print(), WhereClause { gens: &e.generics, indent: 0, end_newline: true } @@ -3364,7 +3364,7 @@ fn render_struct( write!( w, "{}{}{}", - it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + it.visibility.print_with_space(cx.tcx(), it.def_id), if structhead { "struct " } else { "" }, it.name.as_ref().unwrap() ); @@ -3384,7 +3384,7 @@ fn render_struct( w, "\n{} {}{}: {},", tab, - field.visibility.print_with_space(cx.tcx(), field.def_id.expect_local()), + field.visibility.print_with_space(cx.tcx(), field.def_id), field.name.as_ref().unwrap(), ty.print() ); @@ -3416,9 +3416,7 @@ fn render_struct( write!( w, "{}{}", - field - .visibility - .print_with_space(cx.tcx(), field.def_id.expect_local()), + field.visibility.print_with_space(cx.tcx(), field.def_id), ty.print() ) } @@ -3453,7 +3451,7 @@ fn render_union( write!( w, "{}{}{}", - it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + it.visibility.print_with_space(cx.tcx(), it.def_id), if structhead { "union " } else { "" }, it.name.as_ref().unwrap() ); @@ -3468,7 +3466,7 @@ fn render_union( write!( w, " {}{}: {},\n{}", - field.visibility.print_with_space(cx.tcx(), field.def_id.expect_local()), + field.visibility.print_with_space(cx.tcx(), field.def_id), field.name.as_ref().unwrap(), ty.print(), tab @@ -4107,7 +4105,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, cache: write!( w, " {}type {};\n}}", - it.visibility.print_with_space(cx.tcx(), it.def_id.expect_local()), + it.visibility.print_with_space(cx.tcx(), it.def_id), it.name.as_ref().unwrap(), ); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a8adfe08b2561..f392f321fbfc3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -31,7 +31,7 @@ use std::cell::Cell; use std::mem; use std::ops::Range; -use crate::clean::{self, Crate, Item, ItemLink, PrimitiveType}; +use crate::clean::{self, utils::find_closest_parent_module, Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::markdown_links; @@ -774,25 +774,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } else if item.def_id.is_top_level_module() { Some(item.def_id) } else { - let mut current = item.def_id; - // The immediate parent might not always be a module. - // Find the first parent which is. - loop { - if let Some(parent) = self.cx.tcx.parent(current) { - if self.cx.tcx.def_kind(parent) == DefKind::Mod { - break Some(parent); - } - current = parent; - } else { - debug!( - "{:?} has no parent (kind={:?}, original was {:?})", - current, - self.cx.tcx.def_kind(current), - item.def_id - ); - break None; - } - } + find_closest_parent_module(self.cx.tcx, item.def_id) }; if parent_node.is_some() { diff --git a/src/test/rustdoc/decl_macro_priv.rs b/src/test/rustdoc/decl_macro_priv.rs index 4e1279e34d933..cb71bca9cf201 100644 --- a/src/test/rustdoc/decl_macro_priv.rs +++ b/src/test/rustdoc/decl_macro_priv.rs @@ -2,7 +2,7 @@ #![feature(decl_macro)] -// @has decl_macro_priv/macro.crate_macro.html //pre 'pub(crate) macro crate_macro() {' +// @has decl_macro_priv/macro.crate_macro.html //pre 'macro crate_macro() {' // @has - //pre '...' // @has - //pre '}' pub(crate) macro crate_macro() {} diff --git a/src/test/rustdoc/pub-restricted.rs b/src/test/rustdoc/pub-restricted.rs index 6720d848ac3b5..9ff3cad070d82 100644 --- a/src/test/rustdoc/pub-restricted.rs +++ b/src/test/rustdoc/pub-restricted.rs @@ -6,27 +6,27 @@ // @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic' pub struct FooPublic; -// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate' +// @has 'foo/struct.FooJustCrate.html' '//pre' 'struct FooJustCrate' crate struct FooJustCrate; -// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate' +// @has 'foo/struct.FooPubCrate.html' '//pre' 'struct FooPubCrate' pub(crate) struct FooPubCrate; -// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf' +// @has 'foo/struct.FooSelf.html' '//pre' 'struct FooSelf' pub(self) struct FooSelf; -// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf' +// @has 'foo/struct.FooInSelf.html' '//pre' 'struct FooInSelf' pub(in self) struct FooInSelf; mod a { - // @has 'foo/a/struct.FooSuper.html' '//pre' 'pub(crate) struct FooSuper' - pub(super) struct FooSuper; - // @has 'foo/a/struct.FooInSuper.html' '//pre' 'pub(crate) struct FooInSuper' - pub(in super) struct FooInSuper; - // @has 'foo/a/struct.FooInA.html' '//pre' 'pub(in a) struct FooInA' - pub(in a) struct FooInA; + // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper' + pub(super) struct FooASuper; + // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper' + pub(in super) struct FooAInSuper; + // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA' + pub(in a) struct FooAInA; mod b { - // @has 'foo/a/b/struct.FooInSelfSuperB.html' '//pre' 'pub(in a::b) struct FooInSelfSuperB' - pub(in a::b) struct FooInSelfSuperB; - // @has 'foo/a/b/struct.FooInSuperSuper.html' '//pre' 'pub(crate) struct FooInSuperSuper' - pub(in super::super) struct FooInSuperSuper; - // @has 'foo/a/b/struct.FooInAB.html' '//pre' 'pub(in a::b) struct FooInAB' - pub(in a::b) struct FooInAB; + // @has 'foo/a/b/struct.FooBSuper.html' '//pre' 'pub(super) struct FooBSuper' + pub(super) struct FooBSuper; + // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper' + pub(in super::super) struct FooBInSuperSuper; + // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB' + pub(in a::b) struct FooBInAB; } } diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs new file mode 100644 index 0000000000000..9dd0b68b1d95e --- /dev/null +++ b/src/test/rustdoc/visibility.rs @@ -0,0 +1,13 @@ +// compile-flags: --document-private-items + +#![crate_name = "foo"] + +// @has 'foo/fn.foo.html' '//pre' 'fn foo' +// !@has 'foo/fn.foo.html' '//pre' 'pub' +fn foo() {} + +mod bar { + // @has 'foo/bar/fn.baz.html' '//pre' 'fn baz' + // !@has 'foo/bar/fn.baz.html' '//pre' 'pub' + fn baz() {} +} From 2ea0fa53a74050994a153f169ff31cdb36160676 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Dec 2020 15:54:04 -0800 Subject: [PATCH 24/73] Handle `pub(super)` --- src/librustdoc/html/format.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 6a611ccf58ec0..a8eae52fc565e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1097,12 +1097,20 @@ impl clean::Visibility { clean::Inherited => Ok(()), clean::Visibility::Restricted(vis_did) => { - if find_closest_parent_module(tcx, item_did) == Some(vis_did) { + let parent_module = find_closest_parent_module(tcx, item_did); + + if parent_module == Some(vis_did) { // `pub(in foo)` where `foo` is the parent module // is the same as no visibility modifier Ok(()) } else if vis_did.index == CRATE_DEF_INDEX { write!(f, "pub(crate) ") + } else if parent_module + .map(|parent| find_closest_parent_module(tcx, parent)) + .flatten() + == Some(vis_did) + { + write!(f, "pub(super) ") } else { f.write_str("pub(")?; let path = tcx.def_path(vis_did); From 76d26036ae72239f8a497503d03f072ad3ce911f Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Dec 2020 16:16:40 -0800 Subject: [PATCH 25/73] Prefer `pub(crate)` over no modifier --- src/librustdoc/html/format.rs | 6 +++--- src/test/rustdoc/decl_macro_priv.rs | 2 +- src/test/rustdoc/pub-restricted.rs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a8eae52fc565e..90f4aaefc9bc1 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1099,12 +1099,12 @@ impl clean::Visibility { clean::Visibility::Restricted(vis_did) => { let parent_module = find_closest_parent_module(tcx, item_did); - if parent_module == Some(vis_did) { + if vis_did.index == CRATE_DEF_INDEX { + write!(f, "pub(crate) ") + } else if parent_module == Some(vis_did) { // `pub(in foo)` where `foo` is the parent module // is the same as no visibility modifier Ok(()) - } else if vis_did.index == CRATE_DEF_INDEX { - write!(f, "pub(crate) ") } else if parent_module .map(|parent| find_closest_parent_module(tcx, parent)) .flatten() diff --git a/src/test/rustdoc/decl_macro_priv.rs b/src/test/rustdoc/decl_macro_priv.rs index cb71bca9cf201..4e1279e34d933 100644 --- a/src/test/rustdoc/decl_macro_priv.rs +++ b/src/test/rustdoc/decl_macro_priv.rs @@ -2,7 +2,7 @@ #![feature(decl_macro)] -// @has decl_macro_priv/macro.crate_macro.html //pre 'macro crate_macro() {' +// @has decl_macro_priv/macro.crate_macro.html //pre 'pub(crate) macro crate_macro() {' // @has - //pre '...' // @has - //pre '}' pub(crate) macro crate_macro() {} diff --git a/src/test/rustdoc/pub-restricted.rs b/src/test/rustdoc/pub-restricted.rs index 9ff3cad070d82..f828e642abdca 100644 --- a/src/test/rustdoc/pub-restricted.rs +++ b/src/test/rustdoc/pub-restricted.rs @@ -6,13 +6,13 @@ // @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic' pub struct FooPublic; -// @has 'foo/struct.FooJustCrate.html' '//pre' 'struct FooJustCrate' +// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate' crate struct FooJustCrate; -// @has 'foo/struct.FooPubCrate.html' '//pre' 'struct FooPubCrate' +// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate' pub(crate) struct FooPubCrate; -// @has 'foo/struct.FooSelf.html' '//pre' 'struct FooSelf' +// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf' pub(self) struct FooSelf; -// @has 'foo/struct.FooInSelf.html' '//pre' 'struct FooInSelf' +// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf' pub(in self) struct FooInSelf; mod a { // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper' From c73576a22a0c9dc777709e9a753a5c2883339398 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Dec 2020 16:27:56 -0800 Subject: [PATCH 26/73] Merge `pub-restricted` and `visibility` test --- src/test/rustdoc/pub-restricted.rs | 32 ----------------------- src/test/rustdoc/visibility.rs | 41 +++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 39 deletions(-) delete mode 100644 src/test/rustdoc/pub-restricted.rs diff --git a/src/test/rustdoc/pub-restricted.rs b/src/test/rustdoc/pub-restricted.rs deleted file mode 100644 index f828e642abdca..0000000000000 --- a/src/test/rustdoc/pub-restricted.rs +++ /dev/null @@ -1,32 +0,0 @@ -// compile-flags: --document-private-items - -#![feature(crate_visibility_modifier)] - -#![crate_name = "foo"] - -// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic' -pub struct FooPublic; -// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate' -crate struct FooJustCrate; -// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate' -pub(crate) struct FooPubCrate; -// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf' -pub(self) struct FooSelf; -// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf' -pub(in self) struct FooInSelf; -mod a { - // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper' - pub(super) struct FooASuper; - // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper' - pub(in super) struct FooAInSuper; - // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA' - pub(in a) struct FooAInA; - mod b { - // @has 'foo/a/b/struct.FooBSuper.html' '//pre' 'pub(super) struct FooBSuper' - pub(super) struct FooBSuper; - // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper' - pub(in super::super) struct FooBInSuperSuper; - // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB' - pub(in a::b) struct FooBInAB; - } -} diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs index 9dd0b68b1d95e..ebb314a7941b6 100644 --- a/src/test/rustdoc/visibility.rs +++ b/src/test/rustdoc/visibility.rs @@ -1,13 +1,40 @@ // compile-flags: --document-private-items +#![feature(crate_visibility_modifier)] + #![crate_name = "foo"] -// @has 'foo/fn.foo.html' '//pre' 'fn foo' -// !@has 'foo/fn.foo.html' '//pre' 'pub' -fn foo() {} +// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic' +pub struct FooPublic; +// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate' +crate struct FooJustCrate; +// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate' +pub(crate) struct FooPubCrate; +// @has 'foo/struct.FooSelf.html' '//pre' 'pub(crate) struct FooSelf' +pub(self) struct FooSelf; +// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(crate) struct FooInSelf' +pub(in self) struct FooInSelf; +// @has 'foo/struct.FooPriv.html' '//pre' 'pub(crate) struct FooPriv' +struct FooPriv; + +mod a { + // @has 'foo/a/struct.FooASuper.html' '//pre' 'pub(crate) struct FooASuper' + pub(super) struct FooASuper; + // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper' + pub(in super) struct FooAInSuper; + // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA' + pub(in a) struct FooAInA; + // @has 'foo/a/struct.FooAPriv.html' '//pre' 'struct FooAPriv' + struct FooAPriv; -mod bar { - // @has 'foo/bar/fn.baz.html' '//pre' 'fn baz' - // !@has 'foo/bar/fn.baz.html' '//pre' 'pub' - fn baz() {} + mod b { + // @has 'foo/a/b/struct.FooBSuper.html' '//pre' 'pub(super) struct FooBSuper' + pub(super) struct FooBSuper; + // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper' + pub(in super::super) struct FooBInSuperSuper; + // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB' + pub(in a::b) struct FooBInAB; + // @has 'foo/a/b/struct.FooBPriv.html' '//pre' 'struct FooBPriv' + struct FooBPriv; + } } From c7a85ca05d0de86e48417209de46c3b2815a60ef Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Dec 2020 16:33:15 -0800 Subject: [PATCH 27/73] Add missing code to `find_closest_parent_module` --- src/librustdoc/clean/utils.rs | 40 +++++++++++-------- .../passes/collect_intra_doc_links.rs | 10 +---- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index fe1b58164474a..4b9541b7e1421 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -626,23 +626,31 @@ where } crate fn find_closest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - let mut current = def_id; - // The immediate parent might not always be a module. - // Find the first parent which is. - loop { - if let Some(parent) = tcx.parent(current) { - if tcx.def_kind(parent) == DefKind::Mod { - break Some(parent); + if item.is_fake() { + // FIXME: is this correct? + None + // If we're documenting the crate root itself, it has no parent. Use the root instead. + } else if item.def_id.is_top_level_module() { + Some(item.def_id) + } else { + let mut current = def_id; + // The immediate parent might not always be a module. + // Find the first parent which is. + loop { + if let Some(parent) = tcx.parent(current) { + if tcx.def_kind(parent) == DefKind::Mod { + break Some(parent); + } + current = parent; + } else { + debug!( + "{:?} has no parent (kind={:?}, original was {:?})", + current, + tcx.def_kind(current), + def_id + ); + break None; } - current = parent; - } else { - debug!( - "{:?} has no parent (kind={:?}, original was {:?})", - current, - tcx.def_kind(current), - def_id - ); - break None; } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index f392f321fbfc3..4e261c3fd1934 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -767,15 +767,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { fn fold_item(&mut self, mut item: Item) -> Option { use rustc_middle::ty::DefIdTree; - let parent_node = if item.is_fake() { - // FIXME: is this correct? - None - // If we're documenting the crate root itself, it has no parent. Use the root instead. - } else if item.def_id.is_top_level_module() { - Some(item.def_id) - } else { - find_closest_parent_module(self.cx.tcx, item.def_id) - }; + let parent_node = find_closest_parent_module(self.cx.tcx, item.def_id); if parent_node.is_some() { trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id); From 0c127b3d4341691681531831bbfe8b1fb59ec354 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 25 Dec 2020 16:35:28 -0800 Subject: [PATCH 28/73] Simplify loop and remove old debugging code Co-authored-by: Joshua Nelson --- src/librustdoc/clean/utils.rs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 4b9541b7e1421..b49ed07f8e83f 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -636,21 +636,12 @@ crate fn find_closest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option Date: Fri, 25 Dec 2020 16:37:09 -0800 Subject: [PATCH 29/73] Extract local variable --- src/librustdoc/clean/mod.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 33a891da7464e..e6ba3b54ab67d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2311,24 +2311,20 @@ impl Clean for (&hir::MacroDef<'_>, Option) { ) } else { let vis = item.vis.clean(cx); + let vis_printed_with_space = + vis.print_with_space(cx.tcx, cx.tcx.hir().local_def_id(item.hir_id).to_def_id()); if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", - vis.print_with_space( - cx.tcx, - cx.tcx.hir().local_def_id(item.hir_id).to_def_id() - ), + vis_printed_with_space, name, matchers.iter().map(|span| span.to_src(cx)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", - vis.print_with_space( - cx.tcx, - cx.tcx.hir().local_def_id(item.hir_id).to_def_id() - ), + vis_printed_with_space, name, matchers .iter() From e9ae18deb7d0ea4b872d1c01cb855a8aa292dbed Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 30 Dec 2020 16:38:25 -0800 Subject: [PATCH 30/73] Update `find_nearest_parent_module` --- src/librustdoc/clean/utils.rs | 12 +++++------- src/librustdoc/html/format.rs | 6 +++--- src/librustdoc/passes/collect_intra_doc_links.rs | 9 +++++++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b49ed07f8e83f..4009a42955f87 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -625,13 +625,11 @@ where r } -crate fn find_closest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - if item.is_fake() { - // FIXME: is this correct? - None - // If we're documenting the crate root itself, it has no parent. Use the root instead. - } else if item.def_id.is_top_level_module() { - Some(item.def_id) +/// Find the nearest parent module of a [`DefId`]. +crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + if def_id.is_top_level_module() { + // The crate root has no parent. Use it as the root instead. + Some(def_id) } else { let mut current = def_id; // The immediate parent might not always be a module. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 90f4aaefc9bc1..9fca005c34ee0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_target::spec::abi::Abi; -use crate::clean::{self, utils::find_closest_parent_module, PrimitiveType}; +use crate::clean::{self, utils::find_nearest_parent_module, PrimitiveType}; use crate::formats::cache::cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; @@ -1097,7 +1097,7 @@ impl clean::Visibility { clean::Inherited => Ok(()), clean::Visibility::Restricted(vis_did) => { - let parent_module = find_closest_parent_module(tcx, item_did); + let parent_module = find_nearest_parent_module(tcx, item_did); if vis_did.index == CRATE_DEF_INDEX { write!(f, "pub(crate) ") @@ -1106,7 +1106,7 @@ impl clean::Visibility { // is the same as no visibility modifier Ok(()) } else if parent_module - .map(|parent| find_closest_parent_module(tcx, parent)) + .map(|parent| find_nearest_parent_module(tcx, parent)) .flatten() == Some(vis_did) { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 4e261c3fd1934..e225eb47b12be 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -31,7 +31,7 @@ use std::cell::Cell; use std::mem; use std::ops::Range; -use crate::clean::{self, utils::find_closest_parent_module, Crate, Item, ItemLink, PrimitiveType}; +use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::markdown_links; @@ -767,7 +767,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { fn fold_item(&mut self, mut item: Item) -> Option { use rustc_middle::ty::DefIdTree; - let parent_node = find_closest_parent_module(self.cx.tcx, item.def_id); + let parent_node = if item.is_fake() { + // FIXME: is this correct? + None + } else { + find_nearest_parent_module(self.cx.tcx, item.def_id) + }; if parent_node.is_some() { trace!("got parent node for {:?} {:?}, id {:?}", item.type_(), item.name, item.def_id); From 8f0ce5d9f8818bb26a7d9c2612fafa8c674353ea Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 30 Dec 2020 16:29:47 -0800 Subject: [PATCH 31/73] Remove FIXME Co-authored-by: Joshua Nelson --- src/librustdoc/passes/collect_intra_doc_links.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index e225eb47b12be..2e116da6ff5dd 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -768,7 +768,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { use rustc_middle::ty::DefIdTree; let parent_node = if item.is_fake() { - // FIXME: is this correct? None } else { find_nearest_parent_module(self.cx.tcx, item.def_id) From dc7eb419b274297fa31cfeb2106f9a730045cc23 Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 30 Dec 2020 16:41:18 -0800 Subject: [PATCH 32/73] Small refactor --- src/librustdoc/clean/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e6ba3b54ab67d..cd59e7d32dde8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2311,20 +2311,19 @@ impl Clean for (&hir::MacroDef<'_>, Option) { ) } else { let vis = item.vis.clean(cx); - let vis_printed_with_space = - vis.print_with_space(cx.tcx, cx.tcx.hir().local_def_id(item.hir_id).to_def_id()); + let def_id = cx.tcx.hir().local_def_id(item.hir_id).to_def_id(); if matchers.len() <= 1 { format!( "{}macro {}{} {{\n ...\n}}", - vis_printed_with_space, + vis.print_with_space(cx.tcx, def_id), name, matchers.iter().map(|span| span.to_src(cx)).collect::(), ) } else { format!( "{}macro {} {{\n{}}}", - vis_printed_with_space, + vis.print_with_space(cx.tcx, def_id), name, matchers .iter() From 0a3048d95f42fa92d7e4eaa50a418c78cc55322c Mon Sep 17 00:00:00 2001 From: Camelid Date: Wed, 30 Dec 2020 17:39:03 -0800 Subject: [PATCH 33/73] Add note on panic behavior --- src/librustdoc/clean/utils.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 4009a42955f87..17f12d0a82f2e 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -626,6 +626,8 @@ where } /// Find the nearest parent module of a [`DefId`]. +/// +/// **Panics if the item it belongs to [is fake][Item::is_fake].** crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option { if def_id.is_top_level_module() { // The crate root has no parent. Use it as the root instead. From 6ec4c71c5632e28ebce8d4f3122236a3e9ed040a Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 31 Dec 2020 12:00:23 -0800 Subject: [PATCH 34/73] Add FIXME for visibility of a module --- src/librustdoc/html/format.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 9fca005c34ee0..9b2fb8582f54f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1097,6 +1097,9 @@ impl clean::Visibility { clean::Inherited => Ok(()), clean::Visibility::Restricted(vis_did) => { + // FIXME(camelid): This may not work correctly if `item_did` is a module. + // However, rustdoc currently never displays a module's + // visibility, so it shouldn't matter. let parent_module = find_nearest_parent_module(tcx, item_did); if vis_did.index == CRATE_DEF_INDEX { From d239ea6a094925de15f3c0b98d835001870b1b11 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 31 Dec 2020 12:04:13 -0800 Subject: [PATCH 35/73] Add `@!has` checks to ensure private items don't have `pub` --- src/test/rustdoc/visibility.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs index ebb314a7941b6..59427693c5a5d 100644 --- a/src/test/rustdoc/visibility.rs +++ b/src/test/rustdoc/visibility.rs @@ -23,8 +23,10 @@ mod a { // @has 'foo/a/struct.FooAInSuper.html' '//pre' 'pub(crate) struct FooAInSuper' pub(in super) struct FooAInSuper; // @has 'foo/a/struct.FooAInA.html' '//pre' 'struct FooAInA' + // @!has 'foo/a/struct.FooAInA.html' '//pre' 'pub' pub(in a) struct FooAInA; // @has 'foo/a/struct.FooAPriv.html' '//pre' 'struct FooAPriv' + // @!has 'foo/a/struct.FooAPriv.html' '//pre' 'pub' struct FooAPriv; mod b { @@ -33,8 +35,10 @@ mod a { // @has 'foo/a/b/struct.FooBInSuperSuper.html' '//pre' 'pub(crate) struct FooBInSuperSuper' pub(in super::super) struct FooBInSuperSuper; // @has 'foo/a/b/struct.FooBInAB.html' '//pre' 'struct FooBInAB' + // @!has 'foo/a/b/struct.FooBInAB.html' '//pre' 'pub' pub(in a::b) struct FooBInAB; // @has 'foo/a/b/struct.FooBPriv.html' '//pre' 'struct FooBPriv' + // @!has 'foo/a/b/struct.FooBPriv.html' '//pre' 'pub' struct FooBPriv; } } From f86b143602a626f8516a496aa15464ead79c1f3e Mon Sep 17 00:00:00 2001 From: bors Date: Thu, 4 Feb 2021 20:30:11 +0000 Subject: [PATCH 36/73] Auto merge of #81762 - pietroalbini:fix-install-msys2, r=m-ou-se CI: only copy python.exe to python3.exe if the latter does not exist We're copying the binary to make sure we can call `python3.exe` around, but it seems like the base image of GitHub Actions changed, copying the file before we do so. This PR changes the CI script to only copy the file if it doesn't already exist. r? `@m-ou-se` cc `@Mark-Simulacrum` --- src/ci/scripts/install-msys2.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh index 185d361582505..0aa4b42a6a8fb 100755 --- a/src/ci/scripts/install-msys2.sh +++ b/src/ci/scripts/install-msys2.sh @@ -24,7 +24,9 @@ if isWindows; then # baked in which break LLVM's build system one way or another, so let's use the # native version which keeps everything as native as possible. python_home="/c/hostedtoolcache/windows/Python/${native_python_version}/x64" - cp "${python_home}/python.exe" "${python_home}/python3.exe" + if ! [[ -f "${python_home}/python3.exe" ]]; then + cp "${python_home}/python.exe" "${python_home}/python3.exe" + fi ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64" ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts" fi From 567eb04105cd4441b441b152bf637ad408832d81 Mon Sep 17 00:00:00 2001 From: bors Date: Thu, 28 Jan 2021 18:57:10 +0000 Subject: [PATCH 37/73] Auto merge of #81055 - matthewjasper:non-fatal-overflow, r=nikomatsakis Make hitting the recursion limit in projection non-fatal This change was originally made in #80246 to avoid future (effectively) infinite loop bugs in projections, but wundergraph relies on rustc recovering here. cc #80953 r? `@nikomatsakis` --- .../src/traits/project.rs | 11 +--- .../src/traits/select/mod.rs | 4 -- .../project-recursion-limit-non-fatal.rs | 58 +++++++++++++++++++ src/test/ui/issues/issue-23122-2.stderr | 3 +- 4 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/associated-types/project-recursion-limit-non-fatal.rs diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index fa0526445c194..f22b5b9661699 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -736,14 +736,9 @@ fn project_type<'cx, 'tcx>( if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); - match selcx.query_mode() { - super::TraitQueryMode::Standard => { - selcx.infcx().report_overflow_error(&obligation, true); - } - super::TraitQueryMode::Canonical => { - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); - } - } + // This should really be an immediate error, but some existing code + // relies on being able to recover from this. + return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); } let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a8f81445b0397..f1c86eab0956e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -291,10 +291,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - pub(super) fn query_mode(&self) -> TraitQueryMode { - self.query_mode - } - /////////////////////////////////////////////////////////////////////////// // Selection // diff --git a/src/test/ui/associated-types/project-recursion-limit-non-fatal.rs b/src/test/ui/associated-types/project-recursion-limit-non-fatal.rs new file mode 100644 index 0000000000000..3e68b1401020f --- /dev/null +++ b/src/test/ui/associated-types/project-recursion-limit-non-fatal.rs @@ -0,0 +1,58 @@ +// Regression test for #80953. Hitting the recursion limit in projection +// is non-fatal. The above code, minimised from wundergraph shows a case +// where this is relied on. + +// check-pass + +struct AlternateTable {} +struct AlternateQuery {} + +pub trait Query {} +pub trait AsQuery { + type Query; +} +impl AsQuery for T { + type Query = Self; +} +impl AsQuery for AlternateTable { + type Query = AlternateQuery; +} + +pub trait Table: AsQuery { + type PrimaryKey; +} +impl Table for AlternateTable { + type PrimaryKey = (); +} + +pub trait FilterDsl { + type Output; +} +pub type Filter = >::Output; +impl FilterDsl for T +where + T: Table, + T::Query: FilterDsl, +{ + type Output = Filter; +} +impl FilterDsl for AlternateQuery { + type Output = &'static str; +} + +pub trait HandleDelete { + type Filter; +} +impl HandleDelete for T +where + T: Table, + T::Query: FilterDsl, + Filter: , +{ + type Filter = Filter; +} + +fn main() { + let x: ::Filter = "Hello, world"; + println!("{}", x); +} diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index ff7e884ea6f83..ce3bffe602ca0 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,10 +1,11 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`issue_23122_2`) + = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>` error: aborting due to previous error From f6b8e2be8da317318eb3639681f6cd3bec20a355 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 3 Feb 2021 18:51:14 +0100 Subject: [PATCH 38/73] Rollup merge of #81532 - estebank:ice-ice-baby, r=pnkfelix Remove incorrect `delay_span_bug` The following code is supposed to compile ```rust use std::ops::BitOr; pub trait IntWrapper { type InternalStorage; } impl BitOr for dyn IntWrapper where Self: Sized, T: BitOr + BitOr, { type Output = Self; fn bitor(self, _other: Self) -> Self { todo!() } } ``` Before this change it would ICE. In #70998 the removed logic was added to provide better suggestions, and the `delay_span_bug` guard was added to protect against a potential logic error when returning traits. As it happens, there are cases, like the one above, where traits can indeed be returned, so valid code was being rejected. Fix (but not close) #80207. --- compiler/rustc_typeck/src/check/check.rs | 1 - .../ui/typeck/issue-80207-unsized-return.rs | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/typeck/issue-80207-unsized-return.rs diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index ec7369fd3e8ee..d235ad21c7b95 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -188,7 +188,6 @@ pub(super) fn check_fn<'a, 'tcx>( // possible cases. fcx.check_expr(&body.value); fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); } else { fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); fcx.check_return_expr(&body.value); diff --git a/src/test/ui/typeck/issue-80207-unsized-return.rs b/src/test/ui/typeck/issue-80207-unsized-return.rs new file mode 100644 index 0000000000000..75430da148239 --- /dev/null +++ b/src/test/ui/typeck/issue-80207-unsized-return.rs @@ -0,0 +1,20 @@ +// check-pass + +trait Foo { + fn do_stuff() -> Self; +} + +trait Bar { + type Output; +} + +impl Foo for dyn Bar +where + Self: Sized, +{ + fn do_stuff() -> Self { + todo!() + } +} + +fn main() {} From 3b034464a48ff1e75d4db765ee4bf51134975141 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 4 Feb 2021 21:10:34 +0100 Subject: [PATCH 39/73] Rollup merge of #81556 - nikomatsakis:forbidden-lint-groups-lint, r=pnkfelix introduce future-compatibility warning for forbidden lint groups We used to ignore `forbid(group)` scenarios completely. This changed in #78864, but that led to a number of regressions (#80988, #81218). This PR introduces a future compatibility warning for the case where a group is forbidden but then an individual lint within that group is allowed. We now issue a FCW when we see the "allow", but permit it to take effect. r? ``@Mark-Simulacrum`` --- compiler/rustc_lint/src/context.rs | 15 +++ compiler/rustc_lint/src/levels.rs | 101 ++++++++++----- compiler/rustc_lint_defs/src/builtin.rs | 37 ++++++ compiler/rustc_middle/src/lint.rs | 14 ++- src/test/ui/lint/forbid-group-group-1.rs | 13 ++ src/test/ui/lint/forbid-group-group-1.stderr | 15 +++ src/test/ui/lint/forbid-group-group-2.rs | 26 ++++ src/test/ui/lint/forbid-group-group-2.stderr | 115 ++++++++++++++++++ src/test/ui/lint/forbid-group-member.rs | 19 +++ src/test/ui/lint/forbid-group-member.stderr | 51 ++++++++ src/test/ui/lint/forbid-member-group.rs | 12 ++ src/test/ui/lint/forbid-member-group.stderr | 30 +++++ ...0819-dont-override-forbid-in-same-scope.rs | 7 +- ...-dont-override-forbid-in-same-scope.stderr | 30 ++--- src/test/ui/lint/issue-80988.rs | 16 +++ src/test/ui/lint/issue-80988.stderr | 51 ++++++++ src/test/ui/lint/issue-81218.rs | 14 +++ src/test/ui/lint/outer-forbid.rs | 5 + src/test/ui/lint/outer-forbid.stderr | 37 ++++-- 19 files changed, 553 insertions(+), 55 deletions(-) create mode 100644 src/test/ui/lint/forbid-group-group-1.rs create mode 100644 src/test/ui/lint/forbid-group-group-1.stderr create mode 100644 src/test/ui/lint/forbid-group-group-2.rs create mode 100644 src/test/ui/lint/forbid-group-group-2.stderr create mode 100644 src/test/ui/lint/forbid-group-member.rs create mode 100644 src/test/ui/lint/forbid-group-member.stderr create mode 100644 src/test/ui/lint/forbid-member-group.rs create mode 100644 src/test/ui/lint/forbid-member-group.stderr create mode 100644 src/test/ui/lint/issue-80988.rs create mode 100644 src/test/ui/lint/issue-80988.stderr create mode 100644 src/test/ui/lint/issue-81218.rs diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index bfeef4904893a..780bf5fecffe3 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -39,6 +39,7 @@ use rustc_session::SessionLintStore; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; use rustc_target::abi::LayoutOf; +use tracing::debug; use std::cell::Cell; use std::slice; @@ -335,6 +336,20 @@ impl LintStore { } } + /// True if this symbol represents a lint group name. + pub fn is_lint_group(&self, lint_name: Symbol) -> bool { + debug!( + "is_lint_group(lint_name={:?}, lint_groups={:?})", + lint_name, + self.lint_groups.keys().collect::>() + ); + let lint_name_str = &*lint_name.as_str(); + self.lint_groups.contains_key(&lint_name_str) || { + let warnings_name_str = crate::WARNINGS.name_lower(); + lint_name_str == &*warnings_name_str + } + } + /// Checks the name of a lint for its existence, and whether it was /// renamed or removed. Generates a DiagnosticBuilder containing a /// warning for renamed and removed lints. This is over both lint diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 5cece569903c7..570578ff08f17 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -5,7 +5,7 @@ use rustc_ast::attr; use rustc_ast::unwrap_or; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; @@ -17,11 +17,15 @@ use rustc_middle::lint::{ }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::{builtin, Level, Lint, LintId}; +use rustc_session::lint::{ + builtin::{self, FORBIDDEN_LINT_GROUPS}, + Level, Lint, LintId, +}; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP}; +use tracing::debug; use std::cmp; @@ -51,6 +55,7 @@ pub struct LintLevelsBuilder<'s> { id_to_set: FxHashMap, cur: u32, warn_about_weird_lints: bool, + store: &'s LintStore, } pub struct BuilderPush { @@ -59,13 +64,14 @@ pub struct BuilderPush { } impl<'s> LintLevelsBuilder<'s> { - pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &LintStore) -> Self { + pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore) -> Self { let mut builder = LintLevelsBuilder { sess, sets: LintLevelSets::new(), cur: 0, id_to_set: Default::default(), warn_about_weird_lints, + store, }; builder.process_command_line(sess, store); assert_eq!(builder.sets.list.len(), 1); @@ -120,36 +126,75 @@ impl<'s> LintLevelsBuilder<'s> { if let (Level::Forbid, old_src) = self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess) { - let mut diag_builder = struct_span_err!( - self.sess, - src.span(), - E0453, - "{}({}) incompatible with previous forbid", - level.as_str(), - src.name(), + // Backwards compatibility check: + // + // We used to not consider `forbid(lint_group)` + // as preventing `allow(lint)` for some lint `lint` in + // `lint_group`. For now, issue a future-compatibility + // warning for this case. + let id_name = id.lint.name_lower(); + let fcw_warning = match old_src { + LintLevelSource::Default => false, + LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol), + LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol), + }; + debug!( + "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}", + fcw_warning, specs, old_src, id_name ); - diag_builder.span_label(src.span(), "overruled by previous forbid"); - match old_src { - LintLevelSource::Default => { - diag_builder.note(&format!( - "`forbid` lint level is the default for {}", - id.to_string() - )); - } - LintLevelSource::Node(_, forbid_source_span, reason) => { - diag_builder.span_label(forbid_source_span, "`forbid` level set here"); - if let Some(rationale) = reason { - diag_builder.note(&rationale.as_str()); + + let decorate_diag_builder = |mut diag_builder: DiagnosticBuilder<'_>| { + diag_builder.span_label(src.span(), "overruled by previous forbid"); + match old_src { + LintLevelSource::Default => { + diag_builder.note(&format!( + "`forbid` lint level is the default for {}", + id.to_string() + )); + } + LintLevelSource::Node(_, forbid_source_span, reason) => { + diag_builder.span_label(forbid_source_span, "`forbid` level set here"); + if let Some(rationale) = reason { + diag_builder.note(&rationale.as_str()); + } + } + LintLevelSource::CommandLine(_, _) => { + diag_builder.note("`forbid` lint level was set on command line"); } } - LintLevelSource::CommandLine(_, _) => { - diag_builder.note("`forbid` lint level was set on command line"); - } + diag_builder.emit(); + }; + if !fcw_warning { + let diag_builder = struct_span_err!( + self.sess, + src.span(), + E0453, + "{}({}) incompatible with previous forbid", + level.as_str(), + src.name(), + ); + decorate_diag_builder(diag_builder); + } else { + self.struct_lint( + FORBIDDEN_LINT_GROUPS, + Some(src.span().into()), + |diag_builder| { + let diag_builder = diag_builder.build(&format!( + "{}({}) incompatible with previous forbid", + level.as_str(), + src.name(), + )); + decorate_diag_builder(diag_builder); + }, + ); } - diag_builder.emit(); - // Retain the forbid lint level - return; + // Retain the forbid lint level, unless we are + // issuing a FCW. In the FCW case, we want to + // respect the new setting. + if !fcw_warning { + return; + } } } specs.insert(id, (level, src)); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 1c692d4f20762..655eb229e6c8e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -8,6 +8,42 @@ use crate::{declare_lint, declare_lint_pass, declare_tool_lint}; use rustc_span::edition::Edition; use rustc_span::symbol::sym; +declare_lint! { + /// The `forbidden_lint_groups` lint detects violations of + /// `forbid` applied to a lint group. Due to a bug in the compiler, + /// these used to be overlooked entirely. They now generate a warning. + /// + /// ### Example + /// + /// ```rust + /// #![forbid(warnings)] + /// #![deny(bad_style)] + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Recommended fix + /// + /// If your crate is using `#![forbid(warnings)]`, + /// we recommend that you change to `#![deny(warnings)]`. + /// + /// ### Explanation + /// + /// Due to a compiler bug, applying `forbid` to lint groups + /// previously had no effect. The bug is now fixed but instead of + /// enforcing `forbid` we issue this future-compatibility warning + /// to avoid breaking existing crates. + pub FORBIDDEN_LINT_GROUPS, + Warn, + "applying forbid to lint-groups", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #81670 ", + edition: None, + }; +} + declare_lint! { /// The `ill_formed_attribute_input` lint detects ill-formed attribute /// inputs that were previously accepted and used in practice. @@ -2839,6 +2875,7 @@ declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. HardwiredLints => [ + FORBIDDEN_LINT_GROUPS, ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, ARITHMETIC_OVERFLOW, UNCONDITIONAL_PANIC, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 64d850192f449..bd724a5830470 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -5,14 +5,17 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; -use rustc_session::lint::{builtin, Level, Lint, LintId}; +use rustc_session::lint::{ + builtin::{self, FORBIDDEN_LINT_GROUPS}, + Level, Lint, LintId, +}; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; use rustc_span::{symbol, Span, Symbol, DUMMY_SP}; /// How a lint level was set. -#[derive(Clone, Copy, PartialEq, Eq, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, HashStable, Debug)] pub enum LintLevelSource { /// Lint is at the default level as declared /// in rustc or a plugin. @@ -87,7 +90,12 @@ impl LintLevelSets { // If we're about to issue a warning, check at the last minute for any // directives against the warnings "lint". If, for example, there's an // `allow(warnings)` in scope then we want to respect that instead. - if level == Level::Warn { + // + // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically + // triggers in cases (like #80988) where you have `forbid(warnings)`, + // and so if we turned that into an error, it'd defeat the purpose of the + // future compatibility warning. + if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) { let (warnings_level, warnings_src) = self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux); if let Some(configured_warning_level) = warnings_level { diff --git a/src/test/ui/lint/forbid-group-group-1.rs b/src/test/ui/lint/forbid-group-group-1.rs new file mode 100644 index 0000000000000..80f7db4e56036 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-1.rs @@ -0,0 +1,13 @@ +// Check what happens when we forbid a smaller group but +// then allow a superset of that group. + +#![forbid(nonstandard_style)] + +// FIXME: Arguably this should be an error, but the WARNINGS group is +// treated in a very special (and rather ad-hoc) way and +// it fails to trigger. +#[allow(warnings)] +fn main() { + let A: (); + //~^ ERROR should have a snake case name +} diff --git a/src/test/ui/lint/forbid-group-group-1.stderr b/src/test/ui/lint/forbid-group-group-1.stderr new file mode 100644 index 0000000000000..fd425e5f74e6f --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-1.stderr @@ -0,0 +1,15 @@ +error: variable `A` should have a snake case name + --> $DIR/forbid-group-group-1.rs:11:9 + | +LL | let A: (); + | ^ help: convert the identifier to snake case: `a` + | +note: the lint level is defined here + --> $DIR/forbid-group-group-1.rs:4:11 + | +LL | #![forbid(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: `#[forbid(non_snake_case)]` implied by `#[forbid(nonstandard_style)]` + +error: aborting due to previous error + diff --git a/src/test/ui/lint/forbid-group-group-2.rs b/src/test/ui/lint/forbid-group-group-2.rs new file mode 100644 index 0000000000000..b12fd72da7494 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-2.rs @@ -0,0 +1,26 @@ +// Check what happens when we forbid a bigger group but +// then deny a subset of that group. + +#![forbid(warnings)] +#![deny(forbidden_lint_groups)] + +#[allow(nonstandard_style)] +//~^ ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +fn main() {} diff --git a/src/test/ui/lint/forbid-group-group-2.stderr b/src/test/ui/lint/forbid-group-group-2.stderr new file mode 100644 index 0000000000000..214e949c11a74 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-2.stderr @@ -0,0 +1,115 @@ +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/forbid-group-group-2.rs:5:9 + | +LL | #![deny(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/lint/forbid-group-member.rs b/src/test/ui/lint/forbid-group-member.rs new file mode 100644 index 0000000000000..6f1b2e9f66812 --- /dev/null +++ b/src/test/ui/lint/forbid-group-member.rs @@ -0,0 +1,19 @@ +// Check what happens when we forbid a group but +// then allow a member of that group. +// +// check-pass + +#![forbid(unused)] + +#[allow(unused_variables)] +//~^ WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +fn main() { + let a: (); +} diff --git a/src/test/ui/lint/forbid-group-member.stderr b/src/test/ui/lint/forbid-group-member.stderr new file mode 100644 index 0000000000000..c818d7ff60605 --- /dev/null +++ b/src/test/ui/lint/forbid-group-member.stderr @@ -0,0 +1,51 @@ +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = note: `#[warn(forbidden_lint_groups)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/forbid-member-group.rs b/src/test/ui/lint/forbid-member-group.rs new file mode 100644 index 0000000000000..3279029a9cbc3 --- /dev/null +++ b/src/test/ui/lint/forbid-member-group.rs @@ -0,0 +1,12 @@ +// Check what happens when we forbid a member of +// a group but then allow the group. + +#![forbid(unused_variables)] + +#[allow(unused)] +//~^ ERROR incompatible with previous forbid +//~| ERROR incompatible with previous forbid +//~| ERROR incompatible with previous forbid +fn main() { + let a: (); +} diff --git a/src/test/ui/lint/forbid-member-group.stderr b/src/test/ui/lint/forbid-member-group.stderr new file mode 100644 index 0000000000000..1d8ab4d5edb0c --- /dev/null +++ b/src/test/ui/lint/forbid-member-group.stderr @@ -0,0 +1,30 @@ +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs index f725304cf29d4..05d7d924c8fab 100644 --- a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs @@ -14,14 +14,17 @@ // compile-flags: -Z deduplicate-diagnostics=yes +#![forbid(forbidden_lint_groups)] + fn forbid_first(num: i32) -> i32 { #![forbid(unused)] #![deny(unused)] //~^ ERROR: deny(unused) incompatible with previous forbid + //~| WARNING being phased out + //~| ERROR: deny(unused) incompatible with previous forbid + //~| WARNING being phased out #![warn(unused)] - //~^ ERROR: warn(unused) incompatible with previous forbid #![allow(unused)] - //~^ ERROR: allow(unused) incompatible with previous forbid num * num } diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr index 9f107411c102a..475410cecffa3 100644 --- a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr @@ -1,29 +1,29 @@ -error[E0453]: deny(unused) incompatible with previous forbid - --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:19:13 +error: deny(unused) incompatible with previous forbid + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 | LL | #![forbid(unused)] | ------ `forbid` level set here LL | #![deny(unused)] | ^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:17:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error[E0453]: warn(unused) incompatible with previous forbid +error: deny(unused) incompatible with previous forbid --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 | LL | #![forbid(unused)] | ------ `forbid` level set here -... -LL | #![warn(unused)] +LL | #![deny(unused)] | ^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused) incompatible with previous forbid - --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:23:14 | -LL | #![forbid(unused)] - | ------ `forbid` level set here -... -LL | #![allow(unused)] - | ^^^^^^ overruled by previous forbid + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/issue-80988.rs b/src/test/ui/lint/issue-80988.rs new file mode 100644 index 0000000000000..16a041928db73 --- /dev/null +++ b/src/test/ui/lint/issue-80988.rs @@ -0,0 +1,16 @@ +// Regression test for #80988 +// +// check-pass + +#![forbid(warnings)] + +#[deny(warnings)] +//~^ WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +fn main() {} diff --git a/src/test/ui/lint/issue-80988.stderr b/src/test/ui/lint/issue-80988.stderr new file mode 100644 index 0000000000000..4cae11f97c0fb --- /dev/null +++ b/src/test/ui/lint/issue-80988.stderr @@ -0,0 +1,51 @@ +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = note: `#[warn(forbidden_lint_groups)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/issue-81218.rs b/src/test/ui/lint/issue-81218.rs new file mode 100644 index 0000000000000..f02aa9040ebc5 --- /dev/null +++ b/src/test/ui/lint/issue-81218.rs @@ -0,0 +1,14 @@ +// Regression test for #81218 +// +// check-pass + +#![forbid(warnings)] + +#[allow(unused_variables)] +fn main() { + // We want to ensure that you don't get an error + // here. The idea is that a derive might generate + // code that would otherwise trigger the "unused variables" + // lint, but it is meant to be suppressed. + let x: (); +} diff --git a/src/test/ui/lint/outer-forbid.rs b/src/test/ui/lint/outer-forbid.rs index d45848bf706f3..486ec3c46804f 100644 --- a/src/test/ui/lint/outer-forbid.rs +++ b/src/test/ui/lint/outer-forbid.rs @@ -15,11 +15,16 @@ // compile-flags: -Z deduplicate-diagnostics=yes #![forbid(unused, non_snake_case)] +#![forbid(forbidden_lint_groups)] #[allow(unused_variables)] //~ ERROR incompatible with previous +//~^ ERROR incompatible with previous +//~| WARNING this was previously accepted by the compiler +//~| WARNING this was previously accepted by the compiler fn foo() {} #[allow(unused)] //~ ERROR incompatible with previous +//~^ WARNING this was previously accepted by the compiler fn bar() {} #[allow(nonstandard_style)] //~ ERROR incompatible with previous diff --git a/src/test/ui/lint/outer-forbid.stderr b/src/test/ui/lint/outer-forbid.stderr index c012c20697e16..d69157a8bb3ad 100644 --- a/src/test/ui/lint/outer-forbid.stderr +++ b/src/test/ui/lint/outer-forbid.stderr @@ -1,23 +1,34 @@ -error[E0453]: allow(unused_variables) incompatible with previous forbid - --> $DIR/outer-forbid.rs:19:9 +error: allow(unused_variables) incompatible with previous forbid + --> $DIR/outer-forbid.rs:20:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here -LL | +... LL | #[allow(unused_variables)] | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/outer-forbid.rs:18:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error[E0453]: allow(unused) incompatible with previous forbid - --> $DIR/outer-forbid.rs:22:9 +error: allow(unused) incompatible with previous forbid + --> $DIR/outer-forbid.rs:26:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here ... LL | #[allow(unused)] | ^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 error[E0453]: allow(nonstandard_style) incompatible with previous forbid - --> $DIR/outer-forbid.rs:25:9 + --> $DIR/outer-forbid.rs:30:9 | LL | #![forbid(unused, non_snake_case)] | -------------- `forbid` level set here @@ -25,6 +36,18 @@ LL | #![forbid(unused, non_snake_case)] LL | #[allow(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ overruled by previous forbid -error: aborting due to 3 previous errors +error: allow(unused_variables) incompatible with previous forbid + --> $DIR/outer-forbid.rs:20:9 + | +LL | #![forbid(unused, non_snake_case)] + | ------ `forbid` level set here +... +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0453`. From d1eff4c300f6ec268c9820c5d5b6008929f71f79 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 4 Feb 2021 09:08:42 -0800 Subject: [PATCH 40/73] [beta] Update cargo --- src/tools/cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargo b/src/tools/cargo index 1a8df6a5196e4..f04e7fab73128 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 1a8df6a5196e4cad9a3956867e7e928f2bfaaba4 +Subproject commit f04e7fab73128592a4063983c302da788bdfaba5 From 7906dc00fbfb610fa70169eb9c4ebc82c15aac35 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 23 Jan 2021 20:16:16 +0100 Subject: [PATCH 41/73] Rollup merge of #81288 - camelid:fix-trait-item-vis, r=jyn514 rustdoc: Fix visibility of trait and impl items Fixes #81274. r? `@jyn514` --- src/librustdoc/clean/mod.rs | 21 +++++++++++++++++++-- src/test/rustdoc/visibility.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cd59e7d32dde8..2ac8950bcac3c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1096,7 +1096,10 @@ impl Clean for hir::TraitItem<'_> { AssocTypeItem(bounds.clean(cx), default.clean(cx)) } }; - Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx) + let what_rustc_thinks = + Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx); + // Trait items always inherit the trait's visibility -- we don't want to show `pub`. + Item { visibility: Inherited, ..what_rustc_thinks } }) } } @@ -1124,7 +1127,21 @@ impl Clean for hir::ImplItem<'_> { TypedefItem(Typedef { type_, generics: Generics::default(), item_type }, true) } }; - Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx) + + let what_rustc_thinks = + Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx); + let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(self.hir_id)); + if let hir::ItemKind::Impl { of_trait, .. } = &parent_item.kind { + if of_trait.is_some() { + // Trait impl items always inherit the impl's visibility -- + // we don't want to show `pub`. + Item { visibility: Inherited, ..what_rustc_thinks } + } else { + what_rustc_thinks + } + } else { + panic!("found impl item with non-impl parent {:?}", parent_item); + } }) } } diff --git a/src/test/rustdoc/visibility.rs b/src/test/rustdoc/visibility.rs index 59427693c5a5d..beb638406c4be 100644 --- a/src/test/rustdoc/visibility.rs +++ b/src/test/rustdoc/visibility.rs @@ -42,3 +42,35 @@ mod a { struct FooBPriv; } } + +// @has 'foo/trait.PubTrait.html' '//pre' 'pub trait PubTrait' +// +// @has 'foo/trait.PubTrait.html' '//pre' 'type Type;' +// @!has 'foo/trait.PubTrait.html' '//pre' 'pub type Type;' +// +// @has 'foo/trait.PubTrait.html' '//pre' 'const CONST: usize;' +// @!has 'foo/trait.PubTrait.html' '//pre' 'pub const CONST: usize;' +// +// @has 'foo/trait.PubTrait.html' '//pre' 'fn function();' +// @!has 'foo/trait.PubTrait.html' '//pre' 'pub fn function();' + +pub trait PubTrait { + type Type; + const CONST: usize; + fn function(); +} + +// @has 'foo/struct.FooPublic.html' '//code' 'type Type' +// @!has 'foo/struct.FooPublic.html' '//code' 'pub type Type' +// +// @has 'foo/struct.FooPublic.html' '//code' 'const CONST: usize' +// @!has 'foo/struct.FooPublic.html' '//code' 'pub const CONST: usize' +// +// @has 'foo/struct.FooPublic.html' '//code' 'fn function()' +// @!has 'foo/struct.FooPublic.html' '//code' 'pub fn function()' + +impl PubTrait for FooPublic { + type Type = usize; + const CONST: usize = 0; + fn function() {} +} From e364d4a326c89ba43e7ae3f3eba149d267ff34a2 Mon Sep 17 00:00:00 2001 From: bors Date: Wed, 20 Jan 2021 23:40:09 +0000 Subject: [PATCH 42/73] Auto merge of #81229 - m-ou-se:solaris-workaround, r=pietroalbini Work around missing -dev packages in solaris docker image. This should hopefully make the `dist-various-2` docker build work again on CI, which is now blocking everything from getting merged. r? `@pietroalbini` --- .../dist-various-2/build-solaris-toolchain.sh | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh index 4b3f284450eaa..6c4aa875269f9 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh @@ -30,12 +30,12 @@ cd solaris dpkg --add-architecture $APT_ARCH apt-get update apt-get download $(apt-cache depends --recurse --no-replaces \ - libc-dev:$APT_ARCH \ + libc:$APT_ARCH \ libm-dev:$APT_ARCH \ - libpthread-dev:$APT_ARCH \ - libresolv-dev:$APT_ARCH \ - librt-dev:$APT_ARCH \ - libsocket-dev:$APT_ARCH \ + libpthread:$APT_ARCH \ + libresolv:$APT_ARCH \ + librt:$APT_ARCH \ + libsocket:$APT_ARCH \ system-crt:$APT_ARCH \ system-header:$APT_ARCH \ | grep "^\w") @@ -44,6 +44,14 @@ for deb in *$APT_ARCH.deb; do dpkg -x $deb . done +# The -dev packages are not available from the apt repository we're using. +# However, those packages are just symlinks from *.so to *.so.. +# This makes all those symlinks. +for lib in $(find -name '*.so.*'); do + target=${lib%.so.*}.so + [ -e $target ] || ln -s ${lib##*/} $target +done + # Remove Solaris 11 functions that are optionally used by libbacktrace. # This is for Solaris 10 compatibility. rm usr/include/link.h From 78e57dc9803b3f283eb067e984869f90c82747c2 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 5 Feb 2021 12:26:07 +0100 Subject: [PATCH 43/73] Rollup merge of #81767 - exrook:layout-error-stability, r=Mark-Simulacrum Update LayoutError/LayoutErr stability attributes `LayoutError` ended up not making it into 1.49.0, updating the stability attributes to reflect that. I also pushed `LayoutErr` deprecation back a release to allow 2 releases before the deprecation comes into effect. This change should be backported to beta. --- library/core/src/alloc/layout.rs | 4 ++-- library/core/src/alloc/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 57c6624b64f9e..997c1a16cc025 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -394,7 +394,7 @@ impl Layout { #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_deprecated( - since = "1.51.0", + since = "1.52.0", reason = "Name does not follow std convention, use LayoutError", suggestion = "LayoutError" )] @@ -403,7 +403,7 @@ pub type LayoutErr = LayoutError; /// The parameters given to `Layout::from_size_align` /// or some other `Layout` constructor /// do not satisfy its documented constraints. -#[stable(feature = "alloc_layout_error", since = "1.49.0")] +#[stable(feature = "alloc_layout_error", since = "1.50.0")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutError { private: (), diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 045eb58d0135a..c1c993bbc51af 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -11,14 +11,14 @@ pub use self::global::GlobalAlloc; pub use self::layout::Layout; #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_deprecated( - since = "1.51.0", + since = "1.52.0", reason = "Name does not follow std convention, use LayoutError", suggestion = "LayoutError" )] #[allow(deprecated, deprecated_in_future)] pub use self::layout::LayoutErr; -#[stable(feature = "alloc_layout_error", since = "1.49.0")] +#[stable(feature = "alloc_layout_error", since = "1.50.0")] pub use self::layout::LayoutError; use crate::fmt; From eba543261df42672c692e45e3062c4cbbcd03920 Mon Sep 17 00:00:00 2001 From: bors Date: Fri, 5 Feb 2021 14:52:57 +0000 Subject: [PATCH 44/73] Auto merge of #81257 - pnkfelix:issue-80949-short-term-resolution-via-revert-of-pr-78373, r=matthewjasper Revert 78373 ("dont leak return value after panic in drop") Short term resolution for issue #80949. Reopen #47949 after this lands. (We plan to fine-tune PR #78373 to not run into this problem.) --- compiler/rustc_mir_build/src/build/block.rs | 10 +- .../src/build/expr/as_rvalue.rs | 20 +- .../rustc_mir_build/src/build/expr/as_temp.rs | 6 +- .../rustc_mir_build/src/build/expr/into.rs | 90 +- .../rustc_mir_build/src/build/expr/stmt.rs | 2 - compiler/rustc_mir_build/src/build/into.rs | 11 +- .../rustc_mir_build/src/build/matches/mod.rs | 78 +- compiler/rustc_mir_build/src/build/mod.rs | 20 +- compiler/rustc_mir_build/src/build/scope.rs | 216 +- .../alloc/src/collections/btree/map/tests.rs | 2 +- ...ignment.main.SimplifyCfg-initial.after.mir | 28 +- .../box_expr.main.ElaborateDrops.before.mir | 28 +- .../inline/inline_diverging.h.Inline.diff | 11 +- .../issue_41110.main.ElaborateDrops.after.mir | 27 +- .../issue_41110.test.ElaborateDrops.after.mir | 48 +- .../issue_41888.main.ElaborateDrops.after.mir | 74 +- ...issue_62289.test.ElaborateDrops.before.mir | 40 +- ..._after_call.main.ElaborateDrops.before.mir | 10 +- ...ove_out.move_out_by_subslice.mir_map.0.mir | 38 +- ...y_move_out.move_out_from_end.mir_map.0.mir | 38 +- .../expected_show_coverage.uses_crate.txt | 4 +- ...block_on.-------.InstrumentCoverage.0.html | 114 +- ...ync.main.-------.InstrumentCoverage.0.html | 54 +- ...osure#2}.-------.InstrumentCoverage.0.html | 12 +- ...ure.main.-------.InstrumentCoverage.0.html | 19992 ++++++++-------- ...ib_crate.-------.InstrumentCoverage.0.html | 162 +- ...ate.main.-------.InstrumentCoverage.0.html | 176 +- src/test/ui/drop/dynamic-drop-async.rs | 165 +- src/test/ui/drop/dynamic-drop.rs | 437 +- src/test/ui/mir/issue-80949.rs | 34 + 30 files changed, 10904 insertions(+), 11043 deletions(-) create mode 100644 src/test/ui/mir/issue-80949.rs diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 82f38ac0e7620..d5f72e6f22dfa 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -3,7 +3,6 @@ use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_hir as hir; -use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_session::lint::Level; @@ -13,7 +12,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn ast_block( &mut self, destination: Place<'tcx>, - scope: Option, block: BasicBlock, ast_block: &'tcx hir::Block<'tcx>, source_info: SourceInfo, @@ -30,10 +28,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { - this.in_breakable_scope(None, destination, scope, span, |this| { + this.in_breakable_scope(None, destination, span, |this| { Some(this.ast_block_stmts( destination, - scope, block, span, stmts, @@ -42,7 +39,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { )) }) } else { - this.ast_block_stmts(destination, scope, block, span, stmts, expr, safety_mode) + this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode) } }) }) @@ -51,7 +48,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn ast_block_stmts( &mut self, destination: Place<'tcx>, - scope: Option, mut block: BasicBlock, span: Span, stmts: Vec>, @@ -186,7 +182,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span }); - unpack!(block = this.into(destination, scope, block, expr)); + unpack!(block = this.into(destination, block, expr)); let popped = this.block_context.pop(); assert!(popped.map_or(false, |bf| bf.is_tail_expr())); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 3f381f3f15e8e..581d842142f7b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -12,8 +12,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; -use std::slice; - impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns an rvalue suitable for use until the end of the current /// scope expression. @@ -115,19 +113,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); this.cfg.push_assign(block, source_info, Place::from(result), box_); - // Initialize the box contents. No scope is needed since the - // `Box` is already scheduled to be dropped. + // initialize the box contents: unpack!( - block = this.into( - this.hir.tcx().mk_place_deref(Place::from(result)), - None, - block, - value, - ) + block = + this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value) ); - let result_operand = Operand::Move(Place::from(result)); - this.record_operands_moved(slice::from_ref(&result_operand)); - block.and(Rvalue::Use(result_operand)) + block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { let source = unpack!(block = this.as_operand(block, scope, source)); @@ -171,7 +162,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); - this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields)) } ExprKind::Tuple { fields } => { @@ -182,7 +172,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|f| unpack!(block = this.as_operand(block, scope, f))) .collect(); - this.record_operands_moved(&fields); block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } ExprKind::Closure { closure_id, substs, upvars, movability } => { @@ -234,7 +223,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs), }; - this.record_operands_moved(&operands); block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 241330d96e7bd..9984b527ffdb4 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -114,7 +114,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - unpack!(block = this.into(temp_place, temp_lifetime, block, expr)); + unpack!(block = this.into(temp_place, block, expr)); + + if let Some(temp_lifetime) = temp_lifetime { + this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value); + } block.and(temp) } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1f70fdb5ae30b..a86e4cb99c7f9 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -1,37 +1,27 @@ //! See docs in build/expr/mod.rs use crate::build::expr::category::{Category, RvalueFunc}; -use crate::build::scope::DropKind; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; -use std::slice; - impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which /// is assumed to be uninitialized. - /// If a `drop_scope` is provided, `destination` is scheduled to be dropped - /// in `scope` once it has been initialized. crate fn into_expr( &mut self, destination: Place<'tcx>, - scope: Option, mut block: BasicBlock, expr: Expr<'tcx>, ) -> BlockAnd<()> { - debug!( - "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})", - destination, scope, block, expr - ); + debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr); // since we frequently have to reference `self` from within a // closure, where `self` would be shadowed, it's easier to @@ -46,14 +36,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => false, }; - let schedule_drop = move |this: &mut Self| { - if let Some(drop_scope) = scope { - let local = - destination.as_local().expect("cannot schedule drop of non-Local place"); - this.schedule_drop(expr_span, drop_scope, local, DropKind::Value); - } - }; - if !expr_is_block_or_scope { this.block_context.push(BlockFrame::SubExpr); } @@ -63,15 +45,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let region_scope = (region_scope, source_info); ensure_sufficient_stack(|| { this.in_scope(region_scope, lint_level, |this| { - this.into(destination, scope, block, value) + this.into(destination, block, value) }) }) } ExprKind::Block { body: ast_block } => { - this.ast_block(destination, scope, block, ast_block, source_info) + this.ast_block(destination, block, ast_block, source_info) } ExprKind::Match { scrutinee, arms } => { - this.match_expr(destination, scope, expr_span, block, scrutinee, arms) + this.match_expr(destination, expr_span, block, scrutinee, arms) } ExprKind::NeverToAny { source } => { let source = this.hir.mirror(source); @@ -83,7 +65,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // This is an optimization. If the expression was a call then we already have an // unreachable block. Don't bother to terminate it and create a new one. - schedule_drop(this); if is_call { block.unit() } else { @@ -159,35 +140,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Start the loop. this.cfg.goto(block, source_info, loop_block); - this.in_breakable_scope( - Some(loop_block), - destination, - scope, - expr_span, - move |this| { - // conduct the test, if necessary - let body_block = this.cfg.start_new_block(); - this.cfg.terminate( - loop_block, - source_info, - TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, - ); - this.diverge_from(loop_block); - - // The “return” value of the loop body must always be an unit. We therefore - // introduce a unit temporary as the destination for the loop body. - let tmp = this.get_unit_temp(); - // Execute the body, branching back to the test. - // We don't need to provide a drop scope because `tmp` - // has type `()`. - let body_block_end = unpack!(this.into(tmp, None, body_block, body)); - this.cfg.goto(body_block_end, source_info, loop_block); - schedule_drop(this); - - // Loops are only exited by `break` expressions. - None - }, - ) + this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| { + // conduct the test, if necessary + let body_block = this.cfg.start_new_block(); + this.cfg.terminate( + loop_block, + source_info, + TerminatorKind::FalseUnwind { real_target: body_block, unwind: None }, + ); + this.diverge_from(loop_block); + + // The “return” value of the loop body must always be an unit. We therefore + // introduce a unit temporary as the destination for the loop body. + let tmp = this.get_unit_temp(); + // Execute the body, branching back to the test. + let body_block_end = unpack!(this.into(tmp, body_block, body)); + this.cfg.goto(body_block_end, source_info, loop_block); + + // Loops are only exited by `break` expressions. + None + }) } ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => { let intrinsic = match *ty.kind() { @@ -220,13 +192,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .push(LocalDecl::with_source_info(ptr_ty, source_info).internal()); let ptr_temp = Place::from(ptr_temp); // No need for a scope, ptr_temp doesn't need drop - let block = unpack!(this.into(ptr_temp, None, block, ptr)); + let block = unpack!(this.into(ptr_temp, block, ptr)); // Maybe we should provide a scope here so that // `move_val_init` wouldn't leak on panic even with an // arbitrary `val` expression, but `schedule_drop`, // borrowck and drop elaboration all prevent us from // dropping `ptr_temp.deref()`. - this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val) + this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val) } else { let args: Vec<_> = args .into_iter() @@ -259,11 +231,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); this.diverge_from(block); - schedule_drop(this); success.unit() } } - ExprKind::Use { source } => this.into(destination, scope, block, source), + ExprKind::Use { source } => this.into(destination, block, source), ExprKind::Borrow { arg, borrow_kind } => { // We don't do this in `as_rvalue` because we use `as_place` // for borrow expressions, so we cannot create an `RValue` that @@ -340,14 +311,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty, active_field_index, ); - this.record_operands_moved(&fields); this.cfg.push_assign( block, source_info, destination, Rvalue::Aggregate(adt, fields), ); - schedule_drop(this); block.unit() } ExprKind::InlineAsm { template, operands, options, line_spans } => { @@ -444,7 +413,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); - schedule_drop(this); block.unit() } ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => { @@ -462,7 +430,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let place = unpack!(block = this.as_place(block, expr)); let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place)); this.cfg.push_assign(block, source_info, destination, rvalue); - schedule_drop(this); block.unit() } @@ -470,14 +437,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = this.local_scope(); let value = unpack!(block = this.as_operand(block, Some(scope), value)); let resume = this.cfg.start_new_block(); - this.record_operands_moved(slice::from_ref(&value)); this.cfg.terminate( block, source_info, TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None }, ); this.generator_drop_cleanup(block); - schedule_drop(this); resume.unit() } @@ -509,7 +474,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let rvalue = unpack!(block = this.as_local_rvalue(block, expr)); this.cfg.push_assign(block, source_info, destination, rvalue); - schedule_drop(this); block.unit() } }; diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index a974ea0db5f3c..f117689d940fd 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -3,7 +3,6 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::*; -use std::slice; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds a block of MIR statements to evaluate the THIR `expr`. @@ -47,7 +46,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if this.hir.needs_drop(lhs.ty) { let rhs = unpack!(block = this.as_local_operand(block, rhs)); let lhs = unpack!(block = this.as_place(block, lhs)); - this.record_operands_moved(slice::from_ref(&rhs)); unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs)); } else { let rhs = unpack!(block = this.as_local_rvalue(block, rhs)); diff --git a/compiler/rustc_mir_build/src/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs index ee1838ddea66c..7264e495b84fd 100644 --- a/compiler/rustc_mir_build/src/build/into.rs +++ b/compiler/rustc_mir_build/src/build/into.rs @@ -6,7 +6,6 @@ use crate::build::{BlockAnd, Builder}; use crate::thir::*; -use rustc_middle::middle::region; use rustc_middle::mir::*; pub(in crate::build) trait EvalInto<'tcx> { @@ -14,7 +13,6 @@ pub(in crate::build) trait EvalInto<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, - scope: Option, block: BasicBlock, ) -> BlockAnd<()>; } @@ -23,14 +21,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn into( &mut self, destination: Place<'tcx>, - scope: Option, block: BasicBlock, expr: E, ) -> BlockAnd<()> where E: EvalInto<'tcx>, { - expr.eval_into(self, destination, scope, block) + expr.eval_into(self, destination, block) } } @@ -39,11 +36,10 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, - scope: Option, block: BasicBlock, ) -> BlockAnd<()> { let expr = builder.hir.mirror(self); - builder.into_expr(destination, scope, block, expr) + builder.into_expr(destination, block, expr) } } @@ -52,9 +48,8 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> { self, builder: &mut Builder<'_, 'tcx>, destination: Place<'tcx>, - scope: Option, block: BasicBlock, ) -> BlockAnd<()> { - builder.into_expr(destination, scope, block, self) + builder.into_expr(destination, block, self) } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 2e108d480932a..c5f9412bf0ebe 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -87,7 +87,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn match_expr( &mut self, destination: Place<'tcx>, - destination_scope: Option, span: Span, mut block: BasicBlock, scrutinee: ExprRef<'tcx>, @@ -108,7 +107,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.lower_match_arms( destination, - destination_scope, scrutinee_place, scrutinee_span, arm_candidates, @@ -215,13 +213,76 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + /// Lower the bindings, guards and arm bodies of a `match` expression. + /// + /// The decision tree should have already been created + /// (by [Builder::lower_match_tree]). + /// + /// `outer_source_info` is the SourceInfo for the whole match. + fn lower_match_arms( + &mut self, + destination: Place<'tcx>, + scrutinee_place: Place<'tcx>, + scrutinee_span: Span, + arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, + outer_source_info: SourceInfo, + fake_borrow_temps: Vec<(Place<'tcx>, Local)>, + ) -> BlockAnd<()> { + let arm_end_blocks: Vec<_> = arm_candidates + .into_iter() + .map(|(arm, candidate)| { + debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); + + let arm_source_info = self.source_info(arm.span); + let arm_scope = (arm.scope, arm_source_info); + self.in_scope(arm_scope, arm.lint_level, |this| { + let body = this.hir.mirror(arm.body.clone()); + let scope = this.declare_bindings( + None, + arm.span, + &arm.pattern, + ArmHasGuard(arm.guard.is_some()), + Some((Some(&scrutinee_place), scrutinee_span)), + ); + + let arm_block = this.bind_pattern( + outer_source_info, + candidate, + arm.guard.as_ref(), + &fake_borrow_temps, + scrutinee_span, + Some(arm.span), + Some(arm.scope), + ); + + if let Some(source_scope) = scope { + this.source_scope = source_scope; + } + + this.into(destination, arm_block, body) + }) + }) + .collect(); + + // all the arm blocks will rejoin here + let end_block = self.cfg.start_new_block(); + + for arm_block in arm_end_blocks { + self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); + } + + self.source_scope = outer_source_info.scope; + + end_block.unit() + } + /// Binds the variables and ascribes types for a given `match` arm or /// `let` binding. /// /// Also check if the guard matches, if it's provided. /// `arm_scope` should be `Some` if and only if this is called for a /// `match` arm. - crate fn bind_pattern( + fn bind_pattern( &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, @@ -308,14 +369,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); - - unpack!(block = self.into(place, Some(region_scope), block, initializer)); + unpack!(block = self.into(place, block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let source_info = self.source_info(irrefutable_pat.span); self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place); + self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -342,10 +402,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ascription: thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span }, } => { - let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); - unpack!(block = self.into(place, Some(region_scope), block, initializer)); + unpack!(block = self.into(place, block, initializer)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. let pattern_source_info = self.source_info(irrefutable_pat.span); @@ -383,6 +442,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ); + self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard); block.unit() } @@ -629,7 +689,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } #[derive(Debug)] -pub(super) struct Candidate<'pat, 'tcx> { +struct Candidate<'pat, 'tcx> { /// `Span` of the original pattern that gave rise to this candidate span: Span, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index e041464381220..a207997f5780d 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -618,12 +618,8 @@ where let arg_scope_s = (arg_scope, source_info); // Attribute epilogue to function's closing brace let fn_end = span_with_body.shrink_to_hi(); - let return_block = unpack!(builder.in_breakable_scope( - None, - Place::return_place(), - Some(call_site_scope), - fn_end, - |builder| { + let return_block = + unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| { Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body( START_BLOCK, @@ -633,13 +629,11 @@ where &body.value, ) })) - }, - )); + })); let source_info = builder.source_info(fn_end); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); let should_abort = should_abort_on_panic(tcx, fn_def_id, abi); builder.build_drop_trees(should_abort); - builder.unschedule_return_place_drop(); return_block.unit() })); @@ -672,9 +666,7 @@ fn construct_const<'a, 'tcx>( let mut block = START_BLOCK; let ast_expr = &tcx.hir().body(body_id).value; let expr = builder.hir.mirror(ast_expr); - // We don't provide a scope because we can't unwind in constants, so won't - // need to drop the return place. - unpack!(block = builder.into_expr(Place::return_place(), None, block, expr)); + unpack!(block = builder.into_expr(Place::return_place(), block, expr)); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -963,9 +955,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let body = self.hir.mirror(ast_body); - let call_site = - region::Scope { id: ast_body.hir_id.local_id, data: region::ScopeData::CallSite }; - self.into(Place::return_place(), Some(call_site), block, body) + self.into(Place::return_place(), block, body) } fn set_correct_source_scope_for_arg( diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 62d2212d10962..e76175c0456a8 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -81,10 +81,9 @@ that contains only loops and breakable blocks. It tracks where a `break`, */ -use crate::build::matches::{ArmHasGuard, Candidate}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; -use crate::thir::{Arm, Expr, ExprRef, LintLevel}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use crate::thir::{Expr, ExprRef, LintLevel}; +use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::*; @@ -121,6 +120,8 @@ struct Scope { /// end of the vector (top of the stack) first. drops: Vec, + moved_locals: Vec, + /// The drop index that will drop everything in and below this scope on an /// unwind path. cached_unwind_block: Option, @@ -156,8 +157,6 @@ struct BreakableScope<'tcx> { /// The destination of the loop/block expression itself (i.e., where to put /// the result of a `break` or `return` expression) break_destination: Place<'tcx>, - /// The scope that the destination should have its drop scheduled in. - destination_scope: Option, /// Drops that happen on the `break`/`return` path. break_drops: DropTree, /// Drops that happen on the `continue` path. @@ -406,6 +405,7 @@ impl<'tcx> Scopes<'tcx> { region_scope: region_scope.0, region_scope_span: region_scope.1.span, drops: vec![], + moved_locals: vec![], cached_unwind_block: None, cached_generator_drop_block: None, }); @@ -440,7 +440,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, loop_block: Option, break_destination: Place<'tcx>, - destination_scope: Option, span: Span, f: F, ) -> BlockAnd<()> @@ -451,19 +450,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let scope = BreakableScope { region_scope, break_destination, - destination_scope, break_drops: DropTree::new(), continue_drops: loop_block.map(|_| DropTree::new()), }; - let continue_block = loop_block.map(|block| (block, self.diverge_cleanup())); self.scopes.breakable_scopes.push(scope); let normal_exit_block = f(self); let breakable_scope = self.scopes.breakable_scopes.pop().unwrap(); assert!(breakable_scope.region_scope == region_scope); + let break_block = self.build_exit_tree(breakable_scope.break_drops, None); if let Some(drops) = breakable_scope.continue_drops { - self.build_exit_tree(drops, continue_block); + self.build_exit_tree(drops, loop_block); } - let break_block = self.build_exit_tree(breakable_scope.break_drops, None); match (normal_exit_block, break_block) { (Some(block), None) | (None, Some(block)) => block, (None, None) => self.cfg.start_new_block().unit(), @@ -592,22 +589,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .rposition(|breakable_scope| breakable_scope.region_scope == scope) .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found")) }; - let (break_index, destination, dest_scope) = match target { + let (break_index, destination) = match target { BreakableTarget::Return => { let scope = &self.scopes.breakable_scopes[0]; if scope.break_destination != Place::return_place() { span_bug!(span, "`return` in item with no return scope"); } - (0, Some(scope.break_destination), scope.destination_scope) + (0, Some(scope.break_destination)) } BreakableTarget::Break(scope) => { let break_index = get_scope_index(scope); let scope = &self.scopes.breakable_scopes[break_index]; - (break_index, Some(scope.break_destination), scope.destination_scope) + (break_index, Some(scope.break_destination)) } BreakableTarget::Continue(scope) => { let break_index = get_scope_index(scope); - (break_index, None, None) + (break_index, None) } }; @@ -615,10 +612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let Some(value) = value { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); - unpack!(block = self.into(destination, dest_scope, block, value)); - if let Some(scope) = dest_scope { - self.unschedule_drop(scope, destination.as_local().unwrap()) - }; + unpack!(block = self.into(destination, block, value)); self.block_context.pop(); } else { self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx()) @@ -858,47 +852,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local); } - /// Unschedule a drop. Used for `break`, `return` and `match` expressions, - /// where `record_operands_moved` is not powerful enough. - /// - /// The given local is expected to have a value drop scheduled in the given - /// scope and for that drop to be the most recent thing scheduled in that - /// scope. - fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) { - if !self.hir.needs_drop(self.local_decls[local].ty) { - return; - } - for scope in self.scopes.scopes.iter_mut().rev() { - scope.invalidate_cache(); - - if scope.region_scope == region_scope { - let drop = scope.drops.pop(); - - match drop { - Some(DropData { local: removed_local, kind: DropKind::Value, .. }) - if removed_local == local => - { - return; - } - _ => bug!( - "found wrong drop, expected value drop of {:?}, found {:?}", - local, - drop, - ), - } - } - } - - bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local); - } - - /// Indicates that the "local operands" stored in `local` is + /// Indicates that the "local operand" stored in `local` is /// *moved* at some point during execution (see `local_scope` for /// more information about what a "local operand" is -- in short, /// it's an intermediate operand created as part of preparing some /// MIR instruction). We use this information to suppress - /// redundant drops. This results in less MIR, but also avoids spurious - /// borrow check errors (c.f. #64391). + /// redundant drops on the non-unwind paths. This results in less + /// MIR, but also avoids spurious borrow check errors + /// (c.f. #64391). /// /// Example: when compiling the call to `foo` here: /// @@ -937,19 +898,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); // look for moves of a local variable, like `MOVE(_X)` - let locals_moved = operands - .iter() - .filter_map(|operand| match operand { - Operand::Copy(_) | Operand::Constant(_) => None, - Operand::Move(place) => place.as_local(), - }) - .collect::>(); + let locals_moved = operands.iter().flat_map(|operand| match operand { + Operand::Copy(_) | Operand::Constant(_) => None, + Operand::Move(place) => place.as_local(), + }); - // Remove the drops for the moved operands. - scope - .drops - .retain(|drop| drop.kind == DropKind::Storage || !locals_moved.contains(&drop.local)); - scope.invalidate_cache(); + for local in locals_moved { + // check if we have a Drop for this operand and -- if so + // -- add it to the list of moved operands. Note that this + // local might not have been an operand created for this + // call, it could come from other places too. + if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) { + scope.moved_locals.push(local); + } + } } // Other @@ -1136,97 +1098,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { success_block } - /// Lower the arms and guards of a match. - /// - /// The decision tree should have already been created (by - /// [Builder::lower_match_tree]). - /// - /// This is this module, and not in `build::matches` because we have to do - /// some careful scope manipulation to have the drop of the destination be - /// scheduled at the end of each arm and then cleared for the next arm. - crate fn lower_match_arms( - &mut self, - destination: Place<'tcx>, - destination_scope: Option, - scrutinee_place: Place<'tcx>, - scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, - outer_source_info: SourceInfo, - fake_borrow_temps: Vec<(Place<'tcx>, Local)>, - ) -> BlockAnd<()> { - if arm_candidates.is_empty() { - // If there are no arms to schedule drops, then we have to do it - // manually. - if let Some(scope) = destination_scope { - self.schedule_drop( - outer_source_info.span, - scope, - destination.as_local().unwrap(), - DropKind::Value, - ); - } - return self.cfg.start_new_block().unit(); - } - let mut first_arm = true; - let arm_end_blocks: Vec<_> = arm_candidates - .into_iter() - .map(|(arm, candidate)| { - debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate); - - if first_arm { - first_arm = false; - } else if let Some(scope) = destination_scope { - self.unschedule_drop(scope, destination.as_local().unwrap()); - } - - let arm_source_info = self.source_info(arm.span); - let arm_scope = (arm.scope, arm_source_info); - self.in_scope(arm_scope, arm.lint_level, |this| { - let body = this.hir.mirror(arm.body.clone()); - let scope = this.declare_bindings( - None, - arm.span, - &arm.pattern, - ArmHasGuard(arm.guard.is_some()), - Some((Some(&scrutinee_place), scrutinee_span)), - ); - - let arm_block = this.bind_pattern( - outer_source_info, - candidate, - arm.guard.as_ref(), - &fake_borrow_temps, - scrutinee_span, - Some(arm.span), - Some(arm.scope), - ); - - if let Some(source_scope) = scope { - this.source_scope = source_scope; - } - - this.into(destination, destination_scope, arm_block, body) - }) - }) - .collect(); - - // all the arm blocks will rejoin here - let end_block = self.cfg.start_new_block(); - - for arm_block in arm_end_blocks { - self.cfg.goto(unpack!(arm_block), outer_source_info, end_block); - } - - self.source_scope = outer_source_info.scope; - - end_block.unit() - } - /// Unschedules any drops in the top scope. /// /// This is only needed for `match` arm scopes, because they have one /// entrance per pattern, but only one exit. - pub(super) fn clear_top_scope(&mut self, region_scope: region::Scope) { + crate fn clear_top_scope(&mut self, region_scope: region::Scope) { let top_scope = self.scopes.scopes.last_mut().unwrap(); assert_eq!(top_scope.region_scope, region_scope); @@ -1234,18 +1110,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { top_scope.drops.clear(); top_scope.invalidate_cache(); } - - /// Unschedules the drop of the return place. - /// - /// If the return type of a function requires drop, then we schedule it - /// in the outermost scope so that it's dropped if there's a panic while - /// we drop any local variables. But we don't want to drop it if we - /// return normally. - crate fn unschedule_return_place_drop(&mut self) { - assert_eq!(self.scopes.scopes.len(), 1); - assert!(self.scopes.scopes[0].drops.len() <= 1); - self.scopes.scopes[0].drops.clear(); - } } /// Builds drops for `pop_scope` and `leave_top_scope`. @@ -1292,6 +1156,14 @@ fn build_scope_drops<'tcx>( debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind); unwind_to = unwind_drops.drops[unwind_to].1; + // If the operand has been moved, and we are not on an unwind + // path, then don't generate the drop. (We only take this into + // account for non-unwind paths so as not to disturb the + // caching mechanism.) + if scope.moved_locals.iter().any(|&o| o == local) { + continue; + } + unwind_drops.add_entry(block, unwind_to); let next = cfg.start_new_block(); @@ -1321,24 +1193,20 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> { /// Build a drop tree for a breakable scope. /// /// If `continue_block` is `Some`, then the tree is for `continue` inside a - /// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the - /// next drop in the case that the drop tree unwinds. This is needed - /// because the drop of the break destination has already been scheduled - /// but it hasn't been initialized on the `continue` paths. + /// loop. Otherwise this is for `break` or `return`. fn build_exit_tree( &mut self, mut drops: DropTree, - continue_block: Option<(BasicBlock, DropIdx)>, + continue_block: Option, ) -> Option> { let mut blocks = IndexVec::from_elem(None, &drops.drops); - blocks[ROOT_NODE] = continue_block.map(|(block, _)| block); + blocks[ROOT_NODE] = continue_block; drops.build_mir::(&mut self.cfg, &mut blocks); // Link the exit drop tree to unwind drop tree. if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) { - let unwind_target = continue_block - .map_or_else(|| self.diverge_cleanup(), |(_, unwind_target)| unwind_target); + let unwind_target = self.diverge_cleanup(); let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1); for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) { match drop_data.0.kind { diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index c857d4317e495..90bef37f71a93 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1772,7 +1772,7 @@ fn test_append_drop_leak() { catch_unwind(move || left.append(&mut right)).unwrap_err(); - assert_eq!(DROPS.load(SeqCst), 5); + assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy } #[test] diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 0c7b64cb97f8f..7e0ca3dea4b71 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -41,36 +41,44 @@ fn main() -> () { StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 StorageLive(_6); // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 _6 = move _4; // scope 4 at $DIR/basic_assignment.rs:23:14: 23:20 - replace(_5 <- move _6) -> [return: bb1, unwind: bb4]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 + replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:23:5: 23:11 } bb1: { + drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 + } + + bb2: { StorageDead(_6); // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 _0 = const (); // scope 0 at $DIR/basic_assignment.rs:10:11: 24:2 - drop(_5) -> [return: bb2, unwind: bb5]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb2: { + bb3: { StorageDead(_5); // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 - drop(_4) -> [return: bb3, unwind: bb6]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 } - bb3: { + bb4: { StorageDead(_4); // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_2); // scope 1 at $DIR/basic_assignment.rs:24:1: 24:2 StorageDead(_1); // scope 0 at $DIR/basic_assignment.rs:24:1: 24:2 return; // scope 0 at $DIR/basic_assignment.rs:24:2: 24:2 } - bb4 (cleanup): { - drop(_5) -> bb5; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 - } - bb5 (cleanup): { - drop(_4) -> bb6; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + drop(_6) -> bb6; // scope 4 at $DIR/basic_assignment.rs:23:19: 23:20 } bb6 (cleanup): { + drop(_5) -> bb7; // scope 3 at $DIR/basic_assignment.rs:24:1: 24:2 + } + + bb7 (cleanup): { + drop(_4) -> bb8; // scope 2 at $DIR/basic_assignment.rs:24:1: 24:2 + } + + bb8 (cleanup): { resume; // scope 0 at $DIR/basic_assignment.rs:10:1: 24:2 } } diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index 20ea7b026bc6e..cfbd3a58637c0 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -14,7 +14,7 @@ fn main() -> () { StorageLive(_1); // scope 0 at $DIR/box_expr.rs:7:9: 7:10 StorageLive(_2); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 _2 = Box(S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25 - (*_2) = S::new() -> [return: bb1, unwind: bb5]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 + (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25 // mir::Constant // + span: $DIR/box_expr.rs:7:17: 7:23 // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar()) } @@ -22,37 +22,45 @@ fn main() -> () { bb1: { _1 = move _2; // scope 0 at $DIR/box_expr.rs:7:13: 7:25 + drop(_2) -> bb2; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb2: { StorageDead(_2); // scope 0 at $DIR/box_expr.rs:7:24: 7:25 StorageLive(_3); // scope 1 at $DIR/box_expr.rs:8:5: 8:12 StorageLive(_4); // scope 1 at $DIR/box_expr.rs:8:10: 8:11 _4 = move _1; // scope 1 at $DIR/box_expr.rs:8:10: 8:11 - _3 = std::mem::drop::>(move _4) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _3 = std::mem::drop::>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 // mir::Constant // + span: $DIR/box_expr.rs:8:5: 8:9 // + literal: Const { ty: fn(std::boxed::Box) {std::mem::drop::>}, val: Value(Scalar()) } } - bb2: { + bb3: { StorageDead(_4); // scope 1 at $DIR/box_expr.rs:8:11: 8:12 StorageDead(_3); // scope 1 at $DIR/box_expr.rs:8:12: 8:13 _0 = const (); // scope 0 at $DIR/box_expr.rs:6:11: 9:2 - drop(_1) -> bb3; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + drop(_1) -> bb4; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 } - bb3: { + bb4: { StorageDead(_1); // scope 0 at $DIR/box_expr.rs:9:1: 9:2 return; // scope 0 at $DIR/box_expr.rs:9:2: 9:2 } - bb4 (cleanup): { - drop(_1) -> bb6; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 - } - bb5 (cleanup): { - drop(_2) -> bb6; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + drop(_4) -> bb6; // scope 1 at $DIR/box_expr.rs:8:11: 8:12 } bb6 (cleanup): { + drop(_1) -> bb8; // scope 0 at $DIR/box_expr.rs:9:1: 9:2 + } + + bb7 (cleanup): { + drop(_2) -> bb8; // scope 0 at $DIR/box_expr.rs:7:24: 7:25 + } + + bb8 (cleanup): { resume; // scope 0 at $DIR/box_expr.rs:6:1: 9:2 } } diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff index 22737381c71ae..07994eb3c1661 100644 --- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff +++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff @@ -5,19 +5,18 @@ let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12 let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ let mut _7: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _8: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 -+ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 1 (inlined call_twice:: ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22 + debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let _3: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + let mut _6: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ let mut _7: !; // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 2 { + debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:22:5: 22:22 + scope 3 { -+ debug b => _7; // in scope 3 at $DIR/inline-diverging.rs:22:5: 22:22 ++ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:22:5: 22:22 + } + scope 6 (inlined ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:22:5: 22:22 + scope 7 (inlined sleep) { // at $DIR/inline-diverging.rs:22:5: 22:22 @@ -41,12 +40,12 @@ - // mir::Constant // + span: $DIR/inline-diverging.rs:22:16: 22:21 // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar()) } -+ StorageLive(_7); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_6); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ StorageLive(_8); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 -+ _8 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ StorageLive(_7); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 ++ _7 = const (); // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22 + goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22 } diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir index bbbd2bcf128b1..7113c42b9c77f 100644 --- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir @@ -6,18 +6,21 @@ fn main() -> () { let mut _2: S; // in scope 0 at $DIR/issue-41110.rs:8:13: 8:14 let mut _3: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:27 let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:8:21: 8:22 + let mut _5: bool; // in scope 0 at $DIR/issue-41110.rs:8:27: 8:28 scope 1 { debug x => _1; // in scope 1 at $DIR/issue-41110.rs:8:9: 8:10 } bb0: { + _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:8:9: 8:10 StorageLive(_2); // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 + _5 = const true; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 _2 = S; // scope 0 at $DIR/issue-41110.rs:8:13: 8:14 StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 _4 = S; // scope 0 at $DIR/issue-41110.rs:8:21: 8:22 - _3 = S::id(move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 + _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27 // mir::Constant // + span: $DIR/issue-41110.rs:8:23: 8:25 // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(Scalar()) } @@ -25,7 +28,8 @@ fn main() -> () { bb1: { StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 - _1 = S::other(move _2, move _3) -> bb2; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 + _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 + _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28 // mir::Constant // + span: $DIR/issue-41110.rs:8:15: 8:20 // + literal: Const { ty: fn(S, S) {S::other}, val: Value(Scalar()) } @@ -33,6 +37,7 @@ fn main() -> () { bb2: { StorageDead(_3); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + _5 = const false; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 _0 = const (); // scope 0 at $DIR/issue-41110.rs:7:11: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:9:1: 9:2 @@ -40,10 +45,26 @@ fn main() -> () { } bb3 (cleanup): { - drop(_2) -> bb4; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 } bb4 (cleanup): { + goto -> bb5; // scope 0 at $DIR/issue-41110.rs:8:26: 8:27 + } + + bb5 (cleanup): { + goto -> bb8; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + } + + bb6 (cleanup): { resume; // scope 0 at $DIR/issue-41110.rs:7:1: 9:2 } + + bb7 (cleanup): { + drop(_2) -> bb6; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + } + + bb8 (cleanup): { + switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:8:27: 8:28 + } } diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir index b0c7260f0f4dc..c4e852ca3212a 100644 --- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir @@ -25,7 +25,7 @@ fn test() -> () { StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 _4 = move _2; // scope 2 at $DIR/issue-41110.rs:17:10: 17:11 - _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb5]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 + _3 = std::mem::drop::(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12 // mir::Constant // + span: $DIR/issue-41110.rs:17:5: 17:9 // + literal: Const { ty: fn(S) {std::mem::drop::}, val: Value(Scalar()) } @@ -37,53 +37,65 @@ fn test() -> () { StorageLive(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _6 = const false; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _5 = move _1; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 - goto -> bb9; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb12; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } bb2: { + goto -> bb3; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 + } + + bb3: { StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 _0 = const (); // scope 0 at $DIR/issue-41110.rs:14:15: 19:2 - drop(_2) -> [return: bb3, unwind: bb6]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 } - bb3: { + bb4: { StorageDead(_2); // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 - goto -> bb4; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + goto -> bb5; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb4: { + bb5: { _6 = const false; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 return; // scope 0 at $DIR/issue-41110.rs:19:2: 19:2 } - bb5 (cleanup): { - goto -> bb6; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 - } - bb6 (cleanup): { - goto -> bb11; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + goto -> bb8; // scope 2 at $DIR/issue-41110.rs:18:9: 18:10 } bb7 (cleanup): { - resume; // scope 0 at $DIR/issue-41110.rs:14:1: 19:2 + goto -> bb8; // scope 2 at $DIR/issue-41110.rs:17:11: 17:12 } bb8 (cleanup): { + goto -> bb9; // scope 1 at $DIR/issue-41110.rs:19:1: 19:2 + } + + bb9 (cleanup): { + goto -> bb14; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + } + + bb10 (cleanup): { + resume; // scope 0 at $DIR/issue-41110.rs:14:1: 19:2 + } + + bb11 (cleanup): { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 - goto -> bb5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 + goto -> bb6; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb9: { + bb12: { _2 = move _5; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 goto -> bb2; // scope 2 at $DIR/issue-41110.rs:18:5: 18:6 } - bb10 (cleanup): { - drop(_1) -> bb7; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb13 (cleanup): { + drop(_1) -> bb10; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } - bb11 (cleanup): { - switchInt(_6) -> [false: bb7, otherwise: bb10]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 + bb14 (cleanup): { + switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:19:1: 19:2 } } diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir index 5011c2adfa581..453886f3effdf 100644 --- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir +++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir @@ -26,7 +26,7 @@ fn main() -> () { _8 = const false; // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:7:9: 7:10 StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 - _2 = cond() -> [return: bb1, unwind: bb9]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 + _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14 // mir::Constant // + span: $DIR/issue-41888.rs:8:8: 8:12 // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } @@ -38,7 +38,7 @@ fn main() -> () { bb2: { _0 = const (); // scope 1 at $DIR/issue-41888.rs:14:6: 14:6 - goto -> bb7; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 + goto -> bb8; // scope 1 at $DIR/issue-41888.rs:8:5: 14:6 } bb3: { @@ -47,34 +47,38 @@ fn main() -> () { _4 = K; // scope 1 at $DIR/issue-41888.rs:9:18: 9:19 _3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:9:13: 9:20 StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 - goto -> bb12; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb14; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } bb4: { + goto -> bb5; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 + } + + bb5: { StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 _5 = discriminant(_1); // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 - switchInt(move _5) -> [0_isize: bb6, otherwise: bb5]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 + switchInt(move _5) -> [0_isize: bb7, otherwise: bb6]; // scope 1 at $DIR/issue-41888.rs:10:16: 10:24 } - bb5: { + bb6: { _0 = const (); // scope 1 at $DIR/issue-41888.rs:13:10: 13:10 - goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb6: { + bb7: { StorageLive(_6); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _9 = const false; // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _6 = move ((_1 as F).0: K); // scope 1 at $DIR/issue-41888.rs:10:21: 10:23 _0 = const (); // scope 2 at $DIR/issue-41888.rs:10:29: 13:10 StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:13:9: 13:10 - goto -> bb7; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 + goto -> bb8; // scope 1 at $DIR/issue-41888.rs:10:9: 13:10 } - bb7: { - goto -> bb18; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb8: { + goto -> bb20; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb8: { + bb9: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 _8 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 _9 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 @@ -83,23 +87,27 @@ fn main() -> () { return; // scope 0 at $DIR/issue-41888.rs:15:2: 15:2 } - bb9 (cleanup): { - goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb10 (cleanup): { + goto -> bb11; // scope 1 at $DIR/issue-41888.rs:9:19: 9:20 + } + + bb11 (cleanup): { + goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb10 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/issue-41888.rs:6:1: 15:2 } - bb11 (cleanup): { + bb13 (cleanup): { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _1 = move _3; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 - goto -> bb9; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 + goto -> bb10; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb12: { + bb14: { _7 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _8 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 _9 = const true; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 @@ -107,38 +115,38 @@ fn main() -> () { goto -> bb4; // scope 1 at $DIR/issue-41888.rs:9:9: 9:10 } - bb13: { + bb15: { _7 = const false; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - goto -> bb8; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + goto -> bb9; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb14 (cleanup): { - goto -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb16 (cleanup): { + goto -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb15: { - drop(_1) -> [return: bb13, unwind: bb10]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb17: { + drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb16 (cleanup): { - drop(_1) -> bb10; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb18 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb17: { + bb19: { _10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _10) -> [0_isize: bb13, otherwise: bb15]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb18: { - switchInt(_7) -> [false: bb13, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb20: { + switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb19 (cleanup): { + bb21 (cleanup): { _11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 - switchInt(move _11) -> [0_isize: bb14, otherwise: bb16]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } - bb20 (cleanup): { - switchInt(_7) -> [false: bb10, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 + bb22 (cleanup): { + switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:15:1: 15:2 } } diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index f74cdd7191927..c1421f20a0ba2 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -30,7 +30,7 @@ fn test() -> Option> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(std::option::Option) -> std::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } @@ -48,11 +48,7 @@ fn test() -> Option> { (*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 - StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb3: { @@ -65,7 +61,7 @@ fn test() -> Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = >::from(move _9) -> [return: bb5, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = >::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } @@ -73,7 +69,7 @@ fn test() -> Option> { bb5: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb10]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 + _0 = > as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } @@ -82,29 +78,41 @@ fn test() -> Option> { bb6: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> [return: bb7, unwind: bb9]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb7: { + StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + } + + bb8: { + StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + } + + bb9: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb8; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb8: { + bb10: { return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb9 (cleanup): { - drop(_0) -> bb11; // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 + bb11 (cleanup): { + drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } - bb10 (cleanup): { - drop(_2) -> bb11; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + bb12 (cleanup): { + drop(_2) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb11 (cleanup): { + bb13 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index 2f95931d2b2a1..bbb433dbe25c7 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -28,7 +28,7 @@ fn main() -> () { bb1: { StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 - _1 = std::mem::drop::(move _2) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + _1 = std::mem::drop::(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 // + literal: Const { ty: fn(std::string::String) {std::mem::drop::}, val: Value(Scalar()) } @@ -41,4 +41,12 @@ fn main() -> () { _0 = const (); // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:11: 10:2 return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:10:2: 10:2 } + + bb3 (cleanup): { + drop(_2) -> bb4; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:34: 9:35 + } + + bb4 (cleanup): { + resume; // scope 0 at $DIR/no-spurious-drop-after-call.rs:8:1: 10:2 + } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index 9bca5d24605fb..d18f6308ded84 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -22,38 +22,62 @@ fn move_out_by_subslice() -> () { _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19 + drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 + } + + bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26 + drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 + } + + bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27 + drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _6 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2 - drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb1: { + bb5: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2 - drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 } - bb2: { + bb6: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2 } - bb3 (cleanup): { - drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + bb7 (cleanup): { + drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2 + } + + bb8 (cleanup): { + drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 + } + + bb9 (cleanup): { + drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27 } - bb4 (cleanup): { + bb10 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2 } } diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir index c9004416f2ec1..eda8e5fd3afe7 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir @@ -22,38 +22,62 @@ fn move_out_from_end() -> () { _3 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 (*_3) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 _2 = move _3; // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19 + drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 + } + + bb1: { StorageDead(_3); // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19 StorageLive(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 StorageLive(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 _5 = Box(i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 (*_5) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _4 = move _5; // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26 + drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 + } + + bb2: { StorageDead(_5); // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26 _1 = [move _2, move _4]; // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27 + drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb3: { StorageDead(_4); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb4: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 FakeRead(ForLet, _1); // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10 StorageLive(_6); // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _6 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2 - drop(_6) -> [return: bb1, unwind: bb3]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb1: { + bb5: { StorageDead(_6); // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2 - drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 } - bb2: { + bb6: { StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 return; // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2 } - bb3 (cleanup): { - drop(_1) -> bb4; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + bb7 (cleanup): { + drop(_1) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2 + } + + bb8 (cleanup): { + drop(_4) -> bb9; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 + } + + bb9 (cleanup): { + drop(_2) -> bb10; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27 } - bb4 (cleanup): { + bb10 (cleanup): { resume; // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2 } } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt index 4c03e950af029..e14e733fff6d4 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt @@ -19,12 +19,12 @@ 18| 2| println!("used_only_from_bin_crate_generic_function with {:?}", arg); 19| 2|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: + | used_crate::used_only_from_bin_crate_generic_function::<&str>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} ------------------ - | used_crate::used_only_from_bin_crate_generic_function::<&str>: + | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec>: | 17| 1|pub fn used_only_from_bin_crate_generic_function(arg: T) { | 18| 1| println!("used_only_from_bin_crate_generic_function with {:?}", arg); | 19| 1|} diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html index 19707255d07c7..81310c8cb25aa 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.executor-block_on.-------.InstrumentCoverage.0.html @@ -70,166 +70,166 @@
@0,1,2,3,4,5⦊pub fn block_on<F: Future>(mut future: F) -> F::Output { let mut future = unsafe { Pin::new_unchecked(&mut future) }; static VTABLE: RawWakerVTable = RawWakerVTable::new( |_| unimplemented!("clone"), |_| unimplemented!("wake"), |_| unimplemented!("wake_by_ref"), |_| (), ); let waker = unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &VTABLE)) }; let mut context = Context::from_waker(&waker)⦉@0,1,2,3,4,5; loop { if let Poll::Ready(@10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17) = @6,7,8,9⦊future.as_mut().poll(&mut context)⦉@6,7,8,9 { break @10,12,14,15,16,17⦊val⦉@10,12,14,15,16,17; }@11,13⦊⦉@11,13 diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html index 611799161d398..313a36ed6c2f2 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.async/async.main.-------.InstrumentCoverage.0.html @@ -69,9 +69,9 @@ -
@0,1,2,3,4,5,6,7,8,9,10,11,12,13⦊fn main() { - let _ = g(10); - let _ = h(9); - let mut future = Box::pin(i(8)); - j(7); - l(6); - let _ = m(5); - executor::block_on(future.as_mut()); -@4,5,6,7,8⦊format!("'{}'", val) @@ -117,13 +117,13 @@ 103:9-103:29: @4[23]: _18 = (_16.0: &&str) 103:9-103:29: @4[26]: _20 = &(*_18) 103:9-103:29: @4[28]: _21 = <&str as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r &str, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) -103:9-103:29: @4.Call: _19 = ArgumentV1::new::<&str>(move _20, move _21) -> [return: bb5, unwind: bb10] +103:9-103:29: @4.Call: _19 = ArgumentV1::new::<&str>(move _20, move _21) -> [return: bb5, unwind: bb9] 103:9-103:29: @5[2]: _15 = [move _19] 103:9-103:29: @5[5]: _14 = &_15 103:9-103:29: @5[6]: _13 = &(*_14) 103:9-103:29: @5[7]: _12 = move _13 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) -103:9-103:29: @5.Call: _7 = Arguments::new_v1(move _8, move _12) -> [return: bb6, unwind: bb10] -103:9-103:29: @6.Call: _6 = format(move _7) -> [return: bb7, unwind: bb10] +103:9-103:29: @5.Call: _7 = Arguments::new_v1(move _8, move _12) -> [return: bb6, unwind: bb9] +103:9-103:29: @6.Call: _6 = format(move _7) -> [return: bb7, unwind: bb9] 103:9-103:29: @7[1]: FakeRead(ForLet, _6) 103:9-103:29: @7[6]: _0 = move _6 104:6-104:6: @8.Return: return"> }⦉@4,5,6,7,8
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html index 3bd446b0e049d..702c7937064b7 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.closure/closure.main.-------.InstrumentCoverage.0.html @@ -69,7079 +69,7079 @@ -
@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊fn main() { -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊fn main() { + // Initialize test constants in a way that cannot be determined at compile time, to ensure - // Initialize test constants in a way that cannot be determined at compile time, to ensure + // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + // dependent conditions. - // dependent conditions. + let is_true = std::env::args().len() == 1; - let is_true = std::env::args().len() == 1; + let is_false = ! is_true; - let is_false = ! is_true; + - + let mut some_string = Some(String::from("the string content")); - let mut some_string = Some(String::from("the string content")); + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 1".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ + ) - ) + ); - ); + - + some_string = Some(String::from("the string content")); - some_string = Some(String::from("the string content")); + let - let + a - a + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 2".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + a - a + ) - ) + ); - ); + - + some_string = None; - some_string = None; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 3".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ + ) - ) + ); - ); + - + some_string = None; - some_string = None; + let - let + a - a + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +71:19-71:23: @26[9]: _76 = Option::<String>::None +75:9-82:6: @28[3]: _78 = &_5 +73:9-73:10: @28[6]: FakeRead(ForLet, _77) +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|| { let mut countdown = 0; if is_false { countdown = 10; } "alt string 4".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + println!( - println!( + "The string or alt: {}" - "The string or alt: {}" + , - , + some_string - some_string + . - . + unwrap_or_else - unwrap_or_else + ( - ( + a - a + ) - ) + ); - ); + - + let - let + quote_closure - quote_closure + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37|val| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +71:19-71:23: @26[9]: _76 = Option::<String>::None +75:9-82:6: @28[3]: _78 = &_5 +73:9-73:10: @28[6]: FakeRead(ForLet, _77) +84:9-84:32: @28[13]: _134 = const main::promoted[1] +84:9-84:32: @28[14]: _84 = &(*_134) +84:9-84:32: @28[15]: _83 = &(*_84) +84:9-84:32: @28[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @28[26]: _93 = move _7 +90:13-90:14: @28[28]: _94 = _77 +86:9-91:10: @28.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb29, unwind: bb45] +86:9-91:10: @29[2]: _91 = &_92 +83:5-92:7: @29[3]: _90 = (move _91,) +83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @29[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @29[10]: _97 = &(*_95) +83:5-92:7: @29[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @29.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb30, unwind: bb44] +83:5-92:7: @30[2]: _89 = [move _96] +83:5-92:7: @30[5]: _88 = &_89 +83:5-92:7: @30[6]: _87 = &(*_88) +83:5-92:7: @30[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb31, unwind: bb44] +83:5-92:7: @31.Call: _80 = _print(move _81) -> [return: bb32, unwind: bb44] +83:5-92:7: @33[6]: _79 = const () +97:9-104:6: @33[10]: _100 = &_5 +95:9-95:22: @33[13]: FakeRead(ForLet, _99) +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42|val| { let mut countdown = 0; if is_false { countdown = 10; } format!("'{}'", val) - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + println!( - println!( + "Repeated, quoted string: {:?}" - "Repeated, quoted string: {:?}" + , - , + std::iter::repeat("repeat me") - std::iter::repeat("repeat me") + .take(5) - .take(5) + .map - .map + ( - ( + quote_closure - quote_closure + ) - ) + .collect::<Vec<_>>() - .collect::<Vec<_>>() + ); - ); + - + let - let + _unused_closure - _unused_closure + = - = + ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +71:19-71:23: @26[9]: _76 = Option::<String>::None +75:9-82:6: @28[3]: _78 = &_5 +73:9-73:10: @28[6]: FakeRead(ForLet, _77) +84:9-84:32: @28[13]: _134 = const main::promoted[1] +84:9-84:32: @28[14]: _84 = &(*_134) +84:9-84:32: @28[15]: _83 = &(*_84) +84:9-84:32: @28[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @28[26]: _93 = move _7 +90:13-90:14: @28[28]: _94 = _77 +86:9-91:10: @28.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb29, unwind: bb45] +86:9-91:10: @29[2]: _91 = &_92 +83:5-92:7: @29[3]: _90 = (move _91,) +83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @29[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @29[10]: _97 = &(*_95) +83:5-92:7: @29[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @29.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb30, unwind: bb44] +83:5-92:7: @30[2]: _89 = [move _96] +83:5-92:7: @30[5]: _88 = &_89 +83:5-92:7: @30[6]: _87 = &(*_88) +83:5-92:7: @30[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb31, unwind: bb44] +83:5-92:7: @31.Call: _80 = _print(move _81) -> [return: bb32, unwind: bb44] +83:5-92:7: @33[6]: _79 = const () +97:9-104:6: @33[10]: _100 = &_5 +95:9-95:22: @33[13]: FakeRead(ForLet, _99) +106:9-106:40: @33[20]: _133 = const main::promoted[0] +106:9-106:40: @33[21]: _106 = &(*_133) +106:9-106:40: @33[22]: _105 = &(*_106) +106:9-106:40: @33[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @33.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb34, unwind: bb55] +108:9-109:21: @34.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb35, unwind: bb55] +112:13-112:26: @35[2]: _118 = _99 +108:9-113:10: @35.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb36, unwind: bb55] +108:9-114:33: @36.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb37, unwind: bb55] +108:9-114:33: @37[1]: _113 = &_114 +105:5-115:7: @37[2]: _112 = (move _113,) +105:5-115:7: @37[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @37[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @37[9]: _121 = &(*_119) +105:5-115:7: @37[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @37.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb38, unwind: bb43] +105:5-115:7: @38[2]: _111 = [move _120] +105:5-115:7: @38[5]: _110 = &_111 +105:5-115:7: @38[6]: _109 = &(*_110) +105:5-115:7: @38[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @38.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb39, unwind: bb43] +105:5-115:7: @39.Call: _102 = _print(move _103) -> [return: bb40, unwind: bb43] +105:5-115:7: @41[6]: _101 = const () +118:9-118:24: @41[13]: FakeRead(ForLet, _123) +3:11-155:2: @41[38]: _0 = const ()"> ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| mut countdown | { @@ -7149,3773 +7149,3773 @@ countdown = 10; } "closure should be unused".to_owned() - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + - + let mut countdown = 10; - let mut countdown = 10; + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | countdown += 1 let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | countdown += 1@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + - + // Macros can sometimes confuse the coverage results. Compare this next assignment, with an - // Macros can sometimes confuse the coverage results. Compare this next assignment, with an + // unused closure that invokes the `println!()` macro, with the closure assignment above, that - // unused closure that invokes the `println!()` macro, with the closure assignment above, that + // does not use a macro. The closure above correctly shows `0` executions. - // does not use a macro. The closure above correctly shows `0` executions. + let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | println!("not called") let _short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | println!("not called")@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + // The closure assignment above is executed, with a line count of `1`, but the `println!()` - // The closure assignment above is executed, with a line count of `1`, but the `println!()` + // could not have been called, and yet, there is no indication that it wasn't... - // could not have been called, and yet, there is no indication that it wasn't... + - + // ...but adding block braces gives the expected result, showing the block was not executed. - // ...but adding block braces gives the expected result, showing the block was not executed. + let _short_unused_closure_block = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | { println!("not called") } let _short_unused_closure_block = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + - + let _shortish_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| _unused_arg: u8 | { +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +71:19-71:23: @26[9]: _76 = Option::<String>::None +75:9-82:6: @28[3]: _78 = &_5 +73:9-73:10: @28[6]: FakeRead(ForLet, _77) +84:9-84:32: @28[13]: _134 = const main::promoted[1] +84:9-84:32: @28[14]: _84 = &(*_134) +84:9-84:32: @28[15]: _83 = &(*_84) +84:9-84:32: @28[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @28[26]: _93 = move _7 +90:13-90:14: @28[28]: _94 = _77 +86:9-91:10: @28.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb29, unwind: bb45] +86:9-91:10: @29[2]: _91 = &_92 +83:5-92:7: @29[3]: _90 = (move _91,) +83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @29[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @29[10]: _97 = &(*_95) +83:5-92:7: @29[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @29.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb30, unwind: bb44] +83:5-92:7: @30[2]: _89 = [move _96] +83:5-92:7: @30[5]: _88 = &_89 +83:5-92:7: @30[6]: _87 = &(*_88) +83:5-92:7: @30[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb31, unwind: bb44] +83:5-92:7: @31.Call: _80 = _print(move _81) -> [return: bb32, unwind: bb44] +83:5-92:7: @33[6]: _79 = const () +97:9-104:6: @33[10]: _100 = &_5 +95:9-95:22: @33[13]: FakeRead(ForLet, _99) +106:9-106:40: @33[20]: _133 = const main::promoted[0] +106:9-106:40: @33[21]: _106 = &(*_133) +106:9-106:40: @33[22]: _105 = &(*_106) +106:9-106:40: @33[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @33.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb34, unwind: bb55] +108:9-109:21: @34.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb35, unwind: bb55] +112:13-112:26: @35[2]: _118 = _99 +108:9-113:10: @35.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb36, unwind: bb55] +108:9-114:33: @36.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb37, unwind: bb55] +108:9-114:33: @37[1]: _113 = &_114 +105:5-115:7: @37[2]: _112 = (move _113,) +105:5-115:7: @37[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @37[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @37[9]: _121 = &(*_119) +105:5-115:7: @37[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @37.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb38, unwind: bb43] +105:5-115:7: @38[2]: _111 = [move _120] +105:5-115:7: @38[5]: _110 = &_111 +105:5-115:7: @38[6]: _109 = &(*_110) +105:5-115:7: @38[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @38.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb39, unwind: bb43] +105:5-115:7: @39.Call: _102 = _print(move _103) -> [return: bb40, unwind: bb43] +105:5-115:7: @41[6]: _101 = const () +118:9-118:24: @41[13]: FakeRead(ForLet, _123) +130:25-130:27: @41[15]: _125 = const 10_i32 +130:9-130:22: @41[16]: FakeRead(ForLet, _125) +131:33-131:67: @41[19]: _127 = &mut _125 +131:9-131:30: @41[22]: FakeRead(ForLet, _126) +136:9-136:30: @41[25]: FakeRead(ForLet, _128) +141:9-141:36: @41[28]: FakeRead(ForLet, _129) +143:9-143:33: @41[31]: FakeRead(ForLet, _130) +3:11-155:2: @41[38]: _0 = const ()"> let _shortish_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 | { println!("not called") - } }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + - + let _as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +71:19-71:23: @26[9]: _76 = Option::<String>::None +75:9-82:6: @28[3]: _78 = &_5 +73:9-73:10: @28[6]: FakeRead(ForLet, _77) +84:9-84:32: @28[13]: _134 = const main::promoted[1] +84:9-84:32: @28[14]: _84 = &(*_134) +84:9-84:32: @28[15]: _83 = &(*_84) +84:9-84:32: @28[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @28[26]: _93 = move _7 +90:13-90:14: @28[28]: _94 = _77 +86:9-91:10: @28.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb29, unwind: bb45] +86:9-91:10: @29[2]: _91 = &_92 +83:5-92:7: @29[3]: _90 = (move _91,) +83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @29[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @29[10]: _97 = &(*_95) +83:5-92:7: @29[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @29.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb30, unwind: bb44] +83:5-92:7: @30[2]: _89 = [move _96] +83:5-92:7: @30[5]: _88 = &_89 +83:5-92:7: @30[6]: _87 = &(*_88) +83:5-92:7: @30[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb31, unwind: bb44] +83:5-92:7: @31.Call: _80 = _print(move _81) -> [return: bb32, unwind: bb44] +83:5-92:7: @33[6]: _79 = const () +97:9-104:6: @33[10]: _100 = &_5 +95:9-95:22: @33[13]: FakeRead(ForLet, _99) +106:9-106:40: @33[20]: _133 = const main::promoted[0] +106:9-106:40: @33[21]: _106 = &(*_133) +106:9-106:40: @33[22]: _105 = &(*_106) +106:9-106:40: @33[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @33.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb34, unwind: bb55] +108:9-109:21: @34.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb35, unwind: bb55] +112:13-112:26: @35[2]: _118 = _99 +108:9-113:10: @35.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb36, unwind: bb55] +108:9-114:33: @36.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb37, unwind: bb55] +108:9-114:33: @37[1]: _113 = &_114 +105:5-115:7: @37[2]: _112 = (move _113,) +105:5-115:7: @37[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @37[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @37[9]: _121 = &(*_119) +105:5-115:7: @37[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @37.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb38, unwind: bb43] +105:5-115:7: @38[2]: _111 = [move _120] +105:5-115:7: @38[5]: _110 = &_111 +105:5-115:7: @38[6]: _109 = &(*_110) +105:5-115:7: @38[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @38.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb39, unwind: bb43] +105:5-115:7: @39.Call: _102 = _print(move _103) -> [return: bb40, unwind: bb43] +105:5-115:7: @41[6]: _101 = const () +118:9-118:24: @41[13]: FakeRead(ForLet, _123) +130:25-130:27: @41[15]: _125 = const 10_i32 +130:9-130:22: @41[16]: FakeRead(ForLet, _125) +131:33-131:67: @41[19]: _127 = &mut _125 +131:9-131:30: @41[22]: FakeRead(ForLet, _126) +136:9-136:30: @41[25]: FakeRead(ForLet, _128) +141:9-141:36: @41[28]: FakeRead(ForLet, _129) +143:9-143:33: @41[31]: FakeRead(ForLet, _130) +147:9-147:33: @41[34]: FakeRead(ForLet, _131) +3:11-155:2: @41[38]: _0 = const ()"> let _as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 - | { println!("not called") } | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊; -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊; + - + let _almost_as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37| +10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +71:19-71:23: @26[9]: _76 = Option::<String>::None +75:9-82:6: @28[3]: _78 = &_5 +73:9-73:10: @28[6]: FakeRead(ForLet, _77) +84:9-84:32: @28[13]: _134 = const main::promoted[1] +84:9-84:32: @28[14]: _84 = &(*_134) +84:9-84:32: @28[15]: _83 = &(*_84) +84:9-84:32: @28[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @28[26]: _93 = move _7 +90:13-90:14: @28[28]: _94 = _77 +86:9-91:10: @28.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb29, unwind: bb45] +86:9-91:10: @29[2]: _91 = &_92 +83:5-92:7: @29[3]: _90 = (move _91,) +83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @29[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @29[10]: _97 = &(*_95) +83:5-92:7: @29[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @29.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb30, unwind: bb44] +83:5-92:7: @30[2]: _89 = [move _96] +83:5-92:7: @30[5]: _88 = &_89 +83:5-92:7: @30[6]: _87 = &(*_88) +83:5-92:7: @30[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb31, unwind: bb44] +83:5-92:7: @31.Call: _80 = _print(move _81) -> [return: bb32, unwind: bb44] +83:5-92:7: @33[6]: _79 = const () +97:9-104:6: @33[10]: _100 = &_5 +95:9-95:22: @33[13]: FakeRead(ForLet, _99) +106:9-106:40: @33[20]: _133 = const main::promoted[0] +106:9-106:40: @33[21]: _106 = &(*_133) +106:9-106:40: @33[22]: _105 = &(*_106) +106:9-106:40: @33[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @33.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb34, unwind: bb55] +108:9-109:21: @34.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb35, unwind: bb55] +112:13-112:26: @35[2]: _118 = _99 +108:9-113:10: @35.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb36, unwind: bb55] +108:9-114:33: @36.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb37, unwind: bb55] +108:9-114:33: @37[1]: _113 = &_114 +105:5-115:7: @37[2]: _112 = (move _113,) +105:5-115:7: @37[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @37[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @37[9]: _121 = &(*_119) +105:5-115:7: @37[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @37.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb38, unwind: bb43] +105:5-115:7: @38[2]: _111 = [move _120] +105:5-115:7: @38[5]: _110 = &_111 +105:5-115:7: @38[6]: _109 = &(*_110) +105:5-115:7: @38[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @38.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb39, unwind: bb43] +105:5-115:7: @39.Call: _102 = _print(move _103) -> [return: bb40, unwind: bb43] +105:5-115:7: @41[6]: _101 = const () +118:9-118:24: @41[13]: FakeRead(ForLet, _123) +130:25-130:27: @41[15]: _125 = const 10_i32 +130:9-130:22: @41[16]: FakeRead(ForLet, _125) +131:33-131:67: @41[19]: _127 = &mut _125 +131:9-131:30: @41[22]: FakeRead(ForLet, _126) +136:9-136:30: @41[25]: FakeRead(ForLet, _128) +141:9-141:36: @41[28]: FakeRead(ForLet, _129) +143:9-143:33: @41[31]: FakeRead(ForLet, _130) +147:9-147:33: @41[34]: FakeRead(ForLet, _131) +151:9-151:40: @41[37]: FakeRead(ForLet, _132) +3:11-155:2: @41[38]: _0 = const ()"> let _almost_as_short_unused_closure = ⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42| _unused_arg: u8 - | { println!("not called") } | { println!("not called") }@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37⦊ -@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42⦊ + ; - ; +}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37
+10:9-10:24: @5[1]: FakeRead(ForLet, _7) +12:9-12:32: @5[8]: _137 = const main::promoted[4] +12:9-12:32: @5[9]: _14 = &(*_137) +12:9-12:32: @5[10]: _13 = &(*_14) +12:9-12:32: @5[11]: _12 = move _13 as &[&str] (Pointer(Unsize)) +14:9-14:20: @5[21]: _23 = move _7 +14:9-26:10: @5.Call: _22 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:18:13: 25:14]>(move _23, move _24) -> [return: bb6, unwind: bb54] +14:9-26:10: @6[2]: _21 = &_22 +11:5-27:7: @6[3]: _20 = (move _21,) +11:5-27:7: @6[5]: FakeRead(ForMatchedPlace, _20) +11:5-27:7: @6[7]: _26 = (_20.0: &std::string::String) +11:5-27:7: @6[10]: _28 = &(*_26) +11:5-27:7: @6[12]: _29 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +11:5-27:7: @6.Call: _27 = ArgumentV1::new::<String>(move _28, move _29) -> [return: bb7, unwind: bb53] +11:5-27:7: @7[2]: _19 = [move _27] +11:5-27:7: @7[5]: _18 = &_19 +11:5-27:7: @7[6]: _17 = &(*_18) +11:5-27:7: @7[7]: _16 = move _17 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +11:5-27:7: @7.Call: _11 = Arguments::new_v1(move _12, move _16) -> [return: bb8, unwind: bb53] +11:5-27:7: @8.Call: _10 = _print(move _11) -> [return: bb9, unwind: bb53] +11:5-27:7: @10[6]: _9 = const () +29:24-29:58: @10.Call: _31 = <String as From<&str>>::from(const "the string content") -> [return: bb11, unwind: bb55] +29:19-29:59: @11[0]: _30 = Option::<String>::Some(move _31) +33:9-40:6: @14[3]: _33 = &_5 +31:9-31:10: @14[6]: FakeRead(ForLet, _32) +42:9-42:32: @14[13]: _136 = const main::promoted[3] +42:9-42:32: @14[14]: _39 = &(*_136) +42:9-42:32: @14[15]: _38 = &(*_39) +42:9-42:32: @14[16]: _37 = move _38 as &[&str] (Pointer(Unsize)) +44:9-44:20: @14[26]: _48 = move _7 +48:13-48:14: @14[28]: _49 = _32 +44:9-49:10: @14.Call: _47 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:33:9: 40:6]>(move _48, move _49) -> [return: bb15, unwind: bb51] +44:9-49:10: @15[2]: _46 = &_47 +41:5-50:7: @15[3]: _45 = (move _46,) +41:5-50:7: @15[5]: FakeRead(ForMatchedPlace, _45) +41:5-50:7: @15[7]: _50 = (_45.0: &std::string::String) +41:5-50:7: @15[10]: _52 = &(*_50) +41:5-50:7: @15[12]: _53 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +41:5-50:7: @15.Call: _51 = ArgumentV1::new::<String>(move _52, move _53) -> [return: bb16, unwind: bb50] +41:5-50:7: @16[2]: _44 = [move _51] +41:5-50:7: @16[5]: _43 = &_44 +41:5-50:7: @16[6]: _42 = &(*_43) +41:5-50:7: @16[7]: _41 = move _42 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +41:5-50:7: @16.Call: _36 = Arguments::new_v1(move _37, move _41) -> [return: bb17, unwind: bb50] +41:5-50:7: @17.Call: _35 = _print(move _36) -> [return: bb18, unwind: bb50] +41:5-50:7: @19[6]: _34 = const () +52:19-52:23: @19[9]: _54 = Option::<String>::None +54:9-54:32: @21[7]: _135 = const main::promoted[2] +54:9-54:32: @21[8]: _60 = &(*_135) +54:9-54:32: @21[9]: _59 = &(*_60) +54:9-54:32: @21[10]: _58 = move _59 as &[&str] (Pointer(Unsize)) +56:9-56:20: @21[20]: _69 = move _7 +56:9-68:10: @21.Call: _68 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:60:13: 67:14]>(move _69, move _70) -> [return: bb22, unwind: bb48] +56:9-68:10: @22[2]: _67 = &_68 +53:5-69:7: @22[3]: _66 = (move _67,) +53:5-69:7: @22[5]: FakeRead(ForMatchedPlace, _66) +53:5-69:7: @22[7]: _72 = (_66.0: &std::string::String) +53:5-69:7: @22[10]: _74 = &(*_72) +53:5-69:7: @22[12]: _75 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +53:5-69:7: @22.Call: _73 = ArgumentV1::new::<String>(move _74, move _75) -> [return: bb23, unwind: bb47] +53:5-69:7: @23[2]: _65 = [move _73] +53:5-69:7: @23[5]: _64 = &_65 +53:5-69:7: @23[6]: _63 = &(*_64) +53:5-69:7: @23[7]: _62 = move _63 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +53:5-69:7: @23.Call: _57 = Arguments::new_v1(move _58, move _62) -> [return: bb24, unwind: bb47] +53:5-69:7: @24.Call: _56 = _print(move _57) -> [return: bb25, unwind: bb47] +53:5-69:7: @26[6]: _55 = const () +71:19-71:23: @26[9]: _76 = Option::<String>::None +75:9-82:6: @28[3]: _78 = &_5 +73:9-73:10: @28[6]: FakeRead(ForLet, _77) +84:9-84:32: @28[13]: _134 = const main::promoted[1] +84:9-84:32: @28[14]: _84 = &(*_134) +84:9-84:32: @28[15]: _83 = &(*_84) +84:9-84:32: @28[16]: _82 = move _83 as &[&str] (Pointer(Unsize)) +86:9-86:20: @28[26]: _93 = move _7 +90:13-90:14: @28[28]: _94 = _77 +86:9-91:10: @28.Call: _92 = Option::<String>::unwrap_or_else::<[closure@../coverage/closure.rs:75:9: 82:6]>(move _93, move _94) -> [return: bb29, unwind: bb45] +86:9-91:10: @29[2]: _91 = &_92 +83:5-92:7: @29[3]: _90 = (move _91,) +83:5-92:7: @29[5]: FakeRead(ForMatchedPlace, _90) +83:5-92:7: @29[7]: _95 = (_90.0: &std::string::String) +83:5-92:7: @29[10]: _97 = &(*_95) +83:5-92:7: @29[12]: _98 = <String as std::fmt::Display>::fmt as for<'r, 's, 't0> fn(&'r std::string::String, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +83:5-92:7: @29.Call: _96 = ArgumentV1::new::<String>(move _97, move _98) -> [return: bb30, unwind: bb44] +83:5-92:7: @30[2]: _89 = [move _96] +83:5-92:7: @30[5]: _88 = &_89 +83:5-92:7: @30[6]: _87 = &(*_88) +83:5-92:7: @30[7]: _86 = move _87 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +83:5-92:7: @30.Call: _81 = Arguments::new_v1(move _82, move _86) -> [return: bb31, unwind: bb44] +83:5-92:7: @31.Call: _80 = _print(move _81) -> [return: bb32, unwind: bb44] +83:5-92:7: @33[6]: _79 = const () +97:9-104:6: @33[10]: _100 = &_5 +95:9-95:22: @33[13]: FakeRead(ForLet, _99) +106:9-106:40: @33[20]: _133 = const main::promoted[0] +106:9-106:40: @33[21]: _106 = &(*_133) +106:9-106:40: @33[22]: _105 = &(*_106) +106:9-106:40: @33[23]: _104 = move _105 as &[&str] (Pointer(Unsize)) +108:9-108:39: @33.Call: _117 = std::iter::repeat::<&str>(const "repeat me") -> [return: bb34, unwind: bb55] +108:9-109:21: @34.Call: _116 = <std::iter::Repeat<&str> as Iterator>::take(move _117, const 5_usize) -> [return: bb35, unwind: bb55] +112:13-112:26: @35[2]: _118 = _99 +108:9-113:10: @35.Call: _115 = <std::iter::Take<std::iter::Repeat<&str>> as Iterator>::map::<String, [closure@../coverage/closure.rs:97:9: 104:6]>(move _116, move _118) -> [return: bb36, unwind: bb55] +108:9-114:33: @36.Call: _114 = <Map<std::iter::Take<std::iter::Repeat<&str>>, [closure@../coverage/closure.rs:97:9: 104:6]> as Iterator>::collect::<Vec<String>>(move _115) -> [return: bb37, unwind: bb55] +108:9-114:33: @37[1]: _113 = &_114 +105:5-115:7: @37[2]: _112 = (move _113,) +105:5-115:7: @37[4]: FakeRead(ForMatchedPlace, _112) +105:5-115:7: @37[6]: _119 = (_112.0: &std::vec::Vec<std::string::String>) +105:5-115:7: @37[9]: _121 = &(*_119) +105:5-115:7: @37[11]: _122 = <Vec<String> as Debug>::fmt as for<'r, 's, 't0> fn(&'r std::vec::Vec<std::string::String>, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)) +105:5-115:7: @37.Call: _120 = ArgumentV1::new::<Vec<String>>(move _121, move _122) -> [return: bb38, unwind: bb43] +105:5-115:7: @38[2]: _111 = [move _120] +105:5-115:7: @38[5]: _110 = &_111 +105:5-115:7: @38[6]: _109 = &(*_110) +105:5-115:7: @38[7]: _108 = move _109 as &[std::fmt::ArgumentV1] (Pointer(Unsize)) +105:5-115:7: @38.Call: _103 = Arguments::new_v1(move _104, move _108) -> [return: bb39, unwind: bb43] +105:5-115:7: @39.Call: _102 = _print(move _103) -> [return: bb40, unwind: bb43] +105:5-115:7: @41[6]: _101 = const () +118:9-118:24: @41[13]: FakeRead(ForLet, _123) +130:25-130:27: @41[15]: _125 = const 10_i32 +130:9-130:22: @41[16]: FakeRead(ForLet, _125) +131:33-131:67: @41[19]: _127 = &mut _125 +131:9-131:30: @41[22]: FakeRead(ForLet, _126) +136:9-136:30: @41[25]: FakeRead(ForLet, _128) +141:9-141:36: @41[28]: FakeRead(ForLet, _129) +143:9-143:33: @41[31]: FakeRead(ForLet, _130) +147:9-147:33: @41[34]: FakeRead(ForLet, _131) +151:9-151:40: @41[37]: FakeRead(ForLet, _132) +3:11-155:2: @41[38]: _0 = const () +155:2-155:2: @42.Return: return">}⦉@0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42
diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html index 7c44c536379d2..bed5e7bb7ce88 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.used_crate/used_crate.use_this_lib_crate.-------.InstrumentCoverage.0.html @@ -69,122 +69,122 @@ -
@0,1,2,3,4,5,6,7⦊fn use_this_lib_crate() { -@0,1,2,3,4,5,6,7,8⦊fn use_this_lib_crate() { + used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); - used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); + used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - used_with_same_type_from_bin_crate_and_lib_crate_generic_function( + "used from library used_crate.rs", - "used from library used_crate.rs", + ); - ); + let some_vec = vec![5, 6, 7, 8]; - let some_vec = vec![5, 6, 7, 8]; + used_only_from_this_lib_crate_generic_function(some_vec); - used_only_from_this_lib_crate_generic_function(some_vec); + used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); - used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); +}⦉@0,1,2,3,4,5,6,7
+58:20-58:36: @4.Call: _3 = slice::<impl [i32]>::into_vec::<std::alloc::Global>(move _4) -> [return: bb5, unwind: bb12] +58:9-58:17: @5[1]: FakeRead(ForLet, _3) +59:52-59:60: @5[4]: _8 = move _3 +59:5-59:61: @5.Call: _7 = used_only_from_this_lib_crate_generic_function::<Vec<i32>>(move _8) -> [return: bb6, unwind: bb9] +60:5-60:91: @6.Call: _9 = used_only_from_this_lib_crate_generic_function::<&str>(const "used ONLY from library used_crate.rs") -> [return: bb7, unwind: bb10] +53:25-61:2: @7[1]: _0 = const () +61:2-61:2: @8.Return: return">}⦉@0,1,2,3,4,5,6,7,8 diff --git a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html index ba6af60fa5cc9..acb2c7d63f51b 100644 --- a/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/coverage-spanview/expected_mir_dump.uses_crate/uses_crate.main.-------.InstrumentCoverage.0.html @@ -69,125 +69,125 @@ -
@0,1,2,3,4,5,6,7,8⦊fn main() { -@0,1,2,3,4,5,6,7,8,9⦊fn main() { + used_crate::used_function(); - used_crate::used_function(); + let some_vec = vec![1, 2, 3, 4]; - let some_vec = vec![1, 2, 3, 4]; + used_crate::used_only_from_bin_crate_generic_function(&some_vec); - used_crate::used_only_from_bin_crate_generic_function(&some_vec); + used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); - used_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); + used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); - used_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); + used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); - used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function("interesting?"); +}⦉@0,1,2,3,4,5,6,7,8
+7:20-7:36: @3.Call: _2 = slice::<impl [i32]>::into_vec::<std::alloc::Global>(move _3) -> [return: bb4, unwind: bb13] +7:9-7:17: @4[1]: FakeRead(ForLet, _2) +8:59-8:68: @4[4]: _7 = &_2 +8:5-8:69: @4.Call: _6 = used_only_from_bin_crate_generic_function::<&Vec<i32>>(move _7) -> [return: bb5, unwind: bb11] +9:5-9:89: @5.Call: _8 = used_only_from_bin_crate_generic_function::<&str>(const "used from bin uses_crate.rs") -> [return: bb6, unwind: bb11] +10:68-10:76: @6[3]: _10 = move _2 +10:5-10:77: @6.Call: _9 = used_from_bin_crate_and_lib_crate_generic_function::<Vec<i32>>(move _10) -> [return: bb7, unwind: bb10] +11:5-11:98: @7.Call: _11 = used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str>(const "interesting?") -> [return: bb8, unwind: bb11] +5:11-12:2: @8[1]: _0 = const () +12:2-12:2: @9.Return: return">}⦉@0,1,2,3,4,5,6,7,8,9 diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index a952fe8e76e81..c4f7c3786168b 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -43,7 +43,6 @@ impl Future for Defer { /// The `failing_op`-th operation will panic. struct Allocator { data: RefCell>, - name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -55,28 +54,23 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free in {:?}: {:?}", self.name, data); + panic!("missing free: {:?}", data); } } } impl Allocator { - fn new(failing_op: usize, name: &'static str) -> Self { - Allocator { - failing_op, - name, - cur_ops: Cell::new(0), - data: RefCell::new(vec![]), - } + fn new(failing_op: usize) -> Self { + Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) } } - fn alloc(self: &Rc) -> impl Future + 'static { + fn alloc(&self) -> impl Future> + '_ { self.fallible_operation(); let mut data = self.data.borrow_mut(); let addr = data.len(); data.push(true); - Defer { ready: false, value: Some(Ptr(addr, self.clone())) } + Defer { ready: false, value: Some(Ptr(addr, self)) } } fn fallible_operation(&self) { self.cur_ops.set(self.cur_ops.get() + 1); @@ -89,11 +83,11 @@ impl Allocator { // Type that tracks whether it was dropped and can panic when it's created or // destroyed. -struct Ptr(usize, Rc); -impl Drop for Ptr { +struct Ptr<'a>(usize, &'a Allocator); +impl<'a> Drop for Ptr<'a> { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), + false => panic!("double free at index {:?}", self.0), ref mut d => *d = false, } @@ -117,7 +111,7 @@ async fn dynamic_drop(a: Rc, c: bool) { }; } -struct TwoPtrs(Ptr, Ptr); +struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>); async fn struct_dynamic_drop(a: Rc, c0: bool, c1: bool, c: bool) { for i in 0..2 { let x; @@ -238,62 +232,21 @@ async fn move_ref_pattern(a: Rc) { a.alloc().await; } -async fn panic_after_return(a: Rc, c: bool) -> (Ptr,) { - a.alloc().await; - let p = a.alloc().await; - if c { - a.alloc().await; - let q = a.alloc().await; - // We use a return type that isn't used anywhere else to make sure that - // the return place doesn't incorrectly end up in the generator state. - return (a.alloc().await,); - } - (a.alloc().await,) -} - - -async fn panic_after_init_by_loop(a: Rc) { - a.alloc().await; - let p = a.alloc().await; - let q = loop { - a.alloc().await; - let r = a.alloc().await; - break a.alloc().await; - }; -} - -async fn panic_after_init_by_match_with_bindings_and_guard(a: Rc, b: bool) { - a.alloc().await; - let p = a.alloc().await; - let q = match a.alloc().await { - ref _x if b => { - a.alloc().await; - let r = a.alloc().await; - a.alloc().await - } - _x => { - a.alloc().await; - let r = a.alloc().await; - a.alloc().await - }, - }; -} - -fn run_test(cx: &mut Context<'_>, ref f: F, name: &'static str) +fn run_test(cx: &mut Context<'_>, ref f: F) where F: Fn(Rc) -> G, - G: Future, + G: Future, { for polls in 0.. { // Run without any panics to find which operations happen after the // penultimate `poll`. - let first_alloc = Rc::new(Allocator::new(usize::MAX, name)); + let first_alloc = Rc::new(Allocator::new(usize::MAX)); let mut fut = Box::pin(f(first_alloc.clone())); let mut ops_before_last_poll = 0; let mut completed = false; for _ in 0..polls { ops_before_last_poll = first_alloc.cur_ops.get(); - if let Poll::Ready(_) = fut.as_mut().poll(cx) { + if let Poll::Ready(()) = fut.as_mut().poll(cx) { completed = true; } } @@ -302,7 +255,7 @@ where // Start at `ops_before_last_poll` so that we will always be able to // `poll` the expected number of times. for failing_op in ops_before_last_poll..first_alloc.cur_ops.get() { - let alloc = Rc::new(Allocator::new(failing_op + 1, name)); + let alloc = Rc::new(Allocator::new(failing_op + 1)); let f = &f; let cx = &mut *cx; let result = panic::catch_unwind(panic::AssertUnwindSafe(move || { @@ -332,58 +285,48 @@ fn clone_waker(data: *const ()) -> RawWaker { RawWaker::new(data, &RawWakerVTable::new(clone_waker, drop, drop, drop)) } -macro_rules! run_test { - ($ctxt:expr, $e:expr) => { run_test($ctxt, $e, stringify!($e)); }; -} - fn main() { let waker = unsafe { Waker::from_raw(clone_waker(ptr::null())) }; let context = &mut Context::from_waker(&waker); - run_test!(context, |a| dynamic_init(a, false)); - run_test!(context, |a| dynamic_init(a, true)); - run_test!(context, |a| dynamic_drop(a, false)); - run_test!(context, |a| dynamic_drop(a, true)); - - run_test!(context, |a| assignment(a, false, false)); - run_test!(context, |a| assignment(a, false, true)); - run_test!(context, |a| assignment(a, true, false)); - run_test!(context, |a| assignment(a, true, true)); - - run_test!(context, |a| array_simple(a)); - run_test!(context, |a| vec_simple(a)); - run_test!(context, |a| vec_unreachable(a)); - - run_test!(context, |a| struct_dynamic_drop(a, false, false, false)); - run_test!(context, |a| struct_dynamic_drop(a, false, false, true)); - run_test!(context, |a| struct_dynamic_drop(a, false, true, false)); - run_test!(context, |a| struct_dynamic_drop(a, false, true, true)); - run_test!(context, |a| struct_dynamic_drop(a, true, false, false)); - run_test!(context, |a| struct_dynamic_drop(a, true, false, true)); - run_test!(context, |a| struct_dynamic_drop(a, true, true, false)); - run_test!(context, |a| struct_dynamic_drop(a, true, true, true)); - - run_test!(context, |a| field_assignment(a, false)); - run_test!(context, |a| field_assignment(a, true)); - - run_test!(context, |a| mixed_drop_and_nondrop(a)); - - run_test!(context, |a| slice_pattern_one_of(a, 0)); - run_test!(context, |a| slice_pattern_one_of(a, 1)); - run_test!(context, |a| slice_pattern_one_of(a, 2)); - run_test!(context, |a| slice_pattern_one_of(a, 3)); - - run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test!(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test!(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test!(context, |a| subslice_pattern_reassign(a)); - - run_test!(context, |a| move_ref_pattern(a)); - - run_test!(context, |a| panic_after_return(a, false)); - run_test!(context, |a| panic_after_return(a, true)); - run_test!(context, |a| panic_after_init_by_loop(a)); - run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, false)); - run_test!(context, |a| panic_after_init_by_match_with_bindings_and_guard(a, true)); + run_test(context, |a| dynamic_init(a, false)); + run_test(context, |a| dynamic_init(a, true)); + run_test(context, |a| dynamic_drop(a, false)); + run_test(context, |a| dynamic_drop(a, true)); + + run_test(context, |a| assignment(a, false, false)); + run_test(context, |a| assignment(a, false, true)); + run_test(context, |a| assignment(a, true, false)); + run_test(context, |a| assignment(a, true, true)); + + run_test(context, |a| array_simple(a)); + run_test(context, |a| vec_simple(a)); + run_test(context, |a| vec_unreachable(a)); + + run_test(context, |a| struct_dynamic_drop(a, false, false, false)); + run_test(context, |a| struct_dynamic_drop(a, false, false, true)); + run_test(context, |a| struct_dynamic_drop(a, false, true, false)); + run_test(context, |a| struct_dynamic_drop(a, false, true, true)); + run_test(context, |a| struct_dynamic_drop(a, true, false, false)); + run_test(context, |a| struct_dynamic_drop(a, true, false, true)); + run_test(context, |a| struct_dynamic_drop(a, true, true, false)); + run_test(context, |a| struct_dynamic_drop(a, true, true, true)); + + run_test(context, |a| field_assignment(a, false)); + run_test(context, |a| field_assignment(a, true)); + + run_test(context, |a| mixed_drop_and_nondrop(a)); + + run_test(context, |a| slice_pattern_one_of(a, 0)); + run_test(context, |a| slice_pattern_one_of(a, 1)); + run_test(context, |a| slice_pattern_one_of(a, 2)); + run_test(context, |a| slice_pattern_one_of(a, 3)); + + run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test(context, |a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test(context, |a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test(context, |a| subslice_pattern_reassign(a)); + + run_test(context, |a| move_ref_pattern(a)); } diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index ddccee20e12a6..88f557055f371 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -3,6 +3,7 @@ #![feature(generators, generator_trait)] #![feature(bindings_after_at)] + #![allow(unused_assignments)] #![allow(unused_variables)] @@ -16,7 +17,6 @@ struct InjectedFailure; struct Allocator { data: RefCell>, - name: &'static str, failing_op: usize, cur_ops: Cell, } @@ -28,18 +28,17 @@ impl Drop for Allocator { fn drop(&mut self) { let data = self.data.borrow(); if data.iter().any(|d| *d) { - panic!("missing free in {:?}: {:?}", self.name, data); + panic!("missing free: {:?}", data); } } } impl Allocator { - fn new(failing_op: usize, name: &'static str) -> Self { + fn new(failing_op: usize) -> Self { Allocator { failing_op: failing_op, cur_ops: Cell::new(0), - data: RefCell::new(vec![]), - name, + data: RefCell::new(vec![]) } } fn alloc(&self) -> Ptr<'_> { @@ -54,17 +53,33 @@ impl Allocator { data.push(true); Ptr(addr, self) } + // FIXME(#47949) Any use of this indicates a bug in rustc: we should never + // be leaking values in the cases here. + // + // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the + // `failing_op` is in the list of exception. + fn alloc_leaked(&self, exceptions: Vec) -> Ptr<'_> { + let ptr = self.alloc(); + + if exceptions.iter().any(|operation| *operation == self.failing_op) { + let mut data = self.data.borrow_mut(); + data[ptr.0] = false; + } + ptr + } } struct Ptr<'a>(usize, &'a Allocator); impl<'a> Drop for Ptr<'a> { fn drop(&mut self) { match self.1.data.borrow_mut()[self.0] { - false => panic!("double free in {:?} at index {:?}", self.1.name, self.0), - ref mut d => *d = false, + false => { + panic!("double free at index {:?}", self.0) + } + ref mut d => *d = false } - self.1.cur_ops.set(self.1.cur_ops.get() + 1); + self.1.cur_ops.set(self.1.cur_ops.get()+1); if self.1.cur_ops.get() == self.1.failing_op { panic!(InjectedFailure); @@ -162,7 +177,11 @@ fn generator(a: &Allocator, run_count: usize) { assert!(run_count < 4); let mut gen = || { - (a.alloc(), yield a.alloc(), a.alloc(), yield a.alloc()); + (a.alloc(), + yield a.alloc(), + a.alloc(), + yield a.alloc() + ); }; for _ in 0..run_count { Pin::new(&mut gen).resume(()); @@ -186,40 +205,28 @@ fn vec_unreachable(a: &Allocator) { } fn slice_pattern_first(a: &Allocator) { - let [_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; + let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_middle(a: &Allocator) { - let [_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; + let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_two(a: &Allocator) { - let [_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_last(a: &Allocator) { - let [.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; + let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; } fn slice_pattern_one_of(a: &Allocator, i: usize) { let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; let _x = match i { - 0 => { - let [a, ..] = array; - a - } - 1 => { - let [_, a, ..] = array; - a - } - 2 => { - let [_, _, a, _] = array; - a - } - 3 => { - let [_, _, _, a] = array; - a - } + 0 => { let [a, ..] = array; a } + 1 => { let [_, a, ..] = array; a } + 2 => { let [_, _, a, _] = array; a } + 3 => { let [_, _, _, a] = array; a } _ => panic!("unmatched"), }; } @@ -227,9 +234,9 @@ fn slice_pattern_one_of(a: &Allocator, i: usize) { fn subslice_pattern_from_end(a: &Allocator, arg: bool) { let a = [a.alloc(), a.alloc(), a.alloc()]; if arg { - let [.., _x, _] = a; + let[.., _x, _] = a; } else { - let [_, _y @ ..] = a; + let[_, _y @ ..] = a; } } @@ -241,61 +248,45 @@ fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) { } if arg { - let [.., _x, _] = a; + let[.., _x, _] = a; } else { - let [_, _y @ ..] = a; + let[_, _y @ ..] = a; } } fn slice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc()]; - let [_, _x] = ar; + let[_, _x] = ar; ar = [a.alloc(), a.alloc()]; - let [.., _y] = ar; + let[.., _y] = ar; } fn subslice_pattern_reassign(a: &Allocator) { let mut ar = [a.alloc(), a.alloc(), a.alloc()]; - let [_, _, _x] = ar; + let[_, _, _x] = ar; ar = [a.alloc(), a.alloc(), a.alloc()]; - let [_, _y @ ..] = ar; + let[_, _y @ ..] = ar; } fn index_field_mixed_ends(a: &Allocator) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; - let [(_x, _), ..] = ar; - let [(_, _y), _] = ar; - let [_, (_, _w)] = ar; - let [.., (_z, _)] = ar; + let[(_x, _), ..] = ar; + let[(_, _y), _] = ar; + let[_, (_, _w)] = ar; + let[.., (_z, _)] = ar; } fn subslice_mixed_min_lengths(a: &Allocator, c: i32) { let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())]; match c { - 0 => { - let [_x, ..] = ar; - } - 1 => { - let [_x, _, ..] = ar; - } - 2 => { - let [_x, _] = ar; - } - 3 => { - let [(_x, _), _, ..] = ar; - } - 4 => { - let [.., (_x, _)] = ar; - } - 5 => { - let [.., (_x, _), _] = ar; - } - 6 => { - let [_y @ ..] = ar; - } - _ => { - let [_y @ .., _] = ar; - } + 0 => { let[_x, ..] = ar; } + 1 => { let[_x, _, ..] = ar; } + 2 => { let[_x, _] = ar; } + 3 => { let[(_x, _), _, ..] = ar; } + 4 => { let[.., (_x, _)] = ar; } + 5 => { let[.., (_x, _), _] = ar; } + 6 => { let [_y @ ..] = ar; } + _ => { let [_y @ .., _] = ar; } } } @@ -343,160 +334,87 @@ fn move_ref_pattern(a: &Allocator) { } fn panic_after_return(a: &Allocator) -> Ptr<'_> { + // Panic in the drop of `p` or `q` can leak + let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let p = a.alloc(); - a.alloc() + // FIXME (#47949) We leak values when we panic in a destructor after + // evaluating an expression with `rustc_mir::build::Builder::into`. + a.alloc_leaked(exceptions) } } fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> { + // Panic in the drop of `p` or `q` can leak + let exceptions = vec![8, 9]; a.alloc(); let p = a.alloc(); { a.alloc(); let q = a.alloc(); - return a.alloc(); + // FIXME (#47949) + return a.alloc_leaked(exceptions); } } fn panic_after_init(a: &Allocator) { + // Panic in the drop of `r` can leak + let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = { a.alloc(); let r = a.alloc(); - a.alloc() + // FIXME (#47949) + a.alloc_leaked(exceptions) }; } fn panic_after_init_temp(a: &Allocator) { + // Panic in the drop of `r` can leak + let exceptions = vec![8]; a.alloc(); let p = a.alloc(); { a.alloc(); let r = a.alloc(); - a.alloc() + // FIXME (#47949) + a.alloc_leaked(exceptions) }; } fn panic_after_init_by_loop(a: &Allocator) { + // Panic in the drop of `r` can leak + let exceptions = vec![8]; a.alloc(); let p = a.alloc(); let q = loop { a.alloc(); let r = a.alloc(); - break a.alloc(); - }; -} - -fn panic_after_init_by_match(a: &Allocator, b: bool) { - a.alloc(); - let p = a.alloc(); - let _ = loop { - let q = match b { - true => { - a.alloc(); - let r = a.alloc(); - a.alloc() - } - false => { - a.alloc(); - let r = a.alloc(); - break a.alloc(); - } - }; - return; - }; -} - -fn panic_after_init_by_match_with_guard(a: &Allocator, b: bool) { - a.alloc(); - let p = a.alloc(); - let q = match a.alloc() { - _ if b => { - a.alloc(); - let r = a.alloc(); - a.alloc() - } - _ => { - a.alloc(); - let r = a.alloc(); - a.alloc() - } - }; -} - -fn panic_after_init_by_match_with_bindings_and_guard(a: &Allocator, b: bool) { - a.alloc(); - let p = a.alloc(); - let q = match a.alloc() { - _x if b => { - a.alloc(); - let r = a.alloc(); - a.alloc() - } - _x => { - a.alloc(); - let r = a.alloc(); - a.alloc() - } - }; -} - -fn panic_after_init_by_match_with_ref_bindings_and_guard(a: &Allocator, b: bool) { - a.alloc(); - let p = a.alloc(); - let q = match a.alloc() { - ref _x if b => { - a.alloc(); - let r = a.alloc(); - a.alloc() - } - ref _x => { - a.alloc(); - let r = a.alloc(); - a.alloc() - } - }; -} - -fn panic_after_init_by_break_if(a: &Allocator, b: bool) { - a.alloc(); - let p = a.alloc(); - let q = loop { - let r = a.alloc(); - break if b { - let s = a.alloc(); - a.alloc() - } else { - a.alloc() - }; + // FIXME (#47949) + break a.alloc_leaked(exceptions); }; } -fn run_test(mut f: F, name: &'static str) -where - F: FnMut(&Allocator), +fn run_test(mut f: F) + where F: FnMut(&Allocator) { - let first_alloc = Allocator::new(usize::MAX, name); + let first_alloc = Allocator::new(usize::MAX); f(&first_alloc); - for failing_op in 1..first_alloc.cur_ops.get() + 1 { - let alloc = Allocator::new(failing_op, name); + for failing_op in 1..first_alloc.cur_ops.get()+1 { + let alloc = Allocator::new(failing_op); let alloc = &alloc; let f = panic::AssertUnwindSafe(&mut f); let result = panic::catch_unwind(move || { f.0(alloc); }); match result { - Ok(..) => panic!( - "test executed {} ops but now {}", - first_alloc.cur_ops.get(), - alloc.cur_ops.get() - ), + Ok(..) => panic!("test executed {} ops but now {}", + first_alloc.cur_ops.get(), alloc.cur_ops.get()), Err(e) => { if e.downcast_ref::().is_none() { panic::resume_unwind(e); @@ -506,115 +424,98 @@ where } } -fn run_test_nopanic(mut f: F, name: &'static str) -where - F: FnMut(&Allocator), +fn run_test_nopanic(mut f: F) + where F: FnMut(&Allocator) { - let first_alloc = Allocator::new(usize::MAX, name); + let first_alloc = Allocator::new(usize::MAX); f(&first_alloc); } -macro_rules! run_test { - ($e:expr) => { - run_test($e, stringify!($e)); - }; -} - fn main() { - run_test!(|a| dynamic_init(a, false)); - run_test!(|a| dynamic_init(a, true)); - run_test!(|a| dynamic_drop(a, false)); - run_test!(|a| dynamic_drop(a, true)); - - run_test!(|a| assignment2(a, false, false)); - run_test!(|a| assignment2(a, false, true)); - run_test!(|a| assignment2(a, true, false)); - run_test!(|a| assignment2(a, true, true)); - - run_test!(|a| assignment1(a, false)); - run_test!(|a| assignment1(a, true)); - - run_test!(|a| array_simple(a)); - run_test!(|a| vec_simple(a)); - run_test!(|a| vec_unreachable(a)); - - run_test!(|a| struct_dynamic_drop(a, false, false, false)); - run_test!(|a| struct_dynamic_drop(a, false, false, true)); - run_test!(|a| struct_dynamic_drop(a, false, true, false)); - run_test!(|a| struct_dynamic_drop(a, false, true, true)); - run_test!(|a| struct_dynamic_drop(a, true, false, false)); - run_test!(|a| struct_dynamic_drop(a, true, false, true)); - run_test!(|a| struct_dynamic_drop(a, true, true, false)); - run_test!(|a| struct_dynamic_drop(a, true, true, true)); - - run_test!(|a| field_assignment(a, false)); - run_test!(|a| field_assignment(a, true)); - - run_test!(|a| generator(a, 0)); - run_test!(|a| generator(a, 1)); - run_test!(|a| generator(a, 2)); - run_test!(|a| generator(a, 3)); - - run_test!(|a| mixed_drop_and_nondrop(a)); - - run_test!(|a| slice_pattern_first(a)); - run_test!(|a| slice_pattern_middle(a)); - run_test!(|a| slice_pattern_two(a)); - run_test!(|a| slice_pattern_last(a)); - run_test!(|a| slice_pattern_one_of(a, 0)); - run_test!(|a| slice_pattern_one_of(a, 1)); - run_test!(|a| slice_pattern_one_of(a, 2)); - run_test!(|a| slice_pattern_one_of(a, 3)); - - run_test!(|a| subslice_pattern_from_end(a, true)); - run_test!(|a| subslice_pattern_from_end(a, false)); - run_test!(|a| subslice_pattern_from_end_with_drop(a, true, true)); - run_test!(|a| subslice_pattern_from_end_with_drop(a, true, false)); - run_test!(|a| subslice_pattern_from_end_with_drop(a, false, true)); - run_test!(|a| subslice_pattern_from_end_with_drop(a, false, false)); - run_test!(|a| slice_pattern_reassign(a)); - run_test!(|a| subslice_pattern_reassign(a)); - - run_test!(|a| index_field_mixed_ends(a)); - run_test!(|a| subslice_mixed_min_lengths(a, 0)); - run_test!(|a| subslice_mixed_min_lengths(a, 1)); - run_test!(|a| subslice_mixed_min_lengths(a, 2)); - run_test!(|a| subslice_mixed_min_lengths(a, 3)); - run_test!(|a| subslice_mixed_min_lengths(a, 4)); - run_test!(|a| subslice_mixed_min_lengths(a, 5)); - run_test!(|a| subslice_mixed_min_lengths(a, 6)); - run_test!(|a| subslice_mixed_min_lengths(a, 7)); - - run_test!(|a| move_ref_pattern(a)); - - run_test!(|a| { + run_test(|a| dynamic_init(a, false)); + run_test(|a| dynamic_init(a, true)); + run_test(|a| dynamic_drop(a, false)); + run_test(|a| dynamic_drop(a, true)); + + run_test(|a| assignment2(a, false, false)); + run_test(|a| assignment2(a, false, true)); + run_test(|a| assignment2(a, true, false)); + run_test(|a| assignment2(a, true, true)); + + run_test(|a| assignment1(a, false)); + run_test(|a| assignment1(a, true)); + + run_test(|a| array_simple(a)); + run_test(|a| vec_simple(a)); + run_test(|a| vec_unreachable(a)); + + run_test(|a| struct_dynamic_drop(a, false, false, false)); + run_test(|a| struct_dynamic_drop(a, false, false, true)); + run_test(|a| struct_dynamic_drop(a, false, true, false)); + run_test(|a| struct_dynamic_drop(a, false, true, true)); + run_test(|a| struct_dynamic_drop(a, true, false, false)); + run_test(|a| struct_dynamic_drop(a, true, false, true)); + run_test(|a| struct_dynamic_drop(a, true, true, false)); + run_test(|a| struct_dynamic_drop(a, true, true, true)); + + run_test(|a| field_assignment(a, false)); + run_test(|a| field_assignment(a, true)); + + run_test(|a| generator(a, 0)); + run_test(|a| generator(a, 1)); + run_test(|a| generator(a, 2)); + run_test(|a| generator(a, 3)); + + run_test(|a| mixed_drop_and_nondrop(a)); + + run_test(|a| slice_pattern_first(a)); + run_test(|a| slice_pattern_middle(a)); + run_test(|a| slice_pattern_two(a)); + run_test(|a| slice_pattern_last(a)); + run_test(|a| slice_pattern_one_of(a, 0)); + run_test(|a| slice_pattern_one_of(a, 1)); + run_test(|a| slice_pattern_one_of(a, 2)); + run_test(|a| slice_pattern_one_of(a, 3)); + + run_test(|a| subslice_pattern_from_end(a, true)); + run_test(|a| subslice_pattern_from_end(a, false)); + run_test(|a| subslice_pattern_from_end_with_drop(a, true, true)); + run_test(|a| subslice_pattern_from_end_with_drop(a, true, false)); + run_test(|a| subslice_pattern_from_end_with_drop(a, false, true)); + run_test(|a| subslice_pattern_from_end_with_drop(a, false, false)); + run_test(|a| slice_pattern_reassign(a)); + run_test(|a| subslice_pattern_reassign(a)); + + run_test(|a| index_field_mixed_ends(a)); + run_test(|a| subslice_mixed_min_lengths(a, 0)); + run_test(|a| subslice_mixed_min_lengths(a, 1)); + run_test(|a| subslice_mixed_min_lengths(a, 2)); + run_test(|a| subslice_mixed_min_lengths(a, 3)); + run_test(|a| subslice_mixed_min_lengths(a, 4)); + run_test(|a| subslice_mixed_min_lengths(a, 5)); + run_test(|a| subslice_mixed_min_lengths(a, 6)); + run_test(|a| subslice_mixed_min_lengths(a, 7)); + + run_test(|a| move_ref_pattern(a)); + + run_test(|a| { panic_after_return(a); }); - run_test!(|a| { + run_test(|a| { panic_after_return_expr(a); }); - run_test!(|a| panic_after_init(a)); - run_test!(|a| panic_after_init_temp(a)); - run_test!(|a| panic_after_init_by_loop(a)); - run_test!(|a| panic_after_init_by_match(a, false)); - run_test!(|a| panic_after_init_by_match(a, true)); - run_test!(|a| panic_after_init_by_match_with_guard(a, false)); - run_test!(|a| panic_after_init_by_match_with_guard(a, true)); - run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, false)); - run_test!(|a| panic_after_init_by_match_with_bindings_and_guard(a, true)); - run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, false)); - run_test!(|a| panic_after_init_by_match_with_ref_bindings_and_guard(a, true)); - run_test!(|a| panic_after_init_by_break_if(a, false)); - run_test!(|a| panic_after_init_by_break_if(a, true)); - - run_test!(|a| bindings_after_at_dynamic_init_move(a, true)); - run_test!(|a| bindings_after_at_dynamic_init_move(a, false)); - run_test!(|a| bindings_after_at_dynamic_init_ref(a, true)); - run_test!(|a| bindings_after_at_dynamic_init_ref(a, false)); - run_test!(|a| bindings_after_at_dynamic_drop_move(a, true)); - run_test!(|a| bindings_after_at_dynamic_drop_move(a, false)); - run_test!(|a| bindings_after_at_dynamic_drop_ref(a, true)); - run_test!(|a| bindings_after_at_dynamic_drop_ref(a, false)); - - run_test_nopanic(|a| union1(a), "|a| union1(a)"); + run_test(|a| panic_after_init(a)); + run_test(|a| panic_after_init_temp(a)); + run_test(|a| panic_after_init_by_loop(a)); + + run_test(|a| bindings_after_at_dynamic_init_move(a, true)); + run_test(|a| bindings_after_at_dynamic_init_move(a, false)); + run_test(|a| bindings_after_at_dynamic_init_ref(a, true)); + run_test(|a| bindings_after_at_dynamic_init_ref(a, false)); + run_test(|a| bindings_after_at_dynamic_drop_move(a, true)); + run_test(|a| bindings_after_at_dynamic_drop_move(a, false)); + run_test(|a| bindings_after_at_dynamic_drop_ref(a, true)); + run_test(|a| bindings_after_at_dynamic_drop_ref(a, false)); + + run_test_nopanic(|a| union1(a)); } diff --git a/src/test/ui/mir/issue-80949.rs b/src/test/ui/mir/issue-80949.rs new file mode 100644 index 0000000000000..7e34a4f5c2737 --- /dev/null +++ b/src/test/ui/mir/issue-80949.rs @@ -0,0 +1,34 @@ +// build-pass + +trait Trait { type Item; } + +impl<'a, X> Trait for &'a Vec { + type Item = &'a X; +} + +impl Trait for Box> { + type Item = X; +} + +fn make_dyn_trait(_: &()) -> Box> { + todo!() +} + +fn diff<'a, M, N, S>(_: N, _: S) +where + M: 'a, + N: Trait, + S: Trait, +{ + todo!() +} + +fn may_panic(_: X) { } + +fn main() { + let dyn_trait = make_dyn_trait(&()); + let storage = vec![()]; + let _x = may_panic(()); + let storage_ref = &storage; + diff(dyn_trait, storage_ref); +} From fc81b7c091d13f3fd2ca7f1ff9221693fdf7e53b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 2 Feb 2021 19:22:44 +0100 Subject: [PATCH 45/73] Rename `panic_fmt` lint to `non_fmt_panic`. --- compiler/rustc_lint/src/panic_fmt.rs | 11 ++++++----- src/test/ui/fmt/format-args-capture.rs | 2 +- src/test/ui/macros/macro-comma-behavior-rpass.rs | 2 +- src/test/ui/panic-brace.stderr | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_lint/src/panic_fmt.rs b/compiler/rustc_lint/src/panic_fmt.rs index 0d2b20989b0c3..e01ff1641b296 100644 --- a/compiler/rustc_lint/src/panic_fmt.rs +++ b/compiler/rustc_lint/src/panic_fmt.rs @@ -7,7 +7,8 @@ use rustc_parse_format::{ParseMode, Parser, Piece}; use rustc_span::{sym, InnerSpan}; declare_lint! { - /// The `panic_fmt` lint detects `panic!("..")` with `{` or `}` in the string literal. + /// The `non_fmt_panic` lint detects `panic!("..")` with `{` or `}` in the string literal + /// when it is not used as a format string. /// /// ### Example /// @@ -23,13 +24,13 @@ declare_lint! { /// with a single argument does not use `format_args!()`. /// A future edition of Rust will interpret this string as format string, /// which would break this. - PANIC_FMT, + NON_FMT_PANIC, Warn, "detect braces in single-argument panic!() invocations", report_in_external_macro } -declare_lint_pass!(PanicFmt => [PANIC_FMT]); +declare_lint_pass!(PanicFmt => [NON_FMT_PANIC]); impl<'tcx> LateLintPass<'tcx> for PanicFmt { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { @@ -92,7 +93,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc [] => vec![fmt_span], v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(), }; - cx.struct_span_lint(PANIC_FMT, arg_spans, |lint| { + cx.struct_span_lint(NON_FMT_PANIC, arg_spans, |lint| { let mut l = lint.build(match n_arguments { 1 => "panic message contains an unused formatting placeholder", _ => "panic message contains unused formatting placeholders", @@ -129,7 +130,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc Some(v) if v.len() == 1 => "panic message contains a brace", _ => "panic message contains braces", }; - cx.struct_span_lint(PANIC_FMT, brace_spans.unwrap_or(vec![expn.call_site]), |lint| { + cx.struct_span_lint(NON_FMT_PANIC, brace_spans.unwrap_or(vec![expn.call_site]), |lint| { let mut l = lint.build(msg); l.note("this message is not used as a format string, but will be in a future Rust edition"); if expn.call_site.contains(arg.span) { diff --git a/src/test/ui/fmt/format-args-capture.rs b/src/test/ui/fmt/format-args-capture.rs index 4e3fa9a3c589a..d5886a13558c6 100644 --- a/src/test/ui/fmt/format-args-capture.rs +++ b/src/test/ui/fmt/format-args-capture.rs @@ -31,7 +31,7 @@ fn panic_with_single_argument_does_not_get_formatted() { // RFC #2795 suggests that this may need to change so that captured arguments are formatted. // For stability reasons this will need to part of an edition change. - #[allow(panic_fmt)] + #[allow(non_fmt_panic)] let msg = std::panic::catch_unwind(|| { panic!("{foo}"); }).unwrap_err(); diff --git a/src/test/ui/macros/macro-comma-behavior-rpass.rs b/src/test/ui/macros/macro-comma-behavior-rpass.rs index e5e656de6fa7f..e814e075647b1 100644 --- a/src/test/ui/macros/macro-comma-behavior-rpass.rs +++ b/src/test/ui/macros/macro-comma-behavior-rpass.rs @@ -57,7 +57,7 @@ fn writeln_1arg() { // // (Example: Issue #48042) #[test] -#[allow(panic_fmt)] +#[allow(non_fmt_panic)] fn to_format_or_not_to_format() { // ("{}" is the easiest string to test because if this gets // sent to format_args!, it'll simply fail to compile. diff --git a/src/test/ui/panic-brace.stderr b/src/test/ui/panic-brace.stderr index 93808891c3c37..c2aa19c580662 100644 --- a/src/test/ui/panic-brace.stderr +++ b/src/test/ui/panic-brace.stderr @@ -4,7 +4,7 @@ warning: panic message contains a brace LL | panic!("here's a brace: {"); | ^ | - = note: `#[warn(panic_fmt)]` on by default + = note: `#[warn(non_fmt_panic)]` on by default = note: this message is not used as a format string, but will be in a future Rust edition help: add a "{}" format string to use the message literally | From fe8e0c5ccf2afcdcb95aa94b7eec2502756cc95f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 8 Feb 2021 12:07:18 +0100 Subject: [PATCH 46/73] backport release notes from master --- RELEASES.md | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 249 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 9fd796fd775bf..18492213a5dd3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,249 @@ +Version 1.50.0 (2021-02-11) +============================ + +Language +----------------------- +- [You can now use `const` values for `x` in `[x; N]` array expressions.][79270] + This has been technically possible since 1.38.0, as it was unintentionally stabilized. +- [Assignments to `ManuallyDrop` union fields are now considered safe.][78068] + +Compiler +----------------------- +- [Added tier 3\* support for the `armv5te-unknown-linux-uclibceabi` target.][78142] +- [Added tier 3 support for the `aarch64-apple-ios-macabi` target.][77484] +- [The `x86_64-unknown-freebsd` is now built with the full toolset.][79484] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +----------------------- + +- [`proc_macro::Punct` now implements `PartialEq`.][78636] +- [`ops::{Index, IndexMut}` are now implemented for fixed sized arrays of any length.][74989] +- [On Unix platforms, the `std::fs::File` type now has a "niche" of `-1`.][74699] + This value cannot be a valid file descriptor, and now means `Option` takes + up the same amount of space as `File`. + +Stabilized APIs +--------------- + +- [`bool::then`] +- [`btree_map::Entry::or_insert_with_key`] +- [`f32::clamp`] +- [`f64::clamp`] +- [`hash_map::Entry::or_insert_with_key`] +- [`Ord::clamp`] +- [`RefCell::take`] +- [`slice::fill`] +- [`UnsafeCell::get_mut`] + +The following previously stable methods are now `const`. + +- [`IpAddr::is_ipv4`] +- [`IpAddr::is_ipv6`] +- [`Layout::size`] +- [`Layout::align`] +- [`Layout::from_size_align`] +- `pow` for all integer types. +- `checked_pow` for all integer types. +- `saturating_pow` for all integer types. +- `wrapping_pow` for all integer types. +- `next_power_of_two` for all unsigned integer types. +- `checked_power_of_two` for all unsigned integer types. + +Cargo +----------------------- + +- [Added the `[build.rustc-workspace-wrapper]` option.][cargo/8976] + This option sets a wrapper to execute instead of `rustc`, for workspace members only. +- [`cargo:rerun-if-changed` will now, if provided a directory, scan the entire + contents of that directory for changes.][cargo/8973] +- [Added the `--workspace` flag to the `cargo update` command.][cargo/8725] + +Misc +---- + +- [The search results tab and the help button are focusable with keyboard in rustdoc.][79896] +- [Running tests will now print the total time taken to execute.][75752] + +Compatibility Notes +------------------- + +- [The `compare_and_swap` method on atomics has been deprecated.][79261] It's + recommended to use the `compare_exchange` and `compare_exchange_weak` methods instead. +- [Changes in how `TokenStream`s are checked have fixed some cases where you could write + unhygenic `macro_rules!` macros.][79472] +- [`#![test]` as an inner attribute is now considered unstable like other inner macro + attributes, and reports an error by default through the `soft_unstable` lint.][79003] +- [Overriding a `forbid` lint at the same level that it was set is now a hard error.][78864] +- [Dropped support for all cloudabi targets.][78439] +- [You can no longer intercept `panic!` calls by supplying your own macro.][78343] It's + recommended to use the `#[panic_handler]` attribute to provide your own implementation. +- [Semi-colons after item statements (e.g. `struct Foo {};`) now produce a warning.][78296] + +[74989]: https://github.com/rust-lang/rust/pull/74989 +[79261]: https://github.com/rust-lang/rust/pull/79261 +[79896]: https://github.com/rust-lang/rust/pull/79896 +[79484]: https://github.com/rust-lang/rust/pull/79484 +[79472]: https://github.com/rust-lang/rust/pull/79472 +[79270]: https://github.com/rust-lang/rust/pull/79270 +[79003]: https://github.com/rust-lang/rust/pull/79003 +[78864]: https://github.com/rust-lang/rust/pull/78864 +[78636]: https://github.com/rust-lang/rust/pull/78636 +[78439]: https://github.com/rust-lang/rust/pull/78439 +[78343]: https://github.com/rust-lang/rust/pull/78343 +[78296]: https://github.com/rust-lang/rust/pull/78296 +[78068]: https://github.com/rust-lang/rust/pull/78068 +[75752]: https://github.com/rust-lang/rust/pull/75752 +[74699]: https://github.com/rust-lang/rust/pull/74699 +[78142]: https://github.com/rust-lang/rust/pull/78142 +[77484]: https://github.com/rust-lang/rust/pull/77484 +[cargo/8976]: https://github.com/rust-lang/cargo/pull/8976 +[cargo/8973]: https://github.com/rust-lang/cargo/pull/8973 +[cargo/8725]: https://github.com/rust-lang/cargo/pull/8725 +[`IpAddr::is_ipv4`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv4 +[`IpAddr::is_ipv6`]: https://doc.rust-lang.org/stable/std/net/enum.IpAddr.html#method.is_ipv6 +[`Layout::align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.align +[`Layout::from_size_align`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.from_size_align +[`Layout::size`]: https://doc.rust-lang.org/stable/std/alloc/struct.Layout.html#method.size +[`Ord::clamp`]: https://doc.rust-lang.org/stable/std/cmp/trait.Ord.html#method.clamp +[`RefCell::take`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.take +[`UnsafeCell::get_mut`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.get_mut +[`bool::then`]: https://doc.rust-lang.org/stable/std/primitive.bool.html#method.then +[`btree_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/btree_map/enum.Entry.html#method.or_insert_with_key +[`f32::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.clamp +[`f64::clamp`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.clamp +[`hash_map::Entry::or_insert_with_key`]: https://doc.rust-lang.org/stable/std/collections/hash_map/enum.Entry.html#method.or_insert_with_key +[`slice::fill`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.fill + + +Version 1.49.0 (2020-12-31) +============================ + +Language +----------------------- + +- [Unions can now implement `Drop`, and you can now have a field in a union + with `ManuallyDrop`.][77547] +- [You can now cast uninhabited enums to integers.][76199] +- [You can now bind by reference and by move in patterns.][76119] This + allows you to selectively borrow individual components of a type. E.g. + ```rust + #[derive(Debug)] + struct Person { + name: String, + age: u8, + } + + let person = Person { + name: String::from("Alice"), + age: 20, + }; + + // `name` is moved out of person, but `age` is referenced. + let Person { name, ref age } = person; + println!("{} {}", name, age); + ``` + +Compiler +----------------------- + +- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228] +- [Added tier 2 support for `aarch64-apple-darwin`.][75991] +- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914] +- [Added tier 3 support for `mipsel-unknown-none`.][78676] +- [Raised the minimum supported LLVM version to LLVM 9.][78848] +- [Output from threads spawned in tests is now captured.][78227] +- [Change os and vendor values to "none" and "unknown" for some targets][78951] + +\* Refer to Rust's [platform support page][forge-platform-support] for more +information on Rust's tiered platform support. + +Libraries +----------------------- + +- [`RangeInclusive` now checks for exhaustion when calling `contains` and indexing.][78109] +- [`ToString::to_string` now no longer shrinks the internal buffer in the default implementation.][77997] + +Stabilized APIs +--------------- + +- [`slice::select_nth_unstable`] +- [`slice::select_nth_unstable_by`] +- [`slice::select_nth_unstable_by_key`] + +The following previously stable methods are now `const`. + +- [`Poll::is_ready`] +- [`Poll::is_pending`] + +Cargo +----------------------- +- [Building a crate with `cargo-package` should now be independently reproducible.][cargo/8864] +- [`cargo-tree` now marks proc-macro crates.][cargo/8765] +- [Added `CARGO_PRIMARY_PACKAGE` build-time environment variable.][cargo/8758] This + variable will be set if the crate being built is one the user selected to build, either + with `-p` or through defaults. +- [You can now use glob patterns when specifying packages & targets.][cargo/8752] + + +Compatibility Notes +------------------- + +- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier 2 support.][78746] +- [Macros that end with a semi-colon are now treated as statements even if they expand to nothing.][78376] +- [Rustc will now check for the validity of some built-in attributes on enum variants.][77015] + Previously such invalid or unused attributes could be ignored. +- Leading whitespace is stripped more uniformly in documentation comments, which may change behavior. You + read [this post about the changes][rustdoc-ws-post] for more details. +- [Trait bounds are no longer inferred for associated types.][79904] + +Internal Only +------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc and +related tools. + +- [rustc's internal crates are now compiled using the `initial-exec` Thread + Local Storage model.][78201] +- [Calculate visibilities once in resolve.][78077] +- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703] +- [Added `--color` for configuring terminal color support to bootstrap.][79004] + + +[75991]: https://github.com/rust-lang/rust/pull/75991 +[78951]: https://github.com/rust-lang/rust/pull/78951 +[78848]: https://github.com/rust-lang/rust/pull/78848 +[78746]: https://github.com/rust-lang/rust/pull/78746 +[78376]: https://github.com/rust-lang/rust/pull/78376 +[78228]: https://github.com/rust-lang/rust/pull/78228 +[78227]: https://github.com/rust-lang/rust/pull/78227 +[78201]: https://github.com/rust-lang/rust/pull/78201 +[78109]: https://github.com/rust-lang/rust/pull/78109 +[78077]: https://github.com/rust-lang/rust/pull/78077 +[77997]: https://github.com/rust-lang/rust/pull/77997 +[77703]: https://github.com/rust-lang/rust/pull/77703 +[77547]: https://github.com/rust-lang/rust/pull/77547 +[77015]: https://github.com/rust-lang/rust/pull/77015 +[76199]: https://github.com/rust-lang/rust/pull/76199 +[76119]: https://github.com/rust-lang/rust/pull/76119 +[75914]: https://github.com/rust-lang/rust/pull/75914 +[79004]: https://github.com/rust-lang/rust/pull/79004 +[78676]: https://github.com/rust-lang/rust/pull/78676 +[79904]: https://github.com/rust-lang/rust/issues/79904 +[cargo/8864]: https://github.com/rust-lang/cargo/pull/8864 +[cargo/8765]: https://github.com/rust-lang/cargo/pull/8765 +[cargo/8758]: https://github.com/rust-lang/cargo/pull/8758 +[cargo/8752]: https://github.com/rust-lang/cargo/pull/8752 +[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable +[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by +[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key +[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html +[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready +[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending +[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc + Version 1.48.0 (2020-11-19) ========================== @@ -10,7 +256,7 @@ Language Compiler -------- - [Stabilised the `-C link-self-contained=` compiler flag.][76158] This tells - `rustc` whether to link its own C runtime and libraries or to rely on a external + `rustc` whether to link its own C runtime and libraries or to rely on a external linker to find them. (Supported only on `windows-gnu`, `linux-musl`, and `wasi` platforms.) - [You can now use `-C target-feature=+crt-static` on `linux-gnu` targets.][77386] Note: If you're using cargo you must explicitly pass the `--target` flag. @@ -82,7 +328,7 @@ Compatibility Notes - [Foreign exceptions are now caught by `catch_unwind` and will cause an abort.][70212] Note: This behaviour is not guaranteed and is still considered undefined behaviour, see the [`catch_unwind`] documentation for further information. - + Internal Only @@ -102,7 +348,7 @@ related tools. [76030]: https://github.com/rust-lang/rust/pull/76030/ [70212]: https://github.com/rust-lang/rust/pull/70212/ [27675]: https://github.com/rust-lang/rust/issues/27675/ -[54121]: https://github.com/rust-lang/rust/issues/54121/ +[54121]: https://github.com/rust-lang/rust/issues/54121/ [71274]: https://github.com/rust-lang/rust/pull/71274/ [77386]: https://github.com/rust-lang/rust/pull/77386/ [77153]: https://github.com/rust-lang/rust/pull/77153/ From 94c439b9168680f359aff47889c033389039add1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 24 Jan 2021 16:41:12 +0300 Subject: [PATCH 47/73] lexer: Avoid some span arithmetic in `emit_unescape_error` --- compiler/rustc_parse/src/lexer/mod.rs | 5 +++++ .../src/lexer/unescape_error_reporting.rs | 9 ++------- src/test/ui/attributes/key-value-non-ascii.rs | 5 +++++ src/test/ui/attributes/key-value-non-ascii.stderr | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/attributes/key-value-non-ascii.rs create mode 100644 src/test/ui/attributes/key-value-non-ascii.stderr diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index b5b34c7338d88..b2604ea690851 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -532,10 +532,15 @@ impl<'a> StringReader<'a> { if let Err(err) = result { let span_with_quotes = self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)); + let (start, end) = (range.start as u32, range.end as u32); + let lo = content_start + BytePos(start); + let hi = lo + BytePos(end - start); + let span = self.mk_sp(lo, hi); emit_unescape_error( &self.sess.span_diagnostic, lit_content, span_with_quotes, + span, mode, range, err, diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 47d317f918865..6a890be36956a 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -13,6 +13,8 @@ pub(crate) fn emit_unescape_error( lit: &str, // full span of the literal, including quotes span_with_quotes: Span, + // interior span of the literal, without quotes + span: Span, mode: Mode, // range of the error inside `lit` range: Range, @@ -26,13 +28,6 @@ pub(crate) fn emit_unescape_error( range, error ); - let span = { - let Range { start, end } = range; - let (start, end) = (start as u32, end as u32); - let lo = span_with_quotes.lo() + BytePos(start + 1); - let hi = lo + BytePos(end - start); - span_with_quotes.with_lo(lo).with_hi(hi) - }; let last_char = || { let c = lit[range.clone()].chars().rev().next().unwrap(); let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32)); diff --git a/src/test/ui/attributes/key-value-non-ascii.rs b/src/test/ui/attributes/key-value-non-ascii.rs new file mode 100644 index 0000000000000..96c77f4f865e4 --- /dev/null +++ b/src/test/ui/attributes/key-value-non-ascii.rs @@ -0,0 +1,5 @@ +#![feature(rustc_attrs)] + +#[rustc_dummy = b"ffi.rs"] //~ ERROR byte constant must be ASCII + //~| ERROR byte constant must be ASCII +fn main() {} diff --git a/src/test/ui/attributes/key-value-non-ascii.stderr b/src/test/ui/attributes/key-value-non-ascii.stderr new file mode 100644 index 0000000000000..43df0e453bb04 --- /dev/null +++ b/src/test/ui/attributes/key-value-non-ascii.stderr @@ -0,0 +1,14 @@ +error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte + --> $DIR/key-value-non-ascii.rs:3:19 + | +LL | #[rustc_dummy = b"ffi.rs"] + | ^ + +error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte + --> $DIR/key-value-non-ascii.rs:3:21 + | +LL | #[rustc_dummy = b"ffi.rs"] + | ^^^ + +error: aborting due to 2 previous errors + From 2602fa0e53ff00baecd80ee1a75188bb11dc47bc Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 8 Feb 2021 12:27:33 +0100 Subject: [PATCH 48/73] this is 1.50.0 stable --- src/ci/run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/run.sh b/src/ci/run.sh index 8681f84f6ab0a..3a22496bcc81f 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -63,7 +63,7 @@ fi # # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. -export RUST_RELEASE_CHANNEL=beta +export RUST_RELEASE_CHANNEL=stable # Always set the release channel for bootstrap; this is normally not important (i.e., only dist # builds would seem to matter) but in practice bootstrap wants to know whether we're targeting From facc68d99d71656d01dbc06337257d92a6c101c5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 9 Feb 2021 19:04:29 -0800 Subject: [PATCH 49/73] bootstrap: Locate llvm-dwp based on llvm-config bindir --- src/bootstrap/compile.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 091bd2a1c5a16..a31c87d43111c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1021,8 +1021,11 @@ impl Step for Assemble { let src_exe = exe("llvm-dwp", target_compiler.host); let dst_exe = exe("rust-llvm-dwp", target_compiler.host); let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host }); - let llvm_bin_dir = llvm_config_bin.parent().unwrap(); - builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); + if !builder.config.dry_run { + let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir")); + let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); + builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); + } } // Ensure that `libLLVM.so` ends up in the newly build compiler directory, From a7f4cce1cef081595da9e1a77157460e9a0a950a Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 10 Feb 2021 18:33:43 +0100 Subject: [PATCH 50/73] bootstrap: fix wrong docs installation path --- src/bootstrap/install.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index fd0acc3a919b0..22124ec67f5f3 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -29,7 +29,7 @@ fn install_sh( let prefix = default_path(&builder.config.prefix, "/usr/local"); let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); let datadir = prefix.join(default_path(&builder.config.datadir, "share")); - let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc")); + let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust")); let mandir = prefix.join(default_path(&builder.config.mandir, "share/man")); let libdir = prefix.join(default_path(&builder.config.libdir, "lib")); let bindir = prefix.join(&builder.config.bindir); // Default in config.rs From 41927a1718dac299e7db8b9b9b73db307d77e88e Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sun, 17 Jan 2021 15:07:37 +0000 Subject: [PATCH 51/73] Use llvm submodule with Xtensa arch support. --- .gitmodules | 4 ++-- src/llvm-project | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 984113151de4d..09ef878e8d538 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,8 +36,8 @@ url = https://github.com/rust-lang/edition-guide.git [submodule "src/llvm-project"] path = src/llvm-project - url = https://github.com/rust-lang/llvm-project.git - branch = rustc/11.0-2020-10-12 + url = https://github.com/espressif/llvm-project + branch = xtensa_release_11.0.0 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/src/llvm-project b/src/llvm-project index 8d78ad13896b9..9ecb19f774994 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 8d78ad13896b955f630714f386a95ed91b237e3d +Subproject commit 9ecb19f774994a3efff5a6b89aa43ba2b8d2dd23 From e05a6bcd1e15938bd22cf9d632eb562875411dd6 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 12 Sep 2020 23:20:14 +0100 Subject: [PATCH 52/73] Teach rustc about the Xtensa arch. --- compiler/rustc_llvm/build.rs | 1 + compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 7 +++++++ compiler/rustc_llvm/src/lib.rs | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 621363bed80e1..5a8c5d317ba16 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -85,6 +85,7 @@ fn main() { "sparc", "nvptx", "hexagon", + "xtensa", "riscv", ]; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 2264908995bb7..f0e0c87e85073 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -231,6 +231,12 @@ void LLVMRustAddLastExtensionPasses( #define SUBTARGET_SPARC #endif +#ifdef LLVM_COMPONENT_XTENSA +#define SUBTARGET_XTENSA SUBTARGET(XTENSA) +#else +#define SUBTARGET_XTENSA +#endif + #ifdef LLVM_COMPONENT_HEXAGON #define SUBTARGET_HEXAGON SUBTARGET(Hexagon) #else @@ -248,6 +254,7 @@ void LLVMRustAddLastExtensionPasses( SUBTARGET_MSP430 \ SUBTARGET_SPARC \ SUBTARGET_HEXAGON \ + SUBTARGET_XTENSA \ SUBTARGET_RISCV \ #define SUBTARGET(x) \ diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index b2ffa271f62e2..81542047d88cc 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -162,6 +162,14 @@ pub fn initialize_available_targets() { LLVMInitializeHexagonAsmPrinter, LLVMInitializeHexagonAsmParser ); + init_target!( + llvm_component = "xtensa", + LLVMInitializeXtensaTargetInfo, + LLVMInitializeXtensaTarget, + LLVMInitializeXtensaTargetMC, + LLVMInitializeXtensaAsmPrinter, + LLVMInitializeXtensaAsmParser + ); init_target!( llvm_component = "webassembly", LLVMInitializeWebAssemblyTargetInfo, From 0c11a48b2d36e3be44360742f23864dec47a5abe Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 12 Sep 2020 23:31:14 +0100 Subject: [PATCH 53/73] Teach rustc about the Xtensa call ABI. --- compiler/rustc_target/src/abi/call/mod.rs | 2 + compiler/rustc_target/src/abi/call/xtensa.rs | 110 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 compiler/rustc_target/src/abi/call/xtensa.rs diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 5de9a8dfa7ac1..fcf1d643df3a5 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -7,6 +7,7 @@ mod amdgpu; mod arm; mod avr; mod hexagon; +mod xtensa; mod mips; mod mips64; mod msp430; @@ -604,6 +605,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { "nvptx" => nvptx::compute_abi_info(self), "nvptx64" => nvptx64::compute_abi_info(self), "hexagon" => hexagon::compute_abi_info(self), + "xtensa" => xtensa::compute_abi_info(cx, self), "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), "wasm32" if cx.target_spec().os != "emscripten" => { wasm32_bindgen_compat::compute_abi_info(self) diff --git a/compiler/rustc_target/src/abi/call/xtensa.rs b/compiler/rustc_target/src/abi/call/xtensa.rs new file mode 100644 index 0000000000000..422745d0a9e4c --- /dev/null +++ b/compiler/rustc_target/src/abi/call/xtensa.rs @@ -0,0 +1,110 @@ +// reference: https://github.com/MabezDev/llvm-project/blob/xtensa_release_9.0.1_with_rust_patches-31-05-2020-cherry-pick/clang/lib/CodeGen/TargetInfo.cpp#L9668-L9767 + +use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform}; +use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods,Abi, Size}; +use crate::spec::HasTargetSpec; + +const NUM_ARG_GPRS: u64 = 6; +const MAX_ARG_IN_REGS_SIZE: u64 = 4 * 32; +const MAX_RET_IN_REGS_SIZE: u64 = 2 * 32; + +fn classify_ret_ty(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { + if arg.is_ignore() { + return; + } + + // The rules for return and argument types are the same, + // so defer to `classify_arg_ty`. + let mut arg_gprs_left = 2; + let fixed = true; + classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left); +} + +fn classify_arg_ty(arg: &mut ArgAbi<'_, Ty>, xlen: u64, fixed: bool, arg_gprs_left: &mut u64) { + assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow"); + + // Ignore empty structs/unions. + if arg.layout.is_zst() { + return; + } + + let size = arg.layout.size.bits(); + let needed_align = arg.layout.align.abi.bits(); + let mut must_use_stack = false; + + // Determine the number of GPRs needed to pass the current argument + // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" + // register pairs, so may consume 3 registers. + let mut needed_arg_gprs = 1u64; + + if !fixed && needed_align == 2 * xlen { + needed_arg_gprs = 2 + (*arg_gprs_left % 2); + } else if size > xlen && size <= MAX_ARG_IN_REGS_SIZE { + needed_arg_gprs = (size + xlen - 1) / xlen; + } + + if needed_arg_gprs > *arg_gprs_left { + must_use_stack = true; + needed_arg_gprs = *arg_gprs_left; + } + *arg_gprs_left -= needed_arg_gprs; + + if !arg.layout.is_aggregate() && !matches!(arg.layout.abi, Abi::Vector { .. }) { + // All integral types are promoted to `xlen` + // width, unless passed on the stack. + if size < xlen && !must_use_stack { + arg.extend_integer_width_to(xlen); + return; + } + + return; + } + + // Aggregates which are <= 4 * 32 will be passed in + // registers if possible, so coerce to integers. + if size as u64 <= MAX_ARG_IN_REGS_SIZE { + let alignment = arg.layout.align.abi.bits(); + + // Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment + // is required, and a 2-element `xlen` array if only `xlen` alignment is + // required. + if size <= xlen { + arg.cast_to(Reg::i32()); + return; + } else if alignment == 2 * xlen { + arg.cast_to(Reg::i64()); + return; + } else { + let total = Size::from_bits(((size + xlen - 1) / xlen) * xlen); + arg.cast_to(Uniform { unit: Reg::i32(), total }); + return; + } + } + + arg.make_indirect(); +} + +pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +where + Ty: TyAndLayoutMethods<'a, C> + Copy, + C: LayoutOf> + HasDataLayout + HasTargetSpec, +{ + let xlen = cx.data_layout().pointer_size.bits(); + + if !fn_abi.ret.is_ignore() { + classify_ret_ty(&mut fn_abi.ret, xlen); + } + + let is_ret_indirect = + fn_abi.ret.is_indirect() || fn_abi.ret.layout.size.bits() > MAX_RET_IN_REGS_SIZE; + + let mut arg_gprs_left = if is_ret_indirect { NUM_ARG_GPRS - 1 } else { NUM_ARG_GPRS }; + + for arg in &mut fn_abi.args { + if arg.is_ignore() { + continue; + } + let fixed = true; + classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left); + } +} \ No newline at end of file From bc0e24ca614b657ce23fe3d5ba6a6b379f1a61f2 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Sat, 12 Sep 2020 23:36:21 +0100 Subject: [PATCH 54/73] Add some Xtensa targets ESP32, ESP8266 and a generic Xtensa target. --- compiler/rustc_target/src/spec/mod.rs | 4 ++ .../src/spec/xtensa_esp32_none_elf.rs | 47 +++++++++++++++++++ .../src/spec/xtensa_esp8266_none_elf.rs | 47 +++++++++++++++++++ .../rustc_target/src/spec/xtensa_none_elf.rs | 46 ++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs create mode 100644 compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs create mode 100644 compiler/rustc_target/src/spec/xtensa_none_elf.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8d72df6850fc2..9d50c25fda4b8 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -651,6 +651,10 @@ supported_targets! { ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda), + ("xtensa-esp32-none-elf", xtensa_esp32_none_elf), + ("xtensa-esp8266-none-elf", xtensa_esp8266_none_elf), + ("xtensa-none-elf", xtensa_none_elf), + ("i686-wrs-vxworks", i686_wrs_vxworks), ("x86_64-wrs-vxworks", x86_64_wrs_vxworks), ("armv7-wrs-vxworks-eabihf", armv7_wrs_vxworks_eabihf), diff --git a/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs new file mode 100644 index 0000000000000..b1586fd8f976e --- /dev/null +++ b/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs @@ -0,0 +1,47 @@ +use crate::spec::{abi::Abi, LinkerFlavor, PanicStrategy, Target, TargetOptions, RelocModel}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32".to_string(), + arch: "xtensa".to_string(), + + options: TargetOptions { + endian: "little".to_string(), + c_int_width: "32".to_string(), + os: "none".to_string(), + env: String::new(), + vendor: String::new(), + linker_flavor: LinkerFlavor::Gcc, + + executables: true, + cpu: "esp32".to_string(), + linker: Some("xtensa-esp32-elf-gcc".to_string()), + + max_atomic_width: Some(32), + + // Because these devices have very little resources having an + // unwinder is too onerous so we default to "abort" because the + // "unwind" strategy is very rare. + panic_strategy: PanicStrategy::Abort, + + // Similarly, one almost always never wants to use relocatable + // code because of the extra costs it involves. + relocation_model: RelocModel::Static, + + emit_debug_gdb_scripts: false, + + unsupported_abis: vec![ + Abi::Stdcall, + Abi::Fastcall, + Abi::Vectorcall, + Abi::Thiscall, + Abi::Win64, + Abi::SysV64, + ], + + ..Default::default() + }, + } +} \ No newline at end of file diff --git a/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs b/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs new file mode 100644 index 0000000000000..457720549880a --- /dev/null +++ b/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs @@ -0,0 +1,47 @@ +use crate::spec::{abi::Abi, LinkerFlavor, PanicStrategy, Target, TargetOptions, RelocModel}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32".to_string(), + arch: "xtensa".to_string(), + + options: TargetOptions { + endian: "little".to_string(), + c_int_width: "32".to_string(), + os: "none".to_string(), + env: String::new(), + vendor: String::new(), + linker_flavor: LinkerFlavor::Gcc, + + executables: true, + cpu: "esp8266".to_string(), + linker: Some("xtensa-lx106-elf-gcc".to_string()), + + max_atomic_width: Some(32), + + // Because these devices have very little resources having an + // unwinder is too onerous so we default to "abort" because the + // "unwind" strategy is very rare. + panic_strategy: PanicStrategy::Abort, + + // Similarly, one almost always never wants to use relocatable + // code because of the extra costs it involves. + relocation_model: RelocModel::Static, + + emit_debug_gdb_scripts: false, + + unsupported_abis: vec![ + Abi::Stdcall, + Abi::Fastcall, + Abi::Vectorcall, + Abi::Thiscall, + Abi::Win64, + Abi::SysV64, + ], + + ..Default::default() + }, + } +} \ No newline at end of file diff --git a/compiler/rustc_target/src/spec/xtensa_none_elf.rs b/compiler/rustc_target/src/spec/xtensa_none_elf.rs new file mode 100644 index 0000000000000..bc1deb40f9980 --- /dev/null +++ b/compiler/rustc_target/src/spec/xtensa_none_elf.rs @@ -0,0 +1,46 @@ +use crate::spec::{abi::Abi, LinkerFlavor, PanicStrategy, Target, TargetOptions, RelocModel}; + +pub fn target() -> Target { + Target { + llvm_target: "xtensa-none-elf".to_string(), + pointer_width: 32, + data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32".to_string(), + arch: "xtensa".to_string(), + + options: TargetOptions { + endian: "little".to_string(), + c_int_width: "32".to_string(), + os: "none".to_string(), + env: String::new(), + vendor: String::new(), + linker_flavor: LinkerFlavor::Gcc, + + executables: true, + linker: Some("xtensa-esp32-elf-gcc".to_string()), + + max_atomic_width: Some(32), + + // Because these devices have very little resources having an + // unwinder is too onerous so we default to "abort" because the + // "unwind" strategy is very rare. + panic_strategy: PanicStrategy::Abort, + + // Similarly, one almost always never wants to use relocatable + // code because of the extra costs it involves. + relocation_model: RelocModel::Static, + + emit_debug_gdb_scripts: false, + + unsupported_abis: vec![ + Abi::Stdcall, + Abi::Fastcall, + Abi::Vectorcall, + Abi::Thiscall, + Abi::Win64, + Abi::SysV64, + ], + + ..Default::default() + }, + } +} \ No newline at end of file From dc4254eea753c65e0f5b985cdb6f86ac93a43660 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Wed, 4 Dec 2019 17:38:49 +0100 Subject: [PATCH 55/73] Make `libstd` compile. --- .../src/spec/xtensa_esp32_none_elf.rs | 8 +- .../src/spec/xtensa_esp8266_none_elf.rs | 8 +- library/panic_unwind/src/gcc.rs | 3 + library/std/build.rs | 4 + library/std/src/lib.rs | 1 + library/std/src/os/freertos/fs.rs | 95 + library/std/src/os/freertos/mod.rs | 6 + library/std/src/os/freertos/raw.rs | 17 + library/std/src/os/mod.rs | 2 + library/std/src/sys/unix/alloc.rs | 7 +- library/std/src/sys/unix/args.rs | 1 + library/std/src/sys/unix/condvar.rs | 2 + library/std/src/sys/unix/env.rs | 11 + library/std/src/sys/unix/ext/net.rs | 1768 +++++++++++++++++ library/std/src/sys/unix/freertos/condvar.rs | 137 ++ library/std/src/sys/unix/freertos/ffi.rs | 101 + library/std/src/sys/unix/freertos/mutex.rs | 166 ++ library/std/src/sys/unix/freertos/thread.rs | 203 ++ .../std/src/sys/unix/freertos/thread_local.rs | 22 + .../sys/unix/freertos/thread_local_dtor.rs | 24 + .../src/sys/unix/freertos/thread_local_key.rs | 92 + library/std/src/sys/unix/fs.rs | 28 +- library/std/src/sys/unix/mod.rs | 38 +- library/std/src/sys/unix/net.rs | 192 +- library/std/src/sys/unix/net_fd.rs | 231 +++ library/std/src/sys/unix/os.rs | 19 +- library/std/src/sys/unix/pipe.rs | 9 +- library/std/src/sys/unix/process/mod.rs | 5 +- .../src/sys/unix/process/process_common.rs | 10 +- .../src/sys/unix/process/process_freertos.rs | 78 + .../std/src/sys/unix/process/process_unix.rs | 22 +- library/std/src/sys/unix/stdio.rs | 8 + library/std/src/sys/unix/time.rs | 4 +- library/std/src/sys_common/alloc.rs | 3 +- library/std/src/thread/mod.rs | 9 +- library/unwind/src/libunwind.rs | 3 + src/librustdoc/clean/cfg.rs | 1 + 37 files changed, 3244 insertions(+), 94 deletions(-) create mode 100644 library/std/src/os/freertos/fs.rs create mode 100644 library/std/src/os/freertos/mod.rs create mode 100644 library/std/src/os/freertos/raw.rs create mode 100644 library/std/src/sys/unix/ext/net.rs create mode 100644 library/std/src/sys/unix/freertos/condvar.rs create mode 100644 library/std/src/sys/unix/freertos/ffi.rs create mode 100644 library/std/src/sys/unix/freertos/mutex.rs create mode 100644 library/std/src/sys/unix/freertos/thread.rs create mode 100644 library/std/src/sys/unix/freertos/thread_local.rs create mode 100644 library/std/src/sys/unix/freertos/thread_local_dtor.rs create mode 100644 library/std/src/sys/unix/freertos/thread_local_key.rs create mode 100644 library/std/src/sys/unix/net_fd.rs create mode 100644 library/std/src/sys/unix/process/process_freertos.rs diff --git a/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs index b1586fd8f976e..76911e402f019 100644 --- a/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs +++ b/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs @@ -10,14 +10,16 @@ pub fn target() -> Target { options: TargetOptions { endian: "little".to_string(), c_int_width: "32".to_string(), - os: "none".to_string(), - env: String::new(), - vendor: String::new(), + os: "freertos".to_string(), + target_family: Some("unix".to_string()), + env: "newlib".to_string(), + vendor: "espressif".to_string(), linker_flavor: LinkerFlavor::Gcc, executables: true, cpu: "esp32".to_string(), linker: Some("xtensa-esp32-elf-gcc".to_string()), + linker_is_gnu: true, max_atomic_width: Some(32), diff --git a/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs b/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs index 457720549880a..02f48065f7100 100644 --- a/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs +++ b/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs @@ -10,14 +10,16 @@ pub fn target() -> Target { options: TargetOptions { endian: "little".to_string(), c_int_width: "32".to_string(), - os: "none".to_string(), - env: String::new(), - vendor: String::new(), + os: "freertos".to_string(), + target_family: Some("unix".to_string()), + env: "newlib".to_string(), + vendor: "espressif".to_string(), linker_flavor: LinkerFlavor::Gcc, executables: true, cpu: "esp8266".to_string(), linker: Some("xtensa-lx106-elf-gcc".to_string()), + linker_is_gnu: true, max_atomic_width: Some(32), diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index 14f49bbf48337..1484897f11862 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -123,6 +123,9 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 +#[cfg(target_arch = "xtensa")] +const UNWIND_DATA_REG: (i32, i32) = (2, 3); // A2, A3 + // The following code is based on GCC's C and C++ personality routines. For reference, see: // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c diff --git a/library/std/build.rs b/library/std/build.rs index a14ac63c7a8e4..9cc58cab06f7f 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -28,6 +28,10 @@ fn main() { || target.contains("asmjs") { // These platforms don't have any special requirements. + } else if target.contains("esp32") { + println!(r#"cargo:rustc-cfg=target_device="esp32""#); + } else if target.contains("esp8266") { + println!(r#"cargo:rustc-cfg=target_device="esp8266""#); } else { // This is for Cargo's build-std support, to mark std as unstable for // typically no_std platforms. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5bc5ddaa5fe30..b5a49419a1591 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -275,6 +275,7 @@ #![feature(into_future)] #![feature(lang_items)] #![feature(link_args)] +#![feature(linked_list_remove)] #![feature(linkage)] #![feature(llvm_asm)] #![feature(log_syntax)] diff --git a/library/std/src/os/freertos/fs.rs b/library/std/src/os/freertos/fs.rs new file mode 100644 index 0000000000000..59870801d93e3 --- /dev/null +++ b/library/std/src/os/freertos/fs.rs @@ -0,0 +1,95 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + 0 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + 0 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + 0 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/freertos/mod.rs b/library/std/src/os/freertos/mod.rs new file mode 100644 index 0000000000000..c5ba004aeb247 --- /dev/null +++ b/library/std/src/os/freertos/mod.rs @@ -0,0 +1,6 @@ +//! FreeRTOS-specific definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod raw; +pub mod fs; diff --git a/library/std/src/os/freertos/raw.rs b/library/std/src/os/freertos/raw.rs new file mode 100644 index 0000000000000..d43db3f61c664 --- /dev/null +++ b/library/std/src/os/freertos/raw.rs @@ -0,0 +1,17 @@ +//! FreeRTOS-specific raw type definitions + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![rustc_deprecated(since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions")] +#![allow(deprecated)] +#![allow(missing_debug_implementations)] + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub use libc::pthread_t; + +#[doc(inline)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index fd6ee088e961c..286de2a6f9918 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -48,6 +48,8 @@ pub mod emscripten; pub mod fortanix_sgx; #[cfg(target_os = "freebsd")] pub mod freebsd; +#[cfg(target_os = "freertos")] +pub mod freertos; #[cfg(target_os = "fuchsia")] pub mod fuchsia; #[cfg(target_os = "haiku")] diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 964abe8b8c9ea..4972a59305caf 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -53,7 +53,12 @@ unsafe impl GlobalAlloc for System { } cfg_if::cfg_if! { - if #[cfg(any( + if #[cfg(target_os = "freertos")] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + libc::malloc(layout.size()) as *mut u8 + } + } else if #[cfg(any( target_os = "android", target_os = "illumos", target_os = "redox", diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 6967647249390..f4f57ef263358 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -61,6 +61,7 @@ impl DoubleEndedIterator for Args { target_os = "linux", target_os = "android", target_os = "freebsd", + target_os = "freertos", target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd", diff --git a/library/std/src/sys/unix/condvar.rs b/library/std/src/sys/unix/condvar.rs index e38f91af9f0b9..907de0f133bb5 100644 --- a/library/std/src/sys/unix/condvar.rs +++ b/library/std/src/sys/unix/condvar.rs @@ -30,6 +30,7 @@ impl Condvar { target_os = "ios", target_os = "l4re", target_os = "android", + target_os = "freertos", target_os = "redox" ))] pub unsafe fn init(&mut self) {} @@ -39,6 +40,7 @@ impl Condvar { target_os = "ios", target_os = "l4re", target_os = "android", + target_os = "freertos", target_os = "redox" )))] pub unsafe fn init(&mut self) { diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index 7f5e9b04dba4b..64a199bd833f4 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -173,3 +173,14 @@ pub mod os { pub const EXE_SUFFIX: &str = ""; pub const EXE_EXTENSION: &str = ""; } + +#[cfg(target_os = "freertos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "freertos"; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ""; + pub const DLL_EXTENSION: &str = ""; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs new file mode 100644 index 0000000000000..432417bf1d6c8 --- /dev/null +++ b/library/std/src/sys/unix/ext/net.rs @@ -0,0 +1,1768 @@ +//! Unix-specific networking functionality. + +#![stable(feature = "unix_socket", since = "1.10.0")] + +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? +#[cfg(not(unix))] +#[allow(non_camel_case_types)] +mod libc { + pub use libc::c_int; + pub type socklen_t = u32; + pub struct sockaddr; + #[derive(Clone)] + pub struct sockaddr_un; +} + +use crate::ascii; +use crate::ffi::OsStr; +use crate::fmt; +use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::mem; +use crate::net::{self, Shutdown}; +use crate::os::unix::ffi::OsStrExt; +use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +use crate::path::Path; +use crate::sys::{self, cvt}; +use crate::sys::net::{netc, Socket}; +use crate::sys_common::{self, AsInner, FromInner, IntoInner}; +use crate::time::Duration; + +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any( + target_os = "linux", + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "haiku" +)))] +const MSG_NOSIGNAL: libc::c_int = 0x0; + +fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { + // Work with an actual instance of the type since using a null pointer is UB + let base = addr as *const _ as usize; + let path = &addr.sun_path as *const _ as usize; + path - base +} + +unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { + let mut addr: libc::sockaddr_un = mem::zeroed(); + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + + let bytes = path.as_os_str().as_bytes(); + + if bytes.contains(&0) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "paths may not contain interior null bytes", + )); + } + + if bytes.len() >= addr.sun_path.len() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "path must be shorter than SUN_LEN", + )); + } + for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { + *dst = *src as libc::c_char; + } + // null byte for pathname addresses is already there because we zeroed the + // struct + + let mut len = sun_path_offset(&addr) + bytes.len(); + match bytes.get(0) { + Some(&0) | None => {} + Some(_) => len += 1, + } + Ok((addr, len as libc::socklen_t)) +} + +enum AddressKind<'a> { + Unnamed, + Pathname(&'a Path), + Abstract(&'a [u8]), +} + +/// An address associated with a Unix socket. +/// +/// # Examples +/// +/// ``` +/// use std::os::unix::net::UnixListener; +/// +/// let socket = match UnixListener::bind("/tmp/sock") { +/// Ok(sock) => sock, +/// Err(e) => { +/// println!("Couldn't bind: {:?}", e); +/// return +/// } +/// }; +/// let addr = socket.local_addr().expect("Couldn't get local address"); +/// ``` +#[derive(Clone)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct SocketAddr { + addr: libc::sockaddr_un, + len: libc::socklen_t, +} + +impl SocketAddr { + fn new(f: F) -> io::Result + where + F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, + { + unsafe { + let mut addr: libc::sockaddr_un = mem::zeroed(); + let mut len = mem::size_of::() as libc::socklen_t; + cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; + SocketAddr::from_parts(addr, len) + } + } + + fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address + } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "file descriptor did not correspond to a Unix socket", + )); + } + + Ok(SocketAddr { addr, len }) + } + + /// Returns `true` if the address is unnamed. + /// + /// # Examples + /// + /// A named address: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), false); + /// Ok(()) + /// } + /// ``` + /// + /// An unnamed address: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.is_unnamed(), true); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn is_unnamed(&self) -> bool { + if let AddressKind::Unnamed = self.address() { true } else { false } + } + + /// Returns the contents of this address if it is a `pathname` address. + /// + /// # Examples + /// + /// With a pathname: + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// use std::path::Path; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixListener::bind("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); + /// Ok(()) + /// } + /// ``` + /// + /// Without a pathname: + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// assert_eq!(addr.as_pathname(), None); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn as_pathname(&self) -> Option<&Path> { + if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } + } + + fn address(&self) -> AddressKind<'_> { + let len = self.len as usize - sun_path_offset(&self.addr); + let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; + + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { + AddressKind::Unnamed + } else if self.addr.sun_path[0] == 0 { + AddressKind::Abstract(&path[1..len]) + } else { + AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) + } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for SocketAddr { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.address() { + AddressKind::Unnamed => write!(fmt, "(unnamed)"), + AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), + AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + } + } +} + +struct AsciiEscaped<'a>(&'a [u8]); + +impl<'a> fmt::Display for AsciiEscaped<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "\"")?; + for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { + write!(fmt, "{}", byte as char)?; + } + write!(fmt, "\"") + } +} + +/// A Unix stream socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixStream; +/// use std::io::prelude::*; +/// +/// fn main() -> std::io::Result<()> { +/// let mut stream = UnixStream::connect("/path/to/my/socket")?; +/// stream.write_all(b"hello world")?; +/// let mut response = String::new(); +/// stream.read_to_string(&mut response)?; +/// println!("{}", response); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixStream(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixStream { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixStream"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixStream { + /// Connects to the socket named by `path`. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let socket = match UnixStream::connect("/tmp/sock") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(netc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; + Ok(UnixStream(inner)) + } + } + inner(path.as_ref()) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixStream`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// let (sock1, sock2) = match UnixStream::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't create a pair of sockets: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixStream, UnixStream)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; + Ok((UnixStream(i1), UnixStream(i2))) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixStream` is a reference to the same stream that this + /// object references. Both handles will read and write the same stream of + /// data, and options set on one stream will be propagated to the other + /// stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixStream) + } + + /// Returns the socket address of the local half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { netc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the socket address of the remote half of this connection. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let addr = socket.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { netc::getpeername(*self.0.as_inner(), addr, len) }) + } + + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peer_credentials_unix_socket)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`read`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`write`] calls will block + /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is + /// passed to this method. + /// + /// [`read`]: io::Read::read + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::net::UdpSocket; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UdpSocket::bind("127.0.0.1:34254")?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); + /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("Couldn't set write timeout"); + /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// if let Ok(Some(err)) = socket.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shuts down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixStream; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Read for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + io::Read::read(&mut &*self, buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::Read::read_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + io::Read::is_read_vectored(&&*self) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Read for &'a UnixStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + self.0.read_vectored(bufs) + } + + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl io::Write for UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + io::Write::write(&mut &*self, buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + io::Write::write_vectored(&mut &*self, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + + fn flush(&mut self) -> io::Result<()> { + io::Write::flush(&mut &*self) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> io::Write for &'a UnixStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixStream { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixStream { + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixStream { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> RawFd { + *self.as_inner().socket().as_inner() + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + let socket = sys::net::Socket::from_inner(fd); + net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + let socket = sys::net::Socket::from_inner(fd); + net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) + } +} + +#[stable(feature = "from_raw_os", since = "1.1.0")] +impl FromRawFd for net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + let socket = sys::net::Socket::from_inner(fd); + net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_socket().into_inner() + } +} + +/// A structure representing a Unix domain socket server. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// // accept connections and process them, spawning a new thread for each one +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// /* connection succeeded */ +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// /* connection failed */ +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixListener(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixListener { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixListener"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + builder.finish() + } +} + +impl UnixListener { + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; + let (addr, len) = sockaddr_un(path)?; + + cvt(netc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; + cvt(netc::listen(*inner.as_inner(), 128))?; + + Ok(UnixListener(inner)) + } + } + inner(path.as_ref()) + } + + /// Accepts a new incoming connection to this listener. + /// + /// This function will block the calling thread until a new Unix connection + /// is established. When established, the corresponding [`UnixStream`] and + /// the remote peer's address will be returned. + /// + /// [`UnixStream`]: crate::os::unix::net::UnixStream + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// match listener.accept() { + /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), + /// Err(e) => println!("accept function failed: {:?}", e), + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { + let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; + let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; + let addr = SocketAddr::from_parts(storage, len)?; + Ok((UnixStream(sock), addr)) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixListener` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one listener will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let listener_copy = listener.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixListener) + } + + /// Returns the local socket address of this listener. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// let addr = listener.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { netc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// This will result in the `accept` operation becoming nonblocking, + /// i.e., immediately returning from their calls. If the IO operation is + /// successful, `Ok` is returned and no further action is required. If the + /// IO operation could not be completed and needs to be retried, an error + /// with kind [`io::ErrorKind::WouldBlock`] is returned. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/tmp/sock")?; + /// + /// if let Ok(Some(err)) = listener.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + /// + /// # Platform specific + /// On Redox this always returns `None`. + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Returns an iterator over incoming connections. + /// + /// The iterator will never return [`None`] and will also not yield the + /// peer's [`SocketAddr`] structure. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread; + /// use std::os::unix::net::{UnixStream, UnixListener}; + /// + /// fn handle_client(stream: UnixStream) { + /// // ... + /// } + /// + /// fn main() -> std::io::Result<()> { + /// let listener = UnixListener::bind("/path/to/the/socket")?; + /// + /// for stream in listener.incoming() { + /// match stream { + /// Ok(stream) => { + /// thread::spawn(|| handle_client(stream)); + /// } + /// Err(err) => { + /// break; + /// } + /// } + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn incoming(&self) -> Incoming<'_> { + Incoming { listener: self } + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixListener { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixListener { + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixListener { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> IntoIterator for &'a UnixListener { + type Item = io::Result; + type IntoIter = Incoming<'a>; + + fn into_iter(self) -> Incoming<'a> { + self.incoming() + } +} + +/// An iterator over incoming connections to a [`UnixListener`]. +/// +/// It will never return [`None`]. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread; +/// use std::os::unix::net::{UnixStream, UnixListener}; +/// +/// fn handle_client(stream: UnixStream) { +/// // ... +/// } +/// +/// fn main() -> std::io::Result<()> { +/// let listener = UnixListener::bind("/path/to/the/socket")?; +/// +/// for stream in listener.incoming() { +/// match stream { +/// Ok(stream) => { +/// thread::spawn(|| handle_client(stream)); +/// } +/// Err(err) => { +/// break; +/// } +/// } +/// } +/// Ok(()) +/// } +/// ``` +#[derive(Debug)] +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct Incoming<'a> { + listener: &'a UnixListener, +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl<'a> Iterator for Incoming<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + Some(self.listener.accept().map(|s| s.0)) + } + + fn size_hint(&self) -> (usize, Option) { + (usize::MAX, None) + } +} + +/// A Unix datagram socket. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::net::UnixDatagram; +/// +/// fn main() -> std::io::Result<()> { +/// let socket = UnixDatagram::bind("/path/to/my/socket")?; +/// socket.send_to(b"hello world", "/path/to/other/socket")?; +/// let mut buf = [0; 100]; +/// let (count, address) = socket.recv_from(&mut buf)?; +/// println!("socket {:?} sent {:?}", address, &buf[..count]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "unix_socket", since = "1.10.0")] +pub struct UnixDatagram(Socket); + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl fmt::Debug for UnixDatagram { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut builder = fmt.debug_struct("UnixDatagram"); + builder.field("fd", self.0.as_inner()); + if let Ok(addr) = self.local_addr() { + builder.field("local", &addr); + } + if let Ok(addr) = self.peer_addr() { + builder.field("peer", &addr); + } + builder.finish() + } +} + +impl UnixDatagram { + /// Creates a Unix datagram socket bound to the given path. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::bind("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't bind: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn bind>(path: P) -> io::Result { + fn inner(path: &Path) -> io::Result { + unsafe { + let socket = UnixDatagram::unbound()?; + let (addr, len) = sockaddr_un(path)?; + + cvt(netc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; + + Ok(socket) + } + } + inner(path.as_ref()) + } + + /// Creates a Unix Datagram socket which is not bound to any address. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let sock = match UnixDatagram::unbound() { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn unbound() -> io::Result { + let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok(UnixDatagram(inner)) + } + + /// Creates an unnamed pair of connected sockets. + /// + /// Returns two `UnixDatagrams`s which are connected to each other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// let (sock1, sock2) = match UnixDatagram::pair() { + /// Ok((sock1, sock2)) => (sock1, sock2), + /// Err(e) => { + /// println!("Couldn't unbound: {:?}", e); + /// return + /// } + /// }; + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { + let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; + Ok((UnixDatagram(i1), UnixDatagram(i2))) + } + + /// Connects the socket to the specified address. + /// + /// The [`send`] method may be used to send data to the specified address. + /// [`recv`] and [`recv_from`] will only receive data from that address. + /// + /// [`send`]: UnixDatagram::send + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// match sock.connect("/path/to/the/socket") { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return Err(e) + /// } + /// }; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn connect>(&self, path: P) -> io::Result<()> { + fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { + unsafe { + let (addr, len) = sockaddr_un(path)?; + + cvt(netc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; + + Ok(()) + } + } + inner(self, path.as_ref()) + } + + /// Creates a new independently owned handle to the underlying socket. + /// + /// The returned `UnixDatagram` is a reference to the same socket that this + /// object references. Both handles can be used to accept incoming + /// connections and options set on one side will affect the other. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let sock_copy = sock.try_clone().expect("try_clone failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn try_clone(&self) -> io::Result { + self.0.duplicate().map(UnixDatagram) + } + + /// Returns the address of this socket. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let addr = sock.local_addr().expect("Couldn't get local address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn local_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { netc::getsockname(*self.0.as_inner(), addr, len) }) + } + + /// Returns the address of this socket's peer. + /// + /// The [`connect`] method will connect the socket to a peer. + /// + /// [`connect`]: UnixDatagram::connect + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/path/to/the/socket")?; + /// + /// let addr = sock.peer_addr().expect("Couldn't get peer address"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn peer_addr(&self) -> io::Result { + SocketAddr::new(|addr, len| unsafe { netc::getpeername(*self.0.as_inner(), addr, len) }) + } + + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = netc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read and the address from + /// whence the data came. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// let mut buf = vec![0; 10]; + /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; + /// println!("received {} bytes from {:?}", size, sender); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, 0) + } + + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::bind("/path/to/the/socket")?; + /// let mut buf = vec![0; 10]; + /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + /// Sends data on the socket to the specified address. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { + fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { + unsafe { + let (addr, len) = sockaddr_un(path)?; + + let count = cvt(netc::sendto( + *d.0.as_inner(), + buf.as_ptr() as *const _, + buf.len(), + MSG_NOSIGNAL, + &addr as *const _ as *const _, + len, + ))?; + Ok(count as usize) + } + } + inner(self, buf, path.as_ref()) + } + + /// Sends data on the socket to the socket's peer. + /// + /// The peer address may be set by the `connect` method, and this method + /// will return an error if the socket has not already been connected. + /// + /// On success, returns the number of bytes written. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.connect("/some/sock").expect("Couldn't connect"); + /// sock.send(b"omelette au fromage").expect("send_to function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn send(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + /// Sets the read timeout for the socket. + /// + /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] + /// is passed to this method. + /// + /// [`recv`]: UnixDatagram::recv + /// [`recv_from`]: UnixDatagram::recv_from + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will + /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method. + /// + /// [`send`]: UnixDatagram::send + /// [`send_to`]: UnixDatagram::send_to + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// Ok(()) + /// } + /// ``` + /// + /// An [`Err`] is returned if the zero [`Duration`] is passed to this + /// method: + /// + /// ```no_run + /// use std::io; + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::unbound()?; + /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + /// let err = result.unwrap_err(); + /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.0.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + /// Returns the read timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_read_timeout(Some(Duration::new(1, 0))) + /// .expect("set_read_timeout function failed"); + /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn read_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// use std::time::Duration; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_write_timeout(Some(Duration::new(1, 0))) + /// .expect("set_write_timeout function failed"); + /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn write_timeout(&self) -> io::Result> { + self.0.timeout(libc::SO_SNDTIMEO) + } + + /// Moves the socket into or out of nonblocking mode. + /// + /// # Examples + /// + /// ``` + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + self.0.set_nonblocking(nonblocking) + } + + /// Returns the value of the `SO_ERROR` option. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// if let Ok(Some(err)) = sock.take_error() { + /// println!("Got error: {:?}", err); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn take_error(&self) -> io::Result> { + self.0.take_error() + } + + /// Shut down the read, write, or both halves of this connection. + /// + /// This function will cause all pending and future I/O calls on the + /// specified portions to immediately return with an appropriate value + /// (see the documentation of [`Shutdown`]). + /// + /// ```no_run + /// use std::os::unix::net::UnixDatagram; + /// use std::net::Shutdown; + /// + /// fn main() -> std::io::Result<()> { + /// let sock = UnixDatagram::unbound()?; + /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "unix_socket", since = "1.10.0")] + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + self.0.shutdown(how) + } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl AsRawFd for UnixDatagram { + fn as_raw_fd(&self) -> RawFd { + *self.0.as_inner() + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl FromRawFd for UnixDatagram { + unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { + UnixDatagram(Socket::from_inner(fd)) + } +} + +#[stable(feature = "unix_socket", since = "1.10.0")] +impl IntoRawFd for UnixDatagram { + fn into_raw_fd(self) -> RawFd { + self.0.into_inner() + } +} diff --git a/library/std/src/sys/unix/freertos/condvar.rs b/library/std/src/sys/unix/freertos/condvar.rs new file mode 100644 index 0000000000000..5011da4ae9662 --- /dev/null +++ b/library/std/src/sys/unix/freertos/condvar.rs @@ -0,0 +1,137 @@ +use crate::cell::UnsafeCell; +use crate::collections::VecDeque; +use crate::sys::mutex::{Mutex, ReentrantMutex}; +use crate::time::Duration; + +use crate::sys::ffi::*; + +pub struct Condvar { + lock: ReentrantMutex, + waiter_list: UnsafeCell>>, +} + +unsafe impl Send for Condvar {} +unsafe impl Sync for Condvar {} + +impl Condvar { + pub const fn new() -> Condvar { + // Might be moved and address is changing it is better to avoid + // initialization of potentially opaque OS data before it landed + Condvar { + lock: unsafe { ReentrantMutex::uninitialized() }, + waiter_list: UnsafeCell::new(None), + } + } + + #[inline] + pub unsafe fn init(&mut self) {} + + #[inline] + unsafe fn init_waiter_list(&self) { + if (*self.waiter_list.get()).is_none() { + (*self.waiter_list.get()) = Some(VecDeque::new()); + } + } + + #[inline] + pub unsafe fn notify_one(&self) { + self.lock.lock(); + + self.init_waiter_list(); + let waiter_list = (&*self.waiter_list.get()).as_ref().unwrap(); + if let Some(&waiter) = waiter_list.front() { + xSemaphoreGive(waiter); + } + + self.lock.unlock(); + } + + #[inline] + pub unsafe fn notify_all(&self) { + self.lock.lock(); + + self.init_waiter_list(); + let waiter_list = (&*self.waiter_list.get()).as_ref().unwrap(); + for &waiter in waiter_list { + xSemaphoreGive(waiter); + } + + self.lock.unlock(); + } + + #[inline] + pub unsafe fn wait(&self, mutex: &Mutex) { + let r = self.wait_timeout_option(mutex, None); + debug_assert_eq!(r, true); + } + + #[inline] + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + self.wait_timeout_option(mutex, Some(dur)) + } + + unsafe fn wait_timeout_option(&self, mutex: &Mutex, dur: Option) -> bool { + use crate::time::Instant; + + let (now, timeout_ticks) = if let Some(dur) = dur { + let now = Instant::now(); + let timeout_ms = dur.as_millis() as TickType_t; + let portTICK_PERIOD_MS = 1000 / xPortGetTickRateHz(); + (Some(now), timeout_ms / portTICK_PERIOD_MS) + } else { + (None, TickType_t::max_value()) + }; + + let waiter = xSemaphoreCreateCounting(1, 0); + + self.lock.lock(); + + self.init_waiter_list(); + let waiter_list = (&mut *self.waiter_list.get()).as_mut().unwrap(); + waiter_list.push_back(waiter); + + self.lock.unlock(); + + mutex.unlock(); + + let r = if xSemaphoreTake(waiter, timeout_ticks) == pdTRUE { + true + } else { + false + }; + + self.lock.lock(); + + let waiter_list = (&mut *self.waiter_list.get()).as_mut().unwrap(); + let deleted_waiter = if let Some(index) = waiter_list.iter().position(|&w| w == waiter) { + waiter_list.remove(index) + } else { + None + }; + + self.lock.unlock(); + + if let Some(deleted_waiter) = deleted_waiter { + vSemaphoreDelete(deleted_waiter); + } + + mutex.lock(); + + if let (Some(now), Some(dur)) = (now, dur) { + r && now.elapsed() < dur + } else { + r + } + } + + #[inline] + pub unsafe fn destroy(&self) { + self.lock.lock(); + + if let Some(waiter_list) = (&*self.waiter_list.get()).as_ref() { + assert!(waiter_list.is_empty()); + } + + self.lock.unlock(); + } +} diff --git a/library/std/src/sys/unix/freertos/ffi.rs b/library/std/src/sys/unix/freertos/ffi.rs new file mode 100644 index 0000000000000..32a359ed93828 --- /dev/null +++ b/library/std/src/sys/unix/freertos/ffi.rs @@ -0,0 +1,101 @@ +use crate::ptr; + +pub type UBaseType_t = libc::c_uint; +pub type BaseType_t = libc::c_int; +pub type TickType_t = u32; +pub type TaskHandle_t = *mut libc::c_void; +pub type QueueHandle_t = *mut libc::c_void; +pub type SemaphoreHandle_t = QueueHandle_t; +pub type TaskFunction_t = extern "C" fn(*mut libc::c_void) -> *mut libc::c_void; + +pub const queueQUEUE_TYPE_MUTEX: u8 = 1; +pub const queueQUEUE_TYPE_RECURSIVE_MUTEX: u8 = 4; +pub const pdFALSE: BaseType_t = 0; +pub const pdTRUE: BaseType_t = 1; +pub const semGIVE_BLOCK_TIME: TickType_t = 0; +pub const queueSEND_TO_BACK: BaseType_t = 0; +pub const errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: BaseType_t = -1; + +extern "C" { + pub fn vTaskSuspend(handle: TaskHandle_t); + pub fn vTaskDelete(handle: TaskHandle_t); + pub fn xTaskGetCurrentTaskHandle() -> TaskHandle_t; + pub fn vTaskDelay(xTicksToDelay: TickType_t); + pub fn xQueueCreateMutex(ucQueueType: u8) -> QueueHandle_t; + #[link_name = "xQueueTakeMutexRecursive"] + pub fn xSemaphoreTakeRecursive(sem: SemaphoreHandle_t, tmo: TickType_t) -> BaseType_t; + #[link_name = "xQueueGiveMutexRecursive"] + pub fn xSemaphoreGiveRecursive(sem: SemaphoreHandle_t) -> BaseType_t; + pub fn xQueueGenericReceive( + xQueue: QueueHandle_t, + pvBuffer: *const libc::c_void, + xTicksToWait: TickType_t, + xJustPeeking: BaseType_t, + ) -> BaseType_t; + pub fn xQueueGenericSend( + xQueue: QueueHandle_t, + pvItemToQueue: *const libc::c_void, + xTicksToWait: TickType_t, + xCopyPosition: BaseType_t, + ) -> BaseType_t; + #[link_name = "vQueueDelete"] + pub fn vSemaphoreDelete(sem: SemaphoreHandle_t); + #[link_name = "xQueueCreateCountingSemaphore"] + pub fn xSemaphoreCreateCounting(max: UBaseType_t, initial: UBaseType_t) -> SemaphoreHandle_t; + pub fn xPortGetTickRateHz() -> u32; + #[cfg(target_device = "esp8266")] + pub fn xTaskCreate( + pxTaskCode: TaskFunction_t, + pcName: *const libc::c_char, + usStackDepth: u32, + pvParameters: *const libc::c_void, + uxPriority: UBaseType_t, + pxCreatedTask: *mut TaskHandle_t, + ) -> BaseType_t; + #[cfg(target_device = "esp32")] + pub fn xTaskCreatePinnedToCore( + pxTaskCode: TaskFunction_t, + pcName: *const libc::c_char, + usStackDepth: u32, + pvParameters: *const libc::c_void, + uxPriority: UBaseType_t, + pxCreatedTask: *mut TaskHandle_t, + xCoreID: BaseType_t, + ) -> BaseType_t; + pub fn pvTaskGetThreadLocalStoragePointer(xTaskToQuery: TaskHandle_t, xIndex: BaseType_t) -> *mut libc::c_void; + pub fn vTaskSetThreadLocalStoragePointer(xTaskToQuery: TaskHandle_t, xIndex: BaseType_t, pvValue: *mut libc::c_void); +} + +#[cfg(target_device = "esp32")] +#[inline] +pub unsafe fn xTaskCreate( + pxTaskCode: TaskFunction_t, + pcName: *const libc::c_char, + usStackDepth: u32, + pvParameters: *const libc::c_void, + uxPriority: UBaseType_t, + pxCreatedTask: *mut TaskHandle_t, +) -> BaseType_t { + const tskNO_AFFINITY: BaseType_t = BaseType_t::max_value(); + xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, tskNO_AFFINITY) +} + +#[inline] +pub unsafe fn xSemaphoreCreateRecursiveMutex() -> SemaphoreHandle_t { + xQueueCreateMutex(queueQUEUE_TYPE_RECURSIVE_MUTEX) +} + +#[inline] +pub unsafe fn xSemaphoreCreateMutex() -> SemaphoreHandle_t { + xQueueCreateMutex(queueQUEUE_TYPE_MUTEX) +} + +#[inline] +pub unsafe fn xSemaphoreGive(sem: SemaphoreHandle_t) -> BaseType_t { + xQueueGenericSend(sem, ptr::null(), semGIVE_BLOCK_TIME, queueSEND_TO_BACK) +} + +#[inline] +pub unsafe fn xSemaphoreTake(sem: SemaphoreHandle_t, timeout: TickType_t) -> BaseType_t { + xQueueGenericReceive(sem, ptr::null(), timeout, pdFALSE) +} diff --git a/library/std/src/sys/unix/freertos/mutex.rs b/library/std/src/sys/unix/freertos/mutex.rs new file mode 100644 index 0000000000000..361296016c75b --- /dev/null +++ b/library/std/src/sys/unix/freertos/mutex.rs @@ -0,0 +1,166 @@ +use crate::cell::UnsafeCell; +use crate::ptr; +use crate::sync::atomic::{AtomicU8, Ordering::SeqCst}; + +use crate::sys::ffi::*; + +pub struct Mutex { + inner: UnsafeCell, + initialized: AtomicU8, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +const UNINITIALIZING: u8 = 3; +const UNINITIALIZED: u8 = 2; +const INITIALIZING: u8 = 1; +const INITIALIZED: u8 = 0; + +#[allow(dead_code)] // sys isn't exported yet +impl Mutex { + pub const fn new() -> Mutex { + Mutex { inner: UnsafeCell::new(ptr::null_mut()), initialized: AtomicU8::new(UNINITIALIZED) } + } + + #[inline] + pub unsafe fn init(&mut self) { + self.atomic_init(); + } + + #[inline] + unsafe fn atomic_init(&self) { + loop { + match self.initialized.compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst) { + UNINITIALIZED => { + *self.inner.get() = xSemaphoreCreateMutex(); + debug_assert!(!(*self.inner.get()).is_null()); + self.initialized.store(INITIALIZED, SeqCst); + return; + } + INITIALIZED => return, + _ => continue, + } + } + } + + #[inline] + pub unsafe fn lock(&self) { + self.atomic_init(); + let r = xSemaphoreTake(*self.inner.get(), TickType_t::max_value()); + debug_assert_eq!(r, pdTRUE); + } + + #[inline] + pub unsafe fn unlock(&self) { + self.atomic_init(); + let r = xSemaphoreGive(*self.inner.get()); + debug_assert_eq!(r, pdTRUE); + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + self.atomic_init(); + xSemaphoreTake(*self.inner.get(), 0) == pdTRUE + } + + #[inline] + pub unsafe fn destroy(&self) { + loop { + match self.initialized.compare_and_swap(INITIALIZED, UNINITIALIZING, SeqCst) { + INITIALIZED => { + vSemaphoreDelete(*self.inner.get()); + *self.inner.get() = ptr::null_mut(); + self.initialized.store(UNINITIALIZED, SeqCst); + return; + } + UNINITIALIZED => return, + _ => continue, + } + } + } +} + +impl Drop for Mutex { + fn drop(&mut self) { + unsafe { self.destroy() } + } +} + +pub struct ReentrantMutex { + inner: UnsafeCell, + initialized: AtomicU8, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex { + inner: UnsafeCell::new(ptr::null_mut()), + initialized: AtomicU8::new(UNINITIALIZED), + } + } + + #[inline] + pub unsafe fn init(&self) { + self.atomic_init(); + } + + #[inline] + unsafe fn atomic_init(&self) { + loop { + match self.initialized.compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst) { + UNINITIALIZED => { + *self.inner.get() = xSemaphoreCreateRecursiveMutex(); + debug_assert!(!(*self.inner.get()).is_null()); + self.initialized.store(INITIALIZED, SeqCst); + return; + } + INITIALIZED => return, + _ => continue, + } + } + } + + #[inline] + pub unsafe fn lock(&self) { + self.atomic_init(); + let r = xSemaphoreTakeRecursive(*self.inner.get(), TickType_t::max_value()); + debug_assert_eq!(r, pdTRUE); + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + self.atomic_init(); + xSemaphoreTakeRecursive(*self.inner.get(), 0) == pdTRUE + } + + pub unsafe fn unlock(&self) { + self.atomic_init(); + let r = xSemaphoreGiveRecursive(*self.inner.get()); + debug_assert_eq!(r, pdTRUE); + } + + pub unsafe fn destroy(&self) { + loop { + match self.initialized.compare_and_swap(INITIALIZED, UNINITIALIZING, SeqCst) { + INITIALIZED => { + vSemaphoreDelete(*self.inner.get()); + *self.inner.get() = ptr::null_mut(); + self.initialized.store(UNINITIALIZED, SeqCst); + return; + } + UNINITIALIZED => return, + _ => continue, + } + } + } +} + +impl Drop for ReentrantMutex { + fn drop(&mut self) { + unsafe { self.destroy() } + } +} diff --git a/library/std/src/sys/unix/freertos/thread.rs b/library/std/src/sys/unix/freertos/thread.rs new file mode 100644 index 0000000000000..9eed71d08479f --- /dev/null +++ b/library/std/src/sys/unix/freertos/thread.rs @@ -0,0 +1,203 @@ +use crate::ffi::CStr; +use crate::io; +use crate::mem; +use crate::ptr; +use crate::sync::{ + atomic::{AtomicU8, Ordering::SeqCst}, + Arc, +}; +use crate::sys::mutex::Mutex; +use crate::sys::{ffi::*, stack_overflow, thread_local_dtor}; +use crate::time::Duration; + +const PENDING: u8 = 0; +const RUNNING: u8 = 1; +const DETACHED: u8 = 2; +const EXITED: u8 = 3; + +pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; + +pub struct Thread { + id: TaskHandle_t, + join_mutex: Arc, + state: Arc, +} + +unsafe impl Send for Thread {} +unsafe impl Sync for Thread {} + +impl Thread { + // unsafe: see thread::Builder::spawn_unchecked for safety requirements + pub unsafe fn new( + name: Option<&CStr>, + stack: usize, + p: Box, + ) -> io::Result { + let join_mutex = Arc::new(Mutex::new()); + let state = Arc::new(AtomicU8::new(PENDING)); + + let arg = box (Arc::clone(&join_mutex), Arc::clone(&state), p); + + let name = name.unwrap_or_else(|| CStr::from_bytes_with_nul_unchecked(b"\0")); + + let mut thread = Thread { id: ptr::null_mut(), join_mutex, state }; + + let arg = Box::into_raw(arg); + + let res = xTaskCreate( + thread_start, + name.as_ptr(), + stack as u32, + arg as *mut libc::c_void, + 5, + &mut thread.id, + ); + + if res != pdTRUE { + drop(Box::from_raw(arg)); + + if res == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY { + return Err(io::Error::new( + io::ErrorKind::Other, + "could not allocate required memory for thread", + )); + } else { + return Err(io::ErrorKind::WouldBlock.into()); + } + } + + return Ok(thread); + + extern "C" fn thread_start(arg: *mut libc::c_void) -> *mut libc::c_void { + unsafe { + let previous_state = { + let _handler = stack_overflow::Handler::new(); + + let (join_mutex, state, main) = + *Box::from_raw(arg as *mut (Arc, Arc, Box)); + + join_mutex.lock(); + state.compare_and_swap(PENDING, RUNNING, SeqCst); + + main(); + thread_local_dtor::run_dtors(); + + let previous_state = state.compare_and_swap(RUNNING, EXITED, SeqCst); + + join_mutex.unlock(); + + previous_state + }; + + if previous_state == DETACHED { + drop(previous_state); + vTaskDelete(ptr::null_mut()); + } else { + drop(previous_state); + vTaskSuspend(ptr::null_mut()); + } + } + + ptr::null_mut() + } + } + + pub fn yield_now() { + unsafe { vTaskDelay(0) }; + } + + pub fn sleep(dur: Duration) { + use crate::cmp; + + let nanos = dur.as_nanos(); + + if nanos == 0 { + return; + } + + let millis; + + #[cfg(target_arch = "xtensa")] + { + extern "C" { + fn ets_delay_us(us: u32); + } + + let mut micros = cmp::max(1_000, nanos) / 1_000; + let amt = micros % 1_000; + + if amt > 0 { + micros -= amt; + unsafe { ets_delay_us(amt as u32) }; + } + + if micros == 0 { + return; + } + + millis = cmp::max(1_000, micros) / 1_000; + } + + #[cfg(not(target_arch = "xtensa"))] + { + millis = cmp::max(1_000_000, nanos) / 1_000_000; + } + + let tick_rate = unsafe { xPortGetTickRateHz() } as u128; + let ms_per_tick = 1000 / tick_rate; + let mut ticks_to_delay = (millis + ms_per_tick - 1) / ms_per_tick; + + while ticks_to_delay > 0 { + let amt = cmp::min(u32::max_value() as u128, ticks_to_delay); + ticks_to_delay -= amt; + unsafe { vTaskDelay(amt as u32) }; + } + } + + pub fn join(self) { + unsafe { + assert!(self.id != xTaskGetCurrentTaskHandle()); + + while self.state.load(SeqCst) == PENDING { + Self::yield_now() + } + + // Just wait for the thread to finish, the rest is handled by `Drop`. + self.join_mutex.lock(); + self.join_mutex.unlock(); + } + } + + pub fn id(&self) -> TaskHandle_t { + self.id + } + + pub fn into_id(self) -> TaskHandle_t { + let id = self.id; + mem::forget(self); + id + } +} + +impl Drop for Thread { + fn drop(&mut self) { + // If the thread already exited before we could set the state to `DETACHED`, delete it manually here. + if self.state.swap(DETACHED, SeqCst) == EXITED { + unsafe { + vTaskDelete(self.id); + } + } + } +} + +#[cfg_attr(test, allow(dead_code))] +pub mod guard { + use crate::ops::Range; + pub type Guard = Range; + pub unsafe fn current() -> Option { + None + } + pub unsafe fn init() -> Option { + None + } +} diff --git a/library/std/src/sys/unix/freertos/thread_local.rs b/library/std/src/sys/unix/freertos/thread_local.rs new file mode 100644 index 0000000000000..27b17be282f2d --- /dev/null +++ b/library/std/src/sys/unix/freertos/thread_local.rs @@ -0,0 +1,22 @@ +use crate::collections::{BTreeMap, LinkedList}; +use crate::ptr; +use crate::sys::ffi::*; +use crate::sys_common::rwlock::RWLock; + +pub type Key = usize; +pub type Tls = BTreeMap; + +const TLS_INDEX: BaseType_t = 1; + +pub static LOCK: RWLock = RWLock::new(); +pub static mut KEYS: LinkedList<(Key, Option)> = LinkedList::new(); + +#[inline] +pub unsafe fn get_tls() -> *mut Tls { + pvTaskGetThreadLocalStoragePointer(ptr::null_mut(), TLS_INDEX) as *mut Tls +} + +#[inline] +pub unsafe fn set_tls(tls: *mut Tls) { + vTaskSetThreadLocalStoragePointer(ptr::null_mut(), TLS_INDEX, tls as *mut _); +} diff --git a/library/std/src/sys/unix/freertos/thread_local_dtor.rs b/library/std/src/sys/unix/freertos/thread_local_dtor.rs new file mode 100644 index 0000000000000..0931902ad1def --- /dev/null +++ b/library/std/src/sys/unix/freertos/thread_local_dtor.rs @@ -0,0 +1,24 @@ +use crate::ptr; + +mod thread_local; +use thread_local::{LOCK, KEYS, get_tls, set_tls}; + +#[inline] +pub unsafe fn run_dtors() { + if let Some(tls) = get_tls().as_mut() { + let tls = Box::from_raw(tls); + + LOCK.read(); + + for (k, dtor) in KEYS.iter() { + if let (Some(v), Some(dtor)) = (tls.get(k), dtor) { + dtor(*v) + } + } + + LOCK.read_unlock(); + + set_tls(ptr::null_mut()); + } +} + diff --git a/library/std/src/sys/unix/freertos/thread_local_key.rs b/library/std/src/sys/unix/freertos/thread_local_key.rs new file mode 100644 index 0000000000000..898026b05323b --- /dev/null +++ b/library/std/src/sys/unix/freertos/thread_local_key.rs @@ -0,0 +1,92 @@ +use crate::ptr; + +mod thread_local; +use thread_local::{get_tls, set_tls, Tls, KEYS, LOCK}; + +pub use thread_local::Key; + +#[inline] +pub unsafe fn create(dtor: Option) -> Key { + LOCK.write(); + + let key = KEYS.back().map(|&(i, _)| i + 1).unwrap_or(1); + KEYS.push_back((key, dtor)); + + LOCK.write_unlock(); + + key +} + +#[inline] +pub unsafe fn set(key: Key, value: *mut u8) { + #[cfg(debug_assertions)] + { + LOCK.read(); + + let mut found = false; + + for &(k, _) in KEYS.iter() { + if k == key { + found = true; + break; + } + } + + assert!(found); + + LOCK.read_unlock(); + } + + let tls = if let Some(tls) = get_tls().as_mut() { + tls + } else { + let tls = Box::into_raw(box Tls::new()); + set_tls(tls); + &mut *tls + }; + + if value.is_null() { + tls.remove(&key); + } else { + tls.insert(key, value); + } +} + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { + if let Some(tls) = get_tls().as_mut() { + tls.get(&key).cloned().unwrap_or_else(ptr::null_mut) + } else { + ptr::null_mut() + } +} + +#[inline] +pub unsafe fn destroy(key: Key) { + LOCK.write(); + + let mut i = 0; + let mut found = false; + + for &(k, _) in KEYS.iter() { + if k == key { + found = true; + break; + } + + i += 1; + } + + debug_assert!(found); + + if found { + KEYS.remove(i); + } + + LOCK.write_unlock(); +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index d1b0ad9e5f847..264a6d05fdc4a 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -295,7 +295,31 @@ impl FileAttr { } } -#[cfg(not(target_os = "netbsd"))] +#[cfg(target_env = "newlib")] +impl FileAttr { + pub fn modified(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_mtime as libc::time_t, + tv_nsec: 0, + })) + } + + pub fn accessed(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_atime as libc::time_t, + tv_nsec: 0, + })) + } + + pub fn created(&self) -> io::Result { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_ctime as libc::time_t, + tv_nsec: 0, + })) + } +} + +#[cfg(not(any(target_os = "netbsd", target_env = "newlib")))] impl FileAttr { #[cfg(not(target_os = "vxworks"))] pub fn modified(&self) -> io::Result { @@ -587,6 +611,7 @@ impl DirEntry { target_os = "ios", target_os = "linux", target_os = "emscripten", + target_os = "freertos", target_os = "android", target_os = "solaris", target_os = "illumos", @@ -631,6 +656,7 @@ impl DirEntry { target_os = "android", target_os = "linux", target_os = "emscripten", + target_os = "freertos", target_os = "l4re", target_os = "haiku", target_os = "vxworks" diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index f8a5ee8996911..273c492ee4e44 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -13,6 +13,8 @@ pub use crate::os::dragonfly as platform; pub use crate::os::emscripten as platform; #[cfg(all(not(doc), target_os = "freebsd"))] pub use crate::os::freebsd as platform; +#[cfg(all(not(doc), target_os = "freertos"))] +pub use crate::os::freertos as platform; #[cfg(all(not(doc), target_os = "fuchsia"))] pub use crate::os::fuchsia as platform; #[cfg(all(not(doc), target_os = "haiku"))] @@ -37,6 +39,7 @@ pub use crate::os::solaris as platform; pub use self::rand::hashmap_random_keys; pub use libc::strlen; +#[cfg(not(target_os = "freertos"))] #[macro_use] pub mod weak; @@ -44,6 +47,7 @@ pub mod alloc; pub mod android; pub mod args; pub mod cmath; +#[cfg_attr(target_os = "freertos", path = "freertos/condvar.rs")] pub mod condvar; pub mod env; pub mod ext; @@ -56,24 +60,34 @@ pub mod kernel_copy; #[cfg(target_os = "l4re")] mod l4re; pub mod memchr; +#[cfg_attr(target_os = "freertos", path = "freertos/mutex.rs")] pub mod mutex; #[cfg(not(target_os = "l4re"))] pub mod net; #[cfg(target_os = "l4re")] pub use self::l4re::net; +pub mod net_fd; pub mod os; pub mod path; pub mod pipe; pub mod process; pub mod rand; +#[cfg_attr(target_os = "freertos", path = "../wasm/rwlock_atomics.rs")] pub mod rwlock; pub mod stack_overflow; pub mod stdio; +#[cfg_attr(target_os = "freertos", path = "freertos/thread.rs")] pub mod thread; +#[cfg_attr(target_os = "freertos", path = "freertos/thread_local_dtor.rs")] pub mod thread_local_dtor; +#[cfg_attr(target_os = "freertos", path = "freertos/thread_local_key.rs")] pub mod thread_local_key; pub mod time; +#[cfg(target_os = "freertos")] +#[path = "freertos/ffi.rs"] +pub mod ffi; + pub use crate::sys_common::os_str_bytes as os_str; #[cfg(not(test))] @@ -97,8 +111,8 @@ pub fn init() { } cfg_if::cfg_if! { - if #[cfg(miri)] { - // The standard fds are always available in Miri. + if #[cfg(any(target_os = "miri", target_os = "freertos"))] { + // The standard fds are always available in Miri and FreeRTOS. unsafe fn sanitize_standard_fds() {} } else if #[cfg(not(any( target_os = "emscripten", @@ -152,14 +166,25 @@ pub fn init() { } } - #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "freertos")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } - #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))] + #[cfg(any(target_os = "emscripten", target_os = "fuchsia", target_os = "freertos"))] unsafe fn reset_sigpipe() {} } +/// This function is used to implement functionality that simply doesn't exist. +/// Programs relying on this functionality will need to deal with the error. +#[allow(unused)] +pub fn unsupported() -> crate::io::Result { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> crate::io::Error { + crate::io::Error::new(ErrorKind::Other, "operation not supported") +} + #[cfg(target_os = "android")] pub use crate::sys::android::signal; #[cfg(not(target_os = "android"))] @@ -190,6 +215,11 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } +// This enum is used as the storage for a bunch of types which can't actually +// exist. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] +pub enum Void {} + #[doc(hidden)] pub trait IsMinusOne { fn is_minus_one(&self) -> bool; diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 7198a2f08d668..bfd3abffd1719 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -1,24 +1,73 @@ use crate::cmp; -use crate::ffi::CStr; use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; -use crate::str; -use crate::sys::fd::FileDesc; +use crate::sys::net_fd::NetFileDesc; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::{Duration, Instant}; -use libc::{c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; +use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK}; pub use crate::sys::{cvt, cvt_r}; -#[allow(unused_extern_crates)] -pub extern crate libc as netc; +pub mod netc { + pub use libc::*; + + #[cfg(target_os = "freertos")] + extern "C" { + #[link_name = "lwip_fcntl"] + pub fn fcntl(s: c_int, cmd: c_int, val: c_int) -> c_int; + #[link_name = "lwip_close"] + pub fn close(s: c_int) -> ssize_t; + #[link_name = "lwip_read"] + pub fn read(s: c_int, mem: *mut c_void, len: size_t) -> ssize_t; + #[link_name = "lwip_readv"] + pub fn readv(s: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t; + #[link_name = "lwip_write"] + pub fn write(s: c_int, dataptr: *const c_void, len: size_t) -> ssize_t; + #[link_name = "lwip_writev"] + pub fn writev(s: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t; + #[link_name = "lwip_accept"] + pub fn accept(s: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int; + #[link_name = "lwip_bind"] + pub fn bind(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + #[link_name = "lwip_connect"] + pub fn connect(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int; + #[link_name = "lwip_ioctl"] + pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; + #[link_name = "lwip_getaddrinfo"] + pub fn getaddrinfo(nodename: *const c_char, servname: *const c_char, hints: *const addrinfo, res: *mut *mut addrinfo) -> c_int; + #[link_name = "lwip_freeaddrinfo"] + pub fn freeaddrinfo(ai: *mut addrinfo); + #[link_name = "lwip_getsockname"] + pub fn getsockname(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + #[link_name = "lwip_getpeername"] + pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int; + #[link_name = "lwip_listen"] + pub fn listen(s: c_int, backlog: c_int) -> c_int; + #[link_name = "lwip_send"] + pub fn send(s: c_int, dataptr: *const c_void, size: size_t, flags: c_int) -> ssize_t; + #[link_name = "lwip_sendto"] + pub fn sendto(s: c_int, dataptr: *const c_void, size: size_t, flags: c_int, to: *const sockaddr, tolen: socklen_t) -> ssize_t; + #[link_name = "lwip_recv"] + pub fn recv(s: c_int, mem: *mut c_void, len: size_t, flags: c_int) -> ssize_t; + #[link_name = "lwip_recvfrom"] + pub fn recvfrom(s: c_int, mem: *mut c_void, len: size_t, flags: c_int, from: *mut sockaddr, fromlen: *mut socklen_t) -> ssize_t; + #[link_name = "lwip_getsockopt"] + pub fn getsockopt(s: c_int, level: c_int, optname: c_int, optval: *mut c_void, optlen: *mut socklen_t) -> c_int; + #[link_name = "lwip_setsockopt"] + pub fn setsockopt(s: c_int, level: c_int, optname: c_int, optval: *const c_void, optlen: socklen_t) -> c_int; + #[link_name = "lwip_shutdown"] + pub fn shutdown(s: c_int, how: c_int) -> c_int; + #[link_name = "lwip_socket"] + pub fn socket(domain: c_int, r#type: c_int, protocol: c_int) -> c_int; + } +} pub type wrlen_t = size_t; -pub struct Socket(FileDesc); +pub struct Socket(NetFileDesc); pub fn init() {} @@ -30,13 +79,22 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { // We may need to trigger a glibc workaround. See on_resolver_failure() for details. on_resolver_failure(); - if err == EAI_SYSTEM { - return Err(io::Error::last_os_error()); - } + #[cfg(target_os = "freertos")] + let detail = format!("error code {}", err); + + #[cfg(not(target_os = "freertos"))] + let detail = { + if err == netc::EAI_SYSTEM { + return Err(io::Error::last_os_error()); + } - let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned() + unsafe { + use crate::str; + use crate::ffi::CStr; + str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned() + } }; + Err(io::Error::new( io::ErrorKind::Other, &format!("failed to lookup address information: {}", detail)[..], @@ -46,8 +104,8 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { impl Socket { pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, }; Socket::new_raw(fam, ty) } @@ -67,18 +125,18 @@ impl Socket { // On platforms that support it we pass the SOCK_CLOEXEC // flag to atomically create the socket and set it as // CLOEXEC. On Linux this was added in 2.6.27. - let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?; - Ok(Socket(FileDesc::new(fd))) + let fd = cvt(netc::socket(fam, ty | netc::SOCK_CLOEXEC, 0))?; + Ok(Socket(NetFileDesc::new(fd))) } else { - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); + let fd = cvt(netc::socket(fam, ty, 0))?; + let fd = NetFileDesc::new(fd); fd.set_cloexec()?; let socket = Socket(fd); // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt` // flag to disable `SIGPIPE` emission on socket. #[cfg(target_vendor = "apple")] - setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + setsockopt(&socket, netc::SOL_SOCKET, netc::SO_NOSIGPIPE, 1)?; Ok(socket) } @@ -86,7 +144,7 @@ impl Socket { } } - #[cfg(not(target_os = "vxworks"))] + #[cfg(not(any(target_os = "freertos", target_os = "vxworks"))] pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; @@ -102,12 +160,12 @@ impl Socket { target_os = "opensbd", ))] { // Like above, set cloexec atomically - cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?; - Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1])))) + cvt(netc::socketpair(fam, ty | netc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?; + Ok((Socket(NetFileDesc::new(fds[0])), Socket(NetFileDesc::new(fds[1])))) } else { - cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; - let a = FileDesc::new(fds[0]); - let b = FileDesc::new(fds[1]); + cvt(netc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?; + let a = NetFileDesc::new(fds[0]); + let b = NetFileDesc::new(fds[1]); a.set_cloexec()?; b.set_cloexec()?; Ok((Socket(a), Socket(b))) @@ -125,18 +183,18 @@ impl Socket { self.set_nonblocking(true)?; let r = unsafe { let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) + cvt(netc::connect(self.0.raw(), addrp, len)) }; self.set_nonblocking(false)?; match r { Ok(_) => return Ok(()), // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} + Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} Err(e) => return Err(e), } - let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 }; + let mut pollfd = netc::pollfd { fd: self.0.raw(), events: netc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { return Err(io::Error::new( @@ -164,7 +222,7 @@ impl Socket { let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; - match unsafe { libc::poll(&mut pollfd, 1, timeout) } { + match unsafe { netc::poll(&mut pollfd, 1, timeout) } { -1 => { let err = io::Error::last_os_error(); if err.kind() != io::ErrorKind::Interrupted { @@ -175,7 +233,7 @@ impl Socket { _ => { // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look // for POLLHUP rather than read readiness - if pollfd.revents & libc::POLLHUP != 0 { + if pollfd.revents & netc::POLLHUP != 0 { let e = self.take_error()?.unwrap_or_else(|| { io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") }); @@ -203,19 +261,19 @@ impl Socket { target_os = "opensbd", ))] { let fd = cvt_r(|| unsafe { - libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) + netc::accept4(self.0.raw(), storage, len, netc::SOCK_CLOEXEC) })?; Ok(Socket(FileDesc::new(fd))) // While the Android kernel supports the syscall, // it is not included in all versions of Android's libc. } else if #[cfg(target_os = "android")] { let fd = cvt_r(|| unsafe { - libc::syscall(libc::SYS_accept4, self.0.raw(), storage, len, libc::SOCK_CLOEXEC) + netc::syscall(netc::SYS_accept4, self.0.raw(), storage, len, netc::SOCK_CLOEXEC) })?; - Ok(Socket(FileDesc::new(fd as c_int))) + Ok(Socket(NetFileDesc::new(fd as c_int))) } else { - let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; - let fd = FileDesc::new(fd); + let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?; + let fd = NetFileDesc::new(fd); fd.set_cloexec()?; Ok(Socket(fd)) } @@ -228,7 +286,7 @@ impl Socket { fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { let ret = cvt(unsafe { - libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) + netc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) })?; Ok(ret as usize) } @@ -255,11 +313,11 @@ impl Socket { buf: &mut [u8], flags: c_int, ) -> io::Result<(usize, SocketAddr)> { - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; + let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; let n = cvt(unsafe { - libc::recvfrom( + netc::recvfrom( self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), @@ -284,8 +342,8 @@ impl Socket { target_os = "netbsd", target_os = "openbsd", ))] - pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result { - let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?; + pub fn recv_msg(&self, msg: &mut netc::msghdr) -> io::Result { + let n = cvt(unsafe { netc::recvmsg(self.0.raw(), msg, netc::MSG_CMSG_CLOEXEC) })?; Ok(n as usize) } @@ -315,12 +373,12 @@ impl Socket { target_os = "netbsd", target_os = "openbsd", ))] - pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result { - let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?; + pub fn send_msg(&self, msg: &mut netc::msghdr) -> io::Result { + let n = cvt(unsafe { netc::sendmsg(self.0.raw(), msg, 0) })?; Ok(n as usize) } - pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { + pub fn set_timeout(&self, dur: Option, kind: netc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { @@ -330,27 +388,27 @@ impl Socket { )); } - let secs = if dur.as_secs() > libc::time_t::MAX as u64 { - libc::time_t::MAX + let secs = if dur.as_secs() > netc::time_t::MAX as u64 { + netc::time_t::MAX } else { - dur.as_secs() as libc::time_t + dur.as_secs() as netc::time_t }; - let mut timeout = libc::timeval { + let mut timeout = netc::timeval { tv_sec: secs, - tv_usec: dur.subsec_micros() as libc::suseconds_t, + tv_usec: dur.subsec_micros() as netc::suseconds_t, }; if timeout.tv_sec == 0 && timeout.tv_usec == 0 { timeout.tv_usec = 1; } timeout } - None => libc::timeval { tv_sec: 0, tv_usec: 0 }, + None => netc::timeval { tv_sec: 0, tv_usec: 0 }, }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) + setsockopt(self, netc::SOL_SOCKET, kind, timeout) } - pub fn timeout(&self, kind: libc::c_int) -> io::Result> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; + pub fn timeout(&self, kind: netc::c_int) -> io::Result> { + let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; if raw.tv_sec == 0 && raw.tv_usec == 0 { Ok(None) } else { @@ -362,49 +420,49 @@ impl Socket { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { - Shutdown::Write => libc::SHUT_WR, - Shutdown::Read => libc::SHUT_RD, - Shutdown::Both => libc::SHUT_RDWR, + Shutdown::Write => netc::SHUT_WR, + Shutdown::Read => netc::SHUT_RD, + Shutdown::Both => netc::SHUT_RDWR, }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; + cvt(unsafe { netc::shutdown(self.0.raw(), how) })?; Ok(()) } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) + setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) } pub fn nodelay(&self) -> io::Result { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; + let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; Ok(raw != 0) } #[cfg(any(target_os = "android", target_os = "linux",))] pub fn set_passcred(&self, passcred: bool) -> io::Result<()> { - setsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED, passcred as libc::c_int) + setsockopt(self, netc::SOL_SOCKET, netc::SO_PASSCRED, passcred as netc::c_int) } #[cfg(any(target_os = "android", target_os = "linux",))] pub fn passcred(&self) -> io::Result { - let passcred: libc::c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_PASSCRED)?; + let passcred: netc::c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_PASSCRED)?; Ok(passcred != 0) } #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop) + let mut nonblocking = nonblocking as netc::c_int; + cvt(unsafe { netc::ioctl(*self.as_inner(), netc::FIONBIO, &mut nonblocking) }).map(drop) } #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { // FIONBIO is inadequate for sockets on illumos/Solaris, so use the - // fcntl(F_[GS]ETFL)-based method provided by FileDesc instead. + // fcntl(F_[GS]ETFL)-based method provided by NetFileDesc instead. self.0.set_nonblocking(nonblocking) } pub fn take_error(&self) -> io::Result> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; + let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } } } @@ -417,7 +475,7 @@ impl AsInner for Socket { impl FromInner for Socket { fn from_inner(fd: c_int) -> Socket { - Socket(FileDesc::new(fd)) + Socket(NetFileDesc::new(fd)) } } @@ -450,7 +508,7 @@ fn on_resolver_failure() { // If the version fails to parse, we treat it the same as "not glibc". if let Some(version) = sys::os::glibc_version() { if version < (2, 26) { - unsafe { libc::res_init() }; + unsafe { netc::res_init() }; } } } diff --git a/library/std/src/sys/unix/net_fd.rs b/library/std/src/sys/unix/net_fd.rs new file mode 100644 index 0000000000000..31bda5d80e4d1 --- /dev/null +++ b/library/std/src/sys/unix/net_fd.rs @@ -0,0 +1,231 @@ +#![unstable(reason = "not public", issue = "none", feature = "net_fd")] + +use crate::cmp; +use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; +use crate::mem; +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sys::{ + cvt, + net::netc::{self, c_int, c_void, ssize_t}, +}; +use crate::sys_common::AsInner; + +#[derive(Debug)] +pub struct NetFileDesc { + fd: c_int, +} + +fn max_len() -> usize { + // The maximum read limit on most posix-like systems is `SSIZE_MAX`, + // with the man page quoting that if the count of bytes to read is + // greater than `SSIZE_MAX` the result is "unspecified". + // + // On macOS, however, apparently the 64-bit libc is either buggy or + // intentionally showing odd behavior by rejecting any read with a size + // larger than or equal to INT_MAX. To handle both of these the read + // size is capped on both platforms. + if cfg!(target_os = "macos") { + ::max_value() as usize - 1 + } else { + ::max_value() as usize + } +} + +impl NetFileDesc { + pub fn new(fd: c_int) -> NetFileDesc { + NetFileDesc { fd } + } + + pub fn raw(&self) -> c_int { + self.fd + } + + /// Extracts the actual file descriptor without closing it. + pub fn into_raw(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + let ret = cvt(unsafe { + netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len())) + })?; + Ok(ret as usize) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::readv( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + let mut me = self; + (&mut me).read_to_end(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + let ret = cvt(unsafe { + netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len())) + })?; + Ok(ret as usize) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + let ret = cvt(unsafe { + netc::writev( + self.fd, + bufs.as_ptr() as *const netc::iovec, + cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + ) + })?; + Ok(ret as usize) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + + #[cfg(target_os = "linux")] + pub fn get_cloexec(&self) -> io::Result { + unsafe { Ok((cvt(netc::fcntl(self.fd, netc::F_GETFD))? & netc::FD_CLOEXEC) != 0) } + } + + #[cfg(not(any( + target_env = "newlib", + target_os = "solaris", + target_os = "illumos", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "l4re", + target_os = "linux", + target_os = "haiku", + target_os = "redox" + )))] + pub fn set_cloexec(&self) -> io::Result<()> { + unsafe { + cvt(netc::ioctl(self.fd, netc::FIOCLEX))?; + Ok(()) + } + } + #[cfg(all( + any( + target_env = "newlib", + target_os = "solaris", + target_os = "illumos", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "l4re", + target_os = "linux", + target_os = "haiku", + target_os = "redox" + ), + not(target_os = "freertos") + ))] + pub fn set_cloexec(&self) -> io::Result<()> { + unsafe { + let previous = cvt(netc::fcntl(self.fd, netc::F_GETFD))?; + let new = previous | netc::FD_CLOEXEC; + if new != previous { + cvt(netc::fcntl(self.fd, netc::F_SETFD, new))?; + } + Ok(()) + } + } + + // Setting `FD_CLOEXEC` is not supported on FreeRTOS + // since there is no `exec` functionality. + #[cfg(target_os = "freertos")] + pub fn set_cloexec(&self) -> io::Result<()> { + Ok(()) + } + + pub fn duplicate(&self) -> io::Result { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // flag, however, isn't supported on older Linux kernels (earlier than + // 2.6.24). + // + // To detect this and ensure that CLOEXEC is still set, we + // follow a strategy similar to musl [1] where if passing + // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not + // supported (the third parameter, 0, is always valid), so we stop + // trying that. + // + // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to + // resolve so we at least compile this. + // + // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 + #[cfg(any(target_os = "android", target_os = "haiku"))] + use netc::F_DUPFD as F_DUPFD_CLOEXEC; + #[cfg(not(any(target_os = "android", target_os = "haiku")))] + use netc::F_DUPFD_CLOEXEC; + + let make_filedesc = |fd| { + let fd = NetFileDesc::new(fd); + fd.set_cloexec()?; + Ok(fd) + }; + static TRY_CLOEXEC: AtomicBool = AtomicBool::new(!cfg!(target_os = "android")); + let fd = self.raw(); + if TRY_CLOEXEC.load(Ordering::Relaxed) { + match cvt(unsafe { netc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) { + // We *still* call the `set_cloexec` method as apparently some + // linux kernel at some point stopped setting CLOEXEC even + // though it reported doing so on F_DUPFD_CLOEXEC. + Ok(fd) => { + return Ok(if cfg!(target_os = "linux") { + make_filedesc(fd)? + } else { + NetFileDesc::new(fd) + }); + } + Err(ref e) if e.raw_os_error() == Some(netc::EINVAL) => { + TRY_CLOEXEC.store(false, Ordering::Relaxed); + } + Err(e) => return Err(e), + } + } + cvt(unsafe { netc::fcntl(fd, netc::F_DUPFD, 0) }).and_then(make_filedesc) + } +} + +impl<'a> Read for &'a NetFileDesc { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + (**self).read(buf) + } + + #[inline] + unsafe fn initializer(&self) -> Initializer { + Initializer::nop() + } +} + +impl AsInner for NetFileDesc { + fn as_inner(&self) -> &c_int { + &self.fd + } +} + +impl Drop for NetFileDesc { + fn drop(&mut self) { + // Note that errors are ignored when closing a file descriptor. The + // reason for this is that if an error occurs we don't actually know if + // the file descriptor was closed or not, and if we retried (for + // something like EINTR), we might close another valid file descriptor + // opened after we closed ours. + let _ = unsafe { netc::close(self.fd) }; + } +} diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index d5e14bec76572..6d1fbe89b7262 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -73,7 +73,7 @@ pub fn errno() -> i32 { } /// Sets the platform-specific value of errno -#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! +#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "freertos"), not(target_os = "vxworks")))] // needed for readdir and syscall! #[allow(dead_code)] // but not all target cfgs actually end up using it pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } @@ -131,6 +131,12 @@ pub fn error_string(errno: i32) -> String { } } +#[cfg(target_os = "freertos")] +pub fn getcwd() -> io::Result { + crate::sys::unsupported() +} + +#[cfg(not(target_os = "freertos"))] pub fn getcwd() -> io::Result { let mut buf = Vec::with_capacity(512); loop { @@ -157,6 +163,12 @@ pub fn getcwd() -> io::Result { } } +#[cfg(target_os = "freertos")] +pub fn chdir(_p: &path::Path) -> io::Result<()> { + crate::sys::unsupported() +} + +#[cfg(not(target_os = "freertos"))] pub fn chdir(p: &path::Path) -> io::Result<()> { let p: &OsStr = p.as_ref(); let p = CString::new(p.as_bytes())?; @@ -443,7 +455,7 @@ pub fn current_exe() -> io::Result { crate::fs::read_to_string("sys:exe").map(PathBuf::from) } -#[cfg(any(target_os = "fuchsia", target_os = "l4re"))] +#[cfg(any(target_os = "fuchsia", target_os = "freertos", target_os = "l4re"))] pub fn current_exe() -> io::Result { use crate::io::ErrorKind; Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) @@ -570,6 +582,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { } } +#[cfg(not(target_os = "freertos"))] pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } } @@ -591,6 +604,7 @@ pub fn home_dir() -> Option { target_os = "android", target_os = "ios", target_os = "emscripten", + target_os = "freertos", target_os = "redox", target_os = "vxworks" ))] @@ -601,6 +615,7 @@ pub fn home_dir() -> Option { target_os = "android", target_os = "ios", target_os = "emscripten", + target_os = "freertos", target_os = "redox", target_os = "vxworks" )))] diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index 7ae37bdda70bd..ef362ed24ade7 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -1,7 +1,7 @@ use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::sys::fd::FileDesc; -use crate::sys::{cvt, cvt_r}; +use crate::sys::cvt_r; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -9,7 +9,14 @@ use crate::sys::{cvt, cvt_r}; pub struct AnonPipe(FileDesc); +#[cfg(target_os = "freertos")] pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + crate::sys::unsupported() +} + +#[cfg(not(target_os = "freertos"))] +pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + use crate::sys::cvt; let mut fds = [0; 2]; // The only known way right now to create atomically set the CLOEXEC flag is diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 1b7b93f9d4a5f..e7e5bfe62c3a9 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -4,9 +4,12 @@ pub use crate::ffi::OsString as EnvKey; pub use crate::sys_common::process::CommandEnvs; mod process_common; -#[cfg(not(target_os = "fuchsia"))] +#[cfg(not(any(target_os = "freertos", target_os = "fuchsia")))] #[path = "process_unix.rs"] mod process_inner; +#[cfg(target_os = "freertos")] +#[path = "process_freertos.rs"] +mod process_inner; #[cfg(target_os = "fuchsia")] #[path = "process_fuchsia.rs"] mod process_inner; diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 372e5e6a5b367..a65fe6f16719f 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -20,7 +20,7 @@ use crate::sys::fs::OpenOptions; use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS}; cfg_if::cfg_if! { - if #[cfg(target_os = "fuchsia")] { + if #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { const DEV_NULL: &str = "null:\0"; @@ -123,7 +123,7 @@ pub enum ChildStdio { // On Fuchsia, null stdio is the default, so we simply don't specify // any actions at the time of spawning. - #[cfg(target_os = "fuchsia")] + #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] Null, } @@ -363,7 +363,7 @@ impl Stdio { Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) } - #[cfg(not(target_os = "fuchsia"))] + #[cfg(not(any(target_os = "freertos", target_os = "fuchsia")))] Stdio::Null => { let mut opts = OpenOptions::new(); opts.read(readable); @@ -373,7 +373,7 @@ impl Stdio { Ok((ChildStdio::Owned(fd.into_fd()), None)) } - #[cfg(target_os = "fuchsia")] + #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] Stdio::Null => Ok((ChildStdio::Null, None)), } } @@ -398,7 +398,7 @@ impl ChildStdio { ChildStdio::Explicit(fd) => Some(fd), ChildStdio::Owned(ref fd) => Some(fd.raw()), - #[cfg(target_os = "fuchsia")] + #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] ChildStdio::Null => None, } } diff --git a/library/std/src/sys/unix/process/process_freertos.rs b/library/std/src/sys/unix/process/process_freertos.rs new file mode 100644 index 0000000000000..cfa10a5278ef1 --- /dev/null +++ b/library/std/src/sys/unix/process/process_freertos.rs @@ -0,0 +1,78 @@ +use crate::fmt; +use crate::io; +use crate::sys::process::process_common::*; +use crate::sys::{unsupported, unsupported_err, Void}; + +use libc::c_int; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +impl Command { + pub fn spawn( + &mut self, + _default: Stdio, + _needs_stdin: bool, + ) -> io::Result<(Process, StdioPipes)> { + unsupported() + } + + pub fn exec(&mut self, _default: Stdio) -> io::Error { + unsupported_err() + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Processes +//////////////////////////////////////////////////////////////////////////////// + +/// The unique ID of the process (this should never be negative). +pub struct Process(Void); + +impl Process { + pub fn id(&self) -> u32 { + match self.0 {} + } + + pub fn kill(&mut self) -> io::Result<()> { + match self.0 {} + } + + pub fn wait(&mut self) -> io::Result { + match self.0 {} + } + + pub fn try_wait(&mut self) -> io::Result> { + match self.0 {} + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(Void); + +impl ExitStatus { + pub fn success(&self) -> bool { + match self.0 {} + } + + pub fn code(&self) -> Option { + match self.0 {} + } + + pub fn signal(&self) -> Option { + match self.0 {} + } +} + +impl From for ExitStatus { + fn from(_a: c_int) -> ExitStatus { + unimplemented!() + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.0 {} + } +} diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index a590c74435639..3ec286a519d99 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -17,12 +17,22 @@ use libc::{c_int, gid_t, pid_t, uid_t}; //////////////////////////////////////////////////////////////////////////////// impl Command { + #[cfg(target_os = "freertos")] pub fn spawn( &mut self, default: Stdio, needs_stdin: bool, ) -> io::Result<(Process, StdioPipes)> { - const CLOEXEC_MSG_FOOTER: [u8; 4] = *b"NOEX"; + crate::sys::unsupported() + } + + #[cfg(not(target_os = "freertos"))] + pub fn spawn( + &mut self, + default: Stdio, + needs_stdin: bool, + ) -> io::Result<(Process, StdioPipes)> { + const CLOEXEC_MSG_FOOTER: &[u8] = b"NOEX"; let envp = self.capture_env(); @@ -164,6 +174,16 @@ impl Command { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke libc::exit) + #[cfg(target_os = "freertos")] + unsafe fn do_exec( + &mut self, + stdio: ChildPipes, + maybe_envp: Option<&CStringArray> + ) -> Result { + crate::sys::unsupported() + } + + #[cfg(not(target_os = "freertos"))] unsafe fn do_exec( &mut self, stdio: ChildPipes, diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index a05fe8165cff2..8267850abe684 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] + use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::sys::fd::FileDesc; @@ -17,10 +19,12 @@ impl io::Read for Stdin { ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read(buf) } + #[cfg(not(all(target_os = "freertos", target_arch = "xtensa")))] fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs) } + #[cfg(not(all(target_os = "freertos", target_arch = "xtensa")))] #[inline] fn is_read_vectored(&self) -> bool { true @@ -38,10 +42,12 @@ impl io::Write for Stdout { ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write(buf) } + #[cfg(not(all(target_os = "freertos", target_arch = "xtensa")))] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs) } + #[cfg(not(all(target_os = "freertos", target_arch = "xtensa")))] #[inline] fn is_write_vectored(&self) -> bool { true @@ -63,10 +69,12 @@ impl io::Write for Stderr { ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write(buf) } + #[cfg(not(all(target_os = "freertos", target_arch = "xtensa")))] fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs) } + #[cfg(not(all(target_os = "freertos", target_arch = "xtensa")))] #[inline] fn is_write_vectored(&self) -> bool { true diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index fac4b05ad0b5f..85b10de2cf54c 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -361,9 +361,9 @@ mod inner { } } - #[cfg(not(target_os = "dragonfly"))] + #[cfg(not(any(target_os = "dragonfly", target_os = "freertos")))] pub type clock_t = libc::c_int; - #[cfg(target_os = "dragonfly")] + #[cfg(any(target_os = "dragonfly", target_os = "freertos"))] pub type clock_t = libc::c_ulong; fn now(clock: clock_t) -> Timespec { diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs index 6c1bc0d839ad3..578005e068da9 100644 --- a/library/std/src/sys_common/alloc.rs +++ b/library/std/src/sys_common/alloc.rs @@ -16,7 +16,8 @@ use crate::ptr; target_arch = "asmjs", target_arch = "wasm32", target_arch = "hexagon", - target_arch = "riscv32" + target_arch = "riscv32", + target_arch = "xtensa" )))] pub const MIN_ALIGN: usize = 8; #[cfg(all(any( diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 5d65f960fcd39..a151d2f09f926 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -460,8 +460,11 @@ impl Builder { crate::io::set_output_capture(output_capture.clone()); let main = move || { - if let Some(name) = their_thread.cname() { - imp::Thread::set_name(name); + #[cfg(not(target_os = "freertos"))] + { + if let Some(name) = their_thread.cname() { + imp::Thread::set_name(name); + } } crate::io::set_output_capture(output_capture); @@ -496,6 +499,8 @@ impl Builder { // returning. native: unsafe { Some(imp::Thread::new( + #[cfg(target_os = "freertos")] + my_thread.cname(), stack_size, mem::transmute::, Box>( Box::new(main), diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index ff1d82fc99040..834cba4a6f6f1 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -63,6 +63,9 @@ pub const unwinder_private_data_size: usize = 20; #[cfg(all(target_arch = "hexagon", target_os = "linux"))] pub const unwinder_private_data_size: usize = 35; +#[cfg(target_arch = "xtensa")] +pub const unwinder_private_data_size: usize = 2; + #[repr(C)] pub struct _Unwind_Exception { pub exception_class: _Unwind_Exception_Class, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 2f169d1d3f3a5..1d9c58e3548ea 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -479,6 +479,7 @@ impl<'a> fmt::Display for Display<'a> { "dragonfly" => "DragonFly BSD", "emscripten" => "Emscripten", "freebsd" => "FreeBSD", + "freertos" => "FreeRTOS", "fuchsia" => "Fuchsia", "haiku" => "Haiku", "hermit" => "HermitCore", From 68c96264a0b87efa7cc7379c8ece1b7760f85d13 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 5 Mar 2021 13:49:44 +0100 Subject: [PATCH 56/73] Delete `ext/net.rs`. --- library/std/src/sys/unix/ext/net.rs | 1768 --------------------------- 1 file changed, 1768 deletions(-) delete mode 100644 library/std/src/sys/unix/ext/net.rs diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs deleted file mode 100644 index 432417bf1d6c8..0000000000000 --- a/library/std/src/sys/unix/ext/net.rs +++ /dev/null @@ -1,1768 +0,0 @@ -//! Unix-specific networking functionality. - -#![stable(feature = "unix_socket", since = "1.10.0")] - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests; - -// FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? -#[cfg(not(unix))] -#[allow(non_camel_case_types)] -mod libc { - pub use libc::c_int; - pub type socklen_t = u32; - pub struct sockaddr; - #[derive(Clone)] - pub struct sockaddr_un; -} - -use crate::ascii; -use crate::ffi::OsStr; -use crate::fmt; -use crate::io::{self, Initializer, IoSlice, IoSliceMut}; -use crate::mem; -use crate::net::{self, Shutdown}; -use crate::os::unix::ffi::OsStrExt; -use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::path::Path; -use crate::sys::{self, cvt}; -use crate::sys::net::{netc, Socket}; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; -use crate::time::Duration; - -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -use crate::os::unix::ucred; - -#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] -#[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" -))] -pub use ucred::UCred; - -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -))] -use libc::MSG_NOSIGNAL; -#[cfg(not(any( - target_os = "linux", - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "haiku" -)))] -const MSG_NOSIGNAL: libc::c_int = 0x0; - -fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = addr as *const _ as usize; - let path = &addr.sun_path as *const _ as usize; - path - base -} - -unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { - let mut addr: libc::sockaddr_un = mem::zeroed(); - addr.sun_family = libc::AF_UNIX as libc::sa_family_t; - - let bytes = path.as_os_str().as_bytes(); - - if bytes.contains(&0) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "paths may not contain interior null bytes", - )); - } - - if bytes.len() >= addr.sun_path.len() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "path must be shorter than SUN_LEN", - )); - } - for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { - *dst = *src as libc::c_char; - } - // null byte for pathname addresses is already there because we zeroed the - // struct - - let mut len = sun_path_offset(&addr) + bytes.len(); - match bytes.get(0) { - Some(&0) | None => {} - Some(_) => len += 1, - } - Ok((addr, len as libc::socklen_t)) -} - -enum AddressKind<'a> { - Unnamed, - Pathname(&'a Path), - Abstract(&'a [u8]), -} - -/// An address associated with a Unix socket. -/// -/// # Examples -/// -/// ``` -/// use std::os::unix::net::UnixListener; -/// -/// let socket = match UnixListener::bind("/tmp/sock") { -/// Ok(sock) => sock, -/// Err(e) => { -/// println!("Couldn't bind: {:?}", e); -/// return -/// } -/// }; -/// let addr = socket.local_addr().expect("Couldn't get local address"); -/// ``` -#[derive(Clone)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct SocketAddr { - addr: libc::sockaddr_un, - len: libc::socklen_t, -} - -impl SocketAddr { - fn new(f: F) -> io::Result - where - F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, - { - unsafe { - let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; - SocketAddr::from_parts(addr, len) - } - } - - fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result { - if len == 0 { - // When there is a datagram from unnamed unix socket - // linux returns zero bytes of address - len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address - } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "file descriptor did not correspond to a Unix socket", - )); - } - - Ok(SocketAddr { addr, len }) - } - - /// Returns `true` if the address is unnamed. - /// - /// # Examples - /// - /// A named address: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), false); - /// Ok(()) - /// } - /// ``` - /// - /// An unnamed address: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.is_unnamed(), true); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn is_unnamed(&self) -> bool { - if let AddressKind::Unnamed = self.address() { true } else { false } - } - - /// Returns the contents of this address if it is a `pathname` address. - /// - /// # Examples - /// - /// With a pathname: - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// use std::path::Path; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixListener::bind("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock"))); - /// Ok(()) - /// } - /// ``` - /// - /// Without a pathname: - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// assert_eq!(addr.as_pathname(), None); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn as_pathname(&self) -> Option<&Path> { - if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } - } - - fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - sun_path_offset(&self.addr); - let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - - // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 - || (cfg!(not(any(target_os = "linux", target_os = "android"))) - && self.addr.sun_path[0] == 0) - { - AddressKind::Unnamed - } else if self.addr.sun_path[0] == 0 { - AddressKind::Abstract(&path[1..len]) - } else { - AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) - } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for SocketAddr { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.address() { - AddressKind::Unnamed => write!(fmt, "(unnamed)"), - AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), - } - } -} - -struct AsciiEscaped<'a>(&'a [u8]); - -impl<'a> fmt::Display for AsciiEscaped<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "\"")?; - for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { - write!(fmt, "{}", byte as char)?; - } - write!(fmt, "\"") - } -} - -/// A Unix stream socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixStream; -/// use std::io::prelude::*; -/// -/// fn main() -> std::io::Result<()> { -/// let mut stream = UnixStream::connect("/path/to/my/socket")?; -/// stream.write_all(b"hello world")?; -/// let mut response = String::new(); -/// stream.read_to_string(&mut response)?; -/// println!("{}", response); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixStream(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixStream { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixStream"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixStream { - /// Connects to the socket named by `path`. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let socket = match UnixStream::connect("/tmp/sock") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(netc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; - Ok(UnixStream(inner)) - } - } - inner(path.as_ref()) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixStream`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// let (sock1, sock2) = match UnixStream::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixStream, UnixStream)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; - Ok((UnixStream(i1), UnixStream(i2))) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixStream` is a reference to the same stream that this - /// object references. Both handles will read and write the same stream of - /// data, and options set on one stream will be propagated to the other - /// stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let sock_copy = socket.try_clone().expect("Couldn't clone socket"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixStream) - } - - /// Returns the socket address of the local half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { netc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the socket address of the remote half of this connection. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let addr = socket.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { netc::getpeername(*self.0.as_inner(), addr, len) }) - } - - /// Gets the peer credentials for this Unix domain socket. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(peer_credentials_unix_socket)] - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" - ))] - pub fn peer_cred(&self) -> io::Result { - ucred::peer_cred(self) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`read`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`write`] calls will block - /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is - /// passed to this method. - /// - /// [`read`]: io::Read::read - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::net::UdpSocket; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UdpSocket::bind("127.0.0.1:34254")?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout"); - /// assert_eq!(socket.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("Couldn't set write timeout"); - /// assert_eq!(socket.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.set_nonblocking(true).expect("Couldn't set nonblocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shuts down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixStream; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// socket.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixStream; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixStream::connect("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Read for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - io::Read::read(&mut &*self, buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - io::Read::read_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - io::Read::is_read_vectored(&&*self) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Read for &'a UnixStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl io::Write for UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - io::Write::write(&mut &*self, buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - io::Write::write_vectored(&mut &*self, bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - io::Write::is_write_vectored(&&*self) - } - - fn flush(&mut self) -> io::Result<()> { - io::Write::flush(&mut &*self) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> io::Write for &'a UnixStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixStream { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixStream { - unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { - UnixStream(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixStream { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} - -/// A structure representing a Unix domain socket server. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// // accept connections and process them, spawning a new thread for each one -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// /* connection succeeded */ -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// /* connection failed */ -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixListener(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixListener { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixListener"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - builder.finish() - } -} - -impl UnixListener { - /// Creates a new `UnixListener` bound to the specified socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// let listener = match UnixListener::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; - let (addr, len) = sockaddr_un(path)?; - - cvt(netc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; - cvt(netc::listen(*inner.as_inner(), 128))?; - - Ok(UnixListener(inner)) - } - } - inner(path.as_ref()) - } - - /// Accepts a new incoming connection to this listener. - /// - /// This function will block the calling thread until a new Unix connection - /// is established. When established, the corresponding [`UnixStream`] and - /// the remote peer's address will be returned. - /// - /// [`UnixStream`]: crate::os::unix::net::UnixStream - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { - let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; - let addr = SocketAddr::from_parts(storage, len)?; - Ok((UnixStream(sock), addr)) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixListener` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one listener will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let listener_copy = listener.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixListener) - } - - /// Returns the local socket address of this listener. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// let addr = listener.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { netc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// This will result in the `accept` operation becoming nonblocking, - /// i.e., immediately returning from their calls. If the IO operation is - /// successful, `Ok` is returned and no further action is required. If the - /// IO operation could not be completed and needs to be retried, an error - /// with kind [`io::ErrorKind::WouldBlock`] is returned. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// listener.set_nonblocking(true).expect("Couldn't set non blocking"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixListener; - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/tmp/sock")?; - /// - /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// # Platform specific - /// On Redox this always returns `None`. - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Returns an iterator over incoming connections. - /// - /// The iterator will never return [`None`] and will also not yield the - /// peer's [`SocketAddr`] structure. - /// - /// # Examples - /// - /// ```no_run - /// use std::thread; - /// use std::os::unix::net::{UnixStream, UnixListener}; - /// - /// fn handle_client(stream: UnixStream) { - /// // ... - /// } - /// - /// fn main() -> std::io::Result<()> { - /// let listener = UnixListener::bind("/path/to/the/socket")?; - /// - /// for stream in listener.incoming() { - /// match stream { - /// Ok(stream) => { - /// thread::spawn(|| handle_client(stream)); - /// } - /// Err(err) => { - /// break; - /// } - /// } - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn incoming(&self) -> Incoming<'_> { - Incoming { listener: self } - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixListener { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixListener { - unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { - UnixListener(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixListener { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> IntoIterator for &'a UnixListener { - type Item = io::Result; - type IntoIter = Incoming<'a>; - - fn into_iter(self) -> Incoming<'a> { - self.incoming() - } -} - -/// An iterator over incoming connections to a [`UnixListener`]. -/// -/// It will never return [`None`]. -/// -/// # Examples -/// -/// ```no_run -/// use std::thread; -/// use std::os::unix::net::{UnixStream, UnixListener}; -/// -/// fn handle_client(stream: UnixStream) { -/// // ... -/// } -/// -/// fn main() -> std::io::Result<()> { -/// let listener = UnixListener::bind("/path/to/the/socket")?; -/// -/// for stream in listener.incoming() { -/// match stream { -/// Ok(stream) => { -/// thread::spawn(|| handle_client(stream)); -/// } -/// Err(err) => { -/// break; -/// } -/// } -/// } -/// Ok(()) -/// } -/// ``` -#[derive(Debug)] -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct Incoming<'a> { - listener: &'a UnixListener, -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl<'a> Iterator for Incoming<'a> { - type Item = io::Result; - - fn next(&mut self) -> Option> { - Some(self.listener.accept().map(|s| s.0)) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::MAX, None) - } -} - -/// A Unix datagram socket. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::net::UnixDatagram; -/// -/// fn main() -> std::io::Result<()> { -/// let socket = UnixDatagram::bind("/path/to/my/socket")?; -/// socket.send_to(b"hello world", "/path/to/other/socket")?; -/// let mut buf = [0; 100]; -/// let (count, address) = socket.recv_from(&mut buf)?; -/// println!("socket {:?} sent {:?}", address, &buf[..count]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "unix_socket", since = "1.10.0")] -pub struct UnixDatagram(Socket); - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl fmt::Debug for UnixDatagram { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut builder = fmt.debug_struct("UnixDatagram"); - builder.field("fd", self.0.as_inner()); - if let Ok(addr) = self.local_addr() { - builder.field("local", &addr); - } - if let Ok(addr) = self.peer_addr() { - builder.field("peer", &addr); - } - builder.finish() - } -} - -impl UnixDatagram { - /// Creates a Unix datagram socket bound to the given path. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::bind("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't bind: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn bind>(path: P) -> io::Result { - fn inner(path: &Path) -> io::Result { - unsafe { - let socket = UnixDatagram::unbound()?; - let (addr, len) = sockaddr_un(path)?; - - cvt(netc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; - - Ok(socket) - } - } - inner(path.as_ref()) - } - - /// Creates a Unix Datagram socket which is not bound to any address. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let sock = match UnixDatagram::unbound() { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn unbound() -> io::Result { - let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok(UnixDatagram(inner)) - } - - /// Creates an unnamed pair of connected sockets. - /// - /// Returns two `UnixDatagrams`s which are connected to each other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// let (sock1, sock2) = match UnixDatagram::pair() { - /// Ok((sock1, sock2)) => (sock1, sock2), - /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); - /// return - /// } - /// }; - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { - let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; - Ok((UnixDatagram(i1), UnixDatagram(i2))) - } - - /// Connects the socket to the specified address. - /// - /// The [`send`] method may be used to send data to the specified address. - /// [`recv`] and [`recv_from`] will only receive data from that address. - /// - /// [`send`]: UnixDatagram::send - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// match sock.connect("/path/to/the/socket") { - /// Ok(sock) => sock, - /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); - /// return Err(e) - /// } - /// }; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn connect>(&self, path: P) -> io::Result<()> { - fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - cvt(netc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; - - Ok(()) - } - } - inner(self, path.as_ref()) - } - - /// Creates a new independently owned handle to the underlying socket. - /// - /// The returned `UnixDatagram` is a reference to the same socket that this - /// object references. Both handles can be used to accept incoming - /// connections and options set on one side will affect the other. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let sock_copy = sock.try_clone().expect("try_clone failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(UnixDatagram) - } - - /// Returns the address of this socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let addr = sock.local_addr().expect("Couldn't get local address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn local_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { netc::getsockname(*self.0.as_inner(), addr, len) }) - } - - /// Returns the address of this socket's peer. - /// - /// The [`connect`] method will connect the socket to a peer. - /// - /// [`connect`]: UnixDatagram::connect - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/path/to/the/socket")?; - /// - /// let addr = sock.peer_addr().expect("Couldn't get peer address"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn peer_addr(&self) -> io::Result { - SocketAddr::new(|addr, len| unsafe { netc::getpeername(*self.0.as_inner(), addr, len) }) - } - - fn recv_from_flags( - &self, - buf: &mut [u8], - flags: libc::c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = netc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - flags, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read and the address from - /// whence the data came. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// let mut buf = vec![0; 10]; - /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; - /// println!("received {} bytes from {:?}", size, sender); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, 0) - } - - /// Receives data from the socket. - /// - /// On success, returns the number of bytes read. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::bind("/path/to/the/socket")?; - /// let mut buf = vec![0; 10]; - /// sock.recv(buf.as_mut_slice()).expect("recv function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - /// Sends data on the socket to the specified address. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { - fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result { - unsafe { - let (addr, len) = sockaddr_un(path)?; - - let count = cvt(netc::sendto( - *d.0.as_inner(), - buf.as_ptr() as *const _, - buf.len(), - MSG_NOSIGNAL, - &addr as *const _ as *const _, - len, - ))?; - Ok(count as usize) - } - } - inner(self, buf, path.as_ref()) - } - - /// Sends data on the socket to the socket's peer. - /// - /// The peer address may be set by the `connect` method, and this method - /// will return an error if the socket has not already been connected. - /// - /// On success, returns the number of bytes written. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.connect("/some/sock").expect("Couldn't connect"); - /// sock.send(b"omelette au fromage").expect("send_to function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn send(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - /// Sets the read timeout for the socket. - /// - /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] - /// is passed to this method. - /// - /// [`recv`]: UnixDatagram::recv - /// [`recv_from`]: UnixDatagram::recv_from - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_RCVTIMEO) - } - - /// Sets the write timeout for the socket. - /// - /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will - /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method. - /// - /// [`send`]: UnixDatagram::send - /// [`send_to`]: UnixDatagram::send_to - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// Ok(()) - /// } - /// ``` - /// - /// An [`Err`] is returned if the zero [`Duration`] is passed to this - /// method: - /// - /// ```no_run - /// use std::io; - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::unbound()?; - /// let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - /// let err = result.unwrap_err(); - /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { - self.0.set_timeout(timeout, libc::SO_SNDTIMEO) - } - - /// Returns the read timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_read_timeout(Some(Duration::new(1, 0))) - /// .expect("set_read_timeout function failed"); - /// assert_eq!(sock.read_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn read_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_RCVTIMEO) - } - - /// Returns the write timeout of this socket. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// use std::time::Duration; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_write_timeout(Some(Duration::new(1, 0))) - /// .expect("set_write_timeout function failed"); - /// assert_eq!(sock.write_timeout()?, Some(Duration::new(1, 0))); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn write_timeout(&self) -> io::Result> { - self.0.timeout(libc::SO_SNDTIMEO) - } - - /// Moves the socket into or out of nonblocking mode. - /// - /// # Examples - /// - /// ``` - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.set_nonblocking(true).expect("set_nonblocking function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - self.0.set_nonblocking(nonblocking) - } - - /// Returns the value of the `SO_ERROR` option. - /// - /// # Examples - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn take_error(&self) -> io::Result> { - self.0.take_error() - } - - /// Shut down the read, write, or both halves of this connection. - /// - /// This function will cause all pending and future I/O calls on the - /// specified portions to immediately return with an appropriate value - /// (see the documentation of [`Shutdown`]). - /// - /// ```no_run - /// use std::os::unix::net::UnixDatagram; - /// use std::net::Shutdown; - /// - /// fn main() -> std::io::Result<()> { - /// let sock = UnixDatagram::unbound()?; - /// sock.shutdown(Shutdown::Both).expect("shutdown function failed"); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "unix_socket", since = "1.10.0")] - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - self.0.shutdown(how) - } - - /// Receives data on the socket from the remote address to which it is - /// connected, without removing that data from the queue. On success, - /// returns the number of bytes peeked. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recv` system call. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let len = socket.peek(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek(&self, buf: &mut [u8]) -> io::Result { - self.0.peek(buf) - } - - /// Receives a single datagram message on the socket, without removing it from the - /// queue. On success, returns the number of bytes read and the origin. - /// - /// The function must be called with valid byte array `buf` of sufficient size to - /// hold the message bytes. If a message is too long to fit in the supplied buffer, - /// excess bytes may be discarded. - /// - /// Successive calls return the same data. This is accomplished by passing - /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. - /// - /// Do not use this function to implement busy waiting, instead use `libc::poll` to - /// synchronize IO events on one or more sockets. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(unix_socket_peek)] - /// - /// use std::os::unix::net::UnixDatagram; - /// - /// fn main() -> std::io::Result<()> { - /// let socket = UnixDatagram::bind("/tmp/sock")?; - /// let mut buf = [0; 10]; - /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "unix_socket_peek", issue = "76923")] - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_flags(buf, libc::MSG_PEEK) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl AsRawFd for UnixDatagram { - fn as_raw_fd(&self) -> RawFd { - *self.0.as_inner() - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl FromRawFd for UnixDatagram { - unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { - UnixDatagram(Socket::from_inner(fd)) - } -} - -#[stable(feature = "unix_socket", since = "1.10.0")] -impl IntoRawFd for UnixDatagram { - fn into_raw_fd(self) -> RawFd { - self.0.into_inner() - } -} From bc4e16248613771966f1cae687f960d36b632eca Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 5 Mar 2021 15:36:05 +0100 Subject: [PATCH 57/73] Fix `net.rs`. --- library/std/src/sys/unix/net.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index bfd3abffd1719..ee55246010df8 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -144,7 +144,7 @@ impl Socket { } } - #[cfg(not(any(target_os = "freertos", target_os = "vxworks"))] + #[cfg(not(any(target_os = "freertos", target_os = "vxworks")))] pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; @@ -174,7 +174,7 @@ impl Socket { } } - #[cfg(target_os = "vxworks")] + #[cfg(any(target_os = "freertos", target_os = "vxworks"))] pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { unimplemented!() } @@ -263,7 +263,7 @@ impl Socket { let fd = cvt_r(|| unsafe { netc::accept4(self.0.raw(), storage, len, netc::SOCK_CLOEXEC) })?; - Ok(Socket(FileDesc::new(fd))) + Ok(Socket(NetFileDesc::new(fd))) // While the Android kernel supports the syscall, // it is not included in all versions of Android's libc. } else if #[cfg(target_os = "android")] { From f10b29380ed50e3db6d6a713f9c9d67ef93fd570 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 5 Mar 2021 15:55:07 +0100 Subject: [PATCH 58/73] Fix `target_family`. --- compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs | 6 +++--- compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs b/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs index 76911e402f019..71801e845b533 100644 --- a/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs +++ b/compiler/rustc_target/src/spec/xtensa_esp32_none_elf.rs @@ -6,12 +6,12 @@ pub fn target() -> Target { pointer_width: 32, data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32".to_string(), arch: "xtensa".to_string(), - + options: TargetOptions { endian: "little".to_string(), c_int_width: "32".to_string(), os: "freertos".to_string(), - target_family: Some("unix".to_string()), + os_family: Some("unix".to_string()), env: "newlib".to_string(), vendor: "espressif".to_string(), linker_flavor: LinkerFlavor::Gcc, @@ -46,4 +46,4 @@ pub fn target() -> Target { ..Default::default() }, } -} \ No newline at end of file +} diff --git a/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs b/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs index 02f48065f7100..8e7a9bc42ca47 100644 --- a/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs +++ b/compiler/rustc_target/src/spec/xtensa_esp8266_none_elf.rs @@ -6,12 +6,12 @@ pub fn target() -> Target { pointer_width: 32, data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32".to_string(), arch: "xtensa".to_string(), - + options: TargetOptions { endian: "little".to_string(), c_int_width: "32".to_string(), os: "freertos".to_string(), - target_family: Some("unix".to_string()), + os_family: Some("unix".to_string()), env: "newlib".to_string(), vendor: "espressif".to_string(), linker_flavor: LinkerFlavor::Gcc, @@ -46,4 +46,4 @@ pub fn target() -> Target { ..Default::default() }, } -} \ No newline at end of file +} From adee687cea948ce91e997f0706b4d2b35cd803e9 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Fri, 5 Mar 2021 19:17:10 +0100 Subject: [PATCH 59/73] Fix compilation. --- library/std/src/sys/unix/freertos/condvar.rs | 2 ++ library/std/src/sys/unix/freertos/mutex.rs | 26 +++++++++++--------- library/std/src/sys/unix/freertos/thread.rs | 7 ++++-- library/std/src/sys/unix/fs.rs | 4 +-- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/library/std/src/sys/unix/freertos/condvar.rs b/library/std/src/sys/unix/freertos/condvar.rs index 5011da4ae9662..b7835bdcb9b8c 100644 --- a/library/std/src/sys/unix/freertos/condvar.rs +++ b/library/std/src/sys/unix/freertos/condvar.rs @@ -10,6 +10,8 @@ pub struct Condvar { waiter_list: UnsafeCell>>, } +pub type MovableCondvar = Condvar; + unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} diff --git a/library/std/src/sys/unix/freertos/mutex.rs b/library/std/src/sys/unix/freertos/mutex.rs index 361296016c75b..2ee76a0c50a57 100644 --- a/library/std/src/sys/unix/freertos/mutex.rs +++ b/library/std/src/sys/unix/freertos/mutex.rs @@ -9,6 +9,8 @@ pub struct Mutex { initialized: AtomicU8, } +pub type MovableMutex = Mutex; + unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} @@ -31,14 +33,14 @@ impl Mutex { #[inline] unsafe fn atomic_init(&self) { loop { - match self.initialized.compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst) { - UNINITIALIZED => { + match self.initialized.compare_exchange_weak(UNINITIALIZED, INITIALIZING, SeqCst, SeqCst) { + Ok(UNINITIALIZED) => { *self.inner.get() = xSemaphoreCreateMutex(); debug_assert!(!(*self.inner.get()).is_null()); self.initialized.store(INITIALIZED, SeqCst); return; } - INITIALIZED => return, + Err(INITIALIZED) => return, _ => continue, } } @@ -67,14 +69,14 @@ impl Mutex { #[inline] pub unsafe fn destroy(&self) { loop { - match self.initialized.compare_and_swap(INITIALIZED, UNINITIALIZING, SeqCst) { - INITIALIZED => { + match self.initialized.compare_exchange_weak(INITIALIZED, UNINITIALIZING, SeqCst, SeqCst) { + Ok(INITIALIZED) => { vSemaphoreDelete(*self.inner.get()); *self.inner.get() = ptr::null_mut(); self.initialized.store(UNINITIALIZED, SeqCst); return; } - UNINITIALIZED => return, + Err(UNINITIALIZED) => return, _ => continue, } } @@ -111,14 +113,14 @@ impl ReentrantMutex { #[inline] unsafe fn atomic_init(&self) { loop { - match self.initialized.compare_and_swap(UNINITIALIZED, INITIALIZING, SeqCst) { - UNINITIALIZED => { + match self.initialized.compare_exchange_weak(UNINITIALIZED, INITIALIZING, SeqCst, SeqCst) { + Ok(UNINITIALIZED) => { *self.inner.get() = xSemaphoreCreateRecursiveMutex(); debug_assert!(!(*self.inner.get()).is_null()); self.initialized.store(INITIALIZED, SeqCst); return; } - INITIALIZED => return, + Err(INITIALIZED) => return, _ => continue, } } @@ -145,14 +147,14 @@ impl ReentrantMutex { pub unsafe fn destroy(&self) { loop { - match self.initialized.compare_and_swap(INITIALIZED, UNINITIALIZING, SeqCst) { - INITIALIZED => { + match self.initialized.compare_exchange_weak(INITIALIZED, UNINITIALIZING, SeqCst, SeqCst) { + Ok(INITIALIZED) => { vSemaphoreDelete(*self.inner.get()); *self.inner.get() = ptr::null_mut(); self.initialized.store(UNINITIALIZED, SeqCst); return; } - UNINITIALIZED => return, + Err(UNINITIALIZED) => return, _ => continue, } } diff --git a/library/std/src/sys/unix/freertos/thread.rs b/library/std/src/sys/unix/freertos/thread.rs index 9eed71d08479f..eb82d89c51a9d 100644 --- a/library/std/src/sys/unix/freertos/thread.rs +++ b/library/std/src/sys/unix/freertos/thread.rs @@ -77,12 +77,15 @@ impl Thread { *Box::from_raw(arg as *mut (Arc, Arc, Box)); join_mutex.lock(); - state.compare_and_swap(PENDING, RUNNING, SeqCst); + let _ = state.compare_exchange(PENDING, RUNNING, SeqCst, SeqCst); main(); thread_local_dtor::run_dtors(); - let previous_state = state.compare_and_swap(RUNNING, EXITED, SeqCst); + let previous_state = match state.compare_exchange(RUNNING, EXITED, SeqCst, SeqCst) { + Ok(v) => v, + Err(v) => v, + }; join_mutex.unlock(); diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 264a6d05fdc4a..3d2d27ca3bcd6 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1108,8 +1108,8 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { let original = cstr(original)?; let link = cstr(link)?; cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] { - // VxWorks, Redox, and old versions of Android lack `linkat`, so use + if #[cfg(any(target_os = "vxworks", target_os = "freertos", target_os = "redox", target_os = "android"))] { + // VxWorks, FreeRTOS, Redox, and old versions of Android lack `linkat`, so use // `link` instead. POSIX leaves it implementation-defined whether // `link` follows symlinks, so rely on the `symlink_hard_link` test // in library/std/src/fs/tests.rs to check the behavior. From 620c9d5204193b269aa5295f3be60dc71ed268ec Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 6 Mar 2021 15:47:25 +0100 Subject: [PATCH 60/73] `compare_exchange_weak` doesn't work. --- library/std/src/sys/unix/freertos/mutex.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/freertos/mutex.rs b/library/std/src/sys/unix/freertos/mutex.rs index 2ee76a0c50a57..58e8be88e789e 100644 --- a/library/std/src/sys/unix/freertos/mutex.rs +++ b/library/std/src/sys/unix/freertos/mutex.rs @@ -33,7 +33,7 @@ impl Mutex { #[inline] unsafe fn atomic_init(&self) { loop { - match self.initialized.compare_exchange_weak(UNINITIALIZED, INITIALIZING, SeqCst, SeqCst) { + match self.initialized.compare_exchange(UNINITIALIZED, INITIALIZING, SeqCst, SeqCst) { Ok(UNINITIALIZED) => { *self.inner.get() = xSemaphoreCreateMutex(); debug_assert!(!(*self.inner.get()).is_null()); @@ -69,7 +69,7 @@ impl Mutex { #[inline] pub unsafe fn destroy(&self) { loop { - match self.initialized.compare_exchange_weak(INITIALIZED, UNINITIALIZING, SeqCst, SeqCst) { + match self.initialized.compare_exchange(INITIALIZED, UNINITIALIZING, SeqCst, SeqCst) { Ok(INITIALIZED) => { vSemaphoreDelete(*self.inner.get()); *self.inner.get() = ptr::null_mut(); @@ -113,7 +113,7 @@ impl ReentrantMutex { #[inline] unsafe fn atomic_init(&self) { loop { - match self.initialized.compare_exchange_weak(UNINITIALIZED, INITIALIZING, SeqCst, SeqCst) { + match self.initialized.compare_exchange(UNINITIALIZED, INITIALIZING, SeqCst, SeqCst) { Ok(UNINITIALIZED) => { *self.inner.get() = xSemaphoreCreateRecursiveMutex(); debug_assert!(!(*self.inner.get()).is_null()); @@ -147,7 +147,7 @@ impl ReentrantMutex { pub unsafe fn destroy(&self) { loop { - match self.initialized.compare_exchange_weak(INITIALIZED, UNINITIALIZING, SeqCst, SeqCst) { + match self.initialized.compare_exchange(INITIALIZED, UNINITIALIZING, SeqCst, SeqCst) { Ok(INITIALIZED) => { vSemaphoreDelete(*self.inner.get()); *self.inner.get() = ptr::null_mut(); From 6686577bf4a83eecd07c1622dc9301b696c15783 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 6 Mar 2021 16:48:41 +0100 Subject: [PATCH 61/73] `memalign` is now implemented. --- library/std/src/sys/unix/alloc.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 4972a59305caf..1a1b4fa546f01 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -53,13 +53,9 @@ unsafe impl GlobalAlloc for System { } cfg_if::cfg_if! { - if #[cfg(target_os = "freertos")] { - #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - libc::malloc(layout.size()) as *mut u8 - } - } else if #[cfg(any( + if #[cfg(any( target_os = "android", + target_os = "freertos", target_os = "illumos", target_os = "redox", target_os = "solaris" From de64fd96b8277493968d3e447baaeb04296b5ca5 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 6 Mar 2021 20:36:21 +0100 Subject: [PATCH 62/73] Refactor `Condvar`. --- library/std/src/sys/unix/condvar.rs | 2 - library/std/src/sys/unix/freertos/condvar.rs | 65 +++++++++++--------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/library/std/src/sys/unix/condvar.rs b/library/std/src/sys/unix/condvar.rs index 907de0f133bb5..e38f91af9f0b9 100644 --- a/library/std/src/sys/unix/condvar.rs +++ b/library/std/src/sys/unix/condvar.rs @@ -30,7 +30,6 @@ impl Condvar { target_os = "ios", target_os = "l4re", target_os = "android", - target_os = "freertos", target_os = "redox" ))] pub unsafe fn init(&mut self) {} @@ -40,7 +39,6 @@ impl Condvar { target_os = "ios", target_os = "l4re", target_os = "android", - target_os = "freertos", target_os = "redox" )))] pub unsafe fn init(&mut self) { diff --git a/library/std/src/sys/unix/freertos/condvar.rs b/library/std/src/sys/unix/freertos/condvar.rs index b7835bdcb9b8c..c1377b5f134d1 100644 --- a/library/std/src/sys/unix/freertos/condvar.rs +++ b/library/std/src/sys/unix/freertos/condvar.rs @@ -17,8 +17,6 @@ unsafe impl Sync for Condvar {} impl Condvar { pub const fn new() -> Condvar { - // Might be moved and address is changing it is better to avoid - // initialization of potentially opaque OS data before it landed Condvar { lock: unsafe { ReentrantMutex::uninitialized() }, waiter_list: UnsafeCell::new(None), @@ -26,23 +24,20 @@ impl Condvar { } #[inline] - pub unsafe fn init(&mut self) {} - - #[inline] - unsafe fn init_waiter_list(&self) { - if (*self.waiter_list.get()).is_none() { - (*self.waiter_list.get()) = Some(VecDeque::new()); - } + pub unsafe fn init(&mut self) { + self.waiter_list.get_mut().replace(VecDeque::new()); } #[inline] pub unsafe fn notify_one(&self) { self.lock.lock(); - self.init_waiter_list(); - let waiter_list = (&*self.waiter_list.get()).as_ref().unwrap(); - if let Some(&waiter) = waiter_list.front() { - xSemaphoreGive(waiter); + if let Some(waiter_list) = (&*self.waiter_list.get()).as_ref() { + if let Some(&waiter) = waiter_list.front() { + xSemaphoreGive(waiter); + } + } else { + core::hint::unreachable_unchecked(); } self.lock.unlock(); @@ -52,10 +47,12 @@ impl Condvar { pub unsafe fn notify_all(&self) { self.lock.lock(); - self.init_waiter_list(); - let waiter_list = (&*self.waiter_list.get()).as_ref().unwrap(); - for &waiter in waiter_list { - xSemaphoreGive(waiter); + if let Some(waiter_list) = (&*self.waiter_list.get()).as_ref() { + for &waiter in waiter_list { + xSemaphoreGive(waiter); + } + } else { + core::hint::unreachable_unchecked(); } self.lock.unlock(); @@ -88,9 +85,11 @@ impl Condvar { self.lock.lock(); - self.init_waiter_list(); - let waiter_list = (&mut *self.waiter_list.get()).as_mut().unwrap(); - waiter_list.push_back(waiter); + if let Some(waiter_list) = (&mut *self.waiter_list.get()).as_mut() { + waiter_list.push_back(waiter); + } else { + core::hint::unreachable_unchecked(); + } self.lock.unlock(); @@ -104,18 +103,19 @@ impl Condvar { self.lock.lock(); - let waiter_list = (&mut *self.waiter_list.get()).as_mut().unwrap(); - let deleted_waiter = if let Some(index) = waiter_list.iter().position(|&w| w == waiter) { - waiter_list.remove(index) + if let Some(waiter_list) = (&mut *self.waiter_list.get()).as_mut() { + if let Some(index) = waiter_list.iter().position(|&w| w == waiter) { + waiter_list.remove(index); + } else { + core::hint::unreachable_unchecked(); + } } else { - None - }; + core::hint::unreachable_unchecked(); + } self.lock.unlock(); - if let Some(deleted_waiter) = deleted_waiter { - vSemaphoreDelete(deleted_waiter); - } + vSemaphoreDelete(waiter); mutex.lock(); @@ -128,12 +128,17 @@ impl Condvar { #[inline] pub unsafe fn destroy(&self) { + #[cfg(debug)] + { self.lock.lock(); - if let Some(waiter_list) = (&*self.waiter_list.get()).as_ref() { - assert!(waiter_list.is_empty()); + if let Some(waiter_list) = (&*self.waiter_list.get()).as_mut() { + debug_assert!(waiter_list.is_empty()); + } else { + core::hint::unreachable_unchecked(); } self.lock.unlock(); + } } } From 94bdeff4a6f4278382094dab7ea7a2a99bb46a16 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 6 Mar 2021 21:06:02 +0100 Subject: [PATCH 63/73] Simplify `process` stubs. --- library/std/src/sys/unix/ext/mod.rs | 2 + library/std/src/sys/unix/mod.rs | 3 + library/std/src/sys/unix/pipe.rs | 6 -- library/std/src/sys/unix/process/mod.rs | 5 +- .../src/sys/unix/process/process_common.rs | 10 +-- .../src/sys/unix/process/process_freertos.rs | 78 ------------------- .../std/src/sys/unix/process/process_unix.rs | 20 ----- 7 files changed, 11 insertions(+), 113 deletions(-) delete mode 100644 library/std/src/sys/unix/process/process_freertos.rs diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/sys/unix/ext/mod.rs index f43546880983a..655dd5564c910 100644 --- a/library/std/src/sys/unix/ext/mod.rs +++ b/library/std/src/sys/unix/ext/mod.rs @@ -33,6 +33,7 @@ pub mod ffi; pub mod fs; pub mod io; pub mod net; +#[cfg(not(target_os = "freertos"))] pub mod process; pub mod raw; pub mod thread; @@ -69,6 +70,7 @@ pub mod prelude { #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; + #[cfg(not(target_os = "freertos"))] #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::process::{CommandExt, ExitStatusExt}; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 273c492ee4e44..7a4dabb5fa44f 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -69,7 +69,9 @@ pub use self::l4re::net; pub mod net_fd; pub mod os; pub mod path; +#[cfg_attr(target_os = "freertos", path = "../unsupported/pipe.rs")] pub mod pipe; +#[cfg_attr(target_os = "freertos", path = "../unsupported/process.rs")] pub mod process; pub mod rand; #[cfg_attr(target_os = "freertos", path = "../wasm/rwlock_atomics.rs")] @@ -252,6 +254,7 @@ where } } +#[cfg(not(target_os = "freertos"))] pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } } diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index ef362ed24ade7..7d5d735826dae 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -9,12 +9,6 @@ use crate::sys::cvt_r; pub struct AnonPipe(FileDesc); -#[cfg(target_os = "freertos")] -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - crate::sys::unsupported() -} - -#[cfg(not(target_os = "freertos"))] pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { use crate::sys::cvt; let mut fds = [0; 2]; diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index e7e5bfe62c3a9..1b7b93f9d4a5f 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -4,12 +4,9 @@ pub use crate::ffi::OsString as EnvKey; pub use crate::sys_common::process::CommandEnvs; mod process_common; -#[cfg(not(any(target_os = "freertos", target_os = "fuchsia")))] +#[cfg(not(target_os = "fuchsia"))] #[path = "process_unix.rs"] mod process_inner; -#[cfg(target_os = "freertos")] -#[path = "process_freertos.rs"] -mod process_inner; #[cfg(target_os = "fuchsia")] #[path = "process_fuchsia.rs"] mod process_inner; diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index a65fe6f16719f..372e5e6a5b367 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -20,7 +20,7 @@ use crate::sys::fs::OpenOptions; use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS}; cfg_if::cfg_if! { - if #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] { + if #[cfg(target_os = "fuchsia")] { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { const DEV_NULL: &str = "null:\0"; @@ -123,7 +123,7 @@ pub enum ChildStdio { // On Fuchsia, null stdio is the default, so we simply don't specify // any actions at the time of spawning. - #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] + #[cfg(target_os = "fuchsia")] Null, } @@ -363,7 +363,7 @@ impl Stdio { Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) } - #[cfg(not(any(target_os = "freertos", target_os = "fuchsia")))] + #[cfg(not(target_os = "fuchsia"))] Stdio::Null => { let mut opts = OpenOptions::new(); opts.read(readable); @@ -373,7 +373,7 @@ impl Stdio { Ok((ChildStdio::Owned(fd.into_fd()), None)) } - #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] + #[cfg(target_os = "fuchsia")] Stdio::Null => Ok((ChildStdio::Null, None)), } } @@ -398,7 +398,7 @@ impl ChildStdio { ChildStdio::Explicit(fd) => Some(fd), ChildStdio::Owned(ref fd) => Some(fd.raw()), - #[cfg(any(target_os = "freertos", target_os = "fuchsia"))] + #[cfg(target_os = "fuchsia")] ChildStdio::Null => None, } } diff --git a/library/std/src/sys/unix/process/process_freertos.rs b/library/std/src/sys/unix/process/process_freertos.rs deleted file mode 100644 index cfa10a5278ef1..0000000000000 --- a/library/std/src/sys/unix/process/process_freertos.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::fmt; -use crate::io; -use crate::sys::process::process_common::*; -use crate::sys::{unsupported, unsupported_err, Void}; - -use libc::c_int; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -impl Command { - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } - - pub fn exec(&mut self, _default: Stdio) -> io::Error { - unsupported_err() - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Processes -//////////////////////////////////////////////////////////////////////////////// - -/// The unique ID of the process (this should never be negative). -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } - - pub fn signal(&self) -> Option { - match self.0 {} - } -} - -impl From for ExitStatus { - fn from(_a: c_int) -> ExitStatus { - unimplemented!() - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 3ec286a519d99..dc4ef45a11fab 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -17,16 +17,6 @@ use libc::{c_int, gid_t, pid_t, uid_t}; //////////////////////////////////////////////////////////////////////////////// impl Command { - #[cfg(target_os = "freertos")] - pub fn spawn( - &mut self, - default: Stdio, - needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - crate::sys::unsupported() - } - - #[cfg(not(target_os = "freertos"))] pub fn spawn( &mut self, default: Stdio, @@ -174,16 +164,6 @@ impl Command { // allocation). Instead we just close it manually. This will never // have the drop glue anyway because this code never returns (the // child will either exec() or invoke libc::exit) - #[cfg(target_os = "freertos")] - unsafe fn do_exec( - &mut self, - stdio: ChildPipes, - maybe_envp: Option<&CStringArray> - ) -> Result { - crate::sys::unsupported() - } - - #[cfg(not(target_os = "freertos"))] unsafe fn do_exec( &mut self, stdio: ChildPipes, From d0450091625b4a4afb30071e09b6a54b85278015 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 6 Mar 2021 21:33:33 +0100 Subject: [PATCH 64/73] Use `debug_assertions`. --- library/std/src/sys/unix/freertos/condvar.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/freertos/condvar.rs b/library/std/src/sys/unix/freertos/condvar.rs index c1377b5f134d1..8c879b68cd51e 100644 --- a/library/std/src/sys/unix/freertos/condvar.rs +++ b/library/std/src/sys/unix/freertos/condvar.rs @@ -128,12 +128,12 @@ impl Condvar { #[inline] pub unsafe fn destroy(&self) { - #[cfg(debug)] + #[cfg(debug_assertions)] { self.lock.lock(); if let Some(waiter_list) = (&*self.waiter_list.get()).as_mut() { - debug_assert!(waiter_list.is_empty()); + assert!(waiter_list.is_empty()); } else { core::hint::unreachable_unchecked(); } From b2c8c70eeb1e89e923d688f19c9a52fd30133d68 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 6 Mar 2021 22:18:49 +0100 Subject: [PATCH 65/73] Update `ned_fd`. --- library/std/src/sys/unix/net.rs | 2 +- library/std/src/sys/unix/net_fd.rs | 243 +++++++++++++++++++---------- 2 files changed, 160 insertions(+), 85 deletions(-) diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index ee55246010df8..16cba6d9414d9 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -17,7 +17,7 @@ pub mod netc { #[cfg(target_os = "freertos")] extern "C" { #[link_name = "lwip_fcntl"] - pub fn fcntl(s: c_int, cmd: c_int, val: c_int) -> c_int; + pub fn fcntl(s: c_int, cmd: c_int, ...) -> c_int; #[link_name = "lwip_close"] pub fn close(s: c_int) -> ssize_t; #[link_name = "lwip_read"] diff --git a/library/std/src/sys/unix/net_fd.rs b/library/std/src/sys/unix/net_fd.rs index 31bda5d80e4d1..ede527a1e41ef 100644 --- a/library/std/src/sys/unix/net_fd.rs +++ b/library/std/src/sys/unix/net_fd.rs @@ -3,37 +3,72 @@ use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; -use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::{ cvt, - net::netc::{self, c_int, c_void, ssize_t}, + net::netc::{self, c_int, c_void}, }; use crate::sys_common::AsInner; #[derive(Debug)] +#[rustc_layout_scalar_valid_range_start(0)] +// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a +// 32-bit c_int. Below is -2, in two's complement, but that only works out +// because c_int is 32 bits. +#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)] pub struct NetFileDesc { fd: c_int, } -fn max_len() -> usize { - // The maximum read limit on most posix-like systems is `SSIZE_MAX`, - // with the man page quoting that if the count of bytes to read is - // greater than `SSIZE_MAX` the result is "unspecified". - // - // On macOS, however, apparently the 64-bit libc is either buggy or - // intentionally showing odd behavior by rejecting any read with a size - // larger than or equal to INT_MAX. To handle both of these the read - // size is capped on both platforms. - if cfg!(target_os = "macos") { - ::max_value() as usize - 1 - } else { - ::max_value() as usize - } +// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, +// with the man page quoting that if the count of bytes to read is +// greater than `SSIZE_MAX` the result is "unspecified". +// +// On macOS, however, apparently the 64-bit libc is either buggy or +// intentionally showing odd behavior by rejecting any read with a size +// larger than or equal to INT_MAX. To handle both of these the read +// size is capped on both platforms. +#[cfg(target_os = "macos")] +const READ_LIMIT: usize = c_int::MAX as usize - 1; +#[cfg(not(target_os = "macos"))] +const READ_LIMIT: usize = netc::ssize_t::MAX as usize; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +const fn max_iov() -> usize { + netc::IOV_MAX as usize +} + +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] +const fn max_iov() -> usize { + netc::UIO_MAXIOV as usize +} + +#[cfg(not(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +)))] +const fn max_iov() -> usize { + 16 // The minimum value required by POSIX. } impl NetFileDesc { pub fn new(fd: c_int) -> NetFileDesc { - NetFileDesc { fd } + assert_ne!(fd, -1i32); + // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) + unsafe { NetFileDesc { fd } } } pub fn raw(&self) -> c_int { @@ -49,7 +84,7 @@ impl NetFileDesc { pub fn read(&self, buf: &mut [u8]) -> io::Result { let ret = cvt(unsafe { - netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len())) + netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) })?; Ok(ret as usize) } @@ -59,7 +94,7 @@ impl NetFileDesc { netc::readv( self.fd, bufs.as_ptr() as *const netc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), max_iov()) as c_int, ) })?; Ok(ret as usize) @@ -75,9 +110,38 @@ impl NetFileDesc { (&mut me).read_to_end(buf) } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + #[cfg(target_os = "android")] + use super::android::cvt_pread64; + + #[cfg(not(target_os = "android"))] + unsafe fn cvt_pread64( + fd: c_int, + buf: *mut c_void, + count: usize, + offset: i64, + ) -> io::Result { + #[cfg(not(target_os = "linux"))] + use netc::pread as pread64; + #[cfg(target_os = "linux")] + use netc::pread64; + cvt(pread64(fd, buf, count, offset)) + } + + unsafe { + cvt_pread64( + self.fd, + buf.as_mut_ptr() as *mut c_void, + cmp::min(buf.len(), READ_LIMIT), + offset as i64, + ) + .map(|n| n as usize) + } + } + pub fn write(&self, buf: &[u8]) -> io::Result { let ret = cvt(unsafe { - netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len())) + netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) })?; Ok(ret as usize) } @@ -87,7 +151,7 @@ impl NetFileDesc { netc::writev( self.fd, bufs.as_ptr() as *const netc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), max_iov()) as c_int, ) })?; Ok(ret as usize) @@ -98,10 +162,45 @@ impl NetFileDesc { true } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + #[cfg(target_os = "android")] + use super::android::cvt_pwrite64; + + #[cfg(not(target_os = "android"))] + unsafe fn cvt_pwrite64( + fd: c_int, + buf: *const c_void, + count: usize, + offset: i64, + ) -> io::Result { + #[cfg(not(target_os = "linux"))] + use netc::pwrite as pwrite64; + #[cfg(target_os = "linux")] + use netc::pwrite64; + cvt(pwrite64(fd, buf, count, offset)) + } + + unsafe { + cvt_pwrite64( + self.fd, + buf.as_ptr() as *const c_void, + cmp::min(buf.len(), READ_LIMIT), + offset as i64, + ) + .map(|n| n as usize) + } + } + #[cfg(target_os = "linux")] pub fn get_cloexec(&self) -> io::Result { unsafe { Ok((cvt(netc::fcntl(self.fd, netc::F_GETFD))? & netc::FD_CLOEXEC) != 0) } } + // Setting `FD_CLOEXEC` is not supported on FreeRTOS + // since there is no `exec` functionality. + #[cfg(target_os = "freertos")] + pub fn set_cloexec(&self) -> io::Result<()> { + Ok(()) + } #[cfg(not(any( target_env = "newlib", @@ -112,7 +211,8 @@ impl NetFileDesc { target_os = "l4re", target_os = "linux", target_os = "haiku", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -120,19 +220,17 @@ impl NetFileDesc { Ok(()) } } - #[cfg(all( - any( - target_env = "newlib", - target_os = "solaris", - target_os = "illumos", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "l4re", - target_os = "linux", - target_os = "haiku", - target_os = "redox" - ), - not(target_os = "freertos") + #[cfg(any( + all(target_env = "newlib", not(target_os = "freertos")), + target_os = "solaris", + target_os = "illumos", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "l4re", + target_os = "linux", + target_os = "haiku", + target_os = "redox", + target_os = "vxworks" ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -145,60 +243,37 @@ impl NetFileDesc { } } - // Setting `FD_CLOEXEC` is not supported on FreeRTOS - // since there is no `exec` functionality. - #[cfg(target_os = "freertos")] - pub fn set_cloexec(&self) -> io::Result<()> { - Ok(()) + #[cfg(target_os = "linux")] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + unsafe { + let v = nonblocking as c_int; + cvt(netc::ioctl(self.fd, netc::FIONBIO, &v))?; + Ok(()) + } + } + + #[cfg(not(target_os = "linux"))] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + unsafe { + let previous = cvt(netc::fcntl(self.fd, netc::F_GETFL))?; + let new = if nonblocking { + previous | netc::O_NONBLOCK + } else { + previous & !netc::O_NONBLOCK + }; + if new != previous { + cvt(netc::fcntl(self.fd, netc::F_SETFL, new))?; + } + Ok(()) + } } pub fn duplicate(&self) -> io::Result { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // flag, however, isn't supported on older Linux kernels (earlier than - // 2.6.24). - // - // To detect this and ensure that CLOEXEC is still set, we - // follow a strategy similar to musl [1] where if passing - // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not - // supported (the third parameter, 0, is always valid), so we stop - // trying that. - // - // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to - // resolve so we at least compile this. - // - // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 - #[cfg(any(target_os = "android", target_os = "haiku"))] - use netc::F_DUPFD as F_DUPFD_CLOEXEC; - #[cfg(not(any(target_os = "android", target_os = "haiku")))] - use netc::F_DUPFD_CLOEXEC; - - let make_filedesc = |fd| { - let fd = NetFileDesc::new(fd); - fd.set_cloexec()?; - Ok(fd) - }; - static TRY_CLOEXEC: AtomicBool = AtomicBool::new(!cfg!(target_os = "android")); - let fd = self.raw(); - if TRY_CLOEXEC.load(Ordering::Relaxed) { - match cvt(unsafe { netc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) { - // We *still* call the `set_cloexec` method as apparently some - // linux kernel at some point stopped setting CLOEXEC even - // though it reported doing so on F_DUPFD_CLOEXEC. - Ok(fd) => { - return Ok(if cfg!(target_os = "linux") { - make_filedesc(fd)? - } else { - NetFileDesc::new(fd) - }); - } - Err(ref e) if e.raw_os_error() == Some(netc::EINVAL) => { - TRY_CLOEXEC.store(false, Ordering::Relaxed); - } - Err(e) => return Err(e), - } - } - cvt(unsafe { netc::fcntl(fd, netc::F_DUPFD, 0) }).and_then(make_filedesc) + // is a POSIX flag that was added to Linux in 2.6.24. + let fd = cvt(unsafe { netc::fcntl(self.raw(), netc::F_DUPFD_CLOEXEC, 0) })?; + Ok(NetFileDesc::new(fd)) } } From a44476a127f4db6b2383b6a64b5a1a5aa93ae6e8 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 6 Mar 2021 23:08:02 +0100 Subject: [PATCH 66/73] Revert some changes. --- library/std/src/sys/unix/pipe.rs | 3 +-- library/std/src/sys/unix/process/process_unix.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs index 7d5d735826dae..7ae37bdda70bd 100644 --- a/library/std/src/sys/unix/pipe.rs +++ b/library/std/src/sys/unix/pipe.rs @@ -1,7 +1,7 @@ use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem; use crate::sys::fd::FileDesc; -use crate::sys::cvt_r; +use crate::sys::{cvt, cvt_r}; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -10,7 +10,6 @@ use crate::sys::cvt_r; pub struct AnonPipe(FileDesc); pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - use crate::sys::cvt; let mut fds = [0; 2]; // The only known way right now to create atomically set the CLOEXEC flag is diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index dc4ef45a11fab..a590c74435639 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -22,7 +22,7 @@ impl Command { default: Stdio, needs_stdin: bool, ) -> io::Result<(Process, StdioPipes)> { - const CLOEXEC_MSG_FOOTER: &[u8] = b"NOEX"; + const CLOEXEC_MSG_FOOTER: [u8; 4] = *b"NOEX"; let envp = self.capture_env(); From 90ba40b135eca360ecab8771931ef63b02503801 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 7 Mar 2021 18:31:32 +0100 Subject: [PATCH 67/73] Update formatting. --- library/std/src/os/freertos/raw.rs | 12 +++++++----- library/std/src/os/fuchsia/fs.rs | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/library/std/src/os/freertos/raw.rs b/library/std/src/os/freertos/raw.rs index d43db3f61c664..64c2673440440 100644 --- a/library/std/src/os/freertos/raw.rs +++ b/library/std/src/os/freertos/raw.rs @@ -1,11 +1,13 @@ //! FreeRTOS-specific raw type definitions #![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] +#![rustc_deprecated( + since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] #![allow(deprecated)] #![allow(missing_debug_implementations)] diff --git a/library/std/src/os/fuchsia/fs.rs b/library/std/src/os/fuchsia/fs.rs index b48a46f9124a9..1544bdfbe0cde 100644 --- a/library/std/src/os/fuchsia/fs.rs +++ b/library/std/src/os/fuchsia/fs.rs @@ -5,7 +5,7 @@ use crate::sys_common::AsInner; /// OS-specific extensions to [`fs::Metadata`]. /// -/// [`fs::Metadata`]: crate::fs::Metadata +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { #[stable(feature = "metadata_ext2", since = "1.8.0")] From 83047263dc7625c80030b25f668531c06900ebc0 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 7 Mar 2021 18:38:03 +0100 Subject: [PATCH 68/73] Simplify `thread_local_key`. --- .../src/sys/unix/freertos/thread_local_key.rs | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/library/std/src/sys/unix/freertos/thread_local_key.rs b/library/std/src/sys/unix/freertos/thread_local_key.rs index 898026b05323b..4886c0ebdf8f2 100644 --- a/library/std/src/sys/unix/freertos/thread_local_key.rs +++ b/library/std/src/sys/unix/freertos/thread_local_key.rs @@ -23,16 +23,7 @@ pub unsafe fn set(key: Key, value: *mut u8) { { LOCK.read(); - let mut found = false; - - for &(k, _) in KEYS.iter() { - if k == key { - found = true; - break; - } - } - - assert!(found); + assert!(KEYS.iter().any(|&(k, _)| k == key)); LOCK.read_unlock(); } @@ -65,22 +56,11 @@ pub unsafe fn get(key: Key) -> *mut u8 { pub unsafe fn destroy(key: Key) { LOCK.write(); - let mut i = 0; - let mut found = false; - - for &(k, _) in KEYS.iter() { - if k == key { - found = true; - break; - } - - i += 1; - } - - debug_assert!(found); - - if found { + if let Some(i) = KEYS.iter().position(|&(k, _)| k == key) { KEYS.remove(i); + } else { + debug_assert!(false); + core::hint::unreachable_unchecked(); } LOCK.write_unlock(); From c7379a0861ebc07a52309a283cb0c5eb2d6a256a Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 7 Mar 2021 18:52:38 +0100 Subject: [PATCH 69/73] Fix whitespace. --- library/std/src/sys/unix/net_fd.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys/unix/net_fd.rs b/library/std/src/sys/unix/net_fd.rs index ede527a1e41ef..e5a438dd8535d 100644 --- a/library/std/src/sys/unix/net_fd.rs +++ b/library/std/src/sys/unix/net_fd.rs @@ -195,6 +195,7 @@ impl NetFileDesc { pub fn get_cloexec(&self) -> io::Result { unsafe { Ok((cvt(netc::fcntl(self.fd, netc::F_GETFD))? & netc::FD_CLOEXEC) != 0) } } + // Setting `FD_CLOEXEC` is not supported on FreeRTOS // since there is no `exec` functionality. #[cfg(target_os = "freertos")] From 5b30ae11031815dd1b4bad119d270a2b86f21d72 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Mon, 8 Mar 2021 00:51:14 +0100 Subject: [PATCH 70/73] Fix `Condvar`. --- library/std/src/sys/unix/freertos/condvar.rs | 43 +++++++------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/library/std/src/sys/unix/freertos/condvar.rs b/library/std/src/sys/unix/freertos/condvar.rs index 8c879b68cd51e..d86c43f1551ea 100644 --- a/library/std/src/sys/unix/freertos/condvar.rs +++ b/library/std/src/sys/unix/freertos/condvar.rs @@ -25,7 +25,8 @@ impl Condvar { #[inline] pub unsafe fn init(&mut self) { - self.waiter_list.get_mut().replace(VecDeque::new()); + // This must stay empty since `RWLock` uses a `Condvar` + // internally which cannot be mutated. } #[inline] @@ -36,8 +37,6 @@ impl Condvar { if let Some(&waiter) = waiter_list.front() { xSemaphoreGive(waiter); } - } else { - core::hint::unreachable_unchecked(); } self.lock.unlock(); @@ -51,8 +50,6 @@ impl Condvar { for &waiter in waiter_list { xSemaphoreGive(waiter); } - } else { - core::hint::unreachable_unchecked(); } self.lock.unlock(); @@ -85,11 +82,8 @@ impl Condvar { self.lock.lock(); - if let Some(waiter_list) = (&mut *self.waiter_list.get()).as_mut() { - waiter_list.push_back(waiter); - } else { - core::hint::unreachable_unchecked(); - } + let waiter_list = (&mut *self.waiter_list.get()).get_or_insert_with(|| VecDeque::new()); + waiter_list.push_back(waiter); self.lock.unlock(); @@ -103,20 +97,15 @@ impl Condvar { self.lock.lock(); - if let Some(waiter_list) = (&mut *self.waiter_list.get()).as_mut() { - if let Some(index) = waiter_list.iter().position(|&w| w == waiter) { - waiter_list.remove(index); - } else { - core::hint::unreachable_unchecked(); - } + if let Some(index) = waiter_list.iter().position(|&w| w == waiter) { + waiter_list.remove(index); + vSemaphoreDelete(waiter); } else { core::hint::unreachable_unchecked(); } self.lock.unlock(); - vSemaphoreDelete(waiter); - mutex.lock(); if let (Some(now), Some(dur)) = (now, dur) { @@ -128,17 +117,15 @@ impl Condvar { #[inline] pub unsafe fn destroy(&self) { - #[cfg(debug_assertions)] - { - self.lock.lock(); + #[cfg(debug_assertions)] + { + self.lock.lock(); - if let Some(waiter_list) = (&*self.waiter_list.get()).as_mut() { - assert!(waiter_list.is_empty()); - } else { - core::hint::unreachable_unchecked(); - } + if let Some(waiter_list) = (&*self.waiter_list.get()).as_ref() { + assert!(waiter_list.is_empty()); + } - self.lock.unlock(); - } + self.lock.unlock(); + } } } From ca93ffdc554f9c75314b2e77e265eb2d3bacc31d Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Thu, 11 Mar 2021 11:03:17 +0100 Subject: [PATCH 71/73] `clock_t` depends on `newlib`. --- library/std/src/sys/unix/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 85b10de2cf54c..2d13f537c36e4 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -361,9 +361,9 @@ mod inner { } } - #[cfg(not(any(target_os = "dragonfly", target_os = "freertos")))] + #[cfg(not(any(target_os = "dragonfly", target_env = "newlib")))] pub type clock_t = libc::c_int; - #[cfg(any(target_os = "dragonfly", target_os = "freertos"))] + #[cfg(any(target_os = "dragonfly", target_env = "newlib"))] pub type clock_t = libc::c_ulong; fn now(clock: clock_t) -> Timespec { From d1ec22fc790e4e0fd4c27b66db5dac252914bdb5 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Thu, 11 Mar 2021 11:05:44 +0100 Subject: [PATCH 72/73] `memalign` depends on `newlib`. --- library/std/src/sys/unix/alloc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 1a1b4fa546f01..a2bb36af5fc03 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -54,8 +54,8 @@ unsafe impl GlobalAlloc for System { cfg_if::cfg_if! { if #[cfg(any( + target_env = "newlib", target_os = "android", - target_os = "freertos", target_os = "illumos", target_os = "redox", target_os = "solaris" From 9add94154d2469c67ad00a7fcd829fb10b0186f9 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Thu, 11 Mar 2021 11:10:48 +0100 Subject: [PATCH 73/73] Filesystem functions depend on `newlib`. --- library/std/src/sys/unix/fs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 3d2d27ca3bcd6..b84b7fa5804d1 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -607,11 +607,11 @@ impl DirEntry { } #[cfg(any( + target_env = "newlib", target_os = "macos", target_os = "ios", target_os = "linux", target_os = "emscripten", - target_os = "freertos", target_os = "android", target_os = "solaris", target_os = "illumos", @@ -653,10 +653,10 @@ impl DirEntry { } } #[cfg(any( + target_env = "newlib", target_os = "android", target_os = "linux", target_os = "emscripten", - target_os = "freertos", target_os = "l4re", target_os = "haiku", target_os = "vxworks" @@ -1108,8 +1108,8 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> { let original = cstr(original)?; let link = cstr(link)?; cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "freertos", target_os = "redox", target_os = "android"))] { - // VxWorks, FreeRTOS, Redox, and old versions of Android lack `linkat`, so use + if #[cfg(any(target_env = "newlib", target_os = "vxworks", target_os = "redox", target_os = "android"))] { + // Newlib, VxWorks, Redox, and old versions of Android lack `linkat`, so use // `link` instead. POSIX leaves it implementation-defined whether // `link` follows symlinks, so rely on the `symlink_hard_link` test // in library/std/src/fs/tests.rs to check the behavior.