Auto merge of #78889 - Dylan-DPC:rollup-6zjhahf, r=Dylan-DPC
Rollup of 12 pull requests Successful merges: - #77640 (Refactor IntErrorKind to avoid "underflow" terminology) - #78026 (Define `fs::hard_link` to not follow symlinks.) - #78114 (Recognize `private_intra_doc_links` as a lint) - #78228 (Promote aarch64-unknown-linux-gnu to Tier 1) - #78345 (Fix handling of item names for HIR) - #78437 (BTreeMap: stop mistaking node for an orderly place) - #78476 (fix some incorrect aliasing in the BTree) - #78674 (inliner: Use substs_for_mir_body) - #78748 (Implement destructuring assignment for tuples) - #78868 (Fix tab focus on restyled switches) - #78878 (Avoid overlapping cfg attributes when both macOS and aarch64) - #78882 (Nicer hunk headers for rust files) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
fe8f026908
56 changed files with 797 additions and 391 deletions
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -3,7 +3,7 @@
|
||||||
* text=auto eol=lf
|
* text=auto eol=lf
|
||||||
*.cpp rust
|
*.cpp rust
|
||||||
*.h rust
|
*.h rust
|
||||||
*.rs rust
|
*.rs rust diff=rust
|
||||||
*.fixed linguist-language=Rust
|
*.fixed linguist-language=Rust
|
||||||
src/etc/installer/gfx/* binary
|
src/etc/installer/gfx/* binary
|
||||||
*.woff binary
|
*.woff binary
|
||||||
|
|
115
.github/workflows/ci.yml
vendored
115
.github/workflows/ci.yml
vendored
|
@ -154,6 +154,11 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- name: aarch64-gnu
|
||||||
|
os:
|
||||||
|
- self-hosted
|
||||||
|
- ARM64
|
||||||
|
- linux
|
||||||
- name: arm-android
|
- name: arm-android
|
||||||
os: ubuntu-latest-xl
|
os: ubuntu-latest-xl
|
||||||
env: {}
|
env: {}
|
||||||
|
@ -497,116 +502,6 @@ jobs:
|
||||||
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
|
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
|
||||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
|
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
|
||||||
if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
|
if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
|
||||||
auto-fallible:
|
|
||||||
name: auto-fallible
|
|
||||||
env:
|
|
||||||
CI_JOB_NAME: "${{ matrix.name }}"
|
|
||||||
SCCACHE_BUCKET: rust-lang-gha-caches
|
|
||||||
DEPLOY_BUCKET: rust-lang-gha
|
|
||||||
TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
|
|
||||||
TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
|
|
||||||
TOOLSTATE_PUBLISH: 1
|
|
||||||
CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
|
|
||||||
ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
|
|
||||||
CACHE_DOMAIN: ci-caches-gha.rust-lang.org
|
|
||||||
if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- name: aarch64-gnu
|
|
||||||
os:
|
|
||||||
- self-hosted
|
|
||||||
- ARM64
|
|
||||||
- linux
|
|
||||||
timeout-minutes: 600
|
|
||||||
runs-on: "${{ matrix.os }}"
|
|
||||||
steps:
|
|
||||||
- name: disable git crlf conversion
|
|
||||||
run: git config --global core.autocrlf false
|
|
||||||
- name: checkout the source code
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
- name: configure the PR in which the error message will be posted
|
|
||||||
run: "echo \"[CI_PR_NUMBER=$num]\""
|
|
||||||
env:
|
|
||||||
num: "${{ github.event.number }}"
|
|
||||||
if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
|
|
||||||
- name: add extra environment variables
|
|
||||||
run: src/ci/scripts/setup-environment.sh
|
|
||||||
env:
|
|
||||||
EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: decide whether to skip this job
|
|
||||||
run: src/ci/scripts/should-skip-this.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: configure GitHub Actions to kill the build when outdated
|
|
||||||
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
|
|
||||||
with:
|
|
||||||
github_token: "${{ secrets.github_token }}"
|
|
||||||
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
|
|
||||||
- name: collect CPU statistics
|
|
||||||
run: src/ci/scripts/collect-cpu-stats.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: show the current environment
|
|
||||||
run: src/ci/scripts/dump-environment.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: install awscli
|
|
||||||
run: src/ci/scripts/install-awscli.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: install sccache
|
|
||||||
run: src/ci/scripts/install-sccache.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: select Xcode
|
|
||||||
run: src/ci/scripts/select-xcode.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: install clang
|
|
||||||
run: src/ci/scripts/install-clang.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: install WIX
|
|
||||||
run: src/ci/scripts/install-wix.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: ensure the build happens on a partition with enough space
|
|
||||||
run: src/ci/scripts/symlink-build-dir.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: disable git crlf conversion
|
|
||||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: install MSYS2
|
|
||||||
run: src/ci/scripts/install-msys2.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: install MinGW
|
|
||||||
run: src/ci/scripts/install-mingw.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: install ninja
|
|
||||||
run: src/ci/scripts/install-ninja.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: enable ipv6 on Docker
|
|
||||||
run: src/ci/scripts/enable-docker-ipv6.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: disable git crlf conversion
|
|
||||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: checkout submodules
|
|
||||||
run: src/ci/scripts/checkout-submodules.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: ensure line endings are correct
|
|
||||||
run: src/ci/scripts/verify-line-endings.sh
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: run the build
|
|
||||||
run: src/ci/scripts/run-build-from-ci.sh
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
|
|
||||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
|
||||||
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
|
|
||||||
if: success() && !env.SKIP_JOB
|
|
||||||
- name: upload artifacts to S3
|
|
||||||
run: src/ci/scripts/upload-artifacts.sh
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
|
|
||||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
|
|
||||||
if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
|
|
||||||
try:
|
try:
|
||||||
name: try
|
name: try
|
||||||
env:
|
env:
|
||||||
|
|
|
@ -9,6 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
|
use rustc_session::parse::feature_err;
|
||||||
use rustc_span::hygiene::ForLoopLoc;
|
use rustc_span::hygiene::ForLoopLoc;
|
||||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||||
|
@ -146,7 +147,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
|
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
|
||||||
}
|
}
|
||||||
ExprKind::Assign(ref el, ref er, span) => {
|
ExprKind::Assign(ref el, ref er, span) => {
|
||||||
hir::ExprKind::Assign(self.lower_expr(el), self.lower_expr(er), span)
|
self.lower_expr_assign(el, er, span, e.span)
|
||||||
}
|
}
|
||||||
ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
|
ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
|
||||||
self.lower_binop(op),
|
self.lower_binop(op),
|
||||||
|
@ -840,6 +841,134 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Destructure the LHS of complex assignments.
|
||||||
|
/// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.
|
||||||
|
fn lower_expr_assign(
|
||||||
|
&mut self,
|
||||||
|
lhs: &Expr,
|
||||||
|
rhs: &Expr,
|
||||||
|
eq_sign_span: Span,
|
||||||
|
whole_span: Span,
|
||||||
|
) -> hir::ExprKind<'hir> {
|
||||||
|
// Return early in case of an ordinary assignment.
|
||||||
|
fn is_ordinary(lhs: &Expr) -> bool {
|
||||||
|
match &lhs.kind {
|
||||||
|
ExprKind::Tup(..) => false,
|
||||||
|
ExprKind::Paren(e) => {
|
||||||
|
match e.kind {
|
||||||
|
// We special-case `(..)` for consistency with patterns.
|
||||||
|
ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,
|
||||||
|
_ => is_ordinary(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if is_ordinary(lhs) {
|
||||||
|
return hir::ExprKind::Assign(self.lower_expr(lhs), self.lower_expr(rhs), eq_sign_span);
|
||||||
|
}
|
||||||
|
if !self.sess.features_untracked().destructuring_assignment {
|
||||||
|
feature_err(
|
||||||
|
&self.sess.parse_sess,
|
||||||
|
sym::destructuring_assignment,
|
||||||
|
eq_sign_span,
|
||||||
|
"destructuring assignments are unstable",
|
||||||
|
)
|
||||||
|
.span_label(lhs.span, "cannot assign to this expression")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut assignments = vec![];
|
||||||
|
|
||||||
|
// The LHS becomes a pattern: `(lhs1, lhs2)`.
|
||||||
|
let pat = self.destructure_assign(lhs, eq_sign_span, &mut assignments);
|
||||||
|
let rhs = self.lower_expr(rhs);
|
||||||
|
|
||||||
|
// Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`.
|
||||||
|
let destructure_let = self.stmt_let_pat(
|
||||||
|
ThinVec::new(),
|
||||||
|
whole_span,
|
||||||
|
Some(rhs),
|
||||||
|
pat,
|
||||||
|
hir::LocalSource::AssignDesugar(eq_sign_span),
|
||||||
|
);
|
||||||
|
|
||||||
|
// `a = lhs1; b = lhs2;`.
|
||||||
|
let stmts = self
|
||||||
|
.arena
|
||||||
|
.alloc_from_iter(std::iter::once(destructure_let).chain(assignments.into_iter()));
|
||||||
|
|
||||||
|
// Wrap everything in a block.
|
||||||
|
hir::ExprKind::Block(&self.block_all(whole_span, stmts, None), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the LHS of a destructuring assignment to a pattern.
|
||||||
|
/// Each sub-assignment is recorded in `assignments`.
|
||||||
|
fn destructure_assign(
|
||||||
|
&mut self,
|
||||||
|
lhs: &Expr,
|
||||||
|
eq_sign_span: Span,
|
||||||
|
assignments: &mut Vec<hir::Stmt<'hir>>,
|
||||||
|
) -> &'hir hir::Pat<'hir> {
|
||||||
|
match &lhs.kind {
|
||||||
|
// Tuples.
|
||||||
|
ExprKind::Tup(elements) => {
|
||||||
|
let (pats, rest) =
|
||||||
|
self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
|
||||||
|
let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
|
||||||
|
return self.pat_without_dbm(lhs.span, tuple_pat);
|
||||||
|
}
|
||||||
|
ExprKind::Paren(e) => {
|
||||||
|
// We special-case `(..)` for consistency with patterns.
|
||||||
|
if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
|
||||||
|
let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
|
||||||
|
return self.pat_without_dbm(lhs.span, tuple_pat);
|
||||||
|
} else {
|
||||||
|
return self.destructure_assign(e, eq_sign_span, assignments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
// Treat all other cases as normal lvalue.
|
||||||
|
let ident = Ident::new(sym::lhs, lhs.span);
|
||||||
|
let (pat, binding) = self.pat_ident(lhs.span, ident);
|
||||||
|
let ident = self.expr_ident(lhs.span, ident, binding);
|
||||||
|
let assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, eq_sign_span);
|
||||||
|
let expr = self.expr(lhs.span, assign, ThinVec::new());
|
||||||
|
assignments.push(self.stmt_expr(lhs.span, expr));
|
||||||
|
pat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destructure a sequence of expressions occurring on the LHS of an assignment.
|
||||||
|
/// Such a sequence occurs in a tuple (struct)/slice.
|
||||||
|
/// Return a sequence of corresponding patterns, and the index and the span of `..` if it
|
||||||
|
/// exists.
|
||||||
|
/// Each sub-assignment is recorded in `assignments`.
|
||||||
|
fn destructure_sequence(
|
||||||
|
&mut self,
|
||||||
|
elements: &[AstP<Expr>],
|
||||||
|
ctx: &str,
|
||||||
|
eq_sign_span: Span,
|
||||||
|
assignments: &mut Vec<hir::Stmt<'hir>>,
|
||||||
|
) -> (&'hir [&'hir hir::Pat<'hir>], Option<(usize, Span)>) {
|
||||||
|
let mut rest = None;
|
||||||
|
let elements =
|
||||||
|
self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {
|
||||||
|
// Check for `..` pattern.
|
||||||
|
if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
|
||||||
|
if let Some((_, prev_span)) = rest {
|
||||||
|
self.ban_extra_rest_pat(e.span, prev_span, ctx);
|
||||||
|
} else {
|
||||||
|
rest = Some((i, e.span));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.destructure_assign(e, eq_sign_span, assignments))
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
(elements, rest)
|
||||||
|
}
|
||||||
|
|
||||||
/// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
|
/// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
|
||||||
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
||||||
let e1 = self.lower_expr_mut(e1);
|
let e1 = self.lower_expr_mut(e1);
|
||||||
|
|
|
@ -2531,6 +2531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
hir_id,
|
hir_id,
|
||||||
kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
|
kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
|
||||||
span,
|
span,
|
||||||
|
default_binding_modes: true,
|
||||||
}),
|
}),
|
||||||
hir_id,
|
hir_id,
|
||||||
)
|
)
|
||||||
|
@ -2541,7 +2542,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span })
|
self.arena.alloc(hir::Pat {
|
||||||
|
hir_id: self.next_id(),
|
||||||
|
kind,
|
||||||
|
span,
|
||||||
|
default_binding_modes: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
|
self.arena.alloc(hir::Pat {
|
||||||
|
hir_id: self.next_id(),
|
||||||
|
kind,
|
||||||
|
span,
|
||||||
|
default_binding_modes: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_path(
|
fn ty_path(
|
||||||
|
|
|
@ -273,11 +273,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|
|
||||||
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
|
/// Construct a `Pat` with the `HirId` of `p.id` lowered.
|
||||||
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
|
||||||
self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
|
self.arena.alloc(hir::Pat {
|
||||||
|
hir_id: self.lower_node_id(p.id),
|
||||||
|
kind,
|
||||||
|
span: p.span,
|
||||||
|
default_binding_modes: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
/// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
|
||||||
fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
|
crate fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
|
||||||
self.diagnostic()
|
self.diagnostic()
|
||||||
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
|
.struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
|
||||||
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
|
.span_label(sp, &format!("can only be used once per {} pattern", ctx))
|
||||||
|
|
|
@ -361,13 +361,11 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> {
|
||||||
where
|
where
|
||||||
T: TypeFoldable<'tcx> + Copy,
|
T: TypeFoldable<'tcx> + Copy,
|
||||||
{
|
{
|
||||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||||
self.tcx
|
self.tcx,
|
||||||
.subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), value)
|
ty::ParamEnv::reveal_all(),
|
||||||
} else {
|
value
|
||||||
self.tcx
|
)
|
||||||
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
|
pub(crate) fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
|
||||||
|
|
|
@ -92,15 +92,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
T: Copy + TypeFoldable<'tcx>,
|
T: Copy + TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("monomorphize: self.instance={:?}", self.instance);
|
debug!("monomorphize: self.instance={:?}", self.instance);
|
||||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||||
self.cx.tcx().subst_and_normalize_erasing_regions(
|
self.cx.tcx(),
|
||||||
substs,
|
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
&value,
|
value,
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
self.cx.tcx().normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -610,6 +610,9 @@ declare_features! (
|
||||||
/// Allows unsized fn parameters.
|
/// Allows unsized fn parameters.
|
||||||
(active, unsized_fn_params, "1.49.0", Some(48055), None),
|
(active, unsized_fn_params, "1.49.0", Some(48055), None),
|
||||||
|
|
||||||
|
/// Allows the use of destructuring assignments.
|
||||||
|
(active, destructuring_assignment, "1.49.0", Some(71126), None),
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// feature-group-end: actual feature gates
|
// feature-group-end: actual feature gates
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
|
@ -732,6 +732,9 @@ pub struct Pat<'hir> {
|
||||||
pub hir_id: HirId,
|
pub hir_id: HirId,
|
||||||
pub kind: PatKind<'hir>,
|
pub kind: PatKind<'hir>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
// Whether to use default binding modes.
|
||||||
|
// At present, this is false only for destructuring assignment.
|
||||||
|
pub default_binding_modes: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pat<'_> {
|
impl Pat<'_> {
|
||||||
|
@ -1680,6 +1683,9 @@ pub enum LocalSource {
|
||||||
AsyncFn,
|
AsyncFn,
|
||||||
/// A desugared `<expr>.await`.
|
/// A desugared `<expr>.await`.
|
||||||
AwaitDesugar,
|
AwaitDesugar,
|
||||||
|
/// A desugared `expr = expr`, where the LHS is a tuple, struct or array.
|
||||||
|
/// The span is that of the `=` sign.
|
||||||
|
AssignDesugar(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hints at the original code for a `match _ { .. }`.
|
/// Hints at the original code for a `match _ { .. }`.
|
||||||
|
@ -2677,6 +2683,9 @@ impl<'hir> Node<'hir> {
|
||||||
Node::TraitItem(TraitItem { ident, .. })
|
Node::TraitItem(TraitItem { ident, .. })
|
||||||
| Node::ImplItem(ImplItem { ident, .. })
|
| Node::ImplItem(ImplItem { ident, .. })
|
||||||
| Node::ForeignItem(ForeignItem { ident, .. })
|
| Node::ForeignItem(ForeignItem { ident, .. })
|
||||||
|
| Node::Field(StructField { ident, .. })
|
||||||
|
| Node::Variant(Variant { ident, .. })
|
||||||
|
| Node::MacroDef(MacroDef { ident, .. })
|
||||||
| Node::Item(Item { ident, .. }) => Some(*ident),
|
| Node::Item(Item { ident, .. }) => Some(*ident),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2801,6 +2801,7 @@ declare_lint_pass! {
|
||||||
UNSTABLE_NAME_COLLISIONS,
|
UNSTABLE_NAME_COLLISIONS,
|
||||||
IRREFUTABLE_LET_PATTERNS,
|
IRREFUTABLE_LET_PATTERNS,
|
||||||
BROKEN_INTRA_DOC_LINKS,
|
BROKEN_INTRA_DOC_LINKS,
|
||||||
|
PRIVATE_INTRA_DOC_LINKS,
|
||||||
INVALID_CODEBLOCK_ATTRIBUTES,
|
INVALID_CODEBLOCK_ATTRIBUTES,
|
||||||
MISSING_CRATE_LEVEL_DOCS,
|
MISSING_CRATE_LEVEL_DOCS,
|
||||||
MISSING_DOC_CODE_EXAMPLES,
|
MISSING_DOC_CODE_EXAMPLES,
|
||||||
|
|
|
@ -478,7 +478,7 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
|
pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
|
||||||
id.as_local().map(|id| self.get(self.local_def_id_to_hir_id(id)))
|
id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
|
pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
|
||||||
|
|
|
@ -48,10 +48,12 @@ fn update_limit(
|
||||||
.unwrap_or(attr.span);
|
.unwrap_or(attr.span);
|
||||||
|
|
||||||
let error_str = match e.kind() {
|
let error_str = match e.kind() {
|
||||||
IntErrorKind::Overflow => "`limit` is too large",
|
IntErrorKind::PosOverflow => "`limit` is too large",
|
||||||
IntErrorKind::Empty => "`limit` must be a non-negative integer",
|
IntErrorKind::Empty => "`limit` must be a non-negative integer",
|
||||||
IntErrorKind::InvalidDigit => "not a valid integer",
|
IntErrorKind::InvalidDigit => "not a valid integer",
|
||||||
IntErrorKind::Underflow => bug!("`limit` should never underflow"),
|
IntErrorKind::NegOverflow => {
|
||||||
|
bug!("`limit` should never negatively overflow")
|
||||||
|
}
|
||||||
IntErrorKind::Zero => bug!("zero is a valid `limit`"),
|
IntErrorKind::Zero => bug!("zero is a valid `limit`"),
|
||||||
kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
|
kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use crate::ty::print::{FmtPrinter, Printer};
|
use crate::ty::print::{FmtPrinter, Printer};
|
||||||
use crate::ty::subst::InternalSubsts;
|
use crate::ty::subst::{InternalSubsts, Subst};
|
||||||
use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
|
use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
|
@ -470,10 +470,33 @@ impl<'tcx> Instance<'tcx> {
|
||||||
/// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if
|
/// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if
|
||||||
/// this function returns `None`, then the MIR body does not require substitution during
|
/// this function returns `None`, then the MIR body does not require substitution during
|
||||||
/// codegen.
|
/// codegen.
|
||||||
pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
|
fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
|
||||||
if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None }
|
if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: &T) -> T
|
||||||
|
where
|
||||||
|
T: TypeFoldable<'tcx> + Copy,
|
||||||
|
{
|
||||||
|
if let Some(substs) = self.substs_for_mir_body() { v.subst(tcx, substs) } else { *v }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subst_mir_and_normalize_erasing_regions<T>(
|
||||||
|
&self,
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
v: &T,
|
||||||
|
) -> T
|
||||||
|
where
|
||||||
|
T: TypeFoldable<'tcx> + Clone,
|
||||||
|
{
|
||||||
|
if let Some(substs) = self.substs_for_mir_body() {
|
||||||
|
tcx.subst_and_normalize_erasing_regions(substs, param_env, v)
|
||||||
|
} else {
|
||||||
|
tcx.normalize_erasing_regions(param_env, v.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
|
/// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
|
||||||
/// identify parameters if they are determined to be unused in `instance.def`.
|
/// identify parameters if they are determined to be unused in `instance.def`.
|
||||||
pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
|
pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
|
||||||
|
|
|
@ -2795,10 +2795,50 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
.filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
|
.filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn item_name_from_hir(self, def_id: DefId) -> Option<Ident> {
|
||||||
|
self.hir().get_if_local(def_id).and_then(|node| node.ident())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
|
||||||
|
if def_id.index == CRATE_DEF_INDEX {
|
||||||
|
Some(self.original_crate_name(def_id.krate))
|
||||||
|
} else {
|
||||||
|
let def_key = self.def_key(def_id);
|
||||||
|
match def_key.disambiguated_data.data {
|
||||||
|
// The name of a constructor is that of its parent.
|
||||||
|
rustc_hir::definitions::DefPathData::Ctor => self.item_name_from_def_id(DefId {
|
||||||
|
krate: def_id.krate,
|
||||||
|
index: def_key.parent.unwrap(),
|
||||||
|
}),
|
||||||
|
_ => def_key.disambiguated_data.data.get_opt_name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look up the name of an item across crates. This does not look at HIR.
|
||||||
|
///
|
||||||
|
/// When possible, this function should be used for cross-crate lookups over
|
||||||
|
/// [`opt_item_name`] to avoid invalidating the incremental cache. If you
|
||||||
|
/// need to handle items without a name, or HIR items that will not be
|
||||||
|
/// serialized cross-crate, or if you need the span of the item, use
|
||||||
|
/// [`opt_item_name`] instead.
|
||||||
|
///
|
||||||
|
/// [`opt_item_name`]: Self::opt_item_name
|
||||||
|
pub fn item_name(self, id: DefId) -> Symbol {
|
||||||
|
// Look at cross-crate items first to avoid invalidating the incremental cache
|
||||||
|
// unless we have to.
|
||||||
|
self.item_name_from_def_id(id).unwrap_or_else(|| {
|
||||||
|
bug!("item_name: no name for {:?}", self.def_path(id));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Look up the name and span of an item or [`Node`].
|
||||||
|
///
|
||||||
|
/// See [`item_name`][Self::item_name] for more information.
|
||||||
pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> {
|
pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> {
|
||||||
def_id
|
// Look at the HIR first so the span will be correct if this is a local item.
|
||||||
.as_local()
|
self.item_name_from_hir(def_id)
|
||||||
.and_then(|def_id| self.hir().get(self.hir().local_def_id_to_hir_id(def_id)).ident())
|
.or_else(|| self.item_name_from_def_id(def_id).map(Ident::with_dummy_span))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
|
pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
|
||||||
|
@ -2921,23 +2961,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn item_name(self, id: DefId) -> Symbol {
|
|
||||||
if id.index == CRATE_DEF_INDEX {
|
|
||||||
self.original_crate_name(id.krate)
|
|
||||||
} else {
|
|
||||||
let def_key = self.def_key(id);
|
|
||||||
match def_key.disambiguated_data.data {
|
|
||||||
// The name of a constructor is that of its parent.
|
|
||||||
rustc_hir::definitions::DefPathData::Ctor => {
|
|
||||||
self.item_name(DefId { krate: id.krate, index: def_key.parent.unwrap() })
|
|
||||||
}
|
|
||||||
_ => def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| {
|
|
||||||
bug!("item_name: no name for {:?}", self.def_path(id));
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
|
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
|
||||||
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
|
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
|
||||||
match instance {
|
match instance {
|
||||||
|
|
|
@ -505,11 +505,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
|
||||||
value: T,
|
value: T,
|
||||||
) -> T {
|
) -> T {
|
||||||
if let Some(substs) = frame.instance.substs_for_mir_body() {
|
frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, &value)
|
||||||
self.tcx.subst_and_normalize_erasing_regions(substs, self.param_env, &value)
|
|
||||||
} else {
|
|
||||||
self.tcx.normalize_erasing_regions(self.param_env, value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
|
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
|
||||||
|
|
|
@ -543,11 +543,11 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("monomorphize: self.instance={:?}", self.instance);
|
debug!("monomorphize: self.instance={:?}", self.instance);
|
||||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||||
self.tcx.subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), &value)
|
self.tcx,
|
||||||
} else {
|
ty::ParamEnv::reveal_all(),
|
||||||
self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), value)
|
&value,
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ use rustc_index::vec::Idx;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||||
use rustc_middle::mir::visit::*;
|
use rustc_middle::mir::visit::*;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::subst::Subst;
|
|
||||||
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
|
||||||
use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
|
use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
@ -128,17 +127,15 @@ impl Inliner<'tcx> {
|
||||||
self.tcx.instance_mir(callsite.callee.def)
|
self.tcx.instance_mir(callsite.callee.def)
|
||||||
};
|
};
|
||||||
|
|
||||||
let callee_body: &Body<'tcx> = &*callee_body;
|
if !self.consider_optimizing(callsite, &callee_body) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let callee_body = if self.consider_optimizing(callsite, callee_body) {
|
let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
|
||||||
self.tcx.subst_and_normalize_erasing_regions(
|
self.tcx,
|
||||||
&callsite.callee.substs,
|
|
||||||
self.param_env,
|
self.param_env,
|
||||||
callee_body,
|
callee_body,
|
||||||
)
|
);
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let start = caller_body.basic_blocks().len();
|
let start = caller_body.basic_blocks().len();
|
||||||
debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body);
|
debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body);
|
||||||
|
@ -309,7 +306,7 @@ impl Inliner<'tcx> {
|
||||||
work_list.push(target);
|
work_list.push(target);
|
||||||
// If the place doesn't actually need dropping, treat it like
|
// If the place doesn't actually need dropping, treat it like
|
||||||
// a regular goto.
|
// a regular goto.
|
||||||
let ty = place.ty(callee_body, tcx).subst(tcx, callsite.callee.substs).ty;
|
let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
|
||||||
if ty.needs_drop(tcx, self.param_env) {
|
if ty.needs_drop(tcx, self.param_env) {
|
||||||
cost += CALL_PENALTY;
|
cost += CALL_PENALTY;
|
||||||
if let Some(unwind) = unwind {
|
if let Some(unwind) = unwind {
|
||||||
|
@ -371,8 +368,7 @@ impl Inliner<'tcx> {
|
||||||
let ptr_size = tcx.data_layout.pointer_size.bytes();
|
let ptr_size = tcx.data_layout.pointer_size.bytes();
|
||||||
|
|
||||||
for v in callee_body.vars_and_temps_iter() {
|
for v in callee_body.vars_and_temps_iter() {
|
||||||
let v = &callee_body.local_decls[v];
|
let ty = callsite.callee.subst_mir(self.tcx, &callee_body.local_decls[v].ty);
|
||||||
let ty = v.ty.subst(tcx, callsite.callee.substs);
|
|
||||||
// Cost of the var is the size in machine-words, if we know
|
// Cost of the var is the size in machine-words, if we know
|
||||||
// it.
|
// it.
|
||||||
if let Some(size) = type_size_of(tcx, self.param_env, ty) {
|
if let Some(size) = type_size_of(tcx, self.param_env, ty) {
|
||||||
|
|
|
@ -69,6 +69,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
|
||||||
hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
|
hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
|
||||||
hir::LocalSource::AsyncFn => ("async fn binding", None),
|
hir::LocalSource::AsyncFn => ("async fn binding", None),
|
||||||
hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
|
hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
|
||||||
|
hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
|
||||||
};
|
};
|
||||||
self.check_irrefutable(&loc.pat, msg, sp);
|
self.check_irrefutable(&loc.pat, msg, sp);
|
||||||
self.check_patterns(&loc.pat);
|
self.check_patterns(&loc.pat);
|
||||||
|
|
|
@ -434,6 +434,7 @@ symbols! {
|
||||||
deref_mut,
|
deref_mut,
|
||||||
deref_target,
|
deref_target,
|
||||||
derive,
|
derive,
|
||||||
|
destructuring_assignment,
|
||||||
diagnostic,
|
diagnostic,
|
||||||
direct,
|
direct,
|
||||||
discriminant_kind,
|
discriminant_kind,
|
||||||
|
|
|
@ -718,26 +718,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_destructuring_place_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> bool {
|
|
||||||
match &expr.kind {
|
|
||||||
ExprKind::Array(comps) | ExprKind::Tup(comps) => {
|
|
||||||
comps.iter().all(|e| self.is_destructuring_place_expr(e))
|
|
||||||
}
|
|
||||||
ExprKind::Struct(_path, fields, rest) => {
|
|
||||||
rest.as_ref().map(|e| self.is_destructuring_place_expr(e)).unwrap_or(true)
|
|
||||||
&& fields.iter().all(|f| self.is_destructuring_place_expr(&f.expr))
|
|
||||||
}
|
|
||||||
_ => expr.is_syntactic_place_expr(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn check_lhs_assignable(
|
pub(crate) fn check_lhs_assignable(
|
||||||
&self,
|
&self,
|
||||||
lhs: &'tcx hir::Expr<'tcx>,
|
lhs: &'tcx hir::Expr<'tcx>,
|
||||||
err_code: &'static str,
|
err_code: &'static str,
|
||||||
expr_span: &Span,
|
expr_span: &Span,
|
||||||
) {
|
) {
|
||||||
if !lhs.is_syntactic_place_expr() {
|
if lhs.is_syntactic_place_expr() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
|
// FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
|
||||||
let mut err = self.tcx.sess.struct_span_err_with_code(
|
let mut err = self.tcx.sess.struct_span_err_with_code(
|
||||||
*expr_span,
|
*expr_span,
|
||||||
|
@ -745,13 +735,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
DiagnosticId::Error(err_code.into()),
|
DiagnosticId::Error(err_code.into()),
|
||||||
);
|
);
|
||||||
err.span_label(lhs.span, "cannot assign to this expression");
|
err.span_label(lhs.span, "cannot assign to this expression");
|
||||||
if self.is_destructuring_place_expr(lhs) {
|
|
||||||
err.note("destructuring assignments are not currently supported");
|
|
||||||
err.note("for more information, see https://github.com/rust-lang/rfcs/issues/372");
|
|
||||||
}
|
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Type check assignment expression `expr` of form `lhs = rhs`.
|
/// Type check assignment expression `expr` of form `lhs = rhs`.
|
||||||
/// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
|
/// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
|
||||||
|
|
|
@ -270,6 +270,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
///
|
///
|
||||||
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
|
/// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
|
||||||
fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
|
fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
|
||||||
|
// When we perform destructuring assignment, we disable default match bindings, which are
|
||||||
|
// unintuitive in this context.
|
||||||
|
if !pat.default_binding_modes {
|
||||||
|
return AdjustMode::Reset;
|
||||||
|
}
|
||||||
match &pat.kind {
|
match &pat.kind {
|
||||||
// Type checking these product-like types successfully always require
|
// Type checking these product-like types successfully always require
|
||||||
// that the expected type be of those types and not reference types.
|
// that the expected type be of those types and not reference types.
|
||||||
|
|
|
@ -577,7 +577,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
|
||||||
fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
|
fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
|
||||||
debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
|
debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
|
||||||
ignore_err!(self.with_mc(|mc| {
|
ignore_err!(self.with_mc(|mc| {
|
||||||
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| {
|
mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id, .. }| {
|
||||||
// `ref x` pattern
|
// `ref x` pattern
|
||||||
if let PatKind::Binding(..) = kind {
|
if let PatKind::Binding(..) = kind {
|
||||||
if let Some(ty::BindByReference(mutbl)) =
|
if let Some(ty::BindByReference(mutbl)) =
|
||||||
|
|
|
@ -42,7 +42,7 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
|
impl<K, V> BTreeMap<K, V> {
|
||||||
/// Panics if the map (or the code navigating it) is corrupted.
|
/// Panics if the map (or the code navigating it) is corrupted.
|
||||||
fn check(&self)
|
fn check(&self)
|
||||||
where
|
where
|
||||||
|
@ -54,14 +54,14 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
|
||||||
assert!(root_node.ascend().is_err());
|
assert!(root_node.ascend().is_err());
|
||||||
root_node.assert_back_pointers();
|
root_node.assert_back_pointers();
|
||||||
|
|
||||||
let counted = root_node.assert_ascending();
|
|
||||||
assert_eq!(self.length, counted);
|
|
||||||
assert_eq!(self.length, root_node.calc_length());
|
assert_eq!(self.length, root_node.calc_length());
|
||||||
|
|
||||||
root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 });
|
root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 });
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(self.length, 0);
|
assert_eq!(self.length, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.assert_ascending();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the height of the root, if any.
|
/// Returns the height of the root, if any.
|
||||||
|
@ -79,10 +79,28 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
|
||||||
String::from("not yet allocated")
|
String::from("not yet allocated")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Asserts that the keys are in strictly ascending order.
|
||||||
|
fn assert_ascending(&self)
|
||||||
|
where
|
||||||
|
K: Copy + Debug + Ord,
|
||||||
|
{
|
||||||
|
let mut num_seen = 0;
|
||||||
|
let mut keys = self.keys();
|
||||||
|
if let Some(mut previous) = keys.next() {
|
||||||
|
num_seen = 1;
|
||||||
|
for next in keys {
|
||||||
|
assert!(previous < next, "{:?} >= {:?}", previous, next);
|
||||||
|
previous = next;
|
||||||
|
num_seen += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(num_seen, self.len());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
|
impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
|
||||||
pub fn assert_min_len(self, min_len: usize) {
|
fn assert_min_len(self, min_len: usize) {
|
||||||
assert!(self.len() >= min_len, "{} < {}", self.len(), min_len);
|
assert!(self.len() >= min_len, "{} < {}", self.len(), min_len);
|
||||||
if let node::ForceResult::Internal(node) = self.force() {
|
if let node::ForceResult::Internal(node) = self.force() {
|
||||||
for idx in 0..=node.len() {
|
for idx in 0..=node.len() {
|
||||||
|
|
|
@ -1608,15 +1608,19 @@ pub mod marker {
|
||||||
|
|
||||||
unsafe fn slice_insert<T>(slice: &mut [T], idx: usize, val: T) {
|
unsafe fn slice_insert<T>(slice: &mut [T], idx: usize, val: T) {
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
|
let len = slice.len();
|
||||||
ptr::write(slice.get_unchecked_mut(idx), val);
|
let slice_ptr = slice.as_mut_ptr();
|
||||||
|
ptr::copy(slice_ptr.add(idx), slice_ptr.add(idx + 1), len - idx);
|
||||||
|
ptr::write(slice_ptr.add(idx), val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn slice_remove<T>(slice: &mut [T], idx: usize) -> T {
|
unsafe fn slice_remove<T>(slice: &mut [T], idx: usize) -> T {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ret = ptr::read(slice.get_unchecked(idx));
|
let len = slice.len();
|
||||||
ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
|
let slice_ptr = slice.as_mut_ptr();
|
||||||
|
let ret = ptr::read(slice_ptr.add(idx));
|
||||||
|
ptr::copy(slice_ptr.add(idx + 1), slice_ptr.add(idx), len - idx - 1);
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,43 +17,6 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts that the keys are in strictly ascending order.
|
|
||||||
/// Returns how many keys it encountered.
|
|
||||||
pub fn assert_ascending(self) -> usize
|
|
||||||
where
|
|
||||||
K: Copy + Debug + Ord,
|
|
||||||
{
|
|
||||||
struct SeriesChecker<T> {
|
|
||||||
num_seen: usize,
|
|
||||||
previous: Option<T>,
|
|
||||||
}
|
|
||||||
impl<T: Copy + Debug + Ord> SeriesChecker<T> {
|
|
||||||
fn is_ascending(&mut self, next: T) {
|
|
||||||
if let Some(previous) = self.previous {
|
|
||||||
assert!(previous < next, "{:?} >= {:?}", previous, next);
|
|
||||||
}
|
|
||||||
self.previous = Some(next);
|
|
||||||
self.num_seen += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut checker = SeriesChecker { num_seen: 0, previous: None };
|
|
||||||
self.visit_nodes_in_order(|pos| match pos {
|
|
||||||
navigate::Position::Leaf(node) => {
|
|
||||||
for idx in 0..node.len() {
|
|
||||||
let key = *unsafe { node.key_at(idx) };
|
|
||||||
checker.is_ascending(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
navigate::Position::InternalKV(kv) => {
|
|
||||||
let key = *kv.into_kv().0;
|
|
||||||
checker.is_ascending(key);
|
|
||||||
}
|
|
||||||
navigate::Position::Internal(_) => {}
|
|
||||||
});
|
|
||||||
checker.num_seen
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dump_keys(self) -> String
|
pub fn dump_keys(self) -> String
|
||||||
where
|
where
|
||||||
K: Debug,
|
K: Debug,
|
||||||
|
|
|
@ -159,6 +159,7 @@
|
||||||
#![feature(slice_ptr_get)]
|
#![feature(slice_ptr_get)]
|
||||||
#![feature(no_niche)] // rust-lang/rust#68303
|
#![feature(no_niche)] // rust-lang/rust#68303
|
||||||
#![feature(unsafe_block_in_unsafe_fn)]
|
#![feature(unsafe_block_in_unsafe_fn)]
|
||||||
|
#![feature(int_error_matching)]
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
#[prelude_import]
|
#[prelude_import]
|
||||||
|
|
|
@ -98,15 +98,18 @@ pub enum IntErrorKind {
|
||||||
///
|
///
|
||||||
/// Among other causes, this variant will be constructed when parsing an empty string.
|
/// Among other causes, this variant will be constructed when parsing an empty string.
|
||||||
Empty,
|
Empty,
|
||||||
/// Contains an invalid digit.
|
/// Contains an invalid digit in its context.
|
||||||
///
|
///
|
||||||
/// Among other causes, this variant will be constructed when parsing a string that
|
/// Among other causes, this variant will be constructed when parsing a string that
|
||||||
/// contains a letter.
|
/// contains a non-ASCII char.
|
||||||
|
///
|
||||||
|
/// This variant is also constructed when a `+` or `-` is misplaced within a string
|
||||||
|
/// either on its own or in the middle of a number.
|
||||||
InvalidDigit,
|
InvalidDigit,
|
||||||
/// Integer is too large to store in target integer type.
|
/// Integer is too large to store in target integer type.
|
||||||
Overflow,
|
PosOverflow,
|
||||||
/// Integer is too small to store in target integer type.
|
/// Integer is too small to store in target integer type.
|
||||||
Underflow,
|
NegOverflow,
|
||||||
/// Value was Zero
|
/// Value was Zero
|
||||||
///
|
///
|
||||||
/// This variant will be emitted when the parsing string has a value of zero, which
|
/// This variant will be emitted when the parsing string has a value of zero, which
|
||||||
|
@ -136,8 +139,8 @@ impl ParseIntError {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
IntErrorKind::Empty => "cannot parse integer from empty string",
|
IntErrorKind::Empty => "cannot parse integer from empty string",
|
||||||
IntErrorKind::InvalidDigit => "invalid digit found in string",
|
IntErrorKind::InvalidDigit => "invalid digit found in string",
|
||||||
IntErrorKind::Overflow => "number too large to fit in target type",
|
IntErrorKind::PosOverflow => "number too large to fit in target type",
|
||||||
IntErrorKind::Underflow => "number too small to fit in target type",
|
IntErrorKind::NegOverflow => "number too small to fit in target type",
|
||||||
IntErrorKind::Zero => "number would be zero for non-zero type",
|
IntErrorKind::Zero => "number would be zero for non-zero type",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,12 @@ pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, No
|
||||||
#[stable(feature = "try_from", since = "1.34.0")]
|
#[stable(feature = "try_from", since = "1.34.0")]
|
||||||
pub use error::TryFromIntError;
|
pub use error::TryFromIntError;
|
||||||
|
|
||||||
#[unstable(feature = "int_error_matching", issue = "22639")]
|
#[unstable(
|
||||||
|
feature = "int_error_matching",
|
||||||
|
reason = "it can be useful to match errors when making error messages \
|
||||||
|
for integer parsing",
|
||||||
|
issue = "22639"
|
||||||
|
)]
|
||||||
pub use error::IntErrorKind;
|
pub use error::IntErrorKind;
|
||||||
|
|
||||||
macro_rules! usize_isize_to_xe_bytes_doc {
|
macro_rules! usize_isize_to_xe_bytes_doc {
|
||||||
|
@ -830,15 +835,14 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
|
||||||
let src = src.as_bytes();
|
let src = src.as_bytes();
|
||||||
|
|
||||||
let (is_positive, digits) = match src[0] {
|
let (is_positive, digits) = match src[0] {
|
||||||
|
b'+' | b'-' if src[1..].is_empty() => {
|
||||||
|
return Err(PIE { kind: InvalidDigit });
|
||||||
|
}
|
||||||
b'+' => (true, &src[1..]),
|
b'+' => (true, &src[1..]),
|
||||||
b'-' if is_signed_ty => (false, &src[1..]),
|
b'-' if is_signed_ty => (false, &src[1..]),
|
||||||
_ => (true, src),
|
_ => (true, src),
|
||||||
};
|
};
|
||||||
|
|
||||||
if digits.is_empty() {
|
|
||||||
return Err(PIE { kind: Empty });
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = T::from_u32(0);
|
let mut result = T::from_u32(0);
|
||||||
if is_positive {
|
if is_positive {
|
||||||
// The number is positive
|
// The number is positive
|
||||||
|
@ -849,11 +853,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
|
||||||
};
|
};
|
||||||
result = match result.checked_mul(radix) {
|
result = match result.checked_mul(radix) {
|
||||||
Some(result) => result,
|
Some(result) => result,
|
||||||
None => return Err(PIE { kind: Overflow }),
|
None => return Err(PIE { kind: PosOverflow }),
|
||||||
};
|
};
|
||||||
result = match result.checked_add(x) {
|
result = match result.checked_add(x) {
|
||||||
Some(result) => result,
|
Some(result) => result,
|
||||||
None => return Err(PIE { kind: Overflow }),
|
None => return Err(PIE { kind: PosOverflow }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -865,11 +869,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
|
||||||
};
|
};
|
||||||
result = match result.checked_mul(radix) {
|
result = match result.checked_mul(radix) {
|
||||||
Some(result) => result,
|
Some(result) => result,
|
||||||
None => return Err(PIE { kind: Underflow }),
|
None => return Err(PIE { kind: NegOverflow }),
|
||||||
};
|
};
|
||||||
result = match result.checked_sub(x) {
|
result = match result.checked_sub(x) {
|
||||||
Some(result) => result,
|
Some(result) => result,
|
||||||
None => return Err(PIE { kind: Underflow }),
|
None => return Err(PIE { kind: NegOverflow }),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,11 +135,11 @@ fn test_from_str() {
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
|
"-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
|
||||||
Some(IntErrorKind::Underflow)
|
Some(IntErrorKind::NegOverflow)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
|
"257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
|
||||||
Some(IntErrorKind::Overflow)
|
Some(IntErrorKind::PosOverflow)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,11 @@ use core::cmp::PartialEq;
|
||||||
use core::convert::{TryFrom, TryInto};
|
use core::convert::{TryFrom, TryInto};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::marker::Copy;
|
use core::marker::Copy;
|
||||||
use core::num::TryFromIntError;
|
use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
|
||||||
use core::ops::{Add, Div, Mul, Rem, Sub};
|
use core::ops::{Add, Div, Mul, Rem, Sub};
|
||||||
use core::option::Option;
|
use core::option::Option;
|
||||||
use core::option::Option::{None, Some};
|
use core::option::Option::None;
|
||||||
|
use core::str::FromStr;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod int_macros;
|
mod int_macros;
|
||||||
|
@ -67,6 +68,15 @@ where
|
||||||
assert_eq!(ten.rem(two), ten % two);
|
assert_eq!(ten.rem(two), ten % two);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function for asserting number parsing returns a specific error
|
||||||
|
fn test_parse<T>(num_str: &str, expected: Result<T, IntErrorKind>)
|
||||||
|
where
|
||||||
|
T: FromStr<Err = ParseIntError>,
|
||||||
|
Result<T, IntErrorKind>: PartialEq + Debug,
|
||||||
|
{
|
||||||
|
assert_eq!(num_str.parse::<T>().map_err(|e| e.kind().clone()), expected)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_str_issue7588() {
|
fn from_str_issue7588() {
|
||||||
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
|
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
|
||||||
|
@ -77,49 +87,52 @@ fn from_str_issue7588() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_int_from_str_overflow() {
|
fn test_int_from_str_overflow() {
|
||||||
assert_eq!("127".parse::<i8>().ok(), Some(127i8));
|
test_parse::<i8>("127", Ok(127));
|
||||||
assert_eq!("128".parse::<i8>().ok(), None);
|
test_parse::<i8>("128", Err(IntErrorKind::PosOverflow));
|
||||||
|
|
||||||
assert_eq!("-128".parse::<i8>().ok(), Some(-128i8));
|
test_parse::<i8>("-128", Ok(-128));
|
||||||
assert_eq!("-129".parse::<i8>().ok(), None);
|
test_parse::<i8>("-129", Err(IntErrorKind::NegOverflow));
|
||||||
|
|
||||||
assert_eq!("32767".parse::<i16>().ok(), Some(32_767i16));
|
test_parse::<i16>("32767", Ok(32_767));
|
||||||
assert_eq!("32768".parse::<i16>().ok(), None);
|
test_parse::<i16>("32768", Err(IntErrorKind::PosOverflow));
|
||||||
|
|
||||||
assert_eq!("-32768".parse::<i16>().ok(), Some(-32_768i16));
|
test_parse::<i16>("-32768", Ok(-32_768));
|
||||||
assert_eq!("-32769".parse::<i16>().ok(), None);
|
test_parse::<i16>("-32769", Err(IntErrorKind::NegOverflow));
|
||||||
|
|
||||||
assert_eq!("2147483647".parse::<i32>().ok(), Some(2_147_483_647i32));
|
test_parse::<i32>("2147483647", Ok(2_147_483_647));
|
||||||
assert_eq!("2147483648".parse::<i32>().ok(), None);
|
test_parse::<i32>("2147483648", Err(IntErrorKind::PosOverflow));
|
||||||
|
|
||||||
assert_eq!("-2147483648".parse::<i32>().ok(), Some(-2_147_483_648i32));
|
test_parse::<i32>("-2147483648", Ok(-2_147_483_648));
|
||||||
assert_eq!("-2147483649".parse::<i32>().ok(), None);
|
test_parse::<i32>("-2147483649", Err(IntErrorKind::NegOverflow));
|
||||||
|
|
||||||
assert_eq!("9223372036854775807".parse::<i64>().ok(), Some(9_223_372_036_854_775_807i64));
|
test_parse::<i64>("9223372036854775807", Ok(9_223_372_036_854_775_807));
|
||||||
assert_eq!("9223372036854775808".parse::<i64>().ok(), None);
|
test_parse::<i64>("9223372036854775808", Err(IntErrorKind::PosOverflow));
|
||||||
|
|
||||||
assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(-9_223_372_036_854_775_808i64));
|
test_parse::<i64>("-9223372036854775808", Ok(-9_223_372_036_854_775_808));
|
||||||
assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
|
test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_leading_plus() {
|
fn test_leading_plus() {
|
||||||
assert_eq!("+127".parse::<u8>().ok(), Some(127));
|
test_parse::<u8>("+127", Ok(127));
|
||||||
assert_eq!("+9223372036854775807".parse::<i64>().ok(), Some(9223372036854775807));
|
test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_invalid() {
|
fn test_invalid() {
|
||||||
assert_eq!("--129".parse::<i8>().ok(), None);
|
test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
|
||||||
assert_eq!("++129".parse::<i8>().ok(), None);
|
test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
|
||||||
assert_eq!("Съешь".parse::<u8>().ok(), None);
|
test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit));
|
||||||
|
test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit));
|
||||||
|
test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit));
|
||||||
|
test_parse::<i8>("-", Err(IntErrorKind::InvalidDigit));
|
||||||
|
test_parse::<i8>("+", Err(IntErrorKind::InvalidDigit));
|
||||||
|
test_parse::<u8>("-1", Err(IntErrorKind::InvalidDigit));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty() {
|
fn test_empty() {
|
||||||
assert_eq!("-".parse::<i8>().ok(), None);
|
test_parse::<u8>("", Err(IntErrorKind::Empty));
|
||||||
assert_eq!("+".parse::<i8>().ok(), None);
|
|
||||||
assert_eq!("".parse::<u8>().ok(), None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1701,10 +1701,14 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
|
||||||
/// The `dst` path will be a link pointing to the `src` path. Note that systems
|
/// The `dst` path will be a link pointing to the `src` path. Note that systems
|
||||||
/// often require these two paths to both be located on the same filesystem.
|
/// often require these two paths to both be located on the same filesystem.
|
||||||
///
|
///
|
||||||
|
/// If `src` names a symbolic link, it is platform-specific whether the symbolic
|
||||||
|
/// link is followed. On platforms where it's possible to not follow it, it is
|
||||||
|
/// not followed, and the created hard link points to the symbolic link itself.
|
||||||
|
///
|
||||||
/// # Platform-specific behavior
|
/// # Platform-specific behavior
|
||||||
///
|
///
|
||||||
/// This function currently corresponds to the `link` function on Unix
|
/// This function currently corresponds to the `linkat` function with no flags
|
||||||
/// and the `CreateHardLink` function on Windows.
|
/// on Unix and the `CreateHardLink` function on Windows.
|
||||||
/// Note that, this [may change in the future][changes].
|
/// Note that, this [may change in the future][changes].
|
||||||
///
|
///
|
||||||
/// [changes]: io#platform-specific-behavior
|
/// [changes]: io#platform-specific-behavior
|
||||||
|
|
|
@ -1336,3 +1336,54 @@ fn metadata_access_times() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test creating hard links to symlinks.
|
||||||
|
#[test]
|
||||||
|
fn symlink_hard_link() {
|
||||||
|
let tmpdir = tmpdir();
|
||||||
|
|
||||||
|
// Create "file", a file.
|
||||||
|
check!(fs::File::create(tmpdir.join("file")));
|
||||||
|
|
||||||
|
// Create "symlink", a symlink to "file".
|
||||||
|
check!(symlink_file("file", tmpdir.join("symlink")));
|
||||||
|
|
||||||
|
// Create "hard_link", a hard link to "symlink".
|
||||||
|
check!(fs::hard_link(tmpdir.join("symlink"), tmpdir.join("hard_link")));
|
||||||
|
|
||||||
|
// "hard_link" should appear as a symlink.
|
||||||
|
assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
|
||||||
|
|
||||||
|
// We sould be able to open "file" via any of the above names.
|
||||||
|
let _ = check!(fs::File::open(tmpdir.join("file")));
|
||||||
|
assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
|
||||||
|
let _ = check!(fs::File::open(tmpdir.join("symlink")));
|
||||||
|
let _ = check!(fs::File::open(tmpdir.join("hard_link")));
|
||||||
|
|
||||||
|
// Rename "file" to "file.renamed".
|
||||||
|
check!(fs::rename(tmpdir.join("file"), tmpdir.join("file.renamed")));
|
||||||
|
|
||||||
|
// Now, the symlink and the hard link should be dangling.
|
||||||
|
assert!(fs::File::open(tmpdir.join("file")).is_err());
|
||||||
|
let _ = check!(fs::File::open(tmpdir.join("file.renamed")));
|
||||||
|
assert!(fs::File::open(tmpdir.join("symlink")).is_err());
|
||||||
|
assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
|
||||||
|
|
||||||
|
// The symlink and the hard link should both still point to "file".
|
||||||
|
assert!(fs::read_link(tmpdir.join("file")).is_err());
|
||||||
|
assert!(fs::read_link(tmpdir.join("file.renamed")).is_err());
|
||||||
|
assert_eq!(check!(fs::read_link(tmpdir.join("symlink"))), Path::new("file"));
|
||||||
|
assert_eq!(check!(fs::read_link(tmpdir.join("hard_link"))), Path::new("file"));
|
||||||
|
|
||||||
|
// Remove "file.renamed".
|
||||||
|
check!(fs::remove_file(tmpdir.join("file.renamed")));
|
||||||
|
|
||||||
|
// Now, we can't open the file by any name.
|
||||||
|
assert!(fs::File::open(tmpdir.join("file")).is_err());
|
||||||
|
assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
|
||||||
|
assert!(fs::File::open(tmpdir.join("symlink")).is_err());
|
||||||
|
assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
|
||||||
|
|
||||||
|
// "hard_link" should still appear as a symlink.
|
||||||
|
assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
|
||||||
|
}
|
||||||
|
|
|
@ -1081,7 +1081,20 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
|
||||||
pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
|
pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
|
||||||
let src = cstr(src)?;
|
let src = cstr(src)?;
|
||||||
let dst = cstr(dst)?;
|
let dst = cstr(dst)?;
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] {
|
||||||
|
// VxWorks, Redox, and old versions of Android lack `linkat`, so use
|
||||||
|
// `link` instead. POSIX leaves it implementation-defined whether
|
||||||
|
// `link` follows symlinks, so rely on the `symlink_hard_link` test
|
||||||
|
// in library/std/src/fs/tests.rs to check the behavior.
|
||||||
cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
|
cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
|
||||||
|
} else {
|
||||||
|
// Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives
|
||||||
|
// us a flag to specify how symlinks should be handled. Pass 0 as
|
||||||
|
// the flags argument, meaning don't follow symlinks.
|
||||||
|
cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,17 +14,22 @@ macro_rules! t {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(
|
||||||
// See #14232 for more information, but it appears that signal delivery to a
|
// See #14232 for more information, but it appears that signal delivery to a
|
||||||
// newly spawned process may just be raced in the macOS, so to prevent this
|
// newly spawned process may just be raced in the macOS, so to prevent this
|
||||||
// test from being flaky we ignore it on macOS.
|
// test from being flaky we ignore it on macOS.
|
||||||
#[test]
|
target_os = "macos",
|
||||||
#[cfg_attr(target_os = "macos", ignore)]
|
|
||||||
// When run under our current QEMU emulation test suite this test fails,
|
// When run under our current QEMU emulation test suite this test fails,
|
||||||
// although the reason isn't very clear as to why. For now this test is
|
// although the reason isn't very clear as to why. For now this test is
|
||||||
// ignored there.
|
// ignored there.
|
||||||
#[cfg_attr(target_arch = "arm", ignore)]
|
target_arch = "arm",
|
||||||
#[cfg_attr(target_arch = "aarch64", ignore)]
|
target_arch = "aarch64",
|
||||||
#[cfg_attr(target_arch = "riscv64", ignore)]
|
target_arch = "riscv64",
|
||||||
|
),
|
||||||
|
ignore
|
||||||
|
)]
|
||||||
fn test_process_mask() {
|
fn test_process_mask() {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Test to make sure that a signal mask does not get inherited.
|
// Test to make sure that a signal mask does not get inherited.
|
||||||
|
|
|
@ -35,6 +35,5 @@ ENV HOSTS=aarch64-unknown-linux-gnu
|
||||||
ENV RUST_CONFIGURE_ARGS \
|
ENV RUST_CONFIGURE_ARGS \
|
||||||
--enable-full-tools \
|
--enable-full-tools \
|
||||||
--enable-profiler \
|
--enable-profiler \
|
||||||
--enable-sanitizers \
|
--enable-sanitizers
|
||||||
--disable-docs
|
|
||||||
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
|
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
|
||||||
|
|
|
@ -301,6 +301,9 @@ jobs:
|
||||||
# Linux/Docker builders #
|
# Linux/Docker builders #
|
||||||
#############################
|
#############################
|
||||||
|
|
||||||
|
- name: aarch64-gnu
|
||||||
|
<<: *job-aarch64-linux
|
||||||
|
|
||||||
- name: arm-android
|
- name: arm-android
|
||||||
<<: *job-linux-xl
|
<<: *job-linux-xl
|
||||||
|
|
||||||
|
@ -635,23 +638,6 @@ jobs:
|
||||||
SCRIPT: python x.py dist
|
SCRIPT: python x.py dist
|
||||||
<<: *job-windows-xl
|
<<: *job-windows-xl
|
||||||
|
|
||||||
auto-fallible:
|
|
||||||
<<: *base-ci-job
|
|
||||||
name: auto-fallible
|
|
||||||
env:
|
|
||||||
<<: [*shared-ci-variables, *dummy-variables]
|
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
#############################
|
|
||||||
# Linux/Docker builders #
|
|
||||||
#############################
|
|
||||||
|
|
||||||
- name: aarch64-gnu
|
|
||||||
<<: *job-aarch64-linux
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
<<: *base-ci-job
|
<<: *base-ci-job
|
||||||
name: try
|
name: try
|
||||||
|
|
|
@ -34,6 +34,7 @@ Specifically they will each satisfy the following requirements:
|
||||||
|
|
||||||
target | std | host | notes
|
target | std | host | notes
|
||||||
-------|-----|------|-------
|
-------|-----|------|-------
|
||||||
|
`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
|
||||||
`i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
|
`i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
|
||||||
`i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
|
`i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
|
||||||
`i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
|
`i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
|
||||||
|
@ -42,6 +43,12 @@ target | std | host | notes
|
||||||
`x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
|
`x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
|
||||||
`x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
|
`x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
|
||||||
|
|
||||||
|
[^missing-stack-probes]: Stack probes support is missing on
|
||||||
|
`aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
|
||||||
|
future. The implementation is tracked on [issue #77071][77071].
|
||||||
|
|
||||||
|
[77071]: https://github.com/rust-lang/rust/issues/77071
|
||||||
|
|
||||||
## Tier 2
|
## Tier 2
|
||||||
|
|
||||||
Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
|
Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
|
||||||
|
@ -62,7 +69,6 @@ target | std | host | notes
|
||||||
`aarch64-fuchsia` | ✓ | | ARM64 Fuchsia
|
`aarch64-fuchsia` | ✓ | | ARM64 Fuchsia
|
||||||
`aarch64-linux-android` | ✓ | | ARM64 Android
|
`aarch64-linux-android` | ✓ | | ARM64 Android
|
||||||
`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
|
`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
|
||||||
`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17)
|
|
||||||
`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
|
`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
|
||||||
`aarch64-unknown-none` | * | | Bare ARM64, hardfloat
|
`aarch64-unknown-none` | * | | Bare ARM64, hardfloat
|
||||||
`aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat
|
`aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat
|
||||||
|
|
|
@ -322,7 +322,8 @@ pub fn run_core(
|
||||||
let cpath = Some(input.clone());
|
let cpath = Some(input.clone());
|
||||||
let input = Input::File(input);
|
let input = Input::File(input);
|
||||||
|
|
||||||
let intra_link_resolution_failure_name = lint::builtin::BROKEN_INTRA_DOC_LINKS.name;
|
let broken_intra_doc_links = lint::builtin::BROKEN_INTRA_DOC_LINKS.name;
|
||||||
|
let private_intra_doc_links = lint::builtin::PRIVATE_INTRA_DOC_LINKS.name;
|
||||||
let missing_docs = rustc_lint::builtin::MISSING_DOCS.name;
|
let missing_docs = rustc_lint::builtin::MISSING_DOCS.name;
|
||||||
let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name;
|
let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name;
|
||||||
let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
|
let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
|
||||||
|
@ -336,7 +337,8 @@ pub fn run_core(
|
||||||
// In addition to those specific lints, we also need to allow those given through
|
// In addition to those specific lints, we also need to allow those given through
|
||||||
// command line, otherwise they'll get ignored and we don't want that.
|
// command line, otherwise they'll get ignored and we don't want that.
|
||||||
let lints_to_show = vec![
|
let lints_to_show = vec![
|
||||||
intra_link_resolution_failure_name.to_owned(),
|
broken_intra_doc_links.to_owned(),
|
||||||
|
private_intra_doc_links.to_owned(),
|
||||||
missing_docs.to_owned(),
|
missing_docs.to_owned(),
|
||||||
missing_doc_example.to_owned(),
|
missing_doc_example.to_owned(),
|
||||||
private_doc_tests.to_owned(),
|
private_doc_tests.to_owned(),
|
||||||
|
@ -349,9 +351,8 @@ pub fn run_core(
|
||||||
];
|
];
|
||||||
|
|
||||||
let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
|
let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
|
||||||
if lint.name == intra_link_resolution_failure_name
|
// FIXME: why is this necessary?
|
||||||
|| lint.name == invalid_codeblock_attributes_name
|
if lint.name == broken_intra_doc_links || lint.name == invalid_codeblock_attributes_name {
|
||||||
{
|
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some((lint.name_lower(), lint::Allow))
|
Some((lint.name_lower(), lint::Allow))
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle input {
|
.toggle input {
|
||||||
display: none;
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-wrapper {
|
.select-wrapper {
|
||||||
|
@ -90,7 +91,7 @@ input:checked + .slider {
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus + .slider {
|
input:focus + .slider {
|
||||||
box-shadow: 0 0 1px #2196F3;
|
box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
input:checked + .slider:before {
|
input:checked + .slider:before {
|
||||||
|
|
13
src/test/mir-opt/inline/inline-shims.rs
Normal file
13
src/test/mir-opt/inline/inline-shims.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// ignore-wasm32-bare compiled with panic=abort by default
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
// EMIT_MIR inline_shims.clone.Inline.diff
|
||||||
|
pub fn clone<A, B>(f: fn(A, B)) -> fn(A, B) {
|
||||||
|
f.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EMIT_MIR inline_shims.drop.Inline.diff
|
||||||
|
pub fn drop<A, B>(a: *mut Vec<A>, b: *mut Option<B>) {
|
||||||
|
unsafe { std::ptr::drop_in_place(a) }
|
||||||
|
unsafe { std::ptr::drop_in_place(b) }
|
||||||
|
}
|
26
src/test/mir-opt/inline/inline_shims.clone.Inline.diff
Normal file
26
src/test/mir-opt/inline/inline_shims.clone.Inline.diff
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
- // MIR for `clone` before Inline
|
||||||
|
+ // MIR for `clone` after Inline
|
||||||
|
|
||||||
|
fn clone(_1: fn(A, B)) -> fn(A, B) {
|
||||||
|
debug f => _1; // in scope 0 at $DIR/inline-shims.rs:5:20: 5:21
|
||||||
|
let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline-shims.rs:5:36: 5:44
|
||||||
|
let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:6:5: 6:6
|
||||||
|
+ scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline-shims.rs:6:5: 6:14
|
||||||
|
+ }
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:6:5: 6:6
|
||||||
|
_2 = &_1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:6
|
||||||
|
- _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14
|
||||||
|
- // mir::Constant
|
||||||
|
- // + span: $DIR/inline-shims.rs:6:7: 6:12
|
||||||
|
- // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {<fn(A, B) as std::clone::Clone>::clone}, val: Value(Scalar(<ZST>)) }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- bb1: {
|
||||||
|
+ _0 = (*_2); // scope 1 at $DIR/inline-shims.rs:6:5: 6:14
|
||||||
|
StorageDead(_2); // scope 0 at $DIR/inline-shims.rs:6:13: 6:14
|
||||||
|
return; // scope 0 at $DIR/inline-shims.rs:7:2: 7:2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
52
src/test/mir-opt/inline/inline_shims.drop.Inline.diff
Normal file
52
src/test/mir-opt/inline/inline_shims.drop.Inline.diff
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
- // MIR for `drop` before Inline
|
||||||
|
+ // MIR for `drop` after Inline
|
||||||
|
|
||||||
|
fn drop(_1: *mut Vec<A>, _2: *mut Option<B>) -> () {
|
||||||
|
debug a => _1; // in scope 0 at $DIR/inline-shims.rs:10:19: 10:20
|
||||||
|
debug b => _2; // in scope 0 at $DIR/inline-shims.rs:10:35: 10:36
|
||||||
|
let mut _0: (); // return place in scope 0 at $DIR/inline-shims.rs:10:54: 10:54
|
||||||
|
let _3: (); // in scope 0 at $DIR/inline-shims.rs:11:14: 11:40
|
||||||
|
let mut _4: *mut std::vec::Vec<A>; // in scope 0 at $DIR/inline-shims.rs:11:38: 11:39
|
||||||
|
let mut _5: *mut std::option::Option<B>; // in scope 0 at $DIR/inline-shims.rs:12:38: 12:39
|
||||||
|
scope 1 {
|
||||||
|
}
|
||||||
|
scope 2 {
|
||||||
|
+ scope 3 (inlined drop_in_place::<Option<B>> - shim(Some(Option<B>))) { // at $DIR/inline-shims.rs:12:14: 12:40
|
||||||
|
+ let mut _6: isize; // in scope 3 at $DIR/inline-shims.rs:12:14: 12:40
|
||||||
|
+ let mut _7: isize; // in scope 3 at $DIR/inline-shims.rs:12:14: 12:40
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_3); // scope 0 at $DIR/inline-shims.rs:11:5: 11:42
|
||||||
|
StorageLive(_4); // scope 1 at $DIR/inline-shims.rs:11:38: 11:39
|
||||||
|
_4 = _1; // scope 1 at $DIR/inline-shims.rs:11:38: 11:39
|
||||||
|
_3 = drop_in_place::<Vec<A>>(move _4) -> bb1; // scope 1 at $DIR/inline-shims.rs:11:14: 11:40
|
||||||
|
// mir::Constant
|
||||||
|
// + span: $DIR/inline-shims.rs:11:14: 11:37
|
||||||
|
// + literal: Const { ty: unsafe fn(*mut std::vec::Vec<A>) {std::intrinsics::drop_in_place::<std::vec::Vec<A>>}, val: Value(Scalar(<ZST>)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageDead(_4); // scope 1 at $DIR/inline-shims.rs:11:39: 11:40
|
||||||
|
StorageDead(_3); // scope 0 at $DIR/inline-shims.rs:11:41: 11:42
|
||||||
|
StorageLive(_5); // scope 2 at $DIR/inline-shims.rs:12:38: 12:39
|
||||||
|
_5 = _2; // scope 2 at $DIR/inline-shims.rs:12:38: 12:39
|
||||||
|
- _0 = drop_in_place::<Option<B>>(move _5) -> bb2; // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
|
||||||
|
- // mir::Constant
|
||||||
|
- // + span: $DIR/inline-shims.rs:12:14: 12:37
|
||||||
|
- // + literal: Const { ty: unsafe fn(*mut std::option::Option<B>) {std::intrinsics::drop_in_place::<std::option::Option<B>>}, val: Value(Scalar(<ZST>)) }
|
||||||
|
+ _6 = discriminant((*_5)); // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
|
||||||
|
+ switchInt(move _6) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_5); // scope 2 at $DIR/inline-shims.rs:12:39: 12:40
|
||||||
|
return; // scope 0 at $DIR/inline-shims.rs:13:2: 13:2
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ bb3: {
|
||||||
|
+ drop((((*_5) as Some).0: B)) -> bb2; // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
1 = 2; //~ ERROR invalid left-hand side of assignment
|
1 = 2; //~ ERROR invalid left-hand side of assignment
|
||||||
1 += 2; //~ ERROR invalid left-hand side of assignment
|
1 += 2; //~ ERROR invalid left-hand side of assignment
|
||||||
(1, 2) = (3, 4); //~ ERROR invalid left-hand side of assignment
|
(1, 2) = (3, 4); //~ ERROR destructuring assignments are unstable
|
||||||
|
//~| ERROR invalid left-hand side of assignment
|
||||||
|
//~| ERROR invalid left-hand side of assignment
|
||||||
|
|
||||||
let (a, b) = (1, 2);
|
let (a, b) = (1, 2);
|
||||||
(a, b) = (3, 4); //~ ERROR invalid left-hand side of assignment
|
(a, b) = (3, 4); //~ ERROR destructuring assignments are unstable
|
||||||
|
|
||||||
None = Some(3); //~ ERROR invalid left-hand side of assignment
|
None = Some(3); //~ ERROR invalid left-hand side of assignment
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,25 @@
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/bad-expr-lhs.rs:4:12
|
||||||
|
|
|
||||||
|
LL | (1, 2) = (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/bad-expr-lhs.rs:9: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[E0070]: invalid left-hand side of assignment
|
error[E0070]: invalid left-hand side of assignment
|
||||||
--> $DIR/bad-expr-lhs.rs:2:7
|
--> $DIR/bad-expr-lhs.rs:2:7
|
||||||
|
|
|
|
||||||
|
@ -18,30 +40,27 @@ error[E0070]: invalid left-hand side of assignment
|
||||||
--> $DIR/bad-expr-lhs.rs:4:12
|
--> $DIR/bad-expr-lhs.rs:4:12
|
||||||
|
|
|
|
||||||
LL | (1, 2) = (3, 4);
|
LL | (1, 2) = (3, 4);
|
||||||
| ------ ^
|
| - ^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
error[E0070]: invalid left-hand side of assignment
|
||||||
--> $DIR/bad-expr-lhs.rs:7:12
|
--> $DIR/bad-expr-lhs.rs:4:12
|
||||||
|
|
|
|
||||||
LL | (a, b) = (3, 4);
|
LL | (1, 2) = (3, 4);
|
||||||
| ------ ^
|
| - ^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
error[E0070]: invalid left-hand side of assignment
|
||||||
--> $DIR/bad-expr-lhs.rs:9:10
|
--> $DIR/bad-expr-lhs.rs:11:10
|
||||||
|
|
|
|
||||||
LL | None = Some(3);
|
LL | None = Some(3);
|
||||||
| ---- ^
|
| ---- ^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0067, E0070.
|
Some errors have detailed explanations: E0067, E0070, E0658.
|
||||||
For more information about an error, try `rustc --explain E0067`.
|
For more information about an error, try `rustc --explain E0067`.
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut x = &0;
|
||||||
|
let mut y = &0;
|
||||||
|
(x, y) = &(1, 2); //~ ERROR mismatched types
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/default-match-bindings-forbidden.rs:6:5
|
||||||
|
|
|
||||||
|
LL | (x, y) = &(1, 2);
|
||||||
|
| ^^^^^^ ------- this expression has type `&({integer}, {integer})`
|
||||||
|
| |
|
||||||
|
| expected reference, found tuple
|
||||||
|
|
|
||||||
|
= note: expected type `&({integer}, {integer})`
|
||||||
|
found tuple `(_, _)`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -3,23 +3,24 @@ struct S { x: u8, y: u8 }
|
||||||
fn main() {
|
fn main() {
|
||||||
let (a, b) = (1, 2);
|
let (a, b) = (1, 2);
|
||||||
|
|
||||||
(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
|
(a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
|
||||||
//~^ ERROR binary assignment operation `+=` cannot be applied
|
//~| ERROR binary assignment operation `+=` cannot be applied
|
||||||
|
|
||||||
[a, b] = [3, 4]; //~ ERROR invalid left-hand side of assignment
|
[a, b] = [3, 4]; //~ ERROR invalid left-hand side of assignment
|
||||||
[a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
|
[a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
|
||||||
//~^ ERROR binary assignment operation `+=` cannot be applied
|
//~| ERROR binary assignment operation `+=` cannot be applied
|
||||||
|
|
||||||
let s = S { x: 3, y: 4 };
|
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 invalid left-hand side of assignment
|
||||||
S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
|
S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
|
||||||
//~^ ERROR binary assignment operation `+=` cannot be applied
|
//~| ERROR binary assignment operation `+=` cannot be applied
|
||||||
|
|
||||||
S { x: a, ..s } = S { x: 3, y: 4 }; //~ ERROR invalid left-hand side of assignment
|
S { x: a, ..s } = S { x: 3, y: 4 };
|
||||||
|
//~^ ERROR invalid left-hand side of assignment
|
||||||
|
|
||||||
let c = 3;
|
let c = 3;
|
||||||
|
|
||||||
((a, b), c) = ((3, 4), 5); //~ ERROR invalid left-hand side of assignment
|
((a, b), c) = ((3, 4), 5); //~ ERROR destructuring assignments are unstable
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error[E0070]: invalid left-hand side of assignment
|
error[E0658]: destructuring assignments are unstable
|
||||||
--> $DIR/note-unsupported.rs:6:12
|
--> $DIR/note-unsupported.rs:6:12
|
||||||
|
|
|
|
||||||
LL | (a, b) = (3, 4);
|
LL | (a, b) = (3, 4);
|
||||||
|
@ -6,8 +6,19 @@ LL | (a, b) = (3, 4);
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/note-unsupported.rs:25:17
|
||||||
|
|
|
||||||
|
LL | ((a, b), c) = ((3, 4), 5);
|
||||||
|
| ----------- ^
|
||||||
|
| |
|
||||||
|
| 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[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})`
|
error[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})`
|
||||||
--> $DIR/note-unsupported.rs:7:5
|
--> $DIR/note-unsupported.rs:7:5
|
||||||
|
@ -24,9 +35,6 @@ LL | (a, b) += (3, 4);
|
||||||
| ------ ^^
|
| ------ ^^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
error[E0070]: invalid left-hand side of assignment
|
||||||
--> $DIR/note-unsupported.rs:10:12
|
--> $DIR/note-unsupported.rs:10:12
|
||||||
|
@ -35,9 +43,6 @@ LL | [a, b] = [3, 4];
|
||||||
| ------ ^
|
| ------ ^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
|
error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
|
||||||
--> $DIR/note-unsupported.rs:11:5
|
--> $DIR/note-unsupported.rs:11:5
|
||||||
|
@ -54,9 +59,6 @@ LL | [a, b] += [3, 4];
|
||||||
| ------ ^^
|
| ------ ^^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
error[E0070]: invalid left-hand side of assignment
|
||||||
--> $DIR/note-unsupported.rs:16:22
|
--> $DIR/note-unsupported.rs:16:22
|
||||||
|
@ -65,9 +67,6 @@ LL | S { x: a, y: b } = s;
|
||||||
| ---------------- ^
|
| ---------------- ^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
|
error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
|
||||||
--> $DIR/note-unsupported.rs:17:5
|
--> $DIR/note-unsupported.rs:17:5
|
||||||
|
@ -86,9 +85,6 @@ LL | S { x: a, y: b } += s;
|
||||||
| ---------------- ^^
|
| ---------------- ^^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
error[E0070]: invalid left-hand side of assignment
|
||||||
--> $DIR/note-unsupported.rs:20:21
|
--> $DIR/note-unsupported.rs:20:21
|
||||||
|
@ -97,22 +93,8 @@ LL | S { x: a, ..s } = S { x: 3, y: 4 };
|
||||||
| --------------- ^
|
| --------------- ^
|
||||||
| |
|
| |
|
||||||
| cannot assign to this expression
|
| cannot assign to this expression
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error[E0070]: invalid left-hand side of assignment
|
|
||||||
--> $DIR/note-unsupported.rs:24:17
|
|
||||||
|
|
|
||||||
LL | ((a, b), c) = ((3, 4), 5);
|
|
||||||
| ----------- ^
|
|
||||||
| |
|
|
||||||
| cannot assign to this expression
|
|
||||||
|
|
|
||||||
= note: destructuring assignments are not currently supported
|
|
||||||
= note: for more information, see https://github.com/rust-lang/rfcs/issues/372
|
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0067, E0070, E0368.
|
Some errors have detailed explanations: E0067, E0070, E0368, E0658.
|
||||||
For more information about an error, try `rustc --explain E0067`.
|
For more information about an error, try `rustc --explain E0067`.
|
||||||
|
|
37
src/test/ui/destructuring-assignment/tuple_destructure.rs
Normal file
37
src/test/ui/destructuring-assignment/tuple_destructure.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut a, mut b);
|
||||||
|
(a, b) = (0, 1);
|
||||||
|
assert_eq!((a, b), (0, 1));
|
||||||
|
(b, a) = (a, b);
|
||||||
|
assert_eq!((a, b), (1, 0));
|
||||||
|
(a, .., b) = (1, 2);
|
||||||
|
assert_eq!((a, b), (1, 2));
|
||||||
|
(.., a) = (1, 2);
|
||||||
|
assert_eq!((a, b), (2, 2));
|
||||||
|
(..) = (3, 4);
|
||||||
|
assert_eq!((a, b), (2, 2));
|
||||||
|
(b, ..) = (5, 6, 7);
|
||||||
|
assert_eq!(b, 5);
|
||||||
|
|
||||||
|
// Test for a non-Copy type (String):
|
||||||
|
let (mut c, mut d);
|
||||||
|
(c, d) = ("c".to_owned(), "d".to_owned());
|
||||||
|
assert_eq!(c, "c");
|
||||||
|
assert_eq!(d, "d");
|
||||||
|
(d, c) = (c, d);
|
||||||
|
assert_eq!(c, "d");
|
||||||
|
assert_eq!(d, "c");
|
||||||
|
|
||||||
|
// Test nesting/parentheses:
|
||||||
|
((a, b)) = (0, 1);
|
||||||
|
assert_eq!((a, b), (0, 1));
|
||||||
|
(((a, b)), (c)) = ((2, 3), d);
|
||||||
|
assert_eq!((a, b), (2, 3));
|
||||||
|
assert_eq!(c, "c");
|
||||||
|
((a, .., b), .., (..)) = ((4, 5), ());
|
||||||
|
assert_eq!((a, b), (4, 5));
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
const C: i32 = 1;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (mut a, mut b);
|
||||||
|
(a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
|
||||||
|
(a, a, b) = (1, 2); //~ ERROR mismatched types
|
||||||
|
(C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
error: `..` can only be used once per tuple pattern
|
||||||
|
--> $DIR/tuple_destructure_fail.rs:7:16
|
||||||
|
|
|
||||||
|
LL | (a, .., b, ..) = (0, 1);
|
||||||
|
| -- ^^ can only be used once per tuple pattern
|
||||||
|
| |
|
||||||
|
| previously used here
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/tuple_destructure_fail.rs:8:5
|
||||||
|
|
|
||||||
|
LL | (a, a, b) = (1, 2);
|
||||||
|
| ^^^^^^^^^ ------ this expression has type `({integer}, {integer})`
|
||||||
|
| |
|
||||||
|
| expected a tuple with 2 elements, found one with 3 elements
|
||||||
|
|
|
||||||
|
= note: expected type `({integer}, {integer})`
|
||||||
|
found tuple `(_, _, _)`
|
||||||
|
|
||||||
|
error[E0070]: invalid left-hand side of assignment
|
||||||
|
--> $DIR/tuple_destructure_fail.rs:9:13
|
||||||
|
|
|
||||||
|
LL | (C, ..) = (0,1);
|
||||||
|
| - ^
|
||||||
|
| |
|
||||||
|
| cannot assign to this expression
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0070, E0308.
|
||||||
|
For more information about an error, try `rustc --explain E0070`.
|
|
@ -0,0 +1,23 @@
|
||||||
|
// run-pass
|
||||||
|
|
||||||
|
#![feature(destructuring_assignment)]
|
||||||
|
|
||||||
|
#![warn(unused_assignments)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut a;
|
||||||
|
// Assignment occurs left-to-right.
|
||||||
|
// However, we emit warnings when this happens, so it is clear that this is happening.
|
||||||
|
(a, a) = (0, 1); //~ WARN value assigned to `a` is never read
|
||||||
|
assert_eq!(a, 1);
|
||||||
|
|
||||||
|
// We can't always tell when a variable is being assigned to twice, which is why we don't try
|
||||||
|
// to emit an error, which would be fallible.
|
||||||
|
let mut x = 1;
|
||||||
|
(*foo(&mut x), *foo(&mut x)) = (5, 6);
|
||||||
|
assert_eq!(x, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<'a>(x: &'a mut u32) -> &'a mut u32 {
|
||||||
|
x
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
warning: value assigned to `a` is never read
|
||||||
|
--> $DIR/warn-unused-duplication.rs:11:6
|
||||||
|
|
|
||||||
|
LL | (a, a) = (0, 1);
|
||||||
|
| ^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/warn-unused-duplication.rs:5:9
|
||||||
|
|
|
||||||
|
LL | #![warn(unused_assignments)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
= help: maybe it is overwritten before being read?
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
let (a, b) = (0, 1);
|
||||||
|
(a, b) = (2, 3); //~ ERROR destructuring assignments are unstable
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0658]: destructuring assignments are unstable
|
||||||
|
--> $DIR/feature-gate-destructuring_assignment.rs:3:12
|
||||||
|
|
|
||||||
|
LL | (a, b) = (2, 3);
|
||||||
|
| ------ ^
|
||||||
|
| |
|
||||||
|
| 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: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -155,6 +155,7 @@ static TARGETS: &[&str] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
static DOCS_TARGETS: &[&str] = &[
|
static DOCS_TARGETS: &[&str] = &[
|
||||||
|
"aarch64-unknown-linux-gnu",
|
||||||
"i686-apple-darwin",
|
"i686-apple-darwin",
|
||||||
"i686-pc-windows-gnu",
|
"i686-pc-windows-gnu",
|
||||||
"i686-pc-windows-msvc",
|
"i686-pc-windows-msvc",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue