Auto merge of #78998 - m-ou-se:rollup-6r4pt9m, r=m-ou-se

Rollup of 7 pull requests

Successful merges:

 - #76730 (Fix rustdoc rendering of by-value mutable arguments in async fn)
 - #78836 (Implement destructuring assignment for structs and slices)
 - #78857 (Improve BinaryHeap performance)
 - #78950 (Add asm register information for SPIR-V)
 - #78970 (update rustfmt to v1.4.25)
 - #78972 (Update cargo)
 - #78987 (extend min_const_generics param ty tests)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2020-11-12 23:23:56 +00:00
commit e80ee05bfc
45 changed files with 840 additions and 134 deletions

View file

@ -4329,7 +4329,7 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
version = "1.4.24"
version = "1.4.25"
dependencies = [
"annotate-snippets 0.6.1",
"anyhow",

View file

@ -1061,7 +1061,7 @@ pub struct Expr {
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
rustc_data_structures::static_assert_size!(Expr, 112);
rustc_data_structures::static_assert_size!(Expr, 120);
impl Expr {
/// Returns `true` if this expression would be valid somewhere that expects a value;
@ -1218,6 +1218,16 @@ pub enum RangeLimits {
Closed,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum StructRest {
/// `..x`.
Base(P<Expr>),
/// `..`.
Rest(Span),
/// No trailing `..` or expression.
None,
}
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ExprKind {
/// A `box x` expression.
@ -1312,7 +1322,7 @@ pub enum ExprKind {
Field(P<Expr>, Ident),
/// An indexing operation (e.g., `foo[2]`).
Index(P<Expr>, P<Expr>),
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
/// A range (e.g., `1..2`, `1..`, `..2`, `1..=2`, `..=2`; and `..` in destructuring assingment).
Range(Option<P<Expr>>, Option<P<Expr>>, RangeLimits),
/// Variable reference, possibly containing `::` and/or type
@ -1340,9 +1350,8 @@ pub enum ExprKind {
/// A struct literal expression.
///
/// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`,
/// where `base` is the `Option<Expr>`.
Struct(Path, Vec<Field>, Option<P<Expr>>),
/// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. rest}`.
Struct(Path, Vec<Field>, StructRest),
/// An array literal constructed from one repeated element.
///

View file

@ -1288,7 +1288,11 @@ pub fn noop_visit_expr<T: MutVisitor>(
ExprKind::Struct(path, fields, expr) => {
vis.visit_path(path);
fields.flat_map_in_place(|field| vis.flat_map_field(field));
visit_opt(expr, |expr| vis.visit_expr(expr));
match expr {
StructRest::Base(expr) => vis.visit_expr(expr),
StructRest::Rest(_span) => {}
StructRest::None => {}
}
}
ExprKind::Paren(expr) => {
vis.visit_expr(expr);

View file

@ -719,7 +719,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Struct(ref path, ref fields, ref optional_base) => {
visitor.visit_path(path, expression.id);
walk_list!(visitor, visit_field, fields);
walk_list!(visitor, visit_expr, optional_base);
match optional_base {
StructRest::Base(expr) => visitor.visit_expr(expr),
StructRest::Rest(_span) => {}
StructRest::None => {}
}
}
ExprKind::Tup(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);

View file

@ -187,8 +187,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(e.span, asm),
ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_llvm_asm(asm),
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
let maybe_expr = maybe_expr.as_ref().map(|x| self.lower_expr(x));
ExprKind::Struct(ref path, ref fields, ref rest) => {
let rest = match rest {
StructRest::Base(e) => Some(self.lower_expr(e)),
StructRest::Rest(sp) => {
self.sess
.struct_span_err(*sp, "base expression required after `..`")
.span_label(*sp, "add a base expression here")
.emit();
Some(&*self.arena.alloc(self.expr_err(*sp)))
}
StructRest::None => None,
};
hir::ExprKind::Struct(
self.arena.alloc(self.lower_qpath(
e.id,
@ -198,7 +208,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::disallowed(),
)),
self.arena.alloc_from_iter(fields.iter().map(|x| self.lower_field(x))),
maybe_expr,
rest,
)
}
ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
@ -851,20 +861,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
whole_span: Span,
) -> hir::ExprKind<'hir> {
// Return early in case of an ordinary assignment.
fn is_ordinary(lhs: &Expr) -> bool {
fn is_ordinary(lower_ctx: &mut LoweringContext<'_, '_>, lhs: &Expr) -> bool {
match &lhs.kind {
ExprKind::Tup(..) => false,
ExprKind::Array(..) | ExprKind::Struct(..) | ExprKind::Tup(..) => false,
// Check for tuple struct constructor.
ExprKind::Call(callee, ..) => lower_ctx.extract_tuple_struct_path(callee).is_none(),
ExprKind::Paren(e) => {
match e.kind {
// We special-case `(..)` for consistency with patterns.
ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,
_ => is_ordinary(e),
_ => is_ordinary(lower_ctx, e),
}
}
_ => true,
}
}
if is_ordinary(lhs) {
if is_ordinary(self, lhs) {
return hir::ExprKind::Assign(self.lower_expr(lhs), self.lower_expr(rhs), eq_sign_span);
}
if !self.sess.features_untracked().destructuring_assignment {
@ -902,6 +914,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Block(&self.block_all(whole_span, stmts, None), None)
}
/// If the given expression is a path to a tuple struct, returns that path.
/// It is not a complete check, but just tries to reject most paths early
/// if they are not tuple structs.
/// Type checking will take care of the full validation later.
fn extract_tuple_struct_path<'a>(&mut self, expr: &'a Expr) -> Option<&'a Path> {
// For tuple struct destructuring, it must be a non-qualified path (like in patterns).
if let ExprKind::Path(None, path) = &expr.kind {
// Does the path resolves to something disallowed in a tuple struct/variant pattern?
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
if partial_res.unresolved_segments() == 0
&& !partial_res.base_res().expected_in_tuple_struct_pat()
{
return None;
}
}
return Some(path);
}
None
}
/// Convert the LHS of a destructuring assignment to a pattern.
/// Each sub-assignment is recorded in `assignments`.
fn destructure_assign(
@ -911,6 +943,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
assignments: &mut Vec<hir::Stmt<'hir>>,
) -> &'hir hir::Pat<'hir> {
match &lhs.kind {
// Slice patterns.
ExprKind::Array(elements) => {
let (pats, rest) =
self.destructure_sequence(elements, "slice", eq_sign_span, assignments);
let slice_pat = if let Some((i, span)) = rest {
let (before, after) = pats.split_at(i);
hir::PatKind::Slice(
before,
Some(self.pat_without_dbm(span, hir::PatKind::Wild)),
after,
)
} else {
hir::PatKind::Slice(pats, None, &[])
};
return self.pat_without_dbm(lhs.span, slice_pat);
}
// Tuple structs.
ExprKind::Call(callee, args) => {
if let Some(path) = self.extract_tuple_struct_path(callee) {
let (pats, rest) = self.destructure_sequence(
args,
"tuple struct or variant",
eq_sign_span,
assignments,
);
let qpath = self.lower_qpath(
callee.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
);
// Destructure like a tuple struct.
let tuple_struct_pat =
hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0));
return self.pat_without_dbm(lhs.span, tuple_struct_pat);
}
}
// Structs.
ExprKind::Struct(path, fields, rest) => {
let field_pats = self.arena.alloc_from_iter(fields.iter().map(|f| {
let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);
hir::FieldPat {
hir_id: self.next_id(),
ident: f.ident,
pat,
is_shorthand: f.is_shorthand,
span: f.span,
}
}));
let qpath = self.lower_qpath(
lhs.id,
&None,
path,
ParamMode::Optional,
ImplTraitContext::disallowed(),
);
let fields_omitted = match rest {
StructRest::Base(e) => {
self.sess
.struct_span_err(
e.span,
"functional record updates are not allowed in destructuring \
assignments",
)
.span_suggestion(
e.span,
"consider removing the trailing pattern",
String::new(),
rustc_errors::Applicability::MachineApplicable,
)
.emit();
true
}
StructRest::Rest(_) => true,
StructRest::None => false,
};
let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted);
return self.pat_without_dbm(lhs.span, struct_pat);
}
// Tuples.
ExprKind::Tup(elements) => {
let (pats, rest) =

View file

@ -1096,8 +1096,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
let (ident, is_simple_parameter) = match parameter.pat.kind {
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, _) => {
(ident, true)
hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable,
_,
ident,
_,
) => (ident, true),
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
// we can keep the same name for the parameter.
// This lets rustdoc render it correctly in documentation.
hir::PatKind::Binding(_, _, ident, _) => (ident, false),
hir::PatKind::Wild => {
(Ident::with_dummy_span(rustc_span::symbol::kw::Underscore), false)
}
_ => {
// Replace the ident for bindings that aren't simple.

View file

@ -630,6 +630,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
gate_all!(destructuring_assignment, "destructuring assignments are unstable");
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).

View file

@ -1729,7 +1729,7 @@ impl<'a> State<'a> {
&mut self,
path: &ast::Path,
fields: &[ast::Field],
wth: &Option<P<ast::Expr>>,
rest: &ast::StructRest,
attrs: &[ast::Attribute],
) {
self.print_path(path, true, 0);
@ -1750,22 +1750,21 @@ impl<'a> State<'a> {
},
|f| f.span,
);
match *wth {
Some(ref expr) => {
match rest {
ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
self.ibox(INDENT_UNIT);
if !fields.is_empty() {
self.s.word(",");
self.s.space();
}
self.s.word("..");
self.print_expr(expr);
if let ast::StructRest::Base(ref expr) = *rest {
self.print_expr(expr);
}
self.end();
}
_ => {
if !fields.is_empty() {
self.s.word(",")
}
}
ast::StructRest::None if !fields.is_empty() => self.s.word(","),
_ => {}
}
self.s.word("}");
}
@ -1891,8 +1890,8 @@ impl<'a> State<'a> {
ast::ExprKind::Repeat(ref element, ref count) => {
self.print_expr_repeat(element, count, attrs);
}
ast::ExprKind::Struct(ref path, ref fields, ref wth) => {
self.print_expr_struct(path, &fields[..], wth, attrs);
ast::ExprKind::Struct(ref path, ref fields, ref rest) => {
self.print_expr_struct(path, &fields[..], rest, attrs);
}
ast::ExprKind::Tup(ref exprs) => {
self.print_expr_tup(&exprs[..], attrs);

View file

@ -12,8 +12,8 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, span_bug};
use rustc_span::{Pos, Span};
use rustc_target::abi::*;
use rustc_target::asm::*;
@ -260,6 +260,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
InlineAsmArch::Nvptx64 => {}
InlineAsmArch::Hexagon => {}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
InlineAsmArch::SpirV => {}
}
}
if !options.contains(InlineAsmOptions::NOMEM) {
@ -518,6 +519,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
}
.to_string(),
}
@ -580,6 +584,9 @@ fn modifier_to_llvm(
_ => unreachable!(),
},
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
}
}
@ -619,6 +626,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
}
}

View file

@ -298,7 +298,7 @@ impl<'a> ExtCtxt<'a> {
path: ast::Path,
fields: Vec<ast::Field>,
) -> P<ast::Expr> {
self.expr(span, ast::ExprKind::Struct(path, fields, None))
self.expr(span, ast::ExprKind::Struct(path, fields, ast::StructRest::None))
}
pub fn expr_struct_ident(
&self,

View file

@ -484,4 +484,9 @@ impl<Id> Res<Id> {
pub fn matches_ns(&self, ns: Namespace) -> bool {
self.ns().map_or(true, |actual_ns| actual_ns == ns)
}
/// Returns whether such a resolved path can occur in a tuple struct/variant pattern
pub fn expected_in_tuple_struct_pat(&self) -> bool {
matches!(self, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..))
}
}

View file

@ -2087,7 +2087,7 @@ impl<'a> Parser<'a> {
recover: bool,
) -> PResult<'a, P<Expr>> {
let mut fields = Vec::new();
let mut base = None;
let mut base = ast::StructRest::None;
let mut recover_async = false;
attrs.extend(self.parse_inner_attributes()?);
@ -2102,8 +2102,14 @@ impl<'a> Parser<'a> {
while self.token != token::CloseDelim(token::Brace) {
if self.eat(&token::DotDot) {
let exp_span = self.prev_token.span;
// We permit `.. }` on the left-hand side of a destructuring assignment.
if self.check(&token::CloseDelim(token::Brace)) {
self.sess.gated_spans.gate(sym::destructuring_assignment, self.prev_token.span);
base = ast::StructRest::Rest(self.prev_token.span.shrink_to_hi());
break;
}
match self.parse_expr() {
Ok(e) => base = Some(e),
Ok(e) => base = ast::StructRest::Base(e),
Err(mut e) if recover => {
e.emit();
self.recover_stmt();

View file

@ -298,9 +298,7 @@ impl<'a> PathSource<'a> {
_,
)
| Res::SelfCtor(..)),
PathSource::TupleStruct(..) => {
matches!(res, Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..))
}
PathSource::TupleStruct(..) => res.expected_in_tuple_struct_pat(),
PathSource::Struct => matches!(res, Res::Def(
DefKind::Struct
| DefKind::Union

View file

@ -816,7 +816,7 @@ impl<'tcx> DumpVisitor<'tcx> {
path: &'tcx hir::QPath<'tcx>,
fields: &'tcx [hir::Field<'tcx>],
variant: &'tcx ty::VariantDef,
base: Option<&'tcx hir::Expr<'tcx>>,
rest: Option<&'tcx hir::Expr<'tcx>>,
) {
if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
if let hir::QPath::Resolved(_, path) = path {
@ -836,7 +836,9 @@ impl<'tcx> DumpVisitor<'tcx> {
}
}
walk_list!(self, visit_expr, base);
if let Some(base) = rest {
self.visit_expr(&base);
}
}
fn process_method_call(
@ -1399,7 +1401,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
debug!("visit_expr {:?}", ex.kind);
self.process_macro_use(ex.span);
match ex.kind {
hir::ExprKind::Struct(ref path, ref fields, ref base) => {
hir::ExprKind::Struct(ref path, ref fields, ref rest) => {
let hir_expr = self.save_ctxt.tcx.hir().expect_expr(ex.hir_id);
let adt = match self.save_ctxt.typeck_results().expr_ty_opt(&hir_expr) {
Some(ty) if ty.ty_adt_def().is_some() => ty.ty_adt_def().unwrap(),
@ -1409,7 +1411,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
}
};
let res = self.save_ctxt.get_path_res(hir_expr.hir_id);
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *base)
self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest)
}
hir::ExprKind::MethodCall(ref seg, _, args, _) => {
self.process_method_call(ex, seg, args)

View file

@ -155,6 +155,7 @@ mod hexagon;
mod mips;
mod nvptx;
mod riscv;
mod spirv;
mod x86;
pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass};
@ -163,6 +164,7 @@ pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
#[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)]
@ -177,6 +179,7 @@ pub enum InlineAsmArch {
Hexagon,
Mips,
Mips64,
SpirV,
}
impl FromStr for InlineAsmArch {
@ -194,6 +197,7 @@ impl FromStr for InlineAsmArch {
"hexagon" => Ok(Self::Hexagon),
"mips" => Ok(Self::Mips),
"mips64" => Ok(Self::Mips64),
"spirv" => Ok(Self::SpirV),
_ => Err(()),
}
}
@ -208,6 +212,7 @@ pub enum InlineAsmReg {
Nvptx(NvptxInlineAsmReg),
Hexagon(HexagonInlineAsmReg),
Mips(MipsInlineAsmReg),
SpirV(SpirVInlineAsmReg),
}
impl InlineAsmReg {
@ -264,6 +269,9 @@ impl InlineAsmReg {
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
InlineAsmArch::SpirV => {
Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
})
}
@ -306,6 +314,7 @@ pub enum InlineAsmRegClass {
Nvptx(NvptxInlineAsmRegClass),
Hexagon(HexagonInlineAsmRegClass),
Mips(MipsInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass),
}
impl InlineAsmRegClass {
@ -318,6 +327,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(),
Self::SpirV(r) => r.name(),
}
}
@ -333,6 +343,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
}
}
@ -355,6 +366,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.suggest_modifier(arch, ty),
Self::Hexagon(r) => r.suggest_modifier(arch, ty),
Self::Mips(r) => r.suggest_modifier(arch, ty),
Self::SpirV(r) => r.suggest_modifier(arch, ty),
}
}
@ -373,6 +385,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.default_modifier(arch),
Self::Hexagon(r) => r.default_modifier(arch),
Self::Mips(r) => r.default_modifier(arch),
Self::SpirV(r) => r.default_modifier(arch),
}
}
@ -390,6 +403,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.supported_types(arch),
Self::Hexagon(r) => r.supported_types(arch),
Self::Mips(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
}
}
@ -414,6 +428,7 @@ impl InlineAsmRegClass {
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
}
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
})
})
}
@ -429,6 +444,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.valid_modifiers(arch),
Self::Hexagon(r) => r.valid_modifiers(arch),
Self::Mips(r) => r.valid_modifiers(arch),
Self::SpirV(r) => r.valid_modifiers(arch),
}
}
}
@ -571,5 +587,10 @@ pub fn allocatable_registers(
mips::fill_reg_map(arch, has_feature, target, &mut map);
map
}
InlineAsmArch::SpirV => {
let mut map = spirv::regclass_map();
spirv::fill_reg_map(arch, has_feature, target, &mut map);
map
}
}
}

View file

@ -0,0 +1,46 @@
use super::{InlineAsmArch, InlineAsmType};
use rustc_macros::HashStable_Generic;
def_reg_class! {
SpirV SpirVInlineAsmRegClass {
reg,
}
}
impl SpirVInlineAsmRegClass {
pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
&[]
}
pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
None
}
pub fn suggest_modifier(
self,
_arch: InlineAsmArch,
_ty: InlineAsmType,
) -> Option<(char, &'static str)> {
None
}
pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
None
}
pub fn supported_types(
self,
_arch: InlineAsmArch,
) -> &'static [(InlineAsmType, Option<&'static str>)] {
match self {
Self::reg => {
types! { _: I8, I16, I32, I64, F32, F64; }
}
}
}
}
def_regs! {
// SPIR-V is SSA-based, it does not have registers.
SpirV SpirVInlineAsmReg SpirVInlineAsmRegClass {}
}

View file

@ -495,7 +495,14 @@ impl<T: Ord> BinaryHeap<T> {
let mut end = self.len();
while end > 1 {
end -= 1;
self.data.swap(0, end);
// SAFETY: `end` goes from `self.len() - 1` to 1 (both included),
// so it's always a valid index to access.
// It is safe to access index 0 (i.e. `ptr`), because
// 1 <= end < self.len(), which means self.len() >= 2.
unsafe {
let ptr = self.data.as_mut_ptr();
ptr::swap(ptr, ptr.add(end));
}
self.sift_down_range(0, end);
}
self.into_vec()
@ -531,19 +538,19 @@ impl<T: Ord> BinaryHeap<T> {
unsafe {
let mut hole = Hole::new(&mut self.data, pos);
let mut child = 2 * pos + 1;
while child < end {
let right = child + 1;
while child < end - 1 {
// compare with the greater of the two children
if right < end && hole.get(child) <= hole.get(right) {
child = right;
}
child += (hole.get(child) <= hole.get(child + 1)) as usize;
// if we are already in order, stop.
if hole.element() >= hole.get(child) {
break;
return;
}
hole.move_to(child);
child = 2 * hole.pos() + 1;
}
if child == end - 1 && hole.element() < hole.get(child) {
hole.move_to(child);
}
}
}
@ -563,15 +570,14 @@ impl<T: Ord> BinaryHeap<T> {
unsafe {
let mut hole = Hole::new(&mut self.data, pos);
let mut child = 2 * pos + 1;
while child < end {
let right = child + 1;
// compare with the greater of the two children
if right < end && hole.get(child) <= hole.get(right) {
child = right;
}
while child < end - 1 {
child += (hole.get(child) <= hole.get(child + 1)) as usize;
hole.move_to(child);
child = 2 * hole.pos() + 1;
}
if child == end - 1 {
hole.move_to(child);
}
pos = hole.pos;
}
self.sift_up(start, pos);

View file

@ -1,4 +1,5 @@
// edition:2018
#![feature(min_const_generics)]
// @has async_fn/fn.foo.html '//pre[@class="rust fn"]' 'pub async fn foo() -> Option<Foo>'
pub async fn foo() -> Option<Foo> {
@ -20,6 +21,12 @@ pub async unsafe fn qux() -> char {
'⚠'
}
// @has async_fn/fn.mut_args.html '//pre[@class="rust fn"]' 'pub async fn mut_args(a: usize)'
pub async fn mut_args(mut a: usize) {}
// @has async_fn/fn.mut_ref.html '//pre[@class="rust fn"]' 'pub async fn mut_ref(x: i32)'
pub async fn mut_ref(ref mut x: i32) {}
trait Bar {}
impl Bar for () {}
@ -32,9 +39,16 @@ pub async fn quux() -> impl Bar {
// @has async_fn/struct.Foo.html
// @matches - '//code' 'pub async fn f\(\)$'
// @matches - '//code' 'pub async unsafe fn g\(\)$'
// @matches - '//code' 'pub async fn mut_self\(self, first: usize\)$'
pub struct Foo;
impl Foo {
pub async fn f() {}
pub async unsafe fn g() {}
pub async fn mut_self(mut self, mut first: usize) {}
}
pub trait Trait<const N: usize> {}
// @has async_fn/fn.const_generics.html
// @has - '//pre[@class="rust fn"]' 'pub async fn const_generics<const N: usize>(_: impl Trait<N>)'
pub async fn const_generics<const N: usize>(_: impl Trait<N>) {}

View file

@ -70,8 +70,7 @@ pub async fn a_sink<const N: usize>(v: [u8; N]) -> impl Trait<N> {
}
// @has foo/fn.b_sink.html '//pre[@class="rust fn"]' \
// 'pub async fn b_sink<const N: usize>(__arg0: impl Trait<N>)'
// FIXME(const_generics): This should be `_` not `__arg0`.
// 'pub async fn b_sink<const N: usize>(_: impl Trait<N>)'
pub async fn b_sink<const N: usize>(_: impl Trait<N>) {}
// @has foo/fn.concrete.html '//pre[@class="rust fn"]' \

View file

@ -155,7 +155,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
},
17 => {
let path = Path::from_ident(Ident::from_str("S"));
g(ExprKind::Struct(path, vec![], Some(make_x())));
g(ExprKind::Struct(path, vec![], StructRest::Base(make_x())));
},
18 => {
iter_exprs(depth - 1, &mut |e| g(ExprKind::Try(e)));

View file

@ -0,0 +1,51 @@
// Check that all types allowed with `min_const_generics` work.
// run-pass
// revisions: full min
#![cfg_attr(full, feature(const_generics))]
#![cfg_attr(full, allow(incomplete_features))]
#![cfg_attr(min, feature(min_const_generics))]
struct A<const N: u8>;
struct B<const N: u16>;
struct C<const N: u32>;
struct D<const N: u64>;
struct E<const N: u128>;
struct F<const N: usize>;
struct G<const N: i8>;
struct H<const N: i16>;
struct I<const N: i32>;
struct J<const N: i64>;
struct K<const N: i128>;
struct L<const N: isize>;
struct M<const N: char>;
struct N<const N: bool>;
fn main() {
let _ = A::<{u8::MIN}>;
let _ = A::<{u8::MAX}>;
let _ = B::<{u16::MIN}>;
let _ = B::<{u16::MAX}>;
let _ = C::<{u32::MIN}>;
let _ = C::<{u32::MAX}>;
let _ = D::<{u64::MIN}>;
let _ = D::<{u64::MAX}>;
let _ = E::<{u128::MIN}>;
let _ = E::<{u128::MAX}>;
let _ = F::<{usize::MIN}>;
let _ = F::<{usize::MAX}>;
let _ = G::<{i8::MIN}>;
let _ = G::<{i8::MAX}>;
let _ = H::<{i16::MIN}>;
let _ = H::<{i16::MAX}>;
let _ = I::<{i32::MIN}>;
let _ = I::<{i32::MAX}>;
let _ = J::<{i64::MIN}>;
let _ = J::<{i64::MAX}>;
let _ = K::<{i128::MIN}>;
let _ = K::<{i128::MAX}>;
let _ = L::<{isize::MIN}>;
let _ = L::<{isize::MAX}>;
let _ = M::<'A'>;
let _ = N::<true>;
}

View file

@ -1,4 +1,5 @@
#![feature(min_const_generics)]
#![feature(never_type)]
struct Foo<const N: [u8; 0]>;
//~^ ERROR `[u8; 0]` is forbidden
@ -14,4 +15,14 @@ struct Fez<const N: No>;
struct Faz<const N: &'static u8>;
//~^ ERROR `&'static u8` is forbidden
struct Fiz<const N: !>;
//~^ ERROR `!` is forbidden
enum Goo<const N: ()> { A, B }
//~^ ERROR `()` is forbidden
union Boo<const N: ()> { a: () }
//~^ ERROR `()` is forbidden
fn main() {}

View file

@ -1,5 +1,5 @@
error: `[u8; 0]` is forbidden as the type of a const generic parameter
--> $DIR/complex-types.rs:3:21
--> $DIR/complex-types.rs:4:21
|
LL | struct Foo<const N: [u8; 0]>;
| ^^^^^^^
@ -8,7 +8,7 @@ LL | struct Foo<const N: [u8; 0]>;
= note: more complex types are supported with `#[feature(const_generics)]`
error: `()` is forbidden as the type of a const generic parameter
--> $DIR/complex-types.rs:6:21
--> $DIR/complex-types.rs:7:21
|
LL | struct Bar<const N: ()>;
| ^^
@ -17,7 +17,7 @@ LL | struct Bar<const N: ()>;
= note: more complex types are supported with `#[feature(const_generics)]`
error: `No` is forbidden as the type of a const generic parameter
--> $DIR/complex-types.rs:11:21
--> $DIR/complex-types.rs:12:21
|
LL | struct Fez<const N: No>;
| ^^
@ -26,7 +26,7 @@ LL | struct Fez<const N: No>;
= note: more complex types are supported with `#[feature(const_generics)]`
error: `&'static u8` is forbidden as the type of a const generic parameter
--> $DIR/complex-types.rs:14:21
--> $DIR/complex-types.rs:15:21
|
LL | struct Faz<const N: &'static u8>;
| ^^^^^^^^^^^
@ -34,5 +34,32 @@ LL | struct Faz<const N: &'static u8>;
= note: the only supported types are integers, `bool` and `char`
= note: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 4 previous errors
error: `!` is forbidden as the type of a const generic parameter
--> $DIR/complex-types.rs:18:21
|
LL | struct Fiz<const N: !>;
| ^
|
= note: the only supported types are integers, `bool` and `char`
= note: more complex types are supported with `#[feature(const_generics)]`
error: `()` is forbidden as the type of a const generic parameter
--> $DIR/complex-types.rs:21:19
|
LL | enum Goo<const N: ()> { A, B }
| ^^
|
= note: the only supported types are integers, `bool` and `char`
= note: more complex types are supported with `#[feature(const_generics)]`
error: `()` is forbidden as the type of a const generic parameter
--> $DIR/complex-types.rs:24:20
|
LL | union Boo<const N: ()> { a: () }
| ^^
|
= note: the only supported types are integers, `bool` and `char`
= note: more complex types are supported with `#[feature(const_generics)]`
error: aborting due to 7 previous errors

View file

@ -0,0 +1,17 @@
// run-pass
#![feature(destructuring_assignment)]
struct Struct<S, T> {
a: S,
b: T,
}
struct TupleStruct<S, T>(S, T);
fn main() {
let (a, b, c, d);
Struct { a: TupleStruct((a, b), c), b: [d] } =
Struct { a: TupleStruct((0, 1), 2), b: [3] };
assert_eq!((a, b, c, d), (0, 1, 2, 3));
}

View file

@ -7,18 +7,19 @@ fn main() {
(a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
//~| ERROR binary assignment operation `+=` cannot be applied
[a, b] = [3, 4]; //~ ERROR invalid left-hand side of assignment
[a, b] = [3, 4]; //~ ERROR destructuring assignments are unstable
[a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
//~| ERROR binary assignment operation `+=` cannot be applied
let s = S { x: 3, y: 4 };
S { x: a, y: b } = s; //~ ERROR invalid left-hand side of assignment
S { x: a, y: b } = s; //~ ERROR destructuring assignments are unstable
S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
//~| ERROR binary assignment operation `+=` cannot be applied
S { x: a, ..s } = S { x: 3, y: 4 };
//~^ ERROR invalid left-hand side of assignment
//~^ ERROR functional record updates are not allowed in destructuring assignments
//~| ERROR destructuring assignments are unstable
let c = 3;

View file

@ -10,7 +10,46 @@ LL | (a, b) = (3, 4);
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0658]: destructuring assignments are unstable
--> $DIR/note-unsupported.rs:25:17
--> $DIR/note-unsupported.rs:10:12
|
LL | [a, b] = [3, 4];
| ------ ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0658]: destructuring assignments are unstable
--> $DIR/note-unsupported.rs:16:22
|
LL | S { x: a, y: b } = s;
| ---------------- ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0658]: destructuring assignments are unstable
--> $DIR/note-unsupported.rs:20:21
|
LL | S { x: a, ..s } = S { x: 3, y: 4 };
| --------------- ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: functional record updates are not allowed in destructuring assignments
--> $DIR/note-unsupported.rs:20:17
|
LL | S { x: a, ..s } = S { x: 3, y: 4 };
| ^ help: consider removing the trailing pattern
error[E0658]: destructuring assignments are unstable
--> $DIR/note-unsupported.rs:26:17
|
LL | ((a, b), c) = ((3, 4), 5);
| ----------- ^
@ -36,14 +75,6 @@ LL | (a, b) += (3, 4);
| |
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
--> $DIR/note-unsupported.rs:10:12
|
LL | [a, b] = [3, 4];
| ------ ^
| |
| cannot assign to this expression
error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
--> $DIR/note-unsupported.rs:11:5
|
@ -60,14 +91,6 @@ LL | [a, b] += [3, 4];
| |
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
--> $DIR/note-unsupported.rs:16:22
|
LL | S { x: a, y: b } = s;
| ---------------- ^
| |
| cannot assign to this expression
error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
--> $DIR/note-unsupported.rs:17:5
|
@ -86,15 +109,7 @@ LL | S { x: a, y: b } += s;
| |
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
--> $DIR/note-unsupported.rs:20:21
|
LL | S { x: a, ..s } = S { x: 3, y: 4 };
| --------------- ^
| |
| cannot assign to this expression
error: aborting due to 12 previous errors
error: aborting due to 11 previous errors
Some errors have detailed explanations: E0067, E0070, E0368, E0658.
Some errors have detailed explanations: E0067, E0368, E0658.
For more information about an error, try `rustc --explain E0067`.

View file

@ -0,0 +1,15 @@
// run-pass
#![feature(destructuring_assignment)]
fn main() {
let (mut a, mut b);
[a, b] = [0, 1];
assert_eq!((a, b), (0, 1));
let mut c;
[a, .., b, c] = [1, 2, 3, 4, 5];
assert_eq!((a, b, c), (1, 4, 5));
[..] = [1, 2, 3];
[c, ..] = [5, 6, 6];
assert_eq!(c, 5);
}

View file

@ -0,0 +1,7 @@
#![feature(destructuring_assignment)]
fn main() {
let (mut a, mut b);
[a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
[a, a, b] = [1, 2]; //~ ERROR pattern requires 3 elements but array has 2
}

View file

@ -0,0 +1,17 @@
error: `..` can only be used once per slice pattern
--> $DIR/slice_destructure_fail.rs:5:14
|
LL | [a, .., b, ..] = [0, 1];
| -- ^^ can only be used once per slice pattern
| |
| previously used here
error[E0527]: pattern requires 3 elements but array has 2
--> $DIR/slice_destructure_fail.rs:6:3
|
LL | [a, a, b] = [1, 2];
| ^^^^^^^^^ expected 2 elements
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0527`.

View file

@ -0,0 +1,19 @@
// run-pass
#![feature(destructuring_assignment)]
struct Struct<S, T> {
a: S,
b: T,
}
fn main() {
let (mut a, mut b);
Struct { a, b } = Struct { a: 0, b: 1 };
assert_eq!((a, b), (0, 1));
Struct { a: b, b: a } = Struct { a: 1, b: 2 };
assert_eq!((a,b), (2, 1));
Struct { a, .. } = Struct { a: 1, b: 3 };
assert_eq!((a, b), (1, 1));
Struct { .. } = Struct { a: 1, b: 4 };
assert_eq!((a, b), (1, 1));
}

View file

@ -0,0 +1,15 @@
#![feature(destructuring_assignment)]
struct Struct<S, T> {
a: S,
b: T,
}
fn main() {
let (mut a, b);
let mut c;
let d = Struct { a: 0, b: 1 };
Struct { a, b, c } = Struct { a: 0, b: 1 }; //~ ERROR does not have a field named `c`
Struct { a, ..d } = Struct { a: 1, b: 2 };
//~^ ERROR functional record updates are not allowed in destructuring assignments
Struct { a, .. }; //~ ERROR base expression required after `..`
}

View file

@ -0,0 +1,21 @@
error: functional record updates are not allowed in destructuring assignments
--> $DIR/struct_destructure_fail.rs:12:19
|
LL | Struct { a, ..d } = Struct { a: 1, b: 2 };
| ^ help: consider removing the trailing pattern
error: base expression required after `..`
--> $DIR/struct_destructure_fail.rs:14:19
|
LL | Struct { a, .. };
| ^ add a base expression here
error[E0026]: struct `Struct` does not have a field named `c`
--> $DIR/struct_destructure_fail.rs:11:20
|
LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
| ^ struct `Struct` does not have this field
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0026`.

View file

@ -0,0 +1,34 @@
// run-pass
#![feature(destructuring_assignment)]
struct TupleStruct<S, T>(S, T);
impl<S, T> TupleStruct<S, T> {
fn assign(self, first: &mut S, second: &mut T) {
// Test usage of `Self` instead of the struct name:
Self(*first, *second) = self
}
}
enum Enum<S, T> {
SingleVariant(S, T)
}
type Alias<S> = Enum<S, isize>;
fn main() {
let (mut a, mut b);
TupleStruct(a, b) = TupleStruct(0, 1);
assert_eq!((a, b), (0, 1));
TupleStruct(a, .., b) = TupleStruct(1, 2);
assert_eq!((a, b), (1, 2));
TupleStruct(..) = TupleStruct(3, 4);
assert_eq!((a, b), (1, 2));
TupleStruct(5,6).assign(&mut a, &mut b);
assert_eq!((a, b), (5, 6));
Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8);
assert_eq!((a, b), (7, 8));
Alias::SingleVariant(a, b) = Alias::SingleVariant(9, 10);
assert_eq!((a, b), (9, 10));
}

View file

@ -0,0 +1,42 @@
#![feature(destructuring_assignment)]
struct TupleStruct<S, T>(S, T);
enum Enum<S, T> {
SingleVariant(S, T)
}
type Alias<S> = Enum<S, isize>;
trait Test {
fn test() -> TupleStruct<isize, isize> {
TupleStruct(0, 0)
}
}
impl Test for Alias<isize> {}
fn test() -> TupleStruct<isize, isize> {
TupleStruct(0, 0)
}
fn main() {
let (mut a, mut b);
TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
//~^ ERROR `..` can only be used once per tuple struct or variant pattern
Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
//~^ ERROR `..` can only be used once per tuple struct or variant pattern
TupleStruct(a, a, b) = TupleStruct(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple struct has 2 fields
Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
//~^ ERROR this pattern has 3 fields, but the corresponding tuple variant has 2 fields
// Check if `test` is recognized as not a tuple struct but a function call:
test() = TupleStruct(0, 0);
//~^ ERROR invalid left-hand side of assignment
(test)() = TupleStruct(0, 0);
//~^ ERROR invalid left-hand side of assignment
<Alias::<isize> as Test>::test() = TupleStruct(0, 0);
//~^ ERROR invalid left-hand side of assignment
}

View file

@ -0,0 +1,62 @@
error: `..` can only be used once per tuple struct or variant pattern
--> $DIR/tuple_struct_destructure_fail.rs:25:27
|
LL | TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
| -- ^^ can only be used once per tuple struct or variant pattern
| |
| previously used here
error: `..` can only be used once per tuple struct or variant pattern
--> $DIR/tuple_struct_destructure_fail.rs:27:35
|
LL | Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
| -- ^^ can only be used once per tuple struct or variant pattern
| |
| previously used here
error[E0023]: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
--> $DIR/tuple_struct_destructure_fail.rs:30:5
|
LL | struct TupleStruct<S, T>(S, T);
| ------------------------------- tuple struct defined here
...
LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
| ^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
--> $DIR/tuple_struct_destructure_fail.rs:32:5
|
LL | SingleVariant(S, T)
| ------------------- tuple variant defined here
...
LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 3
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_struct_destructure_fail.rs:36:12
|
LL | test() = TupleStruct(0, 0);
| ------ ^
| |
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_struct_destructure_fail.rs:38:14
|
LL | (test)() = TupleStruct(0, 0);
| -------- ^
| |
| cannot assign to this expression
error[E0070]: invalid left-hand side of assignment
--> $DIR/tuple_struct_destructure_fail.rs:40:38
|
LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
| -------------------------------- ^
| |
| cannot assign to this expression
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0023, E0070.
For more information about an error, try `rustc --explain E0023`.

View file

@ -0,0 +1,8 @@
fn main() {}
struct S { x : u32 }
#[cfg(FALSE)]
fn foo() {
S { x: 5, .. }; //~ ERROR destructuring assignments are unstable
}

View file

@ -0,0 +1,12 @@
error[E0658]: destructuring assignments are unstable
--> $DIR/underscore-range-expr-gating.rs:7:15
|
LL | S { x: 5, .. };
| ^^
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,7 +1,11 @@
fn main() {
let value = [7u8];
while Some(0) = value.get(0) { //~ ERROR mismatched types
//~^ NOTE expected `bool`, found `()`
//~| HELP you might have meant to use pattern matching
while Some(0) = value.get(0) { //~ ERROR destructuring assignments are unstable
//~| ERROR invalid left-hand side of assignment
//~| ERROR mismatched types
//~| ERROR mismatched types
// FIXME The following diagnostic should also be emitted
// HELP you might have meant to use pattern matching
}
}

View file

@ -1,14 +1,38 @@
error[E0658]: destructuring assignments are unstable
--> $DIR/issue-77218.rs:3:19
|
LL | while Some(0) = value.get(0) {
| ------- ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0070]: invalid left-hand side of assignment
--> $DIR/issue-77218.rs:3:19
|
LL | while Some(0) = value.get(0) {
| - ^
| |
| cannot assign to this expression
error[E0308]: mismatched types
--> $DIR/issue-77218.rs:3:16
|
LL | while Some(0) = value.get(0) {
| ^
| |
| expected integer, found `&u8`
| help: consider dereferencing the borrow: `*0`
error[E0308]: mismatched types
--> $DIR/issue-77218.rs:3:11
|
LL | while Some(0) = value.get(0) {
| ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
help: you might have meant to use pattern matching
|
LL | while let Some(0) = value.get(0) {
| ^^^
error: aborting due to previous error
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.
Some errors have detailed explanations: E0070, E0308, E0658.
For more information about an error, try `rustc --explain E0070`.

View file

@ -2,7 +2,12 @@ fn main() {
let foo = Some(0);
let bar = None;
if Some(x) = foo {} //~ ERROR cannot find value `x` in this scope
//~^ ERROR mismatched types
//~^^ ERROR destructuring assignments are unstable
if Some(foo) = bar {} //~ ERROR mismatched types
//~^ ERROR destructuring assignments are unstable
if 3 = foo {} //~ ERROR mismatched types
if Some(3) = foo {} //~ ERROR mismatched types
//~^ ERROR destructuring assignments are unstable
//~^^ ERROR invalid left-hand side of assignment
}

View file

@ -9,23 +9,53 @@ help: you might have meant to use pattern matching
LL | if let Some(x) = foo {}
| ^^^
error[E0658]: destructuring assignments are unstable
--> $DIR/if-let-typo.rs:4:16
|
LL | if Some(x) = foo {}
| ------- ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0658]: destructuring assignments are unstable
--> $DIR/if-let-typo.rs:7:18
|
LL | if Some(foo) = bar {}
| --------- ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0658]: destructuring assignments are unstable
--> $DIR/if-let-typo.rs:10:16
|
LL | if Some(3) = foo {}
| ------- ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0308]: mismatched types
--> $DIR/if-let-typo.rs:5:8
--> $DIR/if-let-typo.rs:4:8
|
LL | if Some(x) = foo {}
| ^^^^^^^^^^^^^ expected `bool`, found `()`
error[E0308]: mismatched types
--> $DIR/if-let-typo.rs:7:8
|
LL | if Some(foo) = bar {}
| ^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
help: you might have meant to use pattern matching
|
LL | if let Some(foo) = bar {}
| ^^^
help: you might have meant to compare for equality
|
LL | if Some(foo) == bar {}
| ^^
error[E0308]: mismatched types
--> $DIR/if-let-typo.rs:6:8
--> $DIR/if-let-typo.rs:9:8
|
LL | if 3 = foo {}
| ^^^^^^^ expected `bool`, found `()`
@ -35,22 +65,21 @@ help: you might have meant to use pattern matching
LL | if let 3 = foo {}
| ^^^
error[E0070]: invalid left-hand side of assignment
--> $DIR/if-let-typo.rs:10:16
|
LL | if Some(3) = foo {}
| - ^
| |
| cannot assign to this expression
error[E0308]: mismatched types
--> $DIR/if-let-typo.rs:7:8
--> $DIR/if-let-typo.rs:10:8
|
LL | if Some(3) = foo {}
| ^^^^^^^^^^^^^ expected `bool`, found `()`
|
help: you might have meant to use pattern matching
|
LL | if let Some(3) = foo {}
| ^^^
help: you might have meant to compare for equality
|
LL | if Some(3) == foo {}
| ^^
error: aborting due to 4 previous errors
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0308, E0425.
For more information about an error, try `rustc --explain E0308`.
Some errors have detailed explanations: E0070, E0308, E0425, E0658.
For more information about an error, try `rustc --explain E0070`.

@ -1 +1 @@
Subproject commit d5556aeb8405b1fe696adb6e297ad7a1f2989b62
Subproject commit 8662ab427a8d6ad8047811cc4d78dbd20dd07699

View file

@ -107,6 +107,15 @@ pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
both(l, r, |l, r| eq_expr(l, r))
}
pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
match (l, r) {
(StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb),
(StructRest::Rest(_), StructRest::Rest(_)) => true,
(StructRest::None, StructRest::None) => true,
_ => false,
}
}
pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
use ExprKind::*;
if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) {
@ -150,7 +159,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
(Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => {
eq_path(lp, rp) && eq_expr_opt(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r))
eq_path(lp, rp) && eq_struct_rest(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r))
},
_ => false,
}

View file

@ -1,3 +1,14 @@
error[E0658]: destructuring assignments are unstable
--> $DIR/ice-6250.rs:12:25
|
LL | Some(reference) = cache.data.get(key) {
| --------------- ^
| |
| cannot assign to this expression
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
error[E0601]: `main` function not found in crate `ice_6250`
--> $DIR/ice-6250.rs:4:1
|
@ -10,18 +21,22 @@ LL | | }
LL | | }
| |_^ consider adding a `main` function to `$DIR/ice-6250.rs`
error[E0308]: mismatched types
--> $DIR/ice-6250.rs:12:14
|
LL | Some(reference) = cache.data.get(key) {
| ^^^^^^^^^
| |
| expected integer, found `&i32`
| help: consider dereferencing the borrow: `*reference`
error[E0308]: mismatched types
--> $DIR/ice-6250.rs:12:9
|
LL | Some(reference) = cache.data.get(key) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
|
help: you might have meant to use pattern matching
|
LL | let Some(reference) = cache.data.get(key) {
| ^^^
error: aborting due to 2 previous errors
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0308, E0601.
Some errors have detailed explanations: E0308, E0601, E0658.
For more information about an error, try `rustc --explain E0308`.

@ -1 +1 @@
Subproject commit eb894d53708122a67762de9489881c11aa8ce257
Subproject commit 0f29ff6da0c5ff622e739beb8fc3bbe77119b3c1