diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 10776f31c07bf..13259b30d2180 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -645,6 +645,7 @@ impl Pat { // These patterns do not contain subpatterns, skip. PatKind::Wild | PatKind::Rest + | PatKind::Never | PatKind::Lit(_) | PatKind::Range(..) | PatKind::Ident(..) @@ -795,6 +796,9 @@ pub enum PatKind { /// only one rest pattern may occur in the pattern sequences. Rest, + // A never pattern `!` + Never, + /// Parentheses in patterns used for grouping (i.e., `(PAT)`). Paren(P), @@ -2236,6 +2240,18 @@ pub enum InlineAsmOperand { }, } +impl InlineAsmOperand { + pub fn reg(&self) -> Option<&InlineAsmRegOrRegClass> { + match self { + Self::In { reg, .. } + | Self::Out { reg, .. } + | Self::InOut { reg, .. } + | Self::SplitInOut { reg, .. } => Some(reg), + Self::Const { .. } | Self::Sym { .. } => None, + } + } +} + /// Inline assembly. /// /// E.g., `asm!("NOP");`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 541b987292240..8ce86bf9ecf52 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1249,7 +1249,7 @@ pub fn noop_visit_pat(pat: &mut P, vis: &mut T) { let Pat { id, kind, span, tokens } = pat.deref_mut(); vis.visit_id(id); match kind { - PatKind::Wild | PatKind::Rest => {} + PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1caa39e2dd999..9dbadcb49d3fc 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -559,7 +559,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Wild | PatKind::Rest => {} + PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { walk_list!(visitor, visit_pat, elems); } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 951bf41d9d769..6ac6fe7ebc950 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -354,10 +354,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let idx2 = *o.get(); let (ref op2, op_sp2) = operands[idx2]; - let Some(asm::InlineAsmRegOrRegClass::Reg(reg2)) = op2.reg() - else { - unreachable!(); - }; let in_out = match (op, op2) { ( @@ -375,11 +371,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { _ => None, }; + let reg_str = |idx| -> &str { + // HIR asm doesn't preserve the original alias string of the explicit register, + // so we have to retrieve it from AST + let (op, _): &(InlineAsmOperand, Span) = &asm.operands[idx]; + if let Some(ast::InlineAsmRegOrRegClass::Reg(reg_sym)) = + op.reg() + { + reg_sym.as_str() + } else { + unreachable!(); + } + }; + sess.emit_err(RegisterConflict { op_span1: op_sp, op_span2: op_sp2, - reg1_name: reg.name(), - reg2_name: reg2.name(), + reg1_name: reg_str(idx), + reg2_name: reg_str(idx2), in_out, }); } diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index a30f264bc7dc7..ce7fe5f371def 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -24,6 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let node = loop { match &pattern.kind { PatKind::Wild => break hir::PatKind::Wild, + PatKind::Never => break hir::PatKind::Never, PatKind::Ident(binding_mode, ident, sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s)); break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 8fb7c7de50c6d..8851fbd28f078 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -555,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); + gate_all!(never_patterns, "`!` patterns are experimental"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 86aba343bc476..cbdcc683b566d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1343,6 +1343,7 @@ impl<'a> State<'a> { is that it doesn't matter */ match &pat.kind { PatKind::Wild => self.word("_"), + PatKind::Never => self.word("!"), PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => { if *by_ref == ByRef::Yes { self.word_nbsp("ref"); diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e34661d5fc6da..bffc284816615 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -147,7 +147,7 @@ macro_rules! declare_features { // was set. // // Note that the features are grouped into internal/user-facing and then -// sorted by version inside those groups. This is enforced with tidy. +// sorted alphabetically inside those groups. This is enforced with tidy. // // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. @@ -512,6 +512,8 @@ declare_features! ( (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), /// Allow negative trait implementations. (unstable, negative_impls, "1.44.0", Some(68318), None), + /// Allows the `!` pattern. + (incomplete, never_patterns, "CURRENT_RUSTC_VERSION", Some(118155), None), /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. (unstable, never_type, "1.13.0", Some(35121), None), /// Allows diverging expressions to fall back to `!` rather than `()`. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d2b83d0eb00fa..9581f6cb040da 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1002,7 +1002,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true, + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true, Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), @@ -1029,7 +1029,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {} + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {} Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), @@ -1142,6 +1142,9 @@ pub enum PatKind<'hir> { /// Invariant: `pats.len() >= 2`. Or(&'hir [Pat<'hir>]), + /// A never pattern `!`. + Never, + /// A path pattern for a unit struct/variant or a (maybe-associated) constant. Path(QPath<'hir>), diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8a67285598998..963b324ca1339 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -660,7 +660,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Wild => (), + PatKind::Never | PatKind::Wild => (), PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, slice_pattern); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index b9a4806e6c25c..358660491d409 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1181,10 +1181,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(bound_span) = bound_span { err.span_label( bound_span, - format!( - "ambiguous `{assoc_name}` from `{}`", - bound.print_only_trait_path(), - ), + format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),), ); if let Some(constraint) = &is_equality { where_bounds.push(format!( diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 78c5809f8b4f9..c53d79d105c31 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -106,6 +106,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait here instead: `trait NewTrait: {} {{}}`", regular_traits .iter() + // FIXME: This should `print_sugared`, but also needs to integrate projection bounds... .map(|t| t.trait_ref().print_only_trait_path().to_string()) .collect::>() .join(" + "), diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 9557568b38702..37b308f9f88d3 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -662,6 +662,7 @@ fn resolve_local<'tcx>( PatKind::Ref(_, _) | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..) | PatKind::Wild + | PatKind::Never | PatKind::Path(_) | PatKind::Lit(_) | PatKind::Range(_, _, _) => false, diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 6b18b0ebe9d1a..4a4c287b4b610 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -23,7 +23,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.def_span(def_id), E0199, "implementing the trait `{}` is not unsafe", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() ) .span_suggestion_verbose( item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), @@ -40,13 +40,13 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.def_span(def_id), E0200, "the trait `{}` requires an `unsafe impl` declaration", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() ) .note(format!( "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() )) .span_suggestion_verbose( item.span.shrink_to_lo(), @@ -69,7 +69,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() )) .span_suggestion_verbose( item.span.shrink_to_lo(), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e9e8c7fd4fc25..b7e7d258a9047 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1724,6 +1724,7 @@ impl<'a> State<'a> { // is that it doesn't matter match pat.kind { PatKind::Wild => self.word("_"), + PatKind::Never => self.word("!"), PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => { if by_ref == ByRef::Yes { self.word_nbsp("ref"); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index d7cf6dba9aac6..9991050d7b2d1 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -401,12 +401,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { mc.cat_pattern(discr_place.clone(), pat, |place, pat| { match &pat.kind { PatKind::Binding(.., opt_sub_pat) => { - // If the opt_sub_pat is None, than the binding does not count as + // If the opt_sub_pat is None, then the binding does not count as // a wildcard for the purpose of borrowing discr. if opt_sub_pat.is_none() { needs_to_be_read = true; } } + PatKind::Never => { + // A never pattern reads the value. + // FIXME(never_patterns): does this do what I expect? + needs_to_be_read = true; + } PatKind::Path(qpath) => { // A `Path` pattern is just a name like `Foo`. This is either a // named constant or else it refers to an ADT variant diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 94da4bfcdc491..0bcb7c7b5d75d 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -766,6 +766,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | PatKind::Binding(.., None) | PatKind::Lit(..) | PatKind::Range(..) + | PatKind::Never | PatKind::Wild => { // always ok } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a7764f4ff965b..93ca3ed912876 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2288,7 +2288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) if def.did().is_local() => { spans.push_span_label( self.tcx.def_span(def.did()), - format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), + format!("must implement `{}`", pred.trait_ref.print_trait_sugared()), ); } _ => {} @@ -2299,7 +2299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = if preds.len() == 1 { format!( "an implementation of `{}` might be missing for `{}`", - preds[0].trait_ref.print_only_trait_path(), + preds[0].trait_ref.print_trait_sugared(), preds[0].self_ty() ) } else { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f11ffabf4d4d4..1ecf553d71d3b 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -178,6 +178,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match pat.kind { PatKind::Wild => expected, + // FIXME(never_patterns): check the type is uninhabited. If that is not possible within + // typeck, do that in a later phase. + PatKind::Never => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), PatKind::Binding(ba, var_id, _, sub) => { @@ -287,9 +290,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Box(_) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::Peel, + // A never pattern behaves somewhat like a literal or unit variant. + PatKind::Never => AdjustMode::Peel, // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. - // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. + // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. // // Call `resolve_vars_if_possible` here for inline const blocks. PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { @@ -743,6 +748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Slice(..) => "binding", PatKind::Wild + | PatKind::Never | PatKind::Binding(..) | PatKind::Path(..) | PatKind::Box(..) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index bf9edb5b83d6d..bceea9177ddbd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2221,8 +2221,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { - expected: exp_found.expected.print_only_trait_path(), - found: exp_found.found.print_only_trait_path(), + expected: exp_found.expected.print_trait_sugared(), + found: exp_found.found.print_trait_sugared(), }; match self.expected_found_str(pretty_exp_found) { Some((expected, found, _, _)) if expected == found => { @@ -2233,8 +2233,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { - expected: exp_found.expected.print_only_trait_path(), - found: exp_found.found.print_only_trait_path(), + expected: exp_found.expected.print_trait_sugared(), + found: exp_found.found.print_trait_sugared(), }; match self.expected_found_str(pretty_exp_found) { Some((expected, found, _, _)) if expected == found => { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index b4535c72d6c6f..b0ccffcecc463 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -1154,7 +1154,7 @@ impl EarlyLintPass for UnusedParens { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) // The other cases do not contain sub-patterns. - | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, + | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, // These are list-like patterns; parens can always be removed. TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false, keep_space); diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index ab8fef5129b5d..98642adc19090 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -27,7 +27,7 @@ pub enum UnsafetyViolationKind { UnsafeFn, } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationDetails { CallToUnsafeFunction, UseOfInlineAssembly, @@ -39,10 +39,17 @@ pub enum UnsafetyViolationDetails { AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, - CallToFunctionWith, + CallToFunctionWith { + /// Target features enabled in callee's `#[target_feature]` but missing in + /// caller's `#[target_feature]`. + missing: Vec, + /// Target features in `missing` that are enabled at compile time + /// (e.g., with `-C target-feature`). + build_enabled: Vec, + }, } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub struct UnsafetyViolation { pub source_info: SourceInfo, pub lint_root: hir::HirId, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 00c33113692d0..c48428c713c44 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -635,7 +635,12 @@ impl<'tcx> Pat<'tcx> { use PatKind::*; match &self.kind { - Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} + Wild + | Never + | Range(..) + | Binding { subpattern: None, .. } + | Constant { .. } + | Error(_) => {} AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } @@ -809,6 +814,9 @@ pub enum PatKind<'tcx> { pats: Box<[Box>]>, }, + /// A never pattern `!`. + Never, + /// An error has been encountered during lowering. We probably shouldn't report more lints /// related to this pattern. Error(ErrorGuaranteed), @@ -1069,6 +1077,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { match self.kind { PatKind::Wild => write!(f, "_"), + PatKind::Never => write!(f, "!"), PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"), PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { let is_mut = match mode { diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 62c3ceeab8abf..4943c11848b8a 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -227,7 +227,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' is_primary: _, name: _, } => visitor.visit_pat(subpattern), - Binding { .. } | Wild | Error(_) => {} + Binding { .. } | Wild | Never | Error(_) => {} Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => { for subpattern in subpatterns { visitor.visit_pat(&subpattern.pattern); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d50743bc2075f..80667c3c7d75b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2640,6 +2640,23 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { } } +/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only +/// the trait path, and additionally tries to "sugar" `Fn(...)` trait bounds. +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>); + +impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintSugared<'tcx> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + +impl<'tcx> fmt::Debug for TraitRefPrintSugared<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait name. That is, it will print `Trait` instead of /// `>`. @@ -2657,6 +2674,10 @@ impl<'tcx> ty::TraitRef<'tcx> { TraitRefPrintOnlyTraitPath(self) } + pub fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> { + TraitRefPrintSugared(self) + } + pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { TraitRefPrintOnlyTraitName(self) } @@ -2666,6 +2687,10 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> { self.map_bound(|tr| tr.print_only_trait_path()) } + + pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> { + self.map_bound(|tr| tr.print_trait_sugared()) + } } #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] @@ -2745,6 +2770,7 @@ forward_display_to_print! { ty::PolyExistentialTraitRef<'tcx>, ty::Binder<'tcx, ty::TraitRef<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>, @@ -2844,6 +2870,24 @@ define_print_and_forward_display! { p!(print_def_path(self.0.def_id, self.0.args)); } + TraitRefPrintSugared<'tcx> { + if !with_no_queries() + && let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id) + && let ty::Tuple(args) = self.0.args.type_at(1).kind() + { + p!(write("{}", kind.as_str()), "("); + for (i, arg) in args.iter().enumerate() { + if i > 0 { + p!(", "); + } + p!(print(arg)); + } + p!(")"); + } else { + p!(print_def_path(self.0.def_id, self.0.args)); + } + } + TraitRefPrintOnlyTraitName<'tcx> { p!(print_def_path(self.0.def_id, &[])); } @@ -2892,7 +2936,7 @@ define_print_and_forward_display! { if let ty::ImplPolarity::Negative = self.polarity { p!("!"); } - p!(print(self.trait_ref.print_only_trait_path())) + p!(print(self.trait_ref.print_trait_sugared())) } ty::ProjectionPredicate<'tcx> { diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 7dd0e7d4b928b..c8d6c2114e9eb 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -30,12 +30,32 @@ mir_build_borrow_of_moved_value = borrow of moved value mir_build_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block - .note = can only be called if the required target features are available + .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + .note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` .label = call to function with `#[target_feature]` mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block - .note = can only be called if the required target features are available + .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + .note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` .label = call to function with `#[target_feature]` mir_build_call_to_unsafe_fn_requires_unsafe = @@ -330,7 +350,17 @@ mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_uns mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) - .note = can only be called if the required target features are available + .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + .note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` .label = call to function with `#[target_feature]` mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe = diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 83686667a4aea..90f950d59d551 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -827,6 +827,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild + | PatKind::Never | PatKind::Error(_) => {} PatKind::Deref { ref subpattern } => { diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 8a6cb26242a1f..a7f6f4873e383 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -194,6 +194,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } + PatKind::Never => { + // A never pattern acts like a load from the place. + // FIXME(never_patterns): load from the place + Ok(()) + } + PatKind::Constant { .. } => { // FIXME normalize patterns when possible Err(match_pair) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 6bd60972c8baa..2e7182f261eca 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -75,6 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Array { .. } | PatKind::Wild | PatKind::Binding { .. } + | PatKind::Never | PatKind::Leaf { .. } | PatKind::Deref { .. } | PatKind::Error(_) => self.error_simplifiable(match_pair), @@ -107,6 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Slice { .. } | PatKind::Array { .. } | PatKind::Wild + | PatKind::Never | PatKind::Or { .. } | PatKind::Binding { .. } | PatKind::AscribeUserType { .. } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index bbaa02233e571..c17fdf71b55a0 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,7 +1,10 @@ +use std::borrow::Cow; + use crate::build::ExprCategory; use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; +use rustc_errors::DiagnosticArgValue; use rustc_hir as hir; use rustc_middle::mir::BorrowKind; use rustc_middle::thir::*; @@ -247,8 +250,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.requires_unsafe(pat.span, AccessToUnionField); return; // we can return here since this already requires unsafe } - // wildcard doesn't take anything + // wildcard/never don't take anything PatKind::Wild | + PatKind::Never | // these just wrap other patterns PatKind::Or { .. } | PatKind::InlineConstant { .. } | @@ -392,15 +396,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { // the call requires `unsafe`. Don't check this on wasm // targets, though. For more information on wasm see the // is_like_wasm check in hir_analysis/src/collect.rs + let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; if !self.tcx.sess.target.options.is_like_wasm - && !self - .tcx - .codegen_fn_attrs(func_did) - .target_features + && !callee_features .iter() .all(|feature| self.body_target_features.contains(feature)) { - self.requires_unsafe(expr.span, CallToFunctionWith(func_did)); + let missing: Vec<_> = callee_features + .iter() + .copied() + .filter(|feature| !self.body_target_features.contains(feature)) + .collect(); + let build_enabled = self + .tcx + .sess + .target_features + .iter() + .copied() + .filter(|feature| missing.contains(feature)) + .collect(); + self.requires_unsafe( + expr.span, + CallToFunctionWith { function: func_did, missing, build_enabled }, + ); } } } @@ -526,7 +544,7 @@ struct UnusedUnsafeWarning { enclosing_unsafe: Option, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, PartialEq)] enum UnsafeOpKind { CallToUnsafeFunction(Option), UseOfInlineAssembly, @@ -537,7 +555,15 @@ enum UnsafeOpKind { AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, - CallToFunctionWith(DefId), + CallToFunctionWith { + function: DefId, + /// Target features enabled in callee's `#[target_feature]` but missing in + /// caller's `#[target_feature]`. + missing: Vec, + /// Target features in `missing` that are enabled at compile time + /// (e.g., with `-C target-feature`). + build_enabled: Vec, + }, } use UnsafeOpKind::*; @@ -658,13 +684,22 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - CallToFunctionWith(did) => tcx.emit_spanned_lint( + CallToFunctionWith { function, missing, build_enabled } => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { span, - function: &with_no_trimmed_paths!(tcx.def_path_str(*did)), + function: &with_no_trimmed_paths!(tcx.def_path_str(*function)), + missing_target_features: DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + missing_target_features_count: missing.len(), + note: if build_enabled.is_empty() { None } else { Some(()) }, + build_target_features: DiagnosticArgValue::StrListSepByAnd( + build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, }, ), @@ -821,18 +856,38 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }); } - CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => { + CallToFunctionWith { function, missing, build_enabled } + if unsafe_op_in_unsafe_fn_allowed => + { tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span, + missing_target_features: DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + missing_target_features_count: missing.len(), + note: if build_enabled.is_empty() { None } else { Some(()) }, + build_target_features: DiagnosticArgValue::StrListSepByAnd( + build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, - function: &tcx.def_path_str(*did), + function: &tcx.def_path_str(*function), }); } - CallToFunctionWith(did) => { + CallToFunctionWith { function, missing, build_enabled } => { tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe { span, + missing_target_features: DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + missing_target_features_count: missing.len(), + note: if build_enabled.is_empty() { None } else { Some(()) }, + build_target_features: DiagnosticArgValue::StrListSepByAnd( + build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, - function: &tcx.def_path_str(*did), + function: &tcx.def_path_str(*function), }); } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 418f9bb9de94d..8d2a559e73ce4 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,6 +2,7 @@ use crate::{ fluent_generated as fluent, thir::pattern::{deconstruct_pat::WitnessPat, MatchCheckCtxt}, }; +use rustc_errors::DiagnosticArgValue; use rustc_errors::{ error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage, @@ -124,11 +125,17 @@ pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)] -#[note] +#[help] pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { #[label] pub span: Span, pub function: &'a str, + pub missing_target_features: DiagnosticArgValue<'a>, + pub missing_target_features_count: usize, + #[note] + pub note: Option<()>, + pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } @@ -369,24 +376,36 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed #[derive(Diagnostic)] #[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")] -#[note] +#[help] pub struct CallToFunctionWithRequiresUnsafe<'a> { #[primary_span] #[label] pub span: Span, pub function: &'a str, + pub missing_target_features: DiagnosticArgValue<'a>, + pub missing_target_features_count: usize, + #[note] + pub note: Option<()>, + pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } #[derive(Diagnostic)] #[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] -#[note] +#[help] pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[primary_span] #[label] pub span: Span, pub function: &'a str, + pub missing_target_features: DiagnosticArgValue<'a>, + pub missing_target_features_count: usize, + #[note] + pub note: Option<()>, + pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 8ddc6c924e2a5..31114190f07e8 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1557,6 +1557,12 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let pats = expand_or_pat(pat); fields = Fields::from_iter(cx, pats.into_iter().map(mkpat)); } + PatKind::Never => { + // FIXME(never_patterns): handle `!` in exhaustiveness. This is a sane default + // in the meantime. + ctor = Wildcard; + fields = Fields::empty(); + } PatKind::Error(_) => { ctor = Opaque(OpaqueId::new()); fields = Fields::empty(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8b2a96cff41db..5edb2054fd4ed 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -251,6 +251,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let kind = match pat.kind { hir::PatKind::Wild => PatKind::Wild, + hir::PatKind::Never => PatKind::Never, + hir::PatKind::Lit(value) => self.lower_lit(value), hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index e449928a64357..547da7e700794 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -642,6 +642,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { PatKind::Wild => { print_indented!(self, "Wild", depth_lvl + 1); } + PatKind::Never => { + print_indented!(self, "Never", depth_lvl + 1); + } PatKind::AscribeUserType { ascription, subpattern } => { print_indented!(self, "AscribeUserType: {", depth_lvl + 1); print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 5a99afc45b020..b8dbdf18db3ea 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -42,8 +42,19 @@ mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in } .not_inherited = items do not inherit unsafety from separate enclosing items +mir_transform_target_feature_call_help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + mir_transform_target_feature_call_label = call to function with `#[target_feature]` -mir_transform_target_feature_call_note = can only be called if the required target features are available +mir_transform_target_feature_call_note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index c63b24b194fc2..84e7362c3d0bd 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -287,19 +287,20 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { .safety; match safety { // `unsafe` blocks are required in safe code - Safety::Safe => violations.into_iter().for_each(|&violation| { + Safety::Safe => violations.into_iter().for_each(|violation| { match violation.kind { UnsafetyViolationKind::General => {} UnsafetyViolationKind::UnsafeFn => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } } - if !self.violations.contains(&violation) { - self.violations.push(violation) + if !self.violations.contains(violation) { + self.violations.push(violation.clone()) } }), // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s - Safety::FnUnsafe => violations.into_iter().for_each(|&(mut violation)| { + Safety::FnUnsafe => violations.into_iter().for_each(|violation| { + let mut violation = violation.clone(); violation.kind = UnsafetyViolationKind::UnsafeFn; if !self.violations.contains(&violation) { self.violations.push(violation) @@ -367,9 +368,22 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { // Is `callee_features` a subset of `calling_features`? if !callee_features.iter().all(|feature| self_features.contains(feature)) { + let missing: Vec<_> = callee_features + .iter() + .copied() + .filter(|feature| !self_features.contains(feature)) + .collect(); + let build_enabled = self + .tcx + .sess + .target_features + .iter() + .copied() + .filter(|feature| missing.contains(feature)) + .collect(); self.require_unsafe( UnsafetyViolationKind::General, - UnsafetyViolationDetails::CallToFunctionWith, + UnsafetyViolationDetails::CallToFunctionWith { missing, build_enabled }, ) } } @@ -528,8 +542,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { // Only suggest wrapping the entire function body in an unsafe block once let mut suggest_unsafe_block = true; - for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() { - let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span }; + for &UnsafetyViolation { source_info, lint_root, kind, ref details } in violations.iter() { + let details = + errors::RequiresUnsafeDetail { violation: details.clone(), span: source_info.span }; match kind { UnsafetyViolationKind::General => { diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 5879a803946d6..3a5270f105ae4 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -1,6 +1,8 @@ +use std::borrow::Cow; + use rustc_errors::{ - Applicability, DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler, - IntoDiagnostic, + Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, + EmissionGuarantee, Handler, IntoDiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; @@ -9,6 +11,8 @@ use rustc_session::lint::{self, Lint}; use rustc_span::def_id::DefId; use rustc_span::Span; +use crate::fluent_generated as fluent; + #[derive(LintDiagnostic)] pub(crate) enum ConstMutate { #[diag(mir_transform_const_modify)] @@ -61,72 +65,105 @@ pub(crate) struct RequiresUnsafe { impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe { #[track_caller] fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> { - let mut diag = - handler.struct_diagnostic(crate::fluent_generated::mir_transform_requires_unsafe); + let mut diag = handler.struct_diagnostic(fluent::mir_transform_requires_unsafe); diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string())); diag.set_span(self.span); diag.span_label(self.span, self.details.label()); - diag.note(self.details.note()); let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter()); diag.set_arg("details", desc); diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed); + self.details.add_subdiagnostics(&mut diag); if let Some(sp) = self.enclosing { - diag.span_label(sp, crate::fluent_generated::mir_transform_not_inherited); + diag.span_label(sp, fluent::mir_transform_not_inherited); } diag } } -#[derive(Copy, Clone)] +#[derive(Clone)] pub(crate) struct RequiresUnsafeDetail { pub span: Span, pub violation: UnsafetyViolationDetails, } impl RequiresUnsafeDetail { - fn note(self) -> DiagnosticMessage { + fn add_subdiagnostics(&self, diag: &mut DiagnosticBuilder<'_, G>) { use UnsafetyViolationDetails::*; match self.violation { - CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_note, - UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_note, + CallToUnsafeFunction => { + diag.note(fluent::mir_transform_call_to_unsafe_note); + } + UseOfInlineAssembly => { + diag.note(fluent::mir_transform_use_of_asm_note); + } InitializingTypeWith => { - crate::fluent_generated::mir_transform_initializing_valid_range_note + diag.note(fluent::mir_transform_initializing_valid_range_note); + } + CastOfPointerToInt => { + diag.note(fluent::mir_transform_const_ptr2int_note); + } + UseOfMutableStatic => { + diag.note(fluent::mir_transform_use_of_static_mut_note); + } + UseOfExternStatic => { + diag.note(fluent::mir_transform_use_of_extern_static_note); + } + DerefOfRawPointer => { + diag.note(fluent::mir_transform_deref_ptr_note); + } + AccessToUnionField => { + diag.note(fluent::mir_transform_union_access_note); } - CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_note, - UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_note, - UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_note, - DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_note, - AccessToUnionField => crate::fluent_generated::mir_transform_union_access_note, MutationOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_note + diag.note(fluent::mir_transform_mutation_layout_constrained_note); } BorrowOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_note + diag.note(fluent::mir_transform_mutation_layout_constrained_borrow_note); + } + CallToFunctionWith { ref missing, ref build_enabled } => { + diag.help(fluent::mir_transform_target_feature_call_help); + diag.set_arg( + "missing_target_features", + DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + ); + diag.set_arg("missing_target_features_count", missing.len()); + if !build_enabled.is_empty() { + diag.note(fluent::mir_transform_target_feature_call_note); + diag.set_arg( + "build_target_features", + DiagnosticArgValue::StrListSepByAnd( + build_enabled + .iter() + .map(|feature| Cow::from(feature.as_str())) + .collect(), + ), + ); + diag.set_arg("build_target_features_count", build_enabled.len()); + } } - CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_note, } } - fn label(self) -> DiagnosticMessage { + fn label(&self) -> DiagnosticMessage { use UnsafetyViolationDetails::*; match self.violation { - CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_label, - UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_label, - InitializingTypeWith => { - crate::fluent_generated::mir_transform_initializing_valid_range_label - } - CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_label, - UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_label, - UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_label, - DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_label, - AccessToUnionField => crate::fluent_generated::mir_transform_union_access_label, + CallToUnsafeFunction => fluent::mir_transform_call_to_unsafe_label, + UseOfInlineAssembly => fluent::mir_transform_use_of_asm_label, + InitializingTypeWith => fluent::mir_transform_initializing_valid_range_label, + CastOfPointerToInt => fluent::mir_transform_const_ptr2int_label, + UseOfMutableStatic => fluent::mir_transform_use_of_static_mut_label, + UseOfExternStatic => fluent::mir_transform_use_of_extern_static_label, + DerefOfRawPointer => fluent::mir_transform_deref_ptr_label, + AccessToUnionField => fluent::mir_transform_union_access_label, MutationOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_label + fluent::mir_transform_mutation_layout_constrained_label } BorrowOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_label + fluent::mir_transform_mutation_layout_constrained_borrow_label } - CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_label, + CallToFunctionWith { .. } => fluent::mir_transform_target_feature_call_label, } } } @@ -151,12 +188,12 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter()); diag.set_arg("details", desc); diag.span_label(self.details.span, self.details.label()); - diag.note(self.details.note()); + self.details.add_subdiagnostics(diag); if let Some((start, end, fn_sig)) = self.suggest_unsafe_block { - diag.span_note(fn_sig, crate::fluent_generated::mir_transform_note); + diag.span_note(fn_sig, fluent::mir_transform_note); diag.tool_only_multipart_suggestion( - crate::fluent_generated::mir_transform_suggestion, + fluent::mir_transform_suggestion, vec![(start, " unsafe {".into()), (end, "}".into())], Applicability::MaybeIncorrect, ); @@ -166,7 +203,7 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { } fn msg(&self) -> DiagnosticMessage { - crate::fluent_generated::mir_transform_unsafe_op_in_unsafe_fn + fluent::mir_transform_unsafe_op_in_unsafe_fn } } @@ -193,12 +230,8 @@ impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint

{ fn msg(&self) -> DiagnosticMessage { match self { - AssertLint::ArithmeticOverflow(..) => { - crate::fluent_generated::mir_transform_arithmetic_overflow - } - AssertLint::UnconditionalPanic(..) => { - crate::fluent_generated::mir_transform_operation_will_panic - } + AssertLint::ArithmeticOverflow(..) => fluent::mir_transform_arithmetic_overflow, + AssertLint::UnconditionalPanic(..) => fluent::mir_transform_operation_will_panic, } } } @@ -255,11 +288,11 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> { self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { - diag.span_label(self.yield_sp, crate::fluent_generated::_subdiag::label); + diag.span_label(self.yield_sp, fluent::_subdiag::label); if let Some(reason) = self.reason { diag.subdiagnostic(reason); } - diag.span_help(self.src_sp, crate::fluent_generated::_subdiag::help); + diag.span_help(self.src_sp, fluent::_subdiag::help); diag.set_arg("pre", self.pre); diag.set_arg("def_path", self.tcx.def_path_str(self.def_id)); diag.set_arg("post", self.post); @@ -267,7 +300,7 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> { } fn msg(&self) -> rustc_errors::DiagnosticMessage { - crate::fluent_generated::mir_transform_must_not_suspend + fluent::mir_transform_must_not_suspend } } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 83bbfeb280593..eadd2892d93ec 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -492,9 +492,13 @@ parse_match_arm_body_without_braces = `match` arm body without braces } with a body .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression +parse_maybe_comparison = you might have meant to compare for equality + parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` .suggestion = replace `fn` with `impl` here +parse_maybe_missing_let = you might have meant to continue the let-chain + parse_maybe_recover_from_bad_qpath_stage_2 = missing angle brackets in associated item path .suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 0a919240ce51c..e5d4cb6f4da27 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -415,6 +415,32 @@ pub(crate) struct ExpectedExpressionFoundLet { pub span: Span, #[subdiagnostic] pub reason: ForbiddenLetReason, + #[subdiagnostic] + pub missing_let: Option, + #[subdiagnostic] + pub comparison: Option, +} + +#[derive(Subdiagnostic, Clone, Copy)] +#[multipart_suggestion( + parse_maybe_missing_let, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct MaybeMissingLet { + #[suggestion_part(code = "let ")] + pub span: Span, +} + +#[derive(Subdiagnostic, Clone, Copy)] +#[multipart_suggestion( + parse_maybe_comparison, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct MaybeComparison { + #[suggestion_part(code = "=")] + pub span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 79567eb389868..e334837c1d41f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength use super::diagnostics::SnapshotParser; use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; @@ -2477,7 +2478,7 @@ impl<'a> Parser<'a> { let mut cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?; - CondChecker { parser: self, forbid_let_reason: None }.visit_expr(&mut cond); + CondChecker::new(self).visit_expr(&mut cond); if let ExprKind::Let(_, _, _, None) = cond.kind { // Remove the last feature gating of a `let` expression since it's stable. @@ -2493,6 +2494,8 @@ impl<'a> Parser<'a> { let err = errors::ExpectedExpressionFoundLet { span: self.token.span, reason: ForbiddenLetReason::OtherForbidden, + missing_let: None, + comparison: None, }; if self.prev_token.kind == token::BinOp(token::Or) { // This was part of a closure, the that part of the parser recover. @@ -2876,7 +2879,7 @@ impl<'a> Parser<'a> { let if_span = this.prev_token.span; let mut cond = this.parse_match_guard_condition()?; - CondChecker { parser: this, forbid_let_reason: None }.visit_expr(&mut cond); + CondChecker::new(this).visit_expr(&mut cond); let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond); if has_let_expr { @@ -3552,6 +3555,14 @@ pub(crate) enum ForbiddenLetReason { struct CondChecker<'a> { parser: &'a Parser<'a>, forbid_let_reason: Option, + missing_let: Option, + comparison: Option, +} + +impl<'a> CondChecker<'a> { + fn new(parser: &'a Parser<'a>) -> Self { + CondChecker { parser, forbid_let_reason: None, missing_let: None, comparison: None } + } } impl MutVisitor for CondChecker<'_> { @@ -3562,11 +3573,13 @@ impl MutVisitor for CondChecker<'_> { match e.kind { ExprKind::Let(_, _, _, ref mut is_recovered @ None) => { if let Some(reason) = self.forbid_let_reason { - *is_recovered = Some( - self.parser - .sess - .emit_err(errors::ExpectedExpressionFoundLet { span, reason }), - ); + *is_recovered = + Some(self.parser.sess.emit_err(errors::ExpectedExpressionFoundLet { + span, + reason, + missing_let: self.missing_let, + comparison: self.comparison, + })); } else { self.parser.sess.gated_spans.gate(sym::let_chains, span); } @@ -3590,9 +3603,28 @@ impl MutVisitor for CondChecker<'_> { noop_visit_expr(e, self); self.forbid_let_reason = forbid_let_reason; } + ExprKind::Assign(ref lhs, _, span) => { + let forbid_let_reason = self.forbid_let_reason; + self.forbid_let_reason = Some(OtherForbidden); + let missing_let = self.missing_let; + if let ExprKind::Binary(_, _, rhs) = &lhs.kind + && let ExprKind::Path(_, _) + | ExprKind::Struct(_) + | ExprKind::Call(_, _) + | ExprKind::Array(_) = rhs.kind + { + self.missing_let = + Some(errors::MaybeMissingLet { span: rhs.span.shrink_to_lo() }); + } + let comparison = self.comparison; + self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() }); + noop_visit_expr(e, self); + self.forbid_let_reason = forbid_let_reason; + self.missing_let = missing_let; + self.comparison = comparison; + } ExprKind::Unary(_, _) | ExprKind::Await(_, _) - | ExprKind::Assign(_, _, _) | ExprKind::AssignOp(_, _, _) | ExprKind::Range(_, _, _) | ExprKind::Try(_) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8f5f4459d640a..b05868e235af6 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -368,8 +368,12 @@ impl<'a> Parser<'a> { self.recover_dotdotdot_rest_pat(lo) } else if let Some(form) = self.parse_range_end() { self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`. + } else if self.eat(&token::Not) { + // Parse `!` + self.sess.gated_spans.gate(sym::never_patterns, self.prev_token.span); + PatKind::Never } else if self.eat_keyword(kw::Underscore) { - // Parse _ + // Parse `_` PatKind::Wild } else if self.eat_keyword(kw::Mut) { self.parse_pat_ident_mut(syntax_loc)? diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index f915c1057d6c4..28354ab0986e1 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -286,7 +286,21 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_pat(&mut self, p: &'v hir::Pat<'v>) { record_variants!( (self, p, p.kind, Id::Node(p.hir_id), hir, Pat, PatKind), - [Wild, Binding, Struct, TupleStruct, Or, Path, Tuple, Box, Ref, Lit, Range, Slice] + [ + Wild, + Binding, + Struct, + TupleStruct, + Or, + Never, + Path, + Tuple, + Box, + Ref, + Lit, + Range, + Slice + ] ); hir_visit::walk_pat(self, p) } @@ -554,6 +568,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Range, Slice, Rest, + Never, Paren, MacCall ] diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 40b0387424221..9a2fe01229ddb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1097,6 +1097,7 @@ symbols! { negative_impls, neon, never, + never_patterns, never_type, never_type_fallback, new, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8e97333ad0f3e..8e2ec2e46b24a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -245,7 +245,7 @@ fn overlap<'tcx>( let trait_ref = infcx.resolve_vars_if_possible(trait_ref); format!( "of `{}` for `{}`", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), trait_ref.self_ty() ) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index feeeaa51f81d4..0a4813ae673dc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -184,14 +184,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { flags.push((sym::cause, Some("MainFunctionType".to_string()))); } - if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id) - && let ty::Tuple(args) = trait_ref.args.type_at(1).kind() - { - let args = args.iter().map(|ty| ty.to_string()).collect::>().join(", "); - flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str())))); - } else { - flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string()))); - } + flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string()))); // Add all types without trimmed paths or visible paths, ensuring they end up with // their "canonical" def path. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index b28bff1ca2a7a..6c5c6a05a0d5a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -622,7 +622,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.shrink_to_hi(), format!( "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", - cand.print_only_trait_path(), + cand.print_trait_sugared(), cand.self_ty(), ), format!(" as {}", cand.self_ty()), @@ -1785,7 +1785,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), }); err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (" implemented for `".to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), @@ -1821,7 +1821,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => (" implemented for `", ""), }; err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (desc.to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), @@ -1854,7 +1854,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; err.help(format!( "the following {other}types implement trait `{}`:{}{}", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), candidates[..end].join(""), if candidates.len() > 9 { format!("\nand {} others", candidates.len() - 8) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 0c884b7c16a82..1d852f3bc327e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -78,7 +78,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> { IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => { format!( "downstream crates may implement trait `{trait_desc}`{self_desc}", - trait_desc = trait_ref.print_only_trait_path(), + trait_desc = trait_ref.print_trait_sugared(), self_desc = if let Some(self_ty) = self_ty { format!(" for type `{self_ty}`") } else { @@ -90,7 +90,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> { format!( "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ in future versions", - trait_desc = trait_ref.print_only_trait_path(), + trait_desc = trait_ref.print_trait_sugared(), self_desc = if let Some(self_ty) = self_ty { format!(" for type `{self_ty}`") } else { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 73ba03a361012..72dc644a42a84 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -412,7 +412,7 @@ fn report_conflicting_impls<'tcx>( let msg = DelayDm(|| { format!( "conflicting implementations of trait `{}`{}{}", - overlap.trait_ref.print_only_trait_path(), + overlap.trait_ref.print_trait_sugared(), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), match used_to_be_allowed { Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)", diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 36685f756d08e..c8a0eb4ffc269 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1644,6 +1644,24 @@ impl *const [T] { metadata(self) } + /// Returns `true` if the raw slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_len)] + /// use std::ptr; + /// + /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3); + /// assert!(!slice.is_empty()); + /// ``` + #[inline(always)] + #[unstable(feature = "slice_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + pub const fn is_empty(self) -> bool { + self.len() == 0 + } + /// Returns a raw pointer to the slice's buffer. /// /// This is equivalent to casting `self` to `*const T`, but more type-safe. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index bc362fb627f2b..ce0e6d6f29720 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1920,10 +1920,10 @@ impl *mut [T] { /// /// ``` /// #![feature(slice_ptr_len)] + /// use std::ptr; /// - /// let mut a = [1, 2, 3]; - /// let ptr = &mut a as *mut [_]; - /// assert!(!ptr.is_empty()); + /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); + /// assert!(!slice.is_empty()); /// ``` #[inline(always)] #[unstable(feature = "slice_ptr_len", issue = "71146")] diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c22ad43e04994..82f4a38384dd1 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { debug!("trying to get a name from pattern: {p:?}"); Symbol::intern(&match p.kind { - PatKind::Wild | PatKind::Struct(..) => return kw::Underscore, + // FIXME(never_patterns): does this make sense? + PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore, PatKind::Binding(_, _, ident, _) => return ident.name, PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Or(pats) => { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 575fead5bf3e4..630df9a84f582 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -46,7 +46,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { pats.iter().all(unary_pattern) } match &pat.kind { - PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => { + PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Never | PatKind::Or(_) => { false }, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index ded90f5f9110d..f1f0329b3304c 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { db.note(format!( "`{}` doesn't implement `{}`", trait_pred.self_ty(), - trait_pred.trait_ref.print_only_trait_path(), + trait_pred.trait_ref.print_trait_sugared(), )); } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 745be671b86d7..cbf478620ec33 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -150,6 +150,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { #[derive(Clone, Copy)] enum NormalizedPat<'a> { Wild, + Never, Struct(Option, &'a [(Symbol, Self)]), Tuple(Option, &'a [Self]), Or(&'a [Self]), @@ -229,6 +230,7 @@ impl<'a> NormalizedPat<'a> { PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => { Self::from_pat(cx, arena, pat) }, + PatKind::Never => Self::Never, PatKind::Struct(ref path, fields, _) => { let fields = arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat)))); @@ -333,6 +335,7 @@ impl<'a> NormalizedPat<'a> { fn has_overlapping_values(&self, other: &Self) -> bool { match (*self, *other) { (Self::Wild, _) | (_, Self::Wild) => true, + (Self::Never, Self::Never) => true, (Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => { pats.iter().any(|pat| pat.has_overlapping_values(other)) }, diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 8ff088a208f21..952c0dc72b19b 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec>, focus_idx: us // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, // which we would want to join with other `C(p_j)`s. - Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) + Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_) // Skip immutable refs, as grouping them saves few characters, // and almost always requires adding parens (increasing noisiness). // In the case of only two patterns, replacement adds net characters. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e8842ce10f8aa..e83c04eda2077 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -629,6 +629,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match pat.value.kind { PatKind::Wild => kind!("Wild"), + PatKind::Never => kind!("Never"), PatKind::Binding(ann, _, name, sub) => { bind!(self, name); opt_bind!(self, sub); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 8031e6faa7458..34ec83709ffd5 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1017,6 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, + PatKind::Never => {}, PatKind::Wild => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 172b063df3159..fd37713fc6055 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1707,6 +1707,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild => false, + PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Lit(..) | PatKind::Range(..) => true, diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 33f3b4b8a21a5..8504999b8ff51 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -40,7 +40,9 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool { fn is_short_pattern_inner(pat: &ast::Pat) -> bool { match pat.kind { - ast::PatKind::Rest | ast::PatKind::Wild | ast::PatKind::Lit(_) => true, + ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => { + true + } ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -193,6 +195,7 @@ impl Rewrite for Pat { None } } + PatKind::Never => None, PatKind::Range(ref lhs, ref rhs, ref end_kind) => { let infix = match end_kind.node { RangeEnd::Included(RangeSyntax::DotDotDot) => "...", diff --git a/tests/ui/asm/aarch64/bad-reg.rs b/tests/ui/asm/aarch64/bad-reg.rs index 9ccb8ed676269..f71418161f297 100644 --- a/tests/ui/asm/aarch64/bad-reg.rs +++ b/tests/ui/asm/aarch64/bad-reg.rs @@ -48,14 +48,14 @@ fn main() { // (except in/lateout which don't conflict) asm!("", in("x0") foo, in("w0") bar); - //~^ ERROR register `x0` conflicts with register `x0` + //~^ ERROR register `w0` conflicts with register `x0` asm!("", in("x0") foo, out("x0") bar); //~^ ERROR register `x0` conflicts with register `x0` asm!("", in("w0") foo, lateout("w0") bar); asm!("", in("v0") foo, in("q0") bar); - //~^ ERROR register `v0` conflicts with register `v0` + //~^ ERROR register `q0` conflicts with register `v0` asm!("", in("v0") foo, out("q0") bar); - //~^ ERROR register `v0` conflicts with register `v0` + //~^ ERROR register `q0` conflicts with register `v0` asm!("", in("v0") foo, lateout("q0") bar); } } diff --git a/tests/ui/asm/aarch64/bad-reg.stderr b/tests/ui/asm/aarch64/bad-reg.stderr index 0ba627dac309f..717a788caf67d 100644 --- a/tests/ui/asm/aarch64/bad-reg.stderr +++ b/tests/ui/asm/aarch64/bad-reg.stderr @@ -98,11 +98,11 @@ error: register class `preg` can only be used as a clobber, not as an input or o LL | asm!("{}", out(preg) _); | ^^^^^^^^^^^ -error: register `x0` conflicts with register `x0` +error: register `w0` conflicts with register `x0` --> $DIR/bad-reg.rs:50:32 | LL | asm!("", in("x0") foo, in("w0") bar); - | ------------ ^^^^^^^^^^^^ register `x0` + | ------------ ^^^^^^^^^^^^ register `w0` | | | register `x0` @@ -120,19 +120,19 @@ help: use `lateout` instead of `out` to avoid conflict LL | asm!("", in("x0") foo, out("x0") bar); | ^^^^^^^^^^^^ -error: register `v0` conflicts with register `v0` +error: register `q0` conflicts with register `v0` --> $DIR/bad-reg.rs:55:32 | LL | asm!("", in("v0") foo, in("q0") bar); - | ------------ ^^^^^^^^^^^^ register `v0` + | ------------ ^^^^^^^^^^^^ register `q0` | | | register `v0` -error: register `v0` conflicts with register `v0` +error: register `q0` conflicts with register `v0` --> $DIR/bad-reg.rs:57:32 | LL | asm!("", in("v0") foo, out("q0") bar); - | ------------ ^^^^^^^^^^^^^ register `v0` + | ------------ ^^^^^^^^^^^^^ register `q0` | | | register `v0` | diff --git a/tests/ui/asm/x86_64/bad-reg.rs b/tests/ui/asm/x86_64/bad-reg.rs index f5728079a6a56..e19221bc04e5f 100644 --- a/tests/ui/asm/x86_64/bad-reg.rs +++ b/tests/ui/asm/x86_64/bad-reg.rs @@ -56,10 +56,10 @@ fn main() { // (except in/lateout which don't conflict) asm!("", in("eax") foo, in("al") bar); - //~^ ERROR register `al` conflicts with register `ax` + //~^ ERROR register `al` conflicts with register `eax` //~| ERROR `i32` cannot be used with this register class asm!("", in("rax") foo, out("rax") bar); - //~^ ERROR register `ax` conflicts with register `ax` + //~^ ERROR register `rax` conflicts with register `rax` asm!("", in("al") foo, lateout("al") bar); //~^ ERROR `i32` cannot be used with this register class //~| ERROR `i32` cannot be used with this register class diff --git a/tests/ui/asm/x86_64/bad-reg.stderr b/tests/ui/asm/x86_64/bad-reg.stderr index 82b7ebd0fb07a..8017008e97d75 100644 --- a/tests/ui/asm/x86_64/bad-reg.stderr +++ b/tests/ui/asm/x86_64/bad-reg.stderr @@ -106,21 +106,21 @@ error: register class `mmx_reg` can only be used as a clobber, not as an input o LL | asm!("{}", out(mmx_reg) _); | ^^^^^^^^^^^^^^ -error: register `al` conflicts with register `ax` +error: register `al` conflicts with register `eax` --> $DIR/bad-reg.rs:58:33 | LL | asm!("", in("eax") foo, in("al") bar); | ------------- ^^^^^^^^^^^^ register `al` | | - | register `ax` + | register `eax` -error: register `ax` conflicts with register `ax` +error: register `rax` conflicts with register `rax` --> $DIR/bad-reg.rs:61:33 | LL | asm!("", in("rax") foo, out("rax") bar); - | ------------- ^^^^^^^^^^^^^^ register `ax` + | ------------- ^^^^^^^^^^^^^^ register `rax` | | - | register `ax` + | register `rax` | help: use `lateout` instead of `out` to avoid conflict --> $DIR/bad-reg.rs:61:18 diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr index 0a069e8d35063..d27fade487fe2 100644 --- a/tests/ui/error-codes/E0401.stderr +++ b/tests/ui/error-codes/E0401.stderr @@ -55,7 +55,7 @@ error[E0283]: type annotations needed LL | bfnr(x); | ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr` | - = note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`: + = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - impl Fn for &F where A: Tuple, F: Fn, F: ?Sized; - impl Fn for Box diff --git a/tests/ui/expr/if/bad-if-let-suggestion.rs b/tests/ui/expr/if/bad-if-let-suggestion.rs index 99d584ac7a5d5..b0d0676e1ea75 100644 --- a/tests/ui/expr/if/bad-if-let-suggestion.rs +++ b/tests/ui/expr/if/bad-if-let-suggestion.rs @@ -1,6 +1,3 @@ -// FIXME(compiler-errors): This really should suggest `let` on the RHS of the -// `&&` operator, but that's kinda hard to do because of precedence. -// Instead, for now we just make sure not to suggest `if let let`. fn a() { if let x = 1 && i = 2 {} //~^ ERROR cannot find value `i` in this scope diff --git a/tests/ui/expr/if/bad-if-let-suggestion.stderr b/tests/ui/expr/if/bad-if-let-suggestion.stderr index 20ac9ca76ba9b..0d1f895bd82bf 100644 --- a/tests/ui/expr/if/bad-if-let-suggestion.stderr +++ b/tests/ui/expr/if/bad-if-let-suggestion.stderr @@ -1,19 +1,27 @@ error: expected expression, found `let` statement - --> $DIR/bad-if-let-suggestion.rs:5:8 + --> $DIR/bad-if-let-suggestion.rs:2:8 | LL | if let x = 1 && i = 2 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to continue the let-chain + | +LL | if let x = 1 && let i = 2 {} + | +++ +help: you might have meant to compare for equality + | +LL | if let x = 1 && i == 2 {} + | + error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:5:21 + --> $DIR/bad-if-let-suggestion.rs:2:21 | LL | if let x = 1 && i = 2 {} | ^ not found in this scope error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:12:9 + --> $DIR/bad-if-let-suggestion.rs:9:9 | LL | fn a() { | ------ similarly named function `a` defined here @@ -22,7 +30,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `j` in this scope - --> $DIR/bad-if-let-suggestion.rs:12:13 + --> $DIR/bad-if-let-suggestion.rs:9:13 | LL | fn a() { | ------ similarly named function `a` defined here @@ -31,7 +39,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:12:18 + --> $DIR/bad-if-let-suggestion.rs:9:18 | LL | fn a() { | ------ similarly named function `a` defined here @@ -40,7 +48,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `x` in this scope - --> $DIR/bad-if-let-suggestion.rs:19:8 + --> $DIR/bad-if-let-suggestion.rs:16:8 | LL | fn a() { | ------ similarly named function `a` defined here @@ -49,7 +57,7 @@ LL | if x[0] = 1 {} | ^ help: a function with a similar name exists: `a` error[E0308]: mismatched types - --> $DIR/bad-if-let-suggestion.rs:5:8 + --> $DIR/bad-if-let-suggestion.rs:2:8 | LL | if let x = 1 && i = 2 {} | ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.rs b/tests/ui/feature-gates/feature-gate-never_patterns.rs new file mode 100644 index 0000000000000..69e9f62abf054 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-never_patterns.rs @@ -0,0 +1,27 @@ +// Check that never patterns require the feature gate. +use std::ptr::NonNull; + +enum Void {} + +fn main() { + let res: Result = Ok(0); + let (Ok(_x) | Err(&!)) = res.as_ref(); + //~^ ERROR `!` patterns are experimental + //~| ERROR: is not bound in all patterns + + unsafe { + let ptr: *const Void = NonNull::dangling().as_ptr(); + match *ptr { + ! => {} //~ ERROR `!` patterns are experimental + } + } + + // Check that the gate operates even behind `cfg`. + #[cfg(FALSE)] + unsafe { + let ptr: *const Void = NonNull::dangling().as_ptr(); + match *ptr { + ! => {} //~ ERROR `!` patterns are experimental + } + } +} diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.stderr b/tests/ui/feature-gates/feature-gate-never_patterns.stderr new file mode 100644 index 0000000000000..b7290eeb36dfe --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-never_patterns.stderr @@ -0,0 +1,39 @@ +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/feature-gate-never_patterns.rs:8:19 + | +LL | let (Ok(_x) | Err(&!)) = res.as_ref(); + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:8:24 + | +LL | let (Ok(_x) | Err(&!)) = res.as_ref(); + | ^ + | + = note: see issue #118155 for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:15:13 + | +LL | ! => {} + | ^ + | + = note: see issue #118155 for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:24:13 + | +LL | ! => {} + | ^ + | + = note: see issue #118155 for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0408, E0658. +For more information about an error, try `rustc --explain E0408`. diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index 4ef96cd954106..1cf364aa9f6a1 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` - found trait `for<'a> FnOnce<(&'a &str,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)` + found trait `for<'a> FnOnce(&'a &str)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -23,8 +23,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` - found trait `for<'a> FnOnce<(&'a &str,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)` + found trait `for<'a> FnOnce(&'a &str)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -42,8 +42,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` - found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)` + found trait `for<'a> FnOnce(&'a Wrapper<'_>)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | @@ -61,8 +61,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` - found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)` + found trait `for<'a> FnOnce(&'a Wrapper<'_>)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index 54ecd35ed6acd..f1fa5a5986060 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `for<'a> FnOnce(&u32, &'a u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | @@ -27,8 +27,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `for<'a> FnOnce(&u32, &'a u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `FnOnce<(&u32, &u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `FnOnce(&u32, &u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | @@ -69,8 +69,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `FnOnce<(&u32, &u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `FnOnce(&u32, &u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 75fd87b3fe9b3..86a4ac4132e44 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -31,8 +31,8 @@ error[E0308]: mismatched types LL | take_foo(|a| a); | ^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a i32,)>` - found trait `Fn<(&i32,)>` + = note: expected trait `for<'a> Fn(&'a i32)` + found trait `Fn(&i32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187-2.rs:8:14 | diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index 209f2b7b7398a..14bdfe75c08be 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a u32,)>` - found trait `FnOnce<(&u32,)>` + = note: expected trait `for<'a> FnOnce(&'a u32)` + found trait `FnOnce(&u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187.rs:4:13 | diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr index dbc587dd004a4..677f918fe932e 100644 --- a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr +++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr @@ -18,8 +18,8 @@ error[E0308]: mismatched types LL | f(data, identity) | ^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a T,)>` - found trait `Fn<(&T,)>` + = note: expected trait `for<'a> Fn(&'a T)` + found trait `Fn(&T)` note: the lifetime requirement is introduced here --> $DIR/issue_74400.rs:8:34 | diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 70ca00285c49d..c0eb7f01fdbf0 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -11,6 +11,7 @@ #![feature(decl_macro)] #![feature(explicit_tail_calls)] #![feature(more_qualified_paths)] +#![feature(never_patterns)] #![feature(raw_ref_op)] #![feature(trait_alias)] #![feature(try_blocks)] @@ -635,6 +636,10 @@ fn test_pat() { // PatKind::Rest c1!(pat, [ .. ], ".."); + // PatKind::Never + c1!(pat, [ Some(!) ], "Some(!)"); + c1!(pat, [ None | Some(!) ], "None | Some(!)"); + // PatKind::Paren c1!(pat, [ (pat) ], "(pat)"); diff --git a/tests/ui/mismatched_types/closure-mismatch.stderr b/tests/ui/mismatched_types/closure-mismatch.stderr index c5b8270ba84d5..74033c1857377 100644 --- a/tests/ui/mismatched_types/closure-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.stderr @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | baz(|_| ()); | ^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a (),)>` - found trait `Fn<(&(),)>` + = note: expected trait `for<'a> Fn(&'a ())` + found trait `Fn(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:8:9 | @@ -45,8 +45,8 @@ error[E0308]: mismatched types LL | baz(|x| ()); | ^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a (),)>` - found trait `Fn<(&(),)>` + = note: expected trait `for<'a> Fn(&'a ())` + found trait `Fn(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:11:9 | diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index 988eee61027bc..a616d29c4fea6 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | accept(callback); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a (),)>` - found trait `FnOnce<(&(),)>` + = note: expected trait `for<'a> FnOnce(&'a ())` + found trait `FnOnce(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/missing-universe-cause-issue-114907.rs:32:20 | @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | accept(callback); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a (),)>` - found trait `FnOnce<(&(),)>` + = note: expected trait `for<'a> FnOnce(&'a ())` + found trait `FnOnce(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/missing-universe-cause-issue-114907.rs:32:20 | diff --git a/tests/ui/pattern/never_patterns.rs b/tests/ui/pattern/never_patterns.rs new file mode 100644 index 0000000000000..e2e17e0e9a74e --- /dev/null +++ b/tests/ui/pattern/never_patterns.rs @@ -0,0 +1,99 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn main() {} + +// The classic use for empty types. +fn safe_unwrap_result(res: Result) { + let Ok(_x) = res; + // FIXME(never_patterns): These should be allowed + let (Ok(_x) | Err(!)) = &res; + //~^ ERROR: is not bound in all patterns + let (Ok(_x) | Err(&!)) = res.as_ref(); + //~^ ERROR: is not bound in all patterns +} + +// Check we only accept `!` where we want to. +fn never_pattern_location(void: Void) { + // FIXME(never_patterns): Don't accept on a non-empty type. + match Some(0) { + None => {} + Some(!) => {} + } + // FIXME(never_patterns): Don't accept on an arbitrary type, even if there are no more branches. + match () { + () => {} + ! => {} + } + // FIXME(never_patterns): Don't accept even on an empty branch. + match None:: { + None => {} + ! => {} + } + // FIXME(never_patterns): Let alone if the emptiness is behind a reference. + match None::<&Void> { + None => {} + ! => {} + } + // Participate in match ergonomics. + match &void { + ! => {} + } + match &&void { + ! => {} + } + match &&void { + &! => {} + } + match &None:: { + None => {} + Some(!) => {} + } + match None::<&Void> { + None => {} + Some(!) => {} + } + // Accept on a composite empty type. + match None::<&(u32, Void)> { + None => {} + Some(&!) => {} + } + // Accept on an simple empty type. + match None:: { + None => {} + Some(!) => {} + } + match None::<&Void> { + None => {} + Some(&!) => {} + } + match None::<&(u32, Void)> { + None => {} + Some(&(_, !)) => {} + } +} + +fn never_and_bindings() { + let x: Result = Ok(false); + + // FIXME(never_patterns): Never patterns in or-patterns don't need to share the same bindings. + match x { + Ok(_x) | Err(&!) => {} + //~^ ERROR: is not bound in all patterns + } + let (Ok(_x) | Err(&!)) = x; + //~^ ERROR: is not bound in all patterns + + // FIXME(never_patterns): A never pattern mustn't have bindings. + match x { + Ok(_) => {} + Err(&(_b, !)) => {} + } + match x { + Ok(_a) | Err(&(_b, !)) => {} + //~^ ERROR: is not bound in all patterns + //~| ERROR: is not bound in all patterns + } +} diff --git a/tests/ui/pattern/never_patterns.stderr b/tests/ui/pattern/never_patterns.stderr new file mode 100644 index 0000000000000..11e50debfd39a --- /dev/null +++ b/tests/ui/pattern/never_patterns.stderr @@ -0,0 +1,51 @@ +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:12:19 + | +LL | let (Ok(_x) | Err(!)) = &res; + | -- ^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:14:19 + | +LL | let (Ok(_x) | Err(&!)) = res.as_ref(); + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:83:18 + | +LL | Ok(_x) | Err(&!) => {} + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:86:19 + | +LL | let (Ok(_x) | Err(&!)) = x; + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_b` is not bound in all patterns + --> $DIR/never_patterns.rs:95:9 + | +LL | Ok(_a) | Err(&(_b, !)) => {} + | ^^^^^^ -- variable not in all patterns + | | + | pattern doesn't bind `_b` + +error[E0408]: variable `_a` is not bound in all patterns + --> $DIR/never_patterns.rs:95:18 + | +LL | Ok(_a) | Err(&(_b, !)) => {} + | -- ^^^^^^^^^^^^^ pattern doesn't bind `_a` + | | + | variable not in all patterns + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0408`. diff --git a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr index 5f8c5dbe61938..52c700c326e30 100644 --- a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found trait `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)` + found trait `Fn(&Foo<'_>)` error[E0308]: mismatched types --> $DIR/rfc1623-2.rs:28:8 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found trait `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)` + found trait `Fn(&Foo<'_>)` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `FnOnce` is not general enough diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr index 0ef7b8b09f11f..cabc475fa61cf 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr @@ -1,83 +1,115 @@ error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:23:5 + --> $DIR/safe-calls.rs:28:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:26:5 + --> $DIR/safe-calls.rs:31:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:34:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:36:5 + --> $DIR/safe-calls.rs:41:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:39:5 + --> $DIR/safe-calls.rs:44:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:46:5 + --> $DIR/safe-calls.rs:51:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:49:5 + --> $DIR/safe-calls.rs:54:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:52:5 + --> $DIR/safe-calls.rs:57:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:60:5 + --> $DIR/safe-calls.rs:65:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:65:18 + --> $DIR/safe-calls.rs:70:15 | -LL | const name: () = sse2(); - | ^^^^^^ call to function with `#[target_feature]` +LL | const _: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` -error: aborting due to 10 previous errors +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:74:15 + | +LL | const _: () = sse2_and_fxsr(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr + = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]` + +error: call to function with `#[target_feature]` is unsafe and requires unsafe block (error E0133) + --> $DIR/safe-calls.rs:82:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/safe-calls.rs:81:1 + | +LL | unsafe fn needs_unsafe_block() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/safe-calls.rs:78:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index cebc6f9478404..f17dab269bc4b 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -7,6 +7,11 @@ #[target_feature(enable = "sse2")] const fn sse2() {} +#[target_feature(enable = "sse2")] +#[target_feature(enable = "fxsr")] +const fn sse2_and_fxsr() {} + + #[target_feature(enable = "avx")] #[target_feature(enable = "bmi2")] fn avx_bmi2() {} @@ -62,8 +67,21 @@ fn qux() { //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe } -const name: () = sse2(); +const _: () = sse2(); //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe +const _: () = sse2_and_fxsr(); +//[mir]~^ ERROR call to function with `#[target_feature]` is unsafe +//[thir]~^^ ERROR call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe + +#[deny(unsafe_op_in_unsafe_fn)] +#[target_feature(enable = "avx")] +#[target_feature(enable = "bmi2")] +unsafe fn needs_unsafe_block() { + sse2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe +} + fn main() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr index c75ac6e8b9ae0..13b58fde862d5 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr @@ -1,83 +1,115 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:23:5 + --> $DIR/safe-calls.rs:28:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:26:5 + --> $DIR/safe-calls.rs:31:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:34:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:36:5 + --> $DIR/safe-calls.rs:41:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:39:5 + --> $DIR/safe-calls.rs:44:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:46:5 + --> $DIR/safe-calls.rs:51:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:49:5 + --> $DIR/safe-calls.rs:54:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:52:5 + --> $DIR/safe-calls.rs:57:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:60:5 + --> $DIR/safe-calls.rs:65:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:65:18 + --> $DIR/safe-calls.rs:70:15 | -LL | const name: () = sse2(); - | ^^^^^^ call to function with `#[target_feature]` +LL | const _: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` -error: aborting due to 10 previous errors +error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:74:15 + | +LL | const _: () = sse2_and_fxsr(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr + = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]` + +error: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) + --> $DIR/safe-calls.rs:82:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/safe-calls.rs:81:1 + | +LL | unsafe fn needs_unsafe_block() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/safe-calls.rs:78:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr index 247fad2e99295..f3726166eba71 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr @@ -29,6 +29,10 @@ LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some( | ^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to compare for equality + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] == 1 { + | + error: expected expression, found `let` statement --> $DIR/invalid-let-in-a-valid-let-context.rs:24:23 @@ -53,6 +57,10 @@ LL | if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { | ^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to compare for equality + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = ()] == 1 { + | + error: expected expression, found `let` statement --> $DIR/invalid-let-in-a-valid-let-context.rs:42:21 diff --git a/tests/ui/traits/issue-85735.stderr b/tests/ui/traits/issue-85735.stderr index 1aba418334848..0980c5c33bdb4 100644 --- a/tests/ui/traits/issue-85735.stderr +++ b/tests/ui/traits/issue-85735.stderr @@ -1,10 +1,10 @@ -error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>` +error[E0283]: type annotations needed: cannot satisfy `T: FnMut(&'a ())` --> $DIR/issue-85735.rs:7:8 | LL | T: FnMut(&'a ()), | ^^^^^^^^^^^^^ | -note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found +note: multiple `impl`s or `where` clauses satisfying `T: FnMut(&'a ())` found --> $DIR/issue-85735.rs:7:8 | LL | T: FnMut(&'a ()),