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:
bors 2023-11-29 11:42:03 +00:00
commit ce4727f723
66 changed files with 910 additions and 188 deletions

View file

@ -645,6 +645,7 @@ pub fn walk(&self, it: &mut impl FnMut(&Pat) -> bool) {
// 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>),

View file

@ -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));

View file

@ -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);
}

View file

@ -24,6 +24,7 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'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);

View file

@ -555,6 +555,7 @@ macro_rules! gate_all {
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() {

View file

@ -1343,6 +1343,7 @@ fn print_pat(&mut self, pat: &ast::Pat) {
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");

View file

@ -155,7 +155,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
// 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 @@ pub fn internal(&self, feature: Symbol) -> bool {
(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 `()`.

View file

@ -1002,7 +1002,7 @@ fn walk_short_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) -> bool {
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 @@ fn walk_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) {
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>),

View file

@ -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);

View file

@ -662,6 +662,7 @@ fn is_binding_pat(pat: &hir::Pat<'_>) -> bool {
PatKind::Ref(_, _)
| PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
| PatKind::Wild
| PatKind::Never
| PatKind::Path(_)
| PatKind::Lit(_)
| PatKind::Range(_, _, _) => false,

View file

@ -1724,6 +1724,7 @@ fn print_pat(&mut self, pat: &hir::Pat<'_>) {
// 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");

View file

@ -401,12 +401,17 @@ fn maybe_read_scrutinee<'t>(
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

View file

@ -766,6 +766,7 @@ fn cat_pattern_<F>(
| PatKind::Binding(.., None)
| PatKind::Lit(..)
| PatKind::Range(..)
| PatKind::Never
| PatKind::Wild => {
// always ok
}

View file

@ -178,6 +178,9 @@ fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<
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 @@ fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> A
| 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 @@ fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
| PatKind::Slice(..) => "binding",
PatKind::Wild
| PatKind::Never
| PatKind::Binding(..)
| PatKind::Path(..)
| PatKind::Box(..)

View file

@ -1154,7 +1154,7 @@ fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
// 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);

View file

@ -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,

View file

@ -635,7 +635,12 @@ fn walk_(&self, it: &mut impl FnMut(&Pat<'tcx>) -> bool) {
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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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 {

View file

@ -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);

View file

@ -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 =

View file

@ -827,6 +827,7 @@ pub(super) fn visit_primary_bindings(
PatKind::Constant { .. }
| PatKind::Range { .. }
| PatKind::Wild
| PatKind::Never
| PatKind::Error(_) => {}
PatKind::Deref { ref subpattern } => {

View file

@ -194,6 +194,12 @@ fn simplify_match_pair<'pat>(
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)

View file

@ -75,6 +75,7 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
| PatKind::Array { .. }
| PatKind::Wild
| PatKind::Binding { .. }
| PatKind::Never
| PatKind::Leaf { .. }
| PatKind::Deref { .. }
| PatKind::Error(_) => self.error_simplifiable(match_pair),
@ -107,6 +108,7 @@ pub(super) fn add_cases_to_switch<'pat>(
PatKind::Slice { .. }
| PatKind::Array { .. }
| PatKind::Wild
| PatKind::Never
| PatKind::Or { .. }
| PatKind::Binding { .. }
| PatKind::AscribeUserType { .. }

View file

@ -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 @@ fn visit_pat(&mut self, pat: &Pat<'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 @@ fn visit_expr(&mut self, expr: &Expr<'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 @@ pub fn emit_unsafe_op_in_unsafe_fn_lint(
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 @@ pub fn emit_requires_unsafe_err(
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),
});
}
}

View file

@ -2,6 +2,7 @@
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>,
}

View file

@ -1557,6 +1557,12 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
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();

View file

@ -251,6 +251,8 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
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) => {

View file

@ -642,6 +642,9 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
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);

View file

@ -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

View file

@ -287,19 +287,20 @@ fn register_violations<'a>(
.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 @@ fn check_target_features(&mut self, func_did: DefId) {
// 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 => {

View file

@ -439,6 +439,7 @@ fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Option<()> {
// FIXME we need to revisit this for #67176
if rvalue.has_param() {
trace!("skipping, has param");
return None;
}
if !rvalue
@ -707,7 +708,11 @@ fn visit_projection_elem(
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.

View file

@ -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_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 @@ fn decorate_lint<'b>(
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 @@ fn decorate_lint<'b>(
}
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 @@ fn decorate_lint<'b>(
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 @@ fn decorate_lint<'b>(
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 @@ fn decorate_lint<'b>(
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
crate::fluent_generated::mir_transform_must_not_suspend
fluent::mir_transform_must_not_suspend
}
}

View file

@ -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

View file

@ -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)]

View file

@ -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 @@ fn parse_expr_cond(&mut self) -> PResult<'a, P<Expr>> {
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 @@ fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>>
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 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
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 @@ fn visit_expr(&mut self, e: &mut P<Expr>) {
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 @@ fn visit_expr(&mut self, e: &mut P<Expr>) {
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(_)

View file

@ -368,8 +368,12 @@ fn parse_pat_with_range_pat(
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)?

View file

@ -286,7 +286,21 @@ fn visit_arm(&mut self, a: &'v hir::Arm<'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 @@ fn visit_pat(&mut self, p: &'v ast::Pat) {
Range,
Slice,
Rest,
Never,
Paren,
MacCall
]

View file

@ -1097,6 +1097,7 @@
negative_impls,
neon,
never,
never_patterns,
never_type,
never_type_fallback,
new,

View file

@ -1644,6 +1644,24 @@ pub const fn len(self) -> usize {
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.

View file

@ -1920,10 +1920,10 @@ pub const fn len(self) -> usize {
///
/// ```
/// #![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")]

View file

@ -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

View file

@ -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) => {

View file

@ -9,21 +9,6 @@
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 {

View file

@ -66,7 +66,7 @@
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

View file

@ -22,12 +22,13 @@
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,

View file

@ -15,14 +15,14 @@
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};

View file

@ -46,7 +46,7 @@ fn array_rec(pats: &[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)),

View file

@ -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 @@ fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) ->
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 @@ fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) ->
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))
},

View file

@ -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.

View file

@ -629,6 +629,7 @@ macro_rules! kind {
match pat.value.kind {
PatKind::Wild => kind!("Wild"),
PatKind::Never => kind!("Never"),
PatKind::Binding(ann, _, name, sub) => {
bind!(self, name);
opt_bind!(self, sub);

View file

@ -1017,6 +1017,7 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
}
e.hash(&mut self.s);
},
PatKind::Never => {},
PatKind::Wild => {},
}
}

View file

@ -1707,6 +1707,7 @@ fn are_refutable<'a, I: IntoIterator<Item = &'a Pat<'a>>>(cx: &LateContext<'_>,
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,

View file

@ -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 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
None
}
}
PatKind::Never => None,
PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
let infix = match end_kind.node {
RangeEnd::Included(RangeSyntax::DotDotDot) => "...",

View file

@ -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>());
}

View file

@ -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;
}
}

View file

@ -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>());
}

View file

@ -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

View file

@ -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 `()`

View file

@ -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
}
}
}

View file

@ -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`.

View file

@ -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)");

View file

@ -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
}
}

View file

@ -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`.

View file

@ -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`.

View file

@ -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() {}

View file

@ -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`.

View file

@ -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