diff --git a/RELEASES.md b/RELEASES.md index aae2a66965014..a9422fa103ed8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -156,6 +156,7 @@ Language - [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220] - [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690] - [Allow panicking in constant evaluation.][89508] +- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200] Compiler -------- @@ -216,6 +217,9 @@ Cargo Compatibility notes ------------------- +- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200] + This will break some builds that set `#![deny(dead_code)]`. + Internal changes ---------------- These changes provide no direct user facing benefits, but represent significant @@ -224,6 +228,7 @@ and related tools. - [Added an experimental backend for codegen with `libgccjit`.][87260] +[85200]: https://github.com/rust-lang/rust/pull/85200/ [86191]: https://github.com/rust-lang/rust/pull/86191/ [87220]: https://github.com/rust-lang/rust/pull/87220/ [87260]: https://github.com/rust-lang/rust/pull/87260/ diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs index 785e6886d8a38..93310dd45c575 100644 --- a/compiler/rustc_ast_pretty/src/pp/convenience.rs +++ b/compiler/rustc_ast_pretty/src/pp/convenience.rs @@ -75,6 +75,10 @@ impl Printer { } pub fn trailing_comma(&mut self) { + self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() }); + } + + pub fn trailing_comma_or_space(&mut self) { self.scan_break(BreakToken { blank_space: 1, pre_break: Some(','), diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 44116fa76a0c1..6435f1b6141e3 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -142,7 +142,7 @@ impl<'a> State<'a> { if !field.is_last || has_rest { self.word_space(","); } else { - self.trailing_comma(); + self.trailing_comma_or_space(); } } if has_rest { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index dac84ae9d5fc8..d7e9ef0e50dd8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,5 +1,6 @@ use crate::pp::Breaks::Inconsistent; -use crate::pprust::state::{AnnNode, PrintState, State}; +use crate::pprust::state::delimited::IterDelimited; +use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; use rustc_ast as ast; use rustc_ast::GenericBound; @@ -138,11 +139,10 @@ impl<'a> State<'a> { self.end(); // end outer head-block } ast::ItemKind::Use(ref tree) => { - self.head(visibility_qualified(&item.vis, "use")); + self.print_visibility(&item.vis); + self.word_nbsp("use"); self.print_use_tree(tree); self.word(";"); - self.end(); // end inner head-block - self.end(); // end outer head-block } ast::ItemKind::Static(ref ty, mutbl, ref body) => { let def = ast::Defaultness::Final; @@ -615,8 +615,8 @@ impl<'a> State<'a> { ast::UseTreeKind::Simple(rename, ..) => { self.print_path(&tree.prefix, false, 0); if let Some(rename) = rename { - self.space(); - self.word_space("as"); + self.nbsp(); + self.word_nbsp("as"); self.print_ident(rename); } } @@ -628,16 +628,36 @@ impl<'a> State<'a> { self.word("*"); } ast::UseTreeKind::Nested(ref items) => { - if tree.prefix.segments.is_empty() { - self.word("{"); - } else { + if !tree.prefix.segments.is_empty() { self.print_path(&tree.prefix, false, 0); - self.word("::{"); + self.word("::"); + } + if items.is_empty() { + self.word("{}"); + } else if items.len() == 1 { + self.print_use_tree(&items[0].0); + } else { + self.cbox(INDENT_UNIT); + self.word("{"); + self.zerobreak(); + self.ibox(0); + for use_tree in items.iter().delimited() { + self.print_use_tree(&use_tree.0); + if !use_tree.is_last { + self.word(","); + if let ast::UseTreeKind::Nested(_) = use_tree.0.kind { + self.hardbreak(); + } else { + self.space(); + } + } + } + self.end(); + self.trailing_comma(); + self.offset(-INDENT_UNIT); + self.word("}"); + self.end(); } - self.commasep(Inconsistent, &items, |this, &(ref tree, _)| { - this.print_use_tree(tree) - }); - self.word("}"); } } } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index c401f65eddaed..a72681dbf4e7e 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -97,6 +97,7 @@ E0184: include_str!("./error_codes/E0184.md"), E0185: include_str!("./error_codes/E0185.md"), E0186: include_str!("./error_codes/E0186.md"), E0191: include_str!("./error_codes/E0191.md"), +E0192: include_str!("./error_codes/E0192.md"), E0193: include_str!("./error_codes/E0193.md"), E0195: include_str!("./error_codes/E0195.md"), E0197: include_str!("./error_codes/E0197.md"), @@ -522,7 +523,6 @@ E0787: include_str!("./error_codes/E0787.md"), // E0188, // can not cast an immutable reference to a mutable pointer // E0189, // deprecated: can only cast a boxed pointer to a boxed object // E0190, // deprecated: can only cast a &-pointer to an &-object -// E0192, // negative impl only applicable to auto traits // E0194, // merged into E0403 // E0196, // cannot determine a type for this closure E0208, diff --git a/compiler/rustc_error_codes/src/error_codes/E0192.md b/compiler/rustc_error_codes/src/error_codes/E0192.md index 5fd951b2e86cb..deca042a91a50 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0192.md +++ b/compiler/rustc_error_codes/src/error_codes/E0192.md @@ -1,15 +1,17 @@ +#### Note: this error code is no longer emitted by the compiler. + A negative impl was added on a trait implementation. Erroneous code example: -```compile_fail,E0192 +```compile_fail trait Trait { type Bar; } struct Foo; -impl !Trait for Foo { } //~ ERROR E0192 +impl !Trait for Foo { } //~ ERROR fn main() {} ``` diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4898a4844b9f7..e9aa4adcaf79b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1457,9 +1457,9 @@ impl<'a> Parser<'a> { } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() { self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs) } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) { - // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the - // "must be followed by a colon" error, and the "expected one of" error. - self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly"); + // We're probably inside of a `Path<'a>` that needs a turbofish + let msg = "expected `while`, `for`, `loop` or `{` after a label"; + self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit(); consume_colon = false; Ok(self.mk_expr_err(lo)) } else { diff --git a/src/test/pretty/use-tree.rs b/src/test/pretty/use-tree.rs new file mode 100644 index 0000000000000..5da9523524552 --- /dev/null +++ b/src/test/pretty/use-tree.rs @@ -0,0 +1,23 @@ +// pp-exact +// edition:2021 + +#![allow(unused_imports)] + +use ::std::fmt::{self, Debug, Display, Write as _}; + +use core::option::Option::*; + +use core::{ + cmp::{Eq, Ord, PartialEq, PartialOrd}, + convert::{AsMut, AsRef, From, Into}, + iter::{ + DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, + IntoIterator, Iterator, + }, + marker::{ + Copy as Copy, Send as Send, Sized as Sized, Sync as Sync, Unpin as U, + }, + ops::{*, Drop, Fn, FnMut, FnOnce}, +}; + +fn main() {} diff --git a/src/test/ui/associated-types/issue-91069.rs b/src/test/ui/associated-types/issue-91069.rs new file mode 100644 index 0000000000000..109c2eed27a33 --- /dev/null +++ b/src/test/ui/associated-types/issue-91069.rs @@ -0,0 +1,24 @@ +// check-pass + +pub trait Associate { + type Associated; +} + +pub struct Wrap<'a> { + pub field: &'a i32, +} + +pub trait Create { + fn create() -> Self; +} + +pub fn oh_no<'a, T>() +where + Wrap<'a>: Associate, + as Associate>::Associated: Create, +{ + as Associate>::Associated::create(); +} + + +pub fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.rs b/src/test/ui/generic-associated-types/bugs/issue-80626.rs new file mode 100644 index 0000000000000..aea8aaf4bb393 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.rs @@ -0,0 +1,17 @@ +// check-fail + +// This should pass, but it requires `Sized` to be coinductive. + +#![feature(generic_associated_types)] + +trait Allocator { + type Allocated; +} + +enum LinkedList { + Head, + Next(A::Allocated) + //~^ overflow +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr new file mode 100644 index 0000000000000..e18af9c257f7f --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr @@ -0,0 +1,20 @@ +error[E0275]: overflow evaluating the requirement `LinkedList: Sized` + --> $DIR/issue-80626.rs:13:10 + | +LL | Next(A::Allocated) + | ^^^^^^^^^^^^^^^^^^ + | + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | Next(&A::Allocated) + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | Next(Box>) + | ++++ + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/bugs/issue-86218.rs new file mode 100644 index 0000000000000..3f8776a363770 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-86218.rs @@ -0,0 +1,27 @@ +// check-fail + +// This should pass, but seems to run into a TAIT issue. + +#![feature(generic_associated_types)] +#![feature(type_alias_impl_trait)] + +pub trait Stream { + type Item; +} + +impl Stream for () { + type Item = i32; +} + +trait Yay { + type InnerStream<'s>: Stream + 's; + fn foo<'s>() -> Self::InnerStream<'s>; +} + +impl<'a> Yay<&'a ()> for () { + type InnerStream<'s> = impl Stream + 's; + //~^ the type + fn foo<'s>() -> Self::InnerStream<'s> { todo!() } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr new file mode 100644 index 0000000000000..9f4efc0addb73 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr @@ -0,0 +1,15 @@ +error[E0477]: the type `impl Stream` does not fulfill the required lifetime + --> $DIR/issue-86218.rs:22:28 + | +LL | type InnerStream<'s> = impl Stream + 's; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type must outlive the lifetime `'s` as defined here as required by this binding + --> $DIR/issue-86218.rs:22:22 + | +LL | type InnerStream<'s> = impl Stream + 's; + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0477`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs new file mode 100644 index 0000000000000..5f7a42a740df6 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87735.rs @@ -0,0 +1,45 @@ +// check-fail + +// This should pass, but we need an extension of implied bounds (probably). + +#![feature(generic_associated_types)] + +pub trait AsRef2 { + type Output<'a> where Self: 'a; + + fn as_ref2<'a>(&'a self) -> Self::Output<'a>; +} + +impl AsRef2 for Vec { + type Output<'a> where Self: 'a = &'a [T]; + + fn as_ref2<'a>(&'a self) -> Self::Output<'a> { + &self[..] + } +} + +#[derive(Debug)] +struct Foo(T); +#[derive(Debug)] +struct FooRef<'a, U>(&'a [U]); + +impl<'b, T, U> AsRef2 for Foo //~ the type parameter +where + // * `for<'b, 'c> T: AsRef2 = &'c [U]>>` does not work + // + // * `U` is unconstrained but should be allowed in this context because `Output` is + // an associated type + T: AsRef2 = &'b [U]>, + U: 'b +{ + type Output<'a> where Self: 'a = FooRef<'a, U>; + + fn as_ref2<'a>(&'a self) -> Self::Output<'a> { + FooRef(self.0.as_ref2()) + } +} + +fn main() { + let foo = Foo(vec![1, 2, 3]); + dbg!(foo.as_ref2()); +} diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.stderr b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr new file mode 100644 index 0000000000000..31b3a9619b6af --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-87735.rs:26:13 + | +LL | impl<'b, T, U> AsRef2 for Foo + | ^ unconstrained type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs new file mode 100644 index 0000000000000..4dbaf429ead26 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87748.rs @@ -0,0 +1,22 @@ +// check-fail + +// This should pass, but unnormalized input args aren't treated as implied. + +#![feature(generic_associated_types)] + +trait MyTrait { + type Assoc<'a, 'b> where 'b: 'a; + fn do_sth(arg: Self::Assoc<'_, '_>); +} + +struct Foo; + +impl MyTrait for Foo { + type Assoc<'a, 'b> where 'b: 'a = u32; + + fn do_sth(_: u32) {} //~ lifetime bound + // fn do_sth(_: Self::Assoc<'static, 'static>) {} + // fn do_sth(_: Self::Assoc<'_, '_>) {} +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr new file mode 100644 index 0000000000000..c38d447859233 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr @@ -0,0 +1,20 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/issue-87748.rs:17:5 + | +LL | fn do_sth(_: u32) {} + | ^^^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the anonymous lifetime #2 defined here + --> $DIR/issue-87748.rs:17:5 + | +LL | fn do_sth(_: u32) {} + | ^^^^^^^^^^^^^^^^^ +note: but lifetime parameter must outlive the anonymous lifetime #1 defined here + --> $DIR/issue-87748.rs:17:5 + | +LL | fn do_sth(_: u32) {} + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0478`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.rs b/src/test/ui/generic-associated-types/bugs/issue-87755.rs new file mode 100644 index 0000000000000..1cd3534ba77a0 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87755.rs @@ -0,0 +1,21 @@ +// check-fail + +// This should pass. + +#![feature(generic_associated_types)] + +use std::fmt::Debug; + +trait Foo { + type Ass where Self::Ass: Debug; +} + +#[derive(Debug)] +struct Bar; + +impl Foo for Bar { + type Ass = Bar; + //~^ overflow +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.stderr b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr new file mode 100644 index 0000000000000..d2dc991a2b640 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `::Ass == _` + --> $DIR/issue-87755.rs:17:16 + | +LL | type Ass = Bar; + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.rs b/src/test/ui/generic-associated-types/bugs/issue-87803.rs new file mode 100644 index 0000000000000..3d2ff38ab049e --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87803.rs @@ -0,0 +1,26 @@ +// check-fail + +// This should pass, but using a type alias vs a reference directly +// changes late-bound -> early-bound. + +#![feature(generic_associated_types)] + +trait Scanner { + type Input<'a>; + type Token<'a>; + + fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>; +} + +struct IdScanner(); + +impl Scanner for IdScanner { + type Input<'a> = &'a str; + type Token<'a> = &'a str; + + fn scan<'a>(&mut self, s : &'a str) -> &'a str { //~ lifetime parameters + s + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.stderr b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr new file mode 100644 index 0000000000000..759c0440d07ba --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr @@ -0,0 +1,12 @@ +error[E0195]: lifetime parameters or bounds on method `scan` do not match the trait declaration + --> $DIR/issue-87803.rs:21:12 + | +LL | fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>; + | ---- lifetimes in impl do not match this method in trait +... +LL | fn scan<'a>(&mut self, s : &'a str) -> &'a str { + | ^^^^ lifetimes do not match method in trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0195`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.rs b/src/test/ui/generic-associated-types/bugs/issue-88382.rs new file mode 100644 index 0000000000000..f4633ca516999 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-88382.rs @@ -0,0 +1,31 @@ +// check-fail + +// This should pass, but has a missed normalization due to HRTB. + +#![feature(generic_associated_types)] + +trait Iterable { + type Iterator<'a> where Self: 'a; + fn iter(&self) -> Self::Iterator<'_>; +} + +struct SomeImplementation(); + +impl Iterable for SomeImplementation { + type Iterator<'a> = std::iter::Empty; + fn iter(&self) -> Self::Iterator<'_> { + std::iter::empty() + } +} + +fn do_something(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) { + f(&mut i.iter()); +} + +fn main() { + do_something(SomeImplementation(), |_| ()); + do_something(SomeImplementation(), test); + //~^ type mismatch +} + +fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr new file mode 100644 index 0000000000000..05bc58cbba4e6 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr @@ -0,0 +1,20 @@ +error[E0631]: type mismatch in function arguments + --> $DIR/issue-88382.rs:27:40 + | +LL | do_something(SomeImplementation(), test); + | ------------ ^^^^ expected signature of `for<'a> fn(&mut ::Iterator<'a>) -> _` + | | + | required by a bound introduced by this call +... +LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {} + | ------------------------------------------------- found signature of `for<'r> fn(&'r mut std::iter::Empty) -> _` + | +note: required by a bound in `do_something` + --> $DIR/issue-88382.rs:21:56 + | +LL | fn do_something(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.rs b/src/test/ui/generic-associated-types/bugs/issue-88460.rs new file mode 100644 index 0000000000000..7e62790cc50c3 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-88460.rs @@ -0,0 +1,31 @@ +// check-fail + +// This should pass, but has a missed normalization due to HRTB. + +#![feature(generic_associated_types)] + +pub trait Marker {} + +pub trait Trait { + type Assoc<'a>; +} + +fn test(value: T) +where + T: Trait, + for<'a> T::Assoc<'a>: Marker, +{ +} + +impl Marker for () {} + +struct Foo; + +impl Trait for Foo { + type Assoc<'a> = (); +} + +fn main() { + test(Foo); + //~^ the trait bound +} diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.stderr b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr new file mode 100644 index 0000000000000..604658da7d2c2 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied + --> $DIR/issue-88460.rs:29:5 + | +LL | test(Foo); + | ^^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>` + | +note: required by a bound in `test` + --> $DIR/issue-88460.rs:16:27 + | +LL | fn test(value: T) + | ---- required by a bound in this +... +LL | for<'a> T::Assoc<'a>: Marker, + | ^^^^^^ required by this bound in `test` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.rs b/src/test/ui/generic-associated-types/bugs/issue-88526.rs new file mode 100644 index 0000000000000..90568fcb40125 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-88526.rs @@ -0,0 +1,34 @@ +// check-fail + +// This should pass, but requires more logic. + +#![feature(generic_associated_types)] + +trait A { + type I<'a>; +} + +pub struct TestA +{ + f: F, +} + +impl A for TestA { + type I<'a> = &'a F; +} + +struct TestB +{ + q: Q, + f: F, +} + +impl<'q, Q, I, F> A for TestB //~ the type parameter +where + Q: A = &'q I>, + F: Fn(I), +{ + type I<'a> = (); +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.stderr b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr new file mode 100644 index 0000000000000..ccc5ae0b621a1 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr @@ -0,0 +1,9 @@ +error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-88526.rs:26:13 + | +LL | impl<'q, Q, I, F> A for TestB + | ^ unconstrained type parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.rs b/src/test/ui/generic-associated-types/bugs/issue-89008.rs new file mode 100644 index 0000000000000..5d850849fd21c --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.rs @@ -0,0 +1,43 @@ +// check-fail +// edition:2021 + +// This should pass, but seems to run into a TAIT bug. + +#![feature(type_alias_impl_trait)] +#![feature(generic_associated_types)] + +use std::future::Future; + +trait Stream { + type Item; +} + +struct Empty(T); +impl Stream for Empty { + type Item = (); +} +fn empty() -> Empty { + todo!() +} + +trait X { + type LineStream<'a, Repr>: Stream where Self: 'a; + + type LineStreamFut<'a,Repr>: Future> where Self: 'a; + + fn line_stream<'a,Repr>(&'a self) -> Self::LineStreamFut<'a,Repr>; +} + +struct Y; + +impl X for Y { + type LineStream<'a, Repr> = impl Stream; //~ could not find + + type LineStreamFut<'a, Repr> = impl Future> ; + + fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { //~ type mismatch + async {empty()} + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr new file mode 100644 index 0000000000000..48745fe0fbd96 --- /dev/null +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr @@ -0,0 +1,21 @@ +error[E0271]: type mismatch resolving ` as Future>::Output == impl Stream` + --> $DIR/issue-89008.rs:38:43 + | +LL | type LineStream<'a, Repr> = impl Stream; + | ------------------------ the expected opaque type +... +LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found struct `Empty` + | + = note: expected opaque type `impl Stream` + found struct `Empty<_>` + +error: could not find defining uses + --> $DIR/issue-89008.rs:34:33 + | +LL | type LineStream<'a, Repr> = impl Stream; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs new file mode 100644 index 0000000000000..2b82d2946b3ba --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-91139.rs @@ -0,0 +1,22 @@ +// check-pass + +#![feature(generic_associated_types)] + +trait Foo { + type Type<'a> + where + T: 'a; +} + +impl Foo for () { + type Type<'a> + where + T: 'a, + = (); +} + +fn foo() { + let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); +} + +pub fn main() {} diff --git a/src/test/ui/parser/issues/issue-93282.rs b/src/test/ui/parser/issues/issue-93282.rs index 7be8b25363e09..261fcb5f9183e 100644 --- a/src/test/ui/parser/issues/issue-93282.rs +++ b/src/test/ui/parser/issues/issue-93282.rs @@ -1,4 +1,15 @@ fn main() { f<'a,> //~^ ERROR expected + //~| ERROR expected +} + +fn bar(a: usize, b: usize) -> usize { + a + b +} + +fn foo() { + let x = 1; + bar('y, x); + //~^ ERROR expected } diff --git a/src/test/ui/parser/issues/issue-93282.stderr b/src/test/ui/parser/issues/issue-93282.stderr index 20e6c3ed8a8d5..900f21a7ccef4 100644 --- a/src/test/ui/parser/issues/issue-93282.stderr +++ b/src/test/ui/parser/issues/issue-93282.stderr @@ -1,3 +1,9 @@ +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/issue-93282.rs:2:9 + | +LL | f<'a,> + | ^ expected `while`, `for`, `loop` or `{` after a label + error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `{`, `}`, or an operator, found `,` --> $DIR/issue-93282.rs:2:9 | @@ -9,5 +15,11 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum LL | f::<'a,> | ++ -error: aborting due to previous error +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/issue-93282.rs:13:11 + | +LL | bar('y, x); + | ^ expected `while`, `for`, `loop` or `{` after a label + +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.rs b/src/test/ui/parser/require-parens-for-chained-comparison.rs index 68636f6b907ef..f29fd7a5472d4 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.rs +++ b/src/test/ui/parser/require-parens-for-chained-comparison.rs @@ -22,10 +22,12 @@ fn main() { let _ = f<'_, i8>(); //~^ ERROR expected one of //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + //~| ERROR expected f<'_>(); //~^ comparison operators cannot be chained //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + //~| ERROR expected let _ = f; //~^ ERROR comparison operators cannot be chained diff --git a/src/test/ui/parser/require-parens-for-chained-comparison.stderr b/src/test/ui/parser/require-parens-for-chained-comparison.stderr index cde6f8c674f4b..92d700753dc1b 100644 --- a/src/test/ui/parser/require-parens-for-chained-comparison.stderr +++ b/src/test/ui/parser/require-parens-for-chained-comparison.stderr @@ -53,6 +53,12 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum LL | let _ = f::(); | ++ +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/require-parens-for-chained-comparison.rs:22:17 + | +LL | let _ = f<'_, i8>(); + | ^ expected `while`, `for`, `loop` or `{` after a label + error: expected one of `.`, `:`, `;`, `?`, `else`, `for`, `loop`, `while`, `{`, or an operator, found `,` --> $DIR/require-parens-for-chained-comparison.rs:22:17 | @@ -64,8 +70,14 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum LL | let _ = f::<'_, i8>(); | ++ +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/require-parens-for-chained-comparison.rs:27:9 + | +LL | f<'_>(); + | ^ expected `while`, `for`, `loop` or `{` after a label + error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:26:6 + --> $DIR/require-parens-for-chained-comparison.rs:27:6 | LL | f<'_>(); | ^ ^ @@ -76,7 +88,7 @@ LL | f::<'_>(); | ++ error: comparison operators cannot be chained - --> $DIR/require-parens-for-chained-comparison.rs:30:14 + --> $DIR/require-parens-for-chained-comparison.rs:32:14 | LL | let _ = f; | ^ ^ @@ -84,5 +96,5 @@ LL | let _ = f; = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments = help: or use `(...)` if you meant to specify fn arguments -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 94e82e3d9f766..46daaf42883f0 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -182,8 +182,9 @@ impl Checker { fn walk(&mut self, dir: &Path, report: &mut Report) { for entry in t!(dir.read_dir()).map(|e| t!(e)) { let path = entry.path(); - let kind = t!(entry.file_type()); - if kind.is_dir() { + // Goes through symlinks + let metadata = t!(fs::metadata(&path)); + if metadata.is_dir() { self.walk(&path, report); } else { self.check(&path, report); diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 8ea6bb308b7ba..2a23d72edc064 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -1,7 +1,7 @@ //! Checks that all error codes have at least one test to prevent having error //! codes that are silently not thrown by the compiler anymore. -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::ffi::OsStr; use std::fs::read_to_string; use std::path::Path; @@ -205,6 +205,7 @@ pub fn check(paths: &[&Path], bad: &mut bool) { let mut found_explanations = 0; let mut found_tests = 0; let mut error_codes: HashMap = HashMap::new(); + let mut explanations: HashSet = HashSet::new(); // We want error codes which match the following cases: // // * foo(a, E0111, a) @@ -218,17 +219,27 @@ pub fn check(paths: &[&Path], bad: &mut bool) { for path in paths { super::walk(path, &mut |path| super::filter_dirs(path), &mut |entry, contents| { let file_name = entry.file_name(); + let entry_path = entry.path(); + if file_name == "error_codes.rs" { extract_error_codes(contents, &mut error_codes, entry.path(), &mut errors); found_explanations += 1; - } else if entry.path().extension() == Some(OsStr::new("stderr")) { + } else if entry_path.extension() == Some(OsStr::new("stderr")) { extract_error_codes_from_tests(contents, &mut error_codes); found_tests += 1; - } else if entry.path().extension() == Some(OsStr::new("rs")) { + } else if entry_path.extension() == Some(OsStr::new("rs")) { let path = entry.path().to_string_lossy(); if PATHS_TO_IGNORE_FOR_EXTRACTION.iter().all(|c| !path.contains(c)) { extract_error_codes_from_source(contents, &mut error_codes, ®ex); } + } else if entry_path + .parent() + .and_then(|p| p.file_name()) + .map(|p| p == "error_codes") + .unwrap_or(false) + && entry_path.extension() == Some(OsStr::new("md")) + { + explanations.insert(file_name.to_str().unwrap().replace(".md", "")); } }); } @@ -240,6 +251,10 @@ pub fn check(paths: &[&Path], bad: &mut bool) { eprintln!("No error code was found in compilation errors!"); *bad = true; } + if explanations.is_empty() { + eprintln!("No error code explanation was found!"); + *bad = true; + } if errors.is_empty() { println!("Found {} error codes", error_codes.len()); @@ -282,11 +297,21 @@ pub fn check(paths: &[&Path], bad: &mut bool) { } } } + if errors.is_empty() { + for explanation in explanations { + if !error_codes.contains_key(&explanation) { + errors.push(format!( + "{} error code explanation should be listed in `error_codes.rs`", + explanation + )); + } + } + } errors.sort(); for err in &errors { eprintln!("{}", err); } - println!("Found {} error codes with no tests", errors.len()); + println!("Found {} error(s) in error codes", errors.len()); if !errors.is_empty() { *bad = true; }