diff --git a/Cargo.lock b/Cargo.lock index c29c3158d4a1b..24cd5b825b265 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,7 +674,7 @@ checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ "serde", "termcolor", - "unicode-width 0.2.1", + "unicode-width 0.1.14", ] [[package]] @@ -1458,9 +1458,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "unicode-width 0.2.1", ] diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b5c0ca4727cda..63d0f400aefc4 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -85,7 +85,9 @@ use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; -use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{ + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode, +}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; @@ -233,8 +235,7 @@ fn missing_items_err( }; // Obtain the level of indentation ending in `sugg_sp`. - let padding = - tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new()); + let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new); let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) = (Vec::new(), Vec::new(), Vec::new()); @@ -331,6 +332,7 @@ fn default_body_is_unstable( fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl IntoIterator, Span)>, + assoc: ty::AssocItem, ) -> (String, String) { let mut types: FxIndexMap, Vec> = FxIndexMap::default(); let mut projections = vec![]; @@ -354,34 +356,50 @@ fn bounds_from_generic_predicates<'tcx>( } let mut where_clauses = vec![]; - let mut types_str = vec![]; - for (ty, bounds) in types { - if let ty::Param(_) = ty.kind() { - let mut bounds_str = vec![]; - for bound in bounds { - let mut projections_str = vec![]; - for projection in &projections { - let p = projection.skip_binder(); - if bound == tcx.parent(p.projection_term.def_id) - && p.projection_term.self_ty() == ty - { - let name = tcx.item_name(p.projection_term.def_id); - projections_str.push(format!("{} = {}", name, p.term)); + let generics = tcx.generics_of(assoc.def_id); + let types_str = generics + .own_params + .iter() + .filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. })) + .map(|p| { + // we just checked that it's a type, so the unwrap can't fail + let ty = tcx.mk_param_from_def(p).as_type().unwrap(); + if let Some(bounds) = types.get(&ty) { + let mut bounds_str = vec![]; + for bound in bounds.iter().copied() { + let mut projections_str = vec![]; + for projection in &projections { + let p = projection.skip_binder(); + if bound == tcx.parent(p.projection_term.def_id) + && p.projection_term.self_ty() == ty + { + let name = tcx.item_name(p.projection_term.def_id); + projections_str.push(format!("{} = {}", name, p.term)); + } + } + let bound_def_path = tcx.def_path_str(bound); + if projections_str.is_empty() { + where_clauses.push(format!("{}: {}", ty, bound_def_path)); + } else { + bounds_str.push(format!( + "{}<{}>", + bound_def_path, + projections_str.join(", ") + )); } } - let bound_def_path = tcx.def_path_str(bound); - if projections_str.is_empty() { - where_clauses.push(format!("{}: {}", ty, bound_def_path)); + if bounds_str.is_empty() { + ty.to_string() } else { - bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", "))); + format!("{}: {}", ty, bounds_str.join(" + ")) } - } - if bounds_str.is_empty() { - types_str.push(ty.to_string()); } else { - types_str.push(format!("{}: {}", ty, bounds_str.join(" + "))); + ty.to_string() } - } else { + }) + .collect::>(); + for (ty, bounds) in types.into_iter() { + if !matches!(ty.kind(), ty::Param(_)) { // Avoid suggesting the following: // fn foo::Bar>(_: T) where T: Trait, ::Bar: Other {} where_clauses.extend( @@ -473,10 +491,10 @@ fn fn_sig_suggestion<'tcx>( let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let safety = sig.safety.prefix_str(); - let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates, assoc); // FIXME: this is not entirely correct, as the lifetimes from borrowed params will - // not be present in the `fn` definition, not will we account for renamed + // not be present in the `fn` definition, nor will we account for renamed // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. @@ -512,6 +530,7 @@ fn suggestion_signature<'tcx>( let (generics, where_clauses) = bounds_from_generic_predicates( tcx, tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args), + assoc, ); format!("type {}{generics} = /* Type */{where_clauses};", assoc.name()) } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 77dd313d9b8eb..72cd75f6d8943 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -479,9 +479,6 @@ parse_invalid_identifier_with_leading_number = identifiers cannot start with a n parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` - .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases - .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access - .tuple_exception_line_3 = see issue #60210 for more information parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 797d4830c2ff2..00ca5acd84d51 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1017,10 +1017,6 @@ pub(crate) struct InvalidLiteralSuffixOnTupleIndex { #[label] pub span: Span, pub suffix: Symbol, - #[help(parse_tuple_exception_line_1)] - #[help(parse_tuple_exception_line_2)] - #[help(parse_tuple_exception_line_3)] - pub exception: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 4c02547357ef7..81a5d48d94e8c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1163,7 +1163,10 @@ impl<'a> Parser<'a> { suffix, }) => { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(current.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: current.span, + suffix, + }); } match self.break_up_float(symbol, current.span) { // 1e2 @@ -1239,7 +1242,8 @@ impl<'a> Parser<'a> { suffix: Option, ) -> Box { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(ident_span, suffix); + self.dcx() + .emit_err(errors::InvalidLiteralSuffixOnTupleIndex { span: ident_span, suffix }); } self.mk_expr(lo.to(ident_span), ExprKind::Field(base, Ident::new(field, ident_span))) } @@ -2225,24 +2229,6 @@ impl<'a> Parser<'a> { }) } - pub(super) fn expect_no_tuple_index_suffix(&self, span: Span, suffix: Symbol) { - if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) { - // #59553: warn instead of reject out of hand to allow the fix to percolate - // through the ecosystem when people fix their macros - self.dcx().emit_warn(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: true, - }); - } else { - self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { - span, - suffix, - exception: false, - }); - } - } - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, Box> { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3bbca622975c9..ed4069dae933c 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1335,7 +1335,10 @@ impl<'a> Parser<'a> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { if let Some(suffix) = suffix { - self.expect_no_tuple_index_suffix(self.token.span, suffix); + self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex { + span: self.token.span, + suffix, + }); } self.bump(); Ok(Ident::new(symbol, self.prev_token.span)) diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index dbbc0c217d7d4..8f8f019510fe8 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -1262,7 +1262,7 @@ impl, X: Cx> SearchGraph { encountered_overflow |= stack_entry.encountered_overflow; debug_assert_eq!(stack_entry.input, input); - // If the current goal is not the root of a cycle, we are done. + // If the current goal is not a cycle head, we are done. // // There are no provisional cache entries which depend on this goal. let Some(usages) = stack_entry.usages else { @@ -1278,7 +1278,7 @@ impl, X: Cx> SearchGraph { // // Check whether we reached a fixpoint, either because the final result // is equal to the provisional result of the previous iteration, or because - // this was only the root of either coinductive or inductive cycles, and the + // this was only the head of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. if self.reached_fixpoint(cx, &stack_entry, usages, result) { self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs index 3fd8e2bd16e4e..8348666be412d 100644 --- a/compiler/rustc_type_ir/src/search_graph/stack.rs +++ b/compiler/rustc_type_ir/src/search_graph/stack.rs @@ -13,7 +13,7 @@ rustc_index::newtype_index! { pub(super) struct StackDepth {} } -/// Stack entries of the evaluation stack. Its fields tend to be lazily +/// Stack entries of the evaluation stack. Its fields tend to be lazily updated /// when popping a child goal or completely immutable. #[derive_where(Debug; X: Cx)] pub(super) struct StackEntry { @@ -42,7 +42,7 @@ pub(super) struct StackEntry { /// Whether evaluating this goal encountered overflow. Lazily updated. pub encountered_overflow: bool, - /// Whether and how this goal has been used as the root of a cycle. Lazily updated. + /// Whether and how this goal has been used as a cycle head. Lazily updated. pub usages: Option, /// We want to be able to ignore head usages if they happen inside of candidates diff --git a/library/Cargo.lock b/library/Cargo.lock index e601137e00573..e4b3839847b1a 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -99,13 +99,12 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", - "unicode-width", ] [[package]] @@ -361,16 +360,6 @@ dependencies = [ "std", ] -[[package]] -name = "unicode-width" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" -dependencies = [ - "rustc-std-workspace-core", - "rustc-std-workspace-std", -] - [[package]] name = "unwind" version = "0.0.0" diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index c29d803b25e41..3acd067091415 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -193,13 +193,13 @@ fn test_atanh() { #[test] fn test_gamma() { // precision can differ between platforms - assert_approx_eq!(1.0f32.gamma(), 1.0f32); - assert_approx_eq!(2.0f32.gamma(), 1.0f32); - assert_approx_eq!(3.0f32.gamma(), 2.0f32); + assert_approx_eq!(1.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(2.0f32.gamma(), 1.0f32, APPROX_DELTA); + assert_approx_eq!(3.0f32.gamma(), 2.0f32, APPROX_DELTA); assert_approx_eq!(4.0f32.gamma(), 6.0f32, APPROX_DELTA); assert_approx_eq!(5.0f32.gamma(), 24.0f32, APPROX_DELTA); - assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt()); - assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt()); + assert_approx_eq!(0.5f32.gamma(), consts::PI.sqrt(), APPROX_DELTA); + assert_approx_eq!((-0.5f32).gamma(), -2.0 * consts::PI.sqrt(), APPROX_DELTA); assert_eq!(0.0f32.gamma(), f32::INFINITY); assert_eq!((-0.0f32).gamma(), f32::NEG_INFINITY); assert!((-1.0f32).gamma().is_nan()); diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 2a32a7dd76eed..fe749847b7c00 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -6,7 +6,7 @@ version = "0.0.0" edition = "2024" [dependencies] -getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } +getopts = { version = "0.2.24", default-features = false, features = ['rustc-dep-of-std'] } std = { path = "../std", public = true } core = { path = "../core", public = true } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index fee48bea144de..60347b2ea6456 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -477,7 +477,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "rustc-demangle", "rustc-literal-escaper", "shlex", - "unicode-width", "unwinding", "wasi", "windows-sys", diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index ee06707415f59..849dcb9e88fb1 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2021,7 +2021,6 @@ ui/parser/issues/issue-5806.rs ui/parser/issues/issue-58094-missing-right-square-bracket.rs ui/parser/issues/issue-58856-1.rs ui/parser/issues/issue-58856-2.rs -ui/parser/issues/issue-59418.rs ui/parser/issues/issue-60075.rs ui/parser/issues/issue-61858.rs ui/parser/issues/issue-62524.rs diff --git a/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs new file mode 100644 index 0000000000000..a5084b55aac79 --- /dev/null +++ b/tests/ui/parser/auxiliary/tuple-index-suffix-proc-macro-aux.rs @@ -0,0 +1,33 @@ +#![feature(proc_macro_quote, proc_macro_span)] + +extern crate proc_macro; + +use proc_macro::{Ident, Literal, Span, TokenStream, TokenTree, quote}; + +#[proc_macro] +pub fn bad_tup_indexing(input: TokenStream) -> TokenStream { + let tt = input.into_iter().next().unwrap(); + let TokenTree::Literal(indexing_expr) = tt else { + unreachable!(); + }; + quote! { (42,).$indexing_expr } +} + +// Expects {IDENT, COMMA, LITERAL} +#[proc_macro] +pub fn bad_tup_struct_indexing(input: TokenStream) -> TokenStream { + let mut input = input.into_iter(); + + let ident = input.next().unwrap(); + let _comma = input.next().unwrap(); + let lit = input.next().unwrap(); + + let TokenTree::Ident(ident) = ident else { + unreachable!("id"); + }; + let TokenTree::Literal(indexing_expr) = lit else { + unreachable!("lit"); + }; + + quote! { $ident.$indexing_expr } +} diff --git a/tests/ui/parser/issues/issue-59418.rs b/tests/ui/parser/issues/issue-59418.rs deleted file mode 100644 index 0fa191d4a7ef4..0000000000000 --- a/tests/ui/parser/issues/issue-59418.rs +++ /dev/null @@ -1,18 +0,0 @@ -struct X(i32,i32,i32); - -fn main() { - let a = X(1, 2, 3); - let b = a.1suffix; - //~^ ERROR suffixes on a tuple index are invalid - println!("{}", b); - let c = (1, 2, 3); - let d = c.1suffix; - //~^ ERROR suffixes on a tuple index are invalid - println!("{}", d); - let s = X { 0suffix: 0, 1: 1, 2: 2 }; - //~^ ERROR suffixes on a tuple index are invalid - match s { - X { 0suffix: _, .. } => {} - //~^ ERROR suffixes on a tuple index are invalid - } -} diff --git a/tests/ui/parser/issues/issue-59418.stderr b/tests/ui/parser/issues/issue-59418.stderr deleted file mode 100644 index 347051e9f921c..0000000000000 --- a/tests/ui/parser/issues/issue-59418.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:5:15 - | -LL | let b = a.1suffix; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:9:15 - | -LL | let d = c.1suffix; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:12:17 - | -LL | let s = X { 0suffix: 0, 1: 1, 2: 2 }; - | ^^^^^^^ invalid suffix `suffix` - -error: suffixes on a tuple index are invalid - --> $DIR/issue-59418.rs:15:13 - | -LL | X { 0suffix: _, .. } => {} - | ^^^^^^^ invalid suffix `suffix` - -error: aborting due to 4 previous errors - diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.rs b/tests/ui/parser/tuple-index-suffix-proc-macro.rs new file mode 100644 index 0000000000000..557c67738d30f --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.rs @@ -0,0 +1,32 @@ +//! See #59418. +//! +//! Like `tuple-index-suffix.rs`, but exercises the proc-macro interaction. + +//@ proc-macro: tuple-index-suffix-proc-macro-aux.rs + +extern crate tuple_index_suffix_proc_macro_aux; +use tuple_index_suffix_proc_macro_aux as aux; + +fn main() { + struct TupStruct(i32); + let tup_struct = TupStruct(42); + + // Previously, #60186 had carve outs for `{i,u}{32,usize}` as non-lint pseudo-FCW warnings. Now, + // they all hard error. + + aux::bad_tup_indexing!(0usize); + //~^ ERROR suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0isize); + //~^ ERROR suffixes on a tuple index are invalid + + // Not part of the #60186 carve outs. + + aux::bad_tup_indexing!(0u8); + //~^ ERROR suffixes on a tuple index are invalid + aux::bad_tup_struct_indexing!(tup_struct, 0u64); + //~^ ERROR suffixes on a tuple index are invalid + + // NOTE: didn't bother with trying to figure out how to generate `struct P { 0u32: u32 }` using + // *only* `proc_macro` without help with `syn`/`quote`, looks like you can't with just + // `proc_macro::quote`? +} diff --git a/tests/ui/parser/tuple-index-suffix-proc-macro.stderr b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr new file mode 100644 index 0000000000000..47d179d355513 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix-proc-macro.stderr @@ -0,0 +1,26 @@ +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:17:28 + | +LL | aux::bad_tup_indexing!(0usize); + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:19:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0isize); + | ^^^^^^ invalid suffix `isize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:24:28 + | +LL | aux::bad_tup_indexing!(0u8); + | ^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix-proc-macro.rs:26:47 + | +LL | aux::bad_tup_struct_indexing!(tup_struct, 0u64); + | ^^^^ invalid suffix `u64` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/tuple-index-suffix.rs b/tests/ui/parser/tuple-index-suffix.rs new file mode 100644 index 0000000000000..c476950000545 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix.rs @@ -0,0 +1,79 @@ +//! Regression test for both the original regression in #59418 where invalid suffixes in indexing +//! positions were accidentally accepted, and also for the removal of the temporary carve out that +//! mitigated ecosystem impact following trying to reject #59418 (this was implemented as a FCW +//! tracked in #60210). +//! +//! Check that we hard error on invalid suffixes in tuple indexing subexpressions and struct numeral +//! field names. + +struct X(i32,i32,i32); + +fn main() { + let tup_struct = X(1, 2, 3); + let invalid_tup_struct_suffix = tup_struct.0suffix; + //~^ ERROR suffixes on a tuple index are invalid + let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + //~^ ERROR suffixes on a tuple index are invalid + + let tup = (1, 2, 3); + let invalid_tup_suffix = tup.0suffix; + //~^ ERROR suffixes on a tuple index are invalid + let previous_carve_out_tup_suffix = tup.0u32; + //~^ ERROR suffixes on a tuple index are invalid + + numeral_struct_field_name_suffix_invalid(); + numeral_struct_field_name_suffix_previous_carve_out(); +} + +// Previously, there were very limited carve outs as a ecosystem impact mitigation implemented in +// #60186. *Only* `{i,u}{32,usize}` suffixes were temporarily accepted. Now, they all hard error. +fn previous_carve_outs() { + // Previously temporarily accepted by a pseudo-FCW (#60210), now hard error. + + let previous_carve_out_i32 = (42,).0i32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_i32 = (42,).0u32; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_isize = (42,).0isize; //~ ERROR suffixes on a tuple index are invalid + let previous_carve_out_usize = (42,).0usize; //~ ERROR suffixes on a tuple index are invalid + + // Not part of the carve outs! + let error_i8 = (42,).0i8; //~ ERROR suffixes on a tuple index are invalid + let error_u8 = (42,).0u8; //~ ERROR suffixes on a tuple index are invalid + let error_i16 = (42,).0i16; //~ ERROR suffixes on a tuple index are invalid + let error_u16 = (42,).0u16; //~ ERROR suffixes on a tuple index are invalid + let error_i64 = (42,).0i64; //~ ERROR suffixes on a tuple index are invalid + let error_u64 = (42,).0u64; //~ ERROR suffixes on a tuple index are invalid + let error_i128 = (42,).0i128; //~ ERROR suffixes on a tuple index are invalid + let error_u128 = (42,).0u128; //~ ERROR suffixes on a tuple index are invalid +} + +fn numeral_struct_field_name_suffix_invalid() { + let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match invalid_struct_name { + X { 0suffix: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } +} + +fn numeral_struct_field_name_suffix_previous_carve_out() { + let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + //~^ ERROR suffixes on a tuple index are invalid + match carve_out_struct_name { + X { 0u32: _, .. } => {} + //~^ ERROR suffixes on a tuple index are invalid + } +} + +// Unfortunately, it turns out `std::mem::offset_of!` uses the same expect suffix code path. +fn offset_of_suffix() { + #[repr(C)] + pub struct Struct(u8, T); + + // Previous pseudo-FCW carve outs + assert_eq!(std::mem::offset_of!(Struct, 0usize), 0); + //~^ ERROR suffixes on a tuple index are invalid + + // Not part of carve outs + assert_eq!(std::mem::offset_of!(Struct, 0u8), 0); + //~^ ERROR suffixes on a tuple index are invalid +} diff --git a/tests/ui/parser/tuple-index-suffix.stderr b/tests/ui/parser/tuple-index-suffix.stderr new file mode 100644 index 0000000000000..6d96c6d3cbf88 --- /dev/null +++ b/tests/ui/parser/tuple-index-suffix.stderr @@ -0,0 +1,134 @@ +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:13:48 + | +LL | let invalid_tup_struct_suffix = tup_struct.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:15:59 + | +LL | let previous_carve_out_tup_struct_suffix = tup_struct.0i32; + | ^^^^ invalid suffix `i32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:19:34 + | +LL | let invalid_tup_suffix = tup.0suffix; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:21:45 + | +LL | let previous_carve_out_tup_suffix = tup.0u32; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:33:40 + | +LL | let previous_carve_out_i32 = (42,).0i32; + | ^^^^ invalid suffix `i32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:34:40 + | +LL | let previous_carve_out_i32 = (42,).0u32; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:35:42 + | +LL | let previous_carve_out_isize = (42,).0isize; + | ^^^^^^ invalid suffix `isize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:36:42 + | +LL | let previous_carve_out_usize = (42,).0usize; + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:39:26 + | +LL | let error_i8 = (42,).0i8; + | ^^^ invalid suffix `i8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:40:26 + | +LL | let error_u8 = (42,).0u8; + | ^^^ invalid suffix `u8` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:41:27 + | +LL | let error_i16 = (42,).0i16; + | ^^^^ invalid suffix `i16` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:42:27 + | +LL | let error_u16 = (42,).0u16; + | ^^^^ invalid suffix `u16` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:43:27 + | +LL | let error_i64 = (42,).0i64; + | ^^^^ invalid suffix `i64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:44:27 + | +LL | let error_u64 = (42,).0u64; + | ^^^^ invalid suffix `u64` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:45:28 + | +LL | let error_i128 = (42,).0i128; + | ^^^^^ invalid suffix `i128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:46:28 + | +LL | let error_u128 = (42,).0u128; + | ^^^^^ invalid suffix `u128` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:50:35 + | +LL | let invalid_struct_name = X { 0suffix: 0, 1: 1, 2: 2 }; + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:53:13 + | +LL | X { 0suffix: _, .. } => {} + | ^^^^^^^ invalid suffix `suffix` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:59:37 + | +LL | let carve_out_struct_name = X { 0u32: 0, 1: 1, 2: 2 }; + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:62:13 + | +LL | X { 0u32: _, .. } => {} + | ^^^^ invalid suffix `u32` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:73:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct, 0usize), 0); + | ^^^^^^ invalid suffix `usize` + +error: suffixes on a tuple index are invalid + --> $DIR/tuple-index-suffix.rs:77:50 + | +LL | assert_eq!(std::mem::offset_of!(Struct, 0u8), 0); + | ^^^ invalid suffix `u8` + +error: aborting due to 22 previous errors + diff --git a/tests/ui/suggestions/apitit-unimplemented-method.rs b/tests/ui/suggestions/apitit-unimplemented-method.rs new file mode 100644 index 0000000000000..b182e1939b3e3 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.rs @@ -0,0 +1,12 @@ +//@ aux-build:dep.rs + +extern crate dep; +use dep::*; + +struct Local; +impl Trait for Local {} +//~^ ERROR not all trait items implemented +//~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }` +//~| HELP implement the missing item: `fn bar(_: impl Sized) { todo!() }` + +fn main() {} diff --git a/tests/ui/suggestions/apitit-unimplemented-method.stderr b/tests/ui/suggestions/apitit-unimplemented-method.stderr new file mode 100644 index 0000000000000..b309a64e95829 --- /dev/null +++ b/tests/ui/suggestions/apitit-unimplemented-method.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar` + --> $DIR/apitit-unimplemented-method.rs:7:1 + | +LL | impl Trait for Local {} + | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + | + = help: implement the missing item: `fn foo(_: impl Sized) { todo!() }` + = help: implement the missing item: `fn bar(_: impl Sized) { todo!() }` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/suggestions/auxiliary/dep.rs b/tests/ui/suggestions/auxiliary/dep.rs new file mode 100644 index 0000000000000..ac0de418313c0 --- /dev/null +++ b/tests/ui/suggestions/auxiliary/dep.rs @@ -0,0 +1,4 @@ +pub trait Trait { + fn foo(_: impl Sized); + fn bar(_: impl Sized); +} diff --git a/triagebot.toml b/triagebot.toml index bf9bfee4306d0..2d58c616bc278 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1308,21 +1308,32 @@ cc = ["@m-ou-se"] [mentions."compiler/rustc_ast_lowering/src/format.rs"] cc = ["@m-ou-se"] +# Content-based mentions + [mentions."#[miri::intrinsic_fallback_is_spec]"] type = "content" message = """ -`#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, +⚠️ `#[miri::intrinsic_fallback_is_spec]` must only be used if the function actively checks for all UB cases, and explores the possible non-determinism of the intrinsic. """ cc = ["@rust-lang/miri"] + [mentions."#[rustc_allow_const_fn_unstable"] type = "content" message = """ -`#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable +⚠️ `#[rustc_allow_const_fn_unstable]` needs careful audit to avoid accidentally exposing unstable implementation details on stable. """ cc = ["@rust-lang/wg-const-eval"] +[mentions."#[rustc_intrinsic_const_stable_indirect]"] +type = "content" +message = """ +⚠️ `#[rustc_intrinsic_const_stable_indirect]` controls whether intrinsics can be exposed to stable const +code; adding it needs t-lang approval. +""" +cc = ["@rust-lang/wg-const-eval"] + # ------------------------------------------------------------------------------ # PR assignments