1
Fork 0

Auto merge of #99210 - Dylan-DPC:rollup-879cp1t, r=Dylan-DPC

Rollup of 5 pull requests

Successful merges:

 - #98574 (Lower let-else in MIR)
 - #99011 (`UnsafeCell` blocks niches inside its nested type from being available outside)
 - #99030 (diagnostics: error messages when struct literals fail to parse)
 - #99155 (Keep unstable target features for asm feature checking)
 - #99199 (Refactor: remove an unnecessary `span_to_snippet`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-07-13 17:13:27 +00:00
commit c80dde43f9
72 changed files with 830 additions and 830 deletions

View file

@ -1,8 +1,8 @@
use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext}; use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind}; use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::{sym, DesugaringKind}; use rustc_span::sym;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -36,21 +36,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match s.kind { match s.kind {
StmtKind::Local(ref local) => { StmtKind::Local(ref local) => {
let hir_id = self.lower_node_id(s.id); let hir_id = self.lower_node_id(s.id);
match &local.kind { let local = self.lower_local(local);
LocalKind::InitElse(init, els) => { self.alias_attrs(hir_id, local.hir_id);
let e = self.lower_let_else(hir_id, local, init, els, tail); let kind = hir::StmtKind::Local(local);
expr = Some(e); let span = self.lower_span(s.span);
// remaining statements are in let-else expression stmts.push(hir::Stmt { hir_id, kind, span });
break;
}
_ => {
let local = self.lower_local(local);
self.alias_attrs(hir_id, local.hir_id);
let kind = hir::StmtKind::Local(local);
let span = self.lower_span(s.span);
stmts.push(hir::Stmt { hir_id, kind, span });
}
}
} }
StmtKind::Item(ref it) => { StmtKind::Item(ref it) => {
stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map( stmts.extend(self.lower_item_ref(it).into_iter().enumerate().map(
@ -101,10 +91,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let init = l.kind.init().map(|init| self.lower_expr(init)); let init = l.kind.init().map(|init| self.lower_expr(init));
let hir_id = self.lower_node_id(l.id); let hir_id = self.lower_node_id(l.id);
let pat = self.lower_pat(&l.pat); let pat = self.lower_pat(&l.pat);
let els = if let LocalKind::InitElse(_, els) = &l.kind {
if !self.tcx.features().let_else {
feature_err(
&self.tcx.sess.parse_sess,
sym::let_else,
l.span,
"`let...else` statements are unstable",
)
.emit();
}
Some(self.lower_block(els, false))
} else {
None
};
let span = self.lower_span(l.span); let span = self.lower_span(l.span);
let source = hir::LocalSource::Normal; let source = hir::LocalSource::Normal;
self.lower_attrs(hir_id, &l.attrs); self.lower_attrs(hir_id, &l.attrs);
self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source }) self.arena.alloc(hir::Local { hir_id, ty, pat, init, els, span, source })
} }
fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode { fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
@ -115,59 +119,4 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
} }
fn lower_let_else(
&mut self,
stmt_hir_id: hir::HirId,
local: &Local,
init: &Expr,
els: &Block,
tail: &[Stmt],
) -> &'hir hir::Expr<'hir> {
let ty = local
.ty
.as_ref()
.map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable)));
let span = self.lower_span(local.span);
let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
let init = self.lower_expr(init);
let local_hir_id = self.lower_node_id(local.id);
self.lower_attrs(local_hir_id, &local.attrs);
let let_expr = {
let lex = self.arena.alloc(hir::Let {
hir_id: local_hir_id,
pat: self.lower_pat(&local.pat),
ty,
init,
span,
});
self.arena.alloc(self.expr(span, hir::ExprKind::Let(lex), AttrVec::new()))
};
let then_expr = {
let (stmts, expr) = self.lower_stmts(tail);
let block = self.block_all(span, stmts, expr);
self.arena.alloc(self.expr_block(block, AttrVec::new()))
};
let else_expr = {
let block = self.lower_block(els, false);
self.arena.alloc(self.expr_block(block, AttrVec::new()))
};
self.alias_attrs(let_expr.hir_id, local_hir_id);
self.alias_attrs(else_expr.hir_id, local_hir_id);
let if_expr = self.arena.alloc(hir::Expr {
hir_id: stmt_hir_id,
span,
kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
});
if !self.tcx.features().let_else {
feature_err(
&self.tcx.sess.parse_sess,
sym::let_else,
local.span,
"`let...else` statements are unstable",
)
.emit();
}
if_expr
}
} }

View file

@ -2146,7 +2146,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
debug_assert!(!a.is_empty()); debug_assert!(!a.is_empty());
self.attrs.insert(hir_id.local_id, a); self.attrs.insert(hir_id.local_id, a);
} }
let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None }; let local = hir::Local {
hir_id,
init,
pat,
els: None,
source,
span: self.lower_span(span),
ty: None,
};
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local))) self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
} }

View file

@ -856,7 +856,6 @@ pub enum ReprAttr {
ReprSimd, ReprSimd,
ReprTransparent, ReprTransparent,
ReprAlign(u32), ReprAlign(u32),
ReprNoNiche,
} }
#[derive(Eq, PartialEq, Debug, Copy, Clone)] #[derive(Eq, PartialEq, Debug, Copy, Clone)]
@ -904,7 +903,6 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
sym::packed => Some(ReprPacked(1)), sym::packed => Some(ReprPacked(1)),
sym::simd => Some(ReprSimd), sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent), sym::transparent => Some(ReprTransparent),
sym::no_niche => Some(ReprNoNiche),
sym::align => { sym::align => {
let mut err = struct_span_err!( let mut err = struct_span_err!(
diagnostic, diagnostic,
@ -943,7 +941,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
Ok(literal) => acc.push(ReprPacked(literal)), Ok(literal) => acc.push(ReprPacked(literal)),
Err(message) => literal_error = Some(message), Err(message) => literal_error = Some(message),
}; };
} else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche) } else if matches!(name, sym::C | sym::simd | sym::transparent)
|| int_type_of_word(name).is_some() || int_type_of_word(name).is_some()
{ {
recognised = true; recognised = true;
@ -1001,7 +999,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
} else { } else {
if matches!( if matches!(
meta_item.name_or_empty(), meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent | sym::no_niche sym::C | sym::simd | sym::transparent
) || int_type_of_word(meta_item.name_or_empty()).is_some() ) || int_type_of_word(meta_item.name_or_empty()).is_some()
{ {
recognised = true; recognised = true;
@ -1039,7 +1037,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
.emit(); .emit();
} else if matches!( } else if matches!(
meta_item.name_or_empty(), meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent | sym::no_niche sym::C | sym::simd | sym::transparent
) || int_type_of_word(meta_item.name_or_empty()).is_some() ) || int_type_of_word(meta_item.name_or_empty()).is_some()
{ {
recognised = true; recognised = true;

View file

@ -1598,21 +1598,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let return_ty = tcx.erase_regions(return_ty); let return_ty = tcx.erase_regions(return_ty);
// to avoid panics // to avoid panics
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) { if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
if self && self
.infcx .infcx
.type_implements_trait(iter_trait, return_ty, ty_params, self.param_env) .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env)
.must_apply_modulo_regions() .must_apply_modulo_regions()
{ {
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { err.span_suggestion_hidden(
err.span_suggestion_hidden( return_span.shrink_to_hi(),
return_span, "use `.collect()` to allocate the iterator",
"use `.collect()` to allocate the iterator", ".collect::<Vec<_>>()",
format!("{snippet}.collect::<Vec<_>>()"), Applicability::MaybeIncorrect,
Applicability::MaybeIncorrect, );
);
}
}
} }
} }

View file

@ -167,7 +167,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
} }
} }
fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> { fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> {
vec![] vec![]
} }

View file

@ -140,8 +140,8 @@ impl CodegenBackend for GccCodegenBackend {
) )
} }
fn target_features(&self, sess: &Session) -> Vec<Symbol> { fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
target_features(sess) target_features(sess, allow_unstable)
} }
} }
@ -298,12 +298,12 @@ pub fn target_cpu(sess: &Session) -> &str {
} }
} }
pub fn target_features(sess: &Session) -> Vec<Symbol> { pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
supported_target_features(sess) supported_target_features(sess)
.iter() .iter()
.filter_map( .filter_map(
|&(feature, gate)| { |&(feature, gate)| {
if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } if sess.is_nightly_build() || allow_unstable || gate.is_none() { Some(feature) } else { None }
}, },
) )
.filter(|_feature| { .filter(|_feature| {

View file

@ -324,8 +324,8 @@ impl CodegenBackend for LlvmCodegenBackend {
llvm_util::print_version(); llvm_util::print_version();
} }
fn target_features(&self, sess: &Session) -> Vec<Symbol> { fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
target_features(sess) target_features(sess, allow_unstable)
} }
fn codegen_crate<'tcx>( fn codegen_crate<'tcx>(

View file

@ -233,26 +233,29 @@ pub fn check_tied_features(
// Used to generate cfg variables and apply features // Used to generate cfg variables and apply features
// Must express features in the way Rust understands them // Must express features in the way Rust understands them
pub fn target_features(sess: &Session) -> Vec<Symbol> { pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
let target_machine = create_informational_target_machine(sess); let target_machine = create_informational_target_machine(sess);
let mut features: Vec<Symbol> = let mut features: Vec<Symbol> = supported_target_features(sess)
supported_target_features(sess) .iter()
.iter() .filter_map(|&(feature, gate)| {
.filter_map(|&(feature, gate)| { if sess.is_nightly_build() || allow_unstable || gate.is_none() {
if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None } Some(feature)
}) } else {
.filter(|feature| { None
// check that all features in a given smallvec are enabled }
for llvm_feature in to_llvm_features(sess, feature) { })
let cstr = SmallCStr::new(llvm_feature); .filter(|feature| {
if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } { // check that all features in a given smallvec are enabled
return false; for llvm_feature in to_llvm_features(sess, feature) {
} let cstr = SmallCStr::new(llvm_feature);
if !unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
return false;
} }
true }
}) true
.map(|feature| Symbol::intern(feature)) })
.collect(); .map(|feature| Symbol::intern(feature))
.collect();
// LLVM 14 changed the ABI for i128 arguments to __float/__fix builtins on Win64 // LLVM 14 changed the ABI for i128 arguments to __float/__fix builtins on Win64
// (see https://reviews.llvm.org/D110413). This unstable target feature is intended for use // (see https://reviews.llvm.org/D110413). This unstable target feature is intended for use

View file

@ -59,7 +59,7 @@ impl<'tcx, T> Backend<'tcx> for T where
pub trait CodegenBackend { pub trait CodegenBackend {
fn init(&self, _sess: &Session) {} fn init(&self, _sess: &Session) {}
fn print(&self, _req: PrintRequest, _sess: &Session) {} fn print(&self, _req: PrintRequest, _sess: &Session) {}
fn target_features(&self, _sess: &Session) -> Vec<Symbol> { fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
vec![] vec![]
} }
fn print_passes(&self) {} fn print_passes(&self) {}

View file

@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
} }
if let Some(def) = mplace.layout.ty.ty_adt_def() { if let Some(def) = mplace.layout.ty.ty_adt_def() {
if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() { if def.is_unsafe_cell() {
// We are crossing over an `UnsafeCell`, we can mutate again. This means that // We are crossing over an `UnsafeCell`, we can mutate again. This means that
// References we encounter inside here are interned as pointing to mutable // References we encounter inside here are interned as pointing to mutable
// allocations. // allocations.

View file

@ -821,7 +821,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
// Special check preventing `UnsafeCell` in the inner part of constants // Special check preventing `UnsafeCell` in the inner part of constants
if let Some(def) = op.layout.ty.ty_adt_def() { if let Some(def) = op.layout.ty.ty_adt_def() {
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. }))
&& Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() && def.is_unsafe_cell()
{ {
throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
} }

View file

@ -96,13 +96,13 @@ impl Qualif for HasMutInterior {
} }
fn in_adt_inherently<'tcx>( fn in_adt_inherently<'tcx>(
cx: &ConstCx<'_, 'tcx>, _cx: &ConstCx<'_, 'tcx>,
adt: AdtDef<'tcx>, adt: AdtDef<'tcx>,
_: SubstsRef<'tcx>, _: SubstsRef<'tcx>,
) -> bool { ) -> bool {
// Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently. // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
// It arises structurally for all other types. // It arises structurally for all other types.
Some(adt.did()) == cx.tcx.lang_items().unsafe_cell_type() adt.is_unsafe_cell()
} }
} }

View file

@ -156,9 +156,6 @@ declare_features! (
(active, intrinsics, "1.0.0", None, None), (active, intrinsics, "1.0.0", None, None),
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
(active, lang_items, "1.0.0", None, None), (active, lang_items, "1.0.0", None, None),
/// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`,
/// it is not on path for eventual stabilization).
(active, no_niche, "1.42.0", None, None),
/// Allows using `#[omit_gdb_pretty_printer_section]`. /// Allows using `#[omit_gdb_pretty_printer_section]`.
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None), (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
/// Allows using `#[prelude_import]` on glob `use` items. /// Allows using `#[prelude_import]` on glob `use` items.

View file

@ -1316,6 +1316,8 @@ pub struct Local<'hir> {
pub ty: Option<&'hir Ty<'hir>>, pub ty: Option<&'hir Ty<'hir>>,
/// Initializer expression to set the value, if any. /// Initializer expression to set the value, if any.
pub init: Option<&'hir Expr<'hir>>, pub init: Option<&'hir Expr<'hir>>,
/// Else block for a `let...else` binding.
pub els: Option<&'hir Block<'hir>>,
pub hir_id: HirId, pub hir_id: HirId,
pub span: Span, pub span: Span,
/// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop /// Can be `ForLoopDesugar` if the `let` statement is part of a `for` loop

View file

@ -472,6 +472,9 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
walk_list!(visitor, visit_expr, &local.init); walk_list!(visitor, visit_expr, &local.init);
visitor.visit_id(local.hir_id); visitor.visit_id(local.hir_id);
visitor.visit_pat(&local.pat); visitor.visit_pat(&local.pat);
if let Some(els) = local.els {
visitor.visit_block(els);
}
walk_list!(visitor, visit_ty, &local.ty); walk_list!(visitor, visit_ty, &local.ty);
} }

View file

@ -883,7 +883,12 @@ impl<'a> State<'a> {
self.ann.post(self, AnnNode::SubItem(ii.hir_id())) self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
} }
pub fn print_local(&mut self, init: Option<&hir::Expr<'_>>, decl: impl Fn(&mut Self)) { pub fn print_local(
&mut self,
init: Option<&hir::Expr<'_>>,
els: Option<&hir::Block<'_>>,
decl: impl Fn(&mut Self),
) {
self.space_if_not_bol(); self.space_if_not_bol();
self.ibox(INDENT_UNIT); self.ibox(INDENT_UNIT);
self.word_nbsp("let"); self.word_nbsp("let");
@ -897,6 +902,13 @@ impl<'a> State<'a> {
self.word_space("="); self.word_space("=");
self.print_expr(init); self.print_expr(init);
} }
if let Some(els) = els {
self.nbsp();
self.word_space("else");
self.print_block(els);
}
self.end() self.end()
} }
@ -904,7 +916,7 @@ impl<'a> State<'a> {
self.maybe_print_comment(st.span.lo()); self.maybe_print_comment(st.span.lo());
match st.kind { match st.kind {
hir::StmtKind::Local(loc) => { hir::StmtKind::Local(loc) => {
self.print_local(loc.init, |this| this.print_local_decl(loc)); self.print_local(loc.init, loc.els, |this| this.print_local_decl(loc));
} }
hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)), hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
hir::StmtKind::Expr(expr) => { hir::StmtKind::Expr(expr) => {
@ -1404,7 +1416,7 @@ impl<'a> State<'a> {
// Print `let _t = $init;`: // Print `let _t = $init;`:
let temp = Ident::from_str("_t"); let temp = Ident::from_str("_t");
self.print_local(Some(init), |this| this.print_ident(temp)); self.print_local(Some(init), None, |this| this.print_ident(temp));
self.word(";"); self.word(";");
// Print `_t`: // Print `_t`:

View file

@ -48,7 +48,10 @@ pub fn add_configuration(
) { ) {
let tf = sym::target_feature; let tf = sym::target_feature;
let target_features = codegen_backend.target_features(sess); let unstable_target_features = codegen_backend.target_features(sess, true);
sess.unstable_target_features.extend(unstable_target_features.iter().cloned());
let target_features = codegen_backend.target_features(sess, false);
sess.target_features.extend(target_features.iter().cloned()); sess.target_features.extend(target_features.iter().cloned());
cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat)))); cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));

View file

@ -703,9 +703,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
return true; return true;
} }
// Types with a `#[repr(no_niche)]` attribute have their niche hidden. // `UnsafeCell` has its niche hidden.
// The attribute is used by the UnsafeCell for example (the only use so far). if def.is_unsafe_cell() {
if def.repr().hide_niche() {
return false; return false;
} }

View file

@ -182,6 +182,9 @@ pub enum StmtKind<'tcx> {
/// `let pat: ty = <INIT>` /// `let pat: ty = <INIT>`
initializer: Option<ExprId>, initializer: Option<ExprId>,
/// `let pat: ty = <INIT> else { <ELSE> }
else_block: Option<Block>,
/// The lint level for this `let` statement. /// The lint level for this `let` statement.
lint_level: LintLevel, lint_level: LintLevel,
}, },

View file

@ -167,11 +167,15 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm
init_scope: _, init_scope: _,
ref pattern, ref pattern,
lint_level: _, lint_level: _,
else_block,
} => { } => {
if let Some(init) = initializer { if let Some(init) = initializer {
visitor.visit_expr(&visitor.thir()[*init]); visitor.visit_expr(&visitor.thir()[*init]);
} }
visitor.visit_pat(pattern); visitor.visit_pat(pattern);
if let Some(block) = else_block {
visitor.visit_block(block)
}
} }
} }
} }

View file

@ -52,6 +52,8 @@ bitflags! {
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
/// (i.e., this flag is never set unless this ADT is an enum). /// (i.e., this flag is never set unless this ADT is an enum).
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
/// Indicates whether the type is `UnsafeCell`.
const IS_UNSAFE_CELL = 1 << 9;
} }
} }
@ -247,6 +249,9 @@ impl AdtDefData {
if Some(did) == tcx.lang_items().manually_drop() { if Some(did) == tcx.lang_items().manually_drop() {
flags |= AdtFlags::IS_MANUALLY_DROP; flags |= AdtFlags::IS_MANUALLY_DROP;
} }
if Some(did) == tcx.lang_items().unsafe_cell_type() {
flags |= AdtFlags::IS_UNSAFE_CELL;
}
AdtDefData { did, variants, flags, repr } AdtDefData { did, variants, flags, repr }
} }
@ -333,6 +338,12 @@ impl<'tcx> AdtDef<'tcx> {
self.flags().contains(AdtFlags::IS_BOX) self.flags().contains(AdtFlags::IS_BOX)
} }
/// Returns `true` if this is UnsafeCell<T>.
#[inline]
pub fn is_unsafe_cell(self) -> bool {
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
}
/// Returns `true` if this is `ManuallyDrop<T>`. /// Returns `true` if this is `ManuallyDrop<T>`.
#[inline] #[inline]
pub fn is_manually_drop(self) -> bool { pub fn is_manually_drop(self) -> bool {

View file

@ -542,14 +542,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
debug!("univariant offset: {:?} field: {:#?}", offset, field); debug!("univariant offset: {:?} field: {:#?}", offset, field);
offsets[i as usize] = offset; offsets[i as usize] = offset;
if !repr.hide_niche() { if let Some(mut niche) = field.largest_niche {
if let Some(mut niche) = field.largest_niche { let available = niche.available(dl);
let available = niche.available(dl); if available > largest_niche_available {
if available > largest_niche_available { largest_niche_available = available;
largest_niche_available = available; niche.offset += offset;
niche.offset += offset; largest_niche = Some(niche);
largest_niche = Some(niche);
}
} }
} }
@ -1078,6 +1076,29 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?; let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?;
st.variants = Variants::Single { index: v }; st.variants = Variants::Single { index: v };
if def.is_unsafe_cell() {
let hide_niches = |scalar: &mut _| match scalar {
Scalar::Initialized { value, valid_range } => {
*valid_range = WrappingRange::full(value.size(dl))
}
// Already doesn't have any niches
Scalar::Union { .. } => {}
};
match &mut st.abi {
Abi::Uninhabited => {}
Abi::Scalar(scalar) => hide_niches(scalar),
Abi::ScalarPair(a, b) => {
hide_niches(a);
hide_niches(b);
}
Abi::Vector { element, count: _ } => hide_niches(element),
Abi::Aggregate { sized: _ } => {}
}
st.largest_niche = None;
return Ok(tcx.intern_layout(st));
}
let (start, end) = self.tcx.layout_scalar_valid_range(def.did()); let (start, end) = self.tcx.layout_scalar_valid_range(def.did());
match st.abi { match st.abi {
Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => { Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
@ -1106,11 +1127,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
} }
// Update `largest_niche` if we have introduced a larger niche. // Update `largest_niche` if we have introduced a larger niche.
let niche = if def.repr().hide_niche() { let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
None
} else {
Niche::from_scalar(dl, Size::ZERO, *scalar)
};
if let Some(niche) = niche { if let Some(niche) = niche {
match st.largest_niche { match st.largest_niche {
Some(largest_niche) => { Some(largest_niche) => {

View file

@ -1720,11 +1720,9 @@ bitflags! {
const IS_TRANSPARENT = 1 << 2; const IS_TRANSPARENT = 1 << 2;
// Internal only for now. If true, don't reorder fields. // Internal only for now. If true, don't reorder fields.
const IS_LINEAR = 1 << 3; const IS_LINEAR = 1 << 3;
// If true, don't expose any niche to type's context.
const HIDE_NICHE = 1 << 4;
// If true, the type's layout can be randomized using // If true, the type's layout can be randomized using
// the seed stored in `ReprOptions.layout_seed` // the seed stored in `ReprOptions.layout_seed`
const RANDOMIZE_LAYOUT = 1 << 5; const RANDOMIZE_LAYOUT = 1 << 4;
// Any of these flags being set prevent field reordering optimisation. // Any of these flags being set prevent field reordering optimisation.
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits
| ReprFlags::IS_SIMD.bits | ReprFlags::IS_SIMD.bits
@ -1781,7 +1779,6 @@ impl ReprOptions {
ReprFlags::empty() ReprFlags::empty()
} }
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT, attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
attr::ReprNoNiche => ReprFlags::HIDE_NICHE,
attr::ReprSimd => ReprFlags::IS_SIMD, attr::ReprSimd => ReprFlags::IS_SIMD,
attr::ReprInt(i) => { attr::ReprInt(i) => {
size = Some(i); size = Some(i);
@ -1834,11 +1831,6 @@ impl ReprOptions {
self.flags.contains(ReprFlags::IS_LINEAR) self.flags.contains(ReprFlags::IS_LINEAR)
} }
#[inline]
pub fn hide_niche(&self) -> bool {
self.flags.contains(ReprFlags::HIDE_NICHE)
}
/// Returns the discriminant type, given these `repr` options. /// Returns the discriminant type, given these `repr` options.
/// This must only be called on enums! /// This must only be called on enums!
pub fn discr_type(&self) -> attr::IntType { pub fn discr_type(&self) -> attr::IntType {

View file

@ -99,6 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ref pattern, ref pattern,
initializer, initializer,
lint_level, lint_level,
else_block,
} => { } => {
let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
this.block_context.push(BlockFrame::Statement { ignores_expr_result }); this.block_context.push(BlockFrame::Statement { ignores_expr_result });
@ -124,18 +125,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|this| { |this| {
let scope = (*init_scope, source_info); let scope = (*init_scope, source_info);
this.in_scope(scope, *lint_level, |this| { this.in_scope(scope, *lint_level, |this| {
this.declare_bindings( if let Some(else_block) = else_block {
visibility_scope, this.ast_let_else(
remainder_span, block,
pattern, init,
ArmHasGuard(false), initializer_span,
Some((None, initializer_span)), else_block,
); visibility_scope,
this.expr_into_pattern(block, pattern.clone(), init) remainder_span,
pattern,
)
} else {
this.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern
}
}) })
} },
) )
); )
} else { } else {
let scope = (*init_scope, source_info); let scope = (*init_scope, source_info);
unpack!(this.in_scope(scope, *lint_level, |this| { unpack!(this.in_scope(scope, *lint_level, |this| {

View file

@ -1615,7 +1615,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// those N possible outcomes, create a (initially empty) // those N possible outcomes, create a (initially empty)
// vector of candidates. Those are the candidates that still // vector of candidates. Those are the candidates that still
// apply if the test has that particular outcome. // apply if the test has that particular outcome.
debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair); debug!("test_candidates: test={:?} match_pair={:?}", test, match_pair);
let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![]; let mut target_candidates: Vec<Vec<&mut Candidate<'pat, 'tcx>>> = vec![];
target_candidates.resize_with(test.targets(), Default::default); target_candidates.resize_with(test.targets(), Default::default);
@ -1635,8 +1635,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
// at least the first candidate ought to be tested // at least the first candidate ought to be tested
assert!(total_candidate_count > candidates.len()); assert!(total_candidate_count > candidates.len());
debug!("tested_candidates: {}", total_candidate_count - candidates.len()); debug!("test_candidates: tested_candidates: {}", total_candidate_count - candidates.len());
debug!("untested_candidates: {}", candidates.len()); debug!("test_candidates: untested_candidates: {}", candidates.len());
// HACK(matthewjasper) This is a closure so that we can let the test // HACK(matthewjasper) This is a closure so that we can let the test
// create its blocks before the rest of the match. This currently // create its blocks before the rest of the match. This currently
@ -2274,4 +2274,75 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug!("declare_binding: vars={:?}", locals); debug!("declare_binding: vars={:?}", locals);
self.var_indices.insert(var_id, locals); self.var_indices.insert(var_id, locals);
} }
pub(crate) fn ast_let_else(
&mut self,
mut block: BasicBlock,
init: &Expr<'tcx>,
initializer_span: Span,
else_block: &Block,
visibility_scope: Option<SourceScope>,
remainder_span: Span,
pattern: &Pat<'tcx>,
) -> BlockAnd<()> {
let scrutinee = unpack!(block = self.lower_scrutinee(block, init, initializer_span));
let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) };
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
self.declare_bindings(
visibility_scope,
remainder_span,
pattern,
ArmHasGuard(false),
Some((None, initializer_span)),
);
let mut candidate = Candidate::new(scrutinee.clone(), pattern, false);
let fake_borrow_temps = self.lower_match_tree(
block,
initializer_span,
pattern.span,
false,
&mut [&mut candidate, &mut wildcard],
);
// This block is for the matching case
let matching = self.bind_pattern(
self.source_info(pattern.span),
candidate,
None,
&fake_borrow_temps,
initializer_span,
None,
None,
None,
);
// This block is for the failure case
let failure = self.bind_pattern(
self.source_info(else_block.span),
wildcard,
None,
&fake_borrow_temps,
initializer_span,
None,
None,
None,
);
// This place is not really used because this destination place
// should never be used to take values at the end of the failure
// block.
let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
let failure_block;
unpack!(
failure_block = self.ast_block(
dummy_place,
failure,
else_block,
self.source_info(else_block.span),
)
);
self.cfg.terminate(
failure_block,
self.source_info(else_block.span),
TerminatorKind::Unreachable,
);
matching.unit()
}
} }

View file

@ -74,6 +74,8 @@ impl<'tcx> Cx<'tcx> {
)), )),
}; };
let else_block = local.els.map(|els| self.mirror_block(els));
let mut pattern = self.pattern_from_hir(local.pat); let mut pattern = self.pattern_from_hir(local.pat);
debug!(?pattern); debug!(?pattern);
@ -110,6 +112,7 @@ impl<'tcx> Cx<'tcx> {
}, },
pattern, pattern,
initializer: local.init.map(|init| self.mirror_expr(init)), initializer: local.init.map(|init| self.mirror_expr(init)),
else_block,
lint_level: LintLevel::Explicit(local.hir_id), lint_level: LintLevel::Explicit(local.hir_id),
}, },
opt_destruction_scope: opt_dxn_ext, opt_destruction_scope: opt_dxn_ext,

View file

@ -21,7 +21,7 @@ use rustc_session::lint::builtin::{
}; };
use rustc_session::Session; use rustc_session::Session;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::{BytePos, DesugaringKind, ExpnKind, Span}; use rustc_span::{BytePos, Span};
pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
let body_id = match def_id.as_local() { let body_id = match def_id.as_local() {
@ -77,6 +77,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) { fn visit_local(&mut self, loc: &'tcx hir::Local<'tcx>) {
intravisit::walk_local(self, loc); intravisit::walk_local(self, loc);
let els = loc.els;
if let Some(init) = loc.init && els.is_some() {
self.check_let(&loc.pat, init, loc.span);
}
let (msg, sp) = match loc.source { let (msg, sp) = match loc.source {
hir::LocalSource::Normal => ("local binding", Some(loc.span)), hir::LocalSource::Normal => ("local binding", Some(loc.span)),
@ -84,7 +88,9 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
hir::LocalSource::AwaitDesugar => ("`await` future binding", None), hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None), hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
}; };
self.check_irrefutable(&loc.pat, msg, sp); if els.is_none() {
self.check_irrefutable(&loc.pat, msg, sp);
}
} }
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
@ -1125,17 +1131,16 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
}) if Some(*hir_id) == pat_id => { }) if Some(*hir_id) == pat_id => {
return LetSource::IfLetGuard; return LetSource::IfLetGuard;
} }
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => {
let expn_data = span.ctxt().outer_expn_data();
if let ExpnKind::Desugaring(DesugaringKind::LetElse) = expn_data.kind {
return LetSource::LetElse(expn_data.call_site);
}
}
_ => {} _ => {}
} }
let parent_parent = hir.get_parent_node(parent); let parent_parent = hir.get_parent_node(parent);
let parent_parent_node = hir.get(parent_parent); let parent_parent_node = hir.get(parent_parent);
if let hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) =
parent_parent_node
{
return LetSource::LetElse(*span);
}
let parent_parent_parent = hir.get_parent_node(parent_parent); let parent_parent_parent = hir.get_parent_node(parent_parent);
let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent); let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent);

View file

@ -102,7 +102,7 @@ fn is_needs_drop_and_init<'tcx>(
let field_needs_drop_and_init = |(f, f_ty, mpi)| { let field_needs_drop_and_init = |(f, f_ty, mpi)| {
let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f)); let child = move_path_children_matching(move_data, mpi, |x| x.is_field_to(f));
let Some(mpi) = child else { let Some(mpi) = child else {
return f_ty.needs_drop(tcx, param_env); return Ty::needs_drop(f_ty, tcx, param_env);
}; };
is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi) is_needs_drop_and_init(tcx, param_env, maybe_inits, move_data, f_ty, mpi)

View file

@ -3028,6 +3028,11 @@ impl<'a> Parser<'a> {
} }
}; };
let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.is_shorthand);
// A shorthand field can be turned into a full field with `:`.
// We should point this out.
self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon));
match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) { match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) {
Ok(_) => { Ok(_) => {
if let Some(f) = parsed_field.or(recovery_field) { if let Some(f) = parsed_field.or(recovery_field) {
@ -3048,6 +3053,19 @@ impl<'a> Parser<'a> {
",", ",",
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} else if is_shorthand
&& (AssocOp::from_token(&self.token).is_some()
|| matches!(&self.token.kind, token::OpenDelim(_))
|| self.token.kind == token::Dot)
{
// Looks like they tried to write a shorthand, complex expression.
let ident = parsed_field.expect("is_shorthand implies Some").ident;
e.span_suggestion(
ident.span.shrink_to_lo(),
"try naming a field",
&format!("{ident}: "),
Applicability::HasPlaceholders,
);
} }
} }
if !recover { if !recover {

View file

@ -1808,21 +1808,6 @@ impl CheckAttrVisitor<'_> {
_ => ("a", "struct, enum, or union"), _ => ("a", "struct, enum, or union"),
} }
} }
sym::no_niche => {
if !self.tcx.features().enabled(sym::no_niche) {
feature_err(
&self.tcx.sess.parse_sess,
sym::no_niche,
hint.span(),
"the attribute `repr(no_niche)` is currently unstable",
)
.emit();
}
match target {
Target::Struct | Target::Enum => continue,
_ => ("a", "struct or enum"),
}
}
sym::i8 sym::i8
| sym::u8 | sym::u8
| sym::i16 | sym::i16
@ -1870,10 +1855,8 @@ impl CheckAttrVisitor<'_> {
// This is not ideal, but tracking precisely which ones are at fault is a huge hassle. // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
let hint_spans = hints.iter().map(|hint| hint.span()); let hint_spans = hints.iter().map(|hint| hint.span());
// Error on repr(transparent, <anything else apart from no_niche>). // Error on repr(transparent, <anything else>).
let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche; if is_transparent && hints.len() > 1 {
let non_no_niche_count = hints.iter().filter(non_no_niche).count();
if is_transparent && non_no_niche_count > 1 {
let hint_spans: Vec<_> = hint_spans.clone().collect(); let hint_spans: Vec<_> = hint_spans.clone().collect();
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,

View file

@ -278,7 +278,7 @@ impl<'tcx> IrMaps<'tcx> {
pats.extend(inner_pat.iter()); pats.extend(inner_pat.iter());
} }
Struct(_, fields, _) => { Struct(_, fields, _) => {
let (short, not_short): (Vec<&_>, Vec<&_>) = let (short, not_short): (Vec<_>, _) =
fields.iter().partition(|f| f.is_shorthand); fields.iter().partition(|f| f.is_shorthand);
shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id)); shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id));
pats.extend(not_short.iter().map(|f| f.pat)); pats.extend(not_short.iter().map(|f| f.pat));
@ -298,7 +298,7 @@ impl<'tcx> IrMaps<'tcx> {
} }
} }
return shorthand_field_ids; shorthand_field_ids
} }
fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
@ -368,6 +368,9 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
self.add_from_pat(&local.pat); self.add_from_pat(&local.pat);
if local.els.is_some() {
self.add_live_node_for_node(local.hir_id, ExprNode(local.span, local.hir_id));
}
intravisit::walk_local(self, local); intravisit::walk_local(self, local);
} }
@ -800,8 +803,40 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// initialization, which is mildly more complex than checking // initialization, which is mildly more complex than checking
// once at the func header but otherwise equivalent. // once at the func header but otherwise equivalent.
let succ = self.propagate_through_opt_expr(local.init, succ); if let Some(els) = local.els {
self.define_bindings_in_pat(&local.pat, succ) // Eventually, `let pat: ty = init else { els };` is mostly equivalent to
// `let (bindings, ...) = match init { pat => (bindings, ...), _ => els };`
// except that extended lifetime applies at the `init` location.
//
// (e)
// |
// v
// (expr)
// / \
// | |
// v v
// bindings els
// |
// v
// ( succ )
//
if let Some(init) = local.init {
let else_ln = self.propagate_through_block(els, succ);
let ln = self.live_node(local.hir_id, local.span);
self.init_from_succ(ln, succ);
self.merge_from_succ(ln, else_ln);
let succ = self.propagate_through_expr(init, ln);
self.define_bindings_in_pat(&local.pat, succ)
} else {
span_bug!(
stmt.span,
"variable is uninitialized but an unexpected else branch is found"
)
}
} else {
let succ = self.propagate_through_opt_expr(local.init, succ);
self.define_bindings_in_pat(&local.pat, succ)
}
} }
hir::StmtKind::Item(..) => succ, hir::StmtKind::Item(..) => succ,
hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
@ -1121,7 +1156,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// (rvalue) || (rvalue) // (rvalue) || (rvalue)
// | || | // | || |
// v || v // v || v
// (write of place) || (place components) // (write of place) || (place components)
// | || | // | || |
// v || v // v || v
// (succ) || (succ) // (succ) || (succ)

View file

@ -508,7 +508,7 @@ impl<'a> Resolver<'a> {
E0401, E0401,
"can't use generic parameters from outer function", "can't use generic parameters from outer function",
); );
err.span_label(span, "use of generic parameter from outer function".to_string()); err.span_label(span, "use of generic parameter from outer function");
let sm = self.session.source_map(); let sm = self.session.source_map();
match outer_res { match outer_res {
@ -990,7 +990,7 @@ impl<'a> Resolver<'a> {
E0735, E0735,
"generic parameters cannot use `Self` in their defaults" "generic parameters cannot use `Self` in their defaults"
); );
err.span_label(span, "`Self` in generic parameter default".to_string()); err.span_label(span, "`Self` in generic parameter default");
err err
} }
ResolutionError::UnreachableLabel { name, definition_span, suggestion } => { ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {

View file

@ -82,14 +82,7 @@ impl<'tcx> DumpVisitor<'tcx> {
pub fn new(save_ctxt: SaveContext<'tcx>) -> DumpVisitor<'tcx> { pub fn new(save_ctxt: SaveContext<'tcx>) -> DumpVisitor<'tcx> {
let span_utils = SpanUtils::new(&save_ctxt.tcx.sess); let span_utils = SpanUtils::new(&save_ctxt.tcx.sess);
let dumper = Dumper::new(save_ctxt.config.clone()); let dumper = Dumper::new(save_ctxt.config.clone());
DumpVisitor { DumpVisitor { tcx: save_ctxt.tcx, save_ctxt, dumper, span: span_utils }
tcx: save_ctxt.tcx,
save_ctxt,
dumper,
span: span_utils,
// mac_defs: FxHashSet::default(),
// macro_calls: FxHashSet::default(),
}
} }
pub fn analysis(&self) -> &rls_data::Analysis { pub fn analysis(&self) -> &rls_data::Analysis {
@ -1425,9 +1418,10 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
self.process_macro_use(l.span); self.process_macro_use(l.span);
self.process_var_decl(&l.pat); self.process_var_decl(&l.pat);
// Just walk the initializer and type (don't want to walk the pattern again). // Just walk the initializer, the else branch and type (don't want to walk the pattern again).
walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_ty, &l.ty);
walk_list!(self, visit_expr, &l.init); walk_list!(self, visit_expr, &l.init);
walk_list!(self, visit_block, l.els);
} }
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {

View file

@ -194,6 +194,9 @@ pub struct Session {
/// Set of enabled features for the current target. /// Set of enabled features for the current target.
pub target_features: FxHashSet<Symbol>, pub target_features: FxHashSet<Symbol>,
/// Set of enabled features for the current target, including unstable ones.
pub unstable_target_features: FxHashSet<Symbol>,
} }
pub struct PerfStats { pub struct PerfStats {
@ -1390,6 +1393,7 @@ pub fn build_session(
miri_unleashed_features: Lock::new(Default::default()), miri_unleashed_features: Lock::new(Default::default()),
asm_arch, asm_arch,
target_features: FxHashSet::default(), target_features: FxHashSet::default(),
unstable_target_features: FxHashSet::default(),
}; };
validate_commandline_args_with_session_available(&sess); validate_commandline_args_with_session_available(&sess);

View file

@ -1141,7 +1141,6 @@ pub enum DesugaringKind {
Async, Async,
Await, Await,
ForLoop, ForLoop,
LetElse,
WhileLoop, WhileLoop,
} }
@ -1157,7 +1156,6 @@ impl DesugaringKind {
DesugaringKind::YeetExpr => "`do yeet` expression", DesugaringKind::YeetExpr => "`do yeet` expression",
DesugaringKind::OpaqueTy => "`impl Trait`", DesugaringKind::OpaqueTy => "`impl Trait`",
DesugaringKind::ForLoop => "`for` loop", DesugaringKind::ForLoop => "`for` loop",
DesugaringKind::LetElse => "`let...else`",
DesugaringKind::WhileLoop => "`while` loop", DesugaringKind::WhileLoop => "`while` loop",
} }
} }

View file

@ -980,7 +980,6 @@ symbols! {
no_link, no_link,
no_main, no_main,
no_mangle, no_mangle,
no_niche,
no_sanitize, no_sanitize,
no_stack_check, no_stack_check,
no_start, no_start,
@ -1153,7 +1152,6 @@ symbols! {
repr128, repr128,
repr_align, repr_align,
repr_align_enum, repr_align_enum,
repr_no_niche,
repr_packed, repr_packed,
repr_simd, repr_simd,
repr_transparent, repr_transparent,

View file

@ -1311,7 +1311,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
visitor.visit_body(&body); visitor.visit_body(&body);
let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap(); let typeck_results = self.in_progress_typeck_results.map(|t| t.borrow()).unwrap();
let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id) else { return false; }; let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
let ret_types = visitor let ret_types = visitor
.returns .returns

View file

@ -997,26 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
coerce.coerce(self, &self.misc(sp), then_expr, then_ty); coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
if let Some(else_expr) = opt_else_expr { if let Some(else_expr) = opt_else_expr {
let else_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) { let else_ty = self.check_expr_with_expectation(else_expr, expected);
// todo introduce `check_expr_with_expectation(.., Expectation::LetElse)`
// for errors that point to the offending expression rather than the entire block.
// We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no
// way to detect that the expected type originated from let-else and provide
// a customized error.
let else_ty = self.check_expr(else_expr);
let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse);
if let Some(mut err) =
self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
{
err.emit();
self.tcx.ty_error()
} else {
else_ty
}
} else {
self.check_expr_with_expectation(else_expr, expected)
};
let else_diverges = self.diverges.get(); let else_diverges = self.diverges.get();
let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected); let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);

View file

@ -1215,6 +1215,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr); self.check_pat_top(&decl.pat, decl_ty, ty_span, origin_expr);
let pat_ty = self.node_ty(decl.pat.hir_id); let pat_ty = self.node_ty(decl.pat.hir_id);
self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty); self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, decl_ty, pat_ty);
if let Some(blk) = decl.els {
let previous_diverges = self.diverges.get();
let else_ty = self.check_block_with_expected(blk, NoExpectation);
let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
if let Some(mut err) =
self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
{
err.emit();
}
self.diverges.set(previous_diverges);
}
} }
/// Type check a `let` statement. /// Type check a `let` statement.
@ -1236,8 +1248,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let old_has_errors = self.has_errors.replace(false); let old_has_errors = self.has_errors.replace(false);
match stmt.kind { match stmt.kind {
hir::StmtKind::Local(ref l) => { hir::StmtKind::Local(l) => {
self.check_decl_local(&l); self.check_decl_local(l);
} }
// Ignore for now. // Ignore for now.
hir::StmtKind::Item(_) => {} hir::StmtKind::Item(_) => {}

View file

@ -16,19 +16,20 @@ pub(super) struct Declaration<'a> {
pub ty: Option<&'a hir::Ty<'a>>, pub ty: Option<&'a hir::Ty<'a>>,
pub span: Span, pub span: Span,
pub init: Option<&'a hir::Expr<'a>>, pub init: Option<&'a hir::Expr<'a>>,
pub els: Option<&'a hir::Block<'a>>,
} }
impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> { impl<'a> From<&'a hir::Local<'a>> for Declaration<'a> {
fn from(local: &'a hir::Local<'a>) -> Self { fn from(local: &'a hir::Local<'a>) -> Self {
let hir::Local { hir_id, pat, ty, span, init, .. } = *local; let hir::Local { hir_id, pat, ty, span, init, els, source: _ } = *local;
Declaration { hir_id, pat, ty, span, init } Declaration { hir_id, pat, ty, span, init, els }
} }
} }
impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> { impl<'a> From<&'a hir::Let<'a>> for Declaration<'a> {
fn from(let_expr: &'a hir::Let<'a>) -> Self { fn from(let_expr: &'a hir::Let<'a>) -> Self {
let hir::Let { hir_id, pat, ty, span, init } = *let_expr; let hir::Let { hir_id, pat, ty, span, init } = *let_expr;
Declaration { hir_id, pat, ty, span, init: Some(init) } Declaration { hir_id, pat, ty, span, init: Some(init), els: None }
} }
} }
@ -101,7 +102,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
// Add explicitly-declared locals. // Add explicitly-declared locals.
fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
self.declare(local.into()); self.declare(local.into());
intravisit::walk_local(self, local); intravisit::walk_local(self, local)
} }
fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) { fn visit_let_expr(&mut self, let_expr: &'tcx hir::Let<'tcx>) {

View file

@ -460,6 +460,7 @@ fn resolve_local<'tcx>(
visitor: &mut RegionResolutionVisitor<'tcx>, visitor: &mut RegionResolutionVisitor<'tcx>,
pat: Option<&'tcx hir::Pat<'tcx>>, pat: Option<&'tcx hir::Pat<'tcx>>,
init: Option<&'tcx hir::Expr<'tcx>>, init: Option<&'tcx hir::Expr<'tcx>>,
els: Option<&'tcx hir::Block<'tcx>>,
) { ) {
debug!("resolve_local(pat={:?}, init={:?})", pat, init); debug!("resolve_local(pat={:?}, init={:?})", pat, init);
@ -537,13 +538,18 @@ fn resolve_local<'tcx>(
} }
} }
// Make sure we visit the initializer first, so expr_and_pat_count remains correct // Make sure we visit the initializer first, so expr_and_pat_count remains correct.
// The correct order, as shared between generator_interior, drop_ranges and intravisitor,
// is to walk initializer, followed by pattern bindings, finally followed by the `else` block.
if let Some(expr) = init { if let Some(expr) = init {
visitor.visit_expr(expr); visitor.visit_expr(expr);
} }
if let Some(pat) = pat { if let Some(pat) = pat {
visitor.visit_pat(pat); visitor.visit_pat(pat);
} }
if let Some(els) = els {
visitor.visit_block(els);
}
/// Returns `true` if `pat` match the `P&` non-terminal. /// Returns `true` if `pat` match the `P&` non-terminal.
/// ///
@ -764,7 +770,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
// (i.e., `'static`), which means that after `g` returns, it drops, // (i.e., `'static`), which means that after `g` returns, it drops,
// and all the associated destruction scope rules apply. // and all the associated destruction scope rules apply.
self.cx.var_parent = None; self.cx.var_parent = None;
resolve_local(self, None, Some(&body.value)); resolve_local(self, None, Some(&body.value), None);
} }
if body.generator_kind.is_some() { if body.generator_kind.is_some() {
@ -791,7 +797,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
resolve_expr(self, ex); resolve_expr(self, ex);
} }
fn visit_local(&mut self, l: &'tcx Local<'tcx>) { fn visit_local(&mut self, l: &'tcx Local<'tcx>) {
resolve_local(self, Some(&l.pat), l.init); resolve_local(self, Some(&l.pat), l.init, l.els)
} }
} }

View file

@ -3196,7 +3196,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
/// Computes the set of target features used in a function for the purposes of /// Computes the set of target features used in a function for the purposes of
/// inline assembly. /// inline assembly.
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> { fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
let mut target_features = tcx.sess.target_features.clone(); let mut target_features = tcx.sess.unstable_target_features.clone();
if tcx.def_kind(did).has_codegen_attrs() { if tcx.def_kind(did).has_codegen_attrs() {
let attrs = tcx.codegen_fn_attrs(did); let attrs = tcx.codegen_fn_attrs(did);
target_features.extend(&attrs.target_features); target_features.extend(&attrs.target_features);

View file

@ -2,7 +2,10 @@
//! normal visitor, which just walks the entire body in one shot, the //! normal visitor, which just walks the entire body in one shot, the
//! `ExprUseVisitor` determines how expressions are being used. //! `ExprUseVisitor` determines how expressions are being used.
use std::slice::from_ref;
use hir::def::DefKind; use hir::def::DefKind;
use hir::Expr;
// Export these here so that Clippy can use them. // Export these here so that Clippy can use them.
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
@ -252,96 +255,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
} }
hir::ExprKind::Let(hir::Let { pat, init, .. }) => { hir::ExprKind::Let(hir::Let { pat, init, .. }) => {
self.walk_local(init, pat, |t| t.borrow_expr(init, ty::ImmBorrow)); self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow))
} }
hir::ExprKind::Match(ref discr, arms, _) => { hir::ExprKind::Match(ref discr, arms, _) => {
let discr_place = return_if_err!(self.mc.cat_expr(discr)); let discr_place = return_if_err!(self.mc.cat_expr(discr));
self.maybe_read_scrutinee(
// Matching should not always be considered a use of the place, hence discr,
// discr does not necessarily need to be borrowed. discr_place.clone(),
// We only want to borrow discr if the pattern contain something other arms.iter().map(|arm| arm.pat),
// than wildcards. );
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
let mut needs_to_be_read = false;
for arm in arms.iter() {
return_if_err!(mc.cat_pattern(discr_place.clone(), arm.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
// a wildcard for the purpose of borrowing discr.
if opt_sub_pat.is_none() {
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
let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
match res {
Res::Def(DefKind::Const, _)
| Res::Def(DefKind::AssocConst, _) => {
// Named constants have to be equated with the value
// being matched, so that's a read of the value being matched.
//
// FIXME: We don't actually reads for ZSTs.
needs_to_be_read = true;
}
_ => {
// Otherwise, this is a struct/enum variant, and so it's
// only a read if we need to read the discriminant.
needs_to_be_read |= is_multivariant_adt(place.place.ty());
}
}
}
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
// against a multivariant enum or struct. In that case, we have to read
// the discriminant. Otherwise this kind of pattern doesn't actually
// read anything (we'll get invoked for the `...`, which may indeed
// perform some reads).
let place_ty = place.place.ty();
needs_to_be_read |= is_multivariant_adt(place_ty);
}
PatKind::Lit(_) | PatKind::Range(..) => {
// If the PatKind is a Lit or a Range then we want
// to borrow discr.
needs_to_be_read = true;
}
PatKind::Or(_)
| PatKind::Box(_)
| PatKind::Slice(..)
| PatKind::Ref(..)
| PatKind::Wild => {
// If the PatKind is Or, Box, Slice or Ref, the decision is made later
// as these patterns contains subpatterns
// If the PatKind is Wild, the decision is made based on the other patterns being
// examined
}
}
}));
}
if needs_to_be_read {
self.borrow_expr(discr, ty::ImmBorrow);
} else {
let closure_def_id = match discr_place.place.base {
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
_ => None,
};
self.delegate.fake_read(
&discr_place,
FakeReadCause::ForMatchedPlace(closure_def_id),
discr_place.hir_id,
);
// We always want to walk the discriminant. We want to make sure, for instance,
// that the discriminant has been initialized.
self.walk_expr(discr);
}
// treatment of the discriminant is handled while walking the arms. // treatment of the discriminant is handled while walking the arms.
for arm in arms { for arm in arms {
@ -453,8 +376,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
match stmt.kind { match stmt.kind {
hir::StmtKind::Local(hir::Local { pat, init: Some(expr), .. }) => { hir::StmtKind::Local(hir::Local { pat, init: Some(expr), els, .. }) => {
self.walk_local(expr, pat, |_| {}); self.walk_local(expr, pat, *els, |_| {})
} }
hir::StmtKind::Local(_) => {} hir::StmtKind::Local(_) => {}
@ -470,13 +393,114 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
} }
} }
fn walk_local<F>(&mut self, expr: &hir::Expr<'_>, pat: &hir::Pat<'_>, mut f: F) fn maybe_read_scrutinee<'t>(
where &mut self,
discr: &Expr<'_>,
discr_place: PlaceWithHirId<'tcx>,
pats: impl Iterator<Item = &'t hir::Pat<'t>>,
) {
// Matching should not always be considered a use of the place, hence
// discr does not necessarily need to be borrowed.
// We only want to borrow discr if the pattern contain something other
// than wildcards.
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
let mut needs_to_be_read = false;
for pat in pats {
return_if_err!(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
// a wildcard for the purpose of borrowing discr.
if opt_sub_pat.is_none() {
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
let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
match res {
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
// Named constants have to be equated with the value
// being matched, so that's a read of the value being matched.
//
// FIXME: We don't actually reads for ZSTs.
needs_to_be_read = true;
}
_ => {
// Otherwise, this is a struct/enum variant, and so it's
// only a read if we need to read the discriminant.
needs_to_be_read |= is_multivariant_adt(place.place.ty());
}
}
}
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
// against a multivariant enum or struct. In that case, we have to read
// the discriminant. Otherwise this kind of pattern doesn't actually
// read anything (we'll get invoked for the `...`, which may indeed
// perform some reads).
let place_ty = place.place.ty();
needs_to_be_read |= is_multivariant_adt(place_ty);
}
PatKind::Lit(_) | PatKind::Range(..) => {
// If the PatKind is a Lit or a Range then we want
// to borrow discr.
needs_to_be_read = true;
}
PatKind::Or(_)
| PatKind::Box(_)
| PatKind::Slice(..)
| PatKind::Ref(..)
| PatKind::Wild => {
// If the PatKind is Or, Box, Slice or Ref, the decision is made later
// as these patterns contains subpatterns
// If the PatKind is Wild, the decision is made based on the other patterns being
// examined
}
}
}));
}
if needs_to_be_read {
self.borrow_expr(discr, ty::ImmBorrow);
} else {
let closure_def_id = match discr_place.place.base {
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
_ => None,
};
self.delegate.fake_read(
&discr_place,
FakeReadCause::ForMatchedPlace(closure_def_id),
discr_place.hir_id,
);
// We always want to walk the discriminant. We want to make sure, for instance,
// that the discriminant has been initialized.
self.walk_expr(discr);
}
}
fn walk_local<F>(
&mut self,
expr: &hir::Expr<'_>,
pat: &hir::Pat<'_>,
els: Option<&hir::Block<'_>>,
mut f: F,
) where
F: FnMut(&mut Self), F: FnMut(&mut Self),
{ {
self.walk_expr(expr); self.walk_expr(expr);
let expr_place = return_if_err!(self.mc.cat_expr(expr)); let expr_place = return_if_err!(self.mc.cat_expr(expr));
f(self); f(self);
if let Some(els) = els {
// borrowing because we need to test the descriminant
self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter());
self.walk_block(els)
}
self.walk_irrefutable_pat(&expr_place, &pat); self.walk_irrefutable_pat(&expr_place, &pat);
} }
@ -667,7 +691,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
if let PatKind::Binding(_, canonical_id, ..) = pat.kind { if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
debug!("walk_pat: binding place={:?} pat={:?}", place, pat,); debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
if let Some(bm) = if let Some(bm) =
mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
{ {

View file

@ -1856,7 +1856,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
#[lang = "unsafe_cell"] #[lang = "unsafe_cell"]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[repr(transparent)] #[repr(transparent)]
#[repr(no_niche)] // rust-lang/rust#68303.
pub struct UnsafeCell<T: ?Sized> { pub struct UnsafeCell<T: ?Sized> {
value: T, value: T,
} }

View file

@ -191,7 +191,6 @@
#![feature(never_type)] #![feature(never_type)]
#![feature(no_core)] #![feature(no_core)]
#![feature(no_coverage)] // rust-lang/rust#84605 #![feature(no_coverage)] // rust-lang/rust#84605
#![feature(no_niche)] // rust-lang/rust#68303
#![feature(platform_intrinsics)] #![feature(platform_intrinsics)]
#![feature(prelude_import)] #![feature(prelude_import)]
#![feature(repr_simd)] #![feature(repr_simd)]

View file

@ -0,0 +1,21 @@
// compile-flags: --target thumbv6m-none-eabi
// needs-llvm-components: arm
// needs-asm-support
#![feature(no_core, lang_items, rustc_attrs)]
#![no_core]
#![crate_type = "rlib"]
#[rustc_builtin_macro]
macro_rules! asm {
() => {};
}
#[lang = "sized"]
trait Sized {}
pub fn foo() {
unsafe {
asm!("", in("r8") 0);
//~^ cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code
}
}

View file

@ -0,0 +1,8 @@
error: cannot use register `r8`: high registers (r8+) can only be used as clobbers in Thumb-1 code
--> $DIR/issue-99071.rs:18:18
|
LL | asm!("", in("r8") 0);
| ^^^^^^^^^^
error: aborting due to previous error

View file

@ -0,0 +1,53 @@
// edition:2021
#![feature(let_else)]
use std::rc::Rc;
async fn foo(x: Option<bool>) {
let Some(_) = x else {
let r = Rc::new(());
bar().await
};
}
async fn bar() -> ! {
panic!()
}
fn is_send<T: Send>(_: T) {}
async fn foo2(x: Option<bool>) {
let Some(_) = x else {
bar2(Rc::new(())).await
};
}
async fn bar2<T>(_: T) -> ! {
panic!()
}
async fn foo3(x: Option<bool>) {
let Some(_) = x else {
(Rc::new(()), bar().await);
return;
};
}
async fn foo4(x: Option<bool>) {
let Some(_) = x else {
let r = Rc::new(());
bar().await;
println!("{:?}", r);
return;
};
}
fn main() {
is_send(foo(Some(true)));
//~^ ERROR future cannot be sent between threads safely
is_send(foo2(Some(true)));
//~^ ERROR future cannot be sent between threads safely
is_send(foo3(Some(true)));
//~^ ERROR future cannot be sent between threads safely
is_send(foo4(Some(true)));
//~^ ERROR future cannot be sent between threads safely
}

View file

@ -0,0 +1,94 @@
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:45:13
|
LL | is_send(foo(Some(true)));
| ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:8:14
|
LL | let r = Rc::new(());
| - has type `Rc<()>` which is not `Send`
LL | bar().await
| ^^^^^^ await occurs here, with `r` maybe used later
LL | };
| - `r` is later dropped here
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:16:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:47:13
|
LL | is_send(foo2(Some(true)));
| ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:20:26
|
LL | bar2(Rc::new(())).await
| ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
| |
| has type `Rc<()>` which is not `Send`
LL | };
| - `Rc::new(())` is later dropped here
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:16:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:49:13
|
LL | is_send(foo3(Some(true)));
| ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:30:28
|
LL | (Rc::new(()), bar().await);
| ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
| |
| has type `Rc<()>` which is not `Send`
note: `Rc::new(())` is later dropped here
--> $DIR/async-await-let-else.rs:30:35
|
LL | (Rc::new(()), bar().await);
| ^
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:16:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: future cannot be sent between threads safely
--> $DIR/async-await-let-else.rs:51:13
|
LL | is_send(foo4(Some(true)));
| ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:38:14
|
LL | let r = Rc::new(());
| - has type `Rc<()>` which is not `Send`
LL | bar().await;
| ^^^^^^ await occurs here, with `r` maybe used later
...
LL | };
| - `r` is later dropped here
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:16:15
|
LL | fn is_send<T: Send>(_: T) {}
| ^^^^ required by this bound in `is_send`
error: aborting due to 4 previous errors

View file

@ -3,30 +3,80 @@
// test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same // test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same
// size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes). // size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes).
// run-pass // check-pass
// compile-flags: --crate-type=lib
// only-x86
#![feature(no_niche)] #![feature(repr_simd)]
use std::cell::UnsafeCell; use std::cell::{UnsafeCell, RefCell, Cell};
use std::mem::size_of; use std::mem::size_of;
use std::num::NonZeroU32 as N32; use std::num::NonZeroU32 as N32;
use std::sync::{Mutex, RwLock};
struct Wrapper<T>(T); struct Wrapper<T>(T);
#[repr(transparent)] #[repr(transparent)]
struct Transparent<T>(T); struct Transparent<T>(T);
#[repr(no_niche)] struct NoNiche<T>(UnsafeCell<T>);
struct NoNiche<T>(T);
fn main() { struct Size<const S: usize>;
assert_eq!(size_of::<Option<Wrapper<u32>>>(), 8);
assert_eq!(size_of::<Option<Wrapper<N32>>>(), 4);
assert_eq!(size_of::<Option<Transparent<u32>>>(), 8);
assert_eq!(size_of::<Option<Transparent<N32>>>(), 4);
assert_eq!(size_of::<Option<NoNiche<u32>>>(), 8);
assert_eq!(size_of::<Option<NoNiche<N32>>>(), 8);
assert_eq!(size_of::<Option<UnsafeCell<u32>>>(), 8); macro_rules! check_sizes {
assert_eq!(size_of::<Option<UnsafeCell<N32>>>(), 8); (check_one_specific_size: $ty:ty, $size:expr) => {
const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>;
};
// Any tests run on `UnsafeCell` must be the same for `Cell`
(UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => {
check_sizes!(Cell<$ty>: $size => $optioned_size);
check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size);
};
($ty:ty: $size:expr => $optioned_size:expr) => {
check_sizes!(@actual_check: $ty: $size => $optioned_size);
};
// This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish
// it from other branches and not accidentally match any.
(@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => {
check_sizes!(check_one_specific_size: $ty, $size);
check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size);
check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty);
};
// only check that there is no niche (size goes up when wrapped in an option),
// don't check actual sizes
($ty:ty) => {
check_sizes!(check_no_niche_opt: true, $ty);
};
(check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => {
const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::<Option<$ty>>()); };
};
} }
const PTR_SIZE: usize = std::mem::size_of::<*const ()>();
check_sizes!(Wrapper<u32>: 4 => 8);
check_sizes!(Wrapper<N32>: 4 => 4); // (✓ niche opt)
check_sizes!(Transparent<u32>: 4 => 8);
check_sizes!(Transparent<N32>: 4 => 4); // (✓ niche opt)
check_sizes!(NoNiche<u32>: 4 => 8);
check_sizes!(NoNiche<N32>: 4 => 8);
check_sizes!(UnsafeCell<u32>: 4 => 8);
check_sizes!(UnsafeCell<N32>: 4 => 8);
check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2);
check_sizes!( RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3);
check_sizes!(RwLock<&()>);
check_sizes!(Mutex<&()>);
check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3);
check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3);
trait Trait {}
check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3);
#[repr(simd)]
pub struct Vec4<T>([T; 4]);
check_sizes!(UnsafeCell<Vec4<N32>>: 16 => 32);

View file

@ -2,7 +2,9 @@ error[E0308]: mismatched types
--> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37 --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37
| |
LL | let Some(n): &mut Option<i32> = &&Some(5i32) else { return }; LL | let Some(n): &mut Option<i32> = &&Some(5i32) else { return };
| ^^^^^^^^^^^^ types differ in mutability | ---------------- ^^^^^^^^^^^^ types differ in mutability
| |
| expected due to this
| |
= note: expected mutable reference `&mut Option<i32>` = note: expected mutable reference `&mut Option<i32>`
found reference `&&Option<i32>` found reference `&&Option<i32>`
@ -11,7 +13,9 @@ error[E0308]: mismatched types
--> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37 --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37
| |
LL | let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return }; LL | let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return };
| ^^^^^^^^^^^^^^^^ types differ in mutability | ---------------- ^^^^^^^^^^^^^^^^ types differ in mutability
| |
| expected due to this
| |
= note: expected mutable reference `&mut Option<i32>` = note: expected mutable reference `&mut Option<i32>`
found reference `&&mut Option<i32>` found reference `&&mut Option<i32>`

View file

@ -1,8 +1,8 @@
error: unused variable: `x` error: unused variable: `x`
--> $DIR/let-else-check.rs:18:9 --> $DIR/let-else-check.rs:14:13
| |
LL | let x = 1; LL | let x = 1;
| ^ help: if this is intentional, prefix it with an underscore: `_x` | ^ help: if this is intentional, prefix it with an underscore: `_x`
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/let-else-check.rs:3:9 --> $DIR/let-else-check.rs:3:9
@ -11,10 +11,10 @@ LL | #![deny(unused_variables)]
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
error: unused variable: `x` error: unused variable: `x`
--> $DIR/let-else-check.rs:14:13 --> $DIR/let-else-check.rs:18:9
| |
LL | let x = 1; LL | let x = 1;
| ^ help: if this is intentional, prefix it with an underscore: `_x` | ^ help: if this is intentional, prefix it with an underscore: `_x`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -1,8 +1,11 @@
error[E0308]: `else` clause of `let...else` does not diverge error[E0308]: `else` clause of `let...else` does not diverge
--> $DIR/let-else-non-diverging.rs:12:32 --> $DIR/let-else-non-diverging.rs:4:32
| |
LL | let Some(x) = Some(1) else { Some(2) }; LL | let Some(x) = Some(1) else {
| ^^^^^^^^^^^ expected `!`, found enum `Option` | ________________________________^
LL | | Some(2)
LL | | };
| |_____^ expected `!`, found enum `Option`
| |
= note: expected type `!` = note: expected type `!`
found enum `Option<{integer}>` found enum `Option<{integer}>`
@ -26,13 +29,10 @@ LL | | };
= help: ...or use `match` instead of `let...else` = help: ...or use `match` instead of `let...else`
error[E0308]: `else` clause of `let...else` does not diverge error[E0308]: `else` clause of `let...else` does not diverge
--> $DIR/let-else-non-diverging.rs:4:32 --> $DIR/let-else-non-diverging.rs:12:32
| |
LL | let Some(x) = Some(1) else { LL | let Some(x) = Some(1) else { Some(2) };
| ________________________________^ | ^^^^^^^^^^^ expected `!`, found enum `Option`
LL | | Some(2)
LL | | };
| |_____^ expected `!`, found enum `Option`
| |
= note: expected type `!` = note: expected type `!`
found enum `Option<{integer}>` found enum `Option<{integer}>`

View file

@ -20,7 +20,9 @@ error[E0308]: mismatched types
--> $DIR/let-else-ref-bindings.rs:24:34 --> $DIR/let-else-ref-bindings.rs:24:34
| |
LL | let Some(a): Option<&[u8]> = some else { return }; LL | let Some(a): Option<&[u8]> = some else { return };
| ^^^^ expected `&[u8]`, found struct `Vec` | ------------- ^^^^ expected `&[u8]`, found struct `Vec`
| |
| expected due to this
| |
= note: expected enum `Option<&[u8]>` = note: expected enum `Option<&[u8]>`
found enum `Option<Vec<u8>>` found enum `Option<Vec<u8>>`
@ -29,7 +31,9 @@ error[E0308]: mismatched types
--> $DIR/let-else-ref-bindings.rs:27:34 --> $DIR/let-else-ref-bindings.rs:27:34
| |
LL | let Some(a): Option<&[u8]> = &some else { return }; LL | let Some(a): Option<&[u8]> = &some else { return };
| ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>` | ------------- ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
| |
| expected due to this
| |
= note: expected enum `Option<&[u8]>` = note: expected enum `Option<&[u8]>`
found reference `&Option<Vec<u8>>` found reference `&Option<Vec<u8>>`
@ -56,7 +60,9 @@ error[E0308]: mismatched types
--> $DIR/let-else-ref-bindings.rs:52:38 --> $DIR/let-else-ref-bindings.rs:52:38
| |
LL | let Some(a): Option<&mut [u8]> = some else { return }; LL | let Some(a): Option<&mut [u8]> = some else { return };
| ^^^^ expected `&mut [u8]`, found struct `Vec` | ----------------- ^^^^ expected `&mut [u8]`, found struct `Vec`
| |
| expected due to this
| |
= note: expected enum `Option<&mut [u8]>` = note: expected enum `Option<&mut [u8]>`
found enum `Option<Vec<u8>>` found enum `Option<Vec<u8>>`
@ -65,7 +71,9 @@ error[E0308]: mismatched types
--> $DIR/let-else-ref-bindings.rs:55:38 --> $DIR/let-else-ref-bindings.rs:55:38
| |
LL | let Some(a): Option<&mut [u8]> = &mut some else { return }; LL | let Some(a): Option<&mut [u8]> = &mut some else { return };
| ^^^^^^^^^ expected enum `Option`, found mutable reference | ----------------- ^^^^^^^^^ expected enum `Option`, found mutable reference
| |
| expected due to this
| |
= note: expected enum `Option<&mut [u8]>` = note: expected enum `Option<&mut [u8]>`
found mutable reference `&mut Option<Vec<u8>>` found mutable reference `&mut Option<Vec<u8>>`

View file

@ -0,0 +1,25 @@
// run-pass
#![feature(let_else)]
use std::sync::atomic::{AtomicU8, Ordering};
static TRACKER: AtomicU8 = AtomicU8::new(0);
#[derive(Default)]
struct Droppy {
inner: u32,
}
impl Drop for Droppy {
fn drop(&mut self) {
TRACKER.store(1, Ordering::Release);
println!("I've been dropped");
}
}
fn main() {
assert_eq!(TRACKER.load(Ordering::Acquire), 0);
let 0 = Droppy::default().inner else { return };
assert_eq!(TRACKER.load(Ordering::Acquire), 1);
println!("Should have dropped 👆");
}

View file

@ -1,7 +1,6 @@
// check-pass // check-pass
// aux-build:external_extern_fn.rs // aux-build:external_extern_fn.rs
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(no_niche)]
#![warn(clashing_extern_declarations)] #![warn(clashing_extern_declarations)]
mod redeclared_different_signature { mod redeclared_different_signature {
@ -400,9 +399,8 @@ mod hidden_niche {
#[repr(transparent)] #[repr(transparent)]
struct Transparent { x: NonZeroUsize } struct Transparent { x: NonZeroUsize }
#[repr(no_niche)]
#[repr(transparent)] #[repr(transparent)]
struct TransparentNoNiche { y: NonZeroUsize } struct TransparentNoNiche { y: UnsafeCell<NonZeroUsize> }
extern "C" { extern "C" {
fn hidden_niche_transparent() -> Option<Transparent>; fn hidden_niche_transparent() -> Option<Transparent>;

View file

@ -1,5 +1,5 @@
warning: `clash` redeclared with a different signature warning: `clash` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:15:13 --> $DIR/clashing-extern-fn.rs:14:13
| |
LL | fn clash(x: u8); LL | fn clash(x: u8);
| ---------------- `clash` previously declared here | ---------------- `clash` previously declared here
@ -8,7 +8,7 @@ LL | fn clash(x: u64);
| ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
| |
note: the lint level is defined here note: the lint level is defined here
--> $DIR/clashing-extern-fn.rs:5:9 --> $DIR/clashing-extern-fn.rs:4:9
| |
LL | #![warn(clashing_extern_declarations)] LL | #![warn(clashing_extern_declarations)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -16,7 +16,7 @@ LL | #![warn(clashing_extern_declarations)]
found `unsafe extern "C" fn(u64)` found `unsafe extern "C" fn(u64)`
warning: `extern_link_name` redeclared with a different signature warning: `extern_link_name` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:53:9 --> $DIR/clashing-extern-fn.rs:52:9
| |
LL | / #[link_name = "extern_link_name"] LL | / #[link_name = "extern_link_name"]
LL | | fn some_new_name(x: i16); LL | | fn some_new_name(x: i16);
@ -29,7 +29,7 @@ LL | fn extern_link_name(x: u32);
found `unsafe extern "C" fn(u32)` found `unsafe extern "C" fn(u32)`
warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
--> $DIR/clashing-extern-fn.rs:56:9 --> $DIR/clashing-extern-fn.rs:55:9
| |
LL | fn some_other_new_name(x: i16); LL | fn some_other_new_name(x: i16);
| ------------------------------- `some_other_new_name` previously declared here | ------------------------------- `some_other_new_name` previously declared here
@ -43,7 +43,7 @@ LL | | fn some_other_extern_link_name(x: u32);
found `unsafe extern "C" fn(u32)` found `unsafe extern "C" fn(u32)`
warning: `other_both_names_different` redeclares `link_name_same` with a different signature warning: `other_both_names_different` redeclares `link_name_same` with a different signature
--> $DIR/clashing-extern-fn.rs:60:9 --> $DIR/clashing-extern-fn.rs:59:9
| |
LL | / #[link_name = "link_name_same"] LL | / #[link_name = "link_name_same"]
LL | | fn both_names_different(x: i16); LL | | fn both_names_different(x: i16);
@ -58,7 +58,7 @@ LL | | fn other_both_names_different(x: u32);
found `unsafe extern "C" fn(u32)` found `unsafe extern "C" fn(u32)`
warning: `different_mod` redeclared with a different signature warning: `different_mod` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:73:9 --> $DIR/clashing-extern-fn.rs:72:9
| |
LL | fn different_mod(x: u8); LL | fn different_mod(x: u8);
| ------------------------ `different_mod` previously declared here | ------------------------ `different_mod` previously declared here
@ -70,7 +70,7 @@ LL | fn different_mod(x: u64);
found `unsafe extern "C" fn(u64)` found `unsafe extern "C" fn(u64)`
warning: `variadic_decl` redeclared with a different signature warning: `variadic_decl` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:83:9 --> $DIR/clashing-extern-fn.rs:82:9
| |
LL | fn variadic_decl(x: u8, ...); LL | fn variadic_decl(x: u8, ...);
| ----------------------------- `variadic_decl` previously declared here | ----------------------------- `variadic_decl` previously declared here
@ -82,7 +82,7 @@ LL | fn variadic_decl(x: u8);
found `unsafe extern "C" fn(u8)` found `unsafe extern "C" fn(u8)`
warning: `weigh_banana` redeclared with a different signature warning: `weigh_banana` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:143:13 --> $DIR/clashing-extern-fn.rs:142:13
| |
LL | fn weigh_banana(count: *const Banana) -> u64; LL | fn weigh_banana(count: *const Banana) -> u64;
| --------------------------------------------- `weigh_banana` previously declared here | --------------------------------------------- `weigh_banana` previously declared here
@ -94,7 +94,7 @@ LL | fn weigh_banana(count: *const Banana) -> u64;
found `unsafe extern "C" fn(*const three::Banana) -> u64` found `unsafe extern "C" fn(*const three::Banana) -> u64`
warning: `draw_point` redeclared with a different signature warning: `draw_point` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:172:13 --> $DIR/clashing-extern-fn.rs:171:13
| |
LL | fn draw_point(p: Point); LL | fn draw_point(p: Point);
| ------------------------ `draw_point` previously declared here | ------------------------ `draw_point` previously declared here
@ -106,7 +106,7 @@ LL | fn draw_point(p: Point);
found `unsafe extern "C" fn(sameish_members::b::Point)` found `unsafe extern "C" fn(sameish_members::b::Point)`
warning: `origin` redeclared with a different signature warning: `origin` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:198:13 --> $DIR/clashing-extern-fn.rs:197:13
| |
LL | fn origin() -> Point3; LL | fn origin() -> Point3;
| ---------------------- `origin` previously declared here | ---------------------- `origin` previously declared here
@ -118,7 +118,7 @@ LL | fn origin() -> Point3;
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
warning: `transparent_incorrect` redeclared with a different signature warning: `transparent_incorrect` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:221:13 --> $DIR/clashing-extern-fn.rs:220:13
| |
LL | fn transparent_incorrect() -> T; LL | fn transparent_incorrect() -> T;
| -------------------------------- `transparent_incorrect` previously declared here | -------------------------------- `transparent_incorrect` previously declared here
@ -130,7 +130,7 @@ LL | fn transparent_incorrect() -> isize;
found `unsafe extern "C" fn() -> isize` found `unsafe extern "C" fn() -> isize`
warning: `missing_return_type` redeclared with a different signature warning: `missing_return_type` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:239:13 --> $DIR/clashing-extern-fn.rs:238:13
| |
LL | fn missing_return_type() -> usize; LL | fn missing_return_type() -> usize;
| ---------------------------------- `missing_return_type` previously declared here | ---------------------------------- `missing_return_type` previously declared here
@ -142,7 +142,7 @@ LL | fn missing_return_type();
found `unsafe extern "C" fn()` found `unsafe extern "C" fn()`
warning: `non_zero_usize` redeclared with a different signature warning: `non_zero_usize` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:257:13 --> $DIR/clashing-extern-fn.rs:256:13
| |
LL | fn non_zero_usize() -> core::num::NonZeroUsize; LL | fn non_zero_usize() -> core::num::NonZeroUsize;
| ----------------------------------------------- `non_zero_usize` previously declared here | ----------------------------------------------- `non_zero_usize` previously declared here
@ -154,7 +154,7 @@ LL | fn non_zero_usize() -> usize;
found `unsafe extern "C" fn() -> usize` found `unsafe extern "C" fn() -> usize`
warning: `non_null_ptr` redeclared with a different signature warning: `non_null_ptr` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:259:13 --> $DIR/clashing-extern-fn.rs:258:13
| |
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>; LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
| ----------------------------------------------- `non_null_ptr` previously declared here | ----------------------------------------------- `non_null_ptr` previously declared here
@ -166,7 +166,7 @@ LL | fn non_null_ptr() -> *const usize;
found `unsafe extern "C" fn() -> *const usize` found `unsafe extern "C" fn() -> *const usize`
warning: `option_non_zero_usize_incorrect` redeclared with a different signature warning: `option_non_zero_usize_incorrect` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:357:13 --> $DIR/clashing-extern-fn.rs:356:13
| |
LL | fn option_non_zero_usize_incorrect() -> usize; LL | fn option_non_zero_usize_incorrect() -> usize;
| ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize;
found `unsafe extern "C" fn() -> isize` found `unsafe extern "C" fn() -> isize`
warning: `option_non_null_ptr_incorrect` redeclared with a different signature warning: `option_non_null_ptr_incorrect` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:359:13 --> $DIR/clashing-extern-fn.rs:358:13
| |
LL | fn option_non_null_ptr_incorrect() -> *const usize; LL | fn option_non_null_ptr_incorrect() -> *const usize;
| --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
@ -190,7 +190,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize;
found `unsafe extern "C" fn() -> *const isize` found `unsafe extern "C" fn() -> *const isize`
warning: `hidden_niche_transparent_no_niche` redeclared with a different signature warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:410:13 --> $DIR/clashing-extern-fn.rs:408:13
| |
LL | fn hidden_niche_transparent_no_niche() -> usize; LL | fn hidden_niche_transparent_no_niche() -> usize;
| ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
@ -202,7 +202,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
found `unsafe extern "C" fn() -> Option<TransparentNoNiche>` found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
warning: `hidden_niche_unsafe_cell` redeclared with a different signature warning: `hidden_niche_unsafe_cell` redeclared with a different signature
--> $DIR/clashing-extern-fn.rs:414:13 --> $DIR/clashing-extern-fn.rs:412:13
| |
LL | fn hidden_niche_unsafe_cell() -> usize; LL | fn hidden_niche_unsafe_cell() -> usize;
| --------------------------------------- `hidden_niche_unsafe_cell` previously declared here | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
@ -214,7 +214,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize
found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>` found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>`
warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
--> $DIR/clashing-extern-fn.rs:410:55 --> $DIR/clashing-extern-fn.rs:408:55
| |
LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>; LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@ -224,7 +224,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
= note: enum has no representation hint = note: enum has no representation hint
warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe
--> $DIR/clashing-extern-fn.rs:414:46 --> $DIR/clashing-extern-fn.rs:412:46
| |
LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>; LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe

View file

@ -4,12 +4,13 @@ error: float literals must have an integer part
LL | let _ = Foo { bar: .5, baz: 42 }; LL | let _ = Foo { bar: .5, baz: 42 };
| ^^ help: must have an integer part: `0.5` | ^^ help: must have an integer part: `0.5`
error: expected one of `,` or `}`, found `.` error: expected one of `,`, `:`, or `}`, found `.`
--> $DIR/issue-52496.rs:8:22 --> $DIR/issue-52496.rs:8:22
| |
LL | let _ = Foo { bar.into(), bat: -1, . }; LL | let _ = Foo { bar.into(), bat: -1, . };
| --- ^ expected one of `,` or `}` | --- - ^ expected one of `,`, `:`, or `}`
| | | | |
| | help: try naming a field: `bar:`
| while parsing this struct | while parsing this struct
error: expected identifier, found `.` error: expected identifier, found `.`

View file

@ -20,15 +20,23 @@ LL |
LL | LL |
| ^ | ^
error: expected one of `,` or `}`, found `{` error: expected one of `,`, `:`, or `}`, found `{`
--> $DIR/issue-62973.rs:6:8 --> $DIR/issue-62973.rs:6:8
| |
LL | fn p() { match s { v, E { [) {) } LL | fn p() { match s { v, E { [) {) }
| ^ - -^ expected one of `,` or `}` | ^ - ^ expected one of `,`, `:`, or `}`
| | | | | | |
| | | help: `}` may belong here
| | while parsing this struct | | while parsing this struct
| unclosed delimiter | unclosed delimiter
|
help: `}` may belong here
|
LL | fn p() { match s { v, E} { [) {) }
| +
help: try naming a field
|
LL | fn p() { match s { v, E: E { [) {) }
| ++
error: struct literals are not allowed here error: struct literals are not allowed here
--> $DIR/issue-62973.rs:6:16 --> $DIR/issue-62973.rs:6:16

View file

@ -6,6 +6,6 @@ fn main() {
let a = S { foo: (), bar: () }; let a = S { foo: (), bar: () };
let b = S { foo: (), with a }; let b = S { foo: (), with a };
//~^ ERROR expected one of `,` or `}`, found `a` //~^ ERROR expected one of `,`, `:`, or `}`, found `a`
//~| ERROR missing field `bar` in initializer of `S` //~| ERROR missing field `bar` in initializer of `S`
} }

View file

@ -1,8 +1,8 @@
error: expected one of `,` or `}`, found `a` error: expected one of `,`, `:`, or `}`, found `a`
--> $DIR/removed-syntax-with-2.rs:8:31 --> $DIR/removed-syntax-with-2.rs:8:31
| |
LL | let b = S { foo: (), with a }; LL | let b = S { foo: (), with a };
| - ^ expected one of `,` or `}` | - ^ expected one of `,`, `:`, or `}`
| | | |
| while parsing this struct | while parsing this struct

View file

@ -1,20 +0,0 @@
use std::num::NonZeroU8 as N8;
use std::num::NonZeroU16 as N16;
#[repr(no_niche)]
pub struct Cloaked(N16);
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
#[repr(transparent, no_niche)]
pub struct Shadowy(N16);
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
#[repr(no_niche)]
pub enum Cloaked1 { _A(N16), }
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
#[repr(no_niche)]
pub enum Cloaked2 { _A(N16), _B(u8, N8) }
//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
fn main() { }

View file

@ -1,35 +0,0 @@
error[E0658]: the attribute `repr(no_niche)` is currently unstable
--> $DIR/feature-gate-no-niche.rs:4:8
|
LL | #[repr(no_niche)]
| ^^^^^^^^
|
= help: add `#![feature(no_niche)]` to the crate attributes to enable
error[E0658]: the attribute `repr(no_niche)` is currently unstable
--> $DIR/feature-gate-no-niche.rs:8:21
|
LL | #[repr(transparent, no_niche)]
| ^^^^^^^^
|
= help: add `#![feature(no_niche)]` to the crate attributes to enable
error[E0658]: the attribute `repr(no_niche)` is currently unstable
--> $DIR/feature-gate-no-niche.rs:12:8
|
LL | #[repr(no_niche)]
| ^^^^^^^^
|
= help: add `#![feature(no_niche)]` to the crate attributes to enable
error[E0658]: the attribute `repr(no_niche)` is currently unstable
--> $DIR/feature-gate-no-niche.rs:16:8
|
LL | #[repr(no_niche)]
| ^^^^^^^^
|
= help: add `#![feature(no_niche)]` to the crate attributes to enable
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,14 +0,0 @@
#![feature(no_niche)]
use std::num::NonZeroU8 as N8;
use std::num::NonZeroU16 as N16;
#[repr(no_niche)]
pub union Cloaked1 { _A: N16 }
//~^^ ERROR attribute should be applied to a struct or enum [E0517]
#[repr(no_niche)]
pub union Cloaked2 { _A: N16, _B: (u8, N8) }
//~^^ ERROR attribute should be applied to a struct or enum [E0517]
fn main() { }

View file

@ -1,19 +0,0 @@
error[E0517]: attribute should be applied to a struct or enum
--> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8
|
LL | #[repr(no_niche)]
| ^^^^^^^^
LL | pub union Cloaked1 { _A: N16 }
| ------------------------------ not a struct or enum
error[E0517]: attribute should be applied to a struct or enum
--> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8
|
LL | #[repr(no_niche)]
| ^^^^^^^^
LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) }
| -------------------------------------------- not a struct or enum
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0517`.

View file

@ -1,327 +0,0 @@
// run-pass
// This file tests repr(no_niche), which causes an struct/enum to hide
// any niche space that may exist in its internal state from the
// context it appears in.
// Here are the axes this test is seeking to cover:
//
// repr annotation:
// visible: (); cloaked: (no_niche); transparent: (transparent); shadowy: (transparent, no_niche)
//
// enum vs struct
//
// niche-type via type-parameter vs inline declaration
#![feature(decl_macro)]
#![feature(no_niche)]
use std::mem::size_of;
use std::num::{NonZeroU8, NonZeroU16};
mod struct_inline {
use std::num::NonZeroU16 as N16;
#[derive(Debug)] pub struct Visible(N16);
#[repr(no_niche)]
#[derive(Debug)] pub struct Cloaked(N16);
#[repr(transparent)]
#[derive(Debug)] pub struct Transparent(N16);
#[repr(transparent, no_niche)]
#[derive(Debug)] pub struct Shadowy(N16);
}
mod struct_param {
#[derive(Debug)] pub struct Visible<T>(T);
#[repr(no_niche)]
#[derive(Debug)] pub struct Cloaked<T>(T);
#[repr(transparent)]
#[derive(Debug)] pub struct Transparent<T>(T);
#[repr(transparent, no_niche)]
#[derive(Debug)] pub struct Shadowy<T>(T);
}
mod enum_inline {
use crate::two_fifty_six_variant_enum;
use std::num::{NonZeroU8 as N8, NonZeroU16 as N16};
#[derive(Debug)] pub enum Visible1 { _A(N16), }
#[repr(no_niche)]
#[derive(Debug)] pub enum Cloaked1 { _A(N16), }
// (N.B.: transparent enums must be univariant)
#[repr(transparent)]
#[derive(Debug)] pub enum Transparent { _A(N16), }
#[repr(transparent, no_niche)]
#[derive(Debug)] pub enum Shadowy { _A(N16), }
// including multivariant enums for completeness. Payload and
// number of variants (i.e. discriminant size) have been chosen so
// that layout including discriminant is 4 bytes, with no space in
// padding to hide another discrimnant from the surrounding
// context.
//
// (Note that multivariant enums cannot usefully expose a niche in
// general; this test is relying on that.)
two_fifty_six_variant_enum!(Visible2, N8);
two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2, N8);
}
mod enum_param {
use super::two_fifty_six_variant_enum;
#[derive(Debug)] pub enum Visible1<T> { _A(T), }
#[repr(no_niche)]
#[derive(Debug)] pub enum Cloaked1<T> { _A(T), }
// (N.B.: transparent enums must be univariant)
#[repr(transparent)]
#[derive(Debug)] pub enum Transparent<T> { _A(T), }
#[repr(transparent, no_niche)]
#[derive(Debug)] pub enum Shadowy<T> { _A(T), }
// including multivariant enums for completeness. Same notes apply
// here as above (assuming `T` is instantiated with `NonZeroU8`).
two_fifty_six_variant_enum!(Visible2<T>);
two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2<T>);
}
fn main() {
// sanity-checks
assert_eq!(size_of::<struct_inline::Visible>(), 2);
assert_eq!(size_of::<struct_inline::Cloaked>(), 2);
assert_eq!(size_of::<struct_inline::Transparent>(), 2);
assert_eq!(size_of::<struct_inline::Shadowy>(), 2);
assert_eq!(size_of::<struct_param::Visible<NonZeroU16>>(), 2);
assert_eq!(size_of::<struct_param::Cloaked<NonZeroU16>>(), 2);
assert_eq!(size_of::<struct_param::Transparent<NonZeroU16>>(), 2);
assert_eq!(size_of::<struct_param::Shadowy<NonZeroU16>>(), 2);
assert_eq!(size_of::<enum_inline::Visible1>(), 2);
assert_eq!(size_of::<enum_inline::Cloaked1>(), 2);
assert_eq!(size_of::<enum_inline::Transparent>(), 2); // transparent enums are univariant
assert_eq!(size_of::<enum_inline::Shadowy>(), 2);
assert_eq!(size_of::<enum_inline::Visible2>(), 4);
assert_eq!(size_of::<enum_inline::Cloaked2>(), 4);
assert_eq!(size_of::<enum_param::Visible1<NonZeroU16>>(), 2);
assert_eq!(size_of::<enum_param::Cloaked1<NonZeroU16>>(), 2);
assert_eq!(size_of::<enum_param::Transparent<NonZeroU16>>(), 2);
assert_eq!(size_of::<enum_param::Shadowy<NonZeroU16>>(), 2);
assert_eq!(size_of::<enum_param::Visible2<NonZeroU8>>(), 4);
assert_eq!(size_of::<enum_param::Cloaked2<NonZeroU8>>(), 4);
// now the actual tests of no_niche: how do inputs above compose
// with `Option` type constructor. The cases with a `_+2` are the
// ones where no_niche fires.
assert_eq!(size_of::<Option<struct_inline::Visible>>(), 2);
assert_eq!(size_of::<Option<struct_inline::Cloaked>>(), 2+2);
assert_eq!(size_of::<Option<struct_inline::Transparent>>(), 2);
assert_eq!(size_of::<Option<struct_inline::Shadowy>>(), 2+2);
assert_eq!(size_of::<Option<struct_param::Visible<NonZeroU16>>>(), 2);
assert_eq!(size_of::<Option<struct_param::Cloaked<NonZeroU16>>>(), 2+2);
assert_eq!(size_of::<Option<struct_param::Transparent<NonZeroU16>>>(), 2);
assert_eq!(size_of::<Option<struct_param::Shadowy<NonZeroU16>>>(), 2+2);
assert_eq!(size_of::<Option<enum_inline::Visible1>>(), 2);
assert_eq!(size_of::<Option<enum_inline::Cloaked1>>(), 2+2);
assert_eq!(size_of::<Option<enum_inline::Transparent>>(), 2);
assert_eq!(size_of::<Option<enum_inline::Shadowy>>(), 2+2);
// cannot use niche of multivariant payload
assert_eq!(size_of::<Option<enum_inline::Visible2>>(), 4+2);
assert_eq!(size_of::<Option<enum_inline::Cloaked2>>(), 4+2);
assert_eq!(size_of::<Option<enum_param::Visible1<NonZeroU16>>>(), 2);
assert_eq!(size_of::<Option<enum_param::Cloaked1<NonZeroU16>>>(), 2+2);
assert_eq!(size_of::<Option<enum_param::Transparent<NonZeroU16>>>(), 2);
assert_eq!(size_of::<Option<enum_param::Shadowy<NonZeroU16>>>(), 2+2);
// cannot use niche of multivariant payload
assert_eq!(size_of::<Option<enum_param::Visible2<NonZeroU8>>>(), 4+2);
assert_eq!(size_of::<Option<enum_param::Cloaked2<NonZeroU8>>>(), 4+2);
}
macro two_fifty_six_variant_enum {
($(#[$attr:meta])* $name:ident<$param:ident>) => {
#[derive(Debug)] $(#[$attr])*
pub enum $name<$param> {
_V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
_V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
_V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param),
_V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param),
_V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param),
_V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param),
_V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param),
_V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param),
_V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param),
_V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param),
_V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param),
_V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param),
_V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param),
_V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param),
_V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param),
_V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param),
_V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param),
_V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param),
_V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param),
_V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param),
_V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param),
_V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param),
_V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param),
_V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param),
_V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param),
_V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param),
_V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param),
_V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param),
_V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param),
_V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param),
_V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param),
_V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param),
_V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param),
_V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param),
_V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param),
_V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param),
_V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param),
_V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param),
_V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param),
_V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param),
_Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param),
_Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param),
_Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param),
_Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param),
_Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param),
_Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param),
_Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param),
_Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param),
_Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param),
_Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param),
_Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param),
_Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param),
_Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param),
_Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param),
_Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param),
_Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param),
_Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param),
_Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param),
_Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param),
_Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param),
_Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param),
_Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param),
_Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param),
_Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param),
}
},
($(#[$attr:meta])* $name:ident, $param:ty) => {
#[derive(Debug)] $(#[$attr])*
pub enum $name {
_V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
_V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
_V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param),
_V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param),
_V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param),
_V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param),
_V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param),
_V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param),
_V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param),
_V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param),
_V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param),
_V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param),
_V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param),
_V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param),
_V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param),
_V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param),
_V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param),
_V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param),
_V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param),
_V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param),
_V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param),
_V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param),
_V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param),
_V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param),
_V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param),
_V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param),
_V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param),
_V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param),
_V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param),
_V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param),
_V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param),
_V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param),
_V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param),
_V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param),
_V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param),
_V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param),
_V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param),
_V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param),
_V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param),
_V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param),
_Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param),
_Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param),
_Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param),
_Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param),
_Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param),
_Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param),
_Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param),
_Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param),
_Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param),
_Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param),
_Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param),
_Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param),
_Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param),
_Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param),
_Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param),
_Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param),
_Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param),
_Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param),
_Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param),
_Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param),
_Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param),
_Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param),
_Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param),
_Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param),
}
}
}

View file

@ -11,7 +11,7 @@ use rustc_lint::LateContext;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
([stmt, stmts @ ..], expr) => { ([stmt, stmts @ ..], expr) => {
if let StmtKind::Local(&Local { init: Some(e), .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
(e, !stmts.is_empty() || expr.is_some()) (e, !stmts.is_empty() || expr.is_some())
} else { } else {
return; return;

View file

@ -1041,7 +1041,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
} }
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
self.infallible_destructuring_match_linted |= infallible_destructuring_match::check(cx, local); self.infallible_destructuring_match_linted |=
local.els.is_none() && infallible_destructuring_match::check(cx, local);
} }
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {

View file

@ -92,6 +92,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
if_chain! { if_chain! {
if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id); if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id);
if let Some(init) = local.init; if let Some(init) = local.init;
if local.els.is_none();
if !local.pat.span.from_expansion(); if !local.pat.span.from_expansion();
if has_no_effect(cx, init); if has_no_effect(cx, init);
if let PatKind::Binding(_, _, ident, _) = local.pat.kind; if let PatKind::Binding(_, _, ident, _) = local.pat.kind;

View file

@ -148,7 +148,7 @@ fn is_value_unfrozen_raw<'tcx>(
match val.ty().kind() { match val.ty().kind() {
// the fact that we have to dig into every structs to search enums // the fact that we have to dig into every structs to search enums
// leads us to the point checking `UnsafeCell` directly is the only option. // leads us to the point checking `UnsafeCell` directly is the only option.
ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true, ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
let val = cx.tcx.destructure_mir_constant(cx.param_env, val); let val = cx.tcx.destructure_mir_constant(cx.param_env, val);
val.fields.iter().any(|field| inner(cx, *field)) val.fields.iter().any(|field| inner(cx, *field))

View file

@ -10,7 +10,6 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::sym; use rustc_span::sym;
@ -203,9 +202,7 @@ fn check_final_expr<'tcx>(
check_block_return(cx, ifblock); check_block_return(cx, ifblock);
} }
if let Some(else_clause) = else_clause_opt { if let Some(else_clause) = else_clause_opt {
if expr.span.desugaring_kind() != Some(DesugaringKind::LetElse) { check_final_expr(cx, else_clause, None, RetReplacement::Empty);
check_final_expr(cx, else_clause, None, RetReplacement::Empty);
}
} }
}, },
// a match expr, check all arms // a match expr, check all arms

View file

@ -102,7 +102,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> {
impl HirEqInterExpr<'_, '_, '_> { impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool { pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
match (&left.kind, &right.kind) { match (&left.kind, &right.kind) {
(&StmtKind::Local(l), &StmtKind::Local(r)) => { (&StmtKind::Local(l, ), &StmtKind::Local(r, )) => {
// This additional check ensures that the type of the locals are equivalent even if the init // This additional check ensures that the type of the locals are equivalent even if the init
// expression or type have some inferred parts. // expression or type have some inferred parts.
if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results { if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results {
@ -117,6 +117,7 @@ impl HirEqInterExpr<'_, '_, '_> {
// these only get added if the init and type is equal. // these only get added if the init and type is equal.
both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
&& both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
&& both(&l.els, &r.els, |l, r| self.eq_block(l, r))
&& self.eq_pat(l.pat, r.pat) && self.eq_pat(l.pat, r.pat)
}, },
(&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r), (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
@ -921,11 +922,14 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
std::mem::discriminant(&b.kind).hash(&mut self.s); std::mem::discriminant(&b.kind).hash(&mut self.s);
match &b.kind { match &b.kind {
StmtKind::Local(local) => { StmtKind::Local(local, ) => {
self.hash_pat(local.pat); self.hash_pat(local.pat);
if let Some(init) = local.init { if let Some(init) = local.init {
self.hash_expr(init); self.hash_expr(init);
} }
if let Some(els) = local.els {
self.hash_block(els);
}
}, },
StmtKind::Item(..) => {}, StmtKind::Item(..) => {},
StmtKind::Expr(expr) | StmtKind::Semi(expr) => { StmtKind::Expr(expr) | StmtKind::Semi(expr) => {