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
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -3,7 +3,7 @@
|
||||
* text=auto eol=lf
|
||||
*.cpp rust
|
||||
*.h rust
|
||||
*.rs rust
|
||||
*.rs rust diff=rust
|
||||
*.fixed linguist-language=Rust
|
||||
src/etc/installer/gfx/* binary
|
||||
*.woff binary
|
||||
|
115
.github/workflows/ci.yml
vendored
115
.github/workflows/ci.yml
vendored
@ -154,6 +154,11 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: aarch64-gnu
|
||||
os:
|
||||
- self-hosted
|
||||
- ARM64
|
||||
- linux
|
||||
- name: arm-android
|
||||
os: ubuntu-latest-xl
|
||||
env: {}
|
||||
@ -497,116 +502,6 @@ jobs:
|
||||
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')"
|
||||
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:
|
||||
name: try
|
||||
env:
|
||||
|
@ -9,6 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::hygiene::ForLoopLoc;
|
||||
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
|
||||
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)
|
||||
}
|
||||
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(
|
||||
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>)`.
|
||||
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
|
||||
let e1 = self.lower_expr_mut(e1);
|
||||
|
@ -2531,6 +2531,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
hir_id,
|
||||
kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
|
||||
span,
|
||||
default_binding_modes: true,
|
||||
}),
|
||||
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> {
|
||||
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(
|
||||
|
@ -273,11 +273,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
|
||||
/// 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> {
|
||||
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.
|
||||
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()
|
||||
.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))
|
||||
|
@ -361,13 +361,11 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> {
|
||||
where
|
||||
T: TypeFoldable<'tcx> + Copy,
|
||||
{
|
||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
||||
self.tcx
|
||||
.subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), value)
|
||||
} else {
|
||||
self.tcx
|
||||
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
|
||||
}
|
||||
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||
self.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
value
|
||||
)
|
||||
}
|
||||
|
||||
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>,
|
||||
{
|
||||
debug!("monomorphize: self.instance={:?}", self.instance);
|
||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
||||
self.cx.tcx().subst_and_normalize_erasing_regions(
|
||||
substs,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&value,
|
||||
)
|
||||
} else {
|
||||
self.cx.tcx().normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
|
||||
}
|
||||
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||
self.cx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -610,6 +610,9 @@ declare_features! (
|
||||
/// Allows unsized fn parameters.
|
||||
(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
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -732,6 +732,9 @@ pub struct Pat<'hir> {
|
||||
pub hir_id: HirId,
|
||||
pub kind: PatKind<'hir>,
|
||||
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<'_> {
|
||||
@ -1680,6 +1683,9 @@ pub enum LocalSource {
|
||||
AsyncFn,
|
||||
/// A desugared `<expr>.await`.
|
||||
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 _ { .. }`.
|
||||
@ -2677,6 +2683,9 @@ impl<'hir> Node<'hir> {
|
||||
Node::TraitItem(TraitItem { ident, .. })
|
||||
| Node::ImplItem(ImplItem { ident, .. })
|
||||
| Node::ForeignItem(ForeignItem { ident, .. })
|
||||
| Node::Field(StructField { ident, .. })
|
||||
| Node::Variant(Variant { ident, .. })
|
||||
| Node::MacroDef(MacroDef { ident, .. })
|
||||
| Node::Item(Item { ident, .. }) => Some(*ident),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -2801,6 +2801,7 @@ declare_lint_pass! {
|
||||
UNSTABLE_NAME_COLLISIONS,
|
||||
IRREFUTABLE_LET_PATTERNS,
|
||||
BROKEN_INTRA_DOC_LINKS,
|
||||
PRIVATE_INTRA_DOC_LINKS,
|
||||
INVALID_CODEBLOCK_ATTRIBUTES,
|
||||
MISSING_CRATE_LEVEL_DOCS,
|
||||
MISSING_DOC_CODE_EXAMPLES,
|
||||
|
@ -478,7 +478,7 @@ impl<'hir> Map<'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>> {
|
||||
|
@ -48,10 +48,12 @@ fn update_limit(
|
||||
.unwrap_or(attr.span);
|
||||
|
||||
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::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`"),
|
||||
kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
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 rustc_errors::ErrorReported;
|
||||
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 `None`, then the MIR body does not require substitution during
|
||||
/// 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 }
|
||||
}
|
||||
|
||||
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
|
||||
/// identify parameters if they are determined to be unused in `instance.def`.
|
||||
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())
|
||||
}
|
||||
|
||||
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> {
|
||||
def_id
|
||||
.as_local()
|
||||
.and_then(|def_id| self.hir().get(self.hir().local_def_id_to_hir_id(def_id)).ident())
|
||||
// Look at the HIR first so the span will be correct if this is a local item.
|
||||
self.item_name_from_hir(def_id)
|
||||
.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> {
|
||||
@ -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.
|
||||
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
|
||||
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>,
|
||||
value: T,
|
||||
) -> T {
|
||||
if let Some(substs) = frame.instance.substs_for_mir_body() {
|
||||
self.tcx.subst_and_normalize_erasing_regions(substs, self.param_env, &value)
|
||||
} else {
|
||||
self.tcx.normalize_erasing_regions(self.param_env, value)
|
||||
}
|
||||
frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, &value)
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
{
|
||||
debug!("monomorphize: self.instance={:?}", self.instance);
|
||||
if let Some(substs) = self.instance.substs_for_mir_body() {
|
||||
self.tcx.subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), &value)
|
||||
} else {
|
||||
self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), value)
|
||||
}
|
||||
self.instance.subst_mir_and_normalize_erasing_regions(
|
||||
self.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
&value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ use rustc_index::vec::Idx;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::mir::visit::*;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
|
||||
use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
@ -128,17 +127,15 @@ impl Inliner<'tcx> {
|
||||
self.tcx.instance_mir(callsite.callee.def)
|
||||
};
|
||||
|
||||
let callee_body: &Body<'tcx> = &*callee_body;
|
||||
|
||||
let callee_body = if self.consider_optimizing(callsite, callee_body) {
|
||||
self.tcx.subst_and_normalize_erasing_regions(
|
||||
&callsite.callee.substs,
|
||||
self.param_env,
|
||||
callee_body,
|
||||
)
|
||||
} else {
|
||||
if !self.consider_optimizing(callsite, &callee_body) {
|
||||
continue;
|
||||
};
|
||||
}
|
||||
|
||||
let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
|
||||
self.tcx,
|
||||
self.param_env,
|
||||
callee_body,
|
||||
);
|
||||
|
||||
let start = caller_body.basic_blocks().len();
|
||||
debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body);
|
||||
@ -309,7 +306,7 @@ impl Inliner<'tcx> {
|
||||
work_list.push(target);
|
||||
// If the place doesn't actually need dropping, treat it like
|
||||
// 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) {
|
||||
cost += CALL_PENALTY;
|
||||
if let Some(unwind) = unwind {
|
||||
@ -371,8 +368,7 @@ impl Inliner<'tcx> {
|
||||
let ptr_size = tcx.data_layout.pointer_size.bytes();
|
||||
|
||||
for v in callee_body.vars_and_temps_iter() {
|
||||
let v = &callee_body.local_decls[v];
|
||||
let ty = v.ty.subst(tcx, callsite.callee.substs);
|
||||
let ty = callsite.callee.subst_mir(self.tcx, &callee_body.local_decls[v].ty);
|
||||
// Cost of the var is the size in machine-words, if we know
|
||||
// it.
|
||||
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::AsyncFn => ("async fn 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_patterns(&loc.pat);
|
||||
|
@ -434,6 +434,7 @@ symbols! {
|
||||
deref_mut,
|
||||
deref_target,
|
||||
derive,
|
||||
destructuring_assignment,
|
||||
diagnostic,
|
||||
direct,
|
||||
discriminant_kind,
|
||||
|
@ -718,39 +718,24 @@ 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(
|
||||
&self,
|
||||
lhs: &'tcx hir::Expr<'tcx>,
|
||||
err_code: &'static str,
|
||||
expr_span: &Span,
|
||||
) {
|
||||
if !lhs.is_syntactic_place_expr() {
|
||||
// FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
|
||||
let mut err = self.tcx.sess.struct_span_err_with_code(
|
||||
*expr_span,
|
||||
"invalid left-hand side of assignment",
|
||||
DiagnosticId::Error(err_code.into()),
|
||||
);
|
||||
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();
|
||||
if lhs.is_syntactic_place_expr() {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
|
||||
let mut err = self.tcx.sess.struct_span_err_with_code(
|
||||
*expr_span,
|
||||
"invalid left-hand side of assignment",
|
||||
DiagnosticId::Error(err_code.into()),
|
||||
);
|
||||
err.span_label(lhs.span, "cannot assign to this expression");
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Type check assignment expression `expr` of form `lhs = rhs`.
|
||||
|
@ -270,6 +270,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
///
|
||||
/// 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 {
|
||||
// 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 {
|
||||
// Type checking these product-like types successfully always require
|
||||
// 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<'_>) {
|
||||
debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
|
||||
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
|
||||
if let PatKind::Binding(..) = kind {
|
||||
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.
|
||||
fn check(&self)
|
||||
where
|
||||
@ -54,14 +54,14 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
|
||||
assert!(root_node.ascend().is_err());
|
||||
root_node.assert_back_pointers();
|
||||
|
||||
let counted = root_node.assert_ascending();
|
||||
assert_eq!(self.length, counted);
|
||||
assert_eq!(self.length, root_node.calc_length());
|
||||
|
||||
root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 });
|
||||
} else {
|
||||
assert_eq!(self.length, 0);
|
||||
}
|
||||
|
||||
self.assert_ascending();
|
||||
}
|
||||
|
||||
/// 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")
|
||||
}
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
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);
|
||||
if let node::ForceResult::Internal(node) = self.force() {
|
||||
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 {
|
||||
ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
|
||||
ptr::write(slice.get_unchecked_mut(idx), val);
|
||||
let len = slice.len();
|
||||
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 {
|
||||
let ret = ptr::read(slice.get_unchecked(idx));
|
||||
ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
|
||||
let len = slice.len();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
where
|
||||
K: Debug,
|
||||
|
@ -159,6 +159,7 @@
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(no_niche)] // rust-lang/rust#68303
|
||||
#![feature(unsafe_block_in_unsafe_fn)]
|
||||
#![feature(int_error_matching)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
#[prelude_import]
|
||||
|
@ -98,15 +98,18 @@ pub enum IntErrorKind {
|
||||
///
|
||||
/// Among other causes, this variant will be constructed when parsing an empty string.
|
||||
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
|
||||
/// 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,
|
||||
/// Integer is too large to store in target integer type.
|
||||
Overflow,
|
||||
PosOverflow,
|
||||
/// Integer is too small to store in target integer type.
|
||||
Underflow,
|
||||
NegOverflow,
|
||||
/// Value was Zero
|
||||
///
|
||||
/// This variant will be emitted when the parsing string has a value of zero, which
|
||||
@ -119,7 +122,7 @@ impl ParseIntError {
|
||||
#[unstable(
|
||||
feature = "int_error_matching",
|
||||
reason = "it can be useful to match errors when making error messages \
|
||||
for integer parsing",
|
||||
for integer parsing",
|
||||
issue = "22639"
|
||||
)]
|
||||
pub fn kind(&self) -> &IntErrorKind {
|
||||
@ -136,8 +139,8 @@ impl ParseIntError {
|
||||
match self.kind {
|
||||
IntErrorKind::Empty => "cannot parse integer from empty string",
|
||||
IntErrorKind::InvalidDigit => "invalid digit found in string",
|
||||
IntErrorKind::Overflow => "number too large to fit in target type",
|
||||
IntErrorKind::Underflow => "number too small to fit in target type",
|
||||
IntErrorKind::PosOverflow => "number too large 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",
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,12 @@ pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, No
|
||||
#[stable(feature = "try_from", since = "1.34.0")]
|
||||
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;
|
||||
|
||||
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 (is_positive, digits) = match src[0] {
|
||||
b'+' | b'-' if src[1..].is_empty() => {
|
||||
return Err(PIE { kind: InvalidDigit });
|
||||
}
|
||||
b'+' => (true, &src[1..]),
|
||||
b'-' if is_signed_ty => (false, &src[1..]),
|
||||
_ => (true, src),
|
||||
};
|
||||
|
||||
if digits.is_empty() {
|
||||
return Err(PIE { kind: Empty });
|
||||
}
|
||||
|
||||
let mut result = T::from_u32(0);
|
||||
if 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) {
|
||||
Some(result) => result,
|
||||
None => return Err(PIE { kind: Overflow }),
|
||||
None => return Err(PIE { kind: PosOverflow }),
|
||||
};
|
||||
result = match result.checked_add(x) {
|
||||
Some(result) => result,
|
||||
None => return Err(PIE { kind: Overflow }),
|
||||
None => return Err(PIE { kind: PosOverflow }),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
@ -865,11 +869,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
|
||||
};
|
||||
result = match result.checked_mul(radix) {
|
||||
Some(result) => result,
|
||||
None => return Err(PIE { kind: Underflow }),
|
||||
None => return Err(PIE { kind: NegOverflow }),
|
||||
};
|
||||
result = match result.checked_sub(x) {
|
||||
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!(
|
||||
"-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
|
||||
Some(IntErrorKind::Underflow)
|
||||
Some(IntErrorKind::NegOverflow)
|
||||
);
|
||||
assert_eq!(
|
||||
"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::fmt::Debug;
|
||||
use core::marker::Copy;
|
||||
use core::num::TryFromIntError;
|
||||
use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
|
||||
use core::ops::{Add, Div, Mul, Rem, Sub};
|
||||
use core::option::Option;
|
||||
use core::option::Option::{None, Some};
|
||||
use core::option::Option::None;
|
||||
use core::str::FromStr;
|
||||
|
||||
#[macro_use]
|
||||
mod int_macros;
|
||||
@ -67,6 +68,15 @@ where
|
||||
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]
|
||||
fn from_str_issue7588() {
|
||||
let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
|
||||
@ -77,49 +87,52 @@ fn from_str_issue7588() {
|
||||
|
||||
#[test]
|
||||
fn test_int_from_str_overflow() {
|
||||
assert_eq!("127".parse::<i8>().ok(), Some(127i8));
|
||||
assert_eq!("128".parse::<i8>().ok(), None);
|
||||
test_parse::<i8>("127", Ok(127));
|
||||
test_parse::<i8>("128", Err(IntErrorKind::PosOverflow));
|
||||
|
||||
assert_eq!("-128".parse::<i8>().ok(), Some(-128i8));
|
||||
assert_eq!("-129".parse::<i8>().ok(), None);
|
||||
test_parse::<i8>("-128", Ok(-128));
|
||||
test_parse::<i8>("-129", Err(IntErrorKind::NegOverflow));
|
||||
|
||||
assert_eq!("32767".parse::<i16>().ok(), Some(32_767i16));
|
||||
assert_eq!("32768".parse::<i16>().ok(), None);
|
||||
test_parse::<i16>("32767", Ok(32_767));
|
||||
test_parse::<i16>("32768", Err(IntErrorKind::PosOverflow));
|
||||
|
||||
assert_eq!("-32768".parse::<i16>().ok(), Some(-32_768i16));
|
||||
assert_eq!("-32769".parse::<i16>().ok(), None);
|
||||
test_parse::<i16>("-32768", Ok(-32_768));
|
||||
test_parse::<i16>("-32769", Err(IntErrorKind::NegOverflow));
|
||||
|
||||
assert_eq!("2147483647".parse::<i32>().ok(), Some(2_147_483_647i32));
|
||||
assert_eq!("2147483648".parse::<i32>().ok(), None);
|
||||
test_parse::<i32>("2147483647", Ok(2_147_483_647));
|
||||
test_parse::<i32>("2147483648", Err(IntErrorKind::PosOverflow));
|
||||
|
||||
assert_eq!("-2147483648".parse::<i32>().ok(), Some(-2_147_483_648i32));
|
||||
assert_eq!("-2147483649".parse::<i32>().ok(), None);
|
||||
test_parse::<i32>("-2147483648", Ok(-2_147_483_648));
|
||||
test_parse::<i32>("-2147483649", Err(IntErrorKind::NegOverflow));
|
||||
|
||||
assert_eq!("9223372036854775807".parse::<i64>().ok(), Some(9_223_372_036_854_775_807i64));
|
||||
assert_eq!("9223372036854775808".parse::<i64>().ok(), None);
|
||||
test_parse::<i64>("9223372036854775807", Ok(9_223_372_036_854_775_807));
|
||||
test_parse::<i64>("9223372036854775808", Err(IntErrorKind::PosOverflow));
|
||||
|
||||
assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(-9_223_372_036_854_775_808i64));
|
||||
assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
|
||||
test_parse::<i64>("-9223372036854775808", Ok(-9_223_372_036_854_775_808));
|
||||
test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_leading_plus() {
|
||||
assert_eq!("+127".parse::<u8>().ok(), Some(127));
|
||||
assert_eq!("+9223372036854775807".parse::<i64>().ok(), Some(9223372036854775807));
|
||||
test_parse::<u8>("+127", Ok(127));
|
||||
test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid() {
|
||||
assert_eq!("--129".parse::<i8>().ok(), None);
|
||||
assert_eq!("++129".parse::<i8>().ok(), None);
|
||||
assert_eq!("Съешь".parse::<u8>().ok(), None);
|
||||
test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
|
||||
test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
|
||||
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]
|
||||
fn test_empty() {
|
||||
assert_eq!("-".parse::<i8>().ok(), None);
|
||||
assert_eq!("+".parse::<i8>().ok(), None);
|
||||
assert_eq!("".parse::<u8>().ok(), None);
|
||||
test_parse::<u8>("", Err(IntErrorKind::Empty));
|
||||
}
|
||||
|
||||
#[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
|
||||
/// 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
|
||||
///
|
||||
/// This function currently corresponds to the `link` function on Unix
|
||||
/// and the `CreateHardLink` function on Windows.
|
||||
/// This function currently corresponds to the `linkat` function with no flags
|
||||
/// on Unix and the `CreateHardLink` function on Windows.
|
||||
/// Note that, this [may change in the future][changes].
|
||||
///
|
||||
/// [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<()> {
|
||||
let src = cstr(src)?;
|
||||
let dst = cstr(dst)?;
|
||||
cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
|
||||
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()) })?;
|
||||
} 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(())
|
||||
}
|
||||
|
||||
|
@ -14,17 +14,22 @@ macro_rules! t {
|
||||
};
|
||||
}
|
||||
|
||||
// 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
|
||||
// test from being flaky we ignore it on macOS.
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "macos", ignore)]
|
||||
// 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
|
||||
// ignored there.
|
||||
#[cfg_attr(target_arch = "arm", ignore)]
|
||||
#[cfg_attr(target_arch = "aarch64", ignore)]
|
||||
#[cfg_attr(target_arch = "riscv64", ignore)]
|
||||
#[cfg_attr(
|
||||
any(
|
||||
// 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
|
||||
// test from being flaky we ignore it on macOS.
|
||||
target_os = "macos",
|
||||
// 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
|
||||
// ignored there.
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "riscv64",
|
||||
),
|
||||
ignore
|
||||
)]
|
||||
fn test_process_mask() {
|
||||
unsafe {
|
||||
// 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 \
|
||||
--enable-full-tools \
|
||||
--enable-profiler \
|
||||
--enable-sanitizers \
|
||||
--disable-docs
|
||||
--enable-sanitizers
|
||||
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
@ -301,6 +301,9 @@ jobs:
|
||||
# Linux/Docker builders #
|
||||
#############################
|
||||
|
||||
- name: aarch64-gnu
|
||||
<<: *job-aarch64-linux
|
||||
|
||||
- name: arm-android
|
||||
<<: *job-linux-xl
|
||||
|
||||
@ -635,23 +638,6 @@ jobs:
|
||||
SCRIPT: python x.py dist
|
||||
<<: *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:
|
||||
<<: *base-ci-job
|
||||
name: try
|
||||
|
@ -34,6 +34,7 @@ Specifically they will each satisfy the following requirements:
|
||||
|
||||
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-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
|
||||
`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-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 platforms can be thought of as "guaranteed to build". Automated tests
|
||||
@ -62,7 +69,6 @@ target | std | host | notes
|
||||
`aarch64-fuchsia` | ✓ | | ARM64 Fuchsia
|
||||
`aarch64-linux-android` | ✓ | | ARM64 Android
|
||||
`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-none` | * | | Bare ARM64, hardfloat
|
||||
`aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat
|
||||
|
@ -322,7 +322,8 @@ pub fn run_core(
|
||||
let cpath = Some(input.clone());
|
||||
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_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.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
|
||||
// command line, otherwise they'll get ignored and we don't want that.
|
||||
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_doc_example.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| {
|
||||
if lint.name == intra_link_resolution_failure_name
|
||||
|| lint.name == invalid_codeblock_attributes_name
|
||||
{
|
||||
// FIXME: why is this necessary?
|
||||
if lint.name == broken_intra_doc_links || lint.name == invalid_codeblock_attributes_name {
|
||||
None
|
||||
} else {
|
||||
Some((lint.name_lower(), lint::Allow))
|
||||
|
@ -26,7 +26,8 @@
|
||||
}
|
||||
|
||||
.toggle input {
|
||||
display: none;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.select-wrapper {
|
||||
@ -90,7 +91,7 @@ input:checked + .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 {
|
||||
|
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() {
|
||||
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);
|
||||
(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
|
||||
}
|
||||
|
@ -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
|
||||
--> $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
|
||||
|
|
||||
LL | (1, 2) = (3, 4);
|
||||
| ------ ^
|
||||
| |
|
||||
| cannot assign to this expression
|
||||
| - ^
|
||||
| |
|
||||
| cannot assign to this expression
|
||||
|
||||
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);
|
||||
| ------ ^
|
||||
| |
|
||||
| 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
|
||||
LL | (1, 2) = (3, 4);
|
||||
| - ^
|
||||
| |
|
||||
| cannot assign to this expression
|
||||
|
||||
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);
|
||||
| ---- ^
|
||||
| |
|
||||
| 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`.
|
||||
|
@ -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() {
|
||||
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
|
||||
//~^ 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
|
||||
//~^ ERROR binary assignment operation `+=` cannot be applied
|
||||
//~| ERROR binary assignment operation `+=` cannot be applied
|
||||
|
||||
let s = S { x: 3, y: 4 };
|
||||
|
||||
S { x: a, y: b } = s; //~ ERROR invalid left-hand side of assignment
|
||||
S { x: a, y: b } += s; //~ ERROR 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;
|
||||
|
||||
((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
|
||||
|
|
||||
LL | (a, b) = (3, 4);
|
||||
@ -6,8 +6,19 @@ LL | (a, b) = (3, 4);
|
||||
| |
|
||||
| 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
|
||||
= note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
|
||||
= help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: destructuring assignments are unstable
|
||||
--> $DIR/note-unsupported.rs: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})`
|
||||
--> $DIR/note-unsupported.rs:7:5
|
||||
@ -24,9 +35,6 @@ LL | (a, b) += (3, 4);
|
||||
| ------ ^^
|
||||
| |
|
||||
| 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:10:12
|
||||
@ -35,9 +43,6 @@ LL | [a, b] = [3, 4];
|
||||
| ------ ^
|
||||
| |
|
||||
| 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]`
|
||||
--> $DIR/note-unsupported.rs:11:5
|
||||
@ -54,9 +59,6 @@ LL | [a, b] += [3, 4];
|
||||
| ------ ^^
|
||||
| |
|
||||
| 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:16:22
|
||||
@ -65,9 +67,6 @@ LL | S { x: a, y: b } = s;
|
||||
| ---------------- ^
|
||||
| |
|
||||
| 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`
|
||||
--> $DIR/note-unsupported.rs:17:5
|
||||
@ -86,9 +85,6 @@ LL | S { x: a, y: b } += s;
|
||||
| ---------------- ^^
|
||||
| |
|
||||
| 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:20:21
|
||||
@ -97,22 +93,8 @@ LL | S { x: a, ..s } = S { x: 3, y: 4 };
|
||||
| --------------- ^
|
||||
| |
|
||||
| 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
|
||||
|
||||
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`.
|
||||
|
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] = &[
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"i686-apple-darwin",
|
||||
"i686-pc-windows-gnu",
|
||||
"i686-pc-windows-msvc",
|
||||
|
Loading…
Reference in New Issue
Block a user