Merge pull request #4680 from rust-lang/rustup-2025-11-12
Automatic Rustup
This commit is contained in:
commit
037db1e3c9
753 changed files with 7381 additions and 4556 deletions
2
.github/workflows/post-merge.yml
vendored
2
.github/workflows/post-merge.yml
vendored
|
|
@ -6,7 +6,7 @@ name: Post merge analysis
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
|
|
|
|||
|
|
@ -600,6 +600,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"tempfile",
|
||||
"termize",
|
||||
"tikv-jemalloc-sys",
|
||||
"toml 0.9.7",
|
||||
"ui_test",
|
||||
"walkdir",
|
||||
|
|
@ -4806,6 +4807,7 @@ dependencies = [
|
|||
"stringdex",
|
||||
"tempfile",
|
||||
"threadpool",
|
||||
"tikv-jemalloc-sys",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
|
|
@ -5537,9 +5539,9 @@ version = "0.1.0"
|
|||
|
||||
[[package]]
|
||||
name = "tikv-jemalloc-sys"
|
||||
version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
|
||||
version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d"
|
||||
checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@
|
|||
#build.npm = "npm"
|
||||
|
||||
# Python interpreter to use for various tasks throughout the build, notably
|
||||
# rustdoc tests, the lldb python interpreter, and some dist bits and pieces.
|
||||
# rustdoc tests, and some dist bits and pieces.
|
||||
#
|
||||
# Defaults to the Python interpreter used to execute x.py.
|
||||
#build.python = "python"
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ rustc_public_bridge = { path = "../rustc_public_bridge" }
|
|||
# tidy-alphabetical-end
|
||||
|
||||
[dependencies.tikv-jemalloc-sys]
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
optional = true
|
||||
features = ['unprefixed_malloc_on_supported_platforms']
|
||||
features = ['override_allocator_on_supported_platforms']
|
||||
|
||||
[features]
|
||||
# tidy-alphabetical-start
|
||||
|
|
|
|||
|
|
@ -7,26 +7,25 @@
|
|||
// distribution. The obvious way to do this is with the `#[global_allocator]`
|
||||
// mechanism. However, for complicated reasons (see
|
||||
// https://github.com/rust-lang/rust/pull/81782#issuecomment-784438001 for some
|
||||
// details) that mechanism doesn't work here. Also, we must use a consistent
|
||||
// allocator across the rustc <-> llvm boundary, and `#[global_allocator]`
|
||||
// wouldn't provide that.
|
||||
// details) that mechanism doesn't work here. Also, we'd like to use a
|
||||
// consistent allocator across the rustc <-> llvm boundary, and
|
||||
// `#[global_allocator]` wouldn't provide that.
|
||||
//
|
||||
// Instead, we use a lower-level mechanism. rustc is linked with jemalloc in a
|
||||
// way such that jemalloc's implementation of `malloc`, `free`, etc., override
|
||||
// the libc allocator's implementation. This means that Rust's `System`
|
||||
// allocator, which calls `libc::malloc()` et al., is actually calling into
|
||||
// jemalloc.
|
||||
// Instead, we use a lower-level mechanism, namely the
|
||||
// `"override_allocator_on_supported_platforms"` Cargo feature of jemalloc-sys.
|
||||
//
|
||||
// This makes jemalloc-sys override the libc/system allocator's implementation
|
||||
// of `malloc`, `free`, etc.. This means that Rust's `System` allocator, which
|
||||
// calls `libc::malloc()` et al., is actually calling into jemalloc.
|
||||
//
|
||||
// A consequence of not using `GlobalAlloc` (and the `tikv-jemallocator` crate
|
||||
// provides an impl of that trait, which is called `Jemalloc`) is that we
|
||||
// cannot use the sized deallocation APIs (`sdallocx`) that jemalloc provides.
|
||||
// It's unclear how much performance is lost because of this.
|
||||
//
|
||||
// As for the symbol overrides in `main` below: we're pulling in a static copy
|
||||
// of jemalloc. We need to actually reference its symbols for it to get linked.
|
||||
// The two crates we link to here, `std` and `rustc_driver`, are both dynamic
|
||||
// libraries. So we must reference jemalloc symbols one way or another, because
|
||||
// this file is the only object code in the rustc executable.
|
||||
// NOTE: Even though Cargo passes `--extern` with `tikv_jemalloc_sys`, we still need to `use` the
|
||||
// crate for the compiler to see the `#[used]`, see https://github.com/rust-lang/rust/issues/64402.
|
||||
// This is similarly required if we used a crate with `#[global_allocator]`.
|
||||
//
|
||||
// NOTE: if you are reading this comment because you want to set a custom `global_allocator` for
|
||||
// benchmarking, consider using the benchmarks in the `rustc-perf` collector suite instead:
|
||||
|
|
@ -36,43 +35,9 @@
|
|||
// to compare their performance, see
|
||||
// https://github.com/rust-lang/rust/commit/b90cfc887c31c3e7a9e6d462e2464db1fe506175#diff-43914724af6e464c1da2171e4a9b6c7e607d5bc1203fa95c0ab85be4122605ef
|
||||
// for an example of how to do so.
|
||||
#[cfg(feature = "jemalloc")]
|
||||
use tikv_jemalloc_sys as _;
|
||||
|
||||
fn main() {
|
||||
// See the comment at the top of this file for an explanation of this.
|
||||
#[cfg(feature = "jemalloc")]
|
||||
{
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
use tikv_jemalloc_sys as jemalloc_sys;
|
||||
|
||||
#[used]
|
||||
static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
|
||||
#[used]
|
||||
static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
|
||||
jemalloc_sys::posix_memalign;
|
||||
#[used]
|
||||
static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
|
||||
#[used]
|
||||
static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
|
||||
#[used]
|
||||
static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
|
||||
#[used]
|
||||
static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
|
||||
|
||||
// On OSX, jemalloc doesn't directly override malloc/free, but instead
|
||||
// registers itself with the allocator's zone APIs in a ctor. However,
|
||||
// the linker doesn't seem to consider ctors as "used" when statically
|
||||
// linking, so we need to explicitly depend on the function.
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
unsafe extern "C" {
|
||||
fn _rjem_je_zone_register();
|
||||
}
|
||||
|
||||
#[used]
|
||||
static _F7: unsafe extern "C" fn() = _rjem_je_zone_register;
|
||||
}
|
||||
}
|
||||
|
||||
rustc_driver::main()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -648,9 +648,10 @@ impl Pat {
|
|||
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
|
||||
PatKind::MacCall(mac) => TyKind::MacCall(mac.clone()),
|
||||
// `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
|
||||
PatKind::Ref(pat, mutbl) => {
|
||||
pat.to_ty().map(|ty| TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }))?
|
||||
}
|
||||
PatKind::Ref(pat, pinned, mutbl) => pat.to_ty().map(|ty| match pinned {
|
||||
Pinnedness::Not => TyKind::Ref(None, MutTy { ty, mutbl: *mutbl }),
|
||||
Pinnedness::Pinned => TyKind::PinnedRef(None, MutTy { ty, mutbl: *mutbl }),
|
||||
})?,
|
||||
// A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
|
||||
// when `P` can be reparsed as a type `T`.
|
||||
PatKind::Slice(pats) if let [pat] = pats.as_slice() => {
|
||||
|
|
@ -696,7 +697,7 @@ impl Pat {
|
|||
// Trivial wrappers over inner patterns.
|
||||
PatKind::Box(s)
|
||||
| PatKind::Deref(s)
|
||||
| PatKind::Ref(s, _)
|
||||
| PatKind::Ref(s, _, _)
|
||||
| PatKind::Paren(s)
|
||||
| PatKind::Guard(s, _) => s.walk(it),
|
||||
|
||||
|
|
@ -717,7 +718,7 @@ impl Pat {
|
|||
/// Strip off all reference patterns (`&`, `&mut`) and return the inner pattern.
|
||||
pub fn peel_refs(&self) -> &Pat {
|
||||
let mut current = self;
|
||||
while let PatKind::Ref(inner, _) = ¤t.kind {
|
||||
while let PatKind::Ref(inner, _, _) = ¤t.kind {
|
||||
current = inner;
|
||||
}
|
||||
current
|
||||
|
|
@ -765,7 +766,9 @@ impl Pat {
|
|||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => Some("_".to_string()),
|
||||
PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
|
||||
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
|
||||
PatKind::Ref(pat, pinned, mutbl) => {
|
||||
pat.descr().map(|d| format!("&{}{d}", pinned.prefix_str(*mutbl)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -913,7 +916,7 @@ pub enum PatKind {
|
|||
Deref(Box<Pat>),
|
||||
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(Box<Pat>, Mutability),
|
||||
Ref(Box<Pat>, Pinnedness, Mutability),
|
||||
|
||||
/// A literal, const block or path.
|
||||
Expr(Box<Expr>),
|
||||
|
|
|
|||
|
|
@ -645,8 +645,9 @@ macro_rules! common_visitor_and_walkers {
|
|||
fn visit_fn(
|
||||
&mut self,
|
||||
fk: FnKind<$($lt)? $(${ignore($mut)} '_)?>,
|
||||
_: &AttrVec,
|
||||
_: Span,
|
||||
_: NodeId
|
||||
_: NodeId,
|
||||
) -> Self::Result {
|
||||
walk_fn(self, fk)
|
||||
}
|
||||
|
|
@ -740,6 +741,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
type Ctxt;
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
|
|
@ -773,7 +775,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
) -> V::Result {
|
||||
let Item { attrs, id, kind, vis, span, tokens: _ } = item;
|
||||
visit_visitable!($($mut)? visitor, id, attrs, vis);
|
||||
try_visit!(kind.walk(*span, *id, vis, ctxt, visitor));
|
||||
try_visit!(kind.walk(attrs, *span, *id, vis, ctxt, visitor));
|
||||
visit_visitable!($($mut)? visitor, span);
|
||||
V::Result::output()
|
||||
}
|
||||
|
|
@ -799,6 +801,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
type Ctxt = ();
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
|
|
@ -808,7 +811,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
match self {
|
||||
ItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Free, visibility, &$($mut)? *func);
|
||||
try_visit!(vis.visit_fn(kind, span, id));
|
||||
try_visit!(vis.visit_fn(kind, attrs, span, id));
|
||||
}
|
||||
ItemKind::ExternCrate(orig_name, ident) =>
|
||||
visit_visitable!($($mut)? vis, orig_name, ident),
|
||||
|
|
@ -856,6 +859,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
type Ctxt = AssocCtxt;
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
|
|
@ -867,7 +871,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
visit_visitable!($($mut)? vis, item),
|
||||
AssocItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), visibility, &$($mut)? *func);
|
||||
try_visit!(vis.visit_fn(kind, span, id))
|
||||
try_visit!(vis.visit_fn(kind, attrs, span, id))
|
||||
}
|
||||
AssocItemKind::Type(alias) =>
|
||||
visit_visitable!($($mut)? vis, alias),
|
||||
|
|
@ -886,6 +890,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
type Ctxt = ();
|
||||
fn walk<$($lt,)? V: $Visitor$(<$lt>)?>(
|
||||
&$($lt)? $($mut)? self,
|
||||
attrs: &AttrVec,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
visibility: &$($lt)? $($mut)? Visibility,
|
||||
|
|
@ -897,7 +902,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
visit_visitable!($($mut)? vis, item),
|
||||
ForeignItemKind::Fn(func) => {
|
||||
let kind = FnKind::Fn(FnCtxt::Foreign, visibility, &$($mut)?*func);
|
||||
try_visit!(vis.visit_fn(kind, span, id))
|
||||
try_visit!(vis.visit_fn(kind, attrs, span, id))
|
||||
}
|
||||
ForeignItemKind::TyAlias(alias) =>
|
||||
visit_visitable!($($mut)? vis, alias),
|
||||
|
|
@ -999,7 +1004,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
}) => {
|
||||
visit_visitable!($($mut)? vis, constness, movability, capture_clause);
|
||||
let kind = FnKind::Closure(binder, coroutine_kind, fn_decl, body);
|
||||
try_visit!(vis.visit_fn(kind, *span, *id));
|
||||
try_visit!(vis.visit_fn(kind, attrs, *span, *id));
|
||||
visit_visitable!($($mut)? vis, fn_decl_span, fn_arg_span);
|
||||
}
|
||||
ExprKind::Block(block, opt_label) =>
|
||||
|
|
|
|||
|
|
@ -317,4 +317,15 @@ impl Pinnedness {
|
|||
pub fn is_pinned(self) -> bool {
|
||||
matches!(self, Self::Pinned)
|
||||
}
|
||||
|
||||
/// Returns `""` (empty string), "mut", `"pin mut "` or `"pin const "` depending
|
||||
/// on the pinnedness and mutability.
|
||||
pub fn prefix_str(self, mutbl: Mutability) -> &'static str {
|
||||
match (self, mutbl) {
|
||||
(Pinnedness::Pinned, Mutability::Mut) => "pin mut ",
|
||||
(Pinnedness::Pinned, Mutability::Not) => "pin const ",
|
||||
(Pinnedness::Not, Mutability::Mut) => "mut ",
|
||||
(Pinnedness::Not, Mutability::Not) => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1771,8 +1771,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let pat = self.lower_pat(pat);
|
||||
let for_span =
|
||||
self.mark_span_with_reason(DesugaringKind::ForLoop, self.lower_span(e.span), None);
|
||||
let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
|
||||
let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
|
||||
let for_ctxt = for_span.ctxt();
|
||||
|
||||
// Try to point both the head and pat spans to their position in the for loop
|
||||
// rather than inside a macro.
|
||||
let head_span =
|
||||
head.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(head.span).with_ctxt(for_ctxt);
|
||||
let pat_span =
|
||||
pat.span.find_ancestor_in_same_ctxt(e.span).unwrap_or(pat.span).with_ctxt(for_ctxt);
|
||||
|
||||
let loop_hir_id = self.lower_node_id(e.id);
|
||||
let label = self.lower_label(opt_label, e.id, loop_hir_id);
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
|
|||
}
|
||||
|
||||
impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
||||
/// Because we want to track parent items and so forth, enable
|
||||
/// deep walking so that we walk nested items in the context of
|
||||
/// their outer items.
|
||||
// Because we want to track parent items and so forth, enable
|
||||
// deep walking so that we walk nested items in the context of
|
||||
// their outer items.
|
||||
|
||||
fn visit_nested_item(&mut self, item: ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item);
|
||||
|
|
|
|||
|
|
@ -124,8 +124,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
PatKind::Deref(inner) => {
|
||||
break hir::PatKind::Deref(self.lower_pat(inner));
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
break hir::PatKind::Ref(self.lower_pat(inner), *pinned, *mutbl);
|
||||
}
|
||||
PatKind::Range(e1, e2, Spanned { node: end, .. }) => {
|
||||
break hir::PatKind::Range(
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ ast_passes_c_variadic_bad_extern = `...` is not supported for `extern "{$abi}"`
|
|||
.label = `extern "{$abi}"` because of this
|
||||
.help = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list
|
||||
|
||||
ast_passes_c_variadic_bad_naked_extern = `...` is not supported for `extern "{$abi}"` naked functions
|
||||
.label = `extern "{$abi}"` because of this
|
||||
.help = C-variadic function must have a compatible calling convention
|
||||
|
||||
ast_passes_c_variadic_must_be_unsafe =
|
||||
functions with a C variable argument list must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
|
|||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
|
||||
use rustc_abi::{CVariadicStatus, CanonAbi, ExternAbi, InterruptKind};
|
||||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
|
|
@ -35,6 +35,7 @@ use rustc_session::lint::builtin::{
|
|||
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use rustc_target::spec::{AbiMap, AbiMapping};
|
||||
use thin_vec::thin_vec;
|
||||
|
|
@ -661,7 +662,7 @@ impl<'a> AstValidator<'a> {
|
|||
/// C-variadics must be:
|
||||
/// - Non-const
|
||||
/// - Either foreign, or free and `unsafe extern "C"` semantically
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'a>) {
|
||||
fn check_c_variadic_type(&self, fk: FnKind<'a>, attrs: &'a AttrVec) {
|
||||
// `...` is already rejected when it is not the final parameter.
|
||||
let variadic_param = match fk.decl().inputs.last() {
|
||||
Some(param) if matches!(param.ty.kind, TyKind::CVarArgs) => param,
|
||||
|
|
@ -693,36 +694,92 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
match fn_ctxt {
|
||||
FnCtxt::Foreign => return,
|
||||
FnCtxt::Free | FnCtxt::Assoc(_) => match sig.header.ext {
|
||||
Extern::Implicit(_) => {
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
FnCtxt::Free | FnCtxt::Assoc(_) => {
|
||||
match sig.header.ext {
|
||||
Extern::Implicit(_) => {
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
|
||||
// Just bail if the ABI is not even recognized.
|
||||
let Ok(abi) = ExternAbi::from_str(symbol_unescaped.as_str()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.check_c_variadic_abi(abi, attrs, variadic_param.span, sig);
|
||||
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Extern::None => {
|
||||
let err = errors::CVariadicNoExtern { span: variadic_param.span };
|
||||
self.dcx().emit_err(err);
|
||||
}
|
||||
}
|
||||
Extern::Explicit(StrLit { symbol_unescaped, .. }, _) => {
|
||||
if !matches!(symbol_unescaped, sym::C | sym::C_dash_unwind) {
|
||||
self.dcx().emit_err(errors::CVariadicBadExtern {
|
||||
span: variadic_param.span,
|
||||
abi: symbol_unescaped,
|
||||
extern_span: sig.extern_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_c_variadic_abi(
|
||||
&self,
|
||||
abi: ExternAbi,
|
||||
attrs: &'a AttrVec,
|
||||
dotdotdot_span: Span,
|
||||
sig: &FnSig,
|
||||
) {
|
||||
// For naked functions we accept any ABI that is accepted on c-variadic
|
||||
// foreign functions, if the c_variadic_naked_functions feature is enabled.
|
||||
if attr::contains_name(attrs, sym::naked) {
|
||||
match abi.supports_c_variadic() {
|
||||
CVariadicStatus::Stable if let ExternAbi::C { .. } = abi => {
|
||||
// With `c_variadic` naked c-variadic `extern "C"` functions are allowed.
|
||||
}
|
||||
CVariadicStatus::Stable => {
|
||||
// For e.g. aapcs or sysv64 `c_variadic_naked_functions` must also be enabled.
|
||||
if !self.features.enabled(sym::c_variadic_naked_functions) {
|
||||
let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");
|
||||
feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
CVariadicStatus::Unstable { feature } => {
|
||||
// Some ABIs need additional features.
|
||||
if !self.features.enabled(sym::c_variadic_naked_functions) {
|
||||
let msg = format!("Naked c-variadic `extern {abi}` functions are unstable");
|
||||
feature_err(&self.sess, sym::c_variadic_naked_functions, sig.span, msg)
|
||||
.emit();
|
||||
}
|
||||
|
||||
if !matches!(sig.header.safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::CVariadicMustBeUnsafe {
|
||||
span: variadic_param.span,
|
||||
unsafe_span: sig.safety_span(),
|
||||
});
|
||||
if !self.features.enabled(feature) {
|
||||
let msg = format!(
|
||||
"C-variadic functions with the {abi} calling convention are unstable"
|
||||
);
|
||||
feature_err(&self.sess, feature, sig.span, msg).emit();
|
||||
}
|
||||
}
|
||||
Extern::None => {
|
||||
let err = errors::CVariadicNoExtern { span: variadic_param.span };
|
||||
self.dcx().emit_err(err);
|
||||
CVariadicStatus::NotSupported => {
|
||||
// Some ABIs, e.g. `extern "Rust"`, never support c-variadic functions.
|
||||
self.dcx().emit_err(errors::CVariadicBadNakedExtern {
|
||||
span: dotdotdot_span,
|
||||
abi: abi.as_str(),
|
||||
extern_span: sig.extern_span(),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
} else if !matches!(abi, ExternAbi::C { .. }) {
|
||||
self.dcx().emit_err(errors::CVariadicBadExtern {
|
||||
span: dotdotdot_span,
|
||||
abi: abi.as_str(),
|
||||
extern_span: sig.extern_span(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1106,7 +1163,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
let kind = FnKind::Fn(FnCtxt::Free, &item.vis, &*func);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
self.visit_fn(kind, &item.attrs, item.span, item.id);
|
||||
}
|
||||
ItemKind::ForeignMod(ForeignMod { extern_span, abi, safety, .. }) => {
|
||||
let old_item = mem::replace(&mut self.extern_mod_span, Some(item.span));
|
||||
|
|
@ -1473,7 +1530,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
visit::walk_param_bound(self, bound)
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
|
||||
fn visit_fn(&mut self, fk: FnKind<'a>, attrs: &AttrVec, span: Span, id: NodeId) {
|
||||
// Only associated `fn`s can have `self` parameters.
|
||||
let self_semantic = match fk.ctxt() {
|
||||
Some(FnCtxt::Assoc(_)) => SelfSemantic::Yes,
|
||||
|
|
@ -1492,7 +1549,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
|
||||
}
|
||||
|
||||
self.check_c_variadic_type(fk);
|
||||
self.check_c_variadic_type(fk, attrs);
|
||||
|
||||
// Functions cannot both be `const async` or `const gen`
|
||||
if let Some(&FnHeader {
|
||||
|
|
@ -1643,7 +1700,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
{
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, &func.ident);
|
||||
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.vis, &*func);
|
||||
self.visit_fn(kind, item.span, item.id);
|
||||
self.visit_fn(kind, &item.attrs, item.span, item.id);
|
||||
}
|
||||
AssocItemKind::Type(_) => {
|
||||
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
|
||||
|
|
|
|||
|
|
@ -347,7 +347,18 @@ pub(crate) struct CVariadicMustBeUnsafe {
|
|||
pub(crate) struct CVariadicBadExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub abi: Symbol,
|
||||
pub abi: &'static str,
|
||||
#[label]
|
||||
pub extern_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_c_variadic_bad_naked_extern)]
|
||||
#[help]
|
||||
pub(crate) struct CVariadicBadNakedExtern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub abi: &'static str,
|
||||
#[label]
|
||||
pub extern_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
|
||||
use rustc_ast::{NodeId, PatKind, attr, token};
|
||||
use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token};
|
||||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::{feature_err, feature_warn};
|
||||
|
|
@ -392,7 +391,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
visit::walk_poly_trait_ref(self, t);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, _: &AttrVec, span: Span, _: NodeId) {
|
||||
if let Some(_header) = fn_kind.header() {
|
||||
// Stability of const fn methods are covered in `visit_assoc_item` below.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1807,8 +1807,14 @@ impl<'a> State<'a> {
|
|||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
self.word("&");
|
||||
if pinned.is_pinned() {
|
||||
self.word("pin ");
|
||||
if mutbl.is_not() {
|
||||
self.word("const ");
|
||||
}
|
||||
}
|
||||
if mutbl.is_mut() {
|
||||
self.word("mut ");
|
||||
}
|
||||
|
|
|
|||
89
compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
Normal file
89
compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use rustc_ast::token::Token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AttrStyle, NodeId, token};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span};
|
||||
|
||||
use crate::parser::MetaItemOrLitParser;
|
||||
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
|
||||
|
||||
pub enum CfgSelectPredicate {
|
||||
Cfg(CfgEntry),
|
||||
Wildcard(Token),
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CfgSelectBranches {
|
||||
/// All the conditional branches.
|
||||
pub reachable: Vec<(CfgEntry, TokenStream, Span)>,
|
||||
/// The first wildcard `_ => { ... }` branch.
|
||||
pub wildcard: Option<(Token, TokenStream, Span)>,
|
||||
/// All branches after the first wildcard, including further wildcards.
|
||||
/// These branches are kept for formatting.
|
||||
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
||||
}
|
||||
|
||||
pub fn parse_cfg_select(
|
||||
p: &mut Parser<'_>,
|
||||
sess: &Session,
|
||||
features: Option<&Features>,
|
||||
lint_node_id: NodeId,
|
||||
) -> Result<CfgSelectBranches, ErrorGuaranteed> {
|
||||
let mut branches = CfgSelectBranches::default();
|
||||
|
||||
while p.token != token::Eof {
|
||||
if p.eat_keyword(exp!(Underscore)) {
|
||||
let underscore = p.prev_token;
|
||||
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
|
||||
|
||||
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
|
||||
let span = underscore.span.to(p.token.span);
|
||||
|
||||
match branches.wildcard {
|
||||
None => branches.wildcard = Some((underscore, tts, span)),
|
||||
Some(_) => {
|
||||
branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
|
||||
.map_err(|diag| diag.emit())?;
|
||||
let cfg_span = meta.span();
|
||||
let cfg = AttributeParser::parse_single_args(
|
||||
sess,
|
||||
cfg_span,
|
||||
cfg_span,
|
||||
AttrStyle::Inner,
|
||||
AttrPath {
|
||||
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
|
||||
span: cfg_span,
|
||||
},
|
||||
ParsedDescription::Macro,
|
||||
cfg_span,
|
||||
lint_node_id,
|
||||
features,
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
&meta,
|
||||
parse_cfg_entry,
|
||||
&AttributeTemplate::default(),
|
||||
)?;
|
||||
|
||||
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
|
||||
|
||||
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
|
||||
let span = cfg_span.to(p.token.span);
|
||||
|
||||
match branches.wildcard {
|
||||
None => branches.reachable.push((cfg, tts, span)),
|
||||
Some(_) => branches.unreachable.push((CfgSelectPredicate::Cfg(cfg), tts, span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(branches)
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ pub(crate) mod allow_unstable;
|
|||
pub(crate) mod body;
|
||||
pub(crate) mod cfg;
|
||||
pub(crate) mod cfg_old;
|
||||
pub(crate) mod cfg_select;
|
||||
pub(crate) mod codegen_attrs;
|
||||
pub(crate) mod confusables;
|
||||
pub(crate) mod crate_level;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ pub use attributes::cfg::{
|
|||
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
|
||||
};
|
||||
pub use attributes::cfg_old::*;
|
||||
pub use attributes::cfg_select::*;
|
||||
pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version};
|
||||
pub use context::{Early, Late, OmitDoc, ShouldEmit};
|
||||
pub use interface::AttributeParser;
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ pub fn check_attribute_safety(
|
|||
|
||||
// - Normal builtin attribute
|
||||
// - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
|
||||
(Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
|
||||
(None | Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
|
||||
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
|
||||
span: unsafe_span,
|
||||
name: attr_item.path.clone(),
|
||||
|
|
@ -218,15 +218,10 @@ pub fn check_attribute_safety(
|
|||
|
||||
// - Normal builtin attribute
|
||||
// - No explicit `#[unsafe(..)]` written.
|
||||
(Some(AttributeSafety::Normal), Safety::Default) => {
|
||||
(None | Some(AttributeSafety::Normal), Safety::Default) => {
|
||||
// OK
|
||||
}
|
||||
|
||||
// - Non-builtin attribute
|
||||
(None, Safety::Unsafe(_) | Safety::Default) => {
|
||||
// OK (not checked here)
|
||||
}
|
||||
|
||||
(
|
||||
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
|
||||
Safety::Safe(..),
|
||||
|
|
|
|||
|
|
@ -3087,6 +3087,39 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
});
|
||||
|
||||
explanation.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);
|
||||
|
||||
// Detect buffer reuse pattern
|
||||
if let BorrowExplanation::UsedLater(_dropped_local, _, _, _) = explanation {
|
||||
// Check all locals at the borrow location to find Vec<&T> types
|
||||
for (local, local_decl) in self.body.local_decls.iter_enumerated() {
|
||||
if let ty::Adt(adt_def, args) = local_decl.ty.kind()
|
||||
&& self.infcx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())
|
||||
&& args.len() > 0
|
||||
{
|
||||
let vec_inner_ty = args.type_at(0);
|
||||
// Check if Vec contains references
|
||||
if vec_inner_ty.is_ref() {
|
||||
let local_place = local.into();
|
||||
if let Some(local_name) = self.describe_place(local_place) {
|
||||
err.span_label(
|
||||
local_decl.source_info.span,
|
||||
format!("variable `{local_name}` declared here"),
|
||||
);
|
||||
err.note(
|
||||
format!(
|
||||
"`{local_name}` is a collection that stores borrowed references, \
|
||||
but {name} does not live long enough to be stored in it"
|
||||
)
|
||||
);
|
||||
err.help(
|
||||
"buffer reuse with borrowed references requires unsafe code or restructuring"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
|
|
|
|||
|
|
@ -867,11 +867,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
for (binding_span, opt_ref_pat) in finder.ref_pat_for_binding {
|
||||
if let Some(ref_pat) = opt_ref_pat
|
||||
&& !finder.cannot_remove.contains(&ref_pat.hir_id)
|
||||
&& let hir::PatKind::Ref(subpat, mutbl) = ref_pat.kind
|
||||
&& let hir::PatKind::Ref(subpat, pinned, mutbl) = ref_pat.kind
|
||||
&& let Some(ref_span) = ref_pat.span.trim_end(subpat.span)
|
||||
{
|
||||
let pinned_str = if pinned.is_pinned() { "pinned " } else { "" };
|
||||
let mutable_str = if mutbl.is_mut() { "mutable " } else { "" };
|
||||
let msg = format!("consider removing the {mutable_str}borrow");
|
||||
let msg = format!("consider removing the {pinned_str}{mutable_str}borrow");
|
||||
suggestions.push((ref_span, msg, "".to_string()));
|
||||
} else {
|
||||
let msg = "consider borrowing the pattern binding".to_string();
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
AccessKind::Mutate => {
|
||||
err = self.cannot_assign(span, &(item_msg + &reason));
|
||||
act = "assign";
|
||||
acted_on = "written";
|
||||
acted_on = "written to";
|
||||
span
|
||||
}
|
||||
AccessKind::MutableBorrow => {
|
||||
|
|
@ -518,8 +518,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
err.span_label(
|
||||
span,
|
||||
format!(
|
||||
"`{name}` is a `{pointer_sigil}` {pointer_desc}, \
|
||||
so the data it refers to cannot be {acted_on}",
|
||||
"`{name}` is a `{pointer_sigil}` {pointer_desc}, so it cannot be \
|
||||
{acted_on}",
|
||||
),
|
||||
);
|
||||
|
||||
|
|
@ -542,7 +542,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
self.expected_fn_found_fn_mut_call(&mut err, span, act);
|
||||
}
|
||||
|
||||
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
|
||||
PlaceRef { local, projection: [.., ProjectionElem::Deref] } => {
|
||||
err.span_label(span, format!("cannot {act}"));
|
||||
|
||||
match opt_source {
|
||||
|
|
@ -559,11 +559,36 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
));
|
||||
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
|
||||
}
|
||||
_ => (),
|
||||
_ => {
|
||||
let local = &self.body.local_decls[local];
|
||||
match local.local_info() {
|
||||
LocalInfo::StaticRef { def_id, .. } => {
|
||||
let span = self.infcx.tcx.def_span(def_id);
|
||||
err.span_label(span, format!("this `static` cannot be {acted_on}"));
|
||||
}
|
||||
LocalInfo::ConstRef { def_id } => {
|
||||
let span = self.infcx.tcx.def_span(def_id);
|
||||
err.span_label(span, format!("this `const` cannot be {acted_on}"));
|
||||
}
|
||||
LocalInfo::BlockTailTemp(_) | LocalInfo::Boring
|
||||
if !local.source_info.span.overlaps(span) =>
|
||||
{
|
||||
err.span_label(
|
||||
local.source_info.span,
|
||||
format!("this cannot be {acted_on}"),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
PlaceRef { local, .. } => {
|
||||
let local = &self.body.local_decls[local];
|
||||
if !local.source_info.span.overlaps(span) {
|
||||
err.span_label(local.source_info.span, format!("this cannot be {acted_on}"));
|
||||
}
|
||||
err.span_label(span, format!("cannot {act}"));
|
||||
}
|
||||
}
|
||||
|
|
@ -772,11 +797,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
&& let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(&body).break_value()
|
||||
&& let node = self.infcx.tcx.hir_node(hir_id)
|
||||
&& let hir::Node::LetStmt(hir::LetStmt {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
|
||||
..
|
||||
})
|
||||
| hir::Node::Param(Param {
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
|
||||
pat: hir::Pat { kind: hir::PatKind::Ref(_, _, _), .. },
|
||||
..
|
||||
}) = node
|
||||
{
|
||||
|
|
@ -1494,7 +1519,7 @@ impl<'tcx> Visitor<'tcx> for BindingFinder {
|
|||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result {
|
||||
if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat
|
||||
if let hir::Pat { kind: hir::PatKind::Ref(_, _, _), span, .. } = param.pat
|
||||
&& *span == self.span
|
||||
{
|
||||
ControlFlow::Break(param.hir_id)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_attr_parsing as attr;
|
||||
use rustc_attr_parsing::{
|
||||
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select,
|
||||
};
|
||||
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
|
||||
use rustc_parse::parser::cfg_select::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
|
||||
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
|
||||
|
|
@ -9,11 +11,11 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
|
|||
/// Selects the first arm whose predicate evaluates to true.
|
||||
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
|
||||
for (cfg, tt, arm_span) in branches.reachable {
|
||||
if attr::cfg_matches(
|
||||
&cfg,
|
||||
if let EvalConfigResult::True = attr::eval_config_entry(
|
||||
&ecx.sess,
|
||||
&cfg,
|
||||
ecx.current_expansion.lint_node_id,
|
||||
Some(ecx.ecfg.features),
|
||||
ShouldEmit::ErrorsAndLints,
|
||||
) {
|
||||
return Some((tt, arm_span));
|
||||
}
|
||||
|
|
@ -27,37 +29,41 @@ pub(super) fn expand_cfg_select<'cx>(
|
|||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> MacroExpanderResult<'cx> {
|
||||
ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) {
|
||||
Ok(branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
ExpandResult::Ready(
|
||||
match parse_cfg_select(
|
||||
&mut ecx.new_parser_from_tts(tts),
|
||||
ecx.sess,
|
||||
Some(ecx.ecfg.features),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
) {
|
||||
Ok(branches) => {
|
||||
if let Some((underscore, _, _)) = branches.wildcard {
|
||||
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
|
||||
for (predicate, _, _) in &branches.unreachable {
|
||||
let span = match predicate {
|
||||
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
|
||||
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
|
||||
};
|
||||
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
|
||||
ecx.dcx().emit_warn(err);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
|
||||
return ExpandResult::from_tts(
|
||||
ecx,
|
||||
tts,
|
||||
sp,
|
||||
arm_span,
|
||||
Ident::with_dummy_span(sym::cfg_select),
|
||||
);
|
||||
} else {
|
||||
// Emit a compiler error when none of the predicates matched.
|
||||
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
|
||||
return ExpandResult::from_tts(
|
||||
ecx,
|
||||
tts,
|
||||
sp,
|
||||
arm_span,
|
||||
Ident::with_dummy_span(sym::cfg_select),
|
||||
);
|
||||
} else {
|
||||
// Emit a compiler error when none of the predicates matched.
|
||||
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let guar = err.emit();
|
||||
DummyResult::any(sp, guar)
|
||||
}
|
||||
})
|
||||
Err(guar) => DummyResult::any(sp, guar),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::MetaItem;
|
||||
use rustc_ast::{MetaItem, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
|
@ -24,6 +24,8 @@ pub(crate) fn expand_deriving_copy(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push);
|
||||
|
|
@ -48,6 +50,8 @@ pub(crate) fn expand_deriving_const_param_ty(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
|
||||
use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, Safety, VariantData};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
|
||||
use thin_vec::{ThinVec, thin_vec};
|
||||
|
||||
use crate::deriving::generic::ty::*;
|
||||
|
|
@ -68,6 +68,29 @@ pub(crate) fn expand_deriving_clone(
|
|||
_ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
|
||||
}
|
||||
|
||||
// If the clone method is just copying the value, also mark the type as
|
||||
// `TrivialClone` to allow some library optimizations.
|
||||
if is_simple {
|
||||
let trivial_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(clone::TrivialClone),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: bounds.clone(),
|
||||
supports_unions: true,
|
||||
methods: Vec::new(),
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Unsafe(DUMMY_SP),
|
||||
// `TrivialClone` is not part of an API guarantee, so it shouldn't
|
||||
// appear in rustdoc output.
|
||||
document: false,
|
||||
};
|
||||
|
||||
trivial_def.expand_ext(cx, mitem, item, push, true);
|
||||
}
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(clone::Clone),
|
||||
|
|
@ -88,6 +111,8 @@ pub(crate) fn expand_deriving_clone(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand_ext(cx, mitem, item, push, is_simple)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::{self as ast, MetaItem};
|
||||
use rustc_ast::{self as ast, MetaItem, Safety};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Span, sym};
|
||||
|
|
@ -44,6 +44,8 @@ pub(crate) fn expand_deriving_eq(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand_ext(cx, mitem, item, push, true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::MetaItem;
|
||||
use rustc_ast::{MetaItem, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
|
|
@ -35,6 +35,8 @@ pub(crate) fn expand_deriving_ord(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
|
||||
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
|
|
@ -30,6 +30,8 @@ pub(crate) fn expand_deriving_partial_eq(
|
|||
associated_types: Vec::new(),
|
||||
is_const: false,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
structural_trait_def.expand(cx, mitem, item, push);
|
||||
|
||||
|
|
@ -59,6 +61,8 @@ pub(crate) fn expand_deriving_partial_eq(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind};
|
||||
use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
|
|
@ -65,6 +65,8 @@ pub(crate) fn expand_deriving_partial_ord(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::{self as ast, EnumDef, MetaItem};
|
||||
use rustc_ast::{self as ast, EnumDef, MetaItem, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_session::config::FmtDebug;
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
|
|
@ -42,6 +42,8 @@ pub(crate) fn expand_deriving_debug(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use core::ops::ControlFlow;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::visit::visit_opt;
|
||||
use rustc_ast::{EnumDef, VariantData, attr};
|
||||
use rustc_ast::{self as ast, EnumDef, Safety, VariantData, attr};
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -52,6 +51,8 @@ pub(crate) fn expand_deriving_default(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
trait_def.expand(cx, mitem, item, push)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast as ast;
|
||||
use rustc_ast::{ItemKind, VariantData};
|
||||
use rustc_ast::{ItemKind, Safety, VariantData};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
|
|
@ -127,6 +127,8 @@ pub(crate) fn expand_deriving_from(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
from_trait_def.expand(cx, mitem, annotatable, push);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,12 @@ pub(crate) struct TraitDef<'a> {
|
|||
pub is_const: bool,
|
||||
|
||||
pub is_staged_api_crate: bool,
|
||||
|
||||
/// The safety of the `impl`.
|
||||
pub safety: Safety,
|
||||
|
||||
/// Whether the added `impl` should appear in rustdoc output.
|
||||
pub document: bool,
|
||||
}
|
||||
|
||||
pub(crate) struct MethodDef<'a> {
|
||||
|
|
@ -826,13 +832,17 @@ impl<'a> TraitDef<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
if !self.document {
|
||||
attrs.push(cx.attr_nested_word(sym::doc, sym::hidden, self.span));
|
||||
}
|
||||
|
||||
cx.item(
|
||||
self.span,
|
||||
attrs,
|
||||
ast::ItemKind::Impl(ast::Impl {
|
||||
generics: trait_generics,
|
||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||
safety: ast::Safety::Default,
|
||||
safety: self.safety,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: if self.is_const {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_ast::{MetaItem, Mutability};
|
||||
use rustc_ast::{MetaItem, Mutability, Safety};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Span, sym};
|
||||
use thin_vec::thin_vec;
|
||||
|
|
@ -42,6 +42,8 @@ pub(crate) fn expand_deriving_hash(
|
|||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
is_staged_api_crate: cx.ecfg.features.staged_api(),
|
||||
safety: Safety::Default,
|
||||
document: true,
|
||||
};
|
||||
|
||||
hash_trait_def.expand(cx, mitem, item, push);
|
||||
|
|
|
|||
|
|
@ -916,8 +916,8 @@ pub(crate) fn codegen_call_with_unwind_action(
|
|||
pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam {
|
||||
let param = AbiParam::new(ty);
|
||||
if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() {
|
||||
match (&tcx.sess.target.arch, tcx.sess.target.vendor.as_ref()) {
|
||||
(Arch::X86_64, _) | (Arch::AArch64, "apple") => match (ty, is_signed) {
|
||||
match (&tcx.sess.target.arch, tcx.sess.target.is_like_darwin) {
|
||||
(Arch::X86_64, _) | (Arch::AArch64, true) => match (ty, is_signed) {
|
||||
(types::I8 | types::I16, true) => param.sext(),
|
||||
(types::I8 | types::I16, false) => param.uext(),
|
||||
_ => param,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::prelude::*;
|
|||
|
||||
pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
||||
let (value, arg_ty) =
|
||||
if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
(
|
||||
fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value),
|
||||
lib_call_arg_param(fx.tcx, types::I16, false),
|
||||
|
|
@ -22,8 +22,7 @@ fn f16_to_f64(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
|||
}
|
||||
|
||||
pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
||||
let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64
|
||||
{
|
||||
let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
types::I16
|
||||
} else {
|
||||
types::F16
|
||||
|
|
@ -38,8 +37,7 @@ pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value
|
|||
}
|
||||
|
||||
fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value {
|
||||
let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64
|
||||
{
|
||||
let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 {
|
||||
types::I16
|
||||
} else {
|
||||
types::F16
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
|||
use rustc_session::Session;
|
||||
use rustc_session::config::OutputFilenames;
|
||||
use rustc_span::{Symbol, sym};
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Abi, Arch, Env, Os};
|
||||
|
||||
pub use crate::config::*;
|
||||
use crate::prelude::*;
|
||||
|
|
@ -163,15 +163,15 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
fn target_config(&self, sess: &Session) -> TargetConfig {
|
||||
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
|
||||
let target_features = match sess.target.arch {
|
||||
Arch::X86_64 if sess.target.os != "none" => {
|
||||
Arch::X86_64 if sess.target.os != Os::None => {
|
||||
// x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled
|
||||
vec![sym::fxsr, sym::sse, sym::sse2, Symbol::intern("x87")]
|
||||
}
|
||||
Arch::AArch64 => match &*sess.target.os {
|
||||
"none" => vec![],
|
||||
Arch::AArch64 => match &sess.target.os {
|
||||
Os::None => vec![],
|
||||
// On macOS the aes, sha2 and sha3 features are enabled by default and ring
|
||||
// fails to compile on macOS when they are not present.
|
||||
"macos" => vec![sym::neon, sym::aes, sym::sha2, sym::sha3],
|
||||
Os::MacOs => vec![sym::neon, sym::aes, sym::sha2, sym::sha3],
|
||||
// AArch64 mandates Neon support
|
||||
_ => vec![sym::neon],
|
||||
},
|
||||
|
|
@ -184,9 +184,9 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
// targets due to GCC using a different ABI than LLVM. Therefore `f16` and `f128`
|
||||
// won't be available when using a LLVM-built sysroot.
|
||||
let has_reliable_f16_f128 = !(sess.target.arch == Arch::X86_64
|
||||
&& sess.target.os == "windows"
|
||||
&& sess.target.env == "gnu"
|
||||
&& sess.target.abi != "llvm");
|
||||
&& sess.target.os == Os::Windows
|
||||
&& sess.target.env == Env::Gnu
|
||||
&& sess.target.abi != Abi::Llvm);
|
||||
|
||||
TargetConfig {
|
||||
target_features,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
use rustc_codegen_ssa::common;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv};
|
||||
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Arch, Env};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::context::CodegenCx;
|
||||
|
|
@ -145,7 +145,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
|
|||
if cx.use_dll_storage_attrs
|
||||
&& let Some(library) = tcx.native_library(instance_def_id)
|
||||
&& library.kind.is_dllimport()
|
||||
&& !matches!(tcx.sess.target.env.as_ref(), "gnu" | "uclibc")
|
||||
&& !matches!(tcx.sess.target.env, Env::Gnu | Env::Uclibc)
|
||||
{
|
||||
llvm::set_dllimport_storage_class(llfn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use rustc_span::source_map::Spanned;
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{
|
||||
Arch, HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel,
|
||||
Abi, Arch, Env, HasTargetSpec, Os, RelocModel, SmallDataThresholdSupport, Target, TlsModel,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
@ -335,9 +335,9 @@ pub(crate) unsafe fn create_module<'ll>(
|
|||
|
||||
// Control Flow Guard is currently only supported by MSVC and LLVM on Windows.
|
||||
if sess.target.is_like_msvc
|
||||
|| (sess.target.options.os == "windows"
|
||||
&& sess.target.options.env == "gnu"
|
||||
&& sess.target.options.abi == "llvm")
|
||||
|| (sess.target.options.os == Os::Windows
|
||||
&& sess.target.options.env == Env::Gnu
|
||||
&& sess.target.options.abi == Abi::Llvm)
|
||||
{
|
||||
match sess.opts.cg.control_flow_guard {
|
||||
CFGuard::Disabled => {}
|
||||
|
|
@ -669,7 +669,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
/// This corresponds to the `-fobjc-abi-version=` flag in Clang / GCC.
|
||||
pub(crate) fn objc_abi_version(&self) -> u32 {
|
||||
assert!(self.tcx.sess.target.is_like_darwin);
|
||||
if self.tcx.sess.target.arch == Arch::X86 && self.tcx.sess.target.os == "macos" {
|
||||
if self.tcx.sess.target.arch == Arch::X86 && self.tcx.sess.target.os == Os::MacOs {
|
||||
// 32-bit x86 macOS uses ABI version 1 (a.k.a. the "fragile ABI").
|
||||
1
|
||||
} else {
|
||||
|
|
@ -710,7 +710,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
},
|
||||
);
|
||||
|
||||
if self.tcx.sess.target.env == "sim" {
|
||||
if self.tcx.sess.target.env == Env::Sim {
|
||||
llvm::add_module_flag_u32(
|
||||
self.llmod,
|
||||
llvm::ModuleFlagMergeBehavior::Error,
|
||||
|
|
@ -963,7 +963,7 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
return eh_catch_typeinfo;
|
||||
}
|
||||
let tcx = self.tcx;
|
||||
assert!(self.sess().target.os == "emscripten");
|
||||
assert!(self.sess().target.os == Os::Emscripten);
|
||||
let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
|
||||
Some(def_id) => self.get_static(def_id),
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_middle::{bug, span_bug};
|
|||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
|
||||
use rustc_target::callconv::PassMode;
|
||||
use rustc_target::spec::Os;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::abi::FnAbiLlvmExt;
|
||||
|
|
@ -681,7 +682,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>(
|
|||
codegen_msvc_try(bx, try_func, data, catch_func, dest);
|
||||
} else if wants_wasm_eh(bx.sess()) {
|
||||
codegen_wasm_try(bx, try_func, data, catch_func, dest);
|
||||
} else if bx.sess().target.os == "emscripten" {
|
||||
} else if bx.sess().target.os == Os::Emscripten {
|
||||
codegen_emcc_try(bx, try_func, data, catch_func, dest);
|
||||
} else {
|
||||
codegen_gnu_try(bx, try_func, data, catch_func, dest);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ use rustc_fs_util::path_to_c_string;
|
|||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{PrintKind, PrintRequest};
|
||||
use rustc_target::spec::{Arch, MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
|
||||
use rustc_target::spec::{
|
||||
Abi, Arch, Env, MergeFunctions, Os, PanicStrategy, SmallDataThresholdSupport,
|
||||
};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
|
|
@ -104,7 +106,7 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||
add("-wasm-enable-eh", false);
|
||||
}
|
||||
|
||||
if sess.target.os == "emscripten"
|
||||
if sess.target.os == Os::Emscripten
|
||||
&& !sess.opts.unstable_opts.emscripten_wasm_eh
|
||||
&& sess.panic_strategy().unwinds()
|
||||
{
|
||||
|
|
@ -351,9 +353,9 @@ pub(crate) fn target_config(sess: &Session) -> TargetConfig {
|
|||
/// Determine whether or not experimental float types are reliable based on known bugs.
|
||||
fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
||||
let target_arch = &sess.target.arch;
|
||||
let target_os = sess.target.options.os.as_ref();
|
||||
let target_env = sess.target.options.env.as_ref();
|
||||
let target_abi = sess.target.options.abi.as_ref();
|
||||
let target_os = &sess.target.options.os;
|
||||
let target_env = &sess.target.options.env;
|
||||
let target_abi = &sess.target.options.abi;
|
||||
let target_pointer_width = sess.target.pointer_width;
|
||||
let version = get_version();
|
||||
let lt_20_1_1 = version < (20, 1, 1);
|
||||
|
|
@ -371,7 +373,7 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
|||
// Selection failure <https://github.com/llvm/llvm-project/issues/50374> (fixed in llvm21)
|
||||
(Arch::S390x, _) if lt_21_0_0 => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
(Arch::X86_64, "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
|
||||
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
|
||||
(Arch::CSky, _) => false,
|
||||
(Arch::Hexagon, _) if lt_21_0_0 => false, // (fixed in llvm21)
|
||||
|
|
@ -403,7 +405,7 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
|||
// not fail if our compiler-builtins is linked. (fixed in llvm21)
|
||||
(Arch::X86, _) if lt_21_0_0 => false,
|
||||
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
|
||||
(Arch::X86_64, "windows") if target_env == "gnu" && target_abi != "llvm" => false,
|
||||
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != Abi::Llvm => false,
|
||||
// There are no known problems on other platforms, so the only requirement is that symbols
|
||||
// are available. `compiler-builtins` provides all symbols required for core `f128`
|
||||
// support, so this should work for everything else.
|
||||
|
|
@ -424,9 +426,9 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
|
|||
// (ld is 80-bit extended precision).
|
||||
//
|
||||
// musl does not implement the symbols required for f128 math at all.
|
||||
_ if target_env == "musl" => false,
|
||||
_ if *target_env == Env::Musl => false,
|
||||
(Arch::X86_64, _) => false,
|
||||
(_, "linux") if target_pointer_width == 64 => true,
|
||||
(_, Os::Linux) if target_pointer_width == 64 => true,
|
||||
_ => false,
|
||||
} && cfg.has_reliable_f128;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::{
|
|||
};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Abi, Arch};
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::llvm::{Type, Value};
|
||||
|
|
@ -270,7 +270,7 @@ fn emit_powerpc_va_arg<'ll, 'tcx>(
|
|||
|
||||
// Rust does not currently support any powerpc softfloat targets.
|
||||
let target = &bx.cx.tcx.sess.target;
|
||||
let is_soft_float_abi = target.abi == "softfloat";
|
||||
let is_soft_float_abi = target.abi == Abi::SoftFloat;
|
||||
assert!(!is_soft_float_abi);
|
||||
|
||||
// All instances of VaArgSafe are passed directly.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use itertools::Itertools;
|
|||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_session::Session;
|
||||
pub(super) use rustc_target::spec::apple::OSVersion;
|
||||
use rustc_target::spec::{Arch, Target};
|
||||
use rustc_target::spec::{Arch, Env, Os, Target};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::errors::{XcrunError, XcrunSdkPathWarning};
|
||||
|
|
@ -17,35 +17,35 @@ mod tests;
|
|||
|
||||
/// The canonical name of the desired SDK for a given target.
|
||||
pub(super) fn sdk_name(target: &Target) -> &'static str {
|
||||
match (&*target.os, &*target.env) {
|
||||
("macos", "") => "MacOSX",
|
||||
("ios", "") => "iPhoneOS",
|
||||
("ios", "sim") => "iPhoneSimulator",
|
||||
match (&target.os, &target.env) {
|
||||
(Os::MacOs, Env::Unspecified) => "MacOSX",
|
||||
(Os::IOs, Env::Unspecified) => "iPhoneOS",
|
||||
(Os::IOs, Env::Sim) => "iPhoneSimulator",
|
||||
// Mac Catalyst uses the macOS SDK
|
||||
("ios", "macabi") => "MacOSX",
|
||||
("tvos", "") => "AppleTVOS",
|
||||
("tvos", "sim") => "AppleTVSimulator",
|
||||
("visionos", "") => "XROS",
|
||||
("visionos", "sim") => "XRSimulator",
|
||||
("watchos", "") => "WatchOS",
|
||||
("watchos", "sim") => "WatchSimulator",
|
||||
(Os::IOs, Env::MacAbi) => "MacOSX",
|
||||
(Os::TvOs, Env::Unspecified) => "AppleTVOS",
|
||||
(Os::TvOs, Env::Sim) => "AppleTVSimulator",
|
||||
(Os::VisionOs, Env::Unspecified) => "XROS",
|
||||
(Os::VisionOs, Env::Sim) => "XRSimulator",
|
||||
(Os::WatchOs, Env::Unspecified) => "WatchOS",
|
||||
(Os::WatchOs, Env::Sim) => "WatchSimulator",
|
||||
(os, abi) => unreachable!("invalid os '{os}' / abi '{abi}' combination for Apple target"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn macho_platform(target: &Target) -> u32 {
|
||||
match (&*target.os, &*target.env) {
|
||||
("macos", _) => object::macho::PLATFORM_MACOS,
|
||||
("ios", "macabi") => object::macho::PLATFORM_MACCATALYST,
|
||||
("ios", "sim") => object::macho::PLATFORM_IOSSIMULATOR,
|
||||
("ios", _) => object::macho::PLATFORM_IOS,
|
||||
("watchos", "sim") => object::macho::PLATFORM_WATCHOSSIMULATOR,
|
||||
("watchos", _) => object::macho::PLATFORM_WATCHOS,
|
||||
("tvos", "sim") => object::macho::PLATFORM_TVOSSIMULATOR,
|
||||
("tvos", _) => object::macho::PLATFORM_TVOS,
|
||||
("visionos", "sim") => object::macho::PLATFORM_XROSSIMULATOR,
|
||||
("visionos", _) => object::macho::PLATFORM_XROS,
|
||||
_ => unreachable!("tried to get Mach-O platform for non-Apple target"),
|
||||
match (&target.os, &target.env) {
|
||||
(Os::MacOs, _) => object::macho::PLATFORM_MACOS,
|
||||
(Os::IOs, Env::MacAbi) => object::macho::PLATFORM_MACCATALYST,
|
||||
(Os::IOs, Env::Sim) => object::macho::PLATFORM_IOSSIMULATOR,
|
||||
(Os::IOs, _) => object::macho::PLATFORM_IOS,
|
||||
(Os::WatchOs, Env::Sim) => object::macho::PLATFORM_WATCHOSSIMULATOR,
|
||||
(Os::WatchOs, _) => object::macho::PLATFORM_WATCHOS,
|
||||
(Os::TvOs, Env::Sim) => object::macho::PLATFORM_TVOSSIMULATOR,
|
||||
(Os::TvOs, _) => object::macho::PLATFORM_TVOS,
|
||||
(Os::VisionOs, Env::Sim) => object::macho::PLATFORM_XROSSIMULATOR,
|
||||
(Os::VisionOs, _) => object::macho::PLATFORM_XROS,
|
||||
(os, env) => unreachable!("invalid os '{os}' / env '{env}' combination for Apple target"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ use rustc_session::{Session, filesearch};
|
|||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::crt_objects::CrtObjects;
|
||||
use rustc_target::spec::{
|
||||
BinaryFormat, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault,
|
||||
LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, RelocModel, RelroLevel, SanitizerSet,
|
||||
SplitDebuginfo,
|
||||
Abi, BinaryFormat, Cc, Env, LinkOutputKind, LinkSelfContainedComponents,
|
||||
LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, Os, RelocModel,
|
||||
RelroLevel, SanitizerSet, SplitDebuginfo,
|
||||
};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
|
|
@ -1407,11 +1407,9 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
|||
Some(LinkerFlavorCli::Llbc) => Some(LinkerFlavor::Llbc),
|
||||
Some(LinkerFlavorCli::Ptx) => Some(LinkerFlavor::Ptx),
|
||||
// The linker flavors that corresponds to targets needs logic that keeps the base LinkerFlavor
|
||||
_ => sess
|
||||
.opts
|
||||
.cg
|
||||
.linker_flavor
|
||||
.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor)),
|
||||
linker_flavor => {
|
||||
linker_flavor.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor))
|
||||
}
|
||||
};
|
||||
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor, features) {
|
||||
return ret;
|
||||
|
|
@ -1819,7 +1817,7 @@ fn self_contained_components(
|
|||
LinkSelfContainedDefault::InferredForMusl => sess.crt_static(Some(crate_type)),
|
||||
LinkSelfContainedDefault::InferredForMingw => {
|
||||
sess.host == sess.target
|
||||
&& sess.target.vendor != "uwp"
|
||||
&& sess.target.abi != Abi::Uwp
|
||||
&& detect_self_contained_mingw(sess, linker)
|
||||
}
|
||||
}
|
||||
|
|
@ -1845,7 +1843,7 @@ fn add_pre_link_objects(
|
|||
let empty = Default::default();
|
||||
let objects = if self_contained {
|
||||
&opts.pre_link_objects_self_contained
|
||||
} else if !(sess.target.os == "fuchsia" && matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))) {
|
||||
} else if !(sess.target.os == Os::Fuchsia && matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))) {
|
||||
&opts.pre_link_objects
|
||||
} else {
|
||||
&empty
|
||||
|
|
@ -2496,7 +2494,7 @@ fn add_order_independent_options(
|
|||
|
||||
let apple_sdk_root = add_apple_sdk(cmd, sess, flavor);
|
||||
|
||||
if sess.target.os == "fuchsia"
|
||||
if sess.target.os == Os::Fuchsia
|
||||
&& crate_type == CrateType::Executable
|
||||
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
|
||||
{
|
||||
|
|
@ -2515,7 +2513,7 @@ fn add_order_independent_options(
|
|||
cmd.no_crt_objects();
|
||||
}
|
||||
|
||||
if sess.target.os == "emscripten" {
|
||||
if sess.target.os == Os::Emscripten {
|
||||
cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh {
|
||||
"-fwasm-exceptions"
|
||||
} else if sess.panic_strategy().unwinds() {
|
||||
|
|
@ -3070,8 +3068,8 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
|||
|
||||
// `sess.target.arch` (`target_arch`) is not detailed enough.
|
||||
let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0;
|
||||
let target_os = &*sess.target.os;
|
||||
let target_env = &*sess.target.env;
|
||||
let target_os = &sess.target.os;
|
||||
let target_env = &sess.target.env;
|
||||
|
||||
// The architecture name to forward to the linker.
|
||||
//
|
||||
|
|
@ -3123,12 +3121,12 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
|||
// > - xros-simulator
|
||||
// > - driverkit
|
||||
let platform_name = match (target_os, target_env) {
|
||||
(os, "") => os,
|
||||
("ios", "macabi") => "mac-catalyst",
|
||||
("ios", "sim") => "ios-simulator",
|
||||
("tvos", "sim") => "tvos-simulator",
|
||||
("watchos", "sim") => "watchos-simulator",
|
||||
("visionos", "sim") => "visionos-simulator",
|
||||
(os, Env::Unspecified) => os.desc(),
|
||||
(Os::IOs, Env::MacAbi) => "mac-catalyst",
|
||||
(Os::IOs, Env::Sim) => "ios-simulator",
|
||||
(Os::TvOs, Env::Sim) => "tvos-simulator",
|
||||
(Os::WatchOs, Env::Sim) => "watchos-simulator",
|
||||
(Os::VisionOs, Env::Sim) => "visionos-simulator",
|
||||
_ => bug!("invalid OS/env combination for Apple target: {target_os}, {target_env}"),
|
||||
};
|
||||
|
||||
|
|
@ -3192,7 +3190,7 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
|
|||
// fairly safely use `-target`. See also the following, where it is
|
||||
// made explicit that the recommendation by LLVM developers is to use
|
||||
// `-target`: <https://github.com/llvm/llvm-project/issues/88271>
|
||||
if target_os == "macos" {
|
||||
if *target_os == Os::MacOs {
|
||||
// `-arch` communicates the architecture.
|
||||
//
|
||||
// CC forwards the `-arch` to the linker, so we use the same value
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use rustc_middle::middle::exported_symbols::{
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
|
||||
use rustc_target::spec::{Arch, Cc, LinkOutputKind, LinkerFlavor, Lld};
|
||||
use rustc_target::spec::{Abi, Arch, Cc, LinkOutputKind, LinkerFlavor, Lld, Os};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use super::command::Command;
|
||||
|
|
@ -83,7 +83,7 @@ pub(crate) fn get_linker<'a>(
|
|||
// To comply with the Windows App Certification Kit,
|
||||
// MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
|
||||
let t = &sess.target;
|
||||
if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" {
|
||||
if matches!(flavor, LinkerFlavor::Msvc(..)) && t.abi == Abi::Uwp {
|
||||
if let Some(ref tool) = msvc_tool {
|
||||
let original_path = tool.path();
|
||||
if let Some(root_lib_path) = original_path.ancestors().nth(4) {
|
||||
|
|
@ -134,12 +134,12 @@ pub(crate) fn get_linker<'a>(
|
|||
|
||||
// FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
|
||||
// to the linker args construction.
|
||||
assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
|
||||
assert!(cmd.get_args().is_empty() || sess.target.abi == Abi::Uwp);
|
||||
match flavor {
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => {
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == Os::L4Re => {
|
||||
Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>
|
||||
}
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == "aix" => {
|
||||
LinkerFlavor::Unix(Cc::No) if sess.target.os == Os::Aix => {
|
||||
Box::new(AixLinker::new(cmd, sess)) as Box<dyn Linker>
|
||||
}
|
||||
LinkerFlavor::WasmLld(Cc::No) => Box::new(WasmLd::new(cmd, sess)) as Box<dyn Linker>,
|
||||
|
|
@ -573,7 +573,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
// any `#[link]` attributes in the `libc` crate, see #72782 for details.
|
||||
// FIXME: Switch to using `#[link]` attributes in the `libc` crate
|
||||
// similarly to other targets.
|
||||
if self.sess.target.os == "vxworks"
|
||||
if self.sess.target.os == Os::VxWorks
|
||||
&& matches!(
|
||||
output_kind,
|
||||
LinkOutputKind::StaticNoPicExe
|
||||
|
|
@ -595,7 +595,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
}
|
||||
|
||||
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
|
||||
if self.sess.target.os == "illumos" && name == "c" {
|
||||
if self.sess.target.os == Os::Illumos && name == "c" {
|
||||
// libc will be added via late_link_args on illumos so that it will
|
||||
// appear last in the library search order.
|
||||
// FIXME: This should be replaced by a more complete and generic
|
||||
|
|
@ -1439,7 +1439,7 @@ impl<'a> Linker for WasmLd<'a> {
|
|||
// symbols explicitly passed via the `--export` flags above and hides all
|
||||
// others. Various bits and pieces of wasm32-unknown-unknown tooling use
|
||||
// this, so be sure these symbols make their way out of the linker as well.
|
||||
if self.sess.target.os == "unknown" || self.sess.target.os == "none" {
|
||||
if matches!(self.sess.target.os, Os::Unknown | Os::None) {
|
||||
self.link_args(&["--export=__heap_base", "--export=__data_end"]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use rustc_metadata::fs::METADATA_FILENAME;
|
|||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::sym;
|
||||
use rustc_target::spec::{RelocModel, Target, ef_avr_arch};
|
||||
use rustc_target::spec::{Abi, Os, RelocModel, Target, ef_avr_arch};
|
||||
use tracing::debug;
|
||||
|
||||
use super::apple;
|
||||
|
|
@ -260,10 +260,10 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
|||
}
|
||||
|
||||
pub(super) fn elf_os_abi(sess: &Session) -> u8 {
|
||||
match sess.target.options.os.as_ref() {
|
||||
"hermit" => elf::ELFOSABI_STANDALONE,
|
||||
"freebsd" => elf::ELFOSABI_FREEBSD,
|
||||
"solaris" => elf::ELFOSABI_SOLARIS,
|
||||
match sess.target.options.os {
|
||||
Os::Hermit => elf::ELFOSABI_STANDALONE,
|
||||
Os::FreeBsd => elf::ELFOSABI_FREEBSD,
|
||||
Os::Solaris => elf::ELFOSABI_SOLARIS,
|
||||
_ => elf::ELFOSABI_NONE,
|
||||
}
|
||||
}
|
||||
|
|
@ -379,11 +379,11 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
|
|||
}
|
||||
}
|
||||
Architecture::Csky => {
|
||||
let e_flags = match sess.target.options.abi.as_ref() {
|
||||
"abiv2" => elf::EF_CSKY_ABIV2,
|
||||
_ => elf::EF_CSKY_ABIV1,
|
||||
};
|
||||
e_flags
|
||||
if matches!(sess.target.options.abi, Abi::AbiV2) {
|
||||
elf::EF_CSKY_ABIV2
|
||||
} else {
|
||||
elf::EF_CSKY_ABIV1
|
||||
}
|
||||
}
|
||||
Architecture::PowerPc64 => {
|
||||
const EF_PPC64_ABI_UNKNOWN: u32 = 0;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolNam
|
|||
use rustc_middle::util::Providers;
|
||||
use rustc_session::config::{CrateType, OomStrategy};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{Arch, TlsModel};
|
||||
use rustc_target::spec::{Arch, Os, TlsModel};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::back::symbol_export;
|
||||
|
|
@ -711,7 +711,7 @@ pub(crate) fn extend_exported_symbols<'tcx>(
|
|||
) {
|
||||
let (callconv, _) = calling_convention_for_symbol(tcx, symbol);
|
||||
|
||||
if callconv != CanonAbi::GpuKernel || tcx.sess.target.os != "amdhsa" {
|
||||
if callconv != CanonAbi::GpuKernel || tcx.sess.target.os != Os::AmdHsa {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use rustc_session::Session;
|
|||
use rustc_session::config::{self, CrateType, EntryFnType};
|
||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::Arch;
|
||||
use rustc_target::spec::{Arch, Os};
|
||||
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
|
||||
use tracing::{debug, info};
|
||||
|
|
@ -366,7 +366,7 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// us
|
||||
pub fn wants_wasm_eh(sess: &Session) -> bool {
|
||||
sess.target.is_like_wasm
|
||||
&& (sess.target.os != "emscripten" || sess.opts.unstable_opts.emscripten_wasm_eh)
|
||||
&& (sess.target.os != Os::Emscripten || sess.opts.unstable_opts.emscripten_wasm_eh)
|
||||
}
|
||||
|
||||
/// Returns `true` if this session's target will use SEH-based unwinding.
|
||||
|
|
@ -500,7 +500,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
) -> Bx::Function {
|
||||
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or
|
||||
// `usize efi_main(void *handle, void *system_table)` depending on the target.
|
||||
let llfty = if cx.sess().target.os.contains("uefi") {
|
||||
let llfty = if cx.sess().target.os == Os::Uefi {
|
||||
cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize())
|
||||
} else if cx.sess().target.main_needs_argc_argv {
|
||||
cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int())
|
||||
|
|
@ -562,7 +562,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
};
|
||||
|
||||
let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
|
||||
if cx.sess().target.os.contains("uefi") {
|
||||
if cx.sess().target.os == Os::Uefi {
|
||||
bx.ret(result);
|
||||
} else {
|
||||
let cast = bx.intcast(result, cx.type_int(), true);
|
||||
|
|
@ -576,7 +576,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
/// Obtain the `argc` and `argv` values to pass to the rust start function
|
||||
/// (i.e., the "start" lang item).
|
||||
fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) {
|
||||
if bx.cx().sess().target.os.contains("uefi") {
|
||||
if bx.cx().sess().target.os == Os::Uefi {
|
||||
// Params for UEFI
|
||||
let param_handle = bx.get_param(0);
|
||||
let param_system_table = bx.get_param(1);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc_middle::ty::{self as ty, TyCtxt};
|
|||
use rustc_session::lint;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use rustc_target::spec::Os;
|
||||
|
||||
use crate::errors;
|
||||
use crate::target_features::{
|
||||
|
|
@ -258,7 +259,7 @@ fn process_builtin_attrs(
|
|||
UsedBy::Compiler => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_COMPILER,
|
||||
UsedBy::Linker => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER,
|
||||
UsedBy::Default => {
|
||||
let used_form = if tcx.sess.target.os == "illumos" {
|
||||
let used_form = if tcx.sess.target.os == Os::Illumos {
|
||||
// illumos' `ld` doesn't support a section header that would represent
|
||||
// `#[used(linker)]`, see
|
||||
// https://github.com/rust-lang/rust/issues/146169. For that target,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_middle::ty::{self, Instance, TyCtxt};
|
|||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_session::cstore::{DllCallingConvention, DllImport};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::Target;
|
||||
use rustc_target::spec::{Abi, Env, Os, Target};
|
||||
|
||||
use crate::traits::*;
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ pub fn asm_const_to_str<'tcx>(
|
|||
}
|
||||
|
||||
pub fn is_mingw_gnu_toolchain(target: &Target) -> bool {
|
||||
target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty()
|
||||
target.os == Os::Windows && target.env == Env::Gnu && target.abi == Abi::Unspecified
|
||||
}
|
||||
|
||||
pub fn i686_decorated_name(
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ impl !DynSend for std::env::VarsOs {}
|
|||
|
||||
macro_rules! already_send {
|
||||
($([$ty: ty])*) => {
|
||||
$(unsafe impl DynSend for $ty where $ty: Send {})*
|
||||
$(unsafe impl DynSend for $ty where Self: Send {})*
|
||||
};
|
||||
}
|
||||
|
||||
// These structures are already `Send`.
|
||||
already_send!(
|
||||
[std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File]
|
||||
[std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File][std::panic::Location<'_>]
|
||||
[rustc_arena::DroplessArena][jobserver_crate::Client][jobserver_crate::HelperThread]
|
||||
[crate::memmap::Mmap][crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice]
|
||||
);
|
||||
|
|
@ -127,14 +127,14 @@ impl !DynSync for std::env::VarsOs {}
|
|||
|
||||
macro_rules! already_sync {
|
||||
($([$ty: ty])*) => {
|
||||
$(unsafe impl DynSync for $ty where $ty: Sync {})*
|
||||
$(unsafe impl DynSync for $ty where Self: Sync {})*
|
||||
};
|
||||
}
|
||||
|
||||
// These structures are already `Sync`.
|
||||
already_sync!(
|
||||
[std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8]
|
||||
[std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File]
|
||||
[std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File][std::panic::Location<'_>]
|
||||
[jobserver_crate::Client][jobserver_crate::HelperThread][crate::memmap::Mmap]
|
||||
[crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::stable_hasher::{HashStable, StableHasher};
|
||||
use crate::sync::{MappedReadGuard, ReadGuard, RwLock};
|
||||
use crate::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, RwLock, WriteGuard};
|
||||
|
||||
/// The `Steal` struct is intended to used as the value for a query.
|
||||
/// Specifically, we sometimes have queries (*cough* MIR *cough*)
|
||||
|
|
@ -40,9 +40,17 @@ impl<T> Steal<T> {
|
|||
ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
|
||||
}
|
||||
|
||||
/// An escape hatch for rustc drivers to mutate `Steal` caches.
|
||||
///
|
||||
/// Use at your own risk. This can badly break incremental compilation
|
||||
/// and anything else that relies on the immutability of query caches.
|
||||
#[track_caller]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
self.value.get_mut().as_mut().expect("attempt to read from stolen value")
|
||||
pub fn risky_hack_borrow_mut(&self) -> MappedWriteGuard<'_, T> {
|
||||
let borrow = self.value.borrow_mut();
|
||||
if borrow.is_none() {
|
||||
panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
|
||||
}
|
||||
WriteGuard::map(borrow, |opt| opt.as_mut().unwrap())
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
|
|
|||
|
|
@ -152,7 +152,8 @@ pub(super) fn install() {
|
|||
libc::sigaltstack(&alt_stack, ptr::null_mut());
|
||||
|
||||
let mut sa: libc::sigaction = mem::zeroed();
|
||||
sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
|
||||
sa.sa_sigaction =
|
||||
print_stack_trace as unsafe extern "C" fn(libc::c_int) as libc::sighandler_t;
|
||||
sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK;
|
||||
libc::sigemptyset(&mut sa.sa_mask);
|
||||
for (signum, _signame) in KILL_SIGNALS {
|
||||
|
|
|
|||
|
|
@ -1704,7 +1704,7 @@ impl HumanEmitter {
|
|||
}
|
||||
// print out the span location and spacer before we print the annotated source
|
||||
// to do this, we need to know if this span will be primary
|
||||
let is_primary = primary_lo.file.name == annotated_file.file.name;
|
||||
let is_primary = primary_lo.file.stable_id == annotated_file.file.stable_id;
|
||||
if is_primary {
|
||||
let loc = primary_lo.clone();
|
||||
if !self.short_message {
|
||||
|
|
@ -2322,11 +2322,6 @@ impl HumanEmitter {
|
|||
show_code_change
|
||||
{
|
||||
for part in parts {
|
||||
let snippet = if let Ok(snippet) = sm.span_to_snippet(part.span) {
|
||||
snippet
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
|
||||
let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display;
|
||||
|
||||
|
|
@ -2402,7 +2397,7 @@ impl HumanEmitter {
|
|||
// LL - REMOVED <- row_num - 2 - (newlines - first_i - 1)
|
||||
// LL + NEWER
|
||||
// | <- row_num
|
||||
|
||||
let snippet = sm.span_to_snippet(part.span).unwrap_or_default();
|
||||
let newlines = snippet.lines().count();
|
||||
if newlines > 0 && row_num > newlines {
|
||||
// Account for removals where the part being removed spans multiple
|
||||
|
|
@ -3108,7 +3103,7 @@ impl FileWithAnnotatedLines {
|
|||
) {
|
||||
for slot in file_vec.iter_mut() {
|
||||
// Look through each of our files for the one we're adding to
|
||||
if slot.file.name == file.name {
|
||||
if slot.file.stable_id == file.stable_id {
|
||||
// See if we already have a line for it
|
||||
for line_slot in &mut slot.lines {
|
||||
if line_slot.line_index == line_index {
|
||||
|
|
@ -3471,14 +3466,9 @@ impl Drop for Buffy {
|
|||
|
||||
pub fn stderr_destination(color: ColorConfig) -> Destination {
|
||||
let buffer_writer = std::io::stderr();
|
||||
let choice = color.to_color_choice();
|
||||
// We need to resolve `ColorChoice::Auto` before `Box`ing since
|
||||
// `ColorChoice::Auto` on `dyn Write` will always resolve to `Never`
|
||||
let choice = if matches!(choice, ColorChoice::Auto) {
|
||||
AutoStream::choice(&buffer_writer)
|
||||
} else {
|
||||
choice
|
||||
};
|
||||
let choice = get_stderr_color_choice(color, &buffer_writer);
|
||||
// On Windows we'll be performing global synchronization on the entire
|
||||
// system for emitting rustc errors, so there's no need to buffer
|
||||
// anything.
|
||||
|
|
@ -3493,6 +3483,11 @@ pub fn stderr_destination(color: ColorConfig) -> Destination {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_stderr_color_choice(color: ColorConfig, stderr: &std::io::Stderr) -> ColorChoice {
|
||||
let choice = color.to_color_choice();
|
||||
if matches!(choice, ColorChoice::Auto) { AutoStream::choice(stderr) } else { choice }
|
||||
}
|
||||
|
||||
/// On Windows, BRIGHT_BLUE is hard to read on black. Use cyan instead.
|
||||
///
|
||||
/// See #36178.
|
||||
|
|
|
|||
|
|
@ -886,9 +886,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
} else if let SyntaxExtensionKind::NonMacroAttr = ext {
|
||||
if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety {
|
||||
self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute");
|
||||
}
|
||||
// `-Zmacro-stats` ignores these because they don't do any real expansion.
|
||||
self.cx.expanded_inert_attrs.mark(&attr);
|
||||
item.visit_attrs(|attrs| attrs.insert(pos, attr));
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ impl server::Span for Rustc<'_, '_> {
|
|||
let self_loc = self.psess().source_map().lookup_char_pos(first.lo());
|
||||
let other_loc = self.psess().source_map().lookup_char_pos(second.lo());
|
||||
|
||||
if self_loc.file.name != other_loc.file.name {
|
||||
if self_loc.file.stable_id != other_loc.file.stable_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -410,6 +410,9 @@ declare_features! (
|
|||
(unstable, avx10_target_feature, "1.88.0", Some(138843)),
|
||||
/// Allows using C-variadics.
|
||||
(unstable, c_variadic, "1.34.0", Some(44930)),
|
||||
/// Allows defining c-variadic naked functions with any extern ABI that is allowed
|
||||
/// on c-variadic foreign functions.
|
||||
(unstable, c_variadic_naked_functions, "CURRENT_RUSTC_VERSION", Some(148767)),
|
||||
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
|
||||
(unstable, cfg_contract_checks, "1.86.0", Some(128044)),
|
||||
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
|
||||
|
|
|
|||
|
|
@ -194,6 +194,18 @@ pub enum CfgEntry {
|
|||
Version(Option<RustcVersion>, Span),
|
||||
}
|
||||
|
||||
impl CfgEntry {
|
||||
pub fn span(&self) -> Span {
|
||||
let (CfgEntry::All(_, span)
|
||||
| CfgEntry::Any(_, span)
|
||||
| CfgEntry::Not(_, span)
|
||||
| CfgEntry::Bool(_, span)
|
||||
| CfgEntry::NameValue { span, .. }
|
||||
| CfgEntry::Version(_, span)) = self;
|
||||
*span
|
||||
}
|
||||
}
|
||||
|
||||
/// Possible values for the `#[linkage]` attribute, allowing to specify the
|
||||
/// linkage type for a `MonoItem`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1722,7 +1722,9 @@ impl<'hir> Pat<'hir> {
|
|||
match self.kind {
|
||||
Missing => unreachable!(),
|
||||
Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
|
||||
Box(s) | Deref(s) | Ref(s, _, _) | Binding(.., Some(s)) | Guard(s, _) => {
|
||||
s.walk_short_(it)
|
||||
}
|
||||
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
|
|
@ -1749,7 +1751,7 @@ impl<'hir> Pat<'hir> {
|
|||
use PatKind::*;
|
||||
match self.kind {
|
||||
Missing | Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
|
||||
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||
Box(s) | Deref(s) | Ref(s, _, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
|
||||
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
|
||||
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
|
||||
Slice(before, slice, after) => {
|
||||
|
|
@ -1938,7 +1940,7 @@ pub enum PatKind<'hir> {
|
|||
Deref(&'hir Pat<'hir>),
|
||||
|
||||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(&'hir Pat<'hir>, Mutability),
|
||||
Ref(&'hir Pat<'hir>, Pinnedness, Mutability),
|
||||
|
||||
/// A literal, const block or path.
|
||||
Expr(&'hir PatExpr<'hir>),
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
|
|||
}
|
||||
PatKind::Box(ref subpattern)
|
||||
| PatKind::Deref(ref subpattern)
|
||||
| PatKind::Ref(ref subpattern, _) => {
|
||||
| PatKind::Ref(ref subpattern, _, _) => {
|
||||
try_visit!(visitor.visit_pat(subpattern));
|
||||
}
|
||||
PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ language_item_table! {
|
|||
Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None;
|
||||
CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||
UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None;
|
||||
TrivialClone, sym::trivial_clone, trivial_clone_trait, Target::Trait, GenericRequirement::None;
|
||||
Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||
DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None;
|
||||
/// The associated item of the `DiscriminantKind` trait.
|
||||
|
|
|
|||
|
|
@ -516,12 +516,10 @@ fn resolve_local<'tcx>(
|
|||
|
||||
if let Some(pat) = pat {
|
||||
if is_binding_pat(pat) {
|
||||
visitor.scope_tree.record_rvalue_candidate(
|
||||
expr.hir_id,
|
||||
RvalueCandidate {
|
||||
target: expr.hir_id.local_id,
|
||||
lifetime: visitor.cx.var_parent,
|
||||
},
|
||||
record_subexpr_extended_temp_scopes(
|
||||
&mut visitor.scope_tree,
|
||||
expr,
|
||||
visitor.cx.var_parent,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -593,7 +591,7 @@ fn resolve_local<'tcx>(
|
|||
is_binding_pat(subpat)
|
||||
}
|
||||
|
||||
PatKind::Ref(_, _)
|
||||
PatKind::Ref(_, _, _)
|
||||
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
|
||||
| PatKind::Missing
|
||||
| PatKind::Wild
|
||||
|
|
@ -604,7 +602,7 @@ fn resolve_local<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// If `expr` matches the `E&` grammar, then records an extended rvalue scope as appropriate:
|
||||
/// If `expr` matches the `E&` grammar, then records an extended temporary scope as appropriate:
|
||||
///
|
||||
/// ```text
|
||||
/// E& = & ET
|
||||
|
|
@ -627,10 +625,7 @@ fn resolve_local<'tcx>(
|
|||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(_, _, subexpr) => {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
|
||||
visitor.scope_tree.record_rvalue_candidate(
|
||||
subexpr.hir_id,
|
||||
RvalueCandidate { target: subexpr.hir_id.local_id, lifetime: blk_id },
|
||||
);
|
||||
record_subexpr_extended_temp_scopes(&mut visitor.scope_tree, subexpr, blk_id);
|
||||
}
|
||||
hir::ExprKind::Struct(_, fields, _) => {
|
||||
for field in fields {
|
||||
|
|
@ -687,6 +682,53 @@ fn resolve_local<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
|
||||
/// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
|
||||
/// case, the "temporary lifetime" of `expr` is extended to be the block enclosing the `let`
|
||||
/// statement.
|
||||
///
|
||||
/// More formally, if `expr` matches the grammar `ET`, record the temporary scope of the matching
|
||||
/// `<rvalue>` as `lifetime`:
|
||||
///
|
||||
/// ```text
|
||||
/// ET = *ET
|
||||
/// | ET[...]
|
||||
/// | ET.f
|
||||
/// | (ET)
|
||||
/// | <rvalue>
|
||||
/// ```
|
||||
///
|
||||
/// Note: ET is intended to match "rvalues or places based on rvalues".
|
||||
fn record_subexpr_extended_temp_scopes(
|
||||
scope_tree: &mut ScopeTree,
|
||||
mut expr: &hir::Expr<'_>,
|
||||
lifetime: Option<Scope>,
|
||||
) {
|
||||
debug!(?expr, ?lifetime);
|
||||
|
||||
loop {
|
||||
// Note: give all the expressions matching `ET` with the
|
||||
// extended temporary lifetime, not just the innermost rvalue,
|
||||
// because in MIR building if we must compile e.g., `*rvalue()`
|
||||
// into a temporary, we request the temporary scope of the
|
||||
// outer expression.
|
||||
|
||||
scope_tree.record_extended_temp_scope(expr.hir_id.local_id, lifetime);
|
||||
|
||||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(_, _, subexpr)
|
||||
| hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
|
||||
| hir::ExprKind::Field(subexpr, _)
|
||||
| hir::ExprKind::Index(subexpr, _, _) => {
|
||||
expr = subexpr;
|
||||
}
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ScopeResolutionVisitor<'tcx> {
|
||||
/// Records the current parent (if any) as the parent of `child_scope`.
|
||||
fn record_child_scope(&mut self, child_scope: Scope) {
|
||||
|
|
|
|||
|
|
@ -1487,11 +1487,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
match assoc_tag {
|
||||
// Don't attempt to look up inherent associated types when the feature is not
|
||||
// enabled. Theoretically it'd be fine to do so since we feature-gate their
|
||||
// definition site. However, due to current limitations of the implementation
|
||||
// (caused by us performing selection during HIR ty lowering instead of in the
|
||||
// trait solver), IATs can lead to cycle errors (#108491) which mask the
|
||||
// feature-gate error, needlessly confusing users who use IATs by accident
|
||||
// (#113265).
|
||||
// definition site. However, the current implementation of inherent associated
|
||||
// items is somewhat brittle, so let's not run it by default.
|
||||
ty::AssocTag::Type => return Ok(None),
|
||||
ty::AssocTag::Const => {
|
||||
// We also gate the mgca codepath for type-level uses of inherent consts
|
||||
|
|
@ -1520,9 +1517,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
})
|
||||
.collect();
|
||||
|
||||
// At the moment, we actually bail out with a hard error if the selection of an inherent
|
||||
// associated item fails (see below). This means we never consider trait associated items
|
||||
// as potential fallback candidates (#142006). To temporarily mask that issue, let's not
|
||||
// select at all if there are no early inherent candidates.
|
||||
if candidates.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let (applicable_candidates, fulfillment_errors) =
|
||||
self.select_inherent_assoc_candidates(span, self_ty, candidates.clone());
|
||||
|
||||
// FIXME(#142006): Don't eagerly error here, there might be applicable trait candidates.
|
||||
let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } =
|
||||
match &applicable_candidates[..] {
|
||||
&[] => Err(self.report_unresolved_inherent_assoc_item(
|
||||
|
|
@ -1543,6 +1549,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
)),
|
||||
}?;
|
||||
|
||||
// FIXME(#142006): Don't eagerly validate here, there might be trait candidates that are
|
||||
// accessible (visible and stable) contrary to the inherent candidate.
|
||||
self.check_assoc_item(assoc_item, name, def_scope, block, span);
|
||||
|
||||
// FIXME(fmease): Currently creating throwaway `parent_args` to please
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ impl<'a> fmt::Debug for VarianceTerm<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The first pass over the crate simply builds up the set of inferreds.
|
||||
// The first pass over the crate simply builds up the set of inferreds.
|
||||
|
||||
pub(crate) struct TermsContext<'a, 'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
|
|
|
|||
|
|
@ -2028,9 +2028,15 @@ impl<'a> State<'a> {
|
|||
self.print_pat(inner);
|
||||
self.pclose();
|
||||
}
|
||||
PatKind::Ref(inner, mutbl) => {
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
let is_range_inner = matches!(inner.kind, PatKind::Range(..));
|
||||
self.word("&");
|
||||
if pinned.is_pinned() {
|
||||
self.word("pin ");
|
||||
if mutbl.is_not() {
|
||||
self.word("const ");
|
||||
}
|
||||
}
|
||||
self.word(mutbl.prefix_str());
|
||||
if is_range_inner {
|
||||
self.popen();
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
| hir::PatKind::TupleStruct(_, _, _)
|
||||
| hir::PatKind::Tuple(_, _)
|
||||
| hir::PatKind::Box(_)
|
||||
| hir::PatKind::Ref(_, _)
|
||||
| hir::PatKind::Ref(_, _, _)
|
||||
| hir::PatKind::Deref(_)
|
||||
| hir::PatKind::Expr(_)
|
||||
| hir::PatKind::Range(_, _, _)
|
||||
|
|
|
|||
|
|
@ -1231,7 +1231,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
|
||||
return Ok(first_adjust.source);
|
||||
}
|
||||
} else if let PatKind::Ref(subpat, _) = pat.kind
|
||||
} else if let PatKind::Ref(subpat, _, _) = pat.kind
|
||||
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
|
||||
{
|
||||
return self.pat_ty_adjusted(subpat);
|
||||
|
|
@ -1817,13 +1817,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
self.cat_pattern(place_with_id, subpat, op)?;
|
||||
}
|
||||
|
||||
PatKind::Ref(subpat, _)
|
||||
PatKind::Ref(subpat, _, _)
|
||||
if self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) =>
|
||||
{
|
||||
self.cat_pattern(place_with_id, subpat, op)?;
|
||||
}
|
||||
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
|
||||
PatKind::Box(subpat) | PatKind::Ref(subpat, _, _) => {
|
||||
// box p1, &p1, &mut p1. we can ignore the mutability of
|
||||
// PatKind::Ref since that information is already contained
|
||||
// in the type.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ use tracing::{debug, instrument};
|
|||
use crate::callee::{self, DeferredCallResolution};
|
||||
use crate::errors::{self, CtorIsPrivate};
|
||||
use crate::method::{self, MethodCallee};
|
||||
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, rvalue_scopes};
|
||||
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Produces warning on the given node, if the current point in the
|
||||
|
|
@ -604,13 +604,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.normalize(span, field.ty(self.tcx, args))
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_rvalue_scopes(&self, def_id: DefId) {
|
||||
let scope_tree = self.tcx.region_scope_tree(def_id);
|
||||
let rvalue_scopes = { rvalue_scopes::resolve_rvalue_scopes(self, scope_tree, def_id) };
|
||||
let mut typeck_results = self.typeck_results.borrow_mut();
|
||||
typeck_results.rvalue_scopes = rvalue_scopes;
|
||||
}
|
||||
|
||||
/// Drain all obligations that are stalled on coroutines defined in this body.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(crate) fn drain_stalled_coroutine_obligations(&self) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ mod op;
|
|||
mod opaque_types;
|
||||
mod pat;
|
||||
mod place_op;
|
||||
mod rvalue_scopes;
|
||||
mod typeck_root_ctxt;
|
||||
mod upvar;
|
||||
mod writeback;
|
||||
|
|
@ -237,9 +236,6 @@ fn typeck_with_inspect<'tcx>(
|
|||
// because they don't constrain other type variables.
|
||||
fcx.closure_analyze(body);
|
||||
assert!(fcx.deferred_call_resolutions.borrow().is_empty());
|
||||
// Before the coroutine analysis, temporary scopes shall be marked to provide more
|
||||
// precise information on types to be captured.
|
||||
fcx.resolve_rvalue_scopes(def_id.to_def_id());
|
||||
|
||||
for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) {
|
||||
let ty = fcx.normalize(span, ty);
|
||||
|
|
|
|||
|
|
@ -1079,6 +1079,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_ident, expected);
|
||||
self.suggest_bounds_for_range_to_method(&mut err, source, item_ident);
|
||||
err.emit()
|
||||
}
|
||||
|
||||
|
|
@ -2610,7 +2611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut current_node = parent_node;
|
||||
|
||||
while let Node::Pat(parent_pat) = current_node {
|
||||
if let hir::PatKind::Ref(_, mutability) = parent_pat.kind {
|
||||
if let hir::PatKind::Ref(_, _, mutability) = parent_pat.kind {
|
||||
ref_muts.push(mutability);
|
||||
current_node = self.tcx.parent_hir_node(parent_pat.hir_id);
|
||||
} else {
|
||||
|
|
@ -3260,6 +3261,71 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn suggest_bounds_for_range_to_method(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
source: SelfSource<'tcx>,
|
||||
item_ident: Ident,
|
||||
) {
|
||||
let SelfSource::MethodCall(rcvr_expr) = source else { return };
|
||||
let hir::ExprKind::Struct(qpath, fields, _) = rcvr_expr.kind else { return };
|
||||
let Some(lang_item) = self.tcx.qpath_lang_item(*qpath) else {
|
||||
return;
|
||||
};
|
||||
let is_inclusive = match lang_item {
|
||||
hir::LangItem::RangeTo => false,
|
||||
hir::LangItem::RangeToInclusive | hir::LangItem::RangeInclusiveCopy => true,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) else { return };
|
||||
let Some(_) = self
|
||||
.tcx
|
||||
.associated_items(iterator_trait)
|
||||
.filter_by_name_unhygienic(item_ident.name)
|
||||
.next()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let range_type = if is_inclusive { "RangeInclusive" } else { "Range" };
|
||||
let Some(end_field) = fields.iter().find(|f| f.ident.name == rustc_span::sym::end) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let element_ty = self.typeck_results.borrow().expr_ty_opt(end_field.expr);
|
||||
let is_integral = element_ty.is_some_and(|ty| ty.is_integral());
|
||||
let end_is_negative = is_integral
|
||||
&& matches!(end_field.expr.kind, hir::ExprKind::Unary(rustc_ast::UnOp::Neg, _));
|
||||
|
||||
let Ok(snippet) = source_map.span_to_snippet(rcvr_expr.span) else { return };
|
||||
|
||||
let offset = snippet
|
||||
.chars()
|
||||
.take_while(|&c| c == '(' || c.is_whitespace())
|
||||
.map(|c| c.len_utf8())
|
||||
.sum::<usize>();
|
||||
|
||||
let insert_span = rcvr_expr
|
||||
.span
|
||||
.with_lo(rcvr_expr.span.lo() + rustc_span::BytePos(offset as u32))
|
||||
.shrink_to_lo();
|
||||
|
||||
let (value, appl) = if is_integral && !end_is_negative {
|
||||
("0", Applicability::MachineApplicable)
|
||||
} else {
|
||||
("/* start */", Applicability::HasPlaceholders)
|
||||
};
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
insert_span,
|
||||
format!("consider using a bounded `{range_type}` by adding a concrete starting value"),
|
||||
value,
|
||||
appl,
|
||||
);
|
||||
}
|
||||
|
||||
/// Print out the type for use in value namespace.
|
||||
fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String {
|
||||
match ty.kind() {
|
||||
|
|
@ -4212,7 +4278,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err: &mut Diag<'_>,
|
||||
item_def_id: DefId,
|
||||
hir_id: hir::HirId,
|
||||
rcvr_ty: Option<Ty<'_>>,
|
||||
rcvr_ty: Option<Ty<'tcx>>,
|
||||
) -> bool {
|
||||
let hir_id = self.tcx.parent_hir_id(hir_id);
|
||||
let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false };
|
||||
|
|
@ -4223,49 +4289,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if !self.tcx.is_trait(trait_def_id) {
|
||||
return false;
|
||||
}
|
||||
let krate = self.tcx.crate_name(trait_def_id.krate);
|
||||
let name = self.tcx.item_name(trait_def_id);
|
||||
let candidates: Vec<_> = traits
|
||||
.iter()
|
||||
.filter(|c| {
|
||||
c.def_id.krate != trait_def_id.krate
|
||||
&& self.tcx.crate_name(c.def_id.krate) == krate
|
||||
&& self.tcx.item_name(c.def_id) == name
|
||||
})
|
||||
.map(|c| (c.def_id, c.import_ids.get(0).cloned()))
|
||||
.collect();
|
||||
if candidates.is_empty() {
|
||||
let hir::Node::Expr(rcvr) = self.tcx.hir_node(hir_id) else {
|
||||
return false;
|
||||
}
|
||||
let item_span = self.tcx.def_span(item_def_id);
|
||||
let msg = format!(
|
||||
"there are multiple different versions of crate `{krate}` in the dependency graph",
|
||||
);
|
||||
let trait_span = self.tcx.def_span(trait_def_id);
|
||||
let mut multi_span: MultiSpan = trait_span.into();
|
||||
multi_span.push_span_label(trait_span, "this is the trait that is needed".to_string());
|
||||
let descr = self.tcx.associated_item(item_def_id).descr();
|
||||
let rcvr_ty =
|
||||
rcvr_ty.map(|t| format!("`{t}`")).unwrap_or_else(|| "the receiver".to_string());
|
||||
multi_span
|
||||
.push_span_label(item_span, format!("the {descr} is available for {rcvr_ty} here"));
|
||||
for (def_id, import_def_id) in candidates {
|
||||
if let Some(import_def_id) = import_def_id {
|
||||
multi_span.push_span_label(
|
||||
self.tcx.def_span(import_def_id),
|
||||
format!(
|
||||
"`{name}` imported here doesn't correspond to the right version of crate \
|
||||
`{krate}`",
|
||||
),
|
||||
);
|
||||
}
|
||||
multi_span.push_span_label(
|
||||
self.tcx.def_span(def_id),
|
||||
"this is the trait that was imported".to_string(),
|
||||
);
|
||||
}
|
||||
err.span_note(multi_span, msg);
|
||||
true
|
||||
};
|
||||
let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, rcvr_ty.into_iter());
|
||||
let trait_pred = ty::Binder::dummy(ty::TraitPredicate {
|
||||
trait_ref,
|
||||
polarity: ty::PredicatePolarity::Positive,
|
||||
});
|
||||
let obligation = Obligation::new(self.tcx, self.misc(rcvr.span), self.param_env, trait_ref);
|
||||
self.err_ctxt().note_different_trait_with_same_name(err, &obligation, trait_pred)
|
||||
}
|
||||
|
||||
/// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ struct TopInfo<'tcx> {
|
|||
#[derive(Copy, Clone)]
|
||||
struct PatInfo<'tcx> {
|
||||
binding_mode: ByRef,
|
||||
max_pinnedness: PinnednessCap,
|
||||
max_ref_mutbl: MutblCap,
|
||||
top_info: TopInfo<'tcx>,
|
||||
decl_origin: Option<DeclOrigin<'tcx>>,
|
||||
|
|
@ -241,6 +242,19 @@ impl MutblCap {
|
|||
}
|
||||
}
|
||||
|
||||
/// `ref` or `ref mut` bindings (not pinned, explicitly or match-ergonomics) are only allowed behind
|
||||
/// an `&pin` reference if the binding's type is `Unpin`.
|
||||
///
|
||||
/// Normally, the borrow checker enforces this (not implemented yet), but we track it here for better
|
||||
/// diagnostics.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum PinnednessCap {
|
||||
/// No restriction on pinnedness.
|
||||
Not,
|
||||
/// Pinnedness restricted to pinned.
|
||||
Pinned,
|
||||
}
|
||||
|
||||
/// Variations on RFC 3627's Rule 4: when do reference patterns match against inherited references?
|
||||
///
|
||||
/// "Inherited reference" designates the `&`/`&mut` types that arise from using match ergonomics, i.e.
|
||||
|
|
@ -374,6 +388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
|
||||
let pat_info = PatInfo {
|
||||
binding_mode: ByRef::No,
|
||||
max_pinnedness: PinnednessCap::Not,
|
||||
max_ref_mutbl: MutblCap::Mut,
|
||||
top_info,
|
||||
decl_origin,
|
||||
|
|
@ -489,22 +504,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let old_pat_info = pat_info;
|
||||
let pat_info = PatInfo { current_depth: old_pat_info.current_depth + 1, ..old_pat_info };
|
||||
|
||||
let adjust_binding_mode = |inner_pinnedness, inner_mutability| {
|
||||
match pat_info.binding_mode {
|
||||
// If default binding mode is by value, make it `ref`, `ref mut`, `ref pin const`
|
||||
// or `ref pin mut` (depending on whether we observe `&`, `&mut`, `&pin const` or
|
||||
// `&pin mut`).
|
||||
ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
|
||||
// Pinnedness is preserved.
|
||||
ByRef::Yes(pinnedness, Mutability::Mut) => ByRef::Yes(pinnedness, inner_mutability),
|
||||
// Once a `ref`, always a `ref`.
|
||||
// This is because a `& &mut` cannot mutate the underlying value.
|
||||
// Pinnedness is preserved.
|
||||
ByRef::Yes(pinnedness, Mutability::Not) => ByRef::Yes(pinnedness, Mutability::Not),
|
||||
}
|
||||
};
|
||||
|
||||
match pat.kind {
|
||||
// Peel off a `&` or `&mut`from the scrutinee type. See the examples in
|
||||
// `tests/ui/rfcs/rfc-2005-default-binding-mode`.
|
||||
|
|
@ -524,19 +523,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.or_default()
|
||||
.push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
|
||||
|
||||
let mut binding_mode = adjust_binding_mode(Pinnedness::Not, inner_mutability);
|
||||
|
||||
let mut max_ref_mutbl = pat_info.max_ref_mutbl;
|
||||
if self.downgrade_mut_inside_shared() {
|
||||
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
|
||||
}
|
||||
if matches!(binding_mode, ByRef::Yes(_, Mutability::Not)) {
|
||||
max_ref_mutbl = MutblCap::Not;
|
||||
}
|
||||
debug!("default binding mode is now {:?}", binding_mode);
|
||||
|
||||
// Use the old pat info to keep `current_depth` to its old value.
|
||||
let new_pat_info = PatInfo { binding_mode, max_ref_mutbl, ..old_pat_info };
|
||||
let new_pat_info =
|
||||
self.adjust_pat_info(Pinnedness::Not, inner_mutability, old_pat_info);
|
||||
|
||||
// Recurse with the new expected type.
|
||||
self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
|
||||
}
|
||||
|
|
@ -569,20 +559,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
});
|
||||
}
|
||||
|
||||
let binding_mode = adjust_binding_mode(Pinnedness::Pinned, inner_mutability);
|
||||
// If the pinnedness is `Not`, it means the pattern is unpinned
|
||||
// and thus requires an `Unpin` bound.
|
||||
if matches!(binding_mode, ByRef::Yes(Pinnedness::Not, _)) {
|
||||
self.register_bound(
|
||||
inner_ty,
|
||||
self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
|
||||
self.misc(pat.span),
|
||||
)
|
||||
}
|
||||
debug!("default binding mode is now {:?}", binding_mode);
|
||||
|
||||
// Use the old pat info to keep `current_depth` to its old value.
|
||||
let new_pat_info = PatInfo { binding_mode, ..old_pat_info };
|
||||
let new_pat_info =
|
||||
self.adjust_pat_info(Pinnedness::Pinned, inner_mutability, old_pat_info);
|
||||
|
||||
self.check_deref_pattern(
|
||||
pat,
|
||||
|
|
@ -689,13 +668,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
|
||||
PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
|
||||
PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
|
||||
PatKind::Ref(inner, pinned, mutbl) => {
|
||||
self.check_pat_ref(pat, inner, pinned, mutbl, expected, pat_info)
|
||||
}
|
||||
PatKind::Slice(before, slice, after) => {
|
||||
self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn adjust_pat_info(
|
||||
&self,
|
||||
inner_pinnedness: Pinnedness,
|
||||
inner_mutability: Mutability,
|
||||
pat_info: PatInfo<'tcx>,
|
||||
) -> PatInfo<'tcx> {
|
||||
let mut binding_mode = match pat_info.binding_mode {
|
||||
// If default binding mode is by value, make it `ref`, `ref mut`, `ref pin const`
|
||||
// or `ref pin mut` (depending on whether we observe `&`, `&mut`, `&pin const` or
|
||||
// `&pin mut`).
|
||||
ByRef::No => ByRef::Yes(inner_pinnedness, inner_mutability),
|
||||
ByRef::Yes(pinnedness, mutability) => {
|
||||
let pinnedness = match pinnedness {
|
||||
// When `ref`, stay a `ref` (on `&`) or downgrade to `ref pin` (on `&pin`).
|
||||
Pinnedness::Not => inner_pinnedness,
|
||||
// When `ref pin`, stay a `ref pin`.
|
||||
// This is because we cannot get an `&mut T` from `&mut &pin mut T` unless `T: Unpin`.
|
||||
// Note that `&T` and `&mut T` are `Unpin`, which implies
|
||||
// `& &pin const T` <-> `&pin const &T` and `&mut &pin mut T` <-> `&pin mut &mut T`
|
||||
// (i.e. mutually coercible).
|
||||
Pinnedness::Pinned => Pinnedness::Pinned,
|
||||
};
|
||||
|
||||
let mutability = match mutability {
|
||||
// When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
|
||||
Mutability::Mut => inner_mutability,
|
||||
// Once a `ref`, always a `ref`.
|
||||
// This is because a `& &mut` cannot mutate the underlying value.
|
||||
Mutability::Not => Mutability::Not,
|
||||
};
|
||||
ByRef::Yes(pinnedness, mutability)
|
||||
}
|
||||
};
|
||||
|
||||
let PatInfo { mut max_ref_mutbl, mut max_pinnedness, .. } = pat_info;
|
||||
if self.downgrade_mut_inside_shared() {
|
||||
binding_mode = binding_mode.cap_ref_mutability(max_ref_mutbl.as_mutbl());
|
||||
}
|
||||
match binding_mode {
|
||||
ByRef::Yes(_, Mutability::Not) => max_ref_mutbl = MutblCap::Not,
|
||||
ByRef::Yes(Pinnedness::Pinned, _) => max_pinnedness = PinnednessCap::Pinned,
|
||||
_ => {}
|
||||
}
|
||||
debug!("default binding mode is now {:?}", binding_mode);
|
||||
PatInfo { binding_mode, max_pinnedness, max_ref_mutbl, ..pat_info }
|
||||
}
|
||||
|
||||
fn check_deref_pattern(
|
||||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
|
|
@ -1195,6 +1223,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// If there exists a pinned reference in the pattern but the binding is not pinned,
|
||||
// it means the binding is unpinned and thus requires an `Unpin` bound.
|
||||
if pat_info.max_pinnedness == PinnednessCap::Pinned
|
||||
&& matches!(bm.0, ByRef::Yes(Pinnedness::Not, _))
|
||||
{
|
||||
self.register_bound(
|
||||
expected,
|
||||
self.tcx.require_lang_item(hir::LangItem::Unpin, pat.span),
|
||||
self.misc(pat.span),
|
||||
)
|
||||
}
|
||||
|
||||
if matches!(bm.0, ByRef::Yes(_, Mutability::Mut))
|
||||
&& let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
|
||||
{
|
||||
|
|
@ -1223,22 +1263,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let local_ty = self.local_ty(pat.span, pat.hir_id);
|
||||
let eq_ty = match bm.0 {
|
||||
ByRef::Yes(Pinnedness::Not, mutbl) => {
|
||||
ByRef::Yes(pinnedness, mutbl) => {
|
||||
// If the binding is like `ref x | ref mut x`,
|
||||
// then `x` is assigned a value of type `&M T` where M is the
|
||||
// mutability and T is the expected type.
|
||||
//
|
||||
// Under pin ergonomics, if the binding is like `ref pin const|mut x`,
|
||||
// then `x` is assigned a value of type `&pin M T` where M is the
|
||||
// mutability and T is the expected type.
|
||||
//
|
||||
// `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)`
|
||||
// is required. However, we use equality, which is stronger.
|
||||
// See (note_1) for an explanation.
|
||||
self.new_ref_ty(pat.span, mutbl, expected)
|
||||
self.new_ref_ty(pat.span, pinnedness, mutbl, expected)
|
||||
}
|
||||
// Wrapping the type into `Pin` if the binding is like `ref pin const|mut x`
|
||||
ByRef::Yes(Pinnedness::Pinned, mutbl) => Ty::new_adt(
|
||||
self.tcx,
|
||||
self.tcx.adt_def(self.tcx.require_lang_item(hir::LangItem::Pin, pat.span)),
|
||||
self.tcx.mk_args(&[self.new_ref_ty(pat.span, mutbl, expected).into()]),
|
||||
),
|
||||
// Otherwise, the type of x is the expected type `T`.
|
||||
ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
|
||||
};
|
||||
|
|
@ -1331,18 +1369,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Precondition: pat is a `Ref(_)` pattern
|
||||
// FIXME(pin_ergonomics): add suggestions for `&pin mut` or `&pin const` patterns
|
||||
fn borrow_pat_suggestion(&self, err: &mut Diag<'_>, pat: &Pat<'_>) {
|
||||
let tcx = self.tcx;
|
||||
if let PatKind::Ref(inner, mutbl) = pat.kind
|
||||
if let PatKind::Ref(inner, pinned, mutbl) = pat.kind
|
||||
&& let PatKind::Binding(_, _, binding, ..) = inner.kind
|
||||
{
|
||||
let binding_parent = tcx.parent_hir_node(pat.hir_id);
|
||||
debug!(?inner, ?pat, ?binding_parent);
|
||||
|
||||
let mutability = match mutbl {
|
||||
ast::Mutability::Mut => "mut",
|
||||
ast::Mutability::Not => "",
|
||||
};
|
||||
let pin_and_mut = pinned.prefix_str(mutbl).trim_end();
|
||||
|
||||
let mut_var_suggestion = 'block: {
|
||||
if mutbl.is_not() {
|
||||
|
|
@ -1392,7 +1428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// so we don't suggest moving something to the type that does not exist
|
||||
hir::Node::Param(hir::Param { ty_span, pat, .. }) if pat.span != *ty_span => {
|
||||
err.multipart_suggestion_verbose(
|
||||
format!("to take parameter `{binding}` by reference, move `&{mutability}` to the type"),
|
||||
format!("to take parameter `{binding}` by reference, move `&{pin_and_mut}` to the type"),
|
||||
vec![
|
||||
(pat.span.until(inner.span), "".to_owned()),
|
||||
(ty_span.shrink_to_lo(), mutbl.ref_prefix_str().to_owned()),
|
||||
|
|
@ -1406,13 +1442,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => {
|
||||
for i in pat_arr.iter() {
|
||||
if let PatKind::Ref(the_ref, _) = i.kind
|
||||
if let PatKind::Ref(the_ref, _, _) = i.kind
|
||||
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind
|
||||
{
|
||||
let BindingMode(_, mtblty) = mt;
|
||||
err.span_suggestion_verbose(
|
||||
i.span,
|
||||
format!("consider removing `&{mutability}` from the pattern"),
|
||||
format!("consider removing `&{pin_and_mut}` from the pattern"),
|
||||
mtblty.prefix_str().to_string() + &ident.name.to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -1426,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// rely on match ergonomics or it might be nested `&&pat`
|
||||
err.span_suggestion_verbose(
|
||||
pat.span.until(inner.span),
|
||||
format!("consider removing `&{mutability}` from the pattern"),
|
||||
format!("consider removing `&{pin_and_mut}` from the pattern"),
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
@ -2677,6 +2713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
&self,
|
||||
pat: &'tcx Pat<'tcx>,
|
||||
inner: &'tcx Pat<'tcx>,
|
||||
pat_pinned: Pinnedness,
|
||||
pat_mutbl: Mutability,
|
||||
mut expected: Ty<'tcx>,
|
||||
mut pat_info: PatInfo<'tcx>,
|
||||
|
|
@ -2699,9 +2736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Determine whether we're consuming an inherited reference and resetting the default
|
||||
// binding mode, based on edition and enabled experimental features.
|
||||
if let ByRef::Yes(inh_pin, inh_mut) = pat_info.binding_mode
|
||||
// FIXME(pin_ergonomics): since `&pin` pattern is supported, the condition here
|
||||
// should be adjusted to `pat_pin == inh_pin`
|
||||
&& (!self.tcx.features().pin_ergonomics() || inh_pin == Pinnedness::Not)
|
||||
&& pat_pinned == inh_pin
|
||||
{
|
||||
match self.ref_pat_matches_inherited_ref(pat.span.edition()) {
|
||||
InheritedRefMatchRule::EatOuter => {
|
||||
|
|
@ -2821,21 +2856,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// to avoid creating needless variables. This also helps with
|
||||
// the bad interactions of the given hack detailed in (note_1).
|
||||
debug!("check_pat_ref: expected={:?}", expected);
|
||||
match *expected.kind() {
|
||||
ty::Ref(_, r_ty, r_mutbl)
|
||||
if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
|
||||
|| r_mutbl == pat_mutbl =>
|
||||
match expected.maybe_pinned_ref() {
|
||||
Some((r_ty, r_pinned, r_mutbl))
|
||||
if ((ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl)
|
||||
|| r_mutbl == pat_mutbl)
|
||||
&& pat_pinned == r_pinned =>
|
||||
{
|
||||
if r_mutbl == Mutability::Not {
|
||||
pat_info.max_ref_mutbl = MutblCap::Not;
|
||||
}
|
||||
if r_pinned == Pinnedness::Pinned {
|
||||
pat_info.max_pinnedness = PinnednessCap::Pinned;
|
||||
}
|
||||
|
||||
(expected, r_ty)
|
||||
}
|
||||
|
||||
_ => {
|
||||
let inner_ty = self.next_ty_var(inner.span);
|
||||
let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
|
||||
let ref_ty = self.new_ref_ty(pat.span, pat_pinned, pat_mutbl, inner_ty);
|
||||
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
||||
let err = self.demand_eqtype_pat_diag(
|
||||
pat.span,
|
||||
|
|
@ -2864,10 +2902,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ref_ty
|
||||
}
|
||||
|
||||
/// Create a reference type with a fresh region variable.
|
||||
fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
/// Create a reference or pinned reference type with a fresh region variable.
|
||||
fn new_ref_ty(
|
||||
&self,
|
||||
span: Span,
|
||||
pinnedness: Pinnedness,
|
||||
mutbl: Mutability,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let region = self.next_region_var(RegionVariableOrigin::PatternRegion(span));
|
||||
Ty::new_ref(self.tcx, region, ty, mutbl)
|
||||
let ref_ty = Ty::new_ref(self.tcx, region, ty, mutbl);
|
||||
if pinnedness.is_pinned() {
|
||||
return self.new_pinned_ty(span, ref_ty);
|
||||
}
|
||||
ref_ty
|
||||
}
|
||||
|
||||
/// Create a pinned type.
|
||||
fn new_pinned_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
Ty::new_adt(
|
||||
self.tcx,
|
||||
self.tcx.adt_def(self.tcx.require_lang_item(LangItem::Pin, span)),
|
||||
self.tcx.mk_args(&[ty.into()]),
|
||||
)
|
||||
}
|
||||
|
||||
fn error_inherited_ref_mutability_mismatch(
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
use hir::Node;
|
||||
use hir::def_id::DefId;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::region::{RvalueCandidate, Scope, ScopeTree};
|
||||
use rustc_middle::ty::RvalueScopes;
|
||||
use tracing::debug;
|
||||
|
||||
use super::FnCtxt;
|
||||
|
||||
/// Applied to an expression `expr` if `expr` -- or something owned or partially owned by
|
||||
/// `expr` -- is going to be indirectly referenced by a variable in a let statement. In that
|
||||
/// case, the "temporary lifetime" or `expr` is extended to be the block enclosing the `let`
|
||||
/// statement.
|
||||
///
|
||||
/// More formally, if `expr` matches the grammar `ET`, record the rvalue scope of the matching
|
||||
/// `<rvalue>` as `blk_id`:
|
||||
///
|
||||
/// ```text
|
||||
/// ET = *ET
|
||||
/// | ET[...]
|
||||
/// | ET.f
|
||||
/// | (ET)
|
||||
/// | <rvalue>
|
||||
/// ```
|
||||
///
|
||||
/// Note: ET is intended to match "rvalues or places based on rvalues".
|
||||
fn record_rvalue_scope_rec(
|
||||
rvalue_scopes: &mut RvalueScopes,
|
||||
mut expr: &hir::Expr<'_>,
|
||||
lifetime: Option<Scope>,
|
||||
) {
|
||||
loop {
|
||||
// Note: give all the expressions matching `ET` with the
|
||||
// extended temporary lifetime, not just the innermost rvalue,
|
||||
// because in codegen if we must compile e.g., `*rvalue()`
|
||||
// into a temporary, we request the temporary scope of the
|
||||
// outer expression.
|
||||
|
||||
rvalue_scopes.record_rvalue_scope(expr.hir_id.local_id, lifetime);
|
||||
|
||||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(_, _, subexpr)
|
||||
| hir::ExprKind::Unary(hir::UnOp::Deref, subexpr)
|
||||
| hir::ExprKind::Field(subexpr, _)
|
||||
| hir::ExprKind::Index(subexpr, _, _) => {
|
||||
expr = subexpr;
|
||||
}
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn record_rvalue_scope(
|
||||
rvalue_scopes: &mut RvalueScopes,
|
||||
expr: &hir::Expr<'_>,
|
||||
candidate: &RvalueCandidate,
|
||||
) {
|
||||
debug!("resolve_rvalue_scope(expr={expr:?}, candidate={candidate:?})");
|
||||
record_rvalue_scope_rec(rvalue_scopes, expr, candidate.lifetime)
|
||||
// FIXME(@dingxiangfei2009): handle the candidates in the function call arguments
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_rvalue_scopes<'a, 'tcx>(
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
scope_tree: &'a ScopeTree,
|
||||
def_id: DefId,
|
||||
) -> RvalueScopes {
|
||||
let tcx = &fcx.tcx;
|
||||
let mut rvalue_scopes = RvalueScopes::new();
|
||||
debug!("start resolving rvalue scopes, def_id={def_id:?}");
|
||||
debug!("rvalue_scope: rvalue_candidates={:?}", scope_tree.rvalue_candidates);
|
||||
for (&hir_id, candidate) in &scope_tree.rvalue_candidates {
|
||||
let Node::Expr(expr) = tcx.hir_node(hir_id) else { bug!("hir node does not exist") };
|
||||
record_rvalue_scope(&mut rvalue_scopes, expr, candidate);
|
||||
}
|
||||
rvalue_scopes
|
||||
}
|
||||
|
|
@ -79,9 +79,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
wbcx.visit_offset_of_container_types();
|
||||
wbcx.visit_potentially_region_dependent_goals();
|
||||
|
||||
wbcx.typeck_results.rvalue_scopes =
|
||||
mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
|
||||
|
||||
let used_trait_imports =
|
||||
mem::take(&mut self.typeck_results.borrow_mut().used_trait_imports);
|
||||
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
|
||||
|
|
|
|||
|
|
@ -265,6 +265,9 @@ lint_forgetting_copy_types = calls to `std::mem::forget` with a value that imple
|
|||
lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing
|
||||
.label = argument has type `{$arg_ty}`
|
||||
|
||||
lint_function_casts_as_integer = direct cast of function item into an integer
|
||||
.cast_as_fn = first cast to a pointer `as *const ()`
|
||||
|
||||
lint_hidden_glob_reexport = private item shadows public glob re-export
|
||||
.note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here
|
||||
.note_private_item = but the private item here shadows it
|
||||
|
|
|
|||
|
|
@ -1705,7 +1705,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
|
|||
}
|
||||
|
||||
let (parentheses, endpoints) = match &pat.kind {
|
||||
PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(subpat)),
|
||||
PatKind::Ref(subpat, _, _) => (true, matches_ellipsis_pat(subpat)),
|
||||
_ => (false, matches_ellipsis_pat(pat)),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//! syntactical lints.
|
||||
|
||||
use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
|
||||
use rustc_ast::{self as ast, HasAttrs};
|
||||
use rustc_ast::{self as ast, AttrVec, HasAttrs};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
|
||||
use rustc_feature::Features;
|
||||
|
|
@ -135,7 +135,7 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, span: Span, id: ast::NodeId) {
|
||||
fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, _: &AttrVec, span: Span, id: ast::NodeId) {
|
||||
lint_callback!(self, check_fn, fk, span, id);
|
||||
ast_visit::walk_fn(self, fk);
|
||||
}
|
||||
|
|
|
|||
63
compiler/rustc_lint/src/function_cast_as_integer.rs
Normal file
63
compiler/rustc_lint/src/function_cast_as_integer.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::BytePos;
|
||||
|
||||
use crate::lints::{FunctionCastsAsIntegerDiag, FunctionCastsAsIntegerSugg};
|
||||
use crate::{LateContext, LateLintPass};
|
||||
|
||||
declare_lint! {
|
||||
/// The `function_casts_as_integer` lint detects cases where a function item is cast
|
||||
/// to an integer.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// fn foo() {}
|
||||
/// let x = foo as usize;
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// When casting a function item to an integer, it implicitly creates a
|
||||
/// function pointer that will in turn be cast to an integer. By making
|
||||
/// it explicit, it improves readability of the code and prevents bugs.
|
||||
pub FUNCTION_CASTS_AS_INTEGER,
|
||||
Warn,
|
||||
"casting a function into an integer",
|
||||
}
|
||||
|
||||
declare_lint_pass!(
|
||||
/// Lint for casts of functions into integers.
|
||||
FunctionCastsAsInteger => [FUNCTION_CASTS_AS_INTEGER]
|
||||
);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for FunctionCastsAsInteger {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
let hir::ExprKind::Cast(cast_from_expr, cast_to_expr) = expr.kind else { return };
|
||||
let cast_to_ty = cx.typeck_results().expr_ty(expr);
|
||||
// Casting to a function (pointer?), so all good.
|
||||
//
|
||||
// Normally, only casts to integers is possible, but if it ever changed, this condition
|
||||
// will likely need to be updated.
|
||||
if matches!(cast_to_ty.kind(), ty::FnDef(..) | ty::FnPtr(..) | ty::RawPtr(..)) {
|
||||
return;
|
||||
}
|
||||
let cast_from_ty = cx.typeck_results().expr_ty(cast_from_expr);
|
||||
if matches!(cast_from_ty.kind(), ty::FnDef(..)) {
|
||||
cx.tcx.emit_node_span_lint(
|
||||
FUNCTION_CASTS_AS_INTEGER,
|
||||
expr.hir_id,
|
||||
cast_to_expr.span.with_lo(cast_from_expr.span.hi() + BytePos(1)),
|
||||
FunctionCastsAsIntegerDiag {
|
||||
sugg: FunctionCastsAsIntegerSugg {
|
||||
suggestion: cast_from_expr.span.shrink_to_hi(),
|
||||
cast_to_ty,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,7 @@ mod errors;
|
|||
mod expect;
|
||||
mod for_loops_over_fallibles;
|
||||
mod foreign_modules;
|
||||
mod function_cast_as_integer;
|
||||
mod if_let_rescope;
|
||||
mod impl_trait_overcaptures;
|
||||
mod internal;
|
||||
|
|
@ -89,6 +90,7 @@ use deref_into_dyn_supertrait::*;
|
|||
use drop_forget_useless::*;
|
||||
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
||||
use for_loops_over_fallibles::*;
|
||||
use function_cast_as_integer::*;
|
||||
use if_let_rescope::IfLetRescope;
|
||||
use impl_trait_overcaptures::ImplTraitOvercaptures;
|
||||
use internal::*;
|
||||
|
|
@ -241,6 +243,7 @@ late_lint_methods!(
|
|||
IfLetRescope: IfLetRescope::default(),
|
||||
StaticMutRefs: StaticMutRefs,
|
||||
UnqualifiedLocalImports: UnqualifiedLocalImports,
|
||||
FunctionCastsAsInteger: FunctionCastsAsInteger,
|
||||
CheckTransmutes: CheckTransmutes,
|
||||
LifetimeSyntax: LifetimeSyntax,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3019,6 +3019,26 @@ pub(crate) struct ReservedMultihash {
|
|||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_function_casts_as_integer)]
|
||||
pub(crate) struct FunctionCastsAsIntegerDiag<'tcx> {
|
||||
#[subdiagnostic]
|
||||
pub(crate) sugg: FunctionCastsAsIntegerSugg<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
lint_cast_as_fn,
|
||||
code = " as *const ()",
|
||||
applicability = "machine-applicable",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub(crate) struct FunctionCastsAsIntegerSugg<'tcx> {
|
||||
#[primary_span]
|
||||
pub suggestion: Span,
|
||||
pub cast_to_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MismatchedLifetimeSyntaxes {
|
||||
pub inputs: LifetimeSyntaxCategories<Vec<Span>>,
|
||||
|
|
|
|||
|
|
@ -55,10 +55,10 @@ macro_rules! late_lint_methods {
|
|||
/// Each `check` method checks a single syntax node, and should not
|
||||
/// invoke methods recursively (unlike `Visitor`). By default they
|
||||
/// do nothing.
|
||||
//
|
||||
///
|
||||
// FIXME: eliminate the duplication with `Visitor`. But this also
|
||||
// contains a few lint-specific methods with no equivalent in `Visitor`.
|
||||
|
||||
//
|
||||
macro_rules! declare_late_lint_pass {
|
||||
([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => (
|
||||
pub trait LateLintPass<'tcx>: LintPass {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc_middle::ty::{
|
|||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_target::spec::Os;
|
||||
use tracing::debug;
|
||||
|
||||
use super::repr_nullable_ptr;
|
||||
|
|
@ -177,7 +178,7 @@ fn variant_has_complex_ctor(variant: &ty::VariantDef) -> bool {
|
|||
/// the Power alignment Rule (see the `check_struct_for_power_alignment` function).
|
||||
fn check_arg_for_power_alignment<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
let tcx = cx.tcx;
|
||||
assert!(tcx.sess.target.os == "aix");
|
||||
assert!(tcx.sess.target.os == Os::Aix);
|
||||
// Structs (under repr(C)) follow the power alignment rule if:
|
||||
// - the first field of the struct is a floating-point type that
|
||||
// is greater than 4-bytes, or
|
||||
|
|
@ -222,7 +223,7 @@ fn check_struct_for_power_alignment<'tcx>(
|
|||
let tcx = cx.tcx;
|
||||
|
||||
// Only consider structs (not enums or unions) on AIX.
|
||||
if tcx.sess.target.os != "aix" || !adt_def.is_struct() {
|
||||
if tcx.sess.target.os != Os::Aix || !adt_def.is_struct() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1307,7 +1307,8 @@ impl EarlyLintPass for UnusedParens {
|
|||
Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
|
||||
// Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
|
||||
// Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
|
||||
Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
||||
// FIXME(pin_ergonomics): check pinned patterns
|
||||
Ref(p, _, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ declare_lint_pass! {
|
|||
UNUSED_UNSAFE,
|
||||
UNUSED_VARIABLES,
|
||||
USELESS_DEPRECATED,
|
||||
VARARGS_WITHOUT_PATTERN,
|
||||
WARNINGS,
|
||||
// tidy-alphabetical-end
|
||||
]
|
||||
|
|
@ -5295,3 +5296,50 @@ declare_lint! {
|
|||
report_in_deps: false,
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `varargs_without_pattern` lint detects when `...` is used as an argument to a
|
||||
/// non-foreign function without any pattern being specified.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// // Using `...` in non-foreign function definitions is unstable, however stability is
|
||||
/// // currently only checked after attributes are expanded, so using `#[cfg(false)]` here will
|
||||
/// // allow this to compile on stable Rust.
|
||||
/// #[cfg(false)]
|
||||
/// fn foo(...) {
|
||||
///
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Patterns are currently required for all non-`...` arguments in function definitions (with
|
||||
/// some exceptions in the 2015 edition). Requiring `...` arguments to have patterns in
|
||||
/// non-foreign function definitions makes the language more consistent, and removes a source of
|
||||
/// confusion for the unstable C variadic feature. `...` arguments without a pattern are already
|
||||
/// stable and widely used in foreign function definitions; this lint only affects non-foreign
|
||||
/// function definitions.
|
||||
///
|
||||
/// Using `...` (C varargs) in a non-foreign function definition is currently unstable. However,
|
||||
/// stability checking for the `...` syntax in non-foreign function definitions is currently
|
||||
/// implemented after attributes have been expanded, meaning that if the attribute removes the
|
||||
/// use of the unstable syntax (e.g. `#[cfg(false)]`, or a procedural macro), the code will
|
||||
/// compile on stable Rust; this is the only situation where this lint affects code that
|
||||
/// compiles on stable Rust.
|
||||
///
|
||||
/// This is a [future-incompatible] lint to transition this to a hard error in the future.
|
||||
///
|
||||
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||
pub VARARGS_WITHOUT_PATTERN,
|
||||
Warn,
|
||||
"detects usage of `...` arguments without a pattern in non-foreign items",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseError,
|
||||
reference: "issue #145544 <https://github.com/rust-lang/rust/issues/145544>",
|
||||
report_in_deps: false,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_session::cstore::{DllCallingConvention, DllImport, ForeignModule, Nati
|
|||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_target::spec::{Arch, BinaryFormat, LinkSelfContainedComponents};
|
||||
use rustc_target::spec::{Abi, Arch, BinaryFormat, Env, LinkSelfContainedComponents, Os};
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
|
@ -67,9 +67,9 @@ pub fn walk_native_lib_search_dirs<R>(
|
|||
// FIXME: On AIX this also has the side-effect of making the list of library search paths
|
||||
// non-empty, which is needed or the linker may decide to record the LIBPATH env, if
|
||||
// defined, as the search path instead of appending the default search paths.
|
||||
if sess.target.vendor == "fortanix"
|
||||
|| sess.target.os == "linux"
|
||||
|| sess.target.os == "fuchsia"
|
||||
if sess.target.abi == Abi::Fortanix
|
||||
|| sess.target.os == Os::Linux
|
||||
|| sess.target.os == Os::Fuchsia
|
||||
|| sess.target.is_like_aix
|
||||
|| sess.target.is_like_darwin && !sess.sanitizers().is_empty()
|
||||
{
|
||||
|
|
@ -79,7 +79,7 @@ pub fn walk_native_lib_search_dirs<R>(
|
|||
// Mac Catalyst uses the macOS SDK, but to link to iOS-specific frameworks
|
||||
// we must have the support library stubs in the library search path (#121430).
|
||||
if let Some(sdk_root) = apple_sdk_root
|
||||
&& sess.target.env == "macabi"
|
||||
&& sess.target.env == Env::MacAbi
|
||||
{
|
||||
f(&sdk_root.join("System/iOSSupport/usr/lib"), false)?;
|
||||
f(&sdk_root.join("System/iOSSupport/System/Library/Frameworks"), true)?;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::fmt;
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{HirId, HirIdMap, Node};
|
||||
use rustc_hir::{HirId, ItemLocalMap, Node};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::debug;
|
||||
|
|
@ -221,12 +221,12 @@ pub struct ScopeTree {
|
|||
/// variable is declared.
|
||||
var_map: FxIndexMap<hir::ItemLocalId, Scope>,
|
||||
|
||||
/// Identifies expressions which, if captured into a temporary, ought to
|
||||
/// have a temporary whose lifetime extends to the end of the enclosing *block*,
|
||||
/// and not the enclosing *statement*. Expressions that are not present in this
|
||||
/// table are not rvalue candidates. The set of rvalue candidates is computed
|
||||
/// during type check based on a traversal of the AST.
|
||||
pub rvalue_candidates: HirIdMap<RvalueCandidate>,
|
||||
/// Tracks expressions with extended temporary scopes, based on the syntactic rules for
|
||||
/// temporary lifetime extension. Further details may be found in
|
||||
/// `rustc_hir_analysis::check::region` and in the [Reference].
|
||||
///
|
||||
/// [Reference]: https://doc.rust-lang.org/nightly/reference/destructors.html#temporary-lifetime-extension
|
||||
extended_temp_scopes: ItemLocalMap<Option<Scope>>,
|
||||
|
||||
/// Backwards incompatible scoping that will be introduced in future editions.
|
||||
/// This information is used later for linting to identify locals and
|
||||
|
|
@ -234,16 +234,6 @@ pub struct ScopeTree {
|
|||
pub backwards_incompatible_scope: UnordMap<hir::ItemLocalId, Scope>,
|
||||
}
|
||||
|
||||
/// See the `rvalue_candidates` field for more information on rvalue
|
||||
/// candidates in general.
|
||||
/// The `lifetime` field is None to indicate that certain expressions escape
|
||||
/// into 'static and should have no local cleanup scope.
|
||||
#[derive(Debug, Copy, Clone, HashStable)]
|
||||
pub struct RvalueCandidate {
|
||||
pub target: hir::ItemLocalId,
|
||||
pub lifetime: Option<Scope>,
|
||||
}
|
||||
|
||||
impl ScopeTree {
|
||||
pub fn record_scope_parent(&mut self, child: Scope, parent: Option<Scope>) {
|
||||
debug!("{:?}.parent = {:?}", child, parent);
|
||||
|
|
@ -260,12 +250,13 @@ impl ScopeTree {
|
|||
self.var_map.insert(var, lifetime);
|
||||
}
|
||||
|
||||
pub fn record_rvalue_candidate(&mut self, var: HirId, candidate: RvalueCandidate) {
|
||||
debug!("record_rvalue_candidate(var={var:?}, candidate={candidate:?})");
|
||||
if let Some(lifetime) = &candidate.lifetime {
|
||||
assert!(var.local_id != lifetime.local_id)
|
||||
/// Make an association between a sub-expression and an extended lifetime
|
||||
pub fn record_extended_temp_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
|
||||
debug!(?var, ?lifetime);
|
||||
if let Some(lifetime) = lifetime {
|
||||
assert!(var != lifetime.local_id);
|
||||
}
|
||||
self.rvalue_candidates.insert(var, candidate);
|
||||
self.extended_temp_scopes.insert(var, lifetime);
|
||||
}
|
||||
|
||||
/// Returns the narrowest scope that encloses `id`, if any.
|
||||
|
|
@ -337,4 +328,20 @@ impl ScopeTree {
|
|||
|
||||
span_bug!(ty::tls::with(|tcx| inner.span(tcx, self)), "no enclosing temporary scope")
|
||||
}
|
||||
|
||||
/// Returns the scope when the temp created by `expr_id` will be cleaned up.
|
||||
/// It also emits a lint on potential backwards incompatible change to the temporary scope
|
||||
/// which is *for now* always shortening.
|
||||
pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> (Option<Scope>, Option<Scope>) {
|
||||
// Check for a designated extended temporary scope.
|
||||
if let Some(&s) = self.extended_temp_scopes.get(&expr_id) {
|
||||
debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
|
||||
return (s, None);
|
||||
}
|
||||
|
||||
// Otherwise, locate the innermost terminating scope.
|
||||
let (scope, backward_incompatible) =
|
||||
self.default_temporary_scope(Scope { local_id: expr_id, data: ScopeData::Node });
|
||||
(Some(scope), backward_incompatible)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Evaluated Constants
|
||||
|
||||
///
|
||||
/// Represents the result of const evaluation via the `eval_to_allocation` query.
|
||||
/// Not to be confused with `ConstAllocation`, which directly refers to the underlying data!
|
||||
/// Here we indirect via an `AllocId`.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub use basic_blocks::{BasicBlocks, SwitchTargetValue};
|
|||
use either::Either;
|
||||
use polonius_engine::Atom;
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
pub use rustc_ast::Mutability;
|
||||
pub use rustc_ast::{Mutability, Pinnedness};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg};
|
||||
|
|
|
|||
|
|
@ -856,6 +856,7 @@ bidirectional_lang_item_map! {
|
|||
PointeeTrait,
|
||||
Sized,
|
||||
TransmuteTrait,
|
||||
TrivialClone,
|
||||
Tuple,
|
||||
Unpin,
|
||||
Unsize,
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ pub use self::region::{
|
|||
BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region,
|
||||
RegionKind, RegionVid,
|
||||
};
|
||||
pub use self::rvalue_scopes::RvalueScopes;
|
||||
pub use self::sty::{
|
||||
AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
|
||||
CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst,
|
||||
|
|
@ -156,7 +155,6 @@ mod list;
|
|||
mod opaque_types;
|
||||
mod predicate;
|
||||
mod region;
|
||||
mod rvalue_scopes;
|
||||
mod structural_impls;
|
||||
#[allow(hidden_glob_reexports)]
|
||||
mod sty;
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::ItemLocalMap;
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::middle::region::{Scope, ScopeData, ScopeTree};
|
||||
|
||||
/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
|
||||
/// rules laid out in `rustc_hir_analysis::check::rvalue_scopes`.
|
||||
#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
|
||||
pub struct RvalueScopes {
|
||||
map: ItemLocalMap<Option<Scope>>,
|
||||
}
|
||||
|
||||
impl RvalueScopes {
|
||||
pub fn new() -> Self {
|
||||
Self { map: <_>::default() }
|
||||
}
|
||||
|
||||
/// Returns the scope when the temp created by `expr_id` will be cleaned up.
|
||||
/// It also emits a lint on potential backwards incompatible change to the temporary scope
|
||||
/// which is *for now* always shortening.
|
||||
pub fn temporary_scope(
|
||||
&self,
|
||||
region_scope_tree: &ScopeTree,
|
||||
expr_id: hir::ItemLocalId,
|
||||
) -> (Option<Scope>, Option<Scope>) {
|
||||
// Check for a designated rvalue scope.
|
||||
if let Some(&s) = self.map.get(&expr_id) {
|
||||
debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
|
||||
return (s, None);
|
||||
}
|
||||
|
||||
// Otherwise, locate the innermost terminating scope.
|
||||
let (scope, backward_incompatible) = region_scope_tree
|
||||
.default_temporary_scope(Scope { local_id: expr_id, data: ScopeData::Node });
|
||||
(Some(scope), backward_incompatible)
|
||||
}
|
||||
|
||||
/// Make an association between a sub-expression and an extended lifetime
|
||||
pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
|
||||
debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})");
|
||||
if let Some(lifetime) = lifetime {
|
||||
assert!(var != lifetime.local_id);
|
||||
}
|
||||
self.map.insert(var, lifetime);
|
||||
}
|
||||
}
|
||||
|
|
@ -1366,6 +1366,19 @@ impl<'tcx> Ty<'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
pub fn maybe_pinned_ref(self) -> Option<(Ty<'tcx>, ty::Pinnedness, ty::Mutability)> {
|
||||
match *self.kind() {
|
||||
Adt(def, args)
|
||||
if def.is_pin()
|
||||
&& let ty::Ref(_, ty, mutbl) = *args.type_at(0).kind() =>
|
||||
{
|
||||
Some((ty, ty::Pinnedness::Pinned, mutbl))
|
||||
}
|
||||
ty::Ref(_, ty, mutbl) => Some((ty, ty::Pinnedness::Not, mutbl)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Panics if called on any type other than `Box<T>`.
|
||||
pub fn expect_boxed_ty(self) -> Ty<'tcx> {
|
||||
self.boxed_ty()
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
|
|||
use rustc_session::Session;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::RvalueScopes;
|
||||
use crate::hir::place::Place as HirPlace;
|
||||
use crate::infer::canonical::Canonical;
|
||||
use crate::mir::FakeReadCause;
|
||||
|
|
@ -198,11 +197,6 @@ pub struct TypeckResults<'tcx> {
|
|||
/// issue by fake reading `t`.
|
||||
pub closure_fake_reads: LocalDefIdMap<Vec<(HirPlace<'tcx>, FakeReadCause, HirId)>>,
|
||||
|
||||
/// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
|
||||
/// by applying extended parameter rules.
|
||||
/// Details may be found in `rustc_hir_analysis::check::rvalue_scopes`.
|
||||
pub rvalue_scopes: RvalueScopes,
|
||||
|
||||
/// Stores the predicates that apply on coroutine witness types.
|
||||
/// formatting modified file tests/ui/coroutine/retain-resume-ref.rs
|
||||
pub coroutine_stalled_predicates: FxIndexSet<(ty::Predicate<'tcx>, ObligationCause<'tcx>)>,
|
||||
|
|
@ -254,7 +248,6 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||
hidden_types: Default::default(),
|
||||
closure_min_captures: Default::default(),
|
||||
closure_fake_reads: Default::default(),
|
||||
rvalue_scopes: Default::default(),
|
||||
coroutine_stalled_predicates: Default::default(),
|
||||
potentially_region_dependent_goals: Default::default(),
|
||||
closure_size_eval: Default::default(),
|
||||
|
|
|
|||
|
|
@ -607,9 +607,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// have the same `DefKind`.
|
||||
///
|
||||
/// Note that closures have a `DefId`, but the closure *expression* also has a
|
||||
// `HirId` that is located within the context where the closure appears (and, sadly,
|
||||
// a corresponding `NodeId`, since those are not yet phased out). The parent of
|
||||
// the closure's `DefId` will also be the context where it appears.
|
||||
/// `HirId` that is located within the context where the closure appears (and, sadly,
|
||||
/// a corresponding `NodeId`, since those are not yet phased out). The parent of
|
||||
/// the closure's `DefId` will also be the context where it appears.
|
||||
pub fn is_closure_like(self, def_id: DefId) -> bool {
|
||||
matches!(self.def_kind(def_id), DefKind::Closure)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -779,8 +779,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place),
|
||||
);
|
||||
|
||||
// See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why
|
||||
// this can be `None`.
|
||||
// This can be `None` if the expression's temporary scope was extended so that it can be
|
||||
// borrowed by a `const` or `static`. In that case, it's never dropped.
|
||||
if let Some(temp_lifetime) = temp_lifetime {
|
||||
this.schedule_drop_storage_and_value(upvar_span, temp_lifetime, temp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,14 +284,12 @@ impl<'tcx> MatchPairTree<'tcx> {
|
|||
}
|
||||
|
||||
PatKind::Deref { ref subpattern }
|
||||
| PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => {
|
||||
if cfg!(debug_assertions) && matches!(pattern.kind, PatKind::DerefPattern { .. }) {
|
||||
// Only deref patterns on boxes can be lowered using a built-in deref.
|
||||
debug_assert!(pattern.ty.is_box());
|
||||
}
|
||||
|
||||
| PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) }
|
||||
if let Some(ref_ty) = pattern.ty.pinned_ty()
|
||||
&& ref_ty.is_ref() =>
|
||||
{
|
||||
MatchPairTree::for_pattern(
|
||||
place_builder.deref(),
|
||||
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
|
||||
subpattern,
|
||||
cx,
|
||||
&mut subpairs,
|
||||
|
|
@ -300,12 +298,14 @@ impl<'tcx> MatchPairTree<'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
PatKind::DerefPattern { ref subpattern, borrow: ByRef::Yes(Pinnedness::Pinned, _) } => {
|
||||
let Some(ref_ty) = pattern.ty.pinned_ty() else {
|
||||
rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty);
|
||||
};
|
||||
PatKind::DerefPattern { borrow: ByRef::Yes(Pinnedness::Pinned, _), .. } => {
|
||||
rustc_middle::bug!("RefPin pattern on non-`Pin` type {:?}", pattern.ty)
|
||||
}
|
||||
|
||||
PatKind::Deref { ref subpattern }
|
||||
| PatKind::DerefPattern { ref subpattern, borrow: ByRef::No } => {
|
||||
MatchPairTree::for_pattern(
|
||||
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
|
||||
place_builder.deref(),
|
||||
subpattern,
|
||||
cx,
|
||||
&mut subpairs,
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
let tcx = self.tcx;
|
||||
let expr_ty = self.typeck_results.expr_ty(expr);
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||
self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
|
||||
let kind = match expr.kind {
|
||||
// Here comes the interesting stuff:
|
||||
|
|
@ -502,9 +502,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
expr: Some(arg),
|
||||
safety_mode: BlockSafety::Safe,
|
||||
});
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id);
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.region_scope_tree.temporary_scope(arg_expr.hir_id.local_id);
|
||||
arg = self.thir.exprs.push(Expr {
|
||||
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
|
||||
ty: arg_ty,
|
||||
|
|
@ -996,9 +995,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
}
|
||||
} else {
|
||||
let block_ty = self.typeck_results.node_type(body.hir_id);
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, body.hir_id.local_id);
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.region_scope_tree.temporary_scope(body.hir_id.local_id);
|
||||
let block = self.mirror_block(body);
|
||||
let body = self.thir.exprs.push(Expr {
|
||||
ty: block_ty,
|
||||
|
|
@ -1143,7 +1141,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
overloaded_callee: Option<Ty<'tcx>>,
|
||||
) -> Expr<'tcx> {
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||
self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
let (ty, user_ty) = match overloaded_callee {
|
||||
Some(fn_def) => (fn_def, None),
|
||||
None => {
|
||||
|
|
@ -1237,9 +1235,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
Res::Def(DefKind::Static { .. }, id) => {
|
||||
// this is &raw for extern static or static mut, and & for other statics
|
||||
let ty = self.tcx.static_ptr_ty(id, self.typing_env);
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
let kind = if self.tcx.is_thread_local_static(id) {
|
||||
ExprKind::ThreadLocalRef(id)
|
||||
} else {
|
||||
|
|
@ -1321,7 +1318,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
// construct the complete expression `foo()` for the overloaded call,
|
||||
// which will yield the &T type
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id);
|
||||
self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
|
||||
let fun = self.method_callee(expr, span, overloaded_callee);
|
||||
let fun = self.thir.exprs.push(fun);
|
||||
let fun_ty = self.thir[fun].ty;
|
||||
|
|
@ -1341,9 +1338,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
closure_expr: &'tcx hir::Expr<'tcx>,
|
||||
place: HirPlace<'tcx>,
|
||||
) -> Expr<'tcx> {
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
|
||||
let var_ty = place.base_ty;
|
||||
|
||||
// The result of capture analysis in `rustc_hir_typeck/src/upvar.rs` represents a captured path
|
||||
|
|
@ -1405,9 +1401,8 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
let upvar_capture = captured_place.info.capture_kind;
|
||||
let captured_place_expr =
|
||||
self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
|
||||
let (temp_lifetime, backwards_incompatible) = self
|
||||
.rvalue_scopes
|
||||
.temporary_scope(self.region_scope_tree, closure_expr.hir_id.local_id);
|
||||
let (temp_lifetime, backwards_incompatible) =
|
||||
self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
|
||||
|
||||
match upvar_capture {
|
||||
ty::UpvarCapture::ByValue => captured_place_expr,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_hir::{self as hir, HirId, find_attr};
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::region;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::thir::pattern::pat_from_hir;
|
||||
|
|
@ -62,7 +62,6 @@ struct ThirBuildCx<'tcx> {
|
|||
|
||||
region_scope_tree: &'tcx region::ScopeTree,
|
||||
typeck_results: &'tcx ty::TypeckResults<'tcx>,
|
||||
rvalue_scopes: &'tcx RvalueScopes,
|
||||
|
||||
/// False to indicate that adjustments should not be applied. Only used for `custom_mir`
|
||||
apply_adjustments: bool,
|
||||
|
|
@ -109,7 +108,6 @@ impl<'tcx> ThirBuildCx<'tcx> {
|
|||
typing_env: ty::TypingEnv::non_body_analysis(tcx, def),
|
||||
region_scope_tree: tcx.region_scope_tree(def),
|
||||
typeck_results,
|
||||
rvalue_scopes: &typeck_results.rvalue_scopes,
|
||||
body_owner: def.to_def_id(),
|
||||
apply_adjustments:
|
||||
!find_attr!(tcx.hir_attrs(hir_id), AttributeKind::CustomMir(..) => ()).is_some(),
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
// adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
|
||||
// gets the least-dereferenced type).
|
||||
let unadjusted_pat = match pat.kind {
|
||||
hir::PatKind::Ref(inner, _)
|
||||
hir::PatKind::Ref(inner, _, _)
|
||||
if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
|
||||
{
|
||||
self.lower_pattern(inner)
|
||||
|
|
@ -319,7 +319,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
let borrow = self.typeck_results.deref_pat_borrow_mode(ty, subpattern);
|
||||
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), borrow }
|
||||
}
|
||||
hir::PatKind::Ref(subpattern, _) => {
|
||||
hir::PatKind::Ref(subpattern, _, _) => {
|
||||
// Track the default binding mode for the Rust 2024 migration suggestion.
|
||||
let opt_old_mode_span =
|
||||
self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
|
||||
|
|
@ -370,10 +370,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||
if let Some(pty) = ty.pinned_ty()
|
||||
&& let &ty::Ref(_, rty, _) = pty.kind() =>
|
||||
{
|
||||
debug_assert!(
|
||||
self.tcx.features().pin_ergonomics(),
|
||||
"`pin_ergonomics` must be enabled to have a by-pin-ref binding"
|
||||
);
|
||||
ty = rty;
|
||||
}
|
||||
hir::Pinnedness::Not if let &ty::Ref(_, rty, _) = ty.kind() => {
|
||||
|
|
|
|||
|
|
@ -547,9 +547,11 @@ where
|
|||
Some(SolverTraitLangItem::PointeeSized) => {
|
||||
unreachable!("`PointeeSized` is removed during lowering");
|
||||
}
|
||||
Some(SolverTraitLangItem::Copy | SolverTraitLangItem::Clone) => {
|
||||
G::consider_builtin_copy_clone_candidate(self, goal)
|
||||
}
|
||||
Some(
|
||||
SolverTraitLangItem::Copy
|
||||
| SolverTraitLangItem::Clone
|
||||
| SolverTraitLangItem::TrivialClone,
|
||||
) => G::consider_builtin_copy_clone_candidate(self, goal),
|
||||
Some(SolverTraitLangItem::Fn) => {
|
||||
G::consider_builtin_fn_trait_candidates(self, goal, ty::ClosureKind::Fn)
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue