mirror of https://github.com/rust-lang/rust.git
Auto merge of #118443 - matthiaskrgr:rollup-mp8o3m4, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #118157 (Add `never_patterns` feature gate) - #118191 (Suggest `let` or `==` on typo'd let-chain) - #118231 (also add is_empty to const raw slices) - #118333 (Print list of missing target features when calling a function with target features outside an unsafe block) - #118426 (ConstProp: Correctly remove const if unknown value assigned to it.) - #118428 (rustdoc: Move `AssocItemRender` and `RenderMode` to `html::render`.) - #118438 (Update nto-qnx.md) Failed merges: - #118268 (Pretty print `Fn<(..., ...)>` trait refs with parentheses (almost) always) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
ce4727f723
|
@ -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<Pat>),
|
||||
|
||||
|
|
|
@ -1249,7 +1249,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, 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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -155,7 +155,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.
|
||||
|
@ -520,6 +520,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 `()`.
|
||||
|
|
|
@ -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>),
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -766,6 +766,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
|||
| PatKind::Binding(.., None)
|
||||
| PatKind::Lit(..)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Never
|
||||
| PatKind::Wild => {
|
||||
// always ok
|
||||
}
|
||||
|
|
|
@ -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(..)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Symbol>,
|
||||
/// Target features in `missing` that are enabled at compile time
|
||||
/// (e.g., with `-C target-feature`).
|
||||
build_enabled: Vec<Symbol>,
|
||||
},
|
||||
}
|
||||
|
||||
#[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,
|
||||
|
|
|
@ -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<Pat<'tcx>>]>,
|
||||
},
|
||||
|
||||
/// 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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -827,6 +827,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
PatKind::Constant { .. }
|
||||
| PatKind::Range { .. }
|
||||
| PatKind::Wild
|
||||
| PatKind::Never
|
||||
| PatKind::Error(_) => {}
|
||||
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 { .. }
|
||||
|
|
|
@ -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<UnusedUnsafeEnclosing>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
enum UnsafeOpKind {
|
||||
CallToUnsafeFunction(Option<DefId>),
|
||||
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<Symbol>,
|
||||
/// Target features in `missing` that are enabled at compile time
|
||||
/// (e.g., with `-C target-feature`).
|
||||
build_enabled: Vec<Symbol>,
|
||||
},
|
||||
}
|
||||
|
||||
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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<UnsafeNotInheritedLintNote>,
|
||||
}
|
||||
|
@ -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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[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<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -439,6 +439,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
|
||||
// FIXME we need to revisit this for #67176
|
||||
if rvalue.has_param() {
|
||||
trace!("skipping, has param");
|
||||
return None;
|
||||
}
|
||||
if !rvalue
|
||||
|
@ -707,7 +708,11 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||
fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
self.super_assign(place, rvalue, location);
|
||||
|
||||
let Some(()) = self.check_rvalue(rvalue) else { return };
|
||||
let Some(()) = self.check_rvalue(rvalue) else {
|
||||
trace!("rvalue check failed, removing const");
|
||||
Self::remove_const(&mut self.ecx, place.local);
|
||||
return;
|
||||
};
|
||||
|
||||
match self.ecx.machine.can_const_prop[place.local] {
|
||||
// Do nothing if the place is indirect.
|
||||
|
|
|
@ -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<G: EmissionGuarantee>(&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,
|
||||
InitializingTypeWith => {
|
||||
crate::fluent_generated::mir_transform_initializing_valid_range_note
|
||||
CallToUnsafeFunction => {
|
||||
diag.note(fluent::mir_transform_call_to_unsafe_note);
|
||||
}
|
||||
UseOfInlineAssembly => {
|
||||
diag.note(fluent::mir_transform_use_of_asm_note);
|
||||
}
|
||||
InitializingTypeWith => {
|
||||
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<P> {
|
|||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -415,6 +415,32 @@ pub(crate) struct ExpectedExpressionFoundLet {
|
|||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub reason: ForbiddenLetReason,
|
||||
#[subdiagnostic]
|
||||
pub missing_let: Option<MaybeMissingLet>,
|
||||
#[subdiagnostic]
|
||||
pub comparison: Option<MaybeComparison>,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
|
|
|
@ -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<ForbiddenLetReason>,
|
||||
missing_let: Option<errors::MaybeMissingLet>,
|
||||
comparison: Option<errors::MaybeComparison>,
|
||||
}
|
||||
|
||||
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(_)
|
||||
|
|
|
@ -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)?
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
|
|
@ -1097,6 +1097,7 @@ symbols! {
|
|||
negative_impls,
|
||||
neon,
|
||||
never,
|
||||
never_patterns,
|
||||
never_type,
|
||||
never_type_fallback,
|
||||
new,
|
||||
|
|
|
@ -1644,6 +1644,24 @@ impl<T> *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.
|
||||
|
|
|
@ -1920,10 +1920,10 @@ impl<T> *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")]
|
||||
|
|
|
@ -121,10 +121,8 @@ export build_env='
|
|||
|
||||
env $build_env \
|
||||
./x.py build \
|
||||
--target aarch64-unknown-nto-qnx710 \
|
||||
--target x86_64-pc-nto-qnx710 \
|
||||
--target x86_64-unknown-linux-gnu \
|
||||
rustc library/core library/alloc
|
||||
--target aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \
|
||||
rustc library/core library/alloc library/std
|
||||
```
|
||||
|
||||
## Running the Rust test suite
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -9,21 +9,6 @@ pub(crate) use renderer::{run_format, FormatRenderer};
|
|||
use crate::clean::{self, ItemId};
|
||||
use crate::html::render::Context;
|
||||
|
||||
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
|
||||
/// impl.
|
||||
pub(crate) enum AssocItemRender<'a> {
|
||||
All,
|
||||
DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
|
||||
}
|
||||
|
||||
/// For different handling of associated items from the Deref target of a type rather than the type
|
||||
/// itself.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub(crate) enum RenderMode {
|
||||
Normal,
|
||||
ForDeref { mut_: bool },
|
||||
}
|
||||
|
||||
/// Metadata about implementations for a type or trait.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Impl {
|
||||
|
|
|
@ -66,7 +66,7 @@ use crate::clean::{self, ItemId, RenderedLink, SelfTy};
|
|||
use crate::error::Error;
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::formats::{AssocItemRender, Impl, RenderMode};
|
||||
use crate::formats::Impl;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{
|
||||
display_fn, href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
|
||||
|
@ -89,6 +89,21 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
|
|||
})
|
||||
}
|
||||
|
||||
/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
|
||||
/// impl.
|
||||
pub(crate) enum AssocItemRender<'a> {
|
||||
All,
|
||||
DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
|
||||
}
|
||||
|
||||
/// For different handling of associated items from the Deref target of a type rather than the type
|
||||
/// itself.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub(crate) enum RenderMode {
|
||||
Normal,
|
||||
ForDeref { mut_: bool },
|
||||
}
|
||||
|
||||
// Helper structs for rendering items/sidebars and carrying along contextual
|
||||
// information
|
||||
|
||||
|
|
|
@ -22,12 +22,13 @@ use super::{
|
|||
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
|
||||
render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
|
||||
render_impl, render_rightside, render_stability_since_raw,
|
||||
render_stability_since_raw_with_extra, AssocItemLink, Context, ImplRenderingParameters,
|
||||
render_stability_since_raw_with_extra, AssocItemLink, AssocItemRender, Context,
|
||||
ImplRenderingParameters, RenderMode,
|
||||
};
|
||||
use crate::clean;
|
||||
use crate::config::ModuleSorting;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::formats::{AssocItemRender, Impl, RenderMode};
|
||||
use crate::formats::Impl;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{
|
||||
display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space,
|
||||
|
|
|
@ -15,14 +15,14 @@ use rustc_span::Symbol;
|
|||
use serde::ser::SerializeSeq;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use super::{collect_paths_for_type, ensure_trailing_slash, Context};
|
||||
use super::{collect_paths_for_type, ensure_trailing_slash, Context, RenderMode};
|
||||
use crate::clean::{Crate, Item, ItemId, ItemKind};
|
||||
use crate::config::{EmitType, RenderOptions};
|
||||
use crate::docfs::PathError;
|
||||
use crate::error::Error;
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::formats::{Impl, RenderMode};
|
||||
use crate::formats::Impl;
|
||||
use crate::html::format::Buffer;
|
||||
use crate::html::render::{AssocItemLink, ImplRenderingParameters};
|
||||
use crate::html::{layout, static_files};
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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<DefId>, &'a [(Symbol, Self)]),
|
||||
Tuple(Option<DefId>, &'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))
|
||||
},
|
||||
|
|
|
@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, 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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1017,6 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
}
|
||||
e.hash(&mut self.s);
|
||||
},
|
||||
PatKind::Never => {},
|
||||
PatKind::Wild => {},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) => "...",
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// unit-test: ConstProp
|
||||
// compile-flags: -O
|
||||
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/118328
|
||||
|
||||
#![allow(unused_assignments)]
|
||||
|
||||
struct SizeOfConst<T>(std::marker::PhantomData<T>);
|
||||
impl<T> SizeOfConst<T> {
|
||||
const SIZE: usize = std::mem::size_of::<T>();
|
||||
}
|
||||
|
||||
// EMIT_MIR overwrite_with_const_with_params.size_of.ConstProp.diff
|
||||
fn size_of<T>() -> usize {
|
||||
// CHECK-LABEL: fn size_of(
|
||||
// CHECK: _1 = const 0_usize;
|
||||
// CHECK-NEXT: _1 = const _;
|
||||
// CHECK-NEXT: _0 = _1;
|
||||
let mut a = 0;
|
||||
a = SizeOfConst::<T>::SIZE;
|
||||
a
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(size_of::<u32>(), std::mem::size_of::<u32>());
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
- // MIR for `size_of` before ConstProp
|
||||
+ // MIR for `size_of` after ConstProp
|
||||
|
||||
fn size_of() -> usize {
|
||||
let mut _0: usize;
|
||||
let mut _1: usize;
|
||||
scope 1 {
|
||||
debug a => _1;
|
||||
}
|
||||
|
||||
bb0: {
|
||||
StorageLive(_1);
|
||||
_1 = const 0_usize;
|
||||
_1 = const _;
|
||||
_0 = _1;
|
||||
StorageDead(_1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// compile-flags: -O
|
||||
// run-pass
|
||||
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/118328
|
||||
|
||||
#![allow(unused_assignments)]
|
||||
|
||||
struct SizeOfConst<T>(std::marker::PhantomData<T>);
|
||||
impl<T> SizeOfConst<T> {
|
||||
const SIZE: usize = std::mem::size_of::<T>();
|
||||
}
|
||||
|
||||
fn size_of<T>() -> usize {
|
||||
let mut a = 0;
|
||||
a = SizeOfConst::<T>::SIZE;
|
||||
a
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(size_of::<u32>(), std::mem::size_of::<u32>());
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 `()`
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// Check that never patterns require the feature gate.
|
||||
use std::ptr::NonNull;
|
||||
|
||||
enum Void {}
|
||||
|
||||
fn main() {
|
||||
let res: Result<u32, Void> = 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.
|
|
@ -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)");
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
#![feature(never_patterns)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
enum Void {}
|
||||
|
||||
fn main() {}
|
||||
|
||||
// The classic use for empty types.
|
||||
fn safe_unwrap_result<T>(res: Result<T, Void>) {
|
||||
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::<Void> {
|
||||
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::<Void> {
|
||||
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::<Void> {
|
||||
None => {}
|
||||
Some(!) => {}
|
||||
}
|
||||
match None::<&Void> {
|
||||
None => {}
|
||||
Some(&!) => {}
|
||||
}
|
||||
match None::<&(u32, Void)> {
|
||||
None => {}
|
||||
Some(&(_, !)) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn never_and_bindings() {
|
||||
let x: Result<bool, &(u32, Void)> = 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
|
||||
}
|
||||
}
|
|
@ -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`.
|
|
@ -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`.
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue