diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 9cf3182daea59..2178b65727d09 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -607,8 +607,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) // does not check the same for lib features unless there's at least one // declared lang feature if !sess.opts.unstable_features.is_nightly_build() { - let lang_features = &features.declared_lang_features; - if lang_features.len() == 0 { + if features.declared_features.is_empty() { return; } for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { @@ -624,7 +623,8 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { let name = ident.name; - let stable_since = lang_features + let stable_since = features + .declared_lang_features .iter() .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) .next(); diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index a48c0a4450c29..f47bfdad13128 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -1,5 +1,5 @@ #![feature( - no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, + no_core, lang_items, intrinsics, unboxed_closures, extern_types, decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls, thread_local )] diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 5673101dc2448..1db3774222a09 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -621,8 +621,6 @@ declare_features! ( (unstable, try_blocks, "1.29.0", Some(31436)), /// Allows `impl Trait` to be used inside type aliases (RFC 2515). (unstable, type_alias_impl_trait, "1.38.0", Some(63063)), - /// Allows the use of type ascription in expressions. - (unstable, type_ascription, "1.6.0", Some(23416)), /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b1588357bffec..958458eda9a78 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1537,14 +1537,16 @@ impl<'a> Parser<'a> { // we don't need N spans, but we want at least one, so print all of prev_token dbg_fmt.field("prev_token", &parser.prev_token); - // make it easier to peek farther ahead by taking TokenKinds only until EOF - let tokens = (0..*lookahead) - .map(|i| parser.look_ahead(i, |tok| tok.kind.clone())) - .scan(parser.prev_token == TokenKind::Eof, |eof, tok| { - let current = eof.then_some(tok.clone()); // include a trailing EOF token - *eof |= &tok == &TokenKind::Eof; - current - }); + let mut tokens = vec![]; + for i in 0..*lookahead { + let tok = parser.look_ahead(i, |tok| tok.kind.clone()); + let is_eof = tok == TokenKind::Eof; + tokens.push(tok); + if is_eof { + // Don't look ahead past EOF. + break; + } + } dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish()); dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls); diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 5b2d119e42b45..cf791d332a2fc 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1376,12 +1376,13 @@ fn ttdelim_span() { }); } -// Uses a macro rather than a function so that failure messages mention the -// correct line in the test function. -macro_rules! look { - ($p:ident, $dist:literal, $kind:expr) => { - $p.look_ahead($dist, |tok| assert_eq!($kind, tok.kind)); - }; +#[track_caller] +fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) { + // Do the `assert_eq` outside the closure so that `track_caller` works. + // (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure + // doesn't give the line number in the test below if the assertion fails.) + let tok = p.look_ahead(dist, |tok| tok.clone()); + assert_eq!(kind, tok.kind); } #[test] @@ -1397,63 +1398,63 @@ fn look_ahead() { let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string()); // Current position is the `fn`. - look!(p, 0, token::Ident(kw::Fn, raw_no)); - look!(p, 1, token::Ident(sym_f, raw_no)); - look!(p, 2, token::OpenDelim(Delimiter::Parenthesis)); - look!(p, 3, token::Ident(sym_x, raw_no)); - look!(p, 4, token::Colon); - look!(p, 5, token::Ident(sym::u32, raw_no)); - look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 7, token::OpenDelim(Delimiter::Brace)); - look!(p, 8, token::Ident(sym_x, raw_no)); - look!(p, 9, token::CloseDelim(Delimiter::Brace)); - look!(p, 10, token::Ident(kw::Struct, raw_no)); - look!(p, 11, token::Ident(sym_S, raw_no)); - look!(p, 12, token::Semi); + look(&p, 0, token::Ident(kw::Fn, raw_no)); + look(&p, 1, token::Ident(sym_f, raw_no)); + look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 3, token::Ident(sym_x, raw_no)); + look(&p, 4, token::Colon); + look(&p, 5, token::Ident(sym::u32, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 8, token::Ident(sym_x, raw_no)); + look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 10, token::Ident(kw::Struct, raw_no)); + look(&p, 11, token::Ident(sym_S, raw_no)); + look(&p, 12, token::Semi); // Any lookahead past the end of the token stream returns `Eof`. - look!(p, 13, token::Eof); - look!(p, 14, token::Eof); - look!(p, 15, token::Eof); - look!(p, 100, token::Eof); + look(&p, 13, token::Eof); + look(&p, 14, token::Eof); + look(&p, 15, token::Eof); + look(&p, 100, token::Eof); // Move forward to the first `x`. for _ in 0..3 { p.bump(); } - look!(p, 0, token::Ident(sym_x, raw_no)); - look!(p, 1, token::Colon); - look!(p, 2, token::Ident(sym::u32, raw_no)); - look!(p, 3, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 4, token::OpenDelim(Delimiter::Brace)); - look!(p, 5, token::Ident(sym_x, raw_no)); - look!(p, 6, token::CloseDelim(Delimiter::Brace)); - look!(p, 7, token::Ident(kw::Struct, raw_no)); - look!(p, 8, token::Ident(sym_S, raw_no)); - look!(p, 9, token::Semi); - look!(p, 10, token::Eof); - look!(p, 11, token::Eof); - look!(p, 100, token::Eof); + look(&p, 0, token::Ident(sym_x, raw_no)); + look(&p, 1, token::Colon); + look(&p, 2, token::Ident(sym::u32, raw_no)); + look(&p, 3, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 4, token::OpenDelim(Delimiter::Brace)); + look(&p, 5, token::Ident(sym_x, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Brace)); + look(&p, 7, token::Ident(kw::Struct, raw_no)); + look(&p, 8, token::Ident(sym_S, raw_no)); + look(&p, 9, token::Semi); + look(&p, 10, token::Eof); + look(&p, 11, token::Eof); + look(&p, 100, token::Eof); // Move forward to the `;`. for _ in 0..9 { p.bump(); } - look!(p, 0, token::Semi); + look(&p, 0, token::Semi); // Any lookahead past the end of the token stream returns `Eof`. - look!(p, 1, token::Eof); - look!(p, 100, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); // Move one past the `;`, i.e. past the end of the token stream. p.bump(); - look!(p, 0, token::Eof); - look!(p, 1, token::Eof); - look!(p, 100, token::Eof); + look(&p, 0, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); // Bumping after Eof is idempotent. p.bump(); - look!(p, 0, token::Eof); - look!(p, 1, token::Eof); - look!(p, 100, token::Eof); + look(&p, 0, token::Eof); + look(&p, 1, token::Eof); + look(&p, 100, token::Eof); }); } @@ -1476,24 +1477,261 @@ fn look_ahead_non_outermost_stream() { for _ in 0..3 { p.bump(); } - look!(p, 0, token::Ident(kw::Fn, raw_no)); - look!(p, 1, token::Ident(sym_f, raw_no)); - look!(p, 2, token::OpenDelim(Delimiter::Parenthesis)); - look!(p, 3, token::Ident(sym_x, raw_no)); - look!(p, 4, token::Colon); - look!(p, 5, token::Ident(sym::u32, raw_no)); - look!(p, 6, token::CloseDelim(Delimiter::Parenthesis)); - look!(p, 7, token::OpenDelim(Delimiter::Brace)); - look!(p, 8, token::Ident(sym_x, raw_no)); - look!(p, 9, token::CloseDelim(Delimiter::Brace)); - look!(p, 10, token::Ident(kw::Struct, raw_no)); - look!(p, 11, token::Ident(sym_S, raw_no)); - look!(p, 12, token::Semi); - look!(p, 13, token::CloseDelim(Delimiter::Brace)); + look(&p, 0, token::Ident(kw::Fn, raw_no)); + look(&p, 1, token::Ident(sym_f, raw_no)); + look(&p, 2, token::OpenDelim(Delimiter::Parenthesis)); + look(&p, 3, token::Ident(sym_x, raw_no)); + look(&p, 4, token::Colon); + look(&p, 5, token::Ident(sym::u32, raw_no)); + look(&p, 6, token::CloseDelim(Delimiter::Parenthesis)); + look(&p, 7, token::OpenDelim(Delimiter::Brace)); + look(&p, 8, token::Ident(sym_x, raw_no)); + look(&p, 9, token::CloseDelim(Delimiter::Brace)); + look(&p, 10, token::Ident(kw::Struct, raw_no)); + look(&p, 11, token::Ident(sym_S, raw_no)); + look(&p, 12, token::Semi); + look(&p, 13, token::CloseDelim(Delimiter::Brace)); // Any lookahead past the end of the token stream returns `Eof`. - look!(p, 14, token::Eof); - look!(p, 15, token::Eof); - look!(p, 100, token::Eof); + look(&p, 14, token::Eof); + look(&p, 15, token::Eof); + look(&p, 100, token::Eof); + }); +} + +// FIXME(nnethercote) All the output is currently wrong. +#[test] +fn debug_lookahead() { + create_default_session_globals_then(|| { + let psess = psess(); + let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string()); + + // Current position is the `fn`. + assert_eq!( + &format!("{:#?}", p.debug_lookahead(0)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [], + approx_token_stream_pos: 1, + .. +}" + ); + assert_eq!( + &format!("{:#?}", p.debug_lookahead(7)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"fn\", + No, + ), + Ident( + \"f\", + No, + ), + OpenDelim( + Parenthesis, + ), + Ident( + \"x\", + No, + ), + Colon, + Ident( + \"u32\", + No, + ), + CloseDelim( + Parenthesis, + ), + ], + approx_token_stream_pos: 1, + .. +}" + ); + // There are 13 tokens. We request 15, get 14; the last one is `Eof`. + assert_eq!( + &format!("{:#?}", p.debug_lookahead(15)), + "Parser { + prev_token: Token { + kind: Question, + span: Span { + lo: BytePos( + 0, + ), + hi: BytePos( + 0, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"fn\", + No, + ), + Ident( + \"f\", + No, + ), + OpenDelim( + Parenthesis, + ), + Ident( + \"x\", + No, + ), + Colon, + Ident( + \"u32\", + No, + ), + CloseDelim( + Parenthesis, + ), + OpenDelim( + Brace, + ), + Ident( + \"x\", + No, + ), + CloseDelim( + Brace, + ), + Ident( + \"struct\", + No, + ), + Ident( + \"S\", + No, + ), + Semi, + Eof, + ], + approx_token_stream_pos: 1, + .. +}" + ); + + // Move forward to the second `x`. + for _ in 0..8 { + p.bump(); + } + assert_eq!( + &format!("{:#?}", p.debug_lookahead(1)), + "Parser { + prev_token: Token { + kind: OpenDelim( + Brace, + ), + span: Span { + lo: BytePos( + 13, + ), + hi: BytePos( + 14, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"x\", + No, + ), + ], + approx_token_stream_pos: 9, + .. +}" + ); + assert_eq!( + &format!("{:#?}", p.debug_lookahead(4)), + "Parser { + prev_token: Token { + kind: OpenDelim( + Brace, + ), + span: Span { + lo: BytePos( + 13, + ), + hi: BytePos( + 14, + ), + ctxt: #0, + }, + }, + tokens: [ + Ident( + \"x\", + No, + ), + CloseDelim( + Brace, + ), + Ident( + \"struct\", + No, + ), + Ident( + \"S\", + No, + ), + ], + approx_token_stream_pos: 9, + .. +}" + ); + + // Move two past the final token (the `;`). + for _ in 0..6 { + p.bump(); + } + assert_eq!( + &format!("{:#?}", p.debug_lookahead(3)), + "Parser { + prev_token: Token { + kind: Eof, + span: Span { + lo: BytePos( + 27, + ), + hi: BytePos( + 28, + ), + ctxt: #0, + }, + }, + tokens: [ + Eof, + ], + approx_token_stream_pos: 15, + .. +}" + ); }); } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d7513fbad63c8..1d93cbaddd6fe 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -290,9 +290,6 @@ passes_export_name = passes_extern_main = the `main` function cannot be declared in an `extern` block -passes_feature_only_on_nightly = - `#![feature]` may not be used on the {$release_channel} release channel - passes_feature_previously_declared = feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a026ff3b13b57..58d27d5b4bbaa 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1492,14 +1492,6 @@ pub struct TraitImplConstStable { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_feature_only_on_nightly, code = E0554)] -pub struct FeatureOnlyOnNightly { - #[primary_span] - pub span: Span, - pub release_channel: &'static str, -} - #[derive(Diagnostic)] #[diag(passes_unknown_feature, code = E0635)] pub struct UnknownFeature { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6bdfaf0c90897..2c34f477de5c5 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -936,12 +936,6 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let declared_lib_features = &tcx.features().declared_lib_features; let mut remaining_lib_features = FxIndexMap::default(); for (feature, span) in declared_lib_features { - if !tcx.sess.opts.unstable_features.is_nightly_build() { - tcx.dcx().emit_err(errors::FeatureOnlyOnNightly { - span: *span, - release_channel: env!("CFG_RELEASE_CHANNEL"), - }); - } if remaining_lib_features.contains_key(&feature) { // Warn if the user enables a lib feature multiple times. tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature }); diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index 0168b11c7394a..243f938bce2af 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -8,11 +8,15 @@ use crate::num::NonZero; /// Infinite iterators like `repeat()` are often used with adapters like /// [`Iterator::take()`], in order to make them finite. /// +/// Use [`str::repeat()`] instead of this function if you just want to repeat +/// a char/string `n`th times. +/// /// If the element type of the iterator you need does not implement `Clone`, /// or if you do not want to keep the repeated element in memory, you can /// instead use the [`repeat_with()`] function. /// /// [`repeat_with()`]: crate::iter::repeat_with +/// [`str::repeat()`]: ../../std/primitive.str.html#method.repeat /// /// # Examples /// diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs new file mode 100644 index 0000000000000..21e91c731b363 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs @@ -0,0 +1,24 @@ +#![feature(generic_const_exprs)] +//~^ WARN: the feature `generic_const_exprs` is incomplete + +// Regression test for #125770 which would ICE under the old effects desugaring that +// created a const generic parameter for constness on `Add`. + +use std::ops::Add; + +pub struct Dimension; + +pub struct Quantity(S); +//~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter + +impl Add for Quantity {} +//~^ ERROR: trait takes at most 1 generic argument +//~| ERROR: `Dimension` is forbidden as the type of a const generic parameter + +pub fn add(x: Quantity) -> Quantity { + //~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter + x + y + //~^ ERROR: cannot find value `y` in this scope +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr new file mode 100644 index 0000000000000..8c814295de465 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr @@ -0,0 +1,64 @@ +error[E0425]: cannot find value `y` in this scope + --> $DIR/mismatched_generic_args.rs:20:9 + | +LL | pub fn add(x: Quantity) -> Quantity { + | - similarly named const parameter `U` defined here +LL | +LL | x + y + | ^ help: a const parameter with a similar name exists: `U` + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/mismatched_generic_args.rs:1:12 + | +LL | #![feature(generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:11:33 + | +LL | pub struct Quantity(S); + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error[E0107]: trait takes at most 1 generic argument but 2 generic arguments were supplied + --> $DIR/mismatched_generic_args.rs:14:36 + | +LL | impl Add for Quantity {} + | ^^^ expected at most 1 generic argument + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:14:15 + | +LL | impl Add for Quantity {} + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error: `Dimension` is forbidden as the type of a const generic parameter + --> $DIR/mismatched_generic_args.rs:18:21 + | +LL | pub fn add(x: Quantity) -> Quantity { + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error: aborting due to 5 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0107, E0425. +For more information about an error, try `rustc --explain E0107`.