From 293f95fb0cd27970e147697aa9500acdc22fd0e6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 11 Jul 2025 13:45:51 -0500 Subject: add regression test for RUST-143222 --- tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs | 12 ++++++++++++ tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs create mode 100644 tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs (limited to 'tests') diff --git a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs new file mode 100644 index 00000000000..8ce0a0de544 --- /dev/null +++ b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs @@ -0,0 +1,12 @@ +pub trait Assoc { + type Ty; +} + +pub struct Foo(::Ty); + +const _: () = { + impl crate::Assoc for Foo { + type Ty = Bar; + } + pub struct Bar; +}; diff --git a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs new file mode 100644 index 00000000000..005a5c0b98a --- /dev/null +++ b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Z normalize-docs --document-private-items -Zunstable-options --show-type-layout +//@ aux-build:wrap-unnamable-type.rs +//@ build-aux-docs + +#![crate_name = "foo"] + +extern crate wrap_unnamable_type as helper; +//extern crate helper; +//@ has 'foo/struct.Foo.html' +//@ !hasraw - '_/struct.Bar.html' +#[doc(inline)] +pub use helper::Foo; -- cgit 1.4.1-3-g733a5 From 94700f8f3fd4fc3f3a0e563aa94d4a399691d88f Mon Sep 17 00:00:00 2001 From: binarycat Date: Mon, 14 Jul 2025 12:31:58 -0500 Subject: fix regression test --- tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs | 2 +- tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'tests') diff --git a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs index 8ce0a0de544..7f8e346c8be 100644 --- a/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs +++ b/tests/rustdoc/reexport/auxiliary/wrap-unnamable-type.rs @@ -4,7 +4,7 @@ pub trait Assoc { pub struct Foo(::Ty); -const _: () = { +const _X: () = { impl crate::Assoc for Foo { type Ty = Bar; } diff --git a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs index 005a5c0b98a..9a8893786f5 100644 --- a/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs +++ b/tests/rustdoc/reexport/wrapped-unnamble-type-143222.rs @@ -2,11 +2,15 @@ //@ aux-build:wrap-unnamable-type.rs //@ build-aux-docs +// regression test for https://github.com/rust-lang/rust/issues/143222 +// makes sure normalizing docs does not cause us to link to unnamable types +// in cross-crate reexports. + #![crate_name = "foo"] extern crate wrap_unnamable_type as helper; -//extern crate helper; + //@ has 'foo/struct.Foo.html' -//@ !hasraw - '_/struct.Bar.html' +//@ !hasraw - 'struct.Bar.html' #[doc(inline)] pub use helper::Foo; -- cgit 1.4.1-3-g733a5 From 45231fa599583edc95843aaa4f23b12f762e01e7 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski Date: Wed, 23 Jul 2025 00:00:01 +0000 Subject: [rustdoc] Display unsafe attrs with edition 2024 `unsafe()` wrappers. --- src/librustdoc/clean/types.rs | 6 +++--- tests/rustdoc/attribute-rendering.rs | 6 +++--- tests/rustdoc/attributes-2021-edition.rs | 14 ++++++++++++++ tests/rustdoc/attributes-re-export-2021-edition.rs | 13 +++++++++++++ tests/rustdoc/attributes-re-export.rs | 2 +- tests/rustdoc/attributes.rs | 13 +++++++++---- tests/rustdoc/reexport/reexport-attrs.rs | 6 +++--- 7 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 tests/rustdoc/attributes-2021-edition.rs create mode 100644 tests/rustdoc/attributes-re-export-2021-edition.rs (limited to 'tests') diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5ac5da24299..64e707ad9d3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -768,13 +768,13 @@ impl Item { .iter() .filter_map(|attr| match attr { hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) => { - Some(format!("#[link_section = \"{name}\"]")) + Some(format!("#[unsafe(link_section = \"{name}\")]")) } hir::Attribute::Parsed(AttributeKind::NoMangle(..)) => { - Some("#[no_mangle]".to_string()) + Some("#[unsafe(no_mangle)]".to_string()) } hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) => { - Some(format!("#[export_name = \"{name}\"]")) + Some(format!("#[unsafe(export_name = \"{name}\")]")) } hir::Attribute::Parsed(AttributeKind::NonExhaustive(..)) => { Some("#[non_exhaustive]".to_string()) diff --git a/tests/rustdoc/attribute-rendering.rs b/tests/rustdoc/attribute-rendering.rs index 841533814c3..bf9b81077f3 100644 --- a/tests/rustdoc/attribute-rendering.rs +++ b/tests/rustdoc/attribute-rendering.rs @@ -1,7 +1,7 @@ #![crate_name = "foo"] //@ has 'foo/fn.f.html' -//@ has - //*[@'class="rust item-decl"]' '#[export_name = "f"] pub fn f()' -#[export_name = "\ -f"] +//@ has - //*[@'class="rust item-decl"]' '#[unsafe(export_name = "f")] pub fn f()' +#[unsafe(export_name = "\ +f")] pub fn f() {} diff --git a/tests/rustdoc/attributes-2021-edition.rs b/tests/rustdoc/attributes-2021-edition.rs new file mode 100644 index 00000000000..b5028d8c852 --- /dev/null +++ b/tests/rustdoc/attributes-2021-edition.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 +#![crate_name = "foo"] + +//@ has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' +#[no_mangle] +pub extern "C" fn f() {} + +//@ has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "bar")]' +#[export_name = "bar"] +pub extern "C" fn g() {} + +//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".text")]' +#[link_section = ".text"] +pub extern "C" fn example() {} diff --git a/tests/rustdoc/attributes-re-export-2021-edition.rs b/tests/rustdoc/attributes-re-export-2021-edition.rs new file mode 100644 index 00000000000..04ee6c273dd --- /dev/null +++ b/tests/rustdoc/attributes-re-export-2021-edition.rs @@ -0,0 +1,13 @@ +// Tests that attributes are correctly copied onto a re-exported item. +//@ edition:2024 +#![crate_name = "re_export"] + +//@ has 're_export/fn.thingy2.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' +pub use thingymod::thingy as thingy2; + +mod thingymod { + #[unsafe(no_mangle)] + pub fn thingy() { + + } +} diff --git a/tests/rustdoc/attributes-re-export.rs b/tests/rustdoc/attributes-re-export.rs index 458826ea8a3..820276f83c0 100644 --- a/tests/rustdoc/attributes-re-export.rs +++ b/tests/rustdoc/attributes-re-export.rs @@ -2,7 +2,7 @@ //@ edition:2021 #![crate_name = "re_export"] -//@ has 're_export/fn.thingy2.html' '//pre[@class="rust item-decl"]' '#[no_mangle]' +//@ has 're_export/fn.thingy2.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' pub use thingymod::thingy as thingy2; mod thingymod { diff --git a/tests/rustdoc/attributes.rs b/tests/rustdoc/attributes.rs index e34468a88b1..34487a89127 100644 --- a/tests/rustdoc/attributes.rs +++ b/tests/rustdoc/attributes.rs @@ -1,13 +1,18 @@ +//@ edition: 2024 #![crate_name = "foo"] -//@ has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[no_mangle]' -#[no_mangle] +//@ has foo/fn.f.html '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' +#[unsafe(no_mangle)] pub extern "C" fn f() {} -//@ has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[export_name = "bar"]' -#[export_name = "bar"] +//@ has foo/fn.g.html '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "bar")]' +#[unsafe(export_name = "bar")] pub extern "C" fn g() {} +//@ has foo/fn.example.html '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".text")]' +#[unsafe(link_section = ".text")] +pub extern "C" fn example() {} + //@ has foo/struct.Repr.html '//pre[@class="rust item-decl"]' '#[repr(C, align(8))]' #[repr(C, align(8))] pub struct Repr; diff --git a/tests/rustdoc/reexport/reexport-attrs.rs b/tests/rustdoc/reexport/reexport-attrs.rs index 0ec645841f0..aec0a11c0c6 100644 --- a/tests/rustdoc/reexport/reexport-attrs.rs +++ b/tests/rustdoc/reexport/reexport-attrs.rs @@ -4,13 +4,13 @@ extern crate reexports_attrs; -//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[no_mangle]' +//@ has 'foo/fn.f0.html' '//pre[@class="rust item-decl"]' '#[unsafe(no_mangle)]' pub use reexports_attrs::f0; -//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[link_section = ".here"]' +//@ has 'foo/fn.f1.html' '//pre[@class="rust item-decl"]' '#[unsafe(link_section = ".here")]' pub use reexports_attrs::f1; -//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[export_name = "f2export"]' +//@ has 'foo/fn.f2.html' '//pre[@class="rust item-decl"]' '#[unsafe(export_name = "f2export")]' pub use reexports_attrs::f2; //@ has 'foo/enum.T0.html' '//pre[@class="rust item-decl"]' '#[repr(u8)]' -- cgit 1.4.1-3-g733a5 From d636a6590ce1429ff011e04bb0b4d393dc382226 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 24 Jul 2025 17:15:36 +0500 Subject: moved 35 tests to organized locations --- tests/ui/block-result/blocks-without-results.rs | 37 +++++ tests/ui/borrowck/refcell-borrow-comparison.rs | 7 + tests/ui/closures/fnonce-moved-twice.rs | 14 ++ tests/ui/closures/moved-upvar-mut-rebind.rs | 11 ++ tests/ui/collections/hashset-connected-border.rs | 49 ++++++ .../ui/const-generics/vec-macro-in-static-array.rs | 6 + tests/ui/extern/format-message-windows-ffi.rs | 39 +++++ tests/ui/fn/anonymous-parameters-trait.rs | 9 ++ tests/ui/imports/use-in-impl-scope.rs | 14 ++ tests/ui/issues/issue-11709.rs | 37 ----- tests/ui/issues/issue-11740.rs | 26 --- tests/ui/issues/issue-11771.rs | 11 -- tests/ui/issues/issue-11820.rs | 13 -- tests/ui/issues/issue-11844.rs | 8 - tests/ui/issues/issue-11869.rs | 16 -- tests/ui/issues/issue-11958.rs | 11 -- tests/ui/issues/issue-12033.rs | 7 - tests/ui/issues/issue-12041.rs | 13 -- tests/ui/issues/issue-12127.rs | 14 -- tests/ui/issues/issue-12285.rs | 14 -- tests/ui/issues/issue-12567.rs | 13 -- tests/ui/issues/issue-12677.rs | 9 -- tests/ui/issues/issue-12729.rs | 14 -- tests/ui/issues/issue-12744.rs | 5 - tests/ui/issues/issue-12860.rs | 49 ------ tests/ui/issues/issue-12863.rs | 8 - tests/ui/issues/issue-12909.rs | 19 --- tests/ui/issues/issue-12920.rs | 8 - tests/ui/issues/issue-13027.rs | 178 --------------------- tests/ui/issues/issue-13058.rs | 27 ---- tests/ui/issues/issue-13105.rs | 9 -- tests/ui/issues/issue-13167.rs | 24 --- tests/ui/issues/issue-13202.rs | 7 - tests/ui/issues/issue-13204.rs | 25 --- tests/ui/issues/issue-13214.rs | 22 --- tests/ui/issues/issue-13259-windows-tcb-trash.rs | 39 ----- tests/ui/issues/issue-13264.rs | 74 --------- tests/ui/issues/issue-13323.rs | 58 ------- tests/ui/issues/issue-13359.rs | 15 -- tests/ui/issues/issue-13405.rs | 19 --- tests/ui/issues/issue-13407.rs | 9 -- tests/ui/issues/issue-13434.rs | 21 --- tests/ui/issues/issue-13446.rs | 6 - tests/ui/issues/issue-13466.rs | 22 --- tests/ui/iterators/bytes-iterator-clone.rs | 9 ++ tests/ui/iterators/phf-map-entries-iterator.rs | 24 +++ .../ui/lifetimes/iterator-trait-lifetime-error.rs | 27 ++++ .../lifetimes/struct-lifetime-field-assignment.rs | 19 +++ tests/ui/match/function-in-pattern-error.rs | 8 + tests/ui/match/guard-literal-range-shadow.rs | 178 +++++++++++++++++++++ tests/ui/match/option-result-mismatch.rs | 8 + .../ui/match/option-result-type-param-mismatch.rs | 22 +++ tests/ui/match/slice-move-out-error.rs | 13 ++ tests/ui/match/string-literal-match-patterns.rs | 16 ++ tests/ui/match/struct-reference-patterns.rs | 14 ++ tests/ui/panics/explicit-panic-unreachable.rs | 8 + tests/ui/panics/unwrap-or-panic-input.rs | 7 + tests/ui/privacy/private-unit-struct-assignment.rs | 9 ++ tests/ui/statics/enum-with-static-str-variant.rs | 22 +++ tests/ui/threads/moved-value-in-thread-loop.rs | 13 ++ tests/ui/traits/any-trait-object-debug.rs | 5 + tests/ui/traits/default-method-lifetime-params.rs | 25 +++ tests/ui/traits/deref-chain-method-calls.rs | 74 +++++++++ tests/ui/traits/fnonce-repro-trait-impl.rs | 21 +++ tests/ui/traits/matcher-trait-equality.rs | 58 +++++++ tests/ui/traits/reference-clone-noclone.rs | 13 ++ .../type-inference/isize-usize-mismatch-error.rs | 15 ++ tests/ui/type-inference/type-collect-inference.rs | 19 +++ tests/ui/type-inference/unit-type-add-error.rs | 11 ++ tests/ui/unsafe/unsafe-transmute-in-find.rs | 26 +++ 70 files changed, 850 insertions(+), 850 deletions(-) create mode 100644 tests/ui/block-result/blocks-without-results.rs create mode 100644 tests/ui/borrowck/refcell-borrow-comparison.rs create mode 100644 tests/ui/closures/fnonce-moved-twice.rs create mode 100644 tests/ui/closures/moved-upvar-mut-rebind.rs create mode 100644 tests/ui/collections/hashset-connected-border.rs create mode 100644 tests/ui/const-generics/vec-macro-in-static-array.rs create mode 100644 tests/ui/extern/format-message-windows-ffi.rs create mode 100644 tests/ui/fn/anonymous-parameters-trait.rs create mode 100644 tests/ui/imports/use-in-impl-scope.rs delete mode 100644 tests/ui/issues/issue-11709.rs delete mode 100644 tests/ui/issues/issue-11740.rs delete mode 100644 tests/ui/issues/issue-11771.rs delete mode 100644 tests/ui/issues/issue-11820.rs delete mode 100644 tests/ui/issues/issue-11844.rs delete mode 100644 tests/ui/issues/issue-11869.rs delete mode 100644 tests/ui/issues/issue-11958.rs delete mode 100644 tests/ui/issues/issue-12033.rs delete mode 100644 tests/ui/issues/issue-12041.rs delete mode 100644 tests/ui/issues/issue-12127.rs delete mode 100644 tests/ui/issues/issue-12285.rs delete mode 100644 tests/ui/issues/issue-12567.rs delete mode 100644 tests/ui/issues/issue-12677.rs delete mode 100644 tests/ui/issues/issue-12729.rs delete mode 100644 tests/ui/issues/issue-12744.rs delete mode 100644 tests/ui/issues/issue-12860.rs delete mode 100644 tests/ui/issues/issue-12863.rs delete mode 100644 tests/ui/issues/issue-12909.rs delete mode 100644 tests/ui/issues/issue-12920.rs delete mode 100644 tests/ui/issues/issue-13027.rs delete mode 100644 tests/ui/issues/issue-13058.rs delete mode 100644 tests/ui/issues/issue-13105.rs delete mode 100644 tests/ui/issues/issue-13167.rs delete mode 100644 tests/ui/issues/issue-13202.rs delete mode 100644 tests/ui/issues/issue-13204.rs delete mode 100644 tests/ui/issues/issue-13214.rs delete mode 100644 tests/ui/issues/issue-13259-windows-tcb-trash.rs delete mode 100644 tests/ui/issues/issue-13264.rs delete mode 100644 tests/ui/issues/issue-13323.rs delete mode 100644 tests/ui/issues/issue-13359.rs delete mode 100644 tests/ui/issues/issue-13405.rs delete mode 100644 tests/ui/issues/issue-13407.rs delete mode 100644 tests/ui/issues/issue-13434.rs delete mode 100644 tests/ui/issues/issue-13446.rs delete mode 100644 tests/ui/issues/issue-13466.rs create mode 100644 tests/ui/iterators/bytes-iterator-clone.rs create mode 100644 tests/ui/iterators/phf-map-entries-iterator.rs create mode 100644 tests/ui/lifetimes/iterator-trait-lifetime-error.rs create mode 100644 tests/ui/lifetimes/struct-lifetime-field-assignment.rs create mode 100644 tests/ui/match/function-in-pattern-error.rs create mode 100644 tests/ui/match/guard-literal-range-shadow.rs create mode 100644 tests/ui/match/option-result-mismatch.rs create mode 100644 tests/ui/match/option-result-type-param-mismatch.rs create mode 100644 tests/ui/match/slice-move-out-error.rs create mode 100644 tests/ui/match/string-literal-match-patterns.rs create mode 100644 tests/ui/match/struct-reference-patterns.rs create mode 100644 tests/ui/panics/explicit-panic-unreachable.rs create mode 100644 tests/ui/panics/unwrap-or-panic-input.rs create mode 100644 tests/ui/privacy/private-unit-struct-assignment.rs create mode 100644 tests/ui/statics/enum-with-static-str-variant.rs create mode 100644 tests/ui/threads/moved-value-in-thread-loop.rs create mode 100644 tests/ui/traits/any-trait-object-debug.rs create mode 100644 tests/ui/traits/default-method-lifetime-params.rs create mode 100644 tests/ui/traits/deref-chain-method-calls.rs create mode 100644 tests/ui/traits/fnonce-repro-trait-impl.rs create mode 100644 tests/ui/traits/matcher-trait-equality.rs create mode 100644 tests/ui/traits/reference-clone-noclone.rs create mode 100644 tests/ui/type-inference/isize-usize-mismatch-error.rs create mode 100644 tests/ui/type-inference/type-collect-inference.rs create mode 100644 tests/ui/type-inference/unit-type-add-error.rs create mode 100644 tests/ui/unsafe/unsafe-transmute-in-find.rs (limited to 'tests') diff --git a/tests/ui/block-result/blocks-without-results.rs b/tests/ui/block-result/blocks-without-results.rs new file mode 100644 index 00000000000..8a11074eca8 --- /dev/null +++ b/tests/ui/block-result/blocks-without-results.rs @@ -0,0 +1,37 @@ +//@ run-pass +#![allow(dead_code)] + +// Don't panic on blocks without results +// There are several tests in this run-pass that raised +// when this bug was opened. The cases where the compiler +// panics before the fix have a comment. + +struct S {x:()} + +fn test(slot: &mut Option Box>>) -> () { + let a = slot.take(); + let _a: () = match a { + // `{let .. a(); }` would break + Some(mut a) => { let _a = a(); }, + None => (), + }; +} + +fn not(b: bool) -> bool { + if b { + !b + } else { + // `panic!(...)` would break + panic!("Break the compiler"); + } +} + +pub fn main() { + // {} would break + let _r: () = {}; + let mut slot = None; + // `{ test(...); }` would break + let _s : S = S{ x: { test(&mut slot); } }; + + let _b = not(true); +} diff --git a/tests/ui/borrowck/refcell-borrow-comparison.rs b/tests/ui/borrowck/refcell-borrow-comparison.rs new file mode 100644 index 00000000000..0bf6490bafe --- /dev/null +++ b/tests/ui/borrowck/refcell-borrow-comparison.rs @@ -0,0 +1,7 @@ +//@ run-pass +use std::cell::RefCell; + +fn main() { + let x = RefCell::new(0); + if *x.borrow() == 0 {} else {} +} diff --git a/tests/ui/closures/fnonce-moved-twice.rs b/tests/ui/closures/fnonce-moved-twice.rs new file mode 100644 index 00000000000..199d542e816 --- /dev/null +++ b/tests/ui/closures/fnonce-moved-twice.rs @@ -0,0 +1,14 @@ +#![feature(unboxed_closures, tuple_trait)] + +fn to_fn_once>(f: F) -> F { f } +fn do_it(x: &isize) { } + +fn main() { + let x: Box<_> = Box::new(22); + let f = to_fn_once(move|| do_it(&*x)); + to_fn_once(move|| { + f(); + f(); + //~^ ERROR: use of moved value: `f` + })() +} diff --git a/tests/ui/closures/moved-upvar-mut-rebind.rs b/tests/ui/closures/moved-upvar-mut-rebind.rs new file mode 100644 index 00000000000..9185c5158af --- /dev/null +++ b/tests/ui/closures/moved-upvar-mut-rebind.rs @@ -0,0 +1,11 @@ +//@ run-pass + +// We shouldn't need to rebind a moved upvar as mut if it's already +// marked as mut + +pub fn main() { + let mut x = 1; + let _thunk = Box::new(move|| { x = 2; }); + //~^ WARN value assigned to `x` is never read + //~| WARN unused variable: `x` +} diff --git a/tests/ui/collections/hashset-connected-border.rs b/tests/ui/collections/hashset-connected-border.rs new file mode 100644 index 00000000000..255f6670793 --- /dev/null +++ b/tests/ui/collections/hashset-connected-border.rs @@ -0,0 +1,49 @@ +//@ run-pass +use std::collections::HashSet; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +struct XYZ { + x: isize, + y: isize, + z: isize +} + +fn main() { + let mut connected = HashSet::new(); + let mut border = HashSet::new(); + + let middle = XYZ{x: 0, y: 0, z: 0}; + border.insert(middle); + + while !border.is_empty() && connected.len() < 10000 { + let choice = *(border.iter().next().unwrap()); + border.remove(&choice); + connected.insert(choice); + + let cxp = XYZ{x: choice.x + 1, y: choice.y, z: choice.z}; + let cxm = XYZ{x: choice.x - 1, y: choice.y, z: choice.z}; + let cyp = XYZ{x: choice.x, y: choice.y + 1, z: choice.z}; + let cym = XYZ{x: choice.x, y: choice.y - 1, z: choice.z}; + let czp = XYZ{x: choice.x, y: choice.y, z: choice.z + 1}; + let czm = XYZ{x: choice.x, y: choice.y, z: choice.z - 1}; + + if !connected.contains(&cxp) { + border.insert(cxp); + } + if !connected.contains(&cxm){ + border.insert(cxm); + } + if !connected.contains(&cyp){ + border.insert(cyp); + } + if !connected.contains(&cym) { + border.insert(cym); + } + if !connected.contains(&czp){ + border.insert(czp); + } + if !connected.contains(&czm) { + border.insert(czm); + } + } +} diff --git a/tests/ui/const-generics/vec-macro-in-static-array.rs b/tests/ui/const-generics/vec-macro-in-static-array.rs new file mode 100644 index 00000000000..9f1fc42774f --- /dev/null +++ b/tests/ui/const-generics/vec-macro-in-static-array.rs @@ -0,0 +1,6 @@ +// Used to cause ICE + +static VEC: [u32; 256] = vec![]; +//~^ ERROR mismatched types + +fn main() {} diff --git a/tests/ui/extern/format-message-windows-ffi.rs b/tests/ui/extern/format-message-windows-ffi.rs new file mode 100644 index 00000000000..381e3f15259 --- /dev/null +++ b/tests/ui/extern/format-message-windows-ffi.rs @@ -0,0 +1,39 @@ +//@ run-pass + +#[cfg(windows)] +mod imp { + type LPVOID = *mut u8; + type DWORD = u32; + type LPWSTR = *mut u16; + + extern "system" { + fn FormatMessageW(flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const u8) + -> DWORD; + } + + pub fn test() { + let mut buf: [u16; 50] = [0; 50]; + let ret = unsafe { + FormatMessageW(0x1000, core::ptr::null_mut(), 1, 0x400, + buf.as_mut_ptr(), buf.len() as u32, core::ptr::null()) + }; + // On some 32-bit Windowses (Win7-8 at least) this will panic with segmented + // stacks taking control of pvArbitrary + assert!(ret != 0); + } +} + +#[cfg(not(windows))] +mod imp { + pub fn test() { } +} + +fn main() { + imp::test() +} diff --git a/tests/ui/fn/anonymous-parameters-trait.rs b/tests/ui/fn/anonymous-parameters-trait.rs new file mode 100644 index 00000000000..d119aa9c788 --- /dev/null +++ b/tests/ui/fn/anonymous-parameters-trait.rs @@ -0,0 +1,9 @@ +//@ edition: 2015 +//@ check-pass + +trait Foo { + #[allow(anonymous_parameters)] + fn quux(u8) {} +} + +fn main() {} diff --git a/tests/ui/imports/use-in-impl-scope.rs b/tests/ui/imports/use-in-impl-scope.rs new file mode 100644 index 00000000000..4d45846bc60 --- /dev/null +++ b/tests/ui/imports/use-in-impl-scope.rs @@ -0,0 +1,14 @@ +//@ edition: 2015 +//@ check-pass +#![allow(dead_code)] + +pub struct Foo; + +mod bar { + use Foo; + + impl Foo { + fn baz(&self) {} + } +} +fn main() {} diff --git a/tests/ui/issues/issue-11709.rs b/tests/ui/issues/issue-11709.rs deleted file mode 100644 index 8a11074eca8..00000000000 --- a/tests/ui/issues/issue-11709.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -// Don't panic on blocks without results -// There are several tests in this run-pass that raised -// when this bug was opened. The cases where the compiler -// panics before the fix have a comment. - -struct S {x:()} - -fn test(slot: &mut Option Box>>) -> () { - let a = slot.take(); - let _a: () = match a { - // `{let .. a(); }` would break - Some(mut a) => { let _a = a(); }, - None => (), - }; -} - -fn not(b: bool) -> bool { - if b { - !b - } else { - // `panic!(...)` would break - panic!("Break the compiler"); - } -} - -pub fn main() { - // {} would break - let _r: () = {}; - let mut slot = None; - // `{ test(...); }` would break - let _s : S = S{ x: { test(&mut slot); } }; - - let _b = not(true); -} diff --git a/tests/ui/issues/issue-11740.rs b/tests/ui/issues/issue-11740.rs deleted file mode 100644 index c6099c2a0c0..00000000000 --- a/tests/ui/issues/issue-11740.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ check-pass - -struct Attr { - name: String, - value: String, -} - -struct Element { - attrs: Vec>, -} - -impl Element { - pub unsafe fn get_attr<'a>(&'a self, name: &str) { - self.attrs - .iter() - .find(|attr| { - let attr: &&Box = std::mem::transmute(attr); - true - }); - } -} - -fn main() { - let element = Element { attrs: Vec::new() }; - unsafe { let () = element.get_attr("foo"); }; -} diff --git a/tests/ui/issues/issue-11771.rs b/tests/ui/issues/issue-11771.rs deleted file mode 100644 index c69cd1e79e3..00000000000 --- a/tests/ui/issues/issue-11771.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn main() { - let x = (); - 1 + - x //~^ ERROR E0277 - ; - - let x: () = (); - 1 + - x //~^ ERROR E0277 - ; -} diff --git a/tests/ui/issues/issue-11820.rs b/tests/ui/issues/issue-11820.rs deleted file mode 100644 index ada844f8ee1..00000000000 --- a/tests/ui/issues/issue-11820.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -#![allow(noop_method_call)] - -struct NoClone; - -fn main() { - let rnc = &NoClone; - let rsnc = &Some(NoClone); - - let _: &NoClone = rnc.clone(); - let _: &Option = rsnc.clone(); -} diff --git a/tests/ui/issues/issue-11844.rs b/tests/ui/issues/issue-11844.rs deleted file mode 100644 index f974a470296..00000000000 --- a/tests/ui/issues/issue-11844.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let a = Some(Box::new(1)); - match a { - Ok(a) => //~ ERROR: mismatched types - println!("{}",a), - None => panic!() - } -} diff --git a/tests/ui/issues/issue-11869.rs b/tests/ui/issues/issue-11869.rs deleted file mode 100644 index dd752227bbe..00000000000 --- a/tests/ui/issues/issue-11869.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - -struct A { - a: String -} - -fn borrow<'a>(binding: &'a A) -> &'a str { - match &*binding.a { - "in" => "in_", - "ref" => "ref_", - ident => ident - } -} - -fn main() {} diff --git a/tests/ui/issues/issue-11958.rs b/tests/ui/issues/issue-11958.rs deleted file mode 100644 index 9185c5158af..00000000000 --- a/tests/ui/issues/issue-11958.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass - -// We shouldn't need to rebind a moved upvar as mut if it's already -// marked as mut - -pub fn main() { - let mut x = 1; - let _thunk = Box::new(move|| { x = 2; }); - //~^ WARN value assigned to `x` is never read - //~| WARN unused variable: `x` -} diff --git a/tests/ui/issues/issue-12033.rs b/tests/ui/issues/issue-12033.rs deleted file mode 100644 index 0bf6490bafe..00000000000 --- a/tests/ui/issues/issue-12033.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -use std::cell::RefCell; - -fn main() { - let x = RefCell::new(0); - if *x.borrow() == 0 {} else {} -} diff --git a/tests/ui/issues/issue-12041.rs b/tests/ui/issues/issue-12041.rs deleted file mode 100644 index 091e8fe8b2a..00000000000 --- a/tests/ui/issues/issue-12041.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::sync::mpsc::channel; -use std::thread; - -fn main() { - let (tx, rx) = channel(); - let _t = thread::spawn(move|| -> () { - loop { - let tx = tx; - //~^ ERROR: use of moved value: `tx` - tx.send(1); - } - }); -} diff --git a/tests/ui/issues/issue-12127.rs b/tests/ui/issues/issue-12127.rs deleted file mode 100644 index 199d542e816..00000000000 --- a/tests/ui/issues/issue-12127.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(unboxed_closures, tuple_trait)] - -fn to_fn_once>(f: F) -> F { f } -fn do_it(x: &isize) { } - -fn main() { - let x: Box<_> = Box::new(22); - let f = to_fn_once(move|| do_it(&*x)); - to_fn_once(move|| { - f(); - f(); - //~^ ERROR: use of moved value: `f` - })() -} diff --git a/tests/ui/issues/issue-12285.rs b/tests/ui/issues/issue-12285.rs deleted file mode 100644 index fe199147128..00000000000 --- a/tests/ui/issues/issue-12285.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass - -struct S; - -fn main() { - match Some(&S) { - Some(&S) => {}, - _x => unreachable!() - } - match Some(&S) { - Some(&S) => {}, - None => unreachable!() - } -} diff --git a/tests/ui/issues/issue-12567.rs b/tests/ui/issues/issue-12567.rs deleted file mode 100644 index 1b2a37de475..00000000000 --- a/tests/ui/issues/issue-12567.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { - match (l1, l2) { - //~^ ERROR: cannot move out of type `[T]`, a non-copy slice - //~| ERROR: cannot move out of type `[T]`, a non-copy slice - (&[], &[]) => println!("both empty"), - (&[], &[hd, ..]) | (&[hd, ..], &[]) - => println!("one empty"), - (&[hd1, ..], &[hd2, ..]) - => println!("both nonempty"), - } -} - -fn main() {} diff --git a/tests/ui/issues/issue-12677.rs b/tests/ui/issues/issue-12677.rs deleted file mode 100644 index dbc2dbc8527..00000000000 --- a/tests/ui/issues/issue-12677.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -fn main() { - let s = "Hello"; - let first = s.bytes(); - let second = first.clone(); - - assert_eq!(first.collect::>(), second.collect::>()) -} diff --git a/tests/ui/issues/issue-12729.rs b/tests/ui/issues/issue-12729.rs deleted file mode 100644 index 4d45846bc60..00000000000 --- a/tests/ui/issues/issue-12729.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ edition: 2015 -//@ check-pass -#![allow(dead_code)] - -pub struct Foo; - -mod bar { - use Foo; - - impl Foo { - fn baz(&self) {} - } -} -fn main() {} diff --git a/tests/ui/issues/issue-12744.rs b/tests/ui/issues/issue-12744.rs deleted file mode 100644 index eaf92d413d5..00000000000 --- a/tests/ui/issues/issue-12744.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-pass -fn main() { - fn test() -> Box { Box::new(1) } - println!("{:?}", test()) -} diff --git a/tests/ui/issues/issue-12860.rs b/tests/ui/issues/issue-12860.rs deleted file mode 100644 index 255f6670793..00000000000 --- a/tests/ui/issues/issue-12860.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ run-pass -use std::collections::HashSet; - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct XYZ { - x: isize, - y: isize, - z: isize -} - -fn main() { - let mut connected = HashSet::new(); - let mut border = HashSet::new(); - - let middle = XYZ{x: 0, y: 0, z: 0}; - border.insert(middle); - - while !border.is_empty() && connected.len() < 10000 { - let choice = *(border.iter().next().unwrap()); - border.remove(&choice); - connected.insert(choice); - - let cxp = XYZ{x: choice.x + 1, y: choice.y, z: choice.z}; - let cxm = XYZ{x: choice.x - 1, y: choice.y, z: choice.z}; - let cyp = XYZ{x: choice.x, y: choice.y + 1, z: choice.z}; - let cym = XYZ{x: choice.x, y: choice.y - 1, z: choice.z}; - let czp = XYZ{x: choice.x, y: choice.y, z: choice.z + 1}; - let czm = XYZ{x: choice.x, y: choice.y, z: choice.z - 1}; - - if !connected.contains(&cxp) { - border.insert(cxp); - } - if !connected.contains(&cxm){ - border.insert(cxm); - } - if !connected.contains(&cyp){ - border.insert(cyp); - } - if !connected.contains(&cym) { - border.insert(cym); - } - if !connected.contains(&czp){ - border.insert(czp); - } - if !connected.contains(&czm) { - border.insert(czm); - } - } -} diff --git a/tests/ui/issues/issue-12863.rs b/tests/ui/issues/issue-12863.rs deleted file mode 100644 index 1ac1c3d818e..00000000000 --- a/tests/ui/issues/issue-12863.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod foo { pub fn bar() {} } - -fn main() { - match () { - foo::bar => {} - //~^ ERROR expected unit struct, unit variant or constant, found function `foo::bar` - } -} diff --git a/tests/ui/issues/issue-12909.rs b/tests/ui/issues/issue-12909.rs deleted file mode 100644 index f2c33806aae..00000000000 --- a/tests/ui/issues/issue-12909.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass -#![allow(unused_variables)] - -use std::collections::HashMap; - -fn copy(&x: &T) -> T { - x -} - -fn main() { - let arr = [(1, 1), (2, 2), (3, 3)]; - - let v1: Vec<&_> = arr.iter().collect(); - let v2: Vec<_> = arr.iter().map(copy).collect(); - - let m1: HashMap<_, _> = arr.iter().map(copy).collect(); - let m2: HashMap = arr.iter().map(copy).collect(); - let m3: HashMap<_, usize> = arr.iter().map(copy).collect(); -} diff --git a/tests/ui/issues/issue-12920.rs b/tests/ui/issues/issue-12920.rs deleted file mode 100644 index f3b1b643c45..00000000000 --- a/tests/ui/issues/issue-12920.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-fail -//@ error-pattern:explicit panic -//@ needs-subprocess - -pub fn main() { - panic!(); - println!("{}", 1); -} diff --git a/tests/ui/issues/issue-13027.rs b/tests/ui/issues/issue-13027.rs deleted file mode 100644 index fbd1d75067b..00000000000 --- a/tests/ui/issues/issue-13027.rs +++ /dev/null @@ -1,178 +0,0 @@ -//@ run-pass - -// Tests that match expression handles overlapped literal and range -// properly in the presence of guard function. - -fn val() -> usize { 1 } - -static CONST: usize = 1; - -pub fn main() { - lit_shadow_range(); - range_shadow_lit(); - range_shadow_range(); - multi_pats_shadow_lit(); - multi_pats_shadow_range(); - lit_shadow_multi_pats(); - range_shadow_multi_pats(); - misc(); -} - -fn lit_shadow_range() { - assert_eq!(2, match 1 { - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - let x = 0; - assert_eq!(2, match x+1 { - 0 => 0, - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - assert_eq!(2, match val() { - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - assert_eq!(2, match CONST { - 0 => 0, - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - // value is out of the range of second arm, should match wildcard pattern - assert_eq!(3, match 3 { - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); -} - -fn range_shadow_lit() { - assert_eq!(2, match 1 { - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - let x = 0; - assert_eq!(2, match x+1 { - 0 => 0, - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - assert_eq!(2, match val() { - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - assert_eq!(2, match CONST { - 0 => 0, - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - // ditto - assert_eq!(3, match 3 { - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); -} - -fn range_shadow_range() { - assert_eq!(2, match 1 { - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - let x = 0; - assert_eq!(2, match x+1 { - 100 => 0, - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - assert_eq!(2, match val() { - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - assert_eq!(2, match CONST { - 100 => 0, - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - // ditto - assert_eq!(3, match 5 { - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); -} - -fn multi_pats_shadow_lit() { - assert_eq!(2, match 1 { - 100 => 0, - 0 | 1..=10 if false => 1, - 1 => 2, - _ => 3, - }); -} - -fn multi_pats_shadow_range() { - assert_eq!(2, match 1 { - 100 => 0, - 0 | 1..=10 if false => 1, - 1..=3 => 2, - _ => 3, - }); -} - -fn lit_shadow_multi_pats() { - assert_eq!(2, match 1 { - 100 => 0, - 1 if false => 1, - 0 | 1..=10 => 2, - _ => 3, - }); -} - -fn range_shadow_multi_pats() { - assert_eq!(2, match 1 { - 100 => 0, - 1..=3 if false => 1, - 0 | 1..=10 => 2, - _ => 3, - }); -} - -fn misc() { - enum Foo { - Bar(#[allow(dead_code)] usize, bool) - } - // This test basically mimics how trace_macros! macro is implemented, - // which is a rare combination of vector patterns, multiple wild-card - // patterns and guard functions. - let r = match [Foo::Bar(0, false)] { - [Foo::Bar(_, pred)] if pred => 1, - [Foo::Bar(_, pred)] if !pred => 2, - _ => 0, - }; - assert_eq!(2, r); -} diff --git a/tests/ui/issues/issue-13058.rs b/tests/ui/issues/issue-13058.rs deleted file mode 100644 index a5806feb720..00000000000 --- a/tests/ui/issues/issue-13058.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::ops::Range; - -trait Itble<'r, T, I: Iterator> { fn iter(&'r self) -> I; } - -impl<'r> Itble<'r, usize, Range> for (usize, usize) { - fn iter(&'r self) -> Range { - let &(min, max) = self; - min..max - } -} - -fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool -{ - let cont_iter = cont.iter(); -//~^ ERROR explicit lifetime required in the type of `cont` [E0621] - let result = cont_iter.fold(Some(0), |state, val| { - state.map_or(None, |mask| { - let bit = 1 << val; - if mask & bit == 0 {Some(mask|bit)} else {None} - }) - }); - result.is_some() -} - -fn main() { - check(&(3, 5)); -} diff --git a/tests/ui/issues/issue-13105.rs b/tests/ui/issues/issue-13105.rs deleted file mode 100644 index d119aa9c788..00000000000 --- a/tests/ui/issues/issue-13105.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ edition: 2015 -//@ check-pass - -trait Foo { - #[allow(anonymous_parameters)] - fn quux(u8) {} -} - -fn main() {} diff --git a/tests/ui/issues/issue-13167.rs b/tests/ui/issues/issue-13167.rs deleted file mode 100644 index 5f733e85948..00000000000 --- a/tests/ui/issues/issue-13167.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ check-pass -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver - -use std::slice; - -pub struct PhfMapEntries<'a, T: 'a> { - iter: slice::Iter<'a, (&'static str, T)>, -} - -impl<'a, T> Iterator for PhfMapEntries<'a, T> { - type Item = (&'static str, &'a T); - - fn next(&mut self) -> Option<(&'static str, &'a T)> { - self.iter.by_ref().map(|&(key, ref value)| (key, value)).next() - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -fn main() {} diff --git a/tests/ui/issues/issue-13202.rs b/tests/ui/issues/issue-13202.rs deleted file mode 100644 index 99ffba3fba5..00000000000 --- a/tests/ui/issues/issue-13202.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-fail -//@ error-pattern:bad input -//@ needs-subprocess - -fn main() { - Some("foo").unwrap_or(panic!("bad input")).to_string(); -} diff --git a/tests/ui/issues/issue-13204.rs b/tests/ui/issues/issue-13204.rs deleted file mode 100644 index 01362f6fe61..00000000000 --- a/tests/ui/issues/issue-13204.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] -// Test that when instantiating trait default methods, typeck handles -// lifetime parameters defined on the method bound correctly. - - -pub trait Foo { - fn bar<'a, I: Iterator>(&self, it: I) -> usize { - let mut xs = it.filter(|_| true); - xs.count() - } -} - -pub struct Baz; - -impl Foo for Baz { - // When instantiating `Foo::bar` for `Baz` here, typeck used to - // ICE due to the lifetime parameter of `bar`. -} - -fn main() { - let x = Baz; - let y = vec![(), (), ()]; - assert_eq!(x.bar(y.iter()), 3); -} diff --git a/tests/ui/issues/issue-13214.rs b/tests/ui/issues/issue-13214.rs deleted file mode 100644 index 8140ec943a0..00000000000 --- a/tests/ui/issues/issue-13214.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ build-pass -#![allow(dead_code)] -// defining static with struct that contains enum -// with &'static str variant used to cause ICE - - -pub enum Foo { - Bar, - Baz(&'static str), -} - -pub static TEST: Test = Test { - foo: Foo::Bar, - c: 'a' -}; - -pub struct Test { - foo: Foo, - c: char, -} - -fn main() {} diff --git a/tests/ui/issues/issue-13259-windows-tcb-trash.rs b/tests/ui/issues/issue-13259-windows-tcb-trash.rs deleted file mode 100644 index 381e3f15259..00000000000 --- a/tests/ui/issues/issue-13259-windows-tcb-trash.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ run-pass - -#[cfg(windows)] -mod imp { - type LPVOID = *mut u8; - type DWORD = u32; - type LPWSTR = *mut u16; - - extern "system" { - fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const u8) - -> DWORD; - } - - pub fn test() { - let mut buf: [u16; 50] = [0; 50]; - let ret = unsafe { - FormatMessageW(0x1000, core::ptr::null_mut(), 1, 0x400, - buf.as_mut_ptr(), buf.len() as u32, core::ptr::null()) - }; - // On some 32-bit Windowses (Win7-8 at least) this will panic with segmented - // stacks taking control of pvArbitrary - assert!(ret != 0); - } -} - -#[cfg(not(windows))] -mod imp { - pub fn test() { } -} - -fn main() { - imp::test() -} diff --git a/tests/ui/issues/issue-13264.rs b/tests/ui/issues/issue-13264.rs deleted file mode 100644 index bf4ec388c4f..00000000000 --- a/tests/ui/issues/issue-13264.rs +++ /dev/null @@ -1,74 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -use std::ops::Deref; - -struct Root { - jsref: JSRef -} - -impl Deref for Root { - type Target = JSRef; - - fn deref<'a>(&'a self) -> &'a JSRef { - &self.jsref - } -} - -#[derive(Copy, Clone)] -struct JSRef { - node: *const Node -} - -impl Deref for JSRef { - type Target = Node; - - fn deref<'a>(&'a self) -> &'a Node { - self.get() - } -} - -trait INode { - fn RemoveChild(&self); -} - -impl INode for JSRef { - fn RemoveChild(&self) { - self.get().RemoveChild(0) - } -} - -impl JSRef { - fn AddChild(&self) { - self.get().AddChild(0); - } - - fn get<'a>(&'a self) -> &'a Node { - unsafe { - &*self.node - } - } -} - -struct Node; - -impl Node { - fn RemoveChild(&self, _a: usize) { - } - - fn AddChild(&self, _a: usize) { - } -} - -fn main() { - let n = Node; - let jsref = JSRef { node: &n }; - let root = Root { jsref: jsref }; - - root.AddChild(); - jsref.AddChild(); - - root.RemoveChild(); - jsref.RemoveChild(); -} diff --git a/tests/ui/issues/issue-13323.rs b/tests/ui/issues/issue-13323.rs deleted file mode 100644 index 8f334404f9a..00000000000 --- a/tests/ui/issues/issue-13323.rs +++ /dev/null @@ -1,58 +0,0 @@ -//@ run-pass - -struct StrWrap { - s: String -} - -impl StrWrap { - fn new(s: &str) -> StrWrap { - StrWrap { s: s.to_string() } - } - - fn get_s<'a>(&'a self) -> &'a str { - &self.s - } -} - -struct MyStruct { - s: StrWrap -} - -impl MyStruct { - fn new(s: &str) -> MyStruct { - MyStruct { s: StrWrap::new(s) } - } - - fn get_str_wrap<'a>(&'a self) -> &'a StrWrap { - &self.s - } -} - -trait Matcher { - fn matches(&self, actual: T) -> bool; -} - -fn assert_that>(actual: T, matcher: &U) { - assert!(matcher.matches(actual)); -} - -struct EqualTo { - expected: T -} - -impl Matcher for EqualTo { - fn matches(&self, actual: T) -> bool { - self.expected.eq(&actual) - } -} - -fn equal_to(expected: T) -> Box> { - Box::new(EqualTo { expected: expected }) -} - -pub fn main() { - let my_struct = MyStruct::new("zomg"); - let s = my_struct.get_str_wrap(); - - assert_that(s.get_s(), &*equal_to("zomg")); -} diff --git a/tests/ui/issues/issue-13359.rs b/tests/ui/issues/issue-13359.rs deleted file mode 100644 index 5d31d7f861c..00000000000 --- a/tests/ui/issues/issue-13359.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ dont-require-annotations: NOTE - -fn foo(_s: i16) { } - -fn bar(_s: u32) { } - -fn main() { - foo(1*(1 as isize)); - //~^ ERROR mismatched types - //~| NOTE expected `i16`, found `isize` - - bar(1*(1 as usize)); - //~^ ERROR mismatched types - //~| NOTE expected `u32`, found `usize` -} diff --git a/tests/ui/issues/issue-13405.rs b/tests/ui/issues/issue-13405.rs deleted file mode 100644 index 80b298d2f37..00000000000 --- a/tests/ui/issues/issue-13405.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ check-pass -#![allow(dead_code)] -#![allow(unused_variables)] - -struct Foo<'a> { - i: &'a bool, - j: Option<&'a isize>, -} - -impl<'a> Foo<'a> { - fn bar(&mut self, j: &isize) { - let child = Foo { - i: self.i, - j: Some(j) - }; - } -} - -fn main() {} diff --git a/tests/ui/issues/issue-13407.rs b/tests/ui/issues/issue-13407.rs deleted file mode 100644 index 7794be37b85..00000000000 --- a/tests/ui/issues/issue-13407.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod A { - struct C; -} - -fn main() { - A::C = 1; - //~^ ERROR: mismatched types - //~| ERROR: unit struct `C` is private -} diff --git a/tests/ui/issues/issue-13434.rs b/tests/ui/issues/issue-13434.rs deleted file mode 100644 index caf7b632393..00000000000 --- a/tests/ui/issues/issue-13434.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ run-pass -#[derive(Debug)] -struct MyStruct; - -trait Repro { - fn repro(self, s: MyStruct) -> String; -} - -impl Repro for F where F: FnOnce(MyStruct) -> String { - fn repro(self, s: MyStruct) -> String { - self(s) - } -} - -fn do_stuff(r: R) -> String { - r.repro(MyStruct) -} - -pub fn main() { - assert_eq!("MyStruct".to_string(), do_stuff(|s: MyStruct| format!("{:?}", s))); -} diff --git a/tests/ui/issues/issue-13446.rs b/tests/ui/issues/issue-13446.rs deleted file mode 100644 index 9f1fc42774f..00000000000 --- a/tests/ui/issues/issue-13446.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Used to cause ICE - -static VEC: [u32; 256] = vec![]; -//~^ ERROR mismatched types - -fn main() {} diff --git a/tests/ui/issues/issue-13466.rs b/tests/ui/issues/issue-13466.rs deleted file mode 100644 index 78ce4c1d2f6..00000000000 --- a/tests/ui/issues/issue-13466.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Regression test for #13466 - -//@ dont-require-annotations: NOTE - -pub fn main() { - // The expected arm type `Option` has one type parameter, while - // the actual arm `Result` has two. typeck should not be - // tricked into looking up a non-existing second type parameter. - let _x: usize = match Some(1) { - Ok(u) => u, - //~^ ERROR mismatched types - //~| NOTE expected enum `Option<{integer}>` - //~| NOTE found enum `Result<_, _>` - //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` - - Err(e) => panic!(e) - //~^ ERROR mismatched types - //~| NOTE expected enum `Option<{integer}>` - //~| NOTE found enum `Result<_, _>` - //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` - }; -} diff --git a/tests/ui/iterators/bytes-iterator-clone.rs b/tests/ui/iterators/bytes-iterator-clone.rs new file mode 100644 index 00000000000..dbc2dbc8527 --- /dev/null +++ b/tests/ui/iterators/bytes-iterator-clone.rs @@ -0,0 +1,9 @@ +//@ run-pass + +fn main() { + let s = "Hello"; + let first = s.bytes(); + let second = first.clone(); + + assert_eq!(first.collect::>(), second.collect::>()) +} diff --git a/tests/ui/iterators/phf-map-entries-iterator.rs b/tests/ui/iterators/phf-map-entries-iterator.rs new file mode 100644 index 00000000000..5f733e85948 --- /dev/null +++ b/tests/ui/iterators/phf-map-entries-iterator.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +use std::slice; + +pub struct PhfMapEntries<'a, T: 'a> { + iter: slice::Iter<'a, (&'static str, T)>, +} + +impl<'a, T> Iterator for PhfMapEntries<'a, T> { + type Item = (&'static str, &'a T); + + fn next(&mut self) -> Option<(&'static str, &'a T)> { + self.iter.by_ref().map(|&(key, ref value)| (key, value)).next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/iterator-trait-lifetime-error.rs b/tests/ui/lifetimes/iterator-trait-lifetime-error.rs new file mode 100644 index 00000000000..a5806feb720 --- /dev/null +++ b/tests/ui/lifetimes/iterator-trait-lifetime-error.rs @@ -0,0 +1,27 @@ +use std::ops::Range; + +trait Itble<'r, T, I: Iterator> { fn iter(&'r self) -> I; } + +impl<'r> Itble<'r, usize, Range> for (usize, usize) { + fn iter(&'r self) -> Range { + let &(min, max) = self; + min..max + } +} + +fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool +{ + let cont_iter = cont.iter(); +//~^ ERROR explicit lifetime required in the type of `cont` [E0621] + let result = cont_iter.fold(Some(0), |state, val| { + state.map_or(None, |mask| { + let bit = 1 << val; + if mask & bit == 0 {Some(mask|bit)} else {None} + }) + }); + result.is_some() +} + +fn main() { + check(&(3, 5)); +} diff --git a/tests/ui/lifetimes/struct-lifetime-field-assignment.rs b/tests/ui/lifetimes/struct-lifetime-field-assignment.rs new file mode 100644 index 00000000000..80b298d2f37 --- /dev/null +++ b/tests/ui/lifetimes/struct-lifetime-field-assignment.rs @@ -0,0 +1,19 @@ +//@ check-pass +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Foo<'a> { + i: &'a bool, + j: Option<&'a isize>, +} + +impl<'a> Foo<'a> { + fn bar(&mut self, j: &isize) { + let child = Foo { + i: self.i, + j: Some(j) + }; + } +} + +fn main() {} diff --git a/tests/ui/match/function-in-pattern-error.rs b/tests/ui/match/function-in-pattern-error.rs new file mode 100644 index 00000000000..1ac1c3d818e --- /dev/null +++ b/tests/ui/match/function-in-pattern-error.rs @@ -0,0 +1,8 @@ +mod foo { pub fn bar() {} } + +fn main() { + match () { + foo::bar => {} + //~^ ERROR expected unit struct, unit variant or constant, found function `foo::bar` + } +} diff --git a/tests/ui/match/guard-literal-range-shadow.rs b/tests/ui/match/guard-literal-range-shadow.rs new file mode 100644 index 00000000000..fbd1d75067b --- /dev/null +++ b/tests/ui/match/guard-literal-range-shadow.rs @@ -0,0 +1,178 @@ +//@ run-pass + +// Tests that match expression handles overlapped literal and range +// properly in the presence of guard function. + +fn val() -> usize { 1 } + +static CONST: usize = 1; + +pub fn main() { + lit_shadow_range(); + range_shadow_lit(); + range_shadow_range(); + multi_pats_shadow_lit(); + multi_pats_shadow_range(); + lit_shadow_multi_pats(); + range_shadow_multi_pats(); + misc(); +} + +fn lit_shadow_range() { + assert_eq!(2, match 1 { + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + let x = 0; + assert_eq!(2, match x+1 { + 0 => 0, + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + assert_eq!(2, match val() { + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + assert_eq!(2, match CONST { + 0 => 0, + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + // value is out of the range of second arm, should match wildcard pattern + assert_eq!(3, match 3 { + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); +} + +fn range_shadow_lit() { + assert_eq!(2, match 1 { + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + let x = 0; + assert_eq!(2, match x+1 { + 0 => 0, + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + assert_eq!(2, match val() { + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + assert_eq!(2, match CONST { + 0 => 0, + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + // ditto + assert_eq!(3, match 3 { + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); +} + +fn range_shadow_range() { + assert_eq!(2, match 1 { + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + let x = 0; + assert_eq!(2, match x+1 { + 100 => 0, + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + assert_eq!(2, match val() { + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + assert_eq!(2, match CONST { + 100 => 0, + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + // ditto + assert_eq!(3, match 5 { + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); +} + +fn multi_pats_shadow_lit() { + assert_eq!(2, match 1 { + 100 => 0, + 0 | 1..=10 if false => 1, + 1 => 2, + _ => 3, + }); +} + +fn multi_pats_shadow_range() { + assert_eq!(2, match 1 { + 100 => 0, + 0 | 1..=10 if false => 1, + 1..=3 => 2, + _ => 3, + }); +} + +fn lit_shadow_multi_pats() { + assert_eq!(2, match 1 { + 100 => 0, + 1 if false => 1, + 0 | 1..=10 => 2, + _ => 3, + }); +} + +fn range_shadow_multi_pats() { + assert_eq!(2, match 1 { + 100 => 0, + 1..=3 if false => 1, + 0 | 1..=10 => 2, + _ => 3, + }); +} + +fn misc() { + enum Foo { + Bar(#[allow(dead_code)] usize, bool) + } + // This test basically mimics how trace_macros! macro is implemented, + // which is a rare combination of vector patterns, multiple wild-card + // patterns and guard functions. + let r = match [Foo::Bar(0, false)] { + [Foo::Bar(_, pred)] if pred => 1, + [Foo::Bar(_, pred)] if !pred => 2, + _ => 0, + }; + assert_eq!(2, r); +} diff --git a/tests/ui/match/option-result-mismatch.rs b/tests/ui/match/option-result-mismatch.rs new file mode 100644 index 00000000000..f974a470296 --- /dev/null +++ b/tests/ui/match/option-result-mismatch.rs @@ -0,0 +1,8 @@ +fn main() { + let a = Some(Box::new(1)); + match a { + Ok(a) => //~ ERROR: mismatched types + println!("{}",a), + None => panic!() + } +} diff --git a/tests/ui/match/option-result-type-param-mismatch.rs b/tests/ui/match/option-result-type-param-mismatch.rs new file mode 100644 index 00000000000..78ce4c1d2f6 --- /dev/null +++ b/tests/ui/match/option-result-type-param-mismatch.rs @@ -0,0 +1,22 @@ +// Regression test for #13466 + +//@ dont-require-annotations: NOTE + +pub fn main() { + // The expected arm type `Option` has one type parameter, while + // the actual arm `Result` has two. typeck should not be + // tricked into looking up a non-existing second type parameter. + let _x: usize = match Some(1) { + Ok(u) => u, + //~^ ERROR mismatched types + //~| NOTE expected enum `Option<{integer}>` + //~| NOTE found enum `Result<_, _>` + //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` + + Err(e) => panic!(e) + //~^ ERROR mismatched types + //~| NOTE expected enum `Option<{integer}>` + //~| NOTE found enum `Result<_, _>` + //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` + }; +} diff --git a/tests/ui/match/slice-move-out-error.rs b/tests/ui/match/slice-move-out-error.rs new file mode 100644 index 00000000000..1b2a37de475 --- /dev/null +++ b/tests/ui/match/slice-move-out-error.rs @@ -0,0 +1,13 @@ +fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { + match (l1, l2) { + //~^ ERROR: cannot move out of type `[T]`, a non-copy slice + //~| ERROR: cannot move out of type `[T]`, a non-copy slice + (&[], &[]) => println!("both empty"), + (&[], &[hd, ..]) | (&[hd, ..], &[]) + => println!("one empty"), + (&[hd1, ..], &[hd2, ..]) + => println!("both nonempty"), + } +} + +fn main() {} diff --git a/tests/ui/match/string-literal-match-patterns.rs b/tests/ui/match/string-literal-match-patterns.rs new file mode 100644 index 00000000000..dd752227bbe --- /dev/null +++ b/tests/ui/match/string-literal-match-patterns.rs @@ -0,0 +1,16 @@ +//@ check-pass +#![allow(dead_code)] + +struct A { + a: String +} + +fn borrow<'a>(binding: &'a A) -> &'a str { + match &*binding.a { + "in" => "in_", + "ref" => "ref_", + ident => ident + } +} + +fn main() {} diff --git a/tests/ui/match/struct-reference-patterns.rs b/tests/ui/match/struct-reference-patterns.rs new file mode 100644 index 00000000000..fe199147128 --- /dev/null +++ b/tests/ui/match/struct-reference-patterns.rs @@ -0,0 +1,14 @@ +//@ run-pass + +struct S; + +fn main() { + match Some(&S) { + Some(&S) => {}, + _x => unreachable!() + } + match Some(&S) { + Some(&S) => {}, + None => unreachable!() + } +} diff --git a/tests/ui/panics/explicit-panic-unreachable.rs b/tests/ui/panics/explicit-panic-unreachable.rs new file mode 100644 index 00000000000..f3b1b643c45 --- /dev/null +++ b/tests/ui/panics/explicit-panic-unreachable.rs @@ -0,0 +1,8 @@ +//@ run-fail +//@ error-pattern:explicit panic +//@ needs-subprocess + +pub fn main() { + panic!(); + println!("{}", 1); +} diff --git a/tests/ui/panics/unwrap-or-panic-input.rs b/tests/ui/panics/unwrap-or-panic-input.rs new file mode 100644 index 00000000000..99ffba3fba5 --- /dev/null +++ b/tests/ui/panics/unwrap-or-panic-input.rs @@ -0,0 +1,7 @@ +//@ run-fail +//@ error-pattern:bad input +//@ needs-subprocess + +fn main() { + Some("foo").unwrap_or(panic!("bad input")).to_string(); +} diff --git a/tests/ui/privacy/private-unit-struct-assignment.rs b/tests/ui/privacy/private-unit-struct-assignment.rs new file mode 100644 index 00000000000..7794be37b85 --- /dev/null +++ b/tests/ui/privacy/private-unit-struct-assignment.rs @@ -0,0 +1,9 @@ +mod A { + struct C; +} + +fn main() { + A::C = 1; + //~^ ERROR: mismatched types + //~| ERROR: unit struct `C` is private +} diff --git a/tests/ui/statics/enum-with-static-str-variant.rs b/tests/ui/statics/enum-with-static-str-variant.rs new file mode 100644 index 00000000000..8140ec943a0 --- /dev/null +++ b/tests/ui/statics/enum-with-static-str-variant.rs @@ -0,0 +1,22 @@ +//@ build-pass +#![allow(dead_code)] +// defining static with struct that contains enum +// with &'static str variant used to cause ICE + + +pub enum Foo { + Bar, + Baz(&'static str), +} + +pub static TEST: Test = Test { + foo: Foo::Bar, + c: 'a' +}; + +pub struct Test { + foo: Foo, + c: char, +} + +fn main() {} diff --git a/tests/ui/threads/moved-value-in-thread-loop.rs b/tests/ui/threads/moved-value-in-thread-loop.rs new file mode 100644 index 00000000000..091e8fe8b2a --- /dev/null +++ b/tests/ui/threads/moved-value-in-thread-loop.rs @@ -0,0 +1,13 @@ +use std::sync::mpsc::channel; +use std::thread; + +fn main() { + let (tx, rx) = channel(); + let _t = thread::spawn(move|| -> () { + loop { + let tx = tx; + //~^ ERROR: use of moved value: `tx` + tx.send(1); + } + }); +} diff --git a/tests/ui/traits/any-trait-object-debug.rs b/tests/ui/traits/any-trait-object-debug.rs new file mode 100644 index 00000000000..eaf92d413d5 --- /dev/null +++ b/tests/ui/traits/any-trait-object-debug.rs @@ -0,0 +1,5 @@ +//@ run-pass +fn main() { + fn test() -> Box { Box::new(1) } + println!("{:?}", test()) +} diff --git a/tests/ui/traits/default-method-lifetime-params.rs b/tests/ui/traits/default-method-lifetime-params.rs new file mode 100644 index 00000000000..01362f6fe61 --- /dev/null +++ b/tests/ui/traits/default-method-lifetime-params.rs @@ -0,0 +1,25 @@ +//@ run-pass +#![allow(unused_mut)] +// Test that when instantiating trait default methods, typeck handles +// lifetime parameters defined on the method bound correctly. + + +pub trait Foo { + fn bar<'a, I: Iterator>(&self, it: I) -> usize { + let mut xs = it.filter(|_| true); + xs.count() + } +} + +pub struct Baz; + +impl Foo for Baz { + // When instantiating `Foo::bar` for `Baz` here, typeck used to + // ICE due to the lifetime parameter of `bar`. +} + +fn main() { + let x = Baz; + let y = vec![(), (), ()]; + assert_eq!(x.bar(y.iter()), 3); +} diff --git a/tests/ui/traits/deref-chain-method-calls.rs b/tests/ui/traits/deref-chain-method-calls.rs new file mode 100644 index 00000000000..bf4ec388c4f --- /dev/null +++ b/tests/ui/traits/deref-chain-method-calls.rs @@ -0,0 +1,74 @@ +//@ run-pass +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use std::ops::Deref; + +struct Root { + jsref: JSRef +} + +impl Deref for Root { + type Target = JSRef; + + fn deref<'a>(&'a self) -> &'a JSRef { + &self.jsref + } +} + +#[derive(Copy, Clone)] +struct JSRef { + node: *const Node +} + +impl Deref for JSRef { + type Target = Node; + + fn deref<'a>(&'a self) -> &'a Node { + self.get() + } +} + +trait INode { + fn RemoveChild(&self); +} + +impl INode for JSRef { + fn RemoveChild(&self) { + self.get().RemoveChild(0) + } +} + +impl JSRef { + fn AddChild(&self) { + self.get().AddChild(0); + } + + fn get<'a>(&'a self) -> &'a Node { + unsafe { + &*self.node + } + } +} + +struct Node; + +impl Node { + fn RemoveChild(&self, _a: usize) { + } + + fn AddChild(&self, _a: usize) { + } +} + +fn main() { + let n = Node; + let jsref = JSRef { node: &n }; + let root = Root { jsref: jsref }; + + root.AddChild(); + jsref.AddChild(); + + root.RemoveChild(); + jsref.RemoveChild(); +} diff --git a/tests/ui/traits/fnonce-repro-trait-impl.rs b/tests/ui/traits/fnonce-repro-trait-impl.rs new file mode 100644 index 00000000000..caf7b632393 --- /dev/null +++ b/tests/ui/traits/fnonce-repro-trait-impl.rs @@ -0,0 +1,21 @@ +//@ run-pass +#[derive(Debug)] +struct MyStruct; + +trait Repro { + fn repro(self, s: MyStruct) -> String; +} + +impl Repro for F where F: FnOnce(MyStruct) -> String { + fn repro(self, s: MyStruct) -> String { + self(s) + } +} + +fn do_stuff(r: R) -> String { + r.repro(MyStruct) +} + +pub fn main() { + assert_eq!("MyStruct".to_string(), do_stuff(|s: MyStruct| format!("{:?}", s))); +} diff --git a/tests/ui/traits/matcher-trait-equality.rs b/tests/ui/traits/matcher-trait-equality.rs new file mode 100644 index 00000000000..8f334404f9a --- /dev/null +++ b/tests/ui/traits/matcher-trait-equality.rs @@ -0,0 +1,58 @@ +//@ run-pass + +struct StrWrap { + s: String +} + +impl StrWrap { + fn new(s: &str) -> StrWrap { + StrWrap { s: s.to_string() } + } + + fn get_s<'a>(&'a self) -> &'a str { + &self.s + } +} + +struct MyStruct { + s: StrWrap +} + +impl MyStruct { + fn new(s: &str) -> MyStruct { + MyStruct { s: StrWrap::new(s) } + } + + fn get_str_wrap<'a>(&'a self) -> &'a StrWrap { + &self.s + } +} + +trait Matcher { + fn matches(&self, actual: T) -> bool; +} + +fn assert_that>(actual: T, matcher: &U) { + assert!(matcher.matches(actual)); +} + +struct EqualTo { + expected: T +} + +impl Matcher for EqualTo { + fn matches(&self, actual: T) -> bool { + self.expected.eq(&actual) + } +} + +fn equal_to(expected: T) -> Box> { + Box::new(EqualTo { expected: expected }) +} + +pub fn main() { + let my_struct = MyStruct::new("zomg"); + let s = my_struct.get_str_wrap(); + + assert_that(s.get_s(), &*equal_to("zomg")); +} diff --git a/tests/ui/traits/reference-clone-noclone.rs b/tests/ui/traits/reference-clone-noclone.rs new file mode 100644 index 00000000000..ada844f8ee1 --- /dev/null +++ b/tests/ui/traits/reference-clone-noclone.rs @@ -0,0 +1,13 @@ +//@ run-pass + +#![allow(noop_method_call)] + +struct NoClone; + +fn main() { + let rnc = &NoClone; + let rsnc = &Some(NoClone); + + let _: &NoClone = rnc.clone(); + let _: &Option = rsnc.clone(); +} diff --git a/tests/ui/type-inference/isize-usize-mismatch-error.rs b/tests/ui/type-inference/isize-usize-mismatch-error.rs new file mode 100644 index 00000000000..5d31d7f861c --- /dev/null +++ b/tests/ui/type-inference/isize-usize-mismatch-error.rs @@ -0,0 +1,15 @@ +//@ dont-require-annotations: NOTE + +fn foo(_s: i16) { } + +fn bar(_s: u32) { } + +fn main() { + foo(1*(1 as isize)); + //~^ ERROR mismatched types + //~| NOTE expected `i16`, found `isize` + + bar(1*(1 as usize)); + //~^ ERROR mismatched types + //~| NOTE expected `u32`, found `usize` +} diff --git a/tests/ui/type-inference/type-collect-inference.rs b/tests/ui/type-inference/type-collect-inference.rs new file mode 100644 index 00000000000..f2c33806aae --- /dev/null +++ b/tests/ui/type-inference/type-collect-inference.rs @@ -0,0 +1,19 @@ +//@ run-pass +#![allow(unused_variables)] + +use std::collections::HashMap; + +fn copy(&x: &T) -> T { + x +} + +fn main() { + let arr = [(1, 1), (2, 2), (3, 3)]; + + let v1: Vec<&_> = arr.iter().collect(); + let v2: Vec<_> = arr.iter().map(copy).collect(); + + let m1: HashMap<_, _> = arr.iter().map(copy).collect(); + let m2: HashMap = arr.iter().map(copy).collect(); + let m3: HashMap<_, usize> = arr.iter().map(copy).collect(); +} diff --git a/tests/ui/type-inference/unit-type-add-error.rs b/tests/ui/type-inference/unit-type-add-error.rs new file mode 100644 index 00000000000..c69cd1e79e3 --- /dev/null +++ b/tests/ui/type-inference/unit-type-add-error.rs @@ -0,0 +1,11 @@ +fn main() { + let x = (); + 1 + + x //~^ ERROR E0277 + ; + + let x: () = (); + 1 + + x //~^ ERROR E0277 + ; +} diff --git a/tests/ui/unsafe/unsafe-transmute-in-find.rs b/tests/ui/unsafe/unsafe-transmute-in-find.rs new file mode 100644 index 00000000000..c6099c2a0c0 --- /dev/null +++ b/tests/ui/unsafe/unsafe-transmute-in-find.rs @@ -0,0 +1,26 @@ +//@ check-pass + +struct Attr { + name: String, + value: String, +} + +struct Element { + attrs: Vec>, +} + +impl Element { + pub unsafe fn get_attr<'a>(&'a self, name: &str) { + self.attrs + .iter() + .find(|attr| { + let attr: &&Box = std::mem::transmute(attr); + true + }); + } +} + +fn main() { + let element = Element { attrs: Vec::new() }; + unsafe { let () = element.get_attr("foo"); }; +} -- cgit 1.4.1-3-g733a5 From 5ae2d42a8c80807c7e3ae7e8aff165fb4d8e046f Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 7 Nov 2024 15:33:45 -0600 Subject: get rid of some false negatives in rustdoc::broken_intra_doc_links rustdoc will not try to do intra-doc linking if the "path" of a link looks too much like a "real url". however, only inline links ([text](url)) can actually contain a url, other types of links (reference links, shortcut links) contain a *reference* which is later resolved to an actual url. the "path" in this case cannot be a url, and therefore it should not be skipped due to looking like a url. Co-authored-by: Michael Howell --- src/librustdoc/passes/collect_intra_doc_links.rs | 13 +++++++--- tests/rustdoc-ui/bad-intra-doc.rs | 13 ++++++++++ tests/rustdoc-ui/bad-intra-doc.stderr | 31 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/rustdoc-ui/bad-intra-doc.rs create mode 100644 tests/rustdoc-ui/bad-intra-doc.stderr (limited to 'tests') diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5a9aa2a94c8..97f8a2be10b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -941,13 +941,20 @@ fn preprocess_link( ori_link: &MarkdownLink, dox: &str, ) -> Option> { + // certain link kinds cannot have their path be urls, + // so they should not be ignored, no matter how much they look like urls. + // e.g. [https://example.com/] is not a link to example.com. + let can_be_url = ori_link.kind != LinkType::ShortcutUnknown + && ori_link.kind != LinkType::CollapsedUnknown + && ori_link.kind != LinkType::ReferenceUnknown; + // [] is mostly likely not supposed to be a link if ori_link.link.is_empty() { return None; } // Bail early for real links. - if ori_link.link.contains('/') { + if can_be_url && ori_link.link.contains('/') { return None; } @@ -972,7 +979,7 @@ fn preprocess_link( Ok(None) => (None, link, link), Err((err_msg, relative_range)) => { // Only report error if we would not have ignored this link. See issue #83859. - if !should_ignore_link_with_disambiguators(link) { + if !(can_be_url && should_ignore_link_with_disambiguators(link)) { let disambiguator_range = match range_between_backticks(&ori_link.range, dox) { MarkdownLinkRange::Destination(no_backticks_range) => { MarkdownLinkRange::Destination( @@ -989,7 +996,7 @@ fn preprocess_link( } }; - if should_ignore_link(path_str) { + if can_be_url && should_ignore_link(path_str) { return None; } diff --git a/tests/rustdoc-ui/bad-intra-doc.rs b/tests/rustdoc-ui/bad-intra-doc.rs new file mode 100644 index 00000000000..7bc55756e67 --- /dev/null +++ b/tests/rustdoc-ui/bad-intra-doc.rs @@ -0,0 +1,13 @@ +#![no_std] +#![deny(rustdoc::broken_intra_doc_links)] + +// regression test for https://github.com/rust-lang/rust/issues/54191 + +/// this is not a link to [`example.com`] //~ERROR unresolved link +/// +/// this link [`has spaces in it`]. +/// +/// attempted link to method: [`Foo.bar()`] //~ERROR unresolved link +/// +/// classic broken intra-doc link: [`Bar`] //~ERROR unresolved link +pub struct Foo; diff --git a/tests/rustdoc-ui/bad-intra-doc.stderr b/tests/rustdoc-ui/bad-intra-doc.stderr new file mode 100644 index 00000000000..9533792b35b --- /dev/null +++ b/tests/rustdoc-ui/bad-intra-doc.stderr @@ -0,0 +1,31 @@ +error: unresolved link to `example.com` + --> $DIR/bad-intra-doc.rs:6:29 + | +LL | /// this is not a link to [`example.com`] + | ^^^^^^^^^^^ no item named `example.com` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` +note: the lint level is defined here + --> $DIR/bad-intra-doc.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `Foo.bar` + --> $DIR/bad-intra-doc.rs:10:33 + | +LL | /// attempted link to method: [`Foo.bar()`] + | ^^^^^^^^^ no item named `Foo.bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Bar` + --> $DIR/bad-intra-doc.rs:12:38 + | +LL | /// classic broken intra-doc link: [`Bar`] + | ^^^ no item named `Bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 87d7d80cec060690c9055fa93cb29dfe5eb79ce9 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 8 Nov 2024 13:59:56 -0600 Subject: adjust more unit tests to reflect more aggressive intra-doc linting --- .../disambiguator-endswith-named-suffix.rs | 30 ++--- .../disambiguator-endswith-named-suffix.stderr | 122 ++++++++++++++++++++- tests/rustdoc-ui/intra-doc/weird-syntax.rs | 2 +- tests/rustdoc-ui/intra-doc/weird-syntax.stderr | 24 ++++ .../lints/redundant_explicit_links-utf8.rs | 14 ++- .../lints/redundant_explicit_links-utf8.stderr | 59 ++++++++++ 6 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr (limited to 'tests') diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs index 1174e16dd53..cb277d529ce 100644 --- a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs +++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.rs @@ -2,67 +2,67 @@ //@ normalize-stderr: "nightly|beta|1\.[0-9][0-9]\.[0-9]" -> "$$CHANNEL" //! [struct@m!()] //~ WARN: unmatched disambiguator `struct` and suffix `!()` -//! [struct@m!{}] +//! [struct@m!{}] //~ WARN: unmatched disambiguator `struct` and suffix `!{}` //! [struct@m![]] //! [struct@f()] //~ WARN: unmatched disambiguator `struct` and suffix `()` //! [struct@m!] //~ WARN: unmatched disambiguator `struct` and suffix `!` //! //! [enum@m!()] //~ WARN: unmatched disambiguator `enum` and suffix `!()` -//! [enum@m!{}] +//! [enum@m!{}] //~ WARN: unmatched disambiguator `enum` and suffix `!{}` //! [enum@m![]] //! [enum@f()] //~ WARN: unmatched disambiguator `enum` and suffix `()` //! [enum@m!] //~ WARN: unmatched disambiguator `enum` and suffix `!` //! //! [trait@m!()] //~ WARN: unmatched disambiguator `trait` and suffix `!()` -//! [trait@m!{}] +//! [trait@m!{}] //~ WARN: unmatched disambiguator `trait` and suffix `!{}` //! [trait@m![]] //! [trait@f()] //~ WARN: unmatched disambiguator `trait` and suffix `()` //! [trait@m!] //~ WARN: unmatched disambiguator `trait` and suffix `!` //! //! [module@m!()] //~ WARN: unmatched disambiguator `module` and suffix `!()` -//! [module@m!{}] +//! [module@m!{}] //~ WARN: unmatched disambiguator `module` and suffix `!{}` //! [module@m![]] //! [module@f()] //~ WARN: unmatched disambiguator `module` and suffix `()` //! [module@m!] //~ WARN: unmatched disambiguator `module` and suffix `!` //! //! [mod@m!()] //~ WARN: unmatched disambiguator `mod` and suffix `!()` -//! [mod@m!{}] +//! [mod@m!{}] //~ WARN: unmatched disambiguator `mod` and suffix `!{}` //! [mod@m![]] //! [mod@f()] //~ WARN: unmatched disambiguator `mod` and suffix `()` //! [mod@m!] //~ WARN: unmatched disambiguator `mod` and suffix `!` //! //! [const@m!()] //~ WARN: unmatched disambiguator `const` and suffix `!()` -//! [const@m!{}] +//! [const@m!{}] //~ WARN: unmatched disambiguator `const` and suffix `!{}` //! [const@m![]] //! [const@f()] //~ WARN: incompatible link kind for `f` //! [const@m!] //~ WARN: unmatched disambiguator `const` and suffix `!` //! //! [constant@m!()] //~ WARN: unmatched disambiguator `constant` and suffix `!()` -//! [constant@m!{}] +//! [constant@m!{}] //~ WARN: unmatched disambiguator `constant` and suffix `!{}` //! [constant@m![]] //! [constant@f()] //~ WARN: incompatible link kind for `f` //! [constant@m!] //~ WARN: unmatched disambiguator `constant` and suffix `!` //! //! [static@m!()] //~ WARN: unmatched disambiguator `static` and suffix `!()` -//! [static@m!{}] +//! [static@m!{}] //~ WARN: unmatched disambiguator `static` and suffix `!{}` //! [static@m![]] //! [static@f()] //~ WARN: incompatible link kind for `f` //! [static@m!] //~ WARN: unmatched disambiguator `static` and suffix `!` //! //! [function@m!()] //~ WARN: unmatched disambiguator `function` and suffix `!()` -//! [function@m!{}] +//! [function@m!{}] //~ WARN: unmatched disambiguator `function` and suffix `!{}` //! [function@m![]] //! [function@f()] //! [function@m!] //~ WARN: unmatched disambiguator `function` and suffix `!` //! //! [fn@m!()] //~ WARN: unmatched disambiguator `fn` and suffix `!()` -//! [fn@m!{}] +//! [fn@m!{}] //~ WARN: unmatched disambiguator `fn` and suffix `!{}` //! [fn@m![]] //! [fn@f()] //! [fn@m!] //~ WARN: unmatched disambiguator `fn` and suffix `!` //! //! [method@m!()] //~ WARN: unmatched disambiguator `method` and suffix `!()` -//! [method@m!{}] +//! [method@m!{}] //~ WARN: unmatched disambiguator `method` and suffix `!{}` //! [method@m![]] //! [method@f()] //! [method@m!] //~ WARN: unmatched disambiguator `method` and suffix `!` @@ -74,13 +74,13 @@ //! [derive@m!] //~ WARN: incompatible link kind for `m` //! //! [type@m!()] //~ WARN: unmatched disambiguator `type` and suffix `!()` -//! [type@m!{}] +//! [type@m!{}] //~ WARN: unmatched disambiguator `type` and suffix `!{}` //! [type@m![]] //! [type@f()] //~ WARN: unmatched disambiguator `type` and suffix `()` //! [type@m!] //~ WARN: unmatched disambiguator `type` and suffix `!` //! //! [value@m!()] //~ WARN: unmatched disambiguator `value` and suffix `!()` -//! [value@m!{}] +//! [value@m!{}] //~ WARN: unmatched disambiguator `value` and suffix `!{}` //! [value@m![]] //! [value@f()] //! [value@m!] //~ WARN: unmatched disambiguator `value` and suffix `!` @@ -92,13 +92,13 @@ //! [macro@m!] //! //! [prim@m!()] //~ WARN: unmatched disambiguator `prim` and suffix `!()` -//! [prim@m!{}] +//! [prim@m!{}] //~ WARN: unmatched disambiguator `prim` and suffix `!{}` //! [prim@m![]] //! [prim@f()] //~ WARN: unmatched disambiguator `prim` and suffix `()` //! [prim@m!] //~ WARN: unmatched disambiguator `prim` and suffix `!` //! //! [primitive@m!()] //~ WARN: unmatched disambiguator `primitive` and suffix `!()` -//! [primitive@m!{}] +//! [primitive@m!{}] //~ WARN: unmatched disambiguator `primitive` and suffix `!{}` //! [primitive@m![]] //! [primitive@f()] //~ WARN: unmatched disambiguator `primitive` and suffix `()` //! [primitive@m!] //~ WARN: unmatched disambiguator `primitive` and suffix `!` diff --git a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr index f4e40a48873..18403385968 100644 --- a/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr +++ b/tests/rustdoc-ui/disambiguator-endswith-named-suffix.stderr @@ -7,6 +7,14 @@ LL | //! [struct@m!()] = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default +warning: unmatched disambiguator `struct` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:5:6 + | +LL | //! [struct@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `struct` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:7:6 | @@ -31,6 +39,14 @@ LL | //! [enum@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `enum` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:11:6 + | +LL | //! [enum@m!{}] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `enum` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:13:6 | @@ -55,6 +71,14 @@ LL | //! [trait@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `trait` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:17:6 + | +LL | //! [trait@m!{}] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `trait` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:19:6 | @@ -79,6 +103,14 @@ LL | //! [module@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `module` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:23:6 + | +LL | //! [module@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `module` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:25:6 | @@ -103,6 +135,14 @@ LL | //! [mod@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `mod` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:29:6 + | +LL | //! [mod@m!{}] + | ^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `mod` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:31:6 | @@ -127,6 +167,14 @@ LL | //! [const@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `const` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:35:6 + | +LL | //! [const@m!{}] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: incompatible link kind for `f` --> $DIR/disambiguator-endswith-named-suffix.rs:37:6 | @@ -155,6 +203,14 @@ LL | //! [constant@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `constant` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:41:6 + | +LL | //! [constant@m!{}] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: incompatible link kind for `f` --> $DIR/disambiguator-endswith-named-suffix.rs:43:6 | @@ -183,6 +239,14 @@ LL | //! [static@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `static` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:47:6 + | +LL | //! [static@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: incompatible link kind for `f` --> $DIR/disambiguator-endswith-named-suffix.rs:49:6 | @@ -211,6 +275,14 @@ LL | //! [function@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `function` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:53:6 + | +LL | //! [function@m!{}] + | ^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `function` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:56:6 | @@ -227,6 +299,14 @@ LL | //! [fn@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `fn` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:59:6 + | +LL | //! [fn@m!{}] + | ^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `fn` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:62:6 | @@ -243,6 +323,14 @@ LL | //! [method@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `method` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:65:6 + | +LL | //! [method@m!{}] + | ^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `method` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:68:6 | @@ -303,6 +391,14 @@ LL | //! [type@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `type` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:77:6 + | +LL | //! [type@m!{}] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `type` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:79:6 | @@ -327,6 +423,14 @@ LL | //! [value@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `value` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:83:6 + | +LL | //! [value@m!{}] + | ^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `value` and suffix `!` --> $DIR/disambiguator-endswith-named-suffix.rs:86:6 | @@ -351,6 +455,14 @@ LL | //! [prim@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `prim` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:95:6 + | +LL | //! [prim@m!{}] + | ^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `prim` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:97:6 | @@ -375,6 +487,14 @@ LL | //! [primitive@m!()] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators +warning: unmatched disambiguator `primitive` and suffix `!{}` + --> $DIR/disambiguator-endswith-named-suffix.rs:101:6 + | +LL | //! [primitive@m!{}] + | ^^^^^^^^^ + | + = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators + warning: unmatched disambiguator `primitive` and suffix `()` --> $DIR/disambiguator-endswith-named-suffix.rs:103:6 | @@ -391,5 +511,5 @@ LL | //! [primitive@m!] | = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators -warning: 46 warnings emitted +warning: 61 warnings emitted diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs index d2a922b2b62..1c5977b1bc3 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.rs +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -65,7 +65,7 @@ pub struct XLinkToCloneWithStartSpace; /// [x][struct@Clone ] //~ERROR link pub struct XLinkToCloneWithEndSpace; -/// [x][Clone\(\)] not URL-shaped enough +/// [x][Clone\(\)] //~ERROR link pub struct XLinkToCloneWithEscapedParens; /// [x][`Clone`] not URL-shaped enough diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index ad813f0f9b6..3a567e409ef 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -123,6 +123,14 @@ LL - /// [x][struct@Clone ] LL + /// [x][trait@Clone ] | +error: unresolved link to `Clone\(\)` + --> $DIR/weird-syntax.rs:68:9 + | +LL | /// [x][Clone\(\)] + | ^^^^^^^^^ no item named `Clone\(\)` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | @@ -299,5 +307,21 @@ LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` +error: unresolved link to `Clone` + --> $DIR/weird-syntax.rs:132:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolves to the trait `Clone`, which is not a function + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + +error: incompatible link kind for `Clone` + --> $DIR/weird-syntax.rs:137:9 + | +LL | /// The [cln][] link here will produce a plain text suggestion + | ^^^^^ this link resolved to a trait, which is not a struct + | + = help: to link to the trait, prefix with `trait@`: trait@Clone + error: aborting due to 27 previous errors diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs index 4f4590d45fc..81cd6c73d1c 100644 --- a/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.rs @@ -1,18 +1,24 @@ //@ check-pass -/// [`…foo`] [`…bar`] [`Err`] +/// [`…foo`] //~ WARN: unresolved link +/// [`…bar`] //~ WARN: unresolved link +/// [`Err`] pub struct Broken {} -/// [`…`] [`…`] [`Err`] +/// [`…`] //~ WARN: unresolved link +/// [`…`] //~ WARN: unresolved link +/// [`Err`] pub struct Broken2 {} -/// [`…`][…] [`…`][…] [`Err`] +/// [`…`][…] //~ WARN: unresolved link +/// [`…`][…] //~ WARN: unresolved link +/// [`Err`] pub struct Broken3 {} /// […………………………][Broken3] pub struct Broken4 {} -/// [Broken3][…………………………] +/// [Broken3][…………………………] //~ WARN: unresolved link pub struct Broken5 {} pub struct Err; diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr new file mode 100644 index 00000000000..0a5ff68b908 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-utf8.stderr @@ -0,0 +1,59 @@ +warning: unresolved link to `…foo` + --> $DIR/redundant_explicit_links-utf8.rs:3:7 + | +LL | /// [`…foo`] + | ^^^^ no item named `…foo` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default + +warning: unresolved link to `…bar` + --> $DIR/redundant_explicit_links-utf8.rs:4:7 + | +LL | /// [`…bar`] + | ^^^^ no item named `…bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:8:7 + | +LL | /// [`…`] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:9:7 + | +LL | /// [`…`] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:13:11 + | +LL | /// [`…`][…] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…` + --> $DIR/redundant_explicit_links-utf8.rs:14:11 + | +LL | /// [`…`][…] + | ^ no item named `…` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: unresolved link to `…………………………` + --> $DIR/redundant_explicit_links-utf8.rs:21:15 + | +LL | /// [Broken3][…………………………] + | ^^^^^^^^^^ no item named `…………………………` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +warning: 7 warnings emitted + -- cgit 1.4.1-3-g733a5 From 041348110e2e526a80efd5adfc2909c716cbb37f Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 18 Apr 2025 17:15:11 -0500 Subject: rustdoc: update tests to match new lint behavior --- tests/rustdoc-ui/bad-intra-doc.rs | 2 ++ tests/rustdoc-ui/intra-doc/weird-syntax.rs | 2 +- tests/rustdoc-ui/intra-doc/weird-syntax.stderr | 24 ------------------------ 3 files changed, 3 insertions(+), 25 deletions(-) (limited to 'tests') diff --git a/tests/rustdoc-ui/bad-intra-doc.rs b/tests/rustdoc-ui/bad-intra-doc.rs index 7bc55756e67..c24a848d898 100644 --- a/tests/rustdoc-ui/bad-intra-doc.rs +++ b/tests/rustdoc-ui/bad-intra-doc.rs @@ -10,4 +10,6 @@ /// attempted link to method: [`Foo.bar()`] //~ERROR unresolved link /// /// classic broken intra-doc link: [`Bar`] //~ERROR unresolved link +/// +/// no backticks, so we let this one slide: [Foo.bar()] pub struct Foo; diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs index 1c5977b1bc3..9f18f67fc44 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.rs +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -65,7 +65,7 @@ pub struct XLinkToCloneWithStartSpace; /// [x][struct@Clone ] //~ERROR link pub struct XLinkToCloneWithEndSpace; -/// [x][Clone\(\)] //~ERROR link +/// [x][Clone\(\)] pub struct XLinkToCloneWithEscapedParens; /// [x][`Clone`] not URL-shaped enough diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index 3a567e409ef..ad813f0f9b6 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -123,14 +123,6 @@ LL - /// [x][struct@Clone ] LL + /// [x][trait@Clone ] | -error: unresolved link to `Clone\(\)` - --> $DIR/weird-syntax.rs:68:9 - | -LL | /// [x][Clone\(\)] - | ^^^^^^^^^ no item named `Clone\(\)` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | @@ -307,21 +299,5 @@ LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: unresolved link to `Clone` - --> $DIR/weird-syntax.rs:132:9 - | -LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolves to the trait `Clone`, which is not a function - | - = help: to link to the trait, prefix with `trait@`: trait@Clone - -error: incompatible link kind for `Clone` - --> $DIR/weird-syntax.rs:137:9 - | -LL | /// The [cln][] link here will produce a plain text suggestion - | ^^^^^ this link resolved to a trait, which is not a struct - | - = help: to link to the trait, prefix with `trait@`: trait@Clone - error: aborting due to 27 previous errors -- cgit 1.4.1-3-g733a5 From 6a7d4882a207890c75ca09ce19810d90ac9cfde6 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 18 Apr 2025 20:23:05 -0500 Subject: rustdoc::broken_intra_doc_links: only be lenient with shortcut links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit collapsed links and reference links have a pretty particular syntax, it seems unlikely they would show up on accident. Co-authored-by: León Orell Valerian Liehr --- src/librustdoc/passes/collect_intra_doc_links.rs | 27 +++++++++++++++++++----- tests/rustdoc-ui/intra-doc/weird-syntax.rs | 2 +- tests/rustdoc-ui/intra-doc/weird-syntax.stderr | 10 ++++++++- 3 files changed, 32 insertions(+), 7 deletions(-) (limited to 'tests') diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 08f0d4015fc..c9fa3a4837f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -944,9 +944,10 @@ fn preprocess_link( // certain link kinds cannot have their path be urls, // so they should not be ignored, no matter how much they look like urls. // e.g. [https://example.com/] is not a link to example.com. - let can_be_url = ori_link.kind != LinkType::ShortcutUnknown - && ori_link.kind != LinkType::CollapsedUnknown - && ori_link.kind != LinkType::ReferenceUnknown; + let can_be_url = !matches!( + ori_link.kind, + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown | LinkType::ReferenceUnknown + ); // [] is mostly likely not supposed to be a link if ori_link.link.is_empty() { @@ -996,9 +997,25 @@ fn preprocess_link( } }; - // If there's no backticks, be lenient revert to old behavior. + // If there's no backticks, be lenient and revert to the old behavior. // This is to prevent churn by linting on stuff that isn't meant to be a link. - if (can_be_url || !ori_link.link.contains('`')) && should_ignore_link(path_str) { + // only shortcut links have simple enough syntax that they + // are likely to be written accidentally, collapsed and reference links + // need 4 metachars, and reference links will not usually use + // backticks in the reference name. + // therefore, only shortcut syntax gets the lenient behavior. + // + // here's a truth table for how link kinds that cannot be urls are handled: + // + // |-------------------------------------------------------| + // | | is shortcut link | not shortcut link | + // |--------------|--------------------|-------------------| + // | has backtick | never ignore | never ignore | + // | no backtick | ignore if url-like | never ignore | + // |-------------------------------------------------------| + let ignore_urllike = + can_be_url || (ori_link.kind == LinkType::ShortcutUnknown && !ori_link.link.contains('`')); + if ignore_urllike && should_ignore_link(path_str) { return None; } diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.rs b/tests/rustdoc-ui/intra-doc/weird-syntax.rs index 9f18f67fc44..1c5977b1bc3 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.rs +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.rs @@ -65,7 +65,7 @@ pub struct XLinkToCloneWithStartSpace; /// [x][struct@Clone ] //~ERROR link pub struct XLinkToCloneWithEndSpace; -/// [x][Clone\(\)] +/// [x][Clone\(\)] //~ERROR link pub struct XLinkToCloneWithEscapedParens; /// [x][`Clone`] not URL-shaped enough diff --git a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr index ad813f0f9b6..7f2fc1fe625 100644 --- a/tests/rustdoc-ui/intra-doc/weird-syntax.stderr +++ b/tests/rustdoc-ui/intra-doc/weird-syntax.stderr @@ -123,6 +123,14 @@ LL - /// [x][struct@Clone ] LL + /// [x][trait@Clone ] | +error: unresolved link to `Clone\(\)` + --> $DIR/weird-syntax.rs:68:9 + | +LL | /// [x][Clone\(\)] + | ^^^^^^^^^ no item named `Clone\(\)` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + error: unresolved link to `Clone` --> $DIR/weird-syntax.rs:74:9 | @@ -299,5 +307,5 @@ LL | /// - [`SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER`]: the | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: aborting due to 27 previous errors +error: aborting due to 28 previous errors -- cgit 1.4.1-3-g733a5 From bd85df192d07660511b711cd7d4cae5b5a85577a Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 19 Apr 2025 10:51:40 -0500 Subject: move bad-intra-doc test into intra-doc dir --- tests/rustdoc-ui/bad-intra-doc.rs | 15 ------------ tests/rustdoc-ui/bad-intra-doc.stderr | 31 ------------------------- tests/rustdoc-ui/intra-doc/bad-intra-doc.rs | 15 ++++++++++++ tests/rustdoc-ui/intra-doc/bad-intra-doc.stderr | 31 +++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 46 deletions(-) delete mode 100644 tests/rustdoc-ui/bad-intra-doc.rs delete mode 100644 tests/rustdoc-ui/bad-intra-doc.stderr create mode 100644 tests/rustdoc-ui/intra-doc/bad-intra-doc.rs create mode 100644 tests/rustdoc-ui/intra-doc/bad-intra-doc.stderr (limited to 'tests') diff --git a/tests/rustdoc-ui/bad-intra-doc.rs b/tests/rustdoc-ui/bad-intra-doc.rs deleted file mode 100644 index c24a848d898..00000000000 --- a/tests/rustdoc-ui/bad-intra-doc.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![no_std] -#![deny(rustdoc::broken_intra_doc_links)] - -// regression test for https://github.com/rust-lang/rust/issues/54191 - -/// this is not a link to [`example.com`] //~ERROR unresolved link -/// -/// this link [`has spaces in it`]. -/// -/// attempted link to method: [`Foo.bar()`] //~ERROR unresolved link -/// -/// classic broken intra-doc link: [`Bar`] //~ERROR unresolved link -/// -/// no backticks, so we let this one slide: [Foo.bar()] -pub struct Foo; diff --git a/tests/rustdoc-ui/bad-intra-doc.stderr b/tests/rustdoc-ui/bad-intra-doc.stderr deleted file mode 100644 index 9533792b35b..00000000000 --- a/tests/rustdoc-ui/bad-intra-doc.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: unresolved link to `example.com` - --> $DIR/bad-intra-doc.rs:6:29 - | -LL | /// this is not a link to [`example.com`] - | ^^^^^^^^^^^ no item named `example.com` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -note: the lint level is defined here - --> $DIR/bad-intra-doc.rs:2:9 - | -LL | #![deny(rustdoc::broken_intra_doc_links)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: unresolved link to `Foo.bar` - --> $DIR/bad-intra-doc.rs:10:33 - | -LL | /// attempted link to method: [`Foo.bar()`] - | ^^^^^^^^^ no item named `Foo.bar` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - -error: unresolved link to `Bar` - --> $DIR/bad-intra-doc.rs:12:38 - | -LL | /// classic broken intra-doc link: [`Bar`] - | ^^^ no item named `Bar` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - -error: aborting due to 3 previous errors - diff --git a/tests/rustdoc-ui/intra-doc/bad-intra-doc.rs b/tests/rustdoc-ui/intra-doc/bad-intra-doc.rs new file mode 100644 index 00000000000..c24a848d898 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/bad-intra-doc.rs @@ -0,0 +1,15 @@ +#![no_std] +#![deny(rustdoc::broken_intra_doc_links)] + +// regression test for https://github.com/rust-lang/rust/issues/54191 + +/// this is not a link to [`example.com`] //~ERROR unresolved link +/// +/// this link [`has spaces in it`]. +/// +/// attempted link to method: [`Foo.bar()`] //~ERROR unresolved link +/// +/// classic broken intra-doc link: [`Bar`] //~ERROR unresolved link +/// +/// no backticks, so we let this one slide: [Foo.bar()] +pub struct Foo; diff --git a/tests/rustdoc-ui/intra-doc/bad-intra-doc.stderr b/tests/rustdoc-ui/intra-doc/bad-intra-doc.stderr new file mode 100644 index 00000000000..9533792b35b --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/bad-intra-doc.stderr @@ -0,0 +1,31 @@ +error: unresolved link to `example.com` + --> $DIR/bad-intra-doc.rs:6:29 + | +LL | /// this is not a link to [`example.com`] + | ^^^^^^^^^^^ no item named `example.com` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` +note: the lint level is defined here + --> $DIR/bad-intra-doc.rs:2:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `Foo.bar` + --> $DIR/bad-intra-doc.rs:10:33 + | +LL | /// attempted link to method: [`Foo.bar()`] + | ^^^^^^^^^ no item named `Foo.bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: unresolved link to `Bar` + --> $DIR/bad-intra-doc.rs:12:38 + | +LL | /// classic broken intra-doc link: [`Bar`] + | ^^^ no item named `Bar` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + +error: aborting due to 3 previous errors + -- cgit 1.4.1-3-g733a5 From 534b1355efe3fc0dc962634773b0f6b1474bad13 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 26 Jul 2025 11:41:25 +0200 Subject: tests: Add test for basic line-by-line stepping in a debugger Let's wait with lldb testing until the test works properly with gdb. --- tests/debuginfo/basic-stepping.rs | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/debuginfo/basic-stepping.rs (limited to 'tests') diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs new file mode 100644 index 00000000000..6e1344d22a5 --- /dev/null +++ b/tests/debuginfo/basic-stepping.rs @@ -0,0 +1,47 @@ +//! Test that stepping through a simple program with a debugger one line at a +//! time works intuitively, e.g. that `next` takes you to the next source line. +//! Regression test for . + +//@ ignore-aarch64: Doesn't work yet. +//@ compile-flags: -g + +// gdb-command: run +// FIXME(#97083): Should we be able to break on initialization of zero-sized types? +// FIXME(#97083): Right now the first breakable line is: +// gdb-check: let mut c = 27; +// gdb-command: next +// gdb-check: let d = c = 99; +// gdb-command: next +// FIXME(#33013): gdb-check: let e = "hi bob"; +// FIXME(#33013): gdb-command: next +// FIXME(#33013): gdb-check: let f = b"hi bob"; +// FIXME(#33013): gdb-command: next +// FIXME(#33013): gdb-check: let g = b'9'; +// FIXME(#33013): gdb-command: next +// FIXME(#33013): gdb-check: let h = ["whatever"; 8]; +// FIXME(#33013): gdb-command: next +// gdb-check: let i = [1,2,3,4]; +// gdb-command: next +// gdb-check: let j = (23, "hi"); +// gdb-command: next +// gdb-check: let k = 2..3; +// gdb-command: next +// gdb-check: let l = &i[k]; +// gdb-command: next +// gdb-check: let m: *const() = &a; + +fn main () { + let a = (); // #break + let b : [i32; 0] = []; + let mut c = 27; + let d = c = 99; + let e = "hi bob"; + let f = b"hi bob"; + let g = b'9'; + let h = ["whatever"; 8]; + let i = [1,2,3,4]; + let j = (23, "hi"); + let k = 2..3; + let l = &i[k]; + let m: *const() = &a; +} -- cgit 1.4.1-3-g733a5 From a1f5a6d781d65949fe08c149a695d4cd926cc755 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 26 Jul 2025 00:47:33 +0000 Subject: Perform check_private_in_public by module. --- compiler/rustc_interface/src/passes.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 7 ++- compiler/rustc_privacy/src/lib.rs | 4 +- tests/ui/privacy/private-in-public-warn.stderr | 72 +++++++++++++------------- tests/ui/privacy/projections.stderr | 26 +++++----- 5 files changed, 59 insertions(+), 54 deletions(-) (limited to 'tests') diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fb6897c7d89..aaabf7df42d 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1147,7 +1147,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { parallel!( { - tcx.ensure_ok().check_private_in_public(()); + tcx.par_hir_for_each_module(|module| { + tcx.ensure_ok().check_private_in_public(module) + }) }, { tcx.par_hir_for_each_module(|module| { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 587349d4cf4..7a625f4fee7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1390,8 +1390,11 @@ rustc_queries! { eval_always desc { "checking effective visibilities" } } - query check_private_in_public(_: ()) { - desc { "checking for private elements in public interfaces" } + query check_private_in_public(module_def_id: LocalModDefId) { + desc { |tcx| + "checking for private elements in public interfaces for {}", + describe_as_module(module_def_id, tcx) + } } query reachable_set(_: ()) -> &'tcx LocalDefIdSet { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 6fd2b7fc12f..1a062c63a6f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1854,12 +1854,12 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { tcx.arena.alloc(visitor.effective_visibilities) } -fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { +fn check_private_in_public(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { let effective_visibilities = tcx.effective_visibilities(()); // Check for private types in public interfaces. let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities }; - let crate_items = tcx.hir_crate_items(()); + let crate_items = tcx.hir_module_items(module_def_id); for id in crate_items.free_items() { checker.check_item(id); } diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr index 86f6be85a07..edcffaf6b70 100644 --- a/tests/ui/privacy/private-in-public-warn.stderr +++ b/tests/ui/privacy/private-in-public-warn.stderr @@ -93,6 +93,42 @@ LL | struct Priv; LL | type Alias = Priv; | ^^^^^^^^^^ can't leak private type +error: type `types::Priv` is more private than the item `types::ES` + --> $DIR/private-in-public-warn.rs:27:9 + | +LL | pub static ES: Priv; + | ^^^^^^^^^^^^^^^^^^^ static `types::ES` is reachable at visibility `pub(crate)` + | +note: but type `types::Priv` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:9:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + +error: type `types::Priv` is more private than the item `types::ef1` + --> $DIR/private-in-public-warn.rs:28:9 + | +LL | pub fn ef1(arg: Priv); + | ^^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)` + | +note: but type `types::Priv` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:9:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + +error: type `types::Priv` is more private than the item `types::ef2` + --> $DIR/private-in-public-warn.rs:29:9 + | +LL | pub fn ef2() -> Priv; + | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)` + | +note: but type `types::Priv` is only usable at visibility `pub(self)` + --> $DIR/private-in-public-warn.rs:9:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + error: trait `traits::PrivTr` is more private than the item `traits::Alias` --> $DIR/private-in-public-warn.rs:42:5 | @@ -359,42 +395,6 @@ note: but type `Priv2` is only usable at visibility `pub(self)` LL | struct Priv2; | ^^^^^^^^^^^^ -error: type `types::Priv` is more private than the item `types::ES` - --> $DIR/private-in-public-warn.rs:27:9 - | -LL | pub static ES: Priv; - | ^^^^^^^^^^^^^^^^^^^ static `types::ES` is reachable at visibility `pub(crate)` - | -note: but type `types::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:9:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - -error: type `types::Priv` is more private than the item `types::ef1` - --> $DIR/private-in-public-warn.rs:28:9 - | -LL | pub fn ef1(arg: Priv); - | ^^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)` - | -note: but type `types::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:9:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - -error: type `types::Priv` is more private than the item `types::ef2` - --> $DIR/private-in-public-warn.rs:29:9 - | -LL | pub fn ef2() -> Priv; - | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)` - | -note: but type `types::Priv` is only usable at visibility `pub(self)` - --> $DIR/private-in-public-warn.rs:9:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - warning: bounds on generic parameters in type aliases are not enforced --> $DIR/private-in-public-warn.rs:42:23 | diff --git a/tests/ui/privacy/projections.stderr b/tests/ui/privacy/projections.stderr index 010d77998e3..addb6a075a2 100644 --- a/tests/ui/privacy/projections.stderr +++ b/tests/ui/privacy/projections.stderr @@ -1,16 +1,3 @@ -warning: type `Priv` is more private than the item `Leak` - --> $DIR/projections.rs:3:5 - | -LL | pub type Leak = Priv; - | ^^^^^^^^^^^^^ type alias `Leak` is reachable at visibility `pub(crate)` - | -note: but type `Priv` is only usable at visibility `pub(self)` - --> $DIR/projections.rs:2:5 - | -LL | struct Priv; - | ^^^^^^^^^^^ - = note: `#[warn(private_interfaces)]` on by default - error[E0446]: private type `Priv` in public interface --> $DIR/projections.rs:24:5 | @@ -29,6 +16,19 @@ LL | struct Priv; LL | type A = T::A; | ^^^^^^^^^^^^^^^^ can't leak private type +warning: type `Priv` is more private than the item `Leak` + --> $DIR/projections.rs:3:5 + | +LL | pub type Leak = Priv; + | ^^^^^^^^^^^^^ type alias `Leak` is reachable at visibility `pub(crate)` + | +note: but type `Priv` is only usable at visibility `pub(self)` + --> $DIR/projections.rs:2:5 + | +LL | struct Priv; + | ^^^^^^^^^^^ + = note: `#[warn(private_interfaces)]` on by default + error: type `Priv` is private --> $DIR/projections.rs:14:15 | -- cgit 1.4.1-3-g733a5 From 91bccd6ba8861fd91bcf0f682f50f78fdb38a450 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 24 Jul 2025 14:06:58 +0200 Subject: use `minicore` for fortanix assembly tests --- ...x86_64-fortanix-unknown-sgx-lvi-generic-load.rs | 31 +++++++++++++--------- .../x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs | 14 +++++++--- ..._64-fortanix-unknown-sgx-lvi-inline-assembly.rs | 28 ++++++++++--------- 3 files changed, 46 insertions(+), 27 deletions(-) (limited to 'tests') diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs index f5e2f18e68e..2892ff2882a 100644 --- a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -1,17 +1,24 @@ -// Test LVI load hardening on SGX enclave code +// Test LVI load hardening on SGX enclave code, specifically that `ret` is rewritten. +//@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx +//@ compile-flags: --target x86_64-fortanix-unknown-sgx -Copt-level=0 +//@ needs-llvm-components: x86 + +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; #[no_mangle] -pub extern "C" fn plus_one(r: &mut u64) { - *r = *r + 1; +pub extern "C" fn dereference(a: &mut u64) -> u64 { + // CHECK-LABEL: dereference + // CHECK: lfence + // CHECK: mov + // CHECK: popq [[REGISTER:%[a-z]+]] + // CHECK-NEXT: lfence + // CHECK-NEXT: jmpq *[[REGISTER]] + *a } - -// CHECK: plus_one -// CHECK: lfence -// CHECK-NEXT: incq -// CHECK: popq [[REGISTER:%[a-z]+]] -// CHECK-NEXT: lfence -// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs index f16d68fa255..a0cedc3bc2d 100644 --- a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -1,12 +1,20 @@ // Test LVI ret hardening on generic rust code +//@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx +//@ compile-flags: --target x86_64-fortanix-unknown-sgx +//@ needs-llvm-components: x86 + +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; #[no_mangle] pub extern "C" fn myret() {} -// CHECK: myret: +// CHECK-LABEL: myret: // CHECK: popq [[REGISTER:%[a-z]+]] // CHECK-NEXT: lfence // CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs index a729df8e166..215fb4b804a 100644 --- a/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs +++ b/tests/assembly-llvm/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -1,13 +1,22 @@ // Test LVI load hardening on SGX inline assembly code +//@ add-core-stubs //@ assembly-output: emit-asm -//@ compile-flags: --crate-type staticlib -//@ only-x86_64-fortanix-unknown-sgx +//@ compile-flags: --target x86_64-fortanix-unknown-sgx +//@ needs-llvm-components: x86 -use std::arch::asm; +#![feature(no_core, lang_items, f16)] +#![crate_type = "lib"] +#![no_core] + +extern crate minicore; +use minicore::*; #[no_mangle] pub extern "C" fn get(ptr: *const u64) -> u64 { + // CHECK-LABEL: get + // CHECK: movq + // CHECK-NEXT: lfence let value: u64; unsafe { asm!("mov {}, [{}]", @@ -17,18 +26,13 @@ pub extern "C" fn get(ptr: *const u64) -> u64 { value } -// CHECK: get -// CHECK: movq -// CHECK-NEXT: lfence - #[no_mangle] pub extern "C" fn myret() { + // CHECK-LABEL: myret + // CHECK: shlq $0, (%rsp) + // CHECK-NEXT: lfence + // CHECK-NEXT: retq unsafe { asm!("ret"); } } - -// CHECK: myret -// CHECK: shlq $0, (%rsp) -// CHECK-NEXT: lfence -// CHECK-NEXT: retq -- cgit 1.4.1-3-g733a5 From 8b90847416d5678d784942b46c05f8c97caef83d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 24 Jul 2025 14:07:32 +0200 Subject: update fortanix run-make test Make it more idiomatic with the new run-make infra --- .../x86_64-fortanix-unknown-sgx-lvi/rmake.rs | 43 ++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'tests') diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs index e58762aeb6d..89754cdaf90 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs @@ -13,42 +13,56 @@ //@ only-x86_64-fortanix-unknown-sgx -use run_make_support::{cmd, cwd, llvm_filecheck, llvm_objdump, regex, set_current_dir, target}; +use run_make_support::{ + cargo, cwd, llvm_filecheck, llvm_objdump, regex, run, set_current_dir, target, +}; fn main() { - let main_dir = cwd(); - set_current_dir("enclave"); - // HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. - // These come from the top-level Rust workspace, that this crate is not a - // member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - cmd("cargo") - .env("RUSTC_BOOTSTRAP", "1") + cargo() .arg("-v") - .arg("run") + .arg("build") .arg("--target") .arg(target()) + .current_dir("enclave") + .env("CC_x86_64_fortanix_unknown_sgx", "clang") + .env( + "CFLAGS_x86_64_fortanix_unknown_sgx", + "-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening", + ) + .env("CXX_x86_64_fortanix_unknown_sgx", "clang++") + .env( + "CXXFLAGS_x86_64_fortanix_unknown_sgx", + "-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening", + ) .run(); - set_current_dir(&main_dir); - // Rust has various ways of adding code to a binary: + + // Rust has several ways of including machine code into a binary: + // // - Rust code // - Inline assembly // - Global assembly // - C/C++ code compiled as part of Rust crates - // For those different kinds, we do have very small code examples that should be - // mitigated in some way. Mostly we check that ret instructions should no longer be present. + // + // For each of those, check that the mitigations are applied. Mostly we check + // that ret instructions are no longer present. + + // Check that normal rust code has the right mitigations. check("unw_getcontext", "unw_getcontext.checks"); check("__libunwind_Registers_x86_64_jumpto", "jumpto.checks"); check("std::io::stdio::_print::[[:alnum:]]+", "print.with_frame_pointers.checks"); + // Check that rust global assembly has the right mitigations. check("rust_plus_one_global_asm", "rust_plus_one_global_asm.checks"); + // Check that C code compiled using the `cc` crate has the right mitigations. check("cc_plus_one_c", "cc_plus_one_c.checks"); check("cc_plus_one_c_asm", "cc_plus_one_c_asm.checks"); check("cc_plus_one_cxx", "cc_plus_one_cxx.checks"); check("cc_plus_one_cxx_asm", "cc_plus_one_cxx_asm.checks"); check("cc_plus_one_asm", "cc_plus_one_asm.checks"); + // Check that C++ code compiled using the `cc` crate has the right mitigations. check("cmake_plus_one_c", "cmake_plus_one_c.checks"); check("cmake_plus_one_c_asm", "cmake_plus_one_c_asm.checks"); check("cmake_plus_one_c_global_asm", "cmake_plus_one_c_global_asm.checks"); @@ -71,8 +85,7 @@ fn check(func_re: &str, mut checks: &str) { .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") .args(&["--demangle", &format!("--disassemble-symbols={func}")]) .run() - .stdout_utf8(); - let dump = dump.as_bytes(); + .stdout(); // Unique case, must succeed at one of two possible tests. // This is because frame pointers are optional, and them being enabled requires -- cgit 1.4.1-3-g733a5 From 6c7dc05f7d1f000cdb7de2390c8532545129e32d Mon Sep 17 00:00:00 2001 From: Caiweiran Date: Mon, 28 Jul 2025 11:58:38 +0000 Subject: Fix tests/codegen-llvm/simd/extract-insert-dyn.rs test failure on riscv64 --- tests/codegen-llvm/simd/extract-insert-dyn.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'tests') diff --git a/tests/codegen-llvm/simd/extract-insert-dyn.rs b/tests/codegen-llvm/simd/extract-insert-dyn.rs index 729f0145314..9c17b82e553 100644 --- a/tests/codegen-llvm/simd/extract-insert-dyn.rs +++ b/tests/codegen-llvm/simd/extract-insert-dyn.rs @@ -5,7 +5,8 @@ repr_simd, arm_target_feature, mips_target_feature, - s390x_target_feature + s390x_target_feature, + riscv_target_feature )] #![no_std] #![crate_type = "lib"] @@ -25,97 +26,105 @@ pub struct u32x16([u32; 16]); pub struct i8x16([i8; 16]); // CHECK-LABEL: dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 %idx +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 %idx #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { simd_extract_dyn(x, idx) } // CHECK-LABEL: literal_dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, 7) } // CHECK-LABEL: const_dyn_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, const { 3 + 4 }) } // CHECK-LABEL: const_simd_extract -// CHECK: extractelement <16 x i8> %x, i32 7 +// CHECK: extractelement <16 x i8> %[[TEMP:.+]], i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { simd_extract(x, const { 3 + 4 }) } // CHECK-LABEL: dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 %idx #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { simd_insert_dyn(x, idx, e) } // CHECK-LABEL: literal_dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, 7, e) } // CHECK-LABEL: const_dyn_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, const { 3 + 4 }, e) } // CHECK-LABEL: const_simd_insert -// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7 +// CHECK: insertelement <16 x i8> %[[TEMP:.+]], i8 %e, i32 7 #[no_mangle] #[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))] #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] #[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] +#[cfg_attr(target_arch = "riscv64", target_feature(enable = "v"))] unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert(x, const { 3 + 4 }, e) } -- cgit 1.4.1-3-g733a5 From 0e53d8533bf0bb8d6bc59bb000fe7cc7a361902e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 16 Jun 2025 15:25:31 +0000 Subject: Fortify RemoveUnneededDrops test. --- ...ops.cannot_opt_generic.RemoveUnneededDrops.diff | 15 ++++++++ ...pt_generic.RemoveUnneededDrops.panic-abort.diff | 26 -------------- ...t_generic.RemoveUnneededDrops.panic-unwind.diff | 30 ---------------- ...nneeded_drops.dont_opt.RemoveUnneededDrops.diff | 15 ++++++++ ...s.dont_opt.RemoveUnneededDrops.panic-abort.diff | 26 -------------- ....dont_opt.RemoveUnneededDrops.panic-unwind.diff | 30 ---------------- ...ove_unneeded_drops.opt.RemoveUnneededDrops.diff | 15 ++++++++ ..._drops.opt.RemoveUnneededDrops.panic-abort.diff | 26 -------------- ...drops.opt.RemoveUnneededDrops.panic-unwind.diff | 26 -------------- ...drops.opt_generic_copy.RemoveUnneededDrops.diff | 15 ++++++++ ...neric_copy.RemoveUnneededDrops.panic-abort.diff | 26 -------------- ...eric_copy.RemoveUnneededDrops.panic-unwind.diff | 26 -------------- tests/mir-opt/remove_unneeded_drops.rs | 40 ++++++++++++++++++---- 13 files changed, 94 insertions(+), 222 deletions(-) create mode 100644 tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff create mode 100644 tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff create mode 100644 tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff create mode 100644 tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff delete mode 100644 tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff (limited to 'tests') diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff new file mode 100644 index 00000000000..52832e73905 --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `cannot_opt_generic` before RemoveUnneededDrops ++ // MIR for `cannot_opt_generic` after RemoveUnneededDrops + + fn cannot_opt_generic(_1: T) -> () { + let mut _0: (); + + bb0: { + drop(_1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index 0c73602bec8..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `cannot_opt_generic` before RemoveUnneededDrops -+ // MIR for `cannot_opt_generic` after RemoveUnneededDrops - - fn cannot_opt_generic(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index 59cce9fbcdd..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `cannot_opt_generic` before RemoveUnneededDrops -+ // MIR for `cannot_opt_generic` after RemoveUnneededDrops - - fn cannot_opt_generic(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb2, unwind: bb1]; - } - - bb1 (cleanup): { - resume; - } - - bb2: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff new file mode 100644 index 00000000000..3d67cada5dd --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `dont_opt` before RemoveUnneededDrops ++ // MIR for `dont_opt` after RemoveUnneededDrops + + fn dont_opt(_1: Vec) -> () { + let mut _0: (); + + bb0: { + drop(_1) -> [return: bb1, unwind unreachable]; + } + + bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index 428b366b5a6..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `dont_opt` before RemoveUnneededDrops -+ // MIR for `dont_opt` after RemoveUnneededDrops - - fn dont_opt(_1: Vec) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: std::vec::Vec; - scope 1 (inlined std::mem::drop::>) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index 445c1f82a96..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,30 +0,0 @@ -- // MIR for `dont_opt` before RemoveUnneededDrops -+ // MIR for `dont_opt` after RemoveUnneededDrops - - fn dont_opt(_1: Vec) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: std::vec::Vec; - scope 1 (inlined std::mem::drop::>) { - } - - bb0: { - nop; - StorageLive(_3); - _3 = move _1; - drop(_3) -> [return: bb2, unwind: bb1]; - } - - bb1 (cleanup): { - resume; - } - - bb2: { - StorageDead(_3); - nop; - nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff new file mode 100644 index 00000000000..cb7e58ca1a1 --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `opt` before RemoveUnneededDrops ++ // MIR for `opt` after RemoveUnneededDrops + + fn opt(_1: bool) -> () { + let mut _0: (); + + bb0: { +- drop(_1) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index 01eb6d4901f..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt` before RemoveUnneededDrops -+ // MIR for `opt` after RemoveUnneededDrops - - fn opt(_1: bool) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: bool; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index c2c3cb76e83..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt` before RemoveUnneededDrops -+ // MIR for `opt` after RemoveUnneededDrops - - fn opt(_1: bool) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: bool; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind continue]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff new file mode 100644 index 00000000000..1e166eee9fb --- /dev/null +++ b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -0,0 +1,15 @@ +- // MIR for `opt_generic_copy` before RemoveUnneededDrops ++ // MIR for `opt_generic_copy` after RemoveUnneededDrops + + fn opt_generic_copy(_1: T) -> () { + let mut _0: (); + + bb0: { +- drop(_1) -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { + return; + } + } + diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff deleted file mode 100644 index a82ede6196e..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-abort.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt_generic_copy` before RemoveUnneededDrops -+ // MIR for `opt_generic_copy` after RemoveUnneededDrops - - fn opt_generic_copy(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind unreachable]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff deleted file mode 100644 index 6e7c9ead740..00000000000 --- a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `opt_generic_copy` before RemoveUnneededDrops -+ // MIR for `opt_generic_copy` after RemoveUnneededDrops - - fn opt_generic_copy(_1: T) -> () { - debug x => _1; - let mut _0: (); - let _2: (); - let mut _3: T; - scope 1 (inlined std::mem::drop::) { - } - - bb0: { -- nop; - StorageLive(_3); - _3 = copy _1; -- drop(_3) -> [return: bb1, unwind continue]; -- } -- -- bb1: { - StorageDead(_3); -- nop; -- nop; - return; - } - } - diff --git a/tests/mir-opt/remove_unneeded_drops.rs b/tests/mir-opt/remove_unneeded_drops.rs index cad79e0aa0c..49dc611838e 100644 --- a/tests/mir-opt/remove_unneeded_drops.rs +++ b/tests/mir-opt/remove_unneeded_drops.rs @@ -1,28 +1,56 @@ -// skip-filecheck -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ test-mir-pass: RemoveUnneededDrops + +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + // EMIT_MIR remove_unneeded_drops.opt.RemoveUnneededDrops.diff +#[custom_mir(dialect = "runtime")] fn opt(x: bool) { - drop(x); + // CHECK-LABEL: fn opt( + // CHECK-NOT: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } // EMIT_MIR remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +#[custom_mir(dialect = "runtime")] fn dont_opt(x: Vec) { - drop(x); + // CHECK-LABEL: fn dont_opt( + // CHECK: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } // EMIT_MIR remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +#[custom_mir(dialect = "runtime")] fn opt_generic_copy(x: T) { - drop(x); + // CHECK-LABEL: fn opt_generic_copy( + // CHECK-NOT: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } // EMIT_MIR remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff // since the pass is not running on monomorphisized code, // we can't (but probably should) optimize this +#[custom_mir(dialect = "runtime")] fn cannot_opt_generic(x: T) { - drop(x); + // CHECK-LABEL: fn cannot_opt_generic( + // CHECK: drop( + mir! { + { Drop(x, ReturnTo(bb1), UnwindUnreachable()) } + bb1 = { Return() } + } } fn main() { + // CHECK-LABEL: fn main( opt(true); opt_generic_copy(42); cannot_opt_generic(42); -- cgit 1.4.1-3-g733a5 From 4220587c2232e237a0c39a2c64b0bf046799434a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Tue, 29 Jul 2025 18:30:48 -0700 Subject: `AlignmentEnum` should just be `repr(usize)` now Since it's cfg'd instead of type-aliased --- library/core/src/ptr/alignment.rs | 8 +++++--- ...e.generic_in_place.PreCodegen.after.32bit.panic-abort.mir | 12 ++++-------- ....generic_in_place.PreCodegen.after.32bit.panic-unwind.mir | 12 ++++-------- ...e.generic_in_place.PreCodegen.after.64bit.panic-abort.mir | 12 ++++-------- ....generic_in_place.PreCodegen.after.64bit.panic-unwind.mir | 12 ++++-------- tests/mir-opt/pre-codegen/drop_boxed_slice.rs | 3 +-- 6 files changed, 22 insertions(+), 37 deletions(-) (limited to 'tests') diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index bd5b4e21baa..402634e49b3 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,3 +1,5 @@ +#![allow(clippy::enum_clike_unportable_variant)] + use crate::num::NonZero; use crate::ub_checks::assert_unsafe_precondition; use crate::{cmp, fmt, hash, mem, num}; @@ -241,7 +243,7 @@ impl const Default for Alignment { #[cfg(target_pointer_width = "16")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u16)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, @@ -263,7 +265,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "32")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u32)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, @@ -301,7 +303,7 @@ enum AlignmentEnum { #[cfg(target_pointer_width = "64")] #[derive(Copy, Clone, PartialEq, Eq)] -#[repr(u64)] +#[repr(usize)] enum AlignmentEnum { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 2777bba893b..ba6ce0ee528 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u32; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 2777bba893b..ba6ce0ee528 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u32; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 2be0a478c85..ba6ce0ee528 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u64; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 2be0a478c85..ba6ce0ee528 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _11: (); scope 3 { let _8: std::ptr::alignment::AlignmentEnum; scope 4 { @@ -31,12 +31,11 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; + let mut _10: usize; scope 22 (inlined Layout::size) { } scope 23 (inlined Layout::align) { scope 24 (inlined std::ptr::Alignment::as_usize) { - let mut _10: u64; } } } @@ -87,16 +86,13 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb2: { StorageLive(_9); _9 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); StorageLive(_10); _10 = discriminant(_8); - _11 = move _10 as usize (IntToInt); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _9, move _5, move _11) -> [return: bb3, unwind unreachable]; + _11 = alloc::alloc::__rust_dealloc(move _9, move _5, move _10) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_11); + StorageDead(_10); StorageDead(_9); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs index 11fb7afef0f..9ceba9444b8 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -13,7 +13,6 @@ pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { // CHECK: [[B:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute); // CHECK: [[C:_.+]] = move ([[B]].0: std::ptr::alignment::AlignmentEnum); // CHECK: [[D:_.+]] = discriminant([[C]]); - // CHECK: [[E:_.+]] = move [[D]] as usize (IntToInt); - // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[E]]) -> + // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[D]]) -> std::ptr::drop_in_place(ptr) } -- cgit 1.4.1-3-g733a5 From 1a515e69490cdc3cee5325c4fc8d18baa502f38a Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 30 Jul 2025 19:12:31 +0000 Subject: rustdoc-json: Add test for `#[macro_use]` attribute --- tests/rustdoc-json/attrs/macro_export.rs | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/rustdoc-json/attrs/macro_export.rs (limited to 'tests') diff --git a/tests/rustdoc-json/attrs/macro_export.rs b/tests/rustdoc-json/attrs/macro_export.rs new file mode 100644 index 00000000000..1472aabb6ff --- /dev/null +++ b/tests/rustdoc-json/attrs/macro_export.rs @@ -0,0 +1,40 @@ +//@ compile-flags: --document-private-items + +//@ set exported_id = "$.index[?(@.name=='exported')].id" +//@ is "$.index[?(@.name=='exported')].attrs" '[{"other": "#[macro_export]"}]' +//@ is "$.index[?(@.name=='exported')].visibility" '"public"' + +#[macro_export] +macro_rules! exported { + () => {}; +} + +//@ set not_exported_id = "$.index[?(@.name=='not_exported')].id" +//@ is "$.index[?(@.name=='not_exported')].attrs" [] +//@ is "$.index[?(@.name=='not_exported')].visibility" '"crate"' +macro_rules! not_exported { + () => {}; +} + +//@ set module_id = "$.index[?(@.name=='module')].id" +pub mod module { + //@ set exported_from_mod_id = "$.index[?(@.name=='exported_from_mod')].id" + //@ is "$.index[?(@.name=='exported_from_mod')].attrs" '[{"other": "#[macro_export]"}]' + //@ is "$.index[?(@.name=='exported_from_mod')].visibility" '"public"' + #[macro_export] + macro_rules! exported_from_mod { + () => {}; + } + + //@ set not_exported_from_mod_id = "$.index[?(@.name=='not_exported_from_mod')].id" + //@ is "$.index[?(@.name=='not_exported_from_mod')].attrs" [] + //@ is "$.index[?(@.name=='not_exported_from_mod')].visibility" '"crate"' + macro_rules! not_exported_from_mod { + () => {}; + } +} +// The non-exported macro's are left in place, but the #[macro_export]'d ones +// are moved to the crate root. + +//@ is "$.index[?(@.name=='module')].inner.module.items[*]" $not_exported_from_mod_id +//@ ismany "$.index[?(@.name=='macro_export')].inner.module.items[*]" $exported_id $not_exported_id $module_id $exported_from_mod_id -- cgit 1.4.1-3-g733a5 From a33e084afe698e0a025211abd6dc1c9a4bb22e9d Mon Sep 17 00:00:00 2001 From: Alona Enraght-Moony Date: Wed, 30 Jul 2025 19:57:32 +0000 Subject: rustdoc-json: Move `#[macro_export]` from `Other` to it's own variant --- src/librustdoc/json/conversions.rs | 8 ++++++-- src/rustdoc-json-types/lib.rs | 7 +++++-- tests/rustdoc-json/attrs/macro_export.rs | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'tests') diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 08bc0bb1950..fe69a5abee1 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -908,8 +908,12 @@ fn maybe_from_hir_attr( hir::Attribute::Parsed(kind) => kind, hir::Attribute::Unparsed(_) => { - // FIXME: We should handle `#[doc(hidden)]`. - return Some(other_attr(tcx, attr)); + return Some(if attr.has_name(sym::macro_export) { + Attribute::MacroExport + // FIXME: We should handle `#[doc(hidden)]`. + } else { + other_attr(tcx, attr) + }); } }; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 6235b0e8576..40f89009a43 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -37,8 +37,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Structured Attributes -pub const FORMAT_VERSION: u32 = 54; +// Latest feature: Add Attribute::MacroUse +pub const FORMAT_VERSION: u32 = 55; /// The root of the emitted JSON blob. /// @@ -216,6 +216,9 @@ pub enum Attribute { /// `#[must_use]` MustUse { reason: Option }, + /// `#[macro_export]` + MacroExport, + /// `#[export_name = "name"]` ExportName(String), diff --git a/tests/rustdoc-json/attrs/macro_export.rs b/tests/rustdoc-json/attrs/macro_export.rs index 1472aabb6ff..5d487cf6a56 100644 --- a/tests/rustdoc-json/attrs/macro_export.rs +++ b/tests/rustdoc-json/attrs/macro_export.rs @@ -1,7 +1,7 @@ //@ compile-flags: --document-private-items //@ set exported_id = "$.index[?(@.name=='exported')].id" -//@ is "$.index[?(@.name=='exported')].attrs" '[{"other": "#[macro_export]"}]' +//@ is "$.index[?(@.name=='exported')].attrs" '["macro_export"]' //@ is "$.index[?(@.name=='exported')].visibility" '"public"' #[macro_export] @@ -19,7 +19,7 @@ macro_rules! not_exported { //@ set module_id = "$.index[?(@.name=='module')].id" pub mod module { //@ set exported_from_mod_id = "$.index[?(@.name=='exported_from_mod')].id" - //@ is "$.index[?(@.name=='exported_from_mod')].attrs" '[{"other": "#[macro_export]"}]' + //@ is "$.index[?(@.name=='exported_from_mod')].attrs" '["macro_export"]' //@ is "$.index[?(@.name=='exported_from_mod')].visibility" '"public"' #[macro_export] macro_rules! exported_from_mod { -- cgit 1.4.1-3-g733a5 From ee0118f8a1dbfcad06b8c09644553a3fc3e070d4 Mon Sep 17 00:00:00 2001 From: David Tenty Date: Wed, 30 Jul 2025 16:45:17 -0400 Subject: [test][AIX] ignore extern_weak linkage test The AIX linkage model doesn't support ELF style extern_weak semantic, so just skip this test, like other platforms that don't have it. --- tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'tests') diff --git a/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs index 8c194ec50df..ad7b0674478 100644 --- a/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs +++ b/tests/ui/linkage-attr/propagate-generic-issue-18804/main.rs @@ -4,6 +4,7 @@ //@ ignore-emscripten no weak symbol support //@ ignore-apple no extern_weak linkage +//@ ignore-aix no extern_weak linkage //@ aux-build:lib.rs -- cgit 1.4.1-3-g733a5 From 7b667e7811f4a4b496f38d25c5e824f13638cdbb Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 31 Jul 2025 00:44:22 +0800 Subject: Extend `is_case_difference` to handle digit-letter confusables Signed-off-by: xizheyin --- compiler/rustc_errors/src/emitter.rs | 135 ++++++++++++++++----- compiler/rustc_errors/src/lib.rs | 11 +- .../clippy/tests/ui/match_str_case_mismatch.stderr | 2 +- tests/ui/error-codes/E0423.stderr | 2 +- tests/ui/lint/lint-non-uppercase-usages.stderr | 2 +- tests/ui/parser/item-kw-case-mismatch.stderr | 6 +- tests/ui/parser/kw-in-trait-bounds.stderr | 8 +- tests/ui/parser/misspelled-keywords/hrdt.stderr | 2 +- .../parser/misspelled-keywords/impl-return.stderr | 2 +- tests/ui/parser/misspelled-keywords/static.stderr | 2 +- tests/ui/parser/misspelled-keywords/struct.stderr | 2 +- .../recover/recover-fn-trait-from-fn-kw.stderr | 4 +- .../parser/typod-const-in-const-param-def.stderr | 8 +- .../suggestions/assoc-ct-for-assoc-method.stderr | 2 +- tests/ui/suggestions/bool_typo_err_suggest.stderr | 2 +- .../ui/suggestions/case-difference-suggestions.rs | 57 +++++++++ .../suggestions/case-difference-suggestions.stderr | 99 +++++++++++++++ tests/ui/suggestions/incorrect-variant-literal.svg | 2 +- 18 files changed, 290 insertions(+), 58 deletions(-) create mode 100644 tests/ui/suggestions/case-difference-suggestions.rs create mode 100644 tests/ui/suggestions/case-difference-suggestions.stderr (limited to 'tests') diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 46a4a186824..55a42d0426e 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -262,19 +262,11 @@ pub trait Emitter { format!("help: {msg}") } else { // Show the default suggestion text with the substitution - format!( - "help: {}{}: `{}`", - msg, - if self - .source_map() - .is_some_and(|sm| is_case_difference(sm, snippet, part.span,)) - { - " (notice the capitalization)" - } else { - "" - }, - snippet, - ) + let confusion_type = self + .source_map() + .map(|sm| detect_confusion_type(sm, snippet, part.span)) + .unwrap_or(ConfusionType::None); + format!("help: {}{}: `{}`", msg, confusion_type.label_text(), snippet,) }; primary_span.push_span_label(part.span, msg); @@ -2028,12 +2020,12 @@ impl HumanEmitter { buffer.append(0, ": ", Style::HeaderMsg); let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)]; - if suggestions - .iter() - .take(MAX_SUGGESTIONS) - .any(|(_, _, _, only_capitalization)| *only_capitalization) + if let Some(confusion_type) = + suggestions.iter().take(MAX_SUGGESTIONS).find_map(|(_, _, _, confusion_type)| { + if confusion_type.has_confusion() { Some(*confusion_type) } else { None } + }) { - msg.push((" (notice the capitalization difference)".into(), Style::NoStyle)); + msg.push((confusion_type.label_text().into(), Style::NoStyle)); } self.msgs_to_buffer( &mut buffer, @@ -3528,24 +3520,107 @@ pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool { } /// Whether the original and suggested code are visually similar enough to warrant extra wording. -pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool { - // FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode. +pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> ConfusionType { let found = match sm.span_to_snippet(sp) { Ok(snippet) => snippet, Err(e) => { warn!(error = ?e, "Invalid span {:?}", sp); - return false; + return ConfusionType::None; } }; - let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; - // All the chars that differ in capitalization are confusable (above): - let confusable = iter::zip(found.chars(), suggested.chars()) - .filter(|(f, s)| f != s) - .all(|(f, s)| ascii_confusables.contains(&f) || ascii_confusables.contains(&s)); - confusable && found.to_lowercase() == suggested.to_lowercase() - // FIXME: We sometimes suggest the same thing we already have, which is a - // bug, but be defensive against that here. - && found != suggested + + let mut has_case_confusion = false; + let mut has_digit_letter_confusion = false; + + if found.len() == suggested.len() { + let mut has_case_diff = false; + let mut has_digit_letter_confusable = false; + let mut has_other_diff = false; + + let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; + + let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')]; + + for (f, s) in iter::zip(found.chars(), suggested.chars()) { + if f != s { + if f.to_lowercase().to_string() == s.to_lowercase().to_string() { + // Check for case differences (any character that differs only in case) + if ascii_confusables.contains(&f) || ascii_confusables.contains(&s) { + has_case_diff = true; + } else { + has_other_diff = true; + } + } else if digit_letter_confusables.contains(&(f, s)) + || digit_letter_confusables.contains(&(s, f)) + { + // Check for digit-letter confusables (like 0 vs O, 1 vs l, etc.) + has_digit_letter_confusable = true; + } else { + has_other_diff = true; + } + } + } + + // If we have case differences and no other differences + if has_case_diff && !has_other_diff && found != suggested { + has_case_confusion = true; + } + if has_digit_letter_confusable && !has_other_diff && found != suggested { + has_digit_letter_confusion = true; + } + } + + match (has_case_confusion, has_digit_letter_confusion) { + (true, true) => ConfusionType::Both, + (true, false) => ConfusionType::Case, + (false, true) => ConfusionType::DigitLetter, + (false, false) => ConfusionType::None, + } +} + +/// Represents the type of confusion detected between original and suggested code. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ConfusionType { + /// No confusion detected + None, + /// Only case differences (e.g., "hello" vs "Hello") + Case, + /// Only digit-letter confusion (e.g., "0" vs "O", "1" vs "l") + DigitLetter, + /// Both case and digit-letter confusion + Both, +} + +impl ConfusionType { + /// Returns the appropriate label text for this confusion type. + pub fn label_text(&self) -> &'static str { + match self { + ConfusionType::None => "", + ConfusionType::Case => " (notice the capitalization)", + ConfusionType::DigitLetter => " (notice the digit/letter confusion)", + ConfusionType::Both => " (notice the capitalization and digit/letter confusion)", + } + } + + /// Combines two confusion types. If either is `Both`, the result is `Both`. + /// If one is `Case` and the other is `DigitLetter`, the result is `Both`. + /// Otherwise, returns the non-`None` type, or `None` if both are `None`. + pub fn combine(self, other: ConfusionType) -> ConfusionType { + match (self, other) { + (ConfusionType::None, other) => other, + (this, ConfusionType::None) => this, + (ConfusionType::Both, _) | (_, ConfusionType::Both) => ConfusionType::Both, + (ConfusionType::Case, ConfusionType::DigitLetter) + | (ConfusionType::DigitLetter, ConfusionType::Case) => ConfusionType::Both, + (ConfusionType::Case, ConfusionType::Case) => ConfusionType::Case, + (ConfusionType::DigitLetter, ConfusionType::DigitLetter) => ConfusionType::DigitLetter, + } + } + + /// Returns true if this confusion type represents any kind of confusion. + pub fn has_confusion(&self) -> bool { + *self != ConfusionType::None + } } pub(crate) fn should_show_source_code( diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 381d780077d..2534cddf105 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -50,7 +50,7 @@ pub use diagnostic_impls::{ IndicateAnonymousLifetime, SingleLabelManySpans, }; pub use emitter::ColorConfig; -use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; +use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::StableHasher; @@ -308,7 +308,7 @@ impl CodeSuggestion { pub(crate) fn splice_lines( &self, sm: &SourceMap, - ) -> Vec<(String, Vec, Vec>, bool)> { + ) -> Vec<(String, Vec, Vec>, ConfusionType)> { // For the `Vec>` value, the first level of the vector // corresponds to the output snippet's lines, while the second level corresponds to the // substrings within that line that should be highlighted. @@ -414,14 +414,15 @@ impl CodeSuggestion { // We need to keep track of the difference between the existing code and the added // or deleted code in order to point at the correct column *after* substitution. let mut acc = 0; - let mut only_capitalization = false; + let mut confusion_type = ConfusionType::None; for part in &mut substitution.parts { // If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the // suggestion and snippet to look as if we just suggested to add // `"b"`, which is typically much easier for the user to understand. part.trim_trivial_replacements(sm); - only_capitalization |= is_case_difference(sm, &part.snippet, part.span); + let part_confusion = detect_confusion_type(sm, &part.snippet, part.span); + confusion_type = confusion_type.combine(part_confusion); let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { let mut count = @@ -511,7 +512,7 @@ impl CodeSuggestion { if highlights.iter().all(|parts| parts.is_empty()) { None } else { - Some((buf, substitution.parts, highlights, only_capitalization)) + Some((buf, substitution.parts, highlights, confusion_type)) } }) .collect() diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr index 8068edfff94..c2b58b952aa 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr @@ -18,7 +18,7 @@ error: this `match` arm has a differing case than its expression LL | "~!@#$%^&*()-_=+Foo" => {}, | ^^^^^^^^^^^^^^^^^^^^ | -help: consider changing the case of this arm to respect `to_ascii_lowercase` (notice the capitalization difference) +help: consider changing the case of this arm to respect `to_ascii_lowercase` (notice the capitalization) | LL - "~!@#$%^&*()-_=+Foo" => {}, LL + "~!@#$%^&*()-_=+foo" => {}, diff --git a/tests/ui/error-codes/E0423.stderr b/tests/ui/error-codes/E0423.stderr index e50b8bd820c..b699e53fb48 100644 --- a/tests/ui/error-codes/E0423.stderr +++ b/tests/ui/error-codes/E0423.stderr @@ -54,7 +54,7 @@ help: use struct literal syntax instead LL - let f = Foo(); LL + let f = Foo { a: val }; | -help: a function with a similar name exists (notice the capitalization difference) +help: a function with a similar name exists (notice the capitalization) | LL - let f = Foo(); LL + let f = foo(); diff --git a/tests/ui/lint/lint-non-uppercase-usages.stderr b/tests/ui/lint/lint-non-uppercase-usages.stderr index 7c7e573a88e..b34be31216d 100644 --- a/tests/ui/lint/lint-non-uppercase-usages.stderr +++ b/tests/ui/lint/lint-non-uppercase-usages.stderr @@ -29,7 +29,7 @@ warning: const parameter `foo` should have an upper case name LL | fn foo() { | ^^^ | -help: convert the identifier to upper case (notice the capitalization difference) +help: convert the identifier to upper case (notice the capitalization) | LL - fn foo() { LL + fn foo() { diff --git a/tests/ui/parser/item-kw-case-mismatch.stderr b/tests/ui/parser/item-kw-case-mismatch.stderr index df39eb10fdb..d2a1eb7f2f5 100644 --- a/tests/ui/parser/item-kw-case-mismatch.stderr +++ b/tests/ui/parser/item-kw-case-mismatch.stderr @@ -4,7 +4,7 @@ error: keyword `use` is written in the wrong case LL | Use std::ptr::read; | ^^^ | -help: write it in the correct case (notice the capitalization difference) +help: write it in the correct case (notice the capitalization) | LL - Use std::ptr::read; LL + use std::ptr::read; @@ -28,7 +28,7 @@ error: keyword `fn` is written in the wrong case LL | async Fn _a() {} | ^^ | -help: write it in the correct case (notice the capitalization difference) +help: write it in the correct case (notice the capitalization) | LL - async Fn _a() {} LL + async fn _a() {} @@ -40,7 +40,7 @@ error: keyword `fn` is written in the wrong case LL | Fn _b() {} | ^^ | -help: write it in the correct case (notice the capitalization difference) +help: write it in the correct case (notice the capitalization) | LL - Fn _b() {} LL + fn _b() {} diff --git a/tests/ui/parser/kw-in-trait-bounds.stderr b/tests/ui/parser/kw-in-trait-bounds.stderr index 1892d0b6226..5a4adf3e37b 100644 --- a/tests/ui/parser/kw-in-trait-bounds.stderr +++ b/tests/ui/parser/kw-in-trait-bounds.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn _f(_: impl fn(), _: &dyn fn()) LL + fn _f(_: impl fn(), _: &dyn fn()) @@ -16,7 +16,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn _f(_: impl fn(), _: &dyn fn()) LL + fn _f(_: impl Fn(), _: &dyn fn()) @@ -28,7 +28,7 @@ error: expected identifier, found keyword `fn` LL | fn _f(_: impl fn(), _: &dyn fn()) | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn _f(_: impl fn(), _: &dyn fn()) LL + fn _f(_: impl fn(), _: &dyn Fn()) @@ -40,7 +40,7 @@ error: expected identifier, found keyword `fn` LL | G: fn(), | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - G: fn(), LL + G: Fn(), diff --git a/tests/ui/parser/misspelled-keywords/hrdt.stderr b/tests/ui/parser/misspelled-keywords/hrdt.stderr index e5fc1a50382..497bd613bf4 100644 --- a/tests/ui/parser/misspelled-keywords/hrdt.stderr +++ b/tests/ui/parser/misspelled-keywords/hrdt.stderr @@ -4,7 +4,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found keyword LL | Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, | ^^^ expected one of 7 possible tokens | -help: write keyword `where` in lowercase (notice the capitalization difference) +help: write keyword `where` in lowercase (notice the capitalization) | LL - Where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, LL + where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8, diff --git a/tests/ui/parser/misspelled-keywords/impl-return.stderr b/tests/ui/parser/misspelled-keywords/impl-return.stderr index ff5391461a9..d49d962d7e9 100644 --- a/tests/ui/parser/misspelled-keywords/impl-return.stderr +++ b/tests/ui/parser/misspelled-keywords/impl-return.stderr @@ -4,7 +4,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `where`, or `{`, found `Display LL | fn code() -> Impl Display {} | ^^^^^^^ expected one of 7 possible tokens | -help: write keyword `impl` in lowercase (notice the capitalization difference) +help: write keyword `impl` in lowercase (notice the capitalization) | LL - fn code() -> Impl Display {} LL + fn code() -> impl Display {} diff --git a/tests/ui/parser/misspelled-keywords/static.stderr b/tests/ui/parser/misspelled-keywords/static.stderr index e559f2be109..0df40bcdc33 100644 --- a/tests/ui/parser/misspelled-keywords/static.stderr +++ b/tests/ui/parser/misspelled-keywords/static.stderr @@ -4,7 +4,7 @@ error: expected one of `!` or `::`, found `a` LL | Static a = 0; | ^ expected one of `!` or `::` | -help: write keyword `static` in lowercase (notice the capitalization difference) +help: write keyword `static` in lowercase (notice the capitalization) | LL - Static a = 0; LL + static a = 0; diff --git a/tests/ui/parser/misspelled-keywords/struct.stderr b/tests/ui/parser/misspelled-keywords/struct.stderr index edbec3b9456..af8614ef14b 100644 --- a/tests/ui/parser/misspelled-keywords/struct.stderr +++ b/tests/ui/parser/misspelled-keywords/struct.stderr @@ -4,7 +4,7 @@ error: expected one of `!` or `::`, found `Foor` LL | Struct Foor { | ^^^^ expected one of `!` or `::` | -help: write keyword `struct` in lowercase (notice the capitalization difference) +help: write keyword `struct` in lowercase (notice the capitalization) | LL - Struct Foor { LL + struct Foor { diff --git a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr index 4e1fcaf4936..bd809e77a8f 100644 --- a/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr +++ b/tests/ui/parser/recover/recover-fn-trait-from-fn-kw.stderr @@ -4,7 +4,7 @@ error: expected identifier, found keyword `fn` LL | fn foo(_: impl fn() -> i32) {} | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn foo(_: impl fn() -> i32) {} LL + fn foo(_: impl Fn() -> i32) {} @@ -16,7 +16,7 @@ error: expected identifier, found keyword `fn` LL | fn foo2(_: T) {} | ^^ | -help: use `Fn` to refer to the trait (notice the capitalization difference) +help: use `Fn` to refer to the trait (notice the capitalization) | LL - fn foo2(_: T) {} LL + fn foo2(_: T) {} diff --git a/tests/ui/parser/typod-const-in-const-param-def.stderr b/tests/ui/parser/typod-const-in-const-param-def.stderr index bf7168a0157..cc1600fe5cb 100644 --- a/tests/ui/parser/typod-const-in-const-param-def.stderr +++ b/tests/ui/parser/typod-const-in-const-param-def.stderr @@ -4,7 +4,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn foo() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn foo() {} LL + pub fn foo() {} @@ -16,7 +16,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn baz() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn baz() {} LL + pub fn baz() {} @@ -28,7 +28,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn qux() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn qux() {} LL + pub fn qux() {} @@ -40,7 +40,7 @@ error: `const` keyword was mistyped as `Const` LL | pub fn quux() {} | ^^^^^ | -help: use the `const` keyword (notice the capitalization difference) +help: use the `const` keyword (notice the capitalization) | LL - pub fn quux() {} LL + pub fn quux() {} diff --git a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr index 6d6fd983038..47efe69cfc2 100644 --- a/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr +++ b/tests/ui/suggestions/assoc-ct-for-assoc-method.stderr @@ -8,7 +8,7 @@ LL | let x: i32 = MyS::foo; | = note: expected type `i32` found fn item `fn() -> MyS {MyS::foo}` -help: try referring to the associated const `FOO` instead (notice the capitalization difference) +help: try referring to the associated const `FOO` instead (notice the capitalization) | LL - let x: i32 = MyS::foo; LL + let x: i32 = MyS::FOO; diff --git a/tests/ui/suggestions/bool_typo_err_suggest.stderr b/tests/ui/suggestions/bool_typo_err_suggest.stderr index faf799d0fda..d46ce1ad8a9 100644 --- a/tests/ui/suggestions/bool_typo_err_suggest.stderr +++ b/tests/ui/suggestions/bool_typo_err_suggest.stderr @@ -16,7 +16,7 @@ error[E0425]: cannot find value `False` in this scope LL | let y = False; | ^^^^^ not found in this scope | -help: you may want to use a bool value instead (notice the capitalization difference) +help: you may want to use a bool value instead (notice the capitalization) | LL - let y = False; LL + let y = false; diff --git a/tests/ui/suggestions/case-difference-suggestions.rs b/tests/ui/suggestions/case-difference-suggestions.rs new file mode 100644 index 00000000000..d554b6e9367 --- /dev/null +++ b/tests/ui/suggestions/case-difference-suggestions.rs @@ -0,0 +1,57 @@ +fn main() { + + // Simple case difference, no hit + let hello = "hello"; + println!("{}", Hello); //~ ERROR cannot find value `Hello` in this scope + + // Multiple case differences, hit + let myVariable = 10; + println!("{}", myvariable); //~ ERROR cannot find value `myvariable` in this scope + + // Case difference with special characters, hit + let user_name = "john"; + println!("{}", User_Name); //~ ERROR cannot find value `User_Name` in this scope + + // All uppercase vs all lowercase, hit + let FOO = 42; + println!("{}", foo); //~ ERROR cannot find value `foo` in this scope + + + // 0 vs O + let FFO0 = 100; + println!("{}", FFOO); //~ ERROR cannot find value `FFOO` in this scope + + let l1st = vec![1, 2, 3]; + println!("{}", list); //~ ERROR cannot find value `list` in this scope + + let S5 = "test"; + println!("{}", SS); //~ ERROR cannot find value `SS` in this scope + + let aS5 = "test"; + println!("{}", a55); //~ ERROR cannot find value `a55` in this scope + + let B8 = 8; + println!("{}", BB); //~ ERROR cannot find value `BB` in this scope + + let g9 = 9; + println!("{}", gg); //~ ERROR cannot find value `gg` in this scope + + let o1d = "old"; + println!("{}", old); //~ ERROR cannot find value `old` in this scope + + let new1 = "new"; + println!("{}", newl); //~ ERROR cannot find value `newl` in this scope + + let apple = "apple"; + println!("{}", app1e); //~ ERROR cannot find value `app1e` in this scope + + let a = 1; + println!("{}", A); //~ ERROR cannot find value `A` in this scope + + let worldlu = "world"; + println!("{}", world1U); //~ ERROR cannot find value `world1U` in this scope + + let myV4rlable = 42; + println!("{}", myv4r1able); //~ ERROR cannot find value `myv4r1able` in this scope + +} diff --git a/tests/ui/suggestions/case-difference-suggestions.stderr b/tests/ui/suggestions/case-difference-suggestions.stderr new file mode 100644 index 00000000000..c3d2410a6eb --- /dev/null +++ b/tests/ui/suggestions/case-difference-suggestions.stderr @@ -0,0 +1,99 @@ +error[E0425]: cannot find value `Hello` in this scope + --> $DIR/case-difference-suggestions.rs:5:20 + | +LL | println!("{}", Hello); + | ^^^^^ help: a local variable with a similar name exists: `hello` + +error[E0425]: cannot find value `myvariable` in this scope + --> $DIR/case-difference-suggestions.rs:9:20 + | +LL | println!("{}", myvariable); + | ^^^^^^^^^^ help: a local variable with a similar name exists (notice the capitalization): `myVariable` + +error[E0425]: cannot find value `User_Name` in this scope + --> $DIR/case-difference-suggestions.rs:13:20 + | +LL | println!("{}", User_Name); + | ^^^^^^^^^ help: a local variable with a similar name exists: `user_name` + +error[E0425]: cannot find value `foo` in this scope + --> $DIR/case-difference-suggestions.rs:17:20 + | +LL | println!("{}", foo); + | ^^^ help: a local variable with a similar name exists (notice the capitalization): `FOO` + +error[E0425]: cannot find value `FFOO` in this scope + --> $DIR/case-difference-suggestions.rs:22:20 + | +LL | println!("{}", FFOO); + | ^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `FFO0` + +error[E0425]: cannot find value `list` in this scope + --> $DIR/case-difference-suggestions.rs:25:20 + | +LL | println!("{}", list); + | ^^^^ help: a local variable with a similar name exists: `l1st` + +error[E0425]: cannot find value `SS` in this scope + --> $DIR/case-difference-suggestions.rs:28:20 + | +LL | println!("{}", SS); + | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `S5` + +error[E0425]: cannot find value `a55` in this scope + --> $DIR/case-difference-suggestions.rs:31:20 + | +LL | println!("{}", a55); + | ^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `aS5` + +error[E0425]: cannot find value `BB` in this scope + --> $DIR/case-difference-suggestions.rs:34:20 + | +LL | println!("{}", BB); + | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `B8` + +error[E0425]: cannot find value `gg` in this scope + --> $DIR/case-difference-suggestions.rs:37:20 + | +LL | println!("{}", gg); + | ^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `g9` + +error[E0425]: cannot find value `old` in this scope + --> $DIR/case-difference-suggestions.rs:40:20 + | +LL | println!("{}", old); + | ^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `o1d` + +error[E0425]: cannot find value `newl` in this scope + --> $DIR/case-difference-suggestions.rs:43:20 + | +LL | println!("{}", newl); + | ^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `new1` + +error[E0425]: cannot find value `app1e` in this scope + --> $DIR/case-difference-suggestions.rs:46:20 + | +LL | println!("{}", app1e); + | ^^^^^ help: a local variable with a similar name exists (notice the digit/letter confusion): `apple` + +error[E0425]: cannot find value `A` in this scope + --> $DIR/case-difference-suggestions.rs:49:20 + | +LL | println!("{}", A); + | ^ help: a local variable with a similar name exists: `a` + +error[E0425]: cannot find value `world1U` in this scope + --> $DIR/case-difference-suggestions.rs:52:20 + | +LL | println!("{}", world1U); + | ^^^^^^^ help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion): `worldlu` + +error[E0425]: cannot find value `myv4r1able` in this scope + --> $DIR/case-difference-suggestions.rs:55:20 + | +LL | println!("{}", myv4r1able); + | ^^^^^^^^^^ help: a local variable with a similar name exists (notice the capitalization and digit/letter confusion): `myV4rlable` + +error: aborting due to 16 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/incorrect-variant-literal.svg b/tests/ui/suggestions/incorrect-variant-literal.svg index 279fd30f216..2cab1f4b60f 100644 --- a/tests/ui/suggestions/incorrect-variant-literal.svg +++ b/tests/ui/suggestions/incorrect-variant-literal.svg @@ -455,7 +455,7 @@ | - help: there is a variant with a similar name (notice the capitalization difference) + help: there is a variant with a similar name (notice the capitalization) | -- cgit 1.4.1-3-g733a5 From a78f92be9bd29b8d4d31ca97d2f5ba0bf818df08 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 31 Jul 2025 14:36:22 +0200 Subject: add tests --- tests/ui/traits/next-solver/cycles/rayon-hang-1.rs | 32 ++++++++++++++ tests/ui/traits/next-solver/cycles/rayon-hang-2.rs | 49 ++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/ui/traits/next-solver/cycles/rayon-hang-1.rs create mode 100644 tests/ui/traits/next-solver/cycles/rayon-hang-2.rs (limited to 'tests') diff --git a/tests/ui/traits/next-solver/cycles/rayon-hang-1.rs b/tests/ui/traits/next-solver/cycles/rayon-hang-1.rs new file mode 100644 index 00000000000..61e1f1b200f --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/rayon-hang-1.rs @@ -0,0 +1,32 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for trait-system-refactor-initiative#109. + +trait ParallelIterator: Sized { + type Item; +} +trait IntoParallelIterator { + type Iter: ParallelIterator; + type Item; +} +impl IntoParallelIterator for T { + type Iter = T; + type Item = T::Item; +} + +macro_rules! multizip_impls { + ($($T:ident),+) => { + fn foo<$( $T, )+>() where + $( + $T: IntoParallelIterator, + $T::Iter: ParallelIterator, + )+ + ($( $T, )+): IntoParallelIterator, + {} + } +} + +multizip_impls! { A, B, C, D, E, F, G, H, I, J, K, L } + +fn main() {} diff --git a/tests/ui/traits/next-solver/cycles/rayon-hang-2.rs b/tests/ui/traits/next-solver/cycles/rayon-hang-2.rs new file mode 100644 index 00000000000..bb5d8335dd6 --- /dev/null +++ b/tests/ui/traits/next-solver/cycles/rayon-hang-2.rs @@ -0,0 +1,49 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for trait-system-refactor-initiative#109. +// Unlike `rayon-hang-1.rs` the cycles in this test are not +// unproductive, which causes the `AliasRelate` goal when trying +// to apply where-clauses to only error in the second iteration. +// +// This makes the exponential blowup to be significantly harder +// to avoid. + +trait ParallelIterator: Sized { + type Item; +} + +trait IntoParallelIteratorIndir { + type Iter: ParallelIterator; + type Item; +} +impl IntoParallelIteratorIndir for I +where + Box: IntoParallelIterator, +{ + type Iter = as IntoParallelIterator>::Iter; + type Item = as IntoParallelIterator>::Item; +} +trait IntoParallelIterator { + type Iter: ParallelIterator; + type Item; +} +impl IntoParallelIterator for T { + type Iter = T; + type Item = T::Item; +} + +macro_rules! multizip_impls { + ($($T:ident),+) => { + fn foo<'a, $( $T, )+>() where + $( + $T: IntoParallelIteratorIndir, + $T::Iter: ParallelIterator, + )+ + {} + } +} + +multizip_impls! { A, B, C, D, E, F, G, H, I, J, K, L } + +fn main() {} -- cgit 1.4.1-3-g733a5 From a4a5bf5a71bd0c3fb52a28f81d88ce1755b3bc30 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 24 Jul 2025 17:22:54 +0500 Subject: comments --- .../deref-chain-method-calls-13264.rs | 76 +++++++++ .../block-result/blocks-without-results-11709.rs | 39 +++++ tests/ui/block-result/blocks-without-results.rs | 37 ----- .../borrowck/moved-value-in-thread-loop-12041.rs | 15 ++ .../moved-value-in-thread-loop-12041.stderr | 11 ++ .../ui/borrowck/refcell-borrow-comparison-12033.rs | 9 ++ tests/ui/borrowck/refcell-borrow-comparison.rs | 7 - .../string-literal-match-patterns-11869.rs | 18 +++ tests/ui/closures/fnonce-moved-twice-12127.rs | 16 ++ tests/ui/closures/fnonce-moved-twice-12127.stderr | 18 +++ tests/ui/closures/fnonce-moved-twice.rs | 14 -- tests/ui/closures/moved-upvar-mut-rebind-11958.rs | 13 ++ .../closures/moved-upvar-mut-rebind-11958.stderr | 20 +++ tests/ui/closures/moved-upvar-mut-rebind.rs | 11 -- tests/ui/coercion/any-trait-object-debug-12744.rs | 7 + .../collections/hashset-connected-border-12860.rs | 51 ++++++ tests/ui/collections/hashset-connected-border.rs | 49 ------ .../ui/const-generics/vec-macro-in-static-array.rs | 2 + .../vec-macro-in-static-array.stderr | 13 ++ tests/ui/extern/format-message-windows-ffi.rs | 39 ----- tests/ui/extern/windows-tcb-trash-13259.rs | 49 ++++++ tests/ui/fn/anonymous-parameters-trait-13105.rs | 11 ++ tests/ui/fn/anonymous-parameters-trait.rs | 9 -- tests/ui/imports/use-in-impl-scope.rs | 14 -- tests/ui/issues/issue-11771.stderr | 39 ----- tests/ui/issues/issue-11844.stderr | 14 -- tests/ui/issues/issue-11958.stderr | 20 --- tests/ui/issues/issue-12041.stderr | 11 -- tests/ui/issues/issue-12127.stderr | 18 --- tests/ui/issues/issue-12567.stderr | 51 ------ tests/ui/issues/issue-12863.stderr | 9 -- tests/ui/issues/issue-13058.stderr | 14 -- tests/ui/issues/issue-13359.stderr | 39 ----- tests/ui/issues/issue-13407.stderr | 27 ---- tests/ui/issues/issue-13446.stderr | 13 -- tests/ui/issues/issue-13466.stderr | 26 --- tests/ui/iterators/bytes-iterator-clone-12677.rs | 11 ++ tests/ui/iterators/bytes-iterator-clone.rs | 9 -- tests/ui/iterators/phf-map-entries-iterator.rs | 24 --- .../iterator-trait-lifetime-error-13058.rs | 29 ++++ .../iterator-trait-lifetime-error-13058.stderr | 14 ++ .../ui/lifetimes/iterator-trait-lifetime-error.rs | 27 ---- .../lifetime-inference-destructuring-arg.rs | 26 +++ tests/ui/lifetimes/matcher-trait-equality-13323.rs | 60 +++++++ .../struct-lifetime-field-assignment-13405.rs | 21 +++ .../lifetimes/struct-lifetime-field-assignment.rs | 19 --- .../ui/lifetimes/unsafe-transmute-in-find-11740.rs | 28 ++++ tests/ui/match/function-in-pattern-error.rs | 8 - tests/ui/match/guard-literal-range-shadow.rs | 178 -------------------- tests/ui/match/option-result-mismatch-11844.rs | 10 ++ tests/ui/match/option-result-mismatch-11844.stderr | 14 ++ tests/ui/match/option-result-mismatch.rs | 8 - .../option-result-type-param-mismatch-13466.rs | 24 +++ .../option-result-type-param-mismatch-13466.stderr | 26 +++ .../ui/match/option-result-type-param-mismatch.rs | 22 --- .../ui/match/overeager-sub-match-pruning-13027.rs | 180 +++++++++++++++++++++ tests/ui/match/slice-move-out-error-12567.rs | 15 ++ tests/ui/match/slice-move-out-error-12567.stderr | 51 ++++++ tests/ui/match/slice-move-out-error.rs | 13 -- tests/ui/match/string-literal-match-patterns.rs | 16 -- tests/ui/match/struct-reference-patterns-12285.rs | 16 ++ tests/ui/match/struct-reference-patterns.rs | 14 -- tests/ui/panics/explicit-panic-unreachable.rs | 8 - tests/ui/panics/unwrap-or-panic-input.rs | 7 - tests/ui/parser/encode-symbol-ice-12920.rs | 10 ++ tests/ui/privacy/private-unit-struct-assignment.rs | 2 + .../privacy/private-unit-struct-assignment.stderr | 27 ++++ tests/ui/privacy/use-in-impl-scope-12729.rs | 16 ++ tests/ui/resolve/reference-clone-nonclone-11820.rs | 15 ++ .../statics/enum-with-static-str-variant-13214.rs | 24 +++ tests/ui/statics/enum-with-static-str-variant.rs | 22 --- tests/ui/threads/moved-value-in-thread-loop.rs | 13 -- tests/ui/traits/any-trait-object-debug.rs | 5 - .../traits/default-method-lifetime-params-13204.rs | 27 ++++ tests/ui/traits/default-method-lifetime-params.rs | 25 --- tests/ui/traits/deref-chain-method-calls.rs | 74 --------- tests/ui/traits/fnonce-repro-trait-impl-13434.rs | 23 +++ tests/ui/traits/fnonce-repro-trait-impl.rs | 21 --- tests/ui/traits/matcher-trait-equality.rs | 58 ------- tests/ui/traits/reference-clone-noclone.rs | 13 -- .../type-inference/isize-usize-mismatch-error.rs | 15 -- tests/ui/type-inference/partial-type-hint-12909.rs | 21 +++ tests/ui/type-inference/type-collect-inference.rs | 19 --- tests/ui/type-inference/unit-type-add-error.rs | 11 -- tests/ui/typeck/function-in-pattern-error-12863.rs | 10 ++ .../typeck/function-in-pattern-error-12863.stderr | 9 ++ tests/ui/typeck/isize-usize-mismatch-error.rs | 17 ++ tests/ui/typeck/isize-usize-mismatch-error.stderr | 39 +++++ tests/ui/typeck/unit-type-add-error-11771.rs | 13 ++ tests/ui/typeck/unit-type-add-error-11771.stderr | 39 +++++ tests/ui/typeck/unwrap-or-panic-input-13202.rs | 9 ++ tests/ui/unsafe/unsafe-transmute-in-find.rs | 26 --- 92 files changed, 1194 insertions(+), 1116 deletions(-) create mode 100644 tests/ui/autoref-autoderef/deref-chain-method-calls-13264.rs create mode 100644 tests/ui/block-result/blocks-without-results-11709.rs delete mode 100644 tests/ui/block-result/blocks-without-results.rs create mode 100644 tests/ui/borrowck/moved-value-in-thread-loop-12041.rs create mode 100644 tests/ui/borrowck/moved-value-in-thread-loop-12041.stderr create mode 100644 tests/ui/borrowck/refcell-borrow-comparison-12033.rs delete mode 100644 tests/ui/borrowck/refcell-borrow-comparison.rs create mode 100644 tests/ui/borrowck/string-literal-match-patterns-11869.rs create mode 100644 tests/ui/closures/fnonce-moved-twice-12127.rs create mode 100644 tests/ui/closures/fnonce-moved-twice-12127.stderr delete mode 100644 tests/ui/closures/fnonce-moved-twice.rs create mode 100644 tests/ui/closures/moved-upvar-mut-rebind-11958.rs create mode 100644 tests/ui/closures/moved-upvar-mut-rebind-11958.stderr delete mode 100644 tests/ui/closures/moved-upvar-mut-rebind.rs create mode 100644 tests/ui/coercion/any-trait-object-debug-12744.rs create mode 100644 tests/ui/collections/hashset-connected-border-12860.rs delete mode 100644 tests/ui/collections/hashset-connected-border.rs create mode 100644 tests/ui/const-generics/vec-macro-in-static-array.stderr delete mode 100644 tests/ui/extern/format-message-windows-ffi.rs create mode 100644 tests/ui/extern/windows-tcb-trash-13259.rs create mode 100644 tests/ui/fn/anonymous-parameters-trait-13105.rs delete mode 100644 tests/ui/fn/anonymous-parameters-trait.rs delete mode 100644 tests/ui/imports/use-in-impl-scope.rs delete mode 100644 tests/ui/issues/issue-11771.stderr delete mode 100644 tests/ui/issues/issue-11844.stderr delete mode 100644 tests/ui/issues/issue-11958.stderr delete mode 100644 tests/ui/issues/issue-12041.stderr delete mode 100644 tests/ui/issues/issue-12127.stderr delete mode 100644 tests/ui/issues/issue-12567.stderr delete mode 100644 tests/ui/issues/issue-12863.stderr delete mode 100644 tests/ui/issues/issue-13058.stderr delete mode 100644 tests/ui/issues/issue-13359.stderr delete mode 100644 tests/ui/issues/issue-13407.stderr delete mode 100644 tests/ui/issues/issue-13446.stderr delete mode 100644 tests/ui/issues/issue-13466.stderr create mode 100644 tests/ui/iterators/bytes-iterator-clone-12677.rs delete mode 100644 tests/ui/iterators/bytes-iterator-clone.rs delete mode 100644 tests/ui/iterators/phf-map-entries-iterator.rs create mode 100644 tests/ui/lifetimes/iterator-trait-lifetime-error-13058.rs create mode 100644 tests/ui/lifetimes/iterator-trait-lifetime-error-13058.stderr delete mode 100644 tests/ui/lifetimes/iterator-trait-lifetime-error.rs create mode 100644 tests/ui/lifetimes/lifetime-inference-destructuring-arg.rs create mode 100644 tests/ui/lifetimes/matcher-trait-equality-13323.rs create mode 100644 tests/ui/lifetimes/struct-lifetime-field-assignment-13405.rs delete mode 100644 tests/ui/lifetimes/struct-lifetime-field-assignment.rs create mode 100644 tests/ui/lifetimes/unsafe-transmute-in-find-11740.rs delete mode 100644 tests/ui/match/function-in-pattern-error.rs delete mode 100644 tests/ui/match/guard-literal-range-shadow.rs create mode 100644 tests/ui/match/option-result-mismatch-11844.rs create mode 100644 tests/ui/match/option-result-mismatch-11844.stderr delete mode 100644 tests/ui/match/option-result-mismatch.rs create mode 100644 tests/ui/match/option-result-type-param-mismatch-13466.rs create mode 100644 tests/ui/match/option-result-type-param-mismatch-13466.stderr delete mode 100644 tests/ui/match/option-result-type-param-mismatch.rs create mode 100644 tests/ui/match/overeager-sub-match-pruning-13027.rs create mode 100644 tests/ui/match/slice-move-out-error-12567.rs create mode 100644 tests/ui/match/slice-move-out-error-12567.stderr delete mode 100644 tests/ui/match/slice-move-out-error.rs delete mode 100644 tests/ui/match/string-literal-match-patterns.rs create mode 100644 tests/ui/match/struct-reference-patterns-12285.rs delete mode 100644 tests/ui/match/struct-reference-patterns.rs delete mode 100644 tests/ui/panics/explicit-panic-unreachable.rs delete mode 100644 tests/ui/panics/unwrap-or-panic-input.rs create mode 100644 tests/ui/parser/encode-symbol-ice-12920.rs create mode 100644 tests/ui/privacy/private-unit-struct-assignment.stderr create mode 100644 tests/ui/privacy/use-in-impl-scope-12729.rs create mode 100644 tests/ui/resolve/reference-clone-nonclone-11820.rs create mode 100644 tests/ui/statics/enum-with-static-str-variant-13214.rs delete mode 100644 tests/ui/statics/enum-with-static-str-variant.rs delete mode 100644 tests/ui/threads/moved-value-in-thread-loop.rs delete mode 100644 tests/ui/traits/any-trait-object-debug.rs create mode 100644 tests/ui/traits/default-method-lifetime-params-13204.rs delete mode 100644 tests/ui/traits/default-method-lifetime-params.rs delete mode 100644 tests/ui/traits/deref-chain-method-calls.rs create mode 100644 tests/ui/traits/fnonce-repro-trait-impl-13434.rs delete mode 100644 tests/ui/traits/fnonce-repro-trait-impl.rs delete mode 100644 tests/ui/traits/matcher-trait-equality.rs delete mode 100644 tests/ui/traits/reference-clone-noclone.rs delete mode 100644 tests/ui/type-inference/isize-usize-mismatch-error.rs create mode 100644 tests/ui/type-inference/partial-type-hint-12909.rs delete mode 100644 tests/ui/type-inference/type-collect-inference.rs delete mode 100644 tests/ui/type-inference/unit-type-add-error.rs create mode 100644 tests/ui/typeck/function-in-pattern-error-12863.rs create mode 100644 tests/ui/typeck/function-in-pattern-error-12863.stderr create mode 100644 tests/ui/typeck/isize-usize-mismatch-error.rs create mode 100644 tests/ui/typeck/isize-usize-mismatch-error.stderr create mode 100644 tests/ui/typeck/unit-type-add-error-11771.rs create mode 100644 tests/ui/typeck/unit-type-add-error-11771.stderr create mode 100644 tests/ui/typeck/unwrap-or-panic-input-13202.rs delete mode 100644 tests/ui/unsafe/unsafe-transmute-in-find.rs (limited to 'tests') diff --git a/tests/ui/autoref-autoderef/deref-chain-method-calls-13264.rs b/tests/ui/autoref-autoderef/deref-chain-method-calls-13264.rs new file mode 100644 index 00000000000..f471c1c7eef --- /dev/null +++ b/tests/ui/autoref-autoderef/deref-chain-method-calls-13264.rs @@ -0,0 +1,76 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13264 + +//@ run-pass +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use std::ops::Deref; + +struct Root { + jsref: JSRef +} + +impl Deref for Root { + type Target = JSRef; + + fn deref<'a>(&'a self) -> &'a JSRef { + &self.jsref + } +} + +#[derive(Copy, Clone)] +struct JSRef { + node: *const Node +} + +impl Deref for JSRef { + type Target = Node; + + fn deref<'a>(&'a self) -> &'a Node { + self.get() + } +} + +trait INode { + fn RemoveChild(&self); +} + +impl INode for JSRef { + fn RemoveChild(&self) { + self.get().RemoveChild(0) + } +} + +impl JSRef { + fn AddChild(&self) { + self.get().AddChild(0); + } + + fn get<'a>(&'a self) -> &'a Node { + unsafe { + &*self.node + } + } +} + +struct Node; + +impl Node { + fn RemoveChild(&self, _a: usize) { + } + + fn AddChild(&self, _a: usize) { + } +} + +fn main() { + let n = Node; + let jsref = JSRef { node: &n }; + let root = Root { jsref: jsref }; + + root.AddChild(); + jsref.AddChild(); + + root.RemoveChild(); + jsref.RemoveChild(); +} diff --git a/tests/ui/block-result/blocks-without-results-11709.rs b/tests/ui/block-result/blocks-without-results-11709.rs new file mode 100644 index 00000000000..97ea6f9e19e --- /dev/null +++ b/tests/ui/block-result/blocks-without-results-11709.rs @@ -0,0 +1,39 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11709 + +//@ run-pass +#![allow(dead_code)] + +// Don't panic on blocks without results +// There are several tests in this run-pass that raised +// when this bug was opened. The cases where the compiler +// panics before the fix have a comment. + +struct S {x:()} + +fn test(slot: &mut Option Box>>) -> () { + let a = slot.take(); + let _a: () = match a { + // `{let .. a(); }` would break + Some(mut a) => { let _a = a(); }, + None => (), + }; +} + +fn not(b: bool) -> bool { + if b { + !b + } else { + // `panic!(...)` would break + panic!("Break the compiler"); + } +} + +pub fn main() { + // {} would break + let _r: () = {}; + let mut slot = None; + // `{ test(...); }` would break + let _s : S = S{ x: { test(&mut slot); } }; + + let _b = not(true); +} diff --git a/tests/ui/block-result/blocks-without-results.rs b/tests/ui/block-result/blocks-without-results.rs deleted file mode 100644 index 8a11074eca8..00000000000 --- a/tests/ui/block-result/blocks-without-results.rs +++ /dev/null @@ -1,37 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -// Don't panic on blocks without results -// There are several tests in this run-pass that raised -// when this bug was opened. The cases where the compiler -// panics before the fix have a comment. - -struct S {x:()} - -fn test(slot: &mut Option Box>>) -> () { - let a = slot.take(); - let _a: () = match a { - // `{let .. a(); }` would break - Some(mut a) => { let _a = a(); }, - None => (), - }; -} - -fn not(b: bool) -> bool { - if b { - !b - } else { - // `panic!(...)` would break - panic!("Break the compiler"); - } -} - -pub fn main() { - // {} would break - let _r: () = {}; - let mut slot = None; - // `{ test(...); }` would break - let _s : S = S{ x: { test(&mut slot); } }; - - let _b = not(true); -} diff --git a/tests/ui/borrowck/moved-value-in-thread-loop-12041.rs b/tests/ui/borrowck/moved-value-in-thread-loop-12041.rs new file mode 100644 index 00000000000..98f9cdbdef7 --- /dev/null +++ b/tests/ui/borrowck/moved-value-in-thread-loop-12041.rs @@ -0,0 +1,15 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12041 + +use std::sync::mpsc::channel; +use std::thread; + +fn main() { + let (tx, rx) = channel(); + let _t = thread::spawn(move|| -> () { + loop { + let tx = tx; + //~^ ERROR: use of moved value: `tx` + tx.send(1); + } + }); +} diff --git a/tests/ui/borrowck/moved-value-in-thread-loop-12041.stderr b/tests/ui/borrowck/moved-value-in-thread-loop-12041.stderr new file mode 100644 index 00000000000..627dd193dad --- /dev/null +++ b/tests/ui/borrowck/moved-value-in-thread-loop-12041.stderr @@ -0,0 +1,11 @@ +error[E0382]: use of moved value: `tx` + --> $DIR/moved-value-in-thread-loop-12041.rs:10:22 + | +LL | let tx = tx; + | ^^ value moved here, in previous iteration of loop + | + = note: move occurs because `tx` has type `std::sync::mpsc::Sender`, which does not implement the `Copy` trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/borrowck/refcell-borrow-comparison-12033.rs b/tests/ui/borrowck/refcell-borrow-comparison-12033.rs new file mode 100644 index 00000000000..de22cedd5b9 --- /dev/null +++ b/tests/ui/borrowck/refcell-borrow-comparison-12033.rs @@ -0,0 +1,9 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12033 + +//@ run-pass +use std::cell::RefCell; + +fn main() { + let x = RefCell::new(0); + if *x.borrow() == 0 {} else {} +} diff --git a/tests/ui/borrowck/refcell-borrow-comparison.rs b/tests/ui/borrowck/refcell-borrow-comparison.rs deleted file mode 100644 index 0bf6490bafe..00000000000 --- a/tests/ui/borrowck/refcell-borrow-comparison.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -use std::cell::RefCell; - -fn main() { - let x = RefCell::new(0); - if *x.borrow() == 0 {} else {} -} diff --git a/tests/ui/borrowck/string-literal-match-patterns-11869.rs b/tests/ui/borrowck/string-literal-match-patterns-11869.rs new file mode 100644 index 00000000000..4c159e457cf --- /dev/null +++ b/tests/ui/borrowck/string-literal-match-patterns-11869.rs @@ -0,0 +1,18 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11869 + +//@ check-pass +#![allow(dead_code)] + +struct A { + a: String +} + +fn borrow<'a>(binding: &'a A) -> &'a str { + match &*binding.a { + "in" => "in_", + "ref" => "ref_", + ident => ident + } +} + +fn main() {} diff --git a/tests/ui/closures/fnonce-moved-twice-12127.rs b/tests/ui/closures/fnonce-moved-twice-12127.rs new file mode 100644 index 00000000000..369ddcafaab --- /dev/null +++ b/tests/ui/closures/fnonce-moved-twice-12127.rs @@ -0,0 +1,16 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12127 + +#![feature(unboxed_closures, tuple_trait)] + +fn to_fn_once>(f: F) -> F { f } +fn do_it(x: &isize) { } + +fn main() { + let x: Box<_> = Box::new(22); + let f = to_fn_once(move|| do_it(&*x)); + to_fn_once(move|| { + f(); + f(); + //~^ ERROR: use of moved value: `f` + })() +} diff --git a/tests/ui/closures/fnonce-moved-twice-12127.stderr b/tests/ui/closures/fnonce-moved-twice-12127.stderr new file mode 100644 index 00000000000..c2e12827527 --- /dev/null +++ b/tests/ui/closures/fnonce-moved-twice-12127.stderr @@ -0,0 +1,18 @@ +error[E0382]: use of moved value: `f` + --> $DIR/fnonce-moved-twice-12127.rs:13:9 + | +LL | f(); + | --- `f` moved due to this call +LL | f(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/fnonce-moved-twice-12127.rs:12:9 + | +LL | f(); + | ^ + = note: move occurs because `f` has type `{closure@$DIR/fnonce-moved-twice-12127.rs:10:24: 10:30}`, which does not implement the `Copy` trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/closures/fnonce-moved-twice.rs b/tests/ui/closures/fnonce-moved-twice.rs deleted file mode 100644 index 199d542e816..00000000000 --- a/tests/ui/closures/fnonce-moved-twice.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(unboxed_closures, tuple_trait)] - -fn to_fn_once>(f: F) -> F { f } -fn do_it(x: &isize) { } - -fn main() { - let x: Box<_> = Box::new(22); - let f = to_fn_once(move|| do_it(&*x)); - to_fn_once(move|| { - f(); - f(); - //~^ ERROR: use of moved value: `f` - })() -} diff --git a/tests/ui/closures/moved-upvar-mut-rebind-11958.rs b/tests/ui/closures/moved-upvar-mut-rebind-11958.rs new file mode 100644 index 00000000000..701dc1a2cef --- /dev/null +++ b/tests/ui/closures/moved-upvar-mut-rebind-11958.rs @@ -0,0 +1,13 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11958 + +//@ run-pass + +// We shouldn't need to rebind a moved upvar as mut if it's already +// marked as mut + +pub fn main() { + let mut x = 1; + let _thunk = Box::new(move|| { x = 2; }); + //~^ WARN value assigned to `x` is never read + //~| WARN unused variable: `x` +} diff --git a/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr b/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr new file mode 100644 index 00000000000..b12bbcad925 --- /dev/null +++ b/tests/ui/closures/moved-upvar-mut-rebind-11958.stderr @@ -0,0 +1,20 @@ +warning: value assigned to `x` is never read + --> $DIR/moved-upvar-mut-rebind-11958.rs:10:36 + | +LL | let _thunk = Box::new(move|| { x = 2; }); + | ^ + | + = help: maybe it is overwritten before being read? + = note: `#[warn(unused_assignments)]` on by default + +warning: unused variable: `x` + --> $DIR/moved-upvar-mut-rebind-11958.rs:10:36 + | +LL | let _thunk = Box::new(move|| { x = 2; }); + | ^ + | + = help: did you mean to capture by reference instead? + = note: `#[warn(unused_variables)]` on by default + +warning: 2 warnings emitted + diff --git a/tests/ui/closures/moved-upvar-mut-rebind.rs b/tests/ui/closures/moved-upvar-mut-rebind.rs deleted file mode 100644 index 9185c5158af..00000000000 --- a/tests/ui/closures/moved-upvar-mut-rebind.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass - -// We shouldn't need to rebind a moved upvar as mut if it's already -// marked as mut - -pub fn main() { - let mut x = 1; - let _thunk = Box::new(move|| { x = 2; }); - //~^ WARN value assigned to `x` is never read - //~| WARN unused variable: `x` -} diff --git a/tests/ui/coercion/any-trait-object-debug-12744.rs b/tests/ui/coercion/any-trait-object-debug-12744.rs new file mode 100644 index 00000000000..4d981c077ee --- /dev/null +++ b/tests/ui/coercion/any-trait-object-debug-12744.rs @@ -0,0 +1,7 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12744 + +//@ run-pass +fn main() { + fn test() -> Box { Box::new(1) } + println!("{:?}", test()) +} diff --git a/tests/ui/collections/hashset-connected-border-12860.rs b/tests/ui/collections/hashset-connected-border-12860.rs new file mode 100644 index 00000000000..40185bef7c8 --- /dev/null +++ b/tests/ui/collections/hashset-connected-border-12860.rs @@ -0,0 +1,51 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12860 + +//@ run-pass +use std::collections::HashSet; + +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +struct XYZ { + x: isize, + y: isize, + z: isize +} + +fn main() { + let mut connected = HashSet::new(); + let mut border = HashSet::new(); + + let middle = XYZ{x: 0, y: 0, z: 0}; + border.insert(middle); + + while !border.is_empty() && connected.len() < 10000 { + let choice = *(border.iter().next().unwrap()); + border.remove(&choice); + connected.insert(choice); + + let cxp = XYZ{x: choice.x + 1, y: choice.y, z: choice.z}; + let cxm = XYZ{x: choice.x - 1, y: choice.y, z: choice.z}; + let cyp = XYZ{x: choice.x, y: choice.y + 1, z: choice.z}; + let cym = XYZ{x: choice.x, y: choice.y - 1, z: choice.z}; + let czp = XYZ{x: choice.x, y: choice.y, z: choice.z + 1}; + let czm = XYZ{x: choice.x, y: choice.y, z: choice.z - 1}; + + if !connected.contains(&cxp) { + border.insert(cxp); + } + if !connected.contains(&cxm){ + border.insert(cxm); + } + if !connected.contains(&cyp){ + border.insert(cyp); + } + if !connected.contains(&cym) { + border.insert(cym); + } + if !connected.contains(&czp){ + border.insert(czp); + } + if !connected.contains(&czm) { + border.insert(czm); + } + } +} diff --git a/tests/ui/collections/hashset-connected-border.rs b/tests/ui/collections/hashset-connected-border.rs deleted file mode 100644 index 255f6670793..00000000000 --- a/tests/ui/collections/hashset-connected-border.rs +++ /dev/null @@ -1,49 +0,0 @@ -//@ run-pass -use std::collections::HashSet; - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct XYZ { - x: isize, - y: isize, - z: isize -} - -fn main() { - let mut connected = HashSet::new(); - let mut border = HashSet::new(); - - let middle = XYZ{x: 0, y: 0, z: 0}; - border.insert(middle); - - while !border.is_empty() && connected.len() < 10000 { - let choice = *(border.iter().next().unwrap()); - border.remove(&choice); - connected.insert(choice); - - let cxp = XYZ{x: choice.x + 1, y: choice.y, z: choice.z}; - let cxm = XYZ{x: choice.x - 1, y: choice.y, z: choice.z}; - let cyp = XYZ{x: choice.x, y: choice.y + 1, z: choice.z}; - let cym = XYZ{x: choice.x, y: choice.y - 1, z: choice.z}; - let czp = XYZ{x: choice.x, y: choice.y, z: choice.z + 1}; - let czm = XYZ{x: choice.x, y: choice.y, z: choice.z - 1}; - - if !connected.contains(&cxp) { - border.insert(cxp); - } - if !connected.contains(&cxm){ - border.insert(cxm); - } - if !connected.contains(&cyp){ - border.insert(cyp); - } - if !connected.contains(&cym) { - border.insert(cym); - } - if !connected.contains(&czp){ - border.insert(czp); - } - if !connected.contains(&czm) { - border.insert(czm); - } - } -} diff --git a/tests/ui/const-generics/vec-macro-in-static-array.rs b/tests/ui/const-generics/vec-macro-in-static-array.rs index 9f1fc42774f..7a81836e255 100644 --- a/tests/ui/const-generics/vec-macro-in-static-array.rs +++ b/tests/ui/const-generics/vec-macro-in-static-array.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13446 + // Used to cause ICE static VEC: [u32; 256] = vec![]; diff --git a/tests/ui/const-generics/vec-macro-in-static-array.stderr b/tests/ui/const-generics/vec-macro-in-static-array.stderr new file mode 100644 index 00000000000..de21f2274f3 --- /dev/null +++ b/tests/ui/const-generics/vec-macro-in-static-array.stderr @@ -0,0 +1,13 @@ +error[E0308]: mismatched types + --> $DIR/vec-macro-in-static-array.rs:5:26 + | +LL | static VEC: [u32; 256] = vec![]; + | ^^^^^^ expected `[u32; 256]`, found `Vec<_>` + | + = note: expected array `[u32; 256]` + found struct `Vec<_>` + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/extern/format-message-windows-ffi.rs b/tests/ui/extern/format-message-windows-ffi.rs deleted file mode 100644 index 381e3f15259..00000000000 --- a/tests/ui/extern/format-message-windows-ffi.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ run-pass - -#[cfg(windows)] -mod imp { - type LPVOID = *mut u8; - type DWORD = u32; - type LPWSTR = *mut u16; - - extern "system" { - fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const u8) - -> DWORD; - } - - pub fn test() { - let mut buf: [u16; 50] = [0; 50]; - let ret = unsafe { - FormatMessageW(0x1000, core::ptr::null_mut(), 1, 0x400, - buf.as_mut_ptr(), buf.len() as u32, core::ptr::null()) - }; - // On some 32-bit Windowses (Win7-8 at least) this will panic with segmented - // stacks taking control of pvArbitrary - assert!(ret != 0); - } -} - -#[cfg(not(windows))] -mod imp { - pub fn test() { } -} - -fn main() { - imp::test() -} diff --git a/tests/ui/extern/windows-tcb-trash-13259.rs b/tests/ui/extern/windows-tcb-trash-13259.rs new file mode 100644 index 00000000000..0852e31251a --- /dev/null +++ b/tests/ui/extern/windows-tcb-trash-13259.rs @@ -0,0 +1,49 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13259 + +//@ run-pass + +#[cfg(windows)] +mod imp { + type LPVOID = *mut u8; + type DWORD = u32; + type LPWSTR = *mut u16; + + extern "system" { + fn FormatMessageW( + flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const u8, + ) -> DWORD; + } + + pub fn test() { + let mut buf: [u16; 50] = [0; 50]; + let ret = unsafe { + FormatMessageW( + 0x1000, + core::ptr::null_mut(), + 1, + 0x400, + buf.as_mut_ptr(), + buf.len() as u32, + core::ptr::null(), + ) + }; + // On some 32-bit Windowses (Win7-8 at least) this will panic with segmented + // stacks taking control of pvArbitrary + assert!(ret != 0); + } +} + +#[cfg(not(windows))] +mod imp { + pub fn test() {} +} + +fn main() { + imp::test() +} diff --git a/tests/ui/fn/anonymous-parameters-trait-13105.rs b/tests/ui/fn/anonymous-parameters-trait-13105.rs new file mode 100644 index 00000000000..171dab15fe7 --- /dev/null +++ b/tests/ui/fn/anonymous-parameters-trait-13105.rs @@ -0,0 +1,11 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13105 + +//@ edition: 2015 +//@ check-pass + +trait Foo { + #[allow(anonymous_parameters)] + fn quux(u8) {} +} + +fn main() {} diff --git a/tests/ui/fn/anonymous-parameters-trait.rs b/tests/ui/fn/anonymous-parameters-trait.rs deleted file mode 100644 index d119aa9c788..00000000000 --- a/tests/ui/fn/anonymous-parameters-trait.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ edition: 2015 -//@ check-pass - -trait Foo { - #[allow(anonymous_parameters)] - fn quux(u8) {} -} - -fn main() {} diff --git a/tests/ui/imports/use-in-impl-scope.rs b/tests/ui/imports/use-in-impl-scope.rs deleted file mode 100644 index 4d45846bc60..00000000000 --- a/tests/ui/imports/use-in-impl-scope.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ edition: 2015 -//@ check-pass -#![allow(dead_code)] - -pub struct Foo; - -mod bar { - use Foo; - - impl Foo { - fn baz(&self) {} - } -} -fn main() {} diff --git a/tests/ui/issues/issue-11771.stderr b/tests/ui/issues/issue-11771.stderr deleted file mode 100644 index 5603dc18b63..00000000000 --- a/tests/ui/issues/issue-11771.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0277]: cannot add `()` to `{integer}` - --> $DIR/issue-11771.rs:3:7 - | -LL | 1 + - | ^ no implementation for `{integer} + ()` - | - = help: the trait `Add<()>` is not implemented for `{integer}` - = help: the following other types implement trait `Add`: - `&f128` implements `Add` - `&f128` implements `Add` - `&f16` implements `Add` - `&f16` implements `Add` - `&f32` implements `Add` - `&f32` implements `Add` - `&f64` implements `Add` - `&f64` implements `Add` - and 56 others - -error[E0277]: cannot add `()` to `{integer}` - --> $DIR/issue-11771.rs:8:7 - | -LL | 1 + - | ^ no implementation for `{integer} + ()` - | - = help: the trait `Add<()>` is not implemented for `{integer}` - = help: the following other types implement trait `Add`: - `&f128` implements `Add` - `&f128` implements `Add` - `&f16` implements `Add` - `&f16` implements `Add` - `&f32` implements `Add` - `&f32` implements `Add` - `&f64` implements `Add` - `&f64` implements `Add` - and 56 others - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/issue-11844.stderr b/tests/ui/issues/issue-11844.stderr deleted file mode 100644 index 9ff66eaef49..00000000000 --- a/tests/ui/issues/issue-11844.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-11844.rs:4:9 - | -LL | match a { - | - this expression has type `Option>` -LL | Ok(a) => - | ^^^^^ expected `Option>`, found `Result<_, _>` - | - = note: expected enum `Option>` - found enum `Result<_, _>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-11958.stderr b/tests/ui/issues/issue-11958.stderr deleted file mode 100644 index 5dca4c2f01d..00000000000 --- a/tests/ui/issues/issue-11958.stderr +++ /dev/null @@ -1,20 +0,0 @@ -warning: value assigned to `x` is never read - --> $DIR/issue-11958.rs:8:36 - | -LL | let _thunk = Box::new(move|| { x = 2; }); - | ^ - | - = help: maybe it is overwritten before being read? - = note: `#[warn(unused_assignments)]` on by default - -warning: unused variable: `x` - --> $DIR/issue-11958.rs:8:36 - | -LL | let _thunk = Box::new(move|| { x = 2; }); - | ^ - | - = help: did you mean to capture by reference instead? - = note: `#[warn(unused_variables)]` on by default - -warning: 2 warnings emitted - diff --git a/tests/ui/issues/issue-12041.stderr b/tests/ui/issues/issue-12041.stderr deleted file mode 100644 index f2c10b83383..00000000000 --- a/tests/ui/issues/issue-12041.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0382]: use of moved value: `tx` - --> $DIR/issue-12041.rs:8:22 - | -LL | let tx = tx; - | ^^ value moved here, in previous iteration of loop - | - = note: move occurs because `tx` has type `std::sync::mpsc::Sender`, which does not implement the `Copy` trait - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/issues/issue-12127.stderr b/tests/ui/issues/issue-12127.stderr deleted file mode 100644 index 2a6233547ee..00000000000 --- a/tests/ui/issues/issue-12127.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0382]: use of moved value: `f` - --> $DIR/issue-12127.rs:11:9 - | -LL | f(); - | --- `f` moved due to this call -LL | f(); - | ^ value used here after move - | -note: this value implements `FnOnce`, which causes it to be moved when called - --> $DIR/issue-12127.rs:10:9 - | -LL | f(); - | ^ - = note: move occurs because `f` has type `{closure@$DIR/issue-12127.rs:8:24: 8:30}`, which does not implement the `Copy` trait - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/issues/issue-12567.stderr b/tests/ui/issues/issue-12567.stderr deleted file mode 100644 index 0b19299ece3..00000000000 --- a/tests/ui/issues/issue-12567.stderr +++ /dev/null @@ -1,51 +0,0 @@ -error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:2:11 - | -LL | match (l1, l2) { - | ^^^^^^^^ cannot move out of here -... -LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | -- data moved here -LL | => println!("one empty"), -LL | (&[hd1, ..], &[hd2, ..]) - | --- ...and here - | - = note: move occurs because these variables have types that don't implement the `Copy` trait -help: consider removing the borrow - | -LL - (&[], &[hd, ..]) | (&[hd, ..], &[]) -LL + (&[], [hd, ..]) | (&[hd, ..], &[]) - | -help: consider removing the borrow - | -LL - (&[hd1, ..], &[hd2, ..]) -LL + (&[hd1, ..], [hd2, ..]) - | - -error[E0508]: cannot move out of type `[T]`, a non-copy slice - --> $DIR/issue-12567.rs:2:11 - | -LL | match (l1, l2) { - | ^^^^^^^^ cannot move out of here -... -LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) - | -- data moved here -LL | => println!("one empty"), -LL | (&[hd1, ..], &[hd2, ..]) - | --- ...and here - | - = note: move occurs because these variables have types that don't implement the `Copy` trait -help: consider removing the borrow - | -LL - (&[], &[hd, ..]) | (&[hd, ..], &[]) -LL + (&[], [hd, ..]) | (&[hd, ..], &[]) - | -help: consider removing the borrow - | -LL - (&[hd1, ..], &[hd2, ..]) -LL + ([hd1, ..], &[hd2, ..]) - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0508`. diff --git a/tests/ui/issues/issue-12863.stderr b/tests/ui/issues/issue-12863.stderr deleted file mode 100644 index 95d4a704e72..00000000000 --- a/tests/ui/issues/issue-12863.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0532]: expected unit struct, unit variant or constant, found function `foo::bar` - --> $DIR/issue-12863.rs:5:9 - | -LL | foo::bar => {} - | ^^^^^^^^ not a unit struct, unit variant or constant - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0532`. diff --git a/tests/ui/issues/issue-13058.stderr b/tests/ui/issues/issue-13058.stderr deleted file mode 100644 index 4f4108fa182..00000000000 --- a/tests/ui/issues/issue-13058.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0621]: explicit lifetime required in the type of `cont` - --> $DIR/issue-13058.rs:14:21 - | -LL | let cont_iter = cont.iter(); - | ^^^^^^^^^^^ lifetime `'r` required - | -help: add explicit lifetime `'r` to the type of `cont` - | -LL | fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &'r T) -> bool - | ++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/issues/issue-13359.stderr b/tests/ui/issues/issue-13359.stderr deleted file mode 100644 index 91f5de8e8f3..00000000000 --- a/tests/ui/issues/issue-13359.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-13359.rs:8:9 - | -LL | foo(1*(1 as isize)); - | --- ^^^^^^^^^^^^^^ expected `i16`, found `isize` - | | - | arguments to this function are incorrect - | -note: function defined here - --> $DIR/issue-13359.rs:3:4 - | -LL | fn foo(_s: i16) { } - | ^^^ ------- -help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit - | -LL | foo((1*(1 as isize)).try_into().unwrap()); - | + +++++++++++++++++++++ - -error[E0308]: mismatched types - --> $DIR/issue-13359.rs:12:9 - | -LL | bar(1*(1 as usize)); - | --- ^^^^^^^^^^^^^^ expected `u32`, found `usize` - | | - | arguments to this function are incorrect - | -note: function defined here - --> $DIR/issue-13359.rs:5:4 - | -LL | fn bar(_s: u32) { } - | ^^^ ------- -help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit - | -LL | bar((1*(1 as usize)).try_into().unwrap()); - | + +++++++++++++++++++++ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-13407.stderr b/tests/ui/issues/issue-13407.stderr deleted file mode 100644 index ac2eb6581fe..00000000000 --- a/tests/ui/issues/issue-13407.stderr +++ /dev/null @@ -1,27 +0,0 @@ -error[E0603]: unit struct `C` is private - --> $DIR/issue-13407.rs:6:8 - | -LL | A::C = 1; - | ^ private unit struct - | -note: the unit struct `C` is defined here - --> $DIR/issue-13407.rs:2:5 - | -LL | struct C; - | ^^^^^^^^^ - -error[E0308]: mismatched types - --> $DIR/issue-13407.rs:6:5 - | -LL | struct C; - | -------- unit struct defined here -... -LL | A::C = 1; - | ^^^^ - this expression has type `{integer}` - | | - | expected integer, found `C` - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0308, E0603. -For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-13446.stderr b/tests/ui/issues/issue-13446.stderr deleted file mode 100644 index 28c459e6e62..00000000000 --- a/tests/ui/issues/issue-13446.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-13446.rs:3:26 - | -LL | static VEC: [u32; 256] = vec![]; - | ^^^^^^ expected `[u32; 256]`, found `Vec<_>` - | - = note: expected array `[u32; 256]` - found struct `Vec<_>` - = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-13466.stderr b/tests/ui/issues/issue-13466.stderr deleted file mode 100644 index 68a555a1626..00000000000 --- a/tests/ui/issues/issue-13466.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-13466.rs:10:9 - | -LL | let _x: usize = match Some(1) { - | ------- this expression has type `Option<{integer}>` -LL | Ok(u) => u, - | ^^^^^ expected `Option<{integer}>`, found `Result<_, _>` - | - = note: expected enum `Option<{integer}>` - found enum `Result<_, _>` - -error[E0308]: mismatched types - --> $DIR/issue-13466.rs:16:9 - | -LL | let _x: usize = match Some(1) { - | ------- this expression has type `Option<{integer}>` -... -LL | Err(e) => panic!(e) - | ^^^^^^ expected `Option<{integer}>`, found `Result<_, _>` - | - = note: expected enum `Option<{integer}>` - found enum `Result<_, _>` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/iterators/bytes-iterator-clone-12677.rs b/tests/ui/iterators/bytes-iterator-clone-12677.rs new file mode 100644 index 00000000000..cfbb85a3ecb --- /dev/null +++ b/tests/ui/iterators/bytes-iterator-clone-12677.rs @@ -0,0 +1,11 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12677 + +//@ run-pass + +fn main() { + let s = "Hello"; + let first = s.bytes(); + let second = first.clone(); + + assert_eq!(first.collect::>(), second.collect::>()) +} diff --git a/tests/ui/iterators/bytes-iterator-clone.rs b/tests/ui/iterators/bytes-iterator-clone.rs deleted file mode 100644 index dbc2dbc8527..00000000000 --- a/tests/ui/iterators/bytes-iterator-clone.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -fn main() { - let s = "Hello"; - let first = s.bytes(); - let second = first.clone(); - - assert_eq!(first.collect::>(), second.collect::>()) -} diff --git a/tests/ui/iterators/phf-map-entries-iterator.rs b/tests/ui/iterators/phf-map-entries-iterator.rs deleted file mode 100644 index 5f733e85948..00000000000 --- a/tests/ui/iterators/phf-map-entries-iterator.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ check-pass -//@ revisions: current next -//@ ignore-compare-mode-next-solver (explicit revisions) -//@[next] compile-flags: -Znext-solver - -use std::slice; - -pub struct PhfMapEntries<'a, T: 'a> { - iter: slice::Iter<'a, (&'static str, T)>, -} - -impl<'a, T> Iterator for PhfMapEntries<'a, T> { - type Item = (&'static str, &'a T); - - fn next(&mut self) -> Option<(&'static str, &'a T)> { - self.iter.by_ref().map(|&(key, ref value)| (key, value)).next() - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -fn main() {} diff --git a/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.rs b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.rs new file mode 100644 index 00000000000..6cfe440b43d --- /dev/null +++ b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.rs @@ -0,0 +1,29 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13058 + +use std::ops::Range; + +trait Itble<'r, T, I: Iterator> { fn iter(&'r self) -> I; } + +impl<'r> Itble<'r, usize, Range> for (usize, usize) { + fn iter(&'r self) -> Range { + let &(min, max) = self; + min..max + } +} + +fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool +{ + let cont_iter = cont.iter(); +//~^ ERROR explicit lifetime required in the type of `cont` [E0621] + let result = cont_iter.fold(Some(0), |state, val| { + state.map_or(None, |mask| { + let bit = 1 << val; + if mask & bit == 0 {Some(mask|bit)} else {None} + }) + }); + result.is_some() +} + +fn main() { + check(&(3, 5)); +} diff --git a/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.stderr b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.stderr new file mode 100644 index 00000000000..e6564e36b21 --- /dev/null +++ b/tests/ui/lifetimes/iterator-trait-lifetime-error-13058.stderr @@ -0,0 +1,14 @@ +error[E0621]: explicit lifetime required in the type of `cont` + --> $DIR/iterator-trait-lifetime-error-13058.rs:16:21 + | +LL | let cont_iter = cont.iter(); + | ^^^^^^^^^^^ lifetime `'r` required + | +help: add explicit lifetime `'r` to the type of `cont` + | +LL | fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &'r T) -> bool + | ++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0621`. diff --git a/tests/ui/lifetimes/iterator-trait-lifetime-error.rs b/tests/ui/lifetimes/iterator-trait-lifetime-error.rs deleted file mode 100644 index a5806feb720..00000000000 --- a/tests/ui/lifetimes/iterator-trait-lifetime-error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::ops::Range; - -trait Itble<'r, T, I: Iterator> { fn iter(&'r self) -> I; } - -impl<'r> Itble<'r, usize, Range> for (usize, usize) { - fn iter(&'r self) -> Range { - let &(min, max) = self; - min..max - } -} - -fn check<'r, I: Iterator, T: Itble<'r, usize, I>>(cont: &T) -> bool -{ - let cont_iter = cont.iter(); -//~^ ERROR explicit lifetime required in the type of `cont` [E0621] - let result = cont_iter.fold(Some(0), |state, val| { - state.map_or(None, |mask| { - let bit = 1 << val; - if mask & bit == 0 {Some(mask|bit)} else {None} - }) - }); - result.is_some() -} - -fn main() { - check(&(3, 5)); -} diff --git a/tests/ui/lifetimes/lifetime-inference-destructuring-arg.rs b/tests/ui/lifetimes/lifetime-inference-destructuring-arg.rs new file mode 100644 index 00000000000..7a019a71d75 --- /dev/null +++ b/tests/ui/lifetimes/lifetime-inference-destructuring-arg.rs @@ -0,0 +1,26 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13167 + +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +use std::slice; + +pub struct PhfMapEntries<'a, T: 'a> { + iter: slice::Iter<'a, (&'static str, T)>, +} + +impl<'a, T> Iterator for PhfMapEntries<'a, T> { + type Item = (&'static str, &'a T); + + fn next(&mut self) -> Option<(&'static str, &'a T)> { + self.iter.by_ref().map(|&(key, ref value)| (key, value)).next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/matcher-trait-equality-13323.rs b/tests/ui/lifetimes/matcher-trait-equality-13323.rs new file mode 100644 index 00000000000..efd56294b39 --- /dev/null +++ b/tests/ui/lifetimes/matcher-trait-equality-13323.rs @@ -0,0 +1,60 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13323 + +//@ run-pass + +struct StrWrap { + s: String +} + +impl StrWrap { + fn new(s: &str) -> StrWrap { + StrWrap { s: s.to_string() } + } + + fn get_s<'a>(&'a self) -> &'a str { + &self.s + } +} + +struct MyStruct { + s: StrWrap +} + +impl MyStruct { + fn new(s: &str) -> MyStruct { + MyStruct { s: StrWrap::new(s) } + } + + fn get_str_wrap<'a>(&'a self) -> &'a StrWrap { + &self.s + } +} + +trait Matcher { + fn matches(&self, actual: T) -> bool; +} + +fn assert_that>(actual: T, matcher: &U) { + assert!(matcher.matches(actual)); +} + +struct EqualTo { + expected: T +} + +impl Matcher for EqualTo { + fn matches(&self, actual: T) -> bool { + self.expected.eq(&actual) + } +} + +fn equal_to(expected: T) -> Box> { + Box::new(EqualTo { expected: expected }) +} + +pub fn main() { + let my_struct = MyStruct::new("zomg"); + let s = my_struct.get_str_wrap(); + + assert_that(s.get_s(), &*equal_to("zomg")); +} diff --git a/tests/ui/lifetimes/struct-lifetime-field-assignment-13405.rs b/tests/ui/lifetimes/struct-lifetime-field-assignment-13405.rs new file mode 100644 index 00000000000..9482d89681b --- /dev/null +++ b/tests/ui/lifetimes/struct-lifetime-field-assignment-13405.rs @@ -0,0 +1,21 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13405 + +//@ check-pass +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Foo<'a> { + i: &'a bool, + j: Option<&'a isize>, +} + +impl<'a> Foo<'a> { + fn bar(&mut self, j: &isize) { + let child = Foo { + i: self.i, + j: Some(j) + }; + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/struct-lifetime-field-assignment.rs b/tests/ui/lifetimes/struct-lifetime-field-assignment.rs deleted file mode 100644 index 80b298d2f37..00000000000 --- a/tests/ui/lifetimes/struct-lifetime-field-assignment.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ check-pass -#![allow(dead_code)] -#![allow(unused_variables)] - -struct Foo<'a> { - i: &'a bool, - j: Option<&'a isize>, -} - -impl<'a> Foo<'a> { - fn bar(&mut self, j: &isize) { - let child = Foo { - i: self.i, - j: Some(j) - }; - } -} - -fn main() {} diff --git a/tests/ui/lifetimes/unsafe-transmute-in-find-11740.rs b/tests/ui/lifetimes/unsafe-transmute-in-find-11740.rs new file mode 100644 index 00000000000..eeecd2e9e40 --- /dev/null +++ b/tests/ui/lifetimes/unsafe-transmute-in-find-11740.rs @@ -0,0 +1,28 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11740 + +//@ check-pass + +struct Attr { + name: String, + value: String, +} + +struct Element { + attrs: Vec>, +} + +impl Element { + pub unsafe fn get_attr<'a>(&'a self, name: &str) { + self.attrs + .iter() + .find(|attr| { + let attr: &&Box = std::mem::transmute(attr); + true + }); + } +} + +fn main() { + let element = Element { attrs: Vec::new() }; + unsafe { let () = element.get_attr("foo"); }; +} diff --git a/tests/ui/match/function-in-pattern-error.rs b/tests/ui/match/function-in-pattern-error.rs deleted file mode 100644 index 1ac1c3d818e..00000000000 --- a/tests/ui/match/function-in-pattern-error.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod foo { pub fn bar() {} } - -fn main() { - match () { - foo::bar => {} - //~^ ERROR expected unit struct, unit variant or constant, found function `foo::bar` - } -} diff --git a/tests/ui/match/guard-literal-range-shadow.rs b/tests/ui/match/guard-literal-range-shadow.rs deleted file mode 100644 index fbd1d75067b..00000000000 --- a/tests/ui/match/guard-literal-range-shadow.rs +++ /dev/null @@ -1,178 +0,0 @@ -//@ run-pass - -// Tests that match expression handles overlapped literal and range -// properly in the presence of guard function. - -fn val() -> usize { 1 } - -static CONST: usize = 1; - -pub fn main() { - lit_shadow_range(); - range_shadow_lit(); - range_shadow_range(); - multi_pats_shadow_lit(); - multi_pats_shadow_range(); - lit_shadow_multi_pats(); - range_shadow_multi_pats(); - misc(); -} - -fn lit_shadow_range() { - assert_eq!(2, match 1 { - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - let x = 0; - assert_eq!(2, match x+1 { - 0 => 0, - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - assert_eq!(2, match val() { - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - assert_eq!(2, match CONST { - 0 => 0, - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); - - // value is out of the range of second arm, should match wildcard pattern - assert_eq!(3, match 3 { - 1 if false => 1, - 1..=2 => 2, - _ => 3 - }); -} - -fn range_shadow_lit() { - assert_eq!(2, match 1 { - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - let x = 0; - assert_eq!(2, match x+1 { - 0 => 0, - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - assert_eq!(2, match val() { - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - assert_eq!(2, match CONST { - 0 => 0, - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); - - // ditto - assert_eq!(3, match 3 { - 1..=2 if false => 1, - 1 => 2, - _ => 3 - }); -} - -fn range_shadow_range() { - assert_eq!(2, match 1 { - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - let x = 0; - assert_eq!(2, match x+1 { - 100 => 0, - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - assert_eq!(2, match val() { - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - assert_eq!(2, match CONST { - 100 => 0, - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); - - // ditto - assert_eq!(3, match 5 { - 0..=2 if false => 1, - 1..=3 => 2, - _ => 3, - }); -} - -fn multi_pats_shadow_lit() { - assert_eq!(2, match 1 { - 100 => 0, - 0 | 1..=10 if false => 1, - 1 => 2, - _ => 3, - }); -} - -fn multi_pats_shadow_range() { - assert_eq!(2, match 1 { - 100 => 0, - 0 | 1..=10 if false => 1, - 1..=3 => 2, - _ => 3, - }); -} - -fn lit_shadow_multi_pats() { - assert_eq!(2, match 1 { - 100 => 0, - 1 if false => 1, - 0 | 1..=10 => 2, - _ => 3, - }); -} - -fn range_shadow_multi_pats() { - assert_eq!(2, match 1 { - 100 => 0, - 1..=3 if false => 1, - 0 | 1..=10 => 2, - _ => 3, - }); -} - -fn misc() { - enum Foo { - Bar(#[allow(dead_code)] usize, bool) - } - // This test basically mimics how trace_macros! macro is implemented, - // which is a rare combination of vector patterns, multiple wild-card - // patterns and guard functions. - let r = match [Foo::Bar(0, false)] { - [Foo::Bar(_, pred)] if pred => 1, - [Foo::Bar(_, pred)] if !pred => 2, - _ => 0, - }; - assert_eq!(2, r); -} diff --git a/tests/ui/match/option-result-mismatch-11844.rs b/tests/ui/match/option-result-mismatch-11844.rs new file mode 100644 index 00000000000..24a2004134d --- /dev/null +++ b/tests/ui/match/option-result-mismatch-11844.rs @@ -0,0 +1,10 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11844 + +fn main() { + let a = Some(Box::new(1)); + match a { + Ok(a) => //~ ERROR: mismatched types + println!("{}",a), + None => panic!() + } +} diff --git a/tests/ui/match/option-result-mismatch-11844.stderr b/tests/ui/match/option-result-mismatch-11844.stderr new file mode 100644 index 00000000000..8a84b7b8a48 --- /dev/null +++ b/tests/ui/match/option-result-mismatch-11844.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/option-result-mismatch-11844.rs:6:9 + | +LL | match a { + | - this expression has type `Option>` +LL | Ok(a) => + | ^^^^^ expected `Option>`, found `Result<_, _>` + | + = note: expected enum `Option>` + found enum `Result<_, _>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/option-result-mismatch.rs b/tests/ui/match/option-result-mismatch.rs deleted file mode 100644 index f974a470296..00000000000 --- a/tests/ui/match/option-result-mismatch.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let a = Some(Box::new(1)); - match a { - Ok(a) => //~ ERROR: mismatched types - println!("{}",a), - None => panic!() - } -} diff --git a/tests/ui/match/option-result-type-param-mismatch-13466.rs b/tests/ui/match/option-result-type-param-mismatch-13466.rs new file mode 100644 index 00000000000..05dbdfdee0e --- /dev/null +++ b/tests/ui/match/option-result-type-param-mismatch-13466.rs @@ -0,0 +1,24 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13466 + +// Regression test for #13466 + +//@ dont-require-annotations: NOTE + +pub fn main() { + // The expected arm type `Option` has one type parameter, while + // the actual arm `Result` has two. typeck should not be + // tricked into looking up a non-existing second type parameter. + let _x: usize = match Some(1) { + Ok(u) => u, + //~^ ERROR mismatched types + //~| NOTE expected enum `Option<{integer}>` + //~| NOTE found enum `Result<_, _>` + //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` + + Err(e) => panic!(e) + //~^ ERROR mismatched types + //~| NOTE expected enum `Option<{integer}>` + //~| NOTE found enum `Result<_, _>` + //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` + }; +} diff --git a/tests/ui/match/option-result-type-param-mismatch-13466.stderr b/tests/ui/match/option-result-type-param-mismatch-13466.stderr new file mode 100644 index 00000000000..b0cf1591f5e --- /dev/null +++ b/tests/ui/match/option-result-type-param-mismatch-13466.stderr @@ -0,0 +1,26 @@ +error[E0308]: mismatched types + --> $DIR/option-result-type-param-mismatch-13466.rs:12:9 + | +LL | let _x: usize = match Some(1) { + | ------- this expression has type `Option<{integer}>` +LL | Ok(u) => u, + | ^^^^^ expected `Option<{integer}>`, found `Result<_, _>` + | + = note: expected enum `Option<{integer}>` + found enum `Result<_, _>` + +error[E0308]: mismatched types + --> $DIR/option-result-type-param-mismatch-13466.rs:18:9 + | +LL | let _x: usize = match Some(1) { + | ------- this expression has type `Option<{integer}>` +... +LL | Err(e) => panic!(e) + | ^^^^^^ expected `Option<{integer}>`, found `Result<_, _>` + | + = note: expected enum `Option<{integer}>` + found enum `Result<_, _>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/option-result-type-param-mismatch.rs b/tests/ui/match/option-result-type-param-mismatch.rs deleted file mode 100644 index 78ce4c1d2f6..00000000000 --- a/tests/ui/match/option-result-type-param-mismatch.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Regression test for #13466 - -//@ dont-require-annotations: NOTE - -pub fn main() { - // The expected arm type `Option` has one type parameter, while - // the actual arm `Result` has two. typeck should not be - // tricked into looking up a non-existing second type parameter. - let _x: usize = match Some(1) { - Ok(u) => u, - //~^ ERROR mismatched types - //~| NOTE expected enum `Option<{integer}>` - //~| NOTE found enum `Result<_, _>` - //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` - - Err(e) => panic!(e) - //~^ ERROR mismatched types - //~| NOTE expected enum `Option<{integer}>` - //~| NOTE found enum `Result<_, _>` - //~| NOTE expected `Option<{integer}>`, found `Result<_, _>` - }; -} diff --git a/tests/ui/match/overeager-sub-match-pruning-13027.rs b/tests/ui/match/overeager-sub-match-pruning-13027.rs new file mode 100644 index 00000000000..c4feb697f7d --- /dev/null +++ b/tests/ui/match/overeager-sub-match-pruning-13027.rs @@ -0,0 +1,180 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13027 + +//@ run-pass + +// Tests that match expression handles overlapped literal and range +// properly in the presence of guard function. + +fn val() -> usize { 1 } + +static CONST: usize = 1; + +pub fn main() { + lit_shadow_range(); + range_shadow_lit(); + range_shadow_range(); + multi_pats_shadow_lit(); + multi_pats_shadow_range(); + lit_shadow_multi_pats(); + range_shadow_multi_pats(); + misc(); +} + +fn lit_shadow_range() { + assert_eq!(2, match 1 { + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + let x = 0; + assert_eq!(2, match x+1 { + 0 => 0, + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + assert_eq!(2, match val() { + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + assert_eq!(2, match CONST { + 0 => 0, + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); + + // value is out of the range of second arm, should match wildcard pattern + assert_eq!(3, match 3 { + 1 if false => 1, + 1..=2 => 2, + _ => 3 + }); +} + +fn range_shadow_lit() { + assert_eq!(2, match 1 { + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + let x = 0; + assert_eq!(2, match x+1 { + 0 => 0, + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + assert_eq!(2, match val() { + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + assert_eq!(2, match CONST { + 0 => 0, + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); + + // ditto + assert_eq!(3, match 3 { + 1..=2 if false => 1, + 1 => 2, + _ => 3 + }); +} + +fn range_shadow_range() { + assert_eq!(2, match 1 { + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + let x = 0; + assert_eq!(2, match x+1 { + 100 => 0, + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + assert_eq!(2, match val() { + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + assert_eq!(2, match CONST { + 100 => 0, + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); + + // ditto + assert_eq!(3, match 5 { + 0..=2 if false => 1, + 1..=3 => 2, + _ => 3, + }); +} + +fn multi_pats_shadow_lit() { + assert_eq!(2, match 1 { + 100 => 0, + 0 | 1..=10 if false => 1, + 1 => 2, + _ => 3, + }); +} + +fn multi_pats_shadow_range() { + assert_eq!(2, match 1 { + 100 => 0, + 0 | 1..=10 if false => 1, + 1..=3 => 2, + _ => 3, + }); +} + +fn lit_shadow_multi_pats() { + assert_eq!(2, match 1 { + 100 => 0, + 1 if false => 1, + 0 | 1..=10 => 2, + _ => 3, + }); +} + +fn range_shadow_multi_pats() { + assert_eq!(2, match 1 { + 100 => 0, + 1..=3 if false => 1, + 0 | 1..=10 => 2, + _ => 3, + }); +} + +fn misc() { + enum Foo { + Bar(#[allow(dead_code)] usize, bool) + } + // This test basically mimics how trace_macros! macro is implemented, + // which is a rare combination of vector patterns, multiple wild-card + // patterns and guard functions. + let r = match [Foo::Bar(0, false)] { + [Foo::Bar(_, pred)] if pred => 1, + [Foo::Bar(_, pred)] if !pred => 2, + _ => 0, + }; + assert_eq!(2, r); +} diff --git a/tests/ui/match/slice-move-out-error-12567.rs b/tests/ui/match/slice-move-out-error-12567.rs new file mode 100644 index 00000000000..3f9bf9c76cf --- /dev/null +++ b/tests/ui/match/slice-move-out-error-12567.rs @@ -0,0 +1,15 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12567 + +fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { + match (l1, l2) { + //~^ ERROR: cannot move out of type `[T]`, a non-copy slice + //~| ERROR: cannot move out of type `[T]`, a non-copy slice + (&[], &[]) => println!("both empty"), + (&[], &[hd, ..]) | (&[hd, ..], &[]) + => println!("one empty"), + (&[hd1, ..], &[hd2, ..]) + => println!("both nonempty"), + } +} + +fn main() {} diff --git a/tests/ui/match/slice-move-out-error-12567.stderr b/tests/ui/match/slice-move-out-error-12567.stderr new file mode 100644 index 00000000000..ab5377d4701 --- /dev/null +++ b/tests/ui/match/slice-move-out-error-12567.stderr @@ -0,0 +1,51 @@ +error[E0508]: cannot move out of type `[T]`, a non-copy slice + --> $DIR/slice-move-out-error-12567.rs:4:11 + | +LL | match (l1, l2) { + | ^^^^^^^^ cannot move out of here +... +LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) + | -- data moved here +LL | => println!("one empty"), +LL | (&[hd1, ..], &[hd2, ..]) + | --- ...and here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the borrow + | +LL - (&[], &[hd, ..]) | (&[hd, ..], &[]) +LL + (&[], [hd, ..]) | (&[hd, ..], &[]) + | +help: consider removing the borrow + | +LL - (&[hd1, ..], &[hd2, ..]) +LL + (&[hd1, ..], [hd2, ..]) + | + +error[E0508]: cannot move out of type `[T]`, a non-copy slice + --> $DIR/slice-move-out-error-12567.rs:4:11 + | +LL | match (l1, l2) { + | ^^^^^^^^ cannot move out of here +... +LL | (&[], &[hd, ..]) | (&[hd, ..], &[]) + | -- data moved here +LL | => println!("one empty"), +LL | (&[hd1, ..], &[hd2, ..]) + | --- ...and here + | + = note: move occurs because these variables have types that don't implement the `Copy` trait +help: consider removing the borrow + | +LL - (&[], &[hd, ..]) | (&[hd, ..], &[]) +LL + (&[], [hd, ..]) | (&[hd, ..], &[]) + | +help: consider removing the borrow + | +LL - (&[hd1, ..], &[hd2, ..]) +LL + ([hd1, ..], &[hd2, ..]) + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0508`. diff --git a/tests/ui/match/slice-move-out-error.rs b/tests/ui/match/slice-move-out-error.rs deleted file mode 100644 index 1b2a37de475..00000000000 --- a/tests/ui/match/slice-move-out-error.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { - match (l1, l2) { - //~^ ERROR: cannot move out of type `[T]`, a non-copy slice - //~| ERROR: cannot move out of type `[T]`, a non-copy slice - (&[], &[]) => println!("both empty"), - (&[], &[hd, ..]) | (&[hd, ..], &[]) - => println!("one empty"), - (&[hd1, ..], &[hd2, ..]) - => println!("both nonempty"), - } -} - -fn main() {} diff --git a/tests/ui/match/string-literal-match-patterns.rs b/tests/ui/match/string-literal-match-patterns.rs deleted file mode 100644 index dd752227bbe..00000000000 --- a/tests/ui/match/string-literal-match-patterns.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ check-pass -#![allow(dead_code)] - -struct A { - a: String -} - -fn borrow<'a>(binding: &'a A) -> &'a str { - match &*binding.a { - "in" => "in_", - "ref" => "ref_", - ident => ident - } -} - -fn main() {} diff --git a/tests/ui/match/struct-reference-patterns-12285.rs b/tests/ui/match/struct-reference-patterns-12285.rs new file mode 100644 index 00000000000..246e230b0de --- /dev/null +++ b/tests/ui/match/struct-reference-patterns-12285.rs @@ -0,0 +1,16 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12285 + +//@ run-pass + +struct S; + +fn main() { + match Some(&S) { + Some(&S) => {}, + _x => unreachable!() + } + match Some(&S) { + Some(&S) => {}, + None => unreachable!() + } +} diff --git a/tests/ui/match/struct-reference-patterns.rs b/tests/ui/match/struct-reference-patterns.rs deleted file mode 100644 index fe199147128..00000000000 --- a/tests/ui/match/struct-reference-patterns.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass - -struct S; - -fn main() { - match Some(&S) { - Some(&S) => {}, - _x => unreachable!() - } - match Some(&S) { - Some(&S) => {}, - None => unreachable!() - } -} diff --git a/tests/ui/panics/explicit-panic-unreachable.rs b/tests/ui/panics/explicit-panic-unreachable.rs deleted file mode 100644 index f3b1b643c45..00000000000 --- a/tests/ui/panics/explicit-panic-unreachable.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-fail -//@ error-pattern:explicit panic -//@ needs-subprocess - -pub fn main() { - panic!(); - println!("{}", 1); -} diff --git a/tests/ui/panics/unwrap-or-panic-input.rs b/tests/ui/panics/unwrap-or-panic-input.rs deleted file mode 100644 index 99ffba3fba5..00000000000 --- a/tests/ui/panics/unwrap-or-panic-input.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-fail -//@ error-pattern:bad input -//@ needs-subprocess - -fn main() { - Some("foo").unwrap_or(panic!("bad input")).to_string(); -} diff --git a/tests/ui/parser/encode-symbol-ice-12920.rs b/tests/ui/parser/encode-symbol-ice-12920.rs new file mode 100644 index 00000000000..87389c0ffb4 --- /dev/null +++ b/tests/ui/parser/encode-symbol-ice-12920.rs @@ -0,0 +1,10 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12920 + +//@ run-fail +//@ error-pattern:explicit panic +//@ needs-subprocess + +pub fn main() { + panic!(); + println!("{}", 1); +} diff --git a/tests/ui/privacy/private-unit-struct-assignment.rs b/tests/ui/privacy/private-unit-struct-assignment.rs index 7794be37b85..b8e1c4ecb18 100644 --- a/tests/ui/privacy/private-unit-struct-assignment.rs +++ b/tests/ui/privacy/private-unit-struct-assignment.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13407 + mod A { struct C; } diff --git a/tests/ui/privacy/private-unit-struct-assignment.stderr b/tests/ui/privacy/private-unit-struct-assignment.stderr new file mode 100644 index 00000000000..8c36a08846d --- /dev/null +++ b/tests/ui/privacy/private-unit-struct-assignment.stderr @@ -0,0 +1,27 @@ +error[E0603]: unit struct `C` is private + --> $DIR/private-unit-struct-assignment.rs:8:8 + | +LL | A::C = 1; + | ^ private unit struct + | +note: the unit struct `C` is defined here + --> $DIR/private-unit-struct-assignment.rs:4:5 + | +LL | struct C; + | ^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/private-unit-struct-assignment.rs:8:5 + | +LL | struct C; + | -------- unit struct defined here +... +LL | A::C = 1; + | ^^^^ - this expression has type `{integer}` + | | + | expected integer, found `C` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0603. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/privacy/use-in-impl-scope-12729.rs b/tests/ui/privacy/use-in-impl-scope-12729.rs new file mode 100644 index 00000000000..58fe042beec --- /dev/null +++ b/tests/ui/privacy/use-in-impl-scope-12729.rs @@ -0,0 +1,16 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12729 + +//@ edition: 2015 +//@ check-pass +#![allow(dead_code)] + +pub struct Foo; + +mod bar { + use Foo; + + impl Foo { + fn baz(&self) {} + } +} +fn main() {} diff --git a/tests/ui/resolve/reference-clone-nonclone-11820.rs b/tests/ui/resolve/reference-clone-nonclone-11820.rs new file mode 100644 index 00000000000..74dad96da94 --- /dev/null +++ b/tests/ui/resolve/reference-clone-nonclone-11820.rs @@ -0,0 +1,15 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11820 + +//@ run-pass + +#![allow(noop_method_call)] + +struct NoClone; + +fn main() { + let rnc = &NoClone; + let rsnc = &Some(NoClone); + + let _: &NoClone = rnc.clone(); + let _: &Option = rsnc.clone(); +} diff --git a/tests/ui/statics/enum-with-static-str-variant-13214.rs b/tests/ui/statics/enum-with-static-str-variant-13214.rs new file mode 100644 index 00000000000..1db37da632d --- /dev/null +++ b/tests/ui/statics/enum-with-static-str-variant-13214.rs @@ -0,0 +1,24 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13214 + +//@ build-pass +#![allow(dead_code)] +// defining static with struct that contains enum +// with &'static str variant used to cause ICE + + +pub enum Foo { + Bar, + Baz(&'static str), +} + +pub static TEST: Test = Test { + foo: Foo::Bar, + c: 'a' +}; + +pub struct Test { + foo: Foo, + c: char, +} + +fn main() {} diff --git a/tests/ui/statics/enum-with-static-str-variant.rs b/tests/ui/statics/enum-with-static-str-variant.rs deleted file mode 100644 index 8140ec943a0..00000000000 --- a/tests/ui/statics/enum-with-static-str-variant.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ build-pass -#![allow(dead_code)] -// defining static with struct that contains enum -// with &'static str variant used to cause ICE - - -pub enum Foo { - Bar, - Baz(&'static str), -} - -pub static TEST: Test = Test { - foo: Foo::Bar, - c: 'a' -}; - -pub struct Test { - foo: Foo, - c: char, -} - -fn main() {} diff --git a/tests/ui/threads/moved-value-in-thread-loop.rs b/tests/ui/threads/moved-value-in-thread-loop.rs deleted file mode 100644 index 091e8fe8b2a..00000000000 --- a/tests/ui/threads/moved-value-in-thread-loop.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::sync::mpsc::channel; -use std::thread; - -fn main() { - let (tx, rx) = channel(); - let _t = thread::spawn(move|| -> () { - loop { - let tx = tx; - //~^ ERROR: use of moved value: `tx` - tx.send(1); - } - }); -} diff --git a/tests/ui/traits/any-trait-object-debug.rs b/tests/ui/traits/any-trait-object-debug.rs deleted file mode 100644 index eaf92d413d5..00000000000 --- a/tests/ui/traits/any-trait-object-debug.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-pass -fn main() { - fn test() -> Box { Box::new(1) } - println!("{:?}", test()) -} diff --git a/tests/ui/traits/default-method-lifetime-params-13204.rs b/tests/ui/traits/default-method-lifetime-params-13204.rs new file mode 100644 index 00000000000..cdf34ab773c --- /dev/null +++ b/tests/ui/traits/default-method-lifetime-params-13204.rs @@ -0,0 +1,27 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13204 + +//@ run-pass +#![allow(unused_mut)] +// Test that when instantiating trait default methods, typeck handles +// lifetime parameters defined on the method bound correctly. + + +pub trait Foo { + fn bar<'a, I: Iterator>(&self, it: I) -> usize { + let mut xs = it.filter(|_| true); + xs.count() + } +} + +pub struct Baz; + +impl Foo for Baz { + // When instantiating `Foo::bar` for `Baz` here, typeck used to + // ICE due to the lifetime parameter of `bar`. +} + +fn main() { + let x = Baz; + let y = vec![(), (), ()]; + assert_eq!(x.bar(y.iter()), 3); +} diff --git a/tests/ui/traits/default-method-lifetime-params.rs b/tests/ui/traits/default-method-lifetime-params.rs deleted file mode 100644 index 01362f6fe61..00000000000 --- a/tests/ui/traits/default-method-lifetime-params.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ run-pass -#![allow(unused_mut)] -// Test that when instantiating trait default methods, typeck handles -// lifetime parameters defined on the method bound correctly. - - -pub trait Foo { - fn bar<'a, I: Iterator>(&self, it: I) -> usize { - let mut xs = it.filter(|_| true); - xs.count() - } -} - -pub struct Baz; - -impl Foo for Baz { - // When instantiating `Foo::bar` for `Baz` here, typeck used to - // ICE due to the lifetime parameter of `bar`. -} - -fn main() { - let x = Baz; - let y = vec![(), (), ()]; - assert_eq!(x.bar(y.iter()), 3); -} diff --git a/tests/ui/traits/deref-chain-method-calls.rs b/tests/ui/traits/deref-chain-method-calls.rs deleted file mode 100644 index bf4ec388c4f..00000000000 --- a/tests/ui/traits/deref-chain-method-calls.rs +++ /dev/null @@ -1,74 +0,0 @@ -//@ run-pass -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -use std::ops::Deref; - -struct Root { - jsref: JSRef -} - -impl Deref for Root { - type Target = JSRef; - - fn deref<'a>(&'a self) -> &'a JSRef { - &self.jsref - } -} - -#[derive(Copy, Clone)] -struct JSRef { - node: *const Node -} - -impl Deref for JSRef { - type Target = Node; - - fn deref<'a>(&'a self) -> &'a Node { - self.get() - } -} - -trait INode { - fn RemoveChild(&self); -} - -impl INode for JSRef { - fn RemoveChild(&self) { - self.get().RemoveChild(0) - } -} - -impl JSRef { - fn AddChild(&self) { - self.get().AddChild(0); - } - - fn get<'a>(&'a self) -> &'a Node { - unsafe { - &*self.node - } - } -} - -struct Node; - -impl Node { - fn RemoveChild(&self, _a: usize) { - } - - fn AddChild(&self, _a: usize) { - } -} - -fn main() { - let n = Node; - let jsref = JSRef { node: &n }; - let root = Root { jsref: jsref }; - - root.AddChild(); - jsref.AddChild(); - - root.RemoveChild(); - jsref.RemoveChild(); -} diff --git a/tests/ui/traits/fnonce-repro-trait-impl-13434.rs b/tests/ui/traits/fnonce-repro-trait-impl-13434.rs new file mode 100644 index 00000000000..61d5a1d74ae --- /dev/null +++ b/tests/ui/traits/fnonce-repro-trait-impl-13434.rs @@ -0,0 +1,23 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13434 + +//@ run-pass +#[derive(Debug)] +struct MyStruct; + +trait Repro { + fn repro(self, s: MyStruct) -> String; +} + +impl Repro for F where F: FnOnce(MyStruct) -> String { + fn repro(self, s: MyStruct) -> String { + self(s) + } +} + +fn do_stuff(r: R) -> String { + r.repro(MyStruct) +} + +pub fn main() { + assert_eq!("MyStruct".to_string(), do_stuff(|s: MyStruct| format!("{:?}", s))); +} diff --git a/tests/ui/traits/fnonce-repro-trait-impl.rs b/tests/ui/traits/fnonce-repro-trait-impl.rs deleted file mode 100644 index caf7b632393..00000000000 --- a/tests/ui/traits/fnonce-repro-trait-impl.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ run-pass -#[derive(Debug)] -struct MyStruct; - -trait Repro { - fn repro(self, s: MyStruct) -> String; -} - -impl Repro for F where F: FnOnce(MyStruct) -> String { - fn repro(self, s: MyStruct) -> String { - self(s) - } -} - -fn do_stuff(r: R) -> String { - r.repro(MyStruct) -} - -pub fn main() { - assert_eq!("MyStruct".to_string(), do_stuff(|s: MyStruct| format!("{:?}", s))); -} diff --git a/tests/ui/traits/matcher-trait-equality.rs b/tests/ui/traits/matcher-trait-equality.rs deleted file mode 100644 index 8f334404f9a..00000000000 --- a/tests/ui/traits/matcher-trait-equality.rs +++ /dev/null @@ -1,58 +0,0 @@ -//@ run-pass - -struct StrWrap { - s: String -} - -impl StrWrap { - fn new(s: &str) -> StrWrap { - StrWrap { s: s.to_string() } - } - - fn get_s<'a>(&'a self) -> &'a str { - &self.s - } -} - -struct MyStruct { - s: StrWrap -} - -impl MyStruct { - fn new(s: &str) -> MyStruct { - MyStruct { s: StrWrap::new(s) } - } - - fn get_str_wrap<'a>(&'a self) -> &'a StrWrap { - &self.s - } -} - -trait Matcher { - fn matches(&self, actual: T) -> bool; -} - -fn assert_that>(actual: T, matcher: &U) { - assert!(matcher.matches(actual)); -} - -struct EqualTo { - expected: T -} - -impl Matcher for EqualTo { - fn matches(&self, actual: T) -> bool { - self.expected.eq(&actual) - } -} - -fn equal_to(expected: T) -> Box> { - Box::new(EqualTo { expected: expected }) -} - -pub fn main() { - let my_struct = MyStruct::new("zomg"); - let s = my_struct.get_str_wrap(); - - assert_that(s.get_s(), &*equal_to("zomg")); -} diff --git a/tests/ui/traits/reference-clone-noclone.rs b/tests/ui/traits/reference-clone-noclone.rs deleted file mode 100644 index ada844f8ee1..00000000000 --- a/tests/ui/traits/reference-clone-noclone.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -#![allow(noop_method_call)] - -struct NoClone; - -fn main() { - let rnc = &NoClone; - let rsnc = &Some(NoClone); - - let _: &NoClone = rnc.clone(); - let _: &Option = rsnc.clone(); -} diff --git a/tests/ui/type-inference/isize-usize-mismatch-error.rs b/tests/ui/type-inference/isize-usize-mismatch-error.rs deleted file mode 100644 index 5d31d7f861c..00000000000 --- a/tests/ui/type-inference/isize-usize-mismatch-error.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ dont-require-annotations: NOTE - -fn foo(_s: i16) { } - -fn bar(_s: u32) { } - -fn main() { - foo(1*(1 as isize)); - //~^ ERROR mismatched types - //~| NOTE expected `i16`, found `isize` - - bar(1*(1 as usize)); - //~^ ERROR mismatched types - //~| NOTE expected `u32`, found `usize` -} diff --git a/tests/ui/type-inference/partial-type-hint-12909.rs b/tests/ui/type-inference/partial-type-hint-12909.rs new file mode 100644 index 00000000000..d7017f451e3 --- /dev/null +++ b/tests/ui/type-inference/partial-type-hint-12909.rs @@ -0,0 +1,21 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12909 + +//@ run-pass +#![allow(unused_variables)] + +use std::collections::HashMap; + +fn copy(&x: &T) -> T { + x +} + +fn main() { + let arr = [(1, 1), (2, 2), (3, 3)]; + + let v1: Vec<&_> = arr.iter().collect(); + let v2: Vec<_> = arr.iter().map(copy).collect(); + + let m1: HashMap<_, _> = arr.iter().map(copy).collect(); + let m2: HashMap = arr.iter().map(copy).collect(); + let m3: HashMap<_, usize> = arr.iter().map(copy).collect(); +} diff --git a/tests/ui/type-inference/type-collect-inference.rs b/tests/ui/type-inference/type-collect-inference.rs deleted file mode 100644 index f2c33806aae..00000000000 --- a/tests/ui/type-inference/type-collect-inference.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass -#![allow(unused_variables)] - -use std::collections::HashMap; - -fn copy(&x: &T) -> T { - x -} - -fn main() { - let arr = [(1, 1), (2, 2), (3, 3)]; - - let v1: Vec<&_> = arr.iter().collect(); - let v2: Vec<_> = arr.iter().map(copy).collect(); - - let m1: HashMap<_, _> = arr.iter().map(copy).collect(); - let m2: HashMap = arr.iter().map(copy).collect(); - let m3: HashMap<_, usize> = arr.iter().map(copy).collect(); -} diff --git a/tests/ui/type-inference/unit-type-add-error.rs b/tests/ui/type-inference/unit-type-add-error.rs deleted file mode 100644 index c69cd1e79e3..00000000000 --- a/tests/ui/type-inference/unit-type-add-error.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn main() { - let x = (); - 1 + - x //~^ ERROR E0277 - ; - - let x: () = (); - 1 + - x //~^ ERROR E0277 - ; -} diff --git a/tests/ui/typeck/function-in-pattern-error-12863.rs b/tests/ui/typeck/function-in-pattern-error-12863.rs new file mode 100644 index 00000000000..d2fa2555658 --- /dev/null +++ b/tests/ui/typeck/function-in-pattern-error-12863.rs @@ -0,0 +1,10 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/12863 + +mod foo { pub fn bar() {} } + +fn main() { + match () { + foo::bar => {} + //~^ ERROR expected unit struct, unit variant or constant, found function `foo::bar` + } +} diff --git a/tests/ui/typeck/function-in-pattern-error-12863.stderr b/tests/ui/typeck/function-in-pattern-error-12863.stderr new file mode 100644 index 00000000000..f28874b5d48 --- /dev/null +++ b/tests/ui/typeck/function-in-pattern-error-12863.stderr @@ -0,0 +1,9 @@ +error[E0532]: expected unit struct, unit variant or constant, found function `foo::bar` + --> $DIR/function-in-pattern-error-12863.rs:7:9 + | +LL | foo::bar => {} + | ^^^^^^^^ not a unit struct, unit variant or constant + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0532`. diff --git a/tests/ui/typeck/isize-usize-mismatch-error.rs b/tests/ui/typeck/isize-usize-mismatch-error.rs new file mode 100644 index 00000000000..2fb5cf489c0 --- /dev/null +++ b/tests/ui/typeck/isize-usize-mismatch-error.rs @@ -0,0 +1,17 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13359 + +//@ dont-require-annotations: NOTE + +fn foo(_s: i16) { } + +fn bar(_s: u32) { } + +fn main() { + foo(1*(1 as isize)); + //~^ ERROR mismatched types + //~| NOTE expected `i16`, found `isize` + + bar(1*(1 as usize)); + //~^ ERROR mismatched types + //~| NOTE expected `u32`, found `usize` +} diff --git a/tests/ui/typeck/isize-usize-mismatch-error.stderr b/tests/ui/typeck/isize-usize-mismatch-error.stderr new file mode 100644 index 00000000000..d5724665a03 --- /dev/null +++ b/tests/ui/typeck/isize-usize-mismatch-error.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> $DIR/isize-usize-mismatch-error.rs:10:9 + | +LL | foo(1*(1 as isize)); + | --- ^^^^^^^^^^^^^^ expected `i16`, found `isize` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/isize-usize-mismatch-error.rs:5:4 + | +LL | fn foo(_s: i16) { } + | ^^^ ------- +help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit + | +LL | foo((1*(1 as isize)).try_into().unwrap()); + | + +++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/isize-usize-mismatch-error.rs:14:9 + | +LL | bar(1*(1 as usize)); + | --- ^^^^^^^^^^^^^^ expected `u32`, found `usize` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/isize-usize-mismatch-error.rs:7:4 + | +LL | fn bar(_s: u32) { } + | ^^^ ------- +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit + | +LL | bar((1*(1 as usize)).try_into().unwrap()); + | + +++++++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/unit-type-add-error-11771.rs b/tests/ui/typeck/unit-type-add-error-11771.rs new file mode 100644 index 00000000000..d009f50f4b9 --- /dev/null +++ b/tests/ui/typeck/unit-type-add-error-11771.rs @@ -0,0 +1,13 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/11771 + +fn main() { + let x = (); + 1 + + x //~^ ERROR E0277 + ; + + let x: () = (); + 1 + + x //~^ ERROR E0277 + ; +} diff --git a/tests/ui/typeck/unit-type-add-error-11771.stderr b/tests/ui/typeck/unit-type-add-error-11771.stderr new file mode 100644 index 00000000000..155cc093524 --- /dev/null +++ b/tests/ui/typeck/unit-type-add-error-11771.stderr @@ -0,0 +1,39 @@ +error[E0277]: cannot add `()` to `{integer}` + --> $DIR/unit-type-add-error-11771.rs:5:7 + | +LL | 1 + + | ^ no implementation for `{integer} + ()` + | + = help: the trait `Add<()>` is not implemented for `{integer}` + = help: the following other types implement trait `Add`: + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` + and 56 others + +error[E0277]: cannot add `()` to `{integer}` + --> $DIR/unit-type-add-error-11771.rs:10:7 + | +LL | 1 + + | ^ no implementation for `{integer} + ()` + | + = help: the trait `Add<()>` is not implemented for `{integer}` + = help: the following other types implement trait `Add`: + `&f128` implements `Add` + `&f128` implements `Add` + `&f16` implements `Add` + `&f16` implements `Add` + `&f32` implements `Add` + `&f32` implements `Add` + `&f64` implements `Add` + `&f64` implements `Add` + and 56 others + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/unwrap-or-panic-input-13202.rs b/tests/ui/typeck/unwrap-or-panic-input-13202.rs new file mode 100644 index 00000000000..29833a727c5 --- /dev/null +++ b/tests/ui/typeck/unwrap-or-panic-input-13202.rs @@ -0,0 +1,9 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/13202 + +//@ run-fail +//@ error-pattern:bad input +//@ needs-subprocess + +fn main() { + Some("foo").unwrap_or(panic!("bad input")).to_string(); +} diff --git a/tests/ui/unsafe/unsafe-transmute-in-find.rs b/tests/ui/unsafe/unsafe-transmute-in-find.rs deleted file mode 100644 index c6099c2a0c0..00000000000 --- a/tests/ui/unsafe/unsafe-transmute-in-find.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ check-pass - -struct Attr { - name: String, - value: String, -} - -struct Element { - attrs: Vec>, -} - -impl Element { - pub unsafe fn get_attr<'a>(&'a self, name: &str) { - self.attrs - .iter() - .find(|attr| { - let attr: &&Box = std::mem::transmute(attr); - true - }); - } -} - -fn main() { - let element = Element { attrs: Vec::new() }; - unsafe { let () = element.get_attr("foo"); }; -} -- cgit 1.4.1-3-g733a5 From d525e79157e32abc510714dd32628c9c155f2997 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 18:17:15 +0000 Subject: Stall coroutines based off of ty::Coroutine, not ty::CoroutineWitness --- .../src/solve/trait_goals.rs | 11 +- .../rustc_trait_selection/src/solve/fulfill.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 60 +++++----- .../rustc_trait_selection/src/traits/select/mod.rs | 2 +- compiler/rustc_type_ir/src/flags.rs | 11 +- tests/ui/async-await/issue-70818.rs | 1 + tests/ui/async-await/issue-70818.stderr | 23 +++- tests/ui/async-await/issue-86507.stderr | 2 +- tests/ui/coroutine/clone-impl-async.rs | 6 +- tests/ui/coroutine/clone-impl-async.stderr | 132 ++++++++++----------- tests/ui/coroutine/clone-impl-static.stderr | 12 +- tests/ui/coroutine/clone-impl.rs | 1 + tests/ui/coroutine/clone-impl.stderr | 88 +++++++------- tests/ui/coroutine/ref-upvar-not-send.stderr | 14 +-- tests/ui/impl-trait/issues/issue-55872-3.stderr | 15 +-- 15 files changed, 194 insertions(+), 186 deletions(-) (limited to 'tests') diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 650b85d99d2..31991565b0d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -229,7 +229,7 @@ where } // We need to make sure to stall any coroutines we are inferring to avoid query cycles. - if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) { return cand; } @@ -294,7 +294,7 @@ where } // We need to make sure to stall any coroutines we are inferring to avoid query cycles. - if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) { + if let Some(cand) = ecx.try_stall_coroutine(goal.predicate.self_ty()) { return cand; } @@ -1432,11 +1432,8 @@ where self.merge_trait_candidates(candidates) } - fn try_stall_coroutine_witness( - &mut self, - self_ty: I::Ty, - ) -> Option, NoSolution>> { - if let ty::CoroutineWitness(def_id, _) = self_ty.kind() { + fn try_stall_coroutine(&mut self, self_ty: I::Ty) -> Option, NoSolution>> { + if let ty::Coroutine(def_id, _) = self_ty.kind() { match self.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 01bdae7435d..3f628d80662 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -355,7 +355,7 @@ impl<'tcx> TypeVisitor> for StalledOnCoroutines<'tcx> { return ControlFlow::Continue(()); } - if let ty::CoroutineWitness(def_id, _) = *ty.kind() + if let ty::Coroutine(def_id, _) = *ty.kind() && def_id.as_local().is_some_and(|def_id| self.stalled_coroutines.contains(&def_id)) { ControlFlow::Break(()) diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 2c7089507a8..af6dafb3062 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -794,18 +794,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // The auto impl might apply; we don't know. candidates.ambiguous = true; } - ty::Coroutine(coroutine_def_id, _) - if self.tcx().is_lang_item(def_id, LangItem::Unpin) => - { - match self.tcx().coroutine_movability(coroutine_def_id) { - hir::Movability::Static => { - // Immovable coroutines are never `Unpin`, so - // suppress the normal auto-impl candidate for it. + ty::Coroutine(coroutine_def_id, _) => { + if self.tcx().is_lang_item(def_id, LangItem::Unpin) { + match self.tcx().coroutine_movability(coroutine_def_id) { + hir::Movability::Static => { + // Immovable coroutines are never `Unpin`, so + // suppress the normal auto-impl candidate for it. + } + hir::Movability::Movable => { + // Movable coroutines are always `Unpin`, so add an + // unconditional builtin candidate with no sub-obligations. + candidates.vec.push(BuiltinCandidate); + } } - hir::Movability::Movable => { - // Movable coroutines are always `Unpin`, so add an - // unconditional builtin candidate. - candidates.vec.push(BuiltinCandidate); + } else { + if self.should_stall_coroutine(coroutine_def_id) { + candidates.ambiguous = true; + } else { + // Coroutines implement all other auto traits normally. + candidates.vec.push(AutoImplCandidate); } } } @@ -842,12 +849,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::CoroutineWitness(def_id, _) => { - if self.should_stall_coroutine_witness(def_id) { - candidates.ambiguous = true; - } else { - candidates.vec.push(AutoImplCandidate); - } + ty::CoroutineWitness(..) => { + candidates.vec.push(AutoImplCandidate); } ty::Bool @@ -866,7 +869,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::FnPtr(..) | ty::Closure(..) | ty::CoroutineClosure(..) - | ty::Coroutine(..) | ty::Never | ty::Tuple(_) | ty::UnsafeBinder(_) => { @@ -1153,6 +1155,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Ref(_, _, hir::Mutability::Mut) => {} ty::Coroutine(coroutine_def_id, args) => { + if self.should_stall_coroutine(coroutine_def_id) { + candidates.ambiguous = true; + return; + } + match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => {} hir::Movability::Movable => { @@ -1194,12 +1201,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::CoroutineWitness(coroutine_def_id, _) => { - if self.should_stall_coroutine_witness(coroutine_def_id) { - candidates.ambiguous = true; - } else { - candidates.vec.push(SizedCandidate); - } + ty::CoroutineWitness(..) => { + candidates.vec.push(SizedCandidate); } // Fallback to whatever user-defined impls or param-env clauses exist in this case. @@ -1238,7 +1241,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(..) | ty::Char | ty::Ref(..) - | ty::Coroutine(..) | ty::Array(..) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1247,14 +1249,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(SizedCandidate); } - ty::CoroutineWitness(coroutine_def_id, _) => { - if self.should_stall_coroutine_witness(coroutine_def_id) { + ty::Coroutine(coroutine_def_id, _) => { + if self.should_stall_coroutine(coroutine_def_id) { candidates.ambiguous = true; } else { candidates.vec.push(SizedCandidate); } } + ty::CoroutineWitness(..) => { + candidates.vec.push(SizedCandidate); + } + // Conditionally `Sized`. ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => { candidates.vec.push(SizedCandidate); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d7c3543cb3f..e893add81c8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2841,7 +2841,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligations } - fn should_stall_coroutine_witness(&self, def_id: DefId) -> bool { + fn should_stall_coroutine(&self, def_id: DefId) -> bool { match self.infcx.typing_mode() { TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => { def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index d7b9e0ca340..23b7f55fbbe 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -131,10 +131,7 @@ bitflags::bitflags! { /// Does this have any binders with bound vars (e.g. that need to be anonymized)? const HAS_BINDER_VARS = 1 << 23; - /// Does this type have any coroutine witnesses in it? - // FIXME: This should probably be changed to track whether the type has any - // *coroutines* in it, though this will happen if we remove coroutine witnesses - // altogether. + /// Does this type have any coroutines in it? const HAS_TY_CORO = 1 << 24; } } @@ -246,11 +243,13 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_TY_PARAM); } - ty::Closure(_, args) | ty::Coroutine(_, args) | ty::CoroutineClosure(_, args) => { + ty::Closure(_, args) + | ty::CoroutineClosure(_, args) + | ty::CoroutineWitness(_, args) => { self.add_args(args.as_slice()); } - ty::CoroutineWitness(_, args) => { + ty::Coroutine(_, args) => { self.add_flags(TypeFlags::HAS_TY_CORO); self.add_args(args.as_slice()); } diff --git a/tests/ui/async-await/issue-70818.rs b/tests/ui/async-await/issue-70818.rs index bc181de8d92..c11332fe7d8 100644 --- a/tests/ui/async-await/issue-70818.rs +++ b/tests/ui/async-await/issue-70818.rs @@ -4,6 +4,7 @@ use std::future::Future; fn foo(ty: T, ty1: U) -> impl Future + Send { //~^ ERROR future cannot be sent between threads safely async { (ty, ty1) } + //~^ ERROR future cannot be sent between threads safely } fn main() {} diff --git a/tests/ui/async-await/issue-70818.stderr b/tests/ui/async-await/issue-70818.stderr index 8de6a825042..07fd20cdd77 100644 --- a/tests/ui/async-await/issue-70818.stderr +++ b/tests/ui/async-await/issue-70818.stderr @@ -1,3 +1,24 @@ +error: future cannot be sent between threads safely + --> $DIR/issue-70818.rs:6:5 + | +LL | async { (ty, ty1) } + | ^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` + | +note: captured value is not `Send` + --> $DIR/issue-70818.rs:6:18 + | +LL | async { (ty, ty1) } + | ^^^ has type `U` which is not `Send` +note: required by a bound in an opaque type + --> $DIR/issue-70818.rs:4:69 + | +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | ^^^^ +help: consider restricting type parameter `U` with trait `Send` + | +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | +++++++++++++++++++ + error: future cannot be sent between threads safely --> $DIR/issue-70818.rs:4:38 | @@ -14,5 +35,5 @@ help: consider restricting type parameter `U` with trait `Send` LL | fn foo(ty: T, ty1: U) -> impl Future + Send { | +++++++++++++++++++ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/issue-86507.stderr b/tests/ui/async-await/issue-86507.stderr index 6385a8c975e..c71801dcfc8 100644 --- a/tests/ui/async-await/issue-86507.stderr +++ b/tests/ui/async-await/issue-86507.stderr @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast from `Pin>` to `Pin + Send + 'async_trait)>>` + = note: required for the cast from `Pin>` to `Pin + Send>>` help: consider further restricting type parameter `T` with trait `Sync` | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/tests/ui/coroutine/clone-impl-async.rs b/tests/ui/coroutine/clone-impl-async.rs index 2794b167aa2..4e2b26d0295 100644 --- a/tests/ui/coroutine/clone-impl-async.rs +++ b/tests/ui/coroutine/clone-impl-async.rs @@ -9,7 +9,7 @@ use std::future::ready; struct NonClone; -fn main() { +fn local() { let inner_non_clone = async { let non_clone = NonClone; let () = ready(()).await; @@ -34,7 +34,9 @@ fn main() { //~^ ERROR : Copy` is not satisfied check_clone(&maybe_copy_clone); //~^ ERROR : Clone` is not satisfied +} +fn non_local() { let inner_non_clone_fn = the_inner_non_clone_fn(); check_copy(&inner_non_clone_fn); //~^ ERROR : Copy` is not satisfied @@ -69,3 +71,5 @@ async fn the_maybe_copy_clone_fn() {} fn check_copy(_x: &T) {} fn check_clone(_x: &T) {} + +fn main() {} diff --git a/tests/ui/coroutine/clone-impl-async.stderr b/tests/ui/coroutine/clone-impl-async.stderr index 62bcce2fbcb..319a5ed3d8d 100644 --- a/tests/ui/coroutine/clone-impl-async.stderr +++ b/tests/ui/coroutine/clone-impl-async.stderr @@ -1,167 +1,155 @@ -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:18:16 +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:41:16 | -LL | check_copy(&inner_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` +LL | check_copy(&inner_non_clone_fn); + | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | | | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:20:17 +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:43:17 | -LL | check_clone(&inner_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` +LL | check_clone(&inner_non_clone_fn); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` | | | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:27:16 +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:47:16 | -LL | check_copy(&outer_non_clone); - | ---------- ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` +LL | check_copy(&outer_non_clone_fn); + | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | | | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:29:17 +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:49:17 | -LL | check_clone(&outer_non_clone); - | ----------- ^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` +LL | check_clone(&outer_non_clone_fn); + | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` | | | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:33:16 +error[E0277]: the trait bound `impl Future: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:53:16 | -LL | check_copy(&maybe_copy_clone); - | ---------- ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` +LL | check_copy(&maybe_copy_clone_fn); + | ---------- ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | | | required by a bound introduced by this call | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:35:17 +error[E0277]: the trait bound `impl Future: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:55:17 | -LL | check_clone(&maybe_copy_clone); - | ----------- ^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` +LL | check_clone(&maybe_copy_clone_fn); + | ----------- ^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` | | | required by a bound introduced by this call | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:39:16 +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:18:5 | -LL | check_copy(&inner_non_clone_fn); - | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` - | | - | required by a bound introduced by this call +LL | check_copy(&inner_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `impl Future: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:41:17 +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:20:5 | -LL | check_clone(&inner_non_clone_fn); - | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` - | | - | required by a bound introduced by this call +LL | check_clone(&inner_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:13:27: 13:32}` | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:45:16 +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:27:5 | -LL | check_copy(&outer_non_clone_fn); - | ---------- ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` - | | - | required by a bound introduced by this call +LL | check_copy(&outer_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `impl Future: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:47:17 +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:29:5 | -LL | check_clone(&outer_non_clone_fn); - | ----------- ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` - | | - | required by a bound introduced by this call +LL | check_clone(&outer_non_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:24:27: 24:37}` | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` -error[E0277]: the trait bound `impl Future: Copy` is not satisfied - --> $DIR/clone-impl-async.rs:51:16 +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Copy` is not satisfied + --> $DIR/clone-impl-async.rs:33:5 | -LL | check_copy(&maybe_copy_clone_fn); - | ---------- ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` - | | - | required by a bound introduced by this call +LL | check_copy(&maybe_copy_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` | note: required by a bound in `check_copy` - --> $DIR/clone-impl-async.rs:70:18 + --> $DIR/clone-impl-async.rs:72:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `impl Future: Clone` is not satisfied - --> $DIR/clone-impl-async.rs:53:17 +error[E0277]: the trait bound `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}: Clone` is not satisfied + --> $DIR/clone-impl-async.rs:35:5 | -LL | check_clone(&maybe_copy_clone_fn); - | ----------- ^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl Future` - | | - | required by a bound introduced by this call +LL | check_clone(&maybe_copy_clone); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{async block@$DIR/clone-impl-async.rs:32:28: 32:38}` | note: required by a bound in `check_clone` - --> $DIR/clone-impl-async.rs:71:19 + --> $DIR/clone-impl-async.rs:73:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` diff --git a/tests/ui/coroutine/clone-impl-static.stderr b/tests/ui/coroutine/clone-impl-static.stderr index 9fb71fd5fd0..4df6b9759c3 100644 --- a/tests/ui/coroutine/clone-impl-static.stderr +++ b/tests/ui/coroutine/clone-impl-static.stderr @@ -1,10 +1,8 @@ error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}: Copy` is not satisfied - --> $DIR/clone-impl-static.rs:14:16 + --> $DIR/clone-impl-static.rs:14:5 | LL | check_copy(&generator); - | ---------- ^^^^^^^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` | note: required by a bound in `check_copy` --> $DIR/clone-impl-static.rs:20:18 @@ -13,12 +11,10 @@ LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` error[E0277]: the trait bound `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}: Clone` is not satisfied - --> $DIR/clone-impl-static.rs:16:17 + --> $DIR/clone-impl-static.rs:16:5 | LL | check_clone(&generator); - | ----------- ^^^^^^^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` - | | - | required by a bound introduced by this call + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `{static coroutine@$DIR/clone-impl-static.rs:11:5: 11:19}` | note: required by a bound in `check_clone` --> $DIR/clone-impl-static.rs:21:19 diff --git a/tests/ui/coroutine/clone-impl.rs b/tests/ui/coroutine/clone-impl.rs index e528f031d52..9e04e256fc1 100644 --- a/tests/ui/coroutine/clone-impl.rs +++ b/tests/ui/coroutine/clone-impl.rs @@ -42,6 +42,7 @@ fn test3_upvars() { let clonable_0: Vec = Vec::new(); let gen_clone_0 = #[coroutine] move || { + yield; drop(clonable_0); }; check_copy(&gen_clone_0); diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index 714e5aa3d9e..f316902a42d 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -1,59 +1,81 @@ error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` - --> $DIR/clone-impl.rs:47:16 + --> $DIR/clone-impl.rs:48:5 | LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:45:14 + --> $DIR/clone-impl.rs:46:14 | LL | drop(clonable_0); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 + --> $DIR/clone-impl.rs:92:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` - --> $DIR/clone-impl.rs:73:16 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:55:5: 55:12}` + --> $DIR/clone-impl.rs:60:5 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:55:5: 55:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:55:5: 55:12}`, the trait `Copy` is not implemented for `Vec` + | +note: coroutine does not implement `Copy` as this value is used across a yield + --> $DIR/clone-impl.rs:57:9 + | +LL | let v = vec!['a']; + | - has type `Vec` which does not implement `Copy` +LL | yield; + | ^^^^^ yield occurs here, with `v` maybe used later +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:92:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:68:5: 68:12}` + --> $DIR/clone-impl.rs:74:5 + | +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:68:5: 68:12}` +... +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:68:5: 68:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:71:14 + --> $DIR/clone-impl.rs:72:14 | LL | drop(clonable_1); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 + --> $DIR/clone-impl.rs:92:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` - --> $DIR/clone-impl.rs:85:16 +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` + --> $DIR/clone-impl.rs:86:5 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Copy` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}`, the trait `Copy` is not implemented for `NonClone` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:83:14 + --> $DIR/clone-impl.rs:84:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 + --> $DIR/clone-impl.rs:92:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` @@ -63,22 +85,22 @@ LL + #[derive(Copy)] LL | struct NonClone; | -error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` - --> $DIR/clone-impl.rs:87:17 +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` + --> $DIR/clone-impl.rs:88:5 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Clone` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:82:5: 82:12}`, the trait `Clone` is not implemented for `NonClone` | note: captured value does not implement `Clone` - --> $DIR/clone-impl.rs:83:14 + --> $DIR/clone-impl.rs:84:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` note: required by a bound in `check_clone` - --> $DIR/clone-impl.rs:92:19 + --> $DIR/clone-impl.rs:93:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` @@ -88,28 +110,6 @@ LL + #[derive(Clone)] LL | struct NonClone; | -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` - --> $DIR/clone-impl.rs:59:5 - | -LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` -... -LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}`, the trait `Copy` is not implemented for `Vec` - | -note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:56:9 - | -LL | let v = vec!['a']; - | - has type `Vec` which does not implement `Copy` -LL | yield; - | ^^^^^ yield occurs here, with `v` maybe used later -note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:91:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coroutine/ref-upvar-not-send.stderr b/tests/ui/coroutine/ref-upvar-not-send.stderr index 892b5d261c2..3a5e8ec4dab 100644 --- a/tests/ui/coroutine/ref-upvar-not-send.stderr +++ b/tests/ui/coroutine/ref-upvar-not-send.stderr @@ -1,14 +1,13 @@ error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:15:30 + --> $DIR/ref-upvar-not-send.rs:15:5 | -LL | assert_send(#[coroutine] move || { - | ______________________________^ +LL | / assert_send(#[coroutine] move || { LL | | LL | | LL | | yield; LL | | let _x = x; LL | | }); - | |_____^ coroutine is not `Send` + | |______^ coroutine is not `Send` | = help: the trait `Sync` is not implemented for `*mut ()` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` @@ -23,16 +22,15 @@ LL | fn assert_send(_: T) {} | ^^^^ required by this bound in `assert_send` error: coroutine cannot be sent between threads safely - --> $DIR/ref-upvar-not-send.rs:23:30 + --> $DIR/ref-upvar-not-send.rs:23:5 | -LL | assert_send(#[coroutine] move || { - | ______________________________^ +LL | / assert_send(#[coroutine] move || { LL | | LL | | LL | | yield; LL | | let _y = y; LL | | }); - | |_____^ coroutine is not `Send` + | |______^ coroutine is not `Send` | = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()` note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send` diff --git a/tests/ui/impl-trait/issues/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr index ce2dd7f02b4..b7711e47468 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-3.stderr @@ -1,12 +1,3 @@ -error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied - --> $DIR/issue-55872-3.rs:14:20 - | -LL | fn foo() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` -... -LL | async {} - | -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` here - error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias --> $DIR/issue-55872-3.rs:14:20 | @@ -21,6 +12,12 @@ LL | fn foo() -> Self::E { | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied + --> $DIR/issue-55872-3.rs:14:20 + | +LL | fn foo() -> Self::E { + | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From e9765781b2857da90161157a3fc523f9e1d58848 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 25 Jul 2025 16:46:11 +0000 Subject: Remove the witness type from coroutine args --- .../rustc_borrowck/src/type_check/input_output.rs | 1 - .../rustc_hir_analysis/src/collect/generics_of.rs | 12 +++------ compiler/rustc_hir_typeck/src/closure.rs | 5 ---- compiler/rustc_middle/src/ty/generic_args.rs | 29 ++++++++-------------- compiler/rustc_middle/src/ty/print/pretty.rs | 8 ++---- .../src/solve/assembly/structural_traits.rs | 20 ++++++++++++--- .../src/traits/select/candidate_assembly.rs | 4 +-- .../rustc_trait_selection/src/traits/select/mod.rs | 14 ++++++++--- compiler/rustc_type_ir/src/ty_kind/closure.rs | 27 -------------------- ...sync_await.b-{closure#0}.coroutine_resume.0.mir | 8 ------ .../ui/async-await/async-closures/def-path.stderr | 4 +-- ...igher-ranked-auto-trait-6.no_assumptions.stderr | 26 +------------------ .../print/coroutine-print-verbose-2.stderr | 4 +-- .../print/coroutine-print-verbose-3.stderr | 2 +- tests/ui/impl-trait/issues/issue-55872-2.rs | 1 - tests/ui/impl-trait/issues/issue-55872-2.stderr | 10 +------- tests/ui/impl-trait/issues/issue-55872-3.rs | 1 - tests/ui/impl-trait/issues/issue-55872-3.stderr | 14 +++-------- 18 files changed, 54 insertions(+), 136 deletions(-) (limited to 'tests') diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 99392ea1915..eb31b5de05d 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -86,7 +86,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // them with fresh ty vars. resume_ty: next_ty_var(), yield_ty: next_ty_var(), - witness: next_ty_var(), }, ) .args, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 31e9c3b80fb..e2462c2d465 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -379,20 +379,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // for info on the usage of each of these fields. let dummy_args = match kind { ClosureKind::Closure => &["", "", ""][..], - ClosureKind::Coroutine(_) => &[ - "", - "", - "", - "", - "", - "", - ][..], + ClosureKind::Coroutine(_) => { + &["", "", "", "", ""][..] + } ClosureKind::CoroutineClosure(_) => &[ "", "", "", "", - "", ][..], }; diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index a413f805873..82b7c578a1f 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -161,8 +161,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args); - // Coroutines that come from coroutine closures have not yet determined // their kind ty, so make a fresh infer var which will be constrained // later during upvar analysis. Regular coroutines always have the kind @@ -182,7 +180,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { resume_ty, yield_ty, return_ty: liberated_sig.output(), - witness: interior, tupled_upvars_ty, }, ); @@ -210,7 +207,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Compute all of the variables that will be used to populate the coroutine. let resume_ty = self.next_ty_var(expr_span); - let interior = self.next_ty_var(expr_span); let closure_kind_ty = match expected_kind { Some(kind) => Ty::from_closure_kind(tcx, kind), @@ -243,7 +239,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), tupled_upvars_ty, coroutine_captures_by_ref_ty, - coroutine_witness_ty: interior, }, ); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7d34d8df3f3..b02abb5ab43 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -96,14 +96,12 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArg signature_parts_ty, tupled_upvars_ty, coroutine_captures_by_ref_ty, - coroutine_witness_ty, ] => ty::CoroutineClosureArgsParts { parent_args, closure_kind_ty: closure_kind_ty.expect_ty(), signature_parts_ty: signature_parts_ty.expect_ty(), tupled_upvars_ty: tupled_upvars_ty.expect_ty(), coroutine_captures_by_ref_ty: coroutine_captures_by_ref_ty.expect_ty(), - coroutine_witness_ty: coroutine_witness_ty.expect_ty(), }, _ => bug!("closure args missing synthetics"), } @@ -111,23 +109,16 @@ impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArg fn split_coroutine_args(self) -> ty::CoroutineArgsParts> { match self[..] { - [ - ref parent_args @ .., - kind_ty, - resume_ty, - yield_ty, - return_ty, - witness, - tupled_upvars_ty, - ] => ty::CoroutineArgsParts { - parent_args, - kind_ty: kind_ty.expect_ty(), - resume_ty: resume_ty.expect_ty(), - yield_ty: yield_ty.expect_ty(), - return_ty: return_ty.expect_ty(), - witness: witness.expect_ty(), - tupled_upvars_ty: tupled_upvars_ty.expect_ty(), - }, + [ref parent_args @ .., kind_ty, resume_ty, yield_ty, return_ty, tupled_upvars_ty] => { + ty::CoroutineArgsParts { + parent_args, + kind_ty: kind_ty.expect_ty(), + resume_ty: resume_ty.expect_ty(), + yield_ty: yield_ty.expect_ty(), + return_ty: return_ty.expect_ty(), + tupled_upvars_ty: tupled_upvars_ty.expect_ty(), + } + } _ => bug!("coroutine args missing synthetics"), } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5c44b10ba71..71eac294f15 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -913,9 +913,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { " yield_ty=", print(args.as_coroutine().yield_ty()), " return_ty=", - print(args.as_coroutine().return_ty()), - " witness=", - print(args.as_coroutine().witness()) + print(args.as_coroutine().return_ty()) ); } @@ -1035,9 +1033,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { " upvar_tys=", print(args.as_coroutine_closure().tupled_upvars_ty()), " coroutine_captures_by_ref_ty=", - print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), - " coroutine_witness_ty=", - print(args.as_coroutine_closure().coroutine_witness_ty()) + print(args.as_coroutine_closure().coroutine_captures_by_ref_ty()) ); } p!("}}"); diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index c0bebdf6fb6..faa86734d08 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -75,9 +75,16 @@ where Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()])) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { let coroutine_args = args.as_coroutine(); - Ok(ty::Binder::dummy(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])) + Ok(ty::Binder::dummy(vec![ + coroutine_args.tupled_upvars_ty(), + Ty::new_coroutine_witness( + ecx.cx(), + def_id, + ecx.cx().mk_args(coroutine_args.parent_args().as_slice()), + ), + ])) } ty::CoroutineWitness(def_id, args) => Ok(ecx @@ -245,7 +252,14 @@ where Movability::Movable => { if ecx.cx().features().coroutine_clone() { let coroutine = args.as_coroutine(); - Ok(ty::Binder::dummy(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])) + Ok(ty::Binder::dummy(vec![ + coroutine.tupled_upvars_ty(), + Ty::new_coroutine_witness( + ecx.cx(), + def_id, + ecx.cx().mk_args(coroutine.parent_args().as_slice()), + ), + ])) } else { Err(NoSolution) } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index af6dafb3062..62795c8a3a6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -1166,9 +1166,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if self.tcx().features().coroutine_clone() { let resolved_upvars = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); - let resolved_witness = - self.infcx.shallow_resolve(args.as_coroutine().witness()); - if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { + if resolved_upvars.is_ty_var() { // Not yet resolved. candidates.ambiguous = true; } else { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e893add81c8..7ea1548f8f2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2196,7 +2196,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { args.as_coroutine() .upvar_tys() .iter() - .chain([args.as_coroutine().witness()]) + .chain([Ty::new_coroutine_witness( + self.tcx(), + coroutine_def_id, + self.tcx().mk_args(args.as_coroutine().parent_args()), + )]) .collect::>(), ) } else { @@ -2327,9 +2331,13 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } - ty::Coroutine(_, args) => { + ty::Coroutine(def_id, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); - let witness = args.as_coroutine().witness(); + let witness = Ty::new_coroutine_witness( + self.tcx(), + def_id, + self.tcx().mk_args(args.as_coroutine().parent_args()), + ); ty::Binder::dummy(AutoImplConstituents { types: [ty].into_iter().chain(iter::once(witness)).collect(), assumptions: vec![], diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index d1ca9bdb7fb..c32f8339d0b 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -101,7 +101,6 @@ use crate::{self as ty, Interner}; /// `yield` inside the coroutine. /// * `GR`: The "return type", which is the type of value returned upon /// completion of the coroutine. -/// * `GW`: The "coroutine witness". #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct ClosureArgs { @@ -239,8 +238,6 @@ pub struct CoroutineClosureArgsParts { /// while the `tupled_upvars_ty`, representing the by-move version of the same /// captures, will be `(String,)`. pub coroutine_captures_by_ref_ty: I::Ty, - /// Witness type returned by the generator produced by this coroutine-closure. - pub coroutine_witness_ty: I::Ty, } impl CoroutineClosureArgs { @@ -251,7 +248,6 @@ impl CoroutineClosureArgs { parts.signature_parts_ty.into(), parts.tupled_upvars_ty.into(), parts.coroutine_captures_by_ref_ty.into(), - parts.coroutine_witness_ty.into(), ])), } } @@ -292,7 +288,6 @@ impl CoroutineClosureArgs { } pub fn coroutine_closure_sig(self) -> ty::Binder> { - let interior = self.coroutine_witness_ty(); let ty::FnPtr(sig_tys, hdr) = self.signature_parts_ty().kind() else { panic!() }; sig_tys.map_bound(|sig_tys| { let [resume_ty, tupled_inputs_ty] = *sig_tys.inputs().as_slice() else { @@ -302,7 +297,6 @@ impl CoroutineClosureArgs { panic!() }; CoroutineClosureSignature { - interior, tupled_inputs_ty, resume_ty, yield_ty, @@ -318,10 +312,6 @@ impl CoroutineClosureArgs { self.split().coroutine_captures_by_ref_ty } - pub fn coroutine_witness_ty(self) -> I::Ty { - self.split().coroutine_witness_ty - } - pub fn has_self_borrows(&self) -> bool { match self.coroutine_captures_by_ref_ty().kind() { ty::FnPtr(sig_tys, _) => sig_tys @@ -361,7 +351,6 @@ impl TypeVisitor for HasRegionsBoundAt { #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct CoroutineClosureSignature { - pub interior: I::Ty, pub tupled_inputs_ty: I::Ty, pub resume_ty: I::Ty, pub yield_ty: I::Ty, @@ -407,7 +396,6 @@ impl CoroutineClosureSignature { resume_ty: self.resume_ty, yield_ty: self.yield_ty, return_ty: self.return_ty, - witness: self.interior, tupled_upvars_ty, }, ); @@ -587,11 +575,6 @@ pub struct CoroutineArgsParts { pub yield_ty: I::Ty, pub return_ty: I::Ty, - /// The interior type of the coroutine. - /// Represents all types that are stored in locals - /// in the coroutine's body. - pub witness: I::Ty, - /// The upvars captured by the closure. Remains an inference variable /// until the upvar analysis, which happens late in HIR typeck. pub tupled_upvars_ty: I::Ty, @@ -607,7 +590,6 @@ impl CoroutineArgs { parts.resume_ty.into(), parts.yield_ty.into(), parts.return_ty.into(), - parts.witness.into(), parts.tupled_upvars_ty.into(), ])), } @@ -629,15 +611,6 @@ impl CoroutineArgs { self.split().kind_ty } - /// This describes the types that can be contained in a coroutine. - /// It will be a type variable initially and unified in the last stages of typeck of a body. - /// It contains a tuple of all the types that could end up on a coroutine frame. - /// The state transformation MIR pass may only produce layouts which mention types - /// in this tuple. Upvars are not counted here. - pub fn witness(self) -> I::Ty { - self.split().witness - } - /// Returns an iterator over the list of types of captured paths by the coroutine. /// In case there was a type error in figuring out the types of the captured path, an /// empty iterator is returned. diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 109a41d1ef9..9bff257e063 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -9,10 +9,6 @@ std::future::ResumeTy, (), (), - CoroutineWitness( - DefId(0:5 ~ async_await[ccf8]::a::{closure#0}), - [], - ), (), ], ), @@ -30,10 +26,6 @@ std::future::ResumeTy, (), (), - CoroutineWitness( - DefId(0:5 ~ async_await[ccf8]::a::{closure#0}), - [], - ), (), ], ), diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index 58a5b0b79c4..a507fa69760 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?14t resume_ty=ResumeTy yield_ty=() return_ty=()}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr index d1f2d9a0753..d1c88101618 100644 --- a/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr +++ b/tests/ui/async-await/higher-ranked-auto-trait-6.no_assumptions.stderr @@ -21,30 +21,6 @@ LL | Box::new(async { new(|| async { f().await }).await }) = help: consider pinning your async block and casting it to a trait object = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-6.rs:16:5 - | -LL | Box::new(async { new(|| async { f().await }).await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - = note: no two async blocks, even if identical, have the same type - = help: consider pinning your async block and casting it to a trait object - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0308]: mismatched types - --> $DIR/higher-ranked-auto-trait-6.rs:16:5 - | -LL | Box::new(async { new(|| async { f().await }).await }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other - | - = note: expected `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - found `async` block `{async block@$DIR/higher-ranked-auto-trait-6.rs:16:29: 16:34}` - = note: no two async blocks, even if identical, have the same type - = help: consider pinning your async block and casting it to a trait object - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr index 8877d45ddda..11b78e3bcf8 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr @@ -9,7 +9,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync` + = help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Sync` is not implemented for `NotSync` note: coroutine is not `Sync` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:20:9 | @@ -34,7 +34,7 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend` + = help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Send` is not implemented for `NotSend` note: coroutine is not `Send` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:27:9 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr index 4a1e5b078a8..135e8175793 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr @@ -11,7 +11,7 @@ LL | | }; | |_____^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness={main::{closure#0}}}` + found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str}` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-55872-2.rs b/tests/ui/impl-trait/issues/issue-55872-2.rs index a3b2225126a..aea00dd9e3d 100644 --- a/tests/ui/impl-trait/issues/issue-55872-2.rs +++ b/tests/ui/impl-trait/issues/issue-55872-2.rs @@ -12,7 +12,6 @@ impl Bar for S { type E = impl std::marker::Send; fn foo() -> Self::E { //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - //~| ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias async {} } } diff --git a/tests/ui/impl-trait/issues/issue-55872-2.stderr b/tests/ui/impl-trait/issues/issue-55872-2.stderr index 51a7dd00ade..91c2ecdc8a4 100644 --- a/tests/ui/impl-trait/issues/issue-55872-2.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-2.stderr @@ -4,13 +4,5 @@ error: type parameter `T` is part of concrete type but not used in parameter lis LL | fn foo() -> Self::E { | ^^^^^^^ -error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-2.rs:13:20 - | -LL | fn foo() -> Self::E { - | ^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-55872-3.rs b/tests/ui/impl-trait/issues/issue-55872-3.rs index 763b4b9fd32..698e7f36234 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.rs +++ b/tests/ui/impl-trait/issues/issue-55872-3.rs @@ -14,7 +14,6 @@ impl Bar for S { fn foo() -> Self::E { //~^ ERROR : Copy` is not satisfied [E0277] //~| ERROR type parameter `T` is part of concrete type - //~| ERROR type parameter `T` is part of concrete type async {} } } diff --git a/tests/ui/impl-trait/issues/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr index b7711e47468..5124c46baeb 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-3.stderr @@ -4,20 +4,12 @@ error: type parameter `T` is part of concrete type but not used in parameter lis LL | fn foo() -> Self::E { | ^^^^^^^ -error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-3.rs:14:20 - | -LL | fn foo() -> Self::E { - | ^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}: Copy` is not satisfied --> $DIR/issue-55872-3.rs:14:20 | LL | fn foo() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` + | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From 8a3a7e625a8b607c018cdcf776fa79e29eaa56c8 Mon Sep 17 00:00:00 2001 From: Urgau Date: Tue, 22 Jul 2025 20:54:22 +0200 Subject: Add lint against dangling pointers form local variables --- compiler/rustc_lint/messages.ftl | 6 + compiler/rustc_lint/src/dangling.rs | 150 ++++++++++++- compiler/rustc_lint/src/lints.rs | 16 ++ tests/ui/lint/dangling-pointers-from-locals.rs | 188 ++++++++++++++++ tests/ui/lint/dangling-pointers-from-locals.stderr | 247 +++++++++++++++++++++ 5 files changed, 599 insertions(+), 8 deletions(-) create mode 100644 tests/ui/lint/dangling-pointers-from-locals.rs create mode 100644 tests/ui/lint/dangling-pointers-from-locals.stderr (limited to 'tests') diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 69fe7fe83ff..4d0c0c94a81 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i lint_custom_inner_attribute_unstable = custom inner attributes are unstable +lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped + .ret_ty = return type of the {$fn_kind} is `{$ret_ty}` + .local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind} + .created_at = dangling pointer created here + .note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned + lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index 9e19949c3b6..af4457f4314 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -1,13 +1,14 @@ use rustc_ast::visit::{visit_opt, walk_list}; use rustc_hir::attrs::AttributeKind; +use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; -use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, find_attr}; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, LangItem, TyKind, find_attr}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::{Span, sym}; -use crate::lints::DanglingPointersFromTemporaries; +use crate::lints::{DanglingPointersFromLocals, DanglingPointersFromTemporaries}; use crate::{LateContext, LateLintPass}; declare_lint! { @@ -42,6 +43,36 @@ declare_lint! { "detects getting a pointer from a temporary" } +declare_lint! { + /// The `dangling_pointers_from_locals` lint detects getting a pointer to data + /// of a local that will be dropped at the end of the function. + /// + /// ### Example + /// + /// ```rust + /// fn f() -> *const u8 { + /// let x = 0; + /// &x // returns a dangling ptr to `x` + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Returning a pointer from a local value will not prolong its lifetime, + /// which means that the value can be dropped and the allocation freed + /// while the pointer still exists, making the pointer dangling. + /// This is not an error (as far as the type system is concerned) + /// but probably is not what the user intended either. + /// + /// If you need stronger guarantees, consider using references instead, + /// as they are statically verified by the borrow-checker to never dangle. + pub DANGLING_POINTERS_FROM_LOCALS, + Warn, + "detects returning a pointer from a local variable" +} + /// FIXME: false negatives (i.e. the lint is not emitted when it should be) /// 1. Ways to get a temporary that are not recognized: /// - `owning_temporary.field` @@ -53,20 +84,123 @@ declare_lint! { #[derive(Clone, Copy, Default)] pub(crate) struct DanglingPointers; -impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]); +impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES, DANGLING_POINTERS_FROM_LOCALS]); // This skips over const blocks, but they cannot use or return a dangling pointer anyways. impl<'tcx> LateLintPass<'tcx> for DanglingPointers { fn check_fn( &mut self, cx: &LateContext<'tcx>, - _: FnKind<'tcx>, - _: &'tcx FnDecl<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &'tcx FnDecl<'tcx>, body: &'tcx Body<'tcx>, _: Span, - _: LocalDefId, + def_id: LocalDefId, ) { - DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body) + DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body); + + if let FnRetTy::Return(ret_ty) = &fn_decl.output + && let TyKind::Ptr(_) = ret_ty.kind + { + // get the return type of the function or closure + let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() { + ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(), + ty::Closure(_, args) => args.as_closure().sig(), + _ => return, + }; + let ty = ty.output(); + + // this type is only used for layout computation and pretty-printing, neither of them rely on regions + let ty = cx.tcx.instantiate_bound_regions_with_erased(ty); + + // verify that we have a pointer type + let inner_ty = match ty.kind() { + ty::RawPtr(inner_ty, _) => *inner_ty, + _ => return, + }; + + if cx + .tcx + .layout_of(cx.typing_env().as_query_input(inner_ty)) + .is_ok_and(|layout| !layout.is_1zst()) + { + let dcx = &DanglingPointerLocalContext { + body: def_id, + fn_ret: ty, + fn_ret_span: ret_ty.span, + fn_ret_inner: inner_ty, + fn_kind: match fn_kind { + FnKind::ItemFn(..) => "function", + FnKind::Method(..) => "method", + FnKind::Closure => "closure", + }, + }; + + // look for `return`s + DanglingPointerReturnSearcher { cx, dcx }.visit_body(body); + + // analyze implicit return expression + if let ExprKind::Block(block, None) = &body.value.kind + && let innermost_block = block.innermost_block() + && let Some(expr) = innermost_block.expr + { + lint_addr_of_local(cx, dcx, expr); + } + } + } + } +} + +struct DanglingPointerLocalContext<'tcx> { + body: LocalDefId, + fn_ret: Ty<'tcx>, + fn_ret_span: Span, + fn_ret_inner: Ty<'tcx>, + fn_kind: &'static str, +} + +struct DanglingPointerReturnSearcher<'lcx, 'tcx> { + cx: &'lcx LateContext<'tcx>, + dcx: &'lcx DanglingPointerLocalContext<'tcx>, +} + +impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result { + if let ExprKind::Ret(Some(expr)) = expr.kind { + lint_addr_of_local(self.cx, self.dcx, expr); + } + walk_expr(self, expr) + } +} + +/// Look for `&` pattern and emit lint for it +fn lint_addr_of_local<'a>( + cx: &LateContext<'a>, + dcx: &DanglingPointerLocalContext<'a>, + expr: &'a Expr<'a>, +) { + // peel casts as they do not interest us here, we want the inner expression. + let (inner, _) = super::utils::peel_casts(cx, expr); + + if let ExprKind::AddrOf(_, _, inner_of) = inner.kind + && let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind + && let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id) + && cx.tcx.hir_enclosing_body_owner(from) == dcx.body + { + cx.tcx.emit_node_span_lint( + DANGLING_POINTERS_FROM_LOCALS, + expr.hir_id, + expr.span, + DanglingPointersFromLocals { + ret_ty: dcx.fn_ret, + ret_ty_span: dcx.fn_ret_span, + fn_kind: dcx.fn_kind, + local_var: cx.tcx.hir_span(from), + local_var_name: cx.tcx.hir_ident(from), + local_var_ty: dcx.fn_ret_inner, + created_at: (expr.hir_id != inner.hir_id).then_some(inner.span), + }, + ); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index fd8d0f832aa..ef63c0dee8c 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1188,6 +1188,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub temporary_span: Span, } +#[derive(LintDiagnostic)] +#[diag(lint_dangling_pointers_from_locals)] +#[note] +pub(crate) struct DanglingPointersFromLocals<'tcx> { + pub ret_ty: Ty<'tcx>, + #[label(lint_ret_ty)] + pub ret_ty_span: Span, + pub fn_kind: &'static str, + #[label(lint_local_var)] + pub local_var: Span, + pub local_var_name: Ident, + pub local_var_ty: Ty<'tcx>, + #[label(lint_created_at)] + pub created_at: Option, +} + // multiple_supertrait_upcastable.rs #[derive(LintDiagnostic)] #[diag(lint_multiple_supertrait_upcastable)] diff --git a/tests/ui/lint/dangling-pointers-from-locals.rs b/tests/ui/lint/dangling-pointers-from-locals.rs new file mode 100644 index 00000000000..e321df2f427 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-locals.rs @@ -0,0 +1,188 @@ +//@ check-pass + +struct Zst((), ()); +struct Adt(u8); + +const X: u8 = 5; + +fn simple() -> *const u8 { + let x = 0; + &x + //~^ WARN a dangling pointer will be produced +} + +fn bindings() -> *const u8 { + let x = 0; + let x = &x; + x + //~^ WARN a dangling pointer will be produced +} + +fn bindings_with_return() -> *const u8 { + let x = 42; + let y = &x; + return y; + //~^ WARN a dangling pointer will be produced +} + +fn with_simple_cast() -> *const u8 { + let x = 0u8; + &x as *const u8 + //~^ WARN a dangling pointer will be produced +} + +fn bindings_and_casts() -> *const u8 { + let x = 0u8; + let x = &x as *const u8; + x as *const u8 + //~^ WARN a dangling pointer will be produced +} + +fn return_with_complex_cast() -> *mut u8 { + let mut x = 0u8; + return &mut x as *mut u8 as *const u8 as *mut u8; + //~^ WARN a dangling pointer will be produced +} + +fn with_block() -> *const u8 { + let x = 0; + &{ x } + //~^ WARN a dangling pointer will be produced +} + +fn with_many_blocks() -> *const u8 { + let x = 0; + { + { + &{ + //~^ WARN a dangling pointer will be produced + { x } + } + } + } +} + +fn simple_return() -> *const u8 { + let x = 0; + return &x; + //~^ WARN a dangling pointer will be produced +} + +fn return_mut() -> *mut u8 { + let mut x = 0; + return &mut x; + //~^ WARN a dangling pointer will be produced +} + +fn const_and_flow() -> *const u8 { + if false { + let x = 8; + return &x; + //~^ WARN a dangling pointer will be produced + } + &X // not dangling +} + +fn vector() -> *const Vec { + let x = vec![T::default()]; + &x + //~^ WARN a dangling pointer will be produced +} + +fn local_adt() -> *const Adt { + let x = Adt(5); + return &x; + //~^ WARN a dangling pointer will be produced +} + +fn closure() -> *const u8 { + let _x = || -> *const u8 { + let x = 8; + return &x; + //~^ WARN a dangling pointer will be produced + }; + &X // not dangling +} + +fn fn_ptr() -> *const fn() -> u8 { + fn ret_u8() -> u8 { + 0 + } + + let x = ret_u8 as fn() -> u8; + &x + //~^ WARN a dangling pointer will be produced +} + +fn as_arg(a: Adt) -> *const Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 { + &a + //~^ WARN a dangling pointer will be produced +} + +fn ptr_as_arg(a: *const Adt) -> *const *const Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn adt_as_arg(a: &Adt) -> *const &Adt { + &a + //~^ WARN a dangling pointer will be produced +} + +fn unit() -> *const () { + let x = (); + &x // not dangling +} + +fn zst() -> *const Zst { + let x = Zst((), ()); + &x // not dangling +} + +fn ref_implicit(a: &Adt) -> *const Adt { + a // not dangling +} + +fn ref_explicit(a: &Adt) -> *const Adt { + &*a // not dangling +} + +fn identity(a: *const Adt) -> *const Adt { + a // not dangling +} + +fn from_ref(a: &Adt) -> *const Adt { + std::ptr::from_ref(a) // not dangling +} + +fn inner_static() -> *const u8 { + static U: u8 = 5; + if false { + return &U as *const u8; // not dangling + } + &U // not dangling +} + +fn return_in_closure() { + let x = 0; + let c = || -> *const u8 { + &x // not dangling by it-self + }; +} + +fn option() -> *const Option { + let x = Some(T::default()); + &x // can't compute layout of `Option`, so cnat' be sure it won't be a ZST +} + +fn generic() -> *const T { + let x = T::default(); + &x // can't compute layout of `T`, so can't be sure it won't be a ZST +} + +fn main() {} diff --git a/tests/ui/lint/dangling-pointers-from-locals.stderr b/tests/ui/lint/dangling-pointers-from-locals.stderr new file mode 100644 index 00000000000..e1d28bf22a0 --- /dev/null +++ b/tests/ui/lint/dangling-pointers-from-locals.stderr @@ -0,0 +1,247 @@ +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:10:5 + | +LL | fn simple() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + = note: `#[warn(dangling_pointers_from_locals)]` on by default + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:17:5 + | +LL | fn bindings() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | let x = &x; + | -- dangling pointer created here +LL | x + | ^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:24:12 + | +LL | fn bindings_with_return() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 42; + | - `x` is part the function and will be dropped at the end of the function +LL | let y = &x; + | -- dangling pointer created here +LL | return y; + | ^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:30:5 + | +LL | fn with_simple_cast() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0u8; + | - `x` is part the function and will be dropped at the end of the function +LL | &x as *const u8 + | --^^^^^^^^^^^^^ + | | + | dangling pointer created here + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:37:5 + | +LL | fn bindings_and_casts() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0u8; + | - `x` is part the function and will be dropped at the end of the function +LL | let x = &x as *const u8; + | -- dangling pointer created here +LL | x as *const u8 + | ^^^^^^^^^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:43:12 + | +LL | fn return_with_complex_cast() -> *mut u8 { + | ------- return type of the function is `*mut u8` +LL | let mut x = 0u8; + | ----- `x` is part the function and will be dropped at the end of the function +LL | return &mut x as *mut u8 as *const u8 as *mut u8; + | ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | dangling pointer created here + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:49:5 + | +LL | fn with_block() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | &{ x } + | ^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:57:13 + | +LL | fn with_many_blocks() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +... +LL | / &{ +LL | | +LL | | { x } +LL | | } + | |_____________^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:67:12 + | +LL | fn simple_return() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | let x = 0; + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:73:12 + | +LL | fn return_mut() -> *mut u8 { + | ------- return type of the function is `*mut u8` +LL | let mut x = 0; + | ----- `x` is part the function and will be dropped at the end of the function +LL | return &mut x; + | ^^^^^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:80:16 + | +LL | fn const_and_flow() -> *const u8 { + | --------- return type of the function is `*const u8` +LL | if false { +LL | let x = 8; + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:88:5 + | +LL | fn vector() -> *const Vec { + | ------------- return type of the function is `*const Vec` +LL | let x = vec![T::default()]; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Vec` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:94:12 + | +LL | fn local_adt() -> *const Adt { + | ---------- return type of the function is `*const Adt` +LL | let x = Adt(5); + | - `x` is part the function and will be dropped at the end of the function +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:101:16 + | +LL | let _x = || -> *const u8 { + | --------- return type of the closure is `*const u8` +LL | let x = 8; + | - `x` is part the closure and will be dropped at the end of the closure +LL | return &x; + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `u8` will be deallocated at the end of the closure because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `x` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:113:5 + | +LL | fn fn_ptr() -> *const fn() -> u8 { + | ----------------- return type of the function is `*const fn() -> u8` +... +LL | let x = ret_u8 as fn() -> u8; + | - `x` is part the function and will be dropped at the end of the function +LL | &x + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:118:5 + | +LL | fn as_arg(a: Adt) -> *const Adt { + | - ---------- return type of the function is `*const Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:123:5 + | +LL | fn fn_ptr_as_arg(a: fn() -> u8) -> *const fn() -> u8 { + | - ----------------- return type of the function is `*const fn() -> u8` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `fn() -> u8` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:128:5 + | +LL | fn ptr_as_arg(a: *const Adt) -> *const *const Adt { + | - ----------------- return type of the function is `*const *const Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `*const Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: a dangling pointer will be produced because the local variable `a` will be dropped + --> $DIR/dangling-pointers-from-locals.rs:133:5 + | +LL | fn adt_as_arg(a: &Adt) -> *const &Adt { + | - ----------- return type of the function is `*const &Adt` + | | + | `a` is part the function and will be dropped at the end of the function +LL | &a + | ^^ + | + = note: pointers do not have a lifetime; after returning, the `&Adt` will be deallocated at the end of the function because nothing is referencing it as far as the type system is concerned + +warning: 19 warnings emitted + -- cgit 1.4.1-3-g733a5 From 5aec4379e304ef280ee9a470e7ab121e4a81fd17 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 31 Jul 2025 23:59:06 +0200 Subject: detect infinite recursion with tail calls in ctfe --- compiler/rustc_mir_transform/src/ctfe_limit.rs | 2 +- .../explicit-tail-calls/infinite-recursion-in-ctfe.rs | 10 ++++++++++ .../infinite-recursion-in-ctfe.stderr | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs create mode 100644 tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr (limited to 'tests') diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs index fb17cca30f4..ac46336b834 100644 --- a/compiler/rustc_mir_transform/src/ctfe_limit.rs +++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs @@ -18,7 +18,7 @@ impl<'tcx> crate::MirPass<'tcx> for CtfeLimit { .basic_blocks .iter_enumerated() .filter_map(|(node, node_data)| { - if matches!(node_data.terminator().kind, TerminatorKind::Call { .. }) + if matches!(node_data.terminator().kind, TerminatorKind::Call { .. } | TerminatorKind::TailCall { .. }) // Back edges in a CFG indicate loops || has_back_edge(doms, node, node_data) { diff --git a/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs new file mode 100644 index 00000000000..0c55f13c16c --- /dev/null +++ b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.rs @@ -0,0 +1,10 @@ +#![feature(explicit_tail_calls)] +#![expect(incomplete_features)] + +const _: () = f(); + +const fn f() { + become f(); //~ error: constant evaluation is taking a long time +} + +fn main() {} diff --git a/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr new file mode 100644 index 00000000000..b5a96114a58 --- /dev/null +++ b/tests/ui/explicit-tail-calls/infinite-recursion-in-ctfe.stderr @@ -0,0 +1,17 @@ +error: constant evaluation is taking a long time + --> $DIR/infinite-recursion-in-ctfe.rs:7:5 + | +LL | become f(); + | ^^^^^^^^^^ + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/infinite-recursion-in-ctfe.rs:4:1 + | +LL | const _: () = f(); + | ^^^^^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error + -- cgit 1.4.1-3-g733a5 From 040f71e8123b5994177f787e64aecd9b06cdfa7e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 25 Jul 2025 15:18:51 +0200 Subject: loop match: error on `#[const_continue]` outside `#[loop_match]` --- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir_typeck/src/loops.rs | 50 ++++++++++++---------- compiler/rustc_mir_build/messages.ftl | 2 +- compiler/rustc_mir_build/src/errors.rs | 4 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 +- tests/ui/loop-match/const-continue-to-block.rs | 21 +++++++++ tests/ui/loop-match/const-continue-to-block.stderr | 17 +++++++- tests/ui/loop-match/invalid.rs | 19 ++++++++ tests/ui/loop-match/invalid.stderr | 22 +++++++--- 9 files changed, 107 insertions(+), 34 deletions(-) (limited to 'tests') diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1b1b3ced44d..08361718108 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3016,7 +3016,7 @@ impl fmt::Display for LoopIdError { } } -#[derive(Copy, Clone, Debug, HashStable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, HashStable_Generic)] pub struct Destination { /// This is `Some(_)` iff there is an explicit user-specified 'label pub label: Option