Merge pull request #2200 from Kobzol/rustc-pull

Rustc pull
This commit is contained in:
Jakub Beránek 2025-01-08 13:47:34 +01:00 committed by GitHub
commit 5a11197efd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
631 changed files with 37491 additions and 8026 deletions

View file

@ -7,6 +7,6 @@ tracking issue or there are none, feel free to ignore this.
This PR will get automatically assigned to a reviewer. In case you would like
a specific user to review your work, you can assign it to them by using
r\? <reviewer name> (with the `\` removed)
r? <reviewer name>
-->
<!-- homu-ignore:end -->

View file

@ -185,9 +185,6 @@ name = "anyhow"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
dependencies = [
"backtrace",
]
[[package]]
name = "ar_archive_writer"
@ -3499,6 +3496,7 @@ name = "rustc_codegen_llvm"
version = "0.0.0"
dependencies = [
"bitflags",
"gimli 0.30.0",
"itertools",
"libc",
"measureme",
@ -4117,7 +4115,6 @@ name = "rustc_middle"
version = "0.0.0"
dependencies = [
"bitflags",
"derive-where",
"either",
"field-offset",
"gsgdt",

View file

@ -1,3 +1,119 @@
Version 1.84.0 (2025-01-09)
==========================
<a id="
Language"></a>
Language
--------
- [Allow `#[deny]` inside `#[forbid]` as a no-op](https://github.com/rust-lang/rust/pull/121560/)
- [Show a warning when `-Ctarget-feature` is used to toggle features that can lead to unsoundness due to ABI mismatches](https://github.com/rust-lang/rust/pull/129884)
- [Use the next-generation trait solver in coherence](https://github.com/rust-lang/rust/pull/130654)
- [Allow coercions to drop the principal of trait objects](https://github.com/rust-lang/rust/pull/131857)
- [Support `/` as the path separator for `include!()` in all cases on Windows](https://github.com/rust-lang/rust/pull/125205)
- [Taking a raw ref (`raw (const|mut)`) of a deref of a pointer (`*ptr`) is now safe](https://github.com/rust-lang/rust/pull/129248)
- [Stabilize s390x inline assembly](https://github.com/rust-lang/rust/pull/131258)
- [Stabilize Arm64EC inline assembly](https://github.com/rust-lang/rust/pull/131781)
- [Lint against creating pointers to immediately dropped temporaries](https://github.com/rust-lang/rust/pull/128985)
- [Execute drop glue when unwinding in an `extern "C"` function](https://github.com/rust-lang/rust/pull/129582)
<a id="1.84.0-Compiler"></a>
Compiler
--------
- [Add `--print host-tuple` flag to print the host target tuple and affirm the "target tuple" terminology over "target triple"](https://github.com/rust-lang/rust/pull/125579)
- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935)
- [Set up indirect access to external data for `loongarch64-unknown-linux-{musl,ohos}`](https://github.com/rust-lang/rust/pull/131583)
- [Enable XRay instrumentation for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/131818)
- [Extend the `unexpected_cfgs` lint to also warn in external macros](https://github.com/rust-lang/rust/pull/132577)
- [Stabilize WebAssembly `multivalue`, `reference-types`, and `tail-call` target features](https://github.com/rust-lang/rust/pull/131080)
- [Added Tier 2 support for the `wasm32v1-none` target](https://github.com/rust-lang/rust/pull/131487)
<a id="1.84.0-Libraries"></a>
Libraries
---------
- [Implement `From<&mut {slice}>` for `Box/Rc/Arc<{slice}>`](https://github.com/rust-lang/rust/pull/129329)
- [Move `<float>::copysign`, `<float>::abs`, `<float>::signum` to `core`](https://github.com/rust-lang/rust/pull/131304)
- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377)
- [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608)
- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/130635)
<a id="1.84.0-Stabilized-APIs"></a>
Stabilized APIs
---------------
- [`Ipv6Addr::is_unique_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unique_local)
- [`Ipv6Addr::is_unicast_link_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unicast_link_local)
- [`core::ptr::with_exposed_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance.html)
- [`core::ptr::with_exposed_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance_mut.html)
- [`<ptr>::addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.addr)
- [`<ptr>::expose_provenance`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.expose_provenance)
- [`<ptr>::with_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.with_addr)
- [`<ptr>::map_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.map_addr)
- [`<int>::isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.isqrt)
- [`<int>::checked_isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.checked_isqrt)
- [`<uint>::isqrt`](https://doc.rust-lang.org/stable/core/primitive.u32.html#method.isqrt)
- [`NonZero::isqrt`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html#impl-NonZero%3Cu128%3E/method.isqrt)
- [`core::ptr::without_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance.html)
- [`core::ptr::without_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance_mut.html)
- [`core::ptr::dangling`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling.html)
- [`core::ptr::dangling_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling_mut.html)
These APIs are now stable in const contexts
- [`AtomicBool::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicBool.html#method.from_ptr)
- [`AtomicPtr::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicPtr.html#method.from_ptr)
- [`AtomicU8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU8.html#method.from_ptr)
- [`AtomicU16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU16.html#method.from_ptr)
- [`AtomicU32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.from_ptr)
- [`AtomicU64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU64.html#method.from_ptr)
- [`AtomicUsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.from_ptr)
- [`AtomicI8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI8.html#method.from_ptr)
- [`AtomicI16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI16.html#method.from_ptr)
- [`AtomicI32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI32.html#method.from_ptr)
- [`AtomicI64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI64.html#method.from_ptr)
- [`AtomicIsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicIsize.html#method.from_ptr)
- [`<ptr>::is_null`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_null-1)
- [`<ptr>::as_ref`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_ref-1)
- [`<ptr>::as_mut`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_mut)
- [`Pin::new`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new)
- [`Pin::new_unchecked`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new_unchecked)
- [`Pin::get_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_ref)
- [`Pin::into_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.into_ref)
- [`Pin::get_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_mut)
- [`Pin::get_unchecked_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_unchecked_mut)
- [`Pin::static_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_ref)
- [`Pin::static_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_mut)
<a id="1.84.0-Cargo"></a>
Cargo
-----
- [Stabilize MSRV-aware resolver config](https://github.com/rust-lang/cargo/pull/14639/)
- [Stabilize resolver v3](https://github.com/rust-lang/cargo/pull/14754/)
<a id="1.84-Rustdoc"></a>
Rustdoc
-------
- [rustdoc-search: improve type-driven search](https://github.com/rust-lang/rust/pull/127589)
<a id="1.84.0-Compatibility-Notes"></a>
Compatibility Notes
-------------------
- [Enable by default the `LSX` target feature for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/132140)
- [The unstable `-Zprofile` flag (“gcov-style” coverage instrumentation) has been removed.](https://github.com/rust-lang/rust/pull/131829) This does not affect the stable flags for coverage instrumentation (`-Cinstrument-coverage`) and profile-guided optimization (`-Cprofile-generate`, `-Cprofile-use`), which are unrelated and remain available.
- Support for the target named `wasm32-wasi` has been removed as the target is now named `wasm32-wasip1`. This completes the [transition](https://github.com/rust-lang/compiler-team/issues/607) [plan](https://github.com/rust-lang/compiler-team/issues/695) for this target following [the introduction of `wasm32-wasip1`](https://github.com/rust-lang/rust/pull/120468) in Rust 1.78. Compiler warnings on [use of `wasm32-wasi`](https://github.com/rust-lang/rust/pull/126662) introduced in Rust 1.81 are now gone as well as the target is removed.
- [The syntax `&pin (mut|const) T` is now parsed as a type which in theory could affect macro expansion results in some edge cases](https://github.com/rust-lang/rust/pull/130635#issuecomment-2375462821)
- [Legacy syntax for calling `std::arch` functions is no longer permitted to declare items or bodies (such as closures, inline consts, or async blocks).](https://github.com/rust-lang/rust/pull/130443#issuecomment-2445678945)
- The `wasm32-unknown-emscripten` target's binary release of the standard library is now [built with the latest emsdk 3.1.68](https://github.com/rust-lang/rust/pull/131533), which fixes an ABI-incompatibility with Emscripten >= 3.1.42. If you are locally using a version of emsdk with an incompatible ABI (e.g. before 3.1.42 or a future one), you should build your code with `-Zbuild-std` to ensure that `std` uses the correct ABI.
- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935)
- [The next-generation trait solver is now enabled for coherence, fixing multiple soundness issues](https://github.com/rust-lang/rust/pull/130654)
Version 1.83.0 (2024-11-28)
==========================

View file

@ -120,8 +120,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_range_end(end, e2.is_some()),
);
}
// FIXME(guard_patterns): lower pattern guards to HIR
PatKind::Guard(inner, _) => pattern = inner,
PatKind::Guard(inner, cond) => {
break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
}
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
PatKind::Rest => {
// If we reach here the `..` pattern is not semantically allowed.

View file

@ -242,7 +242,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
ast::ItemKind::Struct(..) => {
ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
for attr in attr::filter_by_name(&i.attrs, sym::repr) {
for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
if item.has_name(sym::simd) {

View file

@ -9,7 +9,12 @@ use crate::RustcVersion;
/// `since` field of the `#[stable]` attribute.
///
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N");
// Note that the `concat!` macro above prevents `src/tools/replace-version-placeholder` from
// replacing the constant with the current version. Hardcoding the tool to skip this file doesn't
// work as the file can (and at some point will) be moved around.
//
// Turning the `concat!` macro into a string literal will make Pietro cry. That'd be sad :(
/// Represents the following attributes:
///

View file

@ -213,6 +213,10 @@ borrowck_suggest_create_fresh_reborrow =
borrowck_suggest_iterate_over_slice =
consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
borrowck_tail_expr_drop_order = relative drop order changing in Rust 2024
.label = this temporary value will be dropped at the end of the block
.note = consider using a `let` binding to ensure the value will live long enough
borrowck_ty_no_impl_copy =
{$is_partial_move ->
[true] partial move

View file

@ -11,7 +11,6 @@ use rustc_mir_dataflow::move_paths::MoveData;
use tracing::debug;
use crate::BorrowIndex;
use crate::path_utils::allow_two_phase_borrow;
use crate::place_ext::PlaceExt;
pub struct BorrowSet<'tcx> {
@ -350,7 +349,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
start_location, assigned_place, borrow_index,
);
if !allow_two_phase_borrow(kind) {
if !kind.allows_two_phase_borrow() {
debug!(" -> {:?}", start_location);
return;
}

View file

@ -1516,15 +1516,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
});
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&mut err,
"",
Some(borrow_span),
None,
);
.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
if let Some(expr) = self.find_expr(borrow_span) {
@ -1591,15 +1583,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
});
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&mut err,
"",
None,
None,
);
.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
err
}
@ -1886,9 +1870,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&self,
&mut err,
first_borrow_desc,
None,
@ -3046,15 +3028,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if let BorrowExplanation::MustBeValidFor { .. } = explanation {
} else {
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&mut err,
"",
None,
None,
);
explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
}
} else {
err.span_label(borrow_span, "borrowed value does not live long enough");
@ -3067,15 +3041,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
});
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&mut err,
"",
Some(borrow_span),
None,
);
explanation.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);
}
err
@ -3128,15 +3094,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
_ => {}
}
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&mut err,
"",
None,
None,
);
explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
self.buffer_error(err);
}
@ -3309,15 +3267,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
_ => {}
}
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&mut err,
"",
None,
None,
);
explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
borrow_spans.args_subdiag(&mut err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::Capture {
@ -3808,15 +3758,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
});
self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
self.infcx.tcx,
self.body,
&self.local_names,
&mut err,
"",
None,
None,
);
self.explain_why_borrow_contains_point(location, loan, None)
.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
self.explain_deref_coercion(loan, &mut err);

View file

@ -5,10 +5,9 @@
use std::assert_matches::assert_matches;
use rustc_errors::{Applicability, Diag};
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_index::IndexSlice;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
use rustc_middle::mir::{
@ -17,14 +16,16 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
use rustc_span::{DesugaringKind, Span, Symbol, kw, sym};
use rustc_middle::util::CallKind;
use rustc_span::{DesugaringKind, Span, kw, sym};
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
use tracing::{debug, instrument};
use super::{RegionName, UseSpans, find_use};
use crate::borrow_set::BorrowData;
use crate::constraints::OutlivesConstraint;
use crate::nll::ConstraintDescription;
use crate::region_infer::{BlameConstraint, Cause, ExtraConstraintInfo};
use crate::region_infer::{BlameConstraint, Cause};
use crate::{MirBorrowckCtxt, WriteKind};
#[derive(Debug)]
@ -42,7 +43,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
span: Span,
region_name: RegionName,
opt_place_desc: Option<String>,
extra_info: Vec<ExtraConstraintInfo>,
path: Vec<OutlivesConstraint<'tcx>>,
},
Unexplained,
}
@ -60,16 +61,18 @@ impl<'tcx> BorrowExplanation<'tcx> {
pub(crate) fn is_explained(&self) -> bool {
!matches!(self, BorrowExplanation::Unexplained)
}
pub(crate) fn add_explanation_to_diagnostic(
pub(crate) fn add_explanation_to_diagnostic<G: EmissionGuarantee>(
&self,
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
local_names: &IndexSlice<Local, Option<Symbol>>,
err: &mut Diag<'_>,
cx: &MirBorrowckCtxt<'_, '_, 'tcx>,
err: &mut Diag<'_, G>,
borrow_desc: &str,
borrow_span: Option<Span>,
multiple_borrow_span: Option<(Span, Span)>,
) {
let tcx = cx.infcx.tcx;
let body = cx.body;
let local_names = &cx.local_names;
if let Some(span) = borrow_span {
let def_id = body.source.def_id();
if let Some(node) = tcx.hir().get_if_local(def_id)
@ -305,7 +308,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
ref region_name,
ref opt_place_desc,
from_closure: _,
ref extra_info,
ref path,
} => {
region_name.highlight_region_name(err);
@ -327,13 +330,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
);
};
for extra in extra_info {
match extra {
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
}
}
}
cx.add_placeholder_from_predicate_note(err, &path);
cx.add_sized_or_copy_bound_info(err, category, &path);
if let ConstraintCategory::Cast {
is_implicit_coercion: true,
@ -348,10 +346,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}
fn add_object_lifetime_default_note(
fn add_object_lifetime_default_note<G: EmissionGuarantee>(
&self,
tcx: TyCtxt<'tcx>,
err: &mut Diag<'_>,
err: &mut Diag<'_, G>,
unsize_ty: Ty<'tcx>,
) {
if let ty::Adt(def, args) = unsize_ty.kind() {
@ -405,9 +403,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}
fn add_lifetime_bound_suggestion_to_diagnostic(
fn add_lifetime_bound_suggestion_to_diagnostic<G: EmissionGuarantee>(
&self,
err: &mut Diag<'_>,
err: &mut Diag<'_, G>,
category: &ConstraintCategory<'tcx>,
span: Span,
region_name: &RegionName,
@ -434,14 +432,14 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}
fn suggest_rewrite_if_let(
fn suggest_rewrite_if_let<G: EmissionGuarantee>(
tcx: TyCtxt<'_>,
expr: &hir::Expr<'_>,
pat: &str,
init: &hir::Expr<'_>,
conseq: &hir::Expr<'_>,
alt: Option<&hir::Expr<'_>>,
err: &mut Diag<'_>,
err: &mut Diag<'_, G>,
) {
let source_map = tcx.sess.source_map();
err.span_note(
@ -486,8 +484,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
&self,
borrow_region: RegionVid,
outlived_region: RegionVid,
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<OutlivesConstraint<'tcx>>)
{
let (blame_constraint, path) = self.regioncx.best_blame_constraint(
borrow_region,
NllRegionVariableOrigin::FreeRegion,
|r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
@ -496,7 +495,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
let outlived_fr_name = self.give_region_a_name(outlived_region);
(category, from_closure, cause.span, outlived_fr_name, extra_info)
(category, from_closure, cause.span, outlived_fr_name, path)
}
/// Returns structured explanation for *why* the borrow contains the
@ -595,7 +594,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
None => {
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
let (category, from_closure, span, region_name, extra_info) =
let (category, from_closure, span, region_name, path) =
self.free_region_constraint_info(borrow_region_vid, region);
if let Some(region_name) = region_name {
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
@ -605,7 +604,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
span,
region_name,
opt_place_desc,
extra_info,
path,
}
} else {
debug!("Could not generate a region name");
@ -635,6 +634,39 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
// Used in a closure.
(LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span))
}
// In the case that the borrowed value (probably a temporary)
// overlaps with the method's receiver, then point at the method.
UseSpans::FnSelfUse {
var_span: span,
kind: CallKind::Normal { desugaring: None, .. },
..
} if span
.overlaps(self.body.local_decls[borrow.assigned_place.local].source_info.span) =>
{
if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } =
&self.body.basic_blocks[location.block].terminator().kind
{
// Just point to the function, to reduce the chance of overlapping spans.
let function_span = match func {
Operand::Constant(c) => c.span,
Operand::Copy(place) | Operand::Move(place) => {
if let Some(l) = place.as_local() {
let local_decl = &self.body.local_decls[l];
if self.local_names[l].is_none() {
local_decl.source_info.span
} else {
span
}
} else {
span
}
}
};
(LaterUseKind::Call, function_span, None)
} else {
(LaterUseKind::Other, span, None)
}
}
UseSpans::PatUse(span)
| UseSpans::OtherUse(span)
| UseSpans::FnSelfUse { var_span: span, .. } => {

View file

@ -4,18 +4,20 @@ use std::collections::BTreeMap;
use rustc_abi::{FieldIdx, VariantIdx};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::{Applicability, Diag, MultiSpan};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan};
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::{self as hir, CoroutineKind, LangItem};
use rustc_index::IndexSlice;
use rustc_infer::infer::BoundRegionConversionTime;
use rustc_infer::infer::{
BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin,
};
use rustc_infer::traits::SelectionError;
use rustc_middle::bug;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
TerminatorKind,
AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
StatementKind, Terminator, TerminatorKind,
};
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
@ -33,7 +35,9 @@ use tracing::debug;
use super::MirBorrowckCtxt;
use super::borrow_set::BorrowData;
use crate::constraints::OutlivesConstraint;
use crate::fluent_generated as fluent;
use crate::nll::ConstraintDescription;
use crate::session_diagnostics::{
CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
@ -619,6 +623,52 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
region.print(&mut printer).unwrap();
printer.into_buffer()
}
/// Add a note to region errors and borrow explanations when higher-ranked regions in predicates
/// implicitly introduce an "outlives `'static`" constraint.
fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(
&self,
err: &mut Diag<'_, G>,
path: &[OutlivesConstraint<'tcx>],
) {
let predicate_span = path.iter().find_map(|constraint| {
let outlived = constraint.sub;
if let Some(origin) = self.regioncx.var_infos.get(outlived)
&& let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) =
origin.origin
&& let ConstraintCategory::Predicate(span) = constraint.category
{
Some(span)
} else {
None
}
});
if let Some(span) = predicate_span {
err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
}
}
/// Add a label to region errors and borrow explanations when outlives constraints arise from
/// proving a type implements `Sized` or `Copy`.
fn add_sized_or_copy_bound_info<G: EmissionGuarantee>(
&self,
err: &mut Diag<'_, G>,
blamed_category: ConstraintCategory<'tcx>,
path: &[OutlivesConstraint<'tcx>],
) {
for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] {
if sought_category != blamed_category
&& let Some(sought_constraint) = path.iter().find(|c| c.category == sought_category)
{
let label = format!(
"requirement occurs due to {}",
sought_category.description().trim_end()
);
err.span_label(sought_constraint.span, label);
}
}
}
}
/// The span(s) associated to a use of a place.
@ -661,9 +711,6 @@ impl UseSpans<'_> {
UseSpans::ClosureUse { args_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
fn_call_span
}
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@ -674,9 +721,6 @@ impl UseSpans<'_> {
UseSpans::ClosureUse { path_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
fn_call_span
}
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@ -687,9 +731,6 @@ impl UseSpans<'_> {
UseSpans::ClosureUse { capture_kind_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
fn_call_span
}
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@ -1001,6 +1042,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
kind,
};
}
normal_ret
}

View file

@ -10,6 +10,7 @@ use rustc_hir::intravisit::Visitor;
use rustc_hir::{self as hir, BindingMode, ByRef, Node};
use rustc_middle::bug;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::visit::PlaceContext;
use rustc_middle::mir::{
self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location, Mutability, Place,
PlaceRef, ProjectionElem,
@ -22,7 +23,6 @@ use rustc_trait_selection::traits;
use tracing::debug;
use crate::diagnostics::BorrowedContentSource;
use crate::util::FindAssignments;
use crate::{MirBorrowckCtxt, session_diagnostics};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@ -1088,6 +1088,38 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
/// Finds all statements that assign directly to local (i.e., X = ...) and returns their
/// locations.
fn find_assignments(&self, local: Local) -> Vec<Location> {
use rustc_middle::mir::visit::Visitor;
struct FindLocalAssignmentVisitor {
needle: Local,
locations: Vec<Location>,
}
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
fn visit_local(
&mut self,
local: Local,
place_context: PlaceContext,
location: Location,
) {
if self.needle != local {
return;
}
if place_context.is_place_assignment() {
self.locations.push(location);
}
}
}
let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
visitor.visit_body(self.body);
visitor.locations
}
fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) {
let local_decl = &self.body.local_decls[local];
@ -1121,7 +1153,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
})) => {
// check if the RHS is from desugaring
let opt_assignment_rhs_span =
self.body.find_assignments(local).first().map(|&location| {
self.find_assignments(local).first().map(|&location| {
if let Some(mir::Statement {
source_info: _,
kind:

View file

@ -13,7 +13,7 @@ use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
use rustc_middle::bug;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor};
use rustc_span::{Ident, Span, kw};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@ -29,7 +29,7 @@ use tracing::{debug, instrument, trace};
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
use crate::nll::ConstraintDescription;
use crate::region_infer::values::RegionElement;
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo, TypeTest};
use crate::region_infer::{BlameConstraint, TypeTest};
use crate::session_diagnostics::{
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
@ -49,8 +49,8 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
ConstraintCategory::Cast { is_implicit_coercion: false, .. } => "cast ",
ConstraintCategory::Cast { is_implicit_coercion: true, .. } => "coercion ",
ConstraintCategory::CallArgument(_) => "argument ",
ConstraintCategory::TypeAnnotation => "type annotation ",
ConstraintCategory::ClosureBounds => "closure body ",
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => "generic argument ",
ConstraintCategory::TypeAnnotation(_) => "type annotation ",
ConstraintCategory::SizedBound => "proving this value is `Sized` ",
ConstraintCategory::CopyBound => "copying this value ",
ConstraintCategory::OpaqueType => "opaque type ",
@ -440,10 +440,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
) {
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
let (blame_constraint, extra_info) =
self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
let (blame_constraint, path) = self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
self.regioncx.provides_universal_region(r, fr, outlived_fr)
});
let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
@ -554,13 +553,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
for extra in extra_info {
match extra {
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
}
}
}
self.add_placeholder_from_predicate_note(&mut diag, &path);
self.add_sized_or_copy_bound_info(&mut diag, category, &path);
self.buffer_error(diag);
}

View file

@ -5,7 +5,7 @@ use std::fmt::{self, Display};
use std::iter;
use rustc_data_structures::fx::IndexEntry;
use rustc_errors::Diag;
use rustc_errors::{Diag, EmissionGuarantee};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_middle::ty::print::RegionHighlightMode;
@ -108,7 +108,7 @@ impl RegionName {
}
}
pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_>) {
pub(crate) fn highlight_region_name<G: EmissionGuarantee>(&self, diag: &mut Diag<'_, G>) {
match &self.source {
RegionNameSource::NamedLateParamRegion(span)
| RegionNameSource::NamedEarlyParamRegion(span) => {

View file

@ -6,6 +6,7 @@
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(file_buffered)]
#![feature(if_let_guard)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(rustc_attrs)]
@ -15,14 +16,17 @@
#![warn(unreachable_pub)]
// tidy-alphabetical-end
use std::borrow::Cow;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ops::{ControlFlow, Deref};
use rustc_abi::FieldIdx;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_errors::LintDiagnostic;
use rustc_hir as hir;
use rustc_hir::CRATE_HIR_ID;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::{BitSet, MixedBitSet};
use rustc_index::{IndexSlice, IndexVec};
@ -42,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
};
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
use rustc_session::lint::builtin::UNUSED_MUT;
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
use rustc_span::{Span, Symbol};
use smallvec::SmallVec;
use tracing::{debug, instrument};
@ -81,7 +85,6 @@ mod session_diagnostics;
mod type_check;
mod universal_regions;
mod used_muts;
mod util;
/// A public API provided for the Rust compiler consumers.
pub mod consumers;
@ -636,9 +639,11 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
| StatementKind::Coverage(..)
// These do not actually affect borrowck
| StatementKind::ConstEvalCounter
// This do not affect borrowck
| StatementKind::BackwardIncompatibleDropHint { .. }
| StatementKind::StorageLive(..) => {}
// This does not affect borrowck
StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
self.check_backward_incompatible_drop(location, (**place, span), state);
}
StatementKind::StorageDead(local) => {
self.access_place(
location,
@ -1007,6 +1012,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
}
}
fn borrows_in_scope<'s>(
&self,
location: Location,
state: &'s BorrowckDomain,
) -> Cow<'s, BitSet<BorrowIndex>> {
if let Some(polonius) = &self.polonius_output {
// Use polonius output if it has been enabled.
let location = self.location_table.start_index(location);
let mut polonius_output = BitSet::new_empty(self.borrow_set.len());
for &idx in polonius.errors_at(location) {
polonius_output.insert(idx);
}
Cow::Owned(polonius_output)
} else {
Cow::Borrowed(&state.borrows)
}
}
#[instrument(level = "debug", skip(self, state))]
fn check_access_for_conflict(
&mut self,
@ -1018,18 +1041,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
) -> bool {
let mut error_reported = false;
// Use polonius output if it has been enabled.
let mut polonius_output;
let borrows_in_scope = if let Some(polonius) = &self.polonius_output {
let location = self.location_table.start_index(location);
polonius_output = BitSet::new_empty(self.borrow_set.len());
for &idx in polonius.errors_at(location) {
polonius_output.insert(idx);
}
&polonius_output
} else {
&state.borrows
};
let borrows_in_scope = self.borrows_in_scope(location, state);
each_borrow_involving_path(
self,
@ -1054,31 +1066,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
rw,
(borrow_index, borrow),
);
Control::Continue
ControlFlow::Continue(())
}
(Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
| (
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
BorrowKind::Mut { .. },
) => Control::Continue,
) => ControlFlow::Continue(()),
(Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
// This used to be a future compatibility warning (to be
// disallowed on NLL). See rust-lang/rust#56254
Control::Continue
ControlFlow::Continue(())
}
(Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
// Handled by initialization checks.
Control::Continue
ControlFlow::Continue(())
}
(Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(this.dominators(), borrow, location) {
assert!(allow_two_phase_borrow(borrow.kind));
return Control::Continue;
assert!(borrow.kind.allows_two_phase_borrow());
return ControlFlow::Continue(());
}
error_reported = true;
@ -1094,7 +1106,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
this.buffer_error(err);
}
}
Control::Break
ControlFlow::Break(())
}
(Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
@ -1141,7 +1153,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
}
}
Control::Break
ControlFlow::Break(())
}
},
);
@ -1149,6 +1161,61 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
error_reported
}
/// Through #123739, backward incompatible drops (BIDs) are introduced.
/// We would like to emit lints whether borrow checking fails at these future drop locations.
#[instrument(level = "debug", skip(self, state))]
fn check_backward_incompatible_drop(
&mut self,
location: Location,
(place, place_span): (Place<'tcx>, Span),
state: &BorrowckDomain,
) {
let tcx = self.infcx.tcx;
// If this type does not need `Drop`, then treat it like a `StorageDead`.
// This is needed because we track the borrows of refs to thread locals,
// and we'll ICE because we don't track borrows behind shared references.
let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
AccessDepth::Drop
} else {
AccessDepth::Shallow(None)
};
let borrows_in_scope = self.borrows_in_scope(location, state);
// This is a very simplified version of `Self::check_access_for_conflict`.
// We are here checking on BIDs and specifically still-live borrows of data involving the BIDs.
each_borrow_involving_path(
self,
self.infcx.tcx,
self.body,
(sd, place),
self.borrow_set,
|borrow_index| borrows_in_scope.contains(borrow_index),
|this, _borrow_index, borrow| {
if matches!(borrow.kind, BorrowKind::Fake(_)) {
return ControlFlow::Continue(());
}
let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
let explain = this.explain_why_borrow_contains_point(
location,
borrow,
Some((WriteKind::StorageDeadOrDrop, place)),
);
this.infcx.tcx.node_span_lint(
TAIL_EXPR_DROP_ORDER,
CRATE_HIR_ID,
borrowed,
|diag| {
session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
},
);
// We may stop at the first case
ControlFlow::Break(())
},
);
}
fn mutate_place(
&mut self,
location: Location,
@ -1185,7 +1252,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
if bk.allows_two_phase_borrow() {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))

View file

@ -142,9 +142,9 @@ pub(crate) fn compute_regions<'a, 'tcx>(
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives
// constraints.
let localized_outlives_constraints = polonius_context
.as_mut()
.map(|polonius_context| polonius_context.create_localized_constraints(&mut regioncx, body));
let localized_outlives_constraints = polonius_context.as_mut().map(|polonius_context| {
polonius_context.create_localized_constraints(infcx.tcx, &regioncx, body)
});
// If requested: dump NLL facts, and run legacy polonius analysis.
let polonius_output = all_facts.as_ref().and_then(|all_facts| {

View file

@ -1,26 +1,14 @@
use std::ops::ControlFlow;
use rustc_abi::FieldIdx;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::mir::{BasicBlock, Body, BorrowKind, Location, Place, PlaceRef, ProjectionElem};
use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::TyCtxt;
use tracing::debug;
use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
use crate::{AccessDepth, BorrowIndex, places_conflict};
/// Returns `true` if the borrow represented by `kind` is
/// allowed to be split into separate Reservation and
/// Activation phases.
pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool {
kind.allows_two_phase_borrow()
}
/// Control for the path borrow checking code
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(super) enum Control {
Continue,
Break,
}
/// Encapsulates the idea of iterating over every borrow that involves a particular path
pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
s: &mut S,
@ -31,7 +19,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
is_candidate: I,
mut op: F,
) where
F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> ControlFlow<()>,
I: Fn(BorrowIndex) -> bool,
{
let (access, place) = access_place;
@ -62,7 +50,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
i, borrowed, place, access
);
let ctrl = op(s, i, borrowed);
if ctrl == Control::Break {
if matches!(ctrl, ControlFlow::Break(_)) {
return;
}
}

View file

@ -1,3 +1,5 @@
use std::ops::ControlFlow;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_middle::bug;
use rustc_middle::mir::visit::Visitor;
@ -260,7 +262,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if allow_two_phase_borrow(bk) {
if bk.allows_two_phase_borrow() {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))
@ -378,8 +380,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(this.dominators, borrow, location) {
// If the borrow isn't active yet, reads don't invalidate it
assert!(allow_two_phase_borrow(borrow.kind));
return Control::Continue;
assert!(borrow.kind.allows_two_phase_borrow());
return ControlFlow::Continue(());
}
// Unique and mutable borrows are invalidated by reads from any
@ -395,7 +397,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
this.emit_loan_invalidated_at(borrow_index, location);
}
}
Control::Continue
ControlFlow::Continue(())
},
);
}

View file

@ -37,21 +37,20 @@ mod constraints;
mod dump;
pub(crate) mod legacy;
mod liveness_constraints;
mod typeck_constraints;
use std::collections::BTreeMap;
use rustc_index::bit_set::SparseBitMatrix;
use rustc_middle::mir::{Body, Location};
use rustc_middle::ty::RegionVid;
use rustc_middle::mir::Body;
use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::points::PointIndex;
pub(crate) use self::constraints::*;
pub(crate) use self::dump::dump_polonius_mir;
use self::liveness_constraints::create_liveness_constraints;
use self::typeck_constraints::convert_typeck_constraints;
use crate::RegionInferenceContext;
use crate::constraints::OutlivesConstraint;
use crate::region_infer::values::LivenessValues;
use crate::type_check::Locations;
/// This struct holds the data needed to create the Polonius localized constraints.
pub(crate) struct PoloniusContext {
@ -88,14 +87,17 @@ impl PoloniusContext {
/// - encoding liveness constraints
pub(crate) fn create_localized_constraints<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
body: &Body<'tcx>,
) -> LocalizedOutlivesConstraintSet {
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
convert_typeck_constraints(
tcx,
body,
regioncx.liveness_constraints(),
regioncx.outlives_constraints(),
regioncx.universal_regions(),
&mut localized_outlives_constraints,
);
@ -117,38 +119,3 @@ impl PoloniusContext {
localized_outlives_constraints
}
}
/// Propagate loans throughout the subset graph at a given point (with some subtleties around the
/// location where effects start to be visible).
fn convert_typeck_constraints<'tcx>(
body: &Body<'tcx>,
liveness: &LivenessValues,
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
) {
for outlives_constraint in outlives_constraints {
match outlives_constraint.locations {
Locations::All(_) => {
// For now, turn logical constraints holding at all points into physical edges at
// every point in the graph.
// FIXME: encode this into *traversal* instead.
for (block, bb) in body.basic_blocks.iter_enumerated() {
let statement_count = bb.statements.len();
for statement_index in 0..=statement_count {
let current_location = Location { block, statement_index };
let current_point = liveness.point_from_location(current_location);
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
});
}
}
}
_ => {}
}
}
}

View file

@ -0,0 +1,241 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::mir::{Body, Location, Statement, StatementKind, Terminator, TerminatorKind};
use rustc_middle::ty::{TyCtxt, TypeVisitable};
use rustc_mir_dataflow::points::PointIndex;
use super::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
use crate::constraints::OutlivesConstraint;
use crate::region_infer::values::LivenessValues;
use crate::type_check::Locations;
use crate::universal_regions::UniversalRegions;
/// Propagate loans throughout the subset graph at a given point (with some subtleties around the
/// location where effects start to be visible).
pub(super) fn convert_typeck_constraints<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
liveness: &LivenessValues,
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
universal_regions: &UniversalRegions<'tcx>,
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
) {
for outlives_constraint in outlives_constraints {
match outlives_constraint.locations {
Locations::All(_) => {
// For now, turn logical constraints holding at all points into physical edges at
// every point in the graph.
// FIXME: encode this into *traversal* instead.
for (block, bb) in body.basic_blocks.iter_enumerated() {
let statement_count = bb.statements.len();
for statement_index in 0..=statement_count {
let current_location = Location { block, statement_index };
let current_point = liveness.point_from_location(current_location);
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
});
}
}
}
Locations::Single(location) => {
// This constraint is marked as holding at one location, we localize it to that
// location or its successor, depending on the corresponding MIR
// statement/terminator. Unfortunately, they all show up from typeck as coming "on
// entry", so for now we modify them to take effects that should apply "on exit"
// into account.
//
// FIXME: this approach is subtle, complicated, and hard to test, so we should track
// this information better in MIR typeck instead, for example with a new `Locations`
// variant that contains which node is crossing over between entry and exit.
let point = liveness.point_from_location(location);
let localized_constraint = if let Some(stmt) =
body[location.block].statements.get(location.statement_index)
{
localize_statement_constraint(
tcx,
body,
stmt,
liveness,
&outlives_constraint,
location,
point,
universal_regions,
)
} else {
assert_eq!(location.statement_index, body[location.block].statements.len());
let terminator = body[location.block].terminator();
localize_terminator_constraint(
tcx,
body,
terminator,
liveness,
&outlives_constraint,
point,
universal_regions,
)
};
localized_outlives_constraints.push(localized_constraint);
}
}
}
}
/// For a given outlives constraint arising from a MIR statement, localize the constraint with the
/// needed CFG `from`-`to` intra-block nodes.
fn localize_statement_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
stmt: &Statement<'tcx>,
liveness: &LivenessValues,
outlives_constraint: &OutlivesConstraint<'tcx>,
current_location: Location,
current_point: PointIndex,
universal_regions: &UniversalRegions<'tcx>,
) -> LocalizedOutlivesConstraint {
match &stmt.kind {
StatementKind::Assign(box (lhs, rhs)) => {
// To create localized outlives constraints without midpoints, we rely on the property
// that no input regions from the RHS of the assignment will flow into themselves: they
// should not appear in the output regions in the LHS. We believe this to be true by
// construction of the MIR, via temporaries, and assert it here.
//
// We think we don't need midpoints because:
// - every LHS Place has a unique set of regions that don't appear elsewhere
// - this implies that for them to be part of the RHS, the same Place must be read and
// written
// - and that should be impossible in MIR
//
// When we have a more complete implementation in the future, tested with crater, etc,
// we can relax this to a debug assert instead, or remove it.
assert!(
{
let mut lhs_regions = FxHashSet::default();
tcx.for_each_free_region(lhs, |region| {
let region = universal_regions.to_region_vid(region);
lhs_regions.insert(region);
});
let mut rhs_regions = FxHashSet::default();
tcx.for_each_free_region(rhs, |region| {
let region = universal_regions.to_region_vid(region);
rhs_regions.insert(region);
});
// The intersection between LHS and RHS regions should be empty.
lhs_regions.is_disjoint(&rhs_regions)
},
"there should be no common regions between the LHS and RHS of an assignment"
);
// As mentioned earlier, we should be tracking these better upstream but: we want to
// relate the types on entry to the type of the place on exit. That is, outlives
// constraints on the RHS are on entry, and outlives constraints to/from the LHS are on
// exit (i.e. on entry to the successor location).
let lhs_ty = body.local_decls[lhs.local].ty;
let successor_location = Location {
block: current_location.block,
statement_index: current_location.statement_index + 1,
};
let successor_point = liveness.point_from_location(successor_location);
compute_constraint_direction(
tcx,
outlives_constraint,
&lhs_ty,
current_point,
successor_point,
universal_regions,
)
}
_ => {
// For the other cases, we localize an outlives constraint to where it arises.
LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
}
}
}
}
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
/// needed CFG `from`-`to` inter-block nodes.
fn localize_terminator_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
terminator: &Terminator<'tcx>,
liveness: &LivenessValues,
outlives_constraint: &OutlivesConstraint<'tcx>,
current_point: PointIndex,
universal_regions: &UniversalRegions<'tcx>,
) -> LocalizedOutlivesConstraint {
// FIXME: check if other terminators need the same handling as `Call`s, in particular
// Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some
// coroutine tests, and that may be why.
match &terminator.kind {
// FIXME: also handle diverging calls.
TerminatorKind::Call { destination, target: Some(target), .. } => {
// Calls are similar to assignments, and thus follow the same pattern. If there is a
// target for the call we also relate what flows into the destination here to entry to
// that successor.
let destination_ty = destination.ty(&body.local_decls, tcx);
let successor_location = Location { block: *target, statement_index: 0 };
let successor_point = liveness.point_from_location(successor_location);
compute_constraint_direction(
tcx,
outlives_constraint,
&destination_ty,
current_point,
successor_point,
universal_regions,
)
}
_ => {
// Typeck constraints guide loans between regions at the current point, so we do that in
// the general case, and liveness will take care of making them flow to the terminator's
// successors.
LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
}
}
}
}
/// For a given outlives constraint and CFG edge, returns the localized constraint with the
/// appropriate `from`-`to` direction. This is computed according to whether the constraint flows to
/// or from a free region in the given `value`, some kind of result for an effectful operation, like
/// the LHS of an assignment.
fn compute_constraint_direction<'tcx>(
tcx: TyCtxt<'tcx>,
outlives_constraint: &OutlivesConstraint<'tcx>,
value: &impl TypeVisitable<TyCtxt<'tcx>>,
current_point: PointIndex,
successor_point: PointIndex,
universal_regions: &UniversalRegions<'tcx>,
) -> LocalizedOutlivesConstraint {
let mut to = current_point;
let mut from = current_point;
tcx.for_each_free_region(value, |region| {
let region = universal_regions.to_region_vid(region);
if region == outlives_constraint.sub {
// This constraint flows into the result, its effects start becoming visible on exit.
to = successor_point;
} else if region == outlives_constraint.sup {
// This constraint flows from the result, its effects start becoming visible on exit.
from = successor_point;
}
});
LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from,
target: outlives_constraint.sub,
to,
}
}

View file

@ -13,15 +13,16 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::bug;
use rustc_middle::mir::{
BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
TerminatorKind,
AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject,
ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location,
ReturnConstraint, TerminatorKind,
};
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::fold::fold_regions;
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex};
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_span::Span;
use rustc_span::hygiene::DesugaringKind;
use tracing::{debug, instrument, trace};
use crate::BorrowckInferCtxt;
@ -315,11 +316,6 @@ enum Trace<'tcx> {
NotVisited,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub(crate) enum ExtraConstraintInfo {
PlaceholderFromPredicate(Span),
}
#[instrument(skip(infcx, sccs), level = "debug")]
fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
use crate::renumber::RegionCtxt;
@ -978,7 +974,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
) -> bool {
let tcx = infcx.tcx;
let TypeTest { generic_kind, lower_bound, span: blame_span, ref verify_bound } = *type_test;
let TypeTest { generic_kind, lower_bound, span: blame_span, verify_bound: _ } = *type_test;
let generic_ty = generic_kind.to_ty(tcx);
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
@ -1016,25 +1012,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// For each region outlived by lower_bound find a non-local,
// universal region (it may be the same region) and add it to
// `ClosureOutlivesRequirement`.
let mut found_outlived_universal_region = false;
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
found_outlived_universal_region = true;
debug!("universal_region_outlived_by ur={:?}", ur);
// Check whether we can already prove that the "subject" outlives `ur`.
// If so, we don't have to propagate this requirement to our caller.
//
// To continue the example from the function, if we are trying to promote
// a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union
// `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here
// we check whether `T: '1` is something we *can* prove. If so, no need
// to propagate that requirement.
//
// This is needed because -- particularly in the case
// where `ur` is a local bound -- we are sometimes in a
// position to prove things that our caller cannot. See
// #53570 for an example.
if self.eval_verify_bound(infcx, generic_ty, ur, &verify_bound) {
continue;
}
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
debug!(?non_local_ub);
@ -1056,6 +1037,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
propagated_outlives_requirements.push(requirement);
}
}
// If we succeed to promote the subject, i.e. it only contains non-local regions,
// and fail to prove the type test inside of the closure, the `lower_bound` has to
// also be at least as large as some universal region, as the type test is otherwise
// trivial.
assert!(found_outlived_universal_region);
true
}
@ -1948,7 +1934,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
from_region: RegionVid,
from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool,
) -> (BlameConstraint<'tcx>, Vec<ExtraConstraintInfo>) {
) -> (BlameConstraint<'tcx>, Vec<OutlivesConstraint<'tcx>>) {
// Find all paths
let (path, target_region) = self
.find_constraint_paths_between_regions(from_region, target_test)
@ -1970,25 +1956,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
.collect::<Vec<_>>()
);
let mut extra_info = vec![];
for constraint in path.iter() {
let outlived = constraint.sub;
let Some(origin) = self.var_infos.get(outlived) else {
continue;
};
let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin
else {
continue;
};
debug!(?constraint, ?p);
let ConstraintCategory::Predicate(span) = constraint.category else {
continue;
};
extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span));
// We only want to point to one
break;
}
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
// Instead, we use it to produce an improved `ObligationCauseCode`.
// FIXME - determine what we should do if we encounter multiple
@ -2007,42 +1974,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
})
.unwrap_or_else(|| ObligationCauseCode::Misc);
// Classify each of the constraints along the path.
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
.iter()
.map(|constraint| BlameConstraint {
category: constraint.category,
from_closure: constraint.from_closure,
cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()),
variance_info: constraint.variance_info,
})
.collect();
debug!("categorized_path={:#?}", categorized_path);
// To find the best span to cite, we first try to look for the
// final constraint that is interesting and where the `sup` is
// not unified with the ultimate target region. The reason
// for this is that we have a chain of constraints that lead
// from the source to the target region, something like:
//
// '0: '1 ('0 is the source)
// '1: '2
// '2: '3
// '3: '4
// '4: '5
// '5: '6 ('6 is the target)
//
// Some of those regions are unified with `'6` (in the same
// SCC). We want to screen those out. After that point, the
// "closest" constraint we have to the end is going to be the
// most likely to be the point where the value escapes -- but
// we still want to screen for an "interesting" point to
// highlight (e.g., a call site or something).
let target_scc = self.constraint_sccs.scc(target_region);
let mut range = 0..path.len();
// As noted above, when reporting an error, there is typically a chain of constraints
// leading from some "source" region which must outlive some "target" region.
// When reporting an error, there is typically a chain of constraints leading from some
// "source" region which must outlive some "target" region.
// In most cases, we prefer to "blame" the constraints closer to the target --
// but there is one exception. When constraints arise from higher-ranked subtyping,
// we generally prefer to blame the source value,
@ -2083,78 +2016,114 @@ impl<'tcx> RegionInferenceContext<'tcx> {
| NllRegionVariableOrigin::Existential { from_forall: true } => false,
};
let find_region = |i: &usize| {
let constraint = &path[*i];
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
if blame_source {
match categorized_path[*i].category {
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal
| ConstraintCategory::Predicate(_) => false,
ConstraintCategory::TypeAnnotation
| ConstraintCategory::Return(_)
| ConstraintCategory::Yield => true,
_ => constraint_sup_scc != target_scc,
}
// To pick a constraint to blame, we organize constraints by how interesting we expect them
// to be in diagnostics, then pick the most interesting one closest to either the source or
// the target on our constraint path.
let constraint_interest = |constraint: &OutlivesConstraint<'tcx>| {
// Try to avoid blaming constraints from desugarings, since they may not clearly match
// match what users have written. As an exception, allow blaming returns generated by
// `?` desugaring, since the correspondence is fairly clear.
let category = if let Some(kind) = constraint.span.desugaring_kind()
&& (kind != DesugaringKind::QuestionMark
|| !matches!(constraint.category, ConstraintCategory::Return(_)))
{
ConstraintCategory::Boring
} else {
!matches!(
categorized_path[*i].category,
ConstraintCategory::OpaqueType
| ConstraintCategory::Boring
| ConstraintCategory::BoringNoLocation
| ConstraintCategory::Internal
| ConstraintCategory::Predicate(_)
constraint.category
};
match category {
// Returns usually provide a type to blame and have specially written diagnostics,
// so prioritize them.
ConstraintCategory::Return(_) => 0,
// Unsizing coercions are interesting, since we have a note for that:
// `BorrowExplanation::add_object_lifetime_default_note`.
// FIXME(dianne): That note shouldn't depend on a coercion being blamed; see issue
// #131008 for an example of where we currently don't emit it but should.
// Once the note is handled properly, this case should be removed. Until then, it
// should be as limited as possible; the note is prone to false positives and this
// constraint usually isn't best to blame.
ConstraintCategory::Cast {
unsize_to: Some(unsize_ty),
is_implicit_coercion: true,
} if target_region == self.universal_regions().fr_static
// Mirror the note's condition, to minimize how often this diverts blame.
&& let ty::Adt(_, args) = unsize_ty.kind()
&& args.iter().any(|arg| arg.as_type().is_some_and(|ty| ty.is_trait()))
// Mimic old logic for this, to minimize false positives in tests.
&& !path
.iter()
.any(|c| matches!(c.category, ConstraintCategory::TypeAnnotation(_))) =>
{
1
}
// Between other interesting constraints, order by their position on the `path`.
ConstraintCategory::Yield
| ConstraintCategory::UseAsConst
| ConstraintCategory::UseAsStatic
| ConstraintCategory::TypeAnnotation(
AnnotationSource::Ascription
| AnnotationSource::Declaration
| AnnotationSource::OpaqueCast,
)
| ConstraintCategory::Cast { .. }
| ConstraintCategory::CallArgument(_)
| ConstraintCategory::CopyBound
| ConstraintCategory::SizedBound
| ConstraintCategory::Assignment
| ConstraintCategory::Usage
| ConstraintCategory::ClosureUpvar(_) => 2,
// Generic arguments are unlikely to be what relates regions together
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => 3,
// We handle predicates and opaque types specially; don't prioritize them here.
ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4,
// `Boring` constraints can correspond to user-written code and have useful spans,
// but don't provide any other useful information for diagnostics.
ConstraintCategory::Boring => 5,
// `BoringNoLocation` constraints can point to user-written code, but are less
// specific, and are not used for relations that would make sense to blame.
ConstraintCategory::BoringNoLocation => 6,
// Do not blame internal constraints.
ConstraintCategory::Internal => 7,
ConstraintCategory::IllegalUniverse => 8,
}
};
let best_choice =
if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
let best_choice = if blame_source {
path.iter().enumerate().rev().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0
} else {
path.iter().enumerate().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0
};
debug!(?best_choice, ?blame_source, ?extra_info);
debug!(?best_choice, ?blame_source);
if let Some(i) = best_choice {
if let Some(next) = categorized_path.get(i + 1) {
if matches!(categorized_path[i].category, ConstraintCategory::Return(_))
&& next.category == ConstraintCategory::OpaqueType
{
// The return expression is being influenced by the return type being
// impl Trait, point at the return type and not the return expr.
return (next.clone(), extra_info);
}
let best_constraint = if let Some(next) = path.get(best_choice + 1)
&& matches!(path[best_choice].category, ConstraintCategory::Return(_))
&& next.category == ConstraintCategory::OpaqueType
{
// The return expression is being influenced by the return type being
// impl Trait, point at the return type and not the return expr.
*next
} else if path[best_choice].category == ConstraintCategory::Return(ReturnConstraint::Normal)
&& let Some(field) = path.iter().find_map(|p| {
if let ConstraintCategory::ClosureUpvar(f) = p.category { Some(f) } else { None }
})
{
OutlivesConstraint {
category: ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)),
..path[best_choice]
}
} else {
path[best_choice]
};
if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal)
{
let field = categorized_path.iter().find_map(|p| {
if let ConstraintCategory::ClosureUpvar(f) = p.category {
Some(f)
} else {
None
}
});
if let Some(field) = field {
categorized_path[i].category =
ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
}
}
return (categorized_path[i].clone(), extra_info);
}
// If that search fails, that is.. unusual. Maybe everything
// is in the same SCC or something. In that case, find what
// appears to be the most interesting point to report to the
// user via an even more ad-hoc guess.
categorized_path.sort_by_key(|p| p.category);
debug!("sorted_path={:#?}", categorized_path);
(categorized_path.remove(0), extra_info)
let blame_constraint = BlameConstraint {
category: best_constraint.category,
from_closure: best_constraint.from_closure,
cause: ObligationCause::new(best_constraint.span, CRATE_DEF_ID, cause_code.clone()),
variance_info: best_constraint.variance_info,
};
(blame_constraint, path)
}
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {

View file

@ -544,12 +544,12 @@ fn pretty_print_region_elements(elements: impl IntoIterator<Item = RegionElement
return result;
fn push_location_range(str: &mut String, location1: Location, location2: Location) {
fn push_location_range(s: &mut String, location1: Location, location2: Location) {
if location1 == location2 {
str.push_str(&format!("{location1:?}"));
s.push_str(&format!("{location1:?}"));
} else {
assert_eq!(location1.block, location2.block);
str.push_str(&format!(
s.push_str(&format!(
"{:?}[{}..={}]",
location1.block, location1.statement_index, location2.statement_index
));

View file

@ -480,3 +480,10 @@ pub(crate) struct SimdIntrinsicArgConst {
pub arg: usize,
pub intrinsic: String,
}
#[derive(LintDiagnostic)]
#[diag(borrowck_tail_expr_drop_order)]
pub(crate) struct TailExprDropOrder {
#[label]
pub borrowed: Span,
}

View file

@ -298,7 +298,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
context.ambient_variance(),
base_ty.ty,
location.to_locations(),
ConstraintCategory::TypeAnnotation,
ConstraintCategory::TypeAnnotation(AnnotationSource::OpaqueCast),
)
.unwrap();
}
@ -333,7 +333,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
ty::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
locations,
ConstraintCategory::Boring,
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg),
) {
let annotation = &self.typeck.user_type_annotations[annotation_index];
span_mirbug!(
@ -455,7 +455,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
ty::Invariant,
user_ty,
Locations::All(*span),
ConstraintCategory::TypeAnnotation,
ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration),
) {
span_mirbug!(
self,
@ -892,6 +892,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Some(l) if !body.local_decls[l].is_user_variable() => {
ConstraintCategory::Boring
}
Some(_)
if let Some(body_id) = tcx
.hir_node_by_def_id(body.source.def_id().expect_local())
.body_id()
&& let params = tcx.hir().body(body_id).params
&& params
.iter()
.any(|param| param.span.contains(stmt.source_info.span)) =>
{
// Assignments generated from lowering argument patterns shouldn't be called
// "assignments" in diagnostics and aren't interesting to blame for errors.
ConstraintCategory::Boring
}
_ => ConstraintCategory::Assignment,
};
debug!(
@ -927,7 +940,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ty::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
location.to_locations(),
ConstraintCategory::Boring,
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg),
) {
let annotation = &self.user_type_annotations[annotation_index];
span_mirbug!(
@ -962,7 +975,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
*variance,
projection,
Locations::All(stmt.source_info.span),
ConstraintCategory::TypeAnnotation,
ConstraintCategory::TypeAnnotation(AnnotationSource::Ascription),
) {
let annotation = &self.user_type_annotations[projection.base];
span_mirbug!(
@ -1226,6 +1239,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Some(l) if !body.local_decls[l].is_user_variable() => {
ConstraintCategory::Boring
}
// The return type of a call is interesting for diagnostics.
_ => ConstraintCategory::Assignment,
};
@ -2169,7 +2183,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ty_left,
common_ty,
location.to_locations(),
ConstraintCategory::Boring,
ConstraintCategory::CallArgument(None),
)
.unwrap_or_else(|err| {
bug!("Could not equate type variable with {:?}: {:?}", ty_left, err)
@ -2178,7 +2192,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ty_right,
common_ty,
location.to_locations(),
ConstraintCategory::Boring,
ConstraintCategory::CallArgument(None),
) {
span_mirbug!(
self,

View file

@ -1,35 +0,0 @@
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location};
pub(crate) trait FindAssignments {
// Finds all statements that assign directly to local (i.e., X = ...)
// and returns their locations.
fn find_assignments(&self, local: Local) -> Vec<Location>;
}
impl<'tcx> FindAssignments for Body<'tcx> {
fn find_assignments(&self, local: Local) -> Vec<Location> {
let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
visitor.visit_body(self);
visitor.locations
}
}
// The Visitor walks the MIR to return the assignment statements corresponding
// to a Local.
struct FindLocalAssignmentVisitor {
needle: Local,
locations: Vec<Location>,
}
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
if self.needle != local {
return;
}
if place_context.is_place_assignment() {
self.locations.push(location);
}
}
}

View file

@ -1,3 +0,0 @@
mod collect_writes;
pub(crate) use collect_writes::FindAssignments;

View file

@ -56,11 +56,6 @@ jobs:
- os: macos-latest
env:
TARGET_TRIPLE: x86_64-apple-darwin
# cross-compile from Linux to Windows using mingw
- os: ubuntu-latest
env:
TARGET_TRIPLE: x86_64-pc-windows-gnu
apt_deps: gcc-mingw-w64-x86-64 wine-stable
- os: ubuntu-latest
env:
TARGET_TRIPLE: aarch64-unknown-linux-gnu
@ -113,15 +108,6 @@ jobs:
- name: Prepare dependencies
run: ./y.sh prepare
# The Wine version shipped with Ubuntu 22.04 doesn't implement bcryptprimitives.dll
- name: Build bcryptprimitives.dll shim for Wine
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: |
rustup target add x86_64-pc-windows-gnu
mkdir wine_shims
rustc patches/bcryptprimitives.rs -Copt-level=3 -Clto=fat --out-dir wine_shims --target x86_64-pc-windows-gnu
echo "WINEPATH=$(pwd)/wine_shims" >> $GITHUB_ENV
- name: Build
run: ./y.sh build --sysroot none
@ -135,9 +121,6 @@ jobs:
# This is roughly config rust-lang/rust uses for testing
- name: Test with LLVM sysroot
# Skip native x86_64-pc-windows-gnu. It is way too slow and cross-compiled
# x86_64-pc-windows-gnu covers at least part of the tests.
if: matrix.os != 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
env:
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
run: ./y.sh test --sysroot llvm --no-unstable-features
@ -215,10 +198,6 @@ jobs:
- os: macos-latest
env:
TARGET_TRIPLE: aarch64-apple-darwin
# cross-compile from Linux to Windows using mingw
- os: ubuntu-latest
env:
TARGET_TRIPLE: x86_64-pc-windows-gnu
- os: windows-latest
env:
TARGET_TRIPLE: x86_64-pc-windows-msvc
@ -243,12 +222,6 @@ jobs:
if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
run: rustup set default-host x86_64-apple-darwin
- name: Install MinGW toolchain
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-mingw-w64-x86-64
- name: Prepare dependencies
run: ./y.sh prepare
@ -262,19 +235,11 @@ jobs:
run: tar cvfJ cg_clif.tar.xz dist
- name: Upload prebuilt cg_clif
if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
uses: actions/upload-artifact@v4
with:
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
path: cg_clif.tar.xz
- name: Upload prebuilt cg_clif (cross compile)
if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
uses: actions/upload-artifact@v4
with:
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
path: cg_clif.tar.xz
release:
runs-on: ubuntu-latest
timeout-minutes: 10

View file

@ -3,22 +3,16 @@
version = 4
[[package]]
name = "ahash"
version = "0.8.11"
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "anyhow"
version = "1.0.86"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
[[package]]
name = "arbitrary"
@ -37,6 +31,9 @@ name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
dependencies = [
"allocator-api2",
]
[[package]]
name = "cfg-if"
@ -46,24 +43,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1"
checksum = "ac89549be94911dd0e839b4a7db99e9ed29c17517e1c026f61066884c168aa3c"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-bitset"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156"
checksum = "b9bd49369f76c77e34e641af85d0956869237832c118964d08bf5f51f210875a"
[[package]]
name = "cranelift-codegen"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b"
checksum = "fd96ce9cf8efebd7f5ab8ced5a0ce44250280bbae9f593d74a6d7effc3582a35"
dependencies = [
"bumpalo",
"cranelift-bforest",
@ -74,7 +71,7 @@ dependencies = [
"cranelift-entity",
"cranelift-isle",
"gimli",
"hashbrown",
"hashbrown 0.14.5",
"log",
"regalloc2",
"rustc-hash",
@ -85,42 +82,42 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7"
checksum = "5a68e358827afe4bfb6239fcbf6fbd5ac56206ece8a99c8f5f9bbd518773281a"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895"
checksum = "e184c9767afbe73d50c55ec29abcf4c32f9baf0d9d22b86d58c4d55e06dee181"
[[package]]
name = "cranelift-control"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec"
checksum = "5cc7664f2a66f053e33f149e952bb5971d138e3af637f5097727ed6dc0ed95dd"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96"
checksum = "118597e3a9cf86c3556fa579a7a23b955fa18231651a52a77a2475d305a9cf84"
dependencies = [
"cranelift-bitset",
]
[[package]]
name = "cranelift-frontend"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e"
checksum = "7638ea1efb069a0aa18d8ee67401b6b0d19f6bfe5de5e9ede348bfc80bb0d8c7"
dependencies = [
"cranelift-codegen",
"log",
@ -130,15 +127,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8"
checksum = "15c53e1152a0b01c4ed2b1e0535602b8e86458777dd9d18b28732b16325c7dc0"
[[package]]
name = "cranelift-jit"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62699329d4ced20fe281fbaef45e11b473b7ab310491b4bdebcd8b818a8ef7fe"
checksum = "36972cab12ff246afe8d45b6a427669cf814bd393c661e5e8a8dedc26a81c73f"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -156,9 +153,9 @@ dependencies = [
[[package]]
name = "cranelift-module"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f20b0b51ba962dac30fc7e812b86e4390d908acd4f59bcc8ac7610a8f3e0977"
checksum = "11841b3f54ac480db1e8e8d5678ba901a13b387012d315e3f8fba3e7b7a80447"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -167,9 +164,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f"
checksum = "7b7d8f895444fa52dd7bdd0bed11bf007a7fb43af65a6deac8fcc4094c6372f7"
dependencies = [
"cranelift-codegen",
"libc",
@ -178,9 +175,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
version = "0.114.0"
version = "0.115.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee231640a7ecceedd0f1f2782d9288db6a6908cc70675ed9427e3bf0ea6daacd"
checksum = "8e235ddfd19f100855ad03358c7ae0a13070c38a000701054cab46458cca6e81"
dependencies = [
"anyhow",
"cranelift-codegen",
@ -212,6 +209,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "foldhash"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
[[package]]
name = "gimli"
version = "0.31.1"
@ -228,18 +231,24 @@ name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"ahash",
"foldhash",
]
[[package]]
name = "indexmap"
version = "2.2.6"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown",
"hashbrown 0.15.2",
]
[[package]]
@ -281,27 +290,21 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "object"
version = "0.36.2"
version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
dependencies = [
"crc32fast",
"hashbrown",
"hashbrown 0.15.2",
"indexmap",
"memchr",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "proc-macro2"
version = "1.0.86"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
@ -317,14 +320,15 @@ dependencies = [
[[package]]
name = "regalloc2"
version = "0.10.2"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0"
checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3"
dependencies = [
"hashbrown",
"allocator-api2",
"bumpalo",
"hashbrown 0.15.2",
"log",
"rustc-hash",
"slice-group-by",
"smallvec",
]
@ -366,30 +370,24 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.210"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.210"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "slice-group-by"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
[[package]]
name = "smallvec"
version = "1.13.2"
@ -404,9 +402,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "syn"
version = "2.0.70"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
@ -425,17 +423,11 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "27.0.0"
version = "28.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad"
checksum = "d40d7722b9e1fbeae135715710a8a2570b1e6cf72b74dd653962d89831c6c70d"
dependencies = [
"anyhow",
"cfg-if",
@ -524,23 +516,3 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -8,12 +8,12 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
cranelift-codegen = { version = "0.114.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
cranelift-frontend = { version = "0.114.0" }
cranelift-module = { version = "0.114.0" }
cranelift-native = { version = "0.114.0" }
cranelift-jit = { version = "0.114.0", optional = true }
cranelift-object = { version = "0.114.0" }
cranelift-codegen = { version = "0.115.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
cranelift-frontend = { version = "0.115.0" }
cranelift-module = { version = "0.115.0" }
cranelift-native = { version = "0.115.0" }
cranelift-jit = { version = "0.115.0", optional = true }
cranelift-object = { version = "0.115.0" }
target-lexicon = "0.12.0"
gimli = { version = "0.31", default-features = false, features = ["write"] }
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }

View file

@ -16,11 +16,7 @@ static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
"<none>",
);
pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
benchmark_simple_raytracer(dirs, bootstrap_host_compiler);
}
fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) {
if std::process::Command::new("hyperfine").output().is_err() {
eprintln!("Hyperfine not installed");
eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine");
@ -39,9 +35,9 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
};
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
let cargo_clif = dirs
.dist_dir
.join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-"));
let cargo_clif = &compiler.cargo;
let rustc_clif = &compiler.rustc;
let rustflags = &compiler.rustflags.join("\x1f");
let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml");
let target_dir = dirs.build_dir.join("simple_raytracer");
@ -56,22 +52,24 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
target_dir = target_dir.display(),
);
let clif_build_cmd = format!(
"RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif",
"RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif",
cargo_clif = cargo_clif.display(),
rustc_clif = rustc_clif.display(),
manifest_path = manifest_path.display(),
target_dir = target_dir.display(),
);
let clif_build_opt_cmd = format!(
"RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt",
"RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt",
cargo_clif = cargo_clif.display(),
rustc_clif = rustc_clif.display(),
manifest_path = manifest_path.display(),
target_dir = target_dir.display(),
);
let bench_compile_markdown = dirs.dist_dir.join("bench_compile.md");
let bench_compile_markdown = dirs.build_dir.join("bench_compile.md");
let bench_compile = hyperfine_command(
1,
0,
bench_runs,
Some(&clean_cmd),
&[
@ -92,23 +90,14 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
let bench_run_markdown = dirs.dist_dir.join("bench_run.md");
let bench_run_markdown = dirs.build_dir.join("bench_run.md");
let raytracer_cg_llvm = Path::new(".").join(get_file_name(
&bootstrap_host_compiler.rustc,
"raytracer_cg_llvm",
"bin",
));
let raytracer_cg_clif = Path::new(".").join(get_file_name(
&bootstrap_host_compiler.rustc,
"raytracer_cg_clif",
"bin",
));
let raytracer_cg_clif_opt = Path::new(".").join(get_file_name(
&bootstrap_host_compiler.rustc,
"raytracer_cg_clif_opt",
"bin",
));
let raytracer_cg_llvm =
Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin"));
let raytracer_cg_clif =
Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin"));
let raytracer_cg_clif_opt =
Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin"));
let mut bench_run = hyperfine_command(
0,
bench_runs,

View file

@ -33,23 +33,3 @@ pub(crate) fn get_bool(name: &str) -> bool {
true
}
}
pub(crate) fn get_value(name: &str) -> Option<String> {
let values = load_config_file()
.into_iter()
.filter(|(key, _)| key == name)
.map(|(_, val)| val)
.collect::<Vec<_>>();
if values.is_empty() {
None
} else if values.len() == 1 {
if values[0].is_none() {
eprintln!("Config `{}` missing value", name);
process::exit(1);
}
values.into_iter().next().unwrap()
} else {
eprintln!("Config `{}` given multiple values: {:?}", name, values);
process::exit(1);
}
}

View file

@ -156,10 +156,8 @@ fn main() {
let cargo = rustc_info::get_cargo_path();
let rustc = rustc_info::get_rustc_path();
let rustdoc = rustc_info::get_rustdoc_path();
let triple = std::env::var("HOST_TRIPLE")
.ok()
.or_else(|| config::get_value("host"))
.unwrap_or_else(|| rustc_info::get_host_triple(&rustc));
let triple =
std::env::var("HOST_TRIPLE").unwrap_or_else(|_| rustc_info::get_host_triple(&rustc));
Compiler {
cargo,
rustc,
@ -170,10 +168,8 @@ fn main() {
runner: vec![],
}
};
let target_triple = std::env::var("TARGET_TRIPLE")
.ok()
.or_else(|| config::get_value("target"))
.unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
let target_triple =
std::env::var("TARGET_TRIPLE").unwrap_or_else(|_| bootstrap_host_compiler.triple.clone());
let dirs = path::Dirs {
source_dir: current_dir.clone(),
@ -247,7 +243,7 @@ fn main() {
);
}
Command::Bench => {
build_sysroot::build_sysroot(
let compiler = build_sysroot::build_sysroot(
&dirs,
sysroot_kind,
&cg_clif_dylib,
@ -255,7 +251,7 @@ fn main() {
rustup_toolchain_name.as_deref(),
target_triple,
);
bench::benchmark(&dirs, &bootstrap_host_compiler);
bench::benchmark(&dirs, &compiler);
}
}
}

View file

@ -11,20 +11,11 @@ pub(crate) struct Dirs {
#[doc(hidden)]
#[derive(Debug, Copy, Clone)]
pub(crate) enum PathBase {
enum PathBase {
Source,
Build,
}
impl PathBase {
fn to_path(self, dirs: &Dirs) -> PathBuf {
match self {
PathBase::Source => dirs.source_dir.clone(),
PathBase::Build => dirs.build_dir.clone(),
}
}
}
#[derive(Debug, Copy, Clone)]
pub(crate) struct RelPath {
base: PathBase,
@ -41,6 +32,9 @@ impl RelPath {
}
pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
self.base.to_path(dirs).join(self.suffix)
match self.base {
PathBase::Source => dirs.source_dir.join(self.suffix),
PathBase::Build => dirs.build_dir.join(self.suffix),
}
}
}

View file

@ -1,15 +1,5 @@
# This file allows configuring the build system.
# Which triple to produce a compiler toolchain for.
#
# Defaults to the default triple of rustc on the host system.
#host = x86_64-unknown-linux-gnu
# Which triple to build libraries (core/alloc/std/test/proc_macro) for.
#
# Defaults to `host`.
#target = x86_64-unknown-linux-gnu
# Disables cleaning of the sysroot dir. This will cause old compiled artifacts to be re-used when
# the sysroot source hasn't changed. This is useful when the codegen backend hasn't been modified.
# This option can be changed while the build system is already running for as long as sysroot

View file

@ -1,22 +0,0 @@
// Shim for bcryptprimitives.dll. The Wine version shipped with Ubuntu 22.04
// doesn't support it yet. Authored by @ChrisDenton
#![crate_type = "cdylib"]
#![allow(nonstandard_style)]
#[no_mangle]
pub unsafe extern "system" fn ProcessPrng(mut pbData: *mut u8, mut cbData: usize) -> i32 {
while cbData > 0 {
let size = core::cmp::min(cbData, u32::MAX as usize);
RtlGenRandom(pbData, size as u32);
cbData -= size;
pbData = pbData.add(size);
}
1
}
#[link(name = "advapi32")]
extern "system" {
#[link_name = "SystemFunction036"]
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
}

View file

@ -1,4 +1,4 @@
[toolchain]
channel = "nightly-2024-12-06"
channel = "nightly-2025-01-05"
components = ["rust-src", "rustc-dev", "llvm-tools"]
profile = "minimal"

View file

@ -123,12 +123,17 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same
rm tests/ui/consts/issue-33537.rs # same
rm tests/ui/consts/const-mut-refs-crate.rs # same
rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift
rm tests/ui/invalid-compile-flags/crate-type-flag.rs # warning about proc-macros and panic=abort
# doesn't work due to the way the rustc test suite is invoked.
# should work when using ./x.py test the way it is intended
# ============================================================
rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
rm -r tests/run-make/strip # same
rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source
rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features
rm -r tests/run-make/const-trait-stable-toolchain # same
rm -r tests/run-make/incr-add-rust-src-component
# genuine bugs
# ============
@ -196,5 +201,5 @@ index e7ae773ffa1d3..04bc2d7787da7 100644
EOF
echo "[TEST] rustc test suite"
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,ui,incremental}
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
popd

View file

@ -333,10 +333,9 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
let mut builder =
ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
// Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
// is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
// can easily double the amount of time necessary to perform linking.
builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false));
builder.per_function_section(
sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections),
);
UnwindModule::new(ObjectModule::new(builder), true)
}

View file

@ -287,7 +287,7 @@ fn dep_symbol_lookup_fn(
let mut dylib_paths = Vec::new();
let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable].1;
let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable];
// `used_crates` is in reverse postorder in terms of dependencies. Reverse the order here to
// get a postorder which ensures that all dependencies of a dylib are loaded before the dylib
// itself. This helps the dynamic linker to find dylibs not in the regular dynamic library

View file

@ -136,7 +136,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
fx.bcx.ins().jump(destination_block, &[]);
}
None => {
fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap());
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
}
}
}

View file

@ -1136,7 +1136,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
_ => {
fx.tcx.dcx().span_err(span, format!("Unknown SIMD intrinsic {}", intrinsic));
// Prevent verifier error
fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap());
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
return;
}
}

View file

@ -27,6 +27,8 @@ extern crate rustc_metadata;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
#[macro_use]
extern crate tracing;
// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
@ -208,6 +210,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
need_metadata_module: bool,
) -> Box<dyn Any> {
tcx.dcx().abort_if_errors();
info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE));
let config = self.config.clone().unwrap_or_else(|| {
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
.unwrap_or_else(|err| tcx.sess.dcx().fatal(err))

View file

@ -660,9 +660,7 @@ pub unsafe fn optimize_thin_module(
{
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule));
}
unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) };
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
}

View file

@ -28,6 +28,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
#[diag(codegen_gcc_forbidden_ctarget_feature)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}

View file

@ -1,9 +1,11 @@
use std::iter::FromIterator;
#[cfg(feature = "master")]
use gccjit::Context;
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::bug;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::unord::UnordSet;
use rustc_session::Session;
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
use smallvec::{SmallVec, smallvec};
@ -37,82 +39,137 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
let mut features = vec![];
// Features implied by an implicit or explicit `--target`.
features.extend(
sess.target
.features
.split(',')
.filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
.map(String::from),
);
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
// -Ctarget-features
let known_features = sess.target.rust_target_features();
let mut featsmap = FxHashMap::default();
let feats = sess
.opts
.cg
.target_feature
.split(',')
.filter_map(|s| {
let enable_disable = match s.chars().next() {
None => return None,
Some(c @ ('+' | '-')) => c,
Some(_) => {
if diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
}
return None;
}
};
// Get the backend feature name, if any.
// This excludes rustc-specific features, that do not get passed down to GCC.
let feature = backend_feature_name(s)?;
// Warn against use of GCC specific feature names on the CLI.
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
// are disabled.
let abi_feature_constraints = sess.target.abi_required_features();
let abi_incompatible_set =
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
.to_sorted_stable_ord()
.iter()
.map(|&&s| (true, s)),
)
} else if let Some(feature) = feature.strip_prefix('-') {
// FIXME: Why do we not remove implied features on "-" here?
// We do the equivalent above in `target_features_cfg`.
// See <https://github.com/rust-lang/rust/issues/134792>.
all_rust_features.push((false, feature));
} else if !feature.is_empty() {
if diagnostics {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
match feature_state {
None => {
let rust_feature =
known_features.iter().find_map(|&(rust_feature, _, _)| {
let gcc_features = to_gcc_features(sess, rust_feature);
if gcc_features.contains(&feature)
&& !gcc_features.contains(&rust_feature)
{
Some(rust_feature)
} else {
None
}
});
let unknown_feature = if let Some(rust_feature) = rust_feature {
UnknownCTargetFeature {
feature,
rust_feature: PossibleFeature::Some { rust_feature },
}
} else {
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
};
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
if let Err(reason) =
stability.toggle_allowed(&sess.target, enable_disable == '+')
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
}
}
}
// Remove features that are meant for rustc, not codegen.
all_rust_features.retain(|(_, feature)| {
// Retain if it is not a rustc feature
!RUSTC_SPECIFIC_FEATURES.contains(feature)
});
// Check feature validity.
if diagnostics {
for &(enable, feature) in &all_rust_features {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
match feature_state {
None => {
let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| {
let gcc_features = to_gcc_features(sess, rust_feature);
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature)
{
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. (It makes little sense
// to hard-error here since we just warn about fully unknown
// features above).
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
Some(rust_feature)
} else {
None
}
});
let unknown_feature = if let Some(rust_feature) = rust_feature {
UnknownCTargetFeature {
feature,
rust_feature: PossibleFeature::Some { rust_feature },
}
} else {
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
};
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. (It makes little sense
// to hard-error here since we just warn about fully unknown
// features above).
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
}
// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable_disable == '+');
}
// ... otherwise though we run through `to_gcc_features` when
// Ensure that the features we enable/disable are compatible with the ABI.
if enable {
if abi_incompatible_set.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "enabled",
reason: "this feature is incompatible with the target ABI",
});
}
} else {
// FIXME: we have to request implied features here since
// negative features do not handle implied features above.
for &required in abi_feature_constraints.required.iter() {
let implied = sess.target.implied_target_features(std::iter::once(required));
if implied.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "disabled",
reason: "this feature is required by the target ABI",
});
}
}
}
// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable);
}
}
// To be sure the ABI-relevant features are all in the right state, we explicitly
// (un)set them here. This means if the target spec sets those features wrong,
// we will silently correct them rather than silently producing wrong code.
// (The target sanity check tries to catch this, but we can't know which features are
// enabled in GCC by default so we can't be fully sure about that check.)
// We add these at the beginning of the list so that `-Ctarget-features` can
// still override it... that's unsound, but more compatible with past behavior.
all_rust_features.splice(
0..0,
abi_feature_constraints
.required
.iter()
.map(|&f| (true, f))
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
);
// Translate this into GCC features.
let feats = all_rust_features
.iter()
.filter_map(|&(enable, feature)| {
let enable_disable = if enable { '+' } else { '-' };
// We run through `to_gcc_features` when
// passing requests down to GCC. This means that all in-language
// features also work on the command line instead of having two
// different names when the GCC name and the Rust name differ.
@ -146,26 +203,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
features
}
/// Returns a feature name for the given `+feature` or `-feature` string.
///
/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
fn backend_feature_name(s: &str) -> Option<&str> {
// features must start with a `+` or `-`.
let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| {
bug!("target feature `{}` must begin with a `+` or `-`", s);
});
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
// are not passed down to GCC.
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
return None;
}
Some(feature)
}
// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
match (arch, s) {
// FIXME: seems like x87 does not exist?
("x86", "x87") => smallvec![],
("x86", "sse4.2") => smallvec!["sse4.2", "crc32"],
("x86", "pclmulqdq") => smallvec!["pclmul"],
("x86", "rdrand") => smallvec!["rdrnd"],

View file

@ -9,6 +9,7 @@ test = false
[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
gimli = "0.30"
itertools = "0.12"
libc = "0.2"
measureme = "11"

View file

@ -10,7 +10,7 @@ codegen_llvm_dynamic_linking_with_lto =
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
codegen_llvm_forbidden_ctarget_feature =
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
@ -24,8 +24,6 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two =
codegen_llvm_invalid_minimum_alignment_too_large =
invalid minimum global alignment: {$align} is too large
codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`"
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}

View file

@ -737,11 +737,7 @@ pub(crate) unsafe fn optimize_thin_module(
{
let _timer =
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
if unsafe {
!llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target)
} {
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
}
unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) };
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
}

View file

@ -0,0 +1,37 @@
//! Definitions of various DWARF-related constants.
use libc::c_uint;
/// Helper macro to let us redeclare gimli's constants as our own constants
/// with a different type, with less risk of copy-paste errors.
macro_rules! declare_constant {
(
$name:ident : $type:ty
) => {
#[allow(non_upper_case_globals)]
pub(crate) const $name: $type = ::gimli::constants::$name.0 as $type;
// Assert that as-cast probably hasn't changed the value.
const _: () = assert!($name as i128 == ::gimli::constants::$name.0 as i128);
};
}
declare_constant!(DW_TAG_const_type: c_uint);
// DWARF languages.
declare_constant!(DW_LANG_Rust: c_uint);
// DWARF attribute type encodings.
declare_constant!(DW_ATE_boolean: c_uint);
declare_constant!(DW_ATE_float: c_uint);
declare_constant!(DW_ATE_signed: c_uint);
declare_constant!(DW_ATE_unsigned: c_uint);
declare_constant!(DW_ATE_UTF: c_uint);
// DWARF expression operators.
declare_constant!(DW_OP_deref: u64);
declare_constant!(DW_OP_plus_uconst: u64);
/// Defined by LLVM in `llvm/include/llvm/BinaryFormat/Dwarf.h`.
/// Double-checked by a static assertion in `RustWrapper.cpp`.
#[allow(non_upper_case_globals)]
pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000;

View file

@ -22,6 +22,7 @@ use rustc_target::spec::DebuginfoKind;
use smallvec::smallvec;
use tracing::{debug, instrument};
pub(crate) use self::type_map::TypeMap;
use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId};
use super::CodegenUnitDebugContext;
use super::namespace::mangled_name_of_instance;
@ -30,6 +31,7 @@ use super::utils::{
DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit,
};
use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::dwarf_const;
use crate::debuginfo::metadata::type_map::build_type_with_children;
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
use crate::llvm::debuginfo::{
@ -59,23 +61,6 @@ impl fmt::Debug for llvm::Metadata {
}
}
// From DWARF 5.
// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1.
const DW_LANG_RUST: c_uint = 0x1c;
#[allow(non_upper_case_globals)]
const DW_ATE_boolean: c_uint = 0x02;
#[allow(non_upper_case_globals)]
const DW_ATE_float: c_uint = 0x04;
#[allow(non_upper_case_globals)]
const DW_ATE_signed: c_uint = 0x05;
#[allow(non_upper_case_globals)]
const DW_ATE_unsigned: c_uint = 0x07;
#[allow(non_upper_case_globals)]
const DW_ATE_UTF: c_uint = 0x10;
#[allow(non_upper_case_globals)]
const DW_TAG_const_type: c_uint = 0x26;
pub(super) const UNKNOWN_LINE_NUMBER: c_uint = 0;
pub(super) const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
@ -90,8 +75,6 @@ type SmallVec<T> = smallvec::SmallVec<[T; 16]>;
mod enums;
mod type_map;
pub(crate) use type_map::TypeMap;
/// Returns from the enclosing function if the type debuginfo node with the given
/// unique ID can be found in the type map.
macro_rules! return_if_di_node_created_in_meantime {
@ -522,7 +505,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D
name.as_c_char_ptr(),
name.len(),
cx.tcx.data_layout.pointer_size.bits(),
DW_ATE_unsigned,
dwarf_const::DW_ATE_unsigned,
)
}
})
@ -781,6 +764,8 @@ fn build_basic_type_di_node<'ll, 'tcx>(
// .natvis visualizers (and perhaps other existing native debuggers?)
let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
use dwarf_const::{DW_ATE_UTF, DW_ATE_boolean, DW_ATE_float, DW_ATE_signed, DW_ATE_unsigned};
let (name, encoding) = match t.kind() {
ty::Never => ("!", DW_ATE_unsigned),
ty::Tuple(elements) if elements.is_empty() => {
@ -961,7 +946,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
debug_context.builder,
DW_LANG_RUST,
dwarf_const::DW_LANG_Rust,
compile_unit_file,
producer.as_c_char_ptr(),
producer.len(),

View file

@ -12,12 +12,13 @@ use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
use smallvec::smallvec;
use crate::common::{AsCCharPtr, CodegenCx};
use crate::debuginfo::dwarf_const::DW_TAG_const_type;
use crate::debuginfo::metadata::enums::DiscrResult;
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
use crate::debuginfo::metadata::{
DINodeCreationResult, DW_TAG_const_type, NO_GENERICS, NO_SCOPE_METADATA, SmallVec,
UNKNOWN_LINE_NUMBER, build_field_di_node, file_metadata, file_metadata_from_def_id,
size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags,
DINodeCreationResult, NO_GENERICS, NO_SCOPE_METADATA, SmallVec, UNKNOWN_LINE_NUMBER,
build_field_di_node, file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
unknown_file_metadata, visibility_di_flags,
};
use crate::debuginfo::utils::DIB;
use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};

View file

@ -39,6 +39,7 @@ use crate::llvm::debuginfo::{
use crate::value::Value;
mod create_scope_map;
mod dwarf_const;
mod gdb;
pub(crate) mod metadata;
mod namespace;
@ -47,6 +48,10 @@ mod utils;
use self::create_scope_map::compute_mir_scopes;
pub(crate) use self::metadata::build_global_var_di_node;
// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were
// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp`
// to decide which C++ API to call. Instead, we should just have two separate
// FFI functions and choose the correct one on the Rust side.
#[allow(non_upper_case_globals)]
const DW_TAG_auto_variable: c_uint = 0x100;
#[allow(non_upper_case_globals)]
@ -152,29 +157,26 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
indirect_offsets: &[Size],
fragment: Option<Range<Size>>,
) {
use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
// Convert the direct and indirect offsets and fragment byte range to address ops.
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
// the values should match the ones in the DWARF standard anyway.
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
let op_llvm_fragment = || unsafe { llvm::LLVMRustDIBuilderCreateOpLLVMFragment() };
let mut addr_ops = SmallVec::<[u64; 8]>::new();
if direct_offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
addr_ops.push(DW_OP_plus_uconst);
addr_ops.push(direct_offset.bytes() as u64);
}
for &offset in indirect_offsets {
addr_ops.push(op_deref());
addr_ops.push(DW_OP_deref);
if offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
addr_ops.push(DW_OP_plus_uconst);
addr_ops.push(offset.bytes() as u64);
}
}
if let Some(fragment) = fragment {
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
// offset and size, both of them in bits.
addr_ops.push(op_llvm_fragment());
addr_ops.push(DW_OP_LLVM_fragment);
addr_ops.push(fragment.start.bits() as u64);
addr_ops.push((fragment.end - fragment.start).bits() as u64);
}

View file

@ -37,6 +37,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
@ -213,12 +214,6 @@ pub(crate) struct MismatchedDataLayout<'a> {
pub llvm_layout: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_invalid_target_feature_prefix)]
pub(crate) struct InvalidTargetFeaturePrefix<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_fixed_x18_invalid_arch)]
pub(crate) struct FixedX18InvalidArch<'a> {

View file

@ -2177,9 +2177,6 @@ unsafe extern "C" {
Location: &'a DILocation,
BD: c_uint,
) -> Option<&'a DILocation>;
pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
@ -2377,7 +2374,7 @@ unsafe extern "C" {
Data: &ThinLTOData,
Module: &Module,
Target: &TargetMachine,
) -> bool;
);
pub fn LLVMRustPrepareThinLTOResolveWeak(Data: &ThinLTOData, Module: &Module) -> bool;
pub fn LLVMRustPrepareThinLTOInternalize(Data: &ThinLTOData, Module: &Module) -> bool;
pub fn LLVMRustPrepareThinLTOImport(

View file

@ -21,8 +21,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU
use crate::back::write::create_informational_target_machine;
use crate::errors::{
FixedX18InvalidArch, ForbiddenCTargetFeature, InvalidTargetFeaturePrefix, PossibleFeature,
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
};
use crate::llvm;
@ -109,7 +109,10 @@ unsafe fn configure_llvm(sess: &Session) {
add("-wasm-enable-eh", false);
}
if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
if sess.target.os == "emscripten"
&& !sess.opts.unstable_opts.emscripten_wasm_eh
&& sess.panic_strategy() == PanicStrategy::Unwind
{
add("-enable-emscripten-cxx-exceptions", false);
}
@ -348,7 +351,16 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
{
if enabled {
// Also add all transitively implied features.
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
// We don't care about the order in `features` since the only thing we use it for is the
// `features.contains` below.
#[allow(rustc::potential_query_instability)]
features.extend(
sess.target
.implied_target_features(std::iter::once(feature.as_str()))
.iter()
.map(|s| Symbol::intern(s)),
);
} else {
// Remove transitively reverse-implied features.
@ -356,7 +368,11 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
// `features.contains` below.
#[allow(rustc::potential_query_instability)]
features.retain(|f| {
if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) {
if sess
.target
.implied_target_features(std::iter::once(f.as_str()))
.contains(&feature.as_str())
{
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
// remove `f`. (This is the standard logical contraposition principle.)
false
@ -638,7 +654,7 @@ pub(crate) fn global_llvm_features(
sess.target
.features
.split(',')
.filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
.filter(|v| !v.is_empty())
// Drop +v8plus feature introduced in LLVM 20.
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
.map(String::from),
@ -651,89 +667,136 @@ pub(crate) fn global_llvm_features(
// -Ctarget-features
if !only_base_features {
let known_features = sess.target.rust_target_features();
// Will only be filled when `diagnostics` is set!
let mut featsmap = FxHashMap::default();
// insert implied features
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
// are disabled.
let abi_feature_constraints = sess.target.abi_required_features();
let abi_incompatible_set =
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
match feature.strip_prefix('+') {
Some(feature) => all_rust_features.extend(
UnordSet::from(
sess.target
.implied_target_features(std::iter::once(Symbol::intern(feature))),
)
.to_sorted_stable_ord()
.iter()
.map(|s| format!("+{}", s.as_str())),
),
_ => all_rust_features.push(feature.to_string()),
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
.to_sorted_stable_ord()
.iter()
.map(|&&s| (true, s)),
)
} else if let Some(feature) = feature.strip_prefix('-') {
// FIXME: Why do we not remove implied features on "-" here?
// We do the equivalent above in `target_features_cfg`.
// See <https://github.com/rust-lang/rust/issues/134792>.
all_rust_features.push((false, feature));
} else if !feature.is_empty() {
if diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
}
}
}
// Remove features that are meant for rustc, not LLVM.
all_rust_features.retain(|(_, feature)| {
// Retain if it is not a rustc feature
!RUSTC_SPECIFIC_FEATURES.contains(feature)
});
// Check feature validity.
if diagnostics {
for &(enable, feature) in &all_rust_features {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
match feature_state {
None => {
let rust_feature =
known_features.iter().find_map(|&(rust_feature, _, _)| {
let llvm_features = to_llvm_features(sess, rust_feature)?;
if llvm_features.contains(feature)
&& !llvm_features.contains(rust_feature)
{
Some(rust_feature)
} else {
None
}
});
let unknown_feature = if let Some(rust_feature) = rust_feature {
UnknownCTargetFeature {
feature,
rust_feature: PossibleFeature::Some { rust_feature },
}
} else {
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
};
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. It makes little sense
// to hard-error here since we just warn about fully unknown
// features above.
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
}
}
// Ensure that the features we enable/disable are compatible with the ABI.
if enable {
if abi_incompatible_set.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "enabled",
reason: "this feature is incompatible with the target ABI",
});
}
} else {
// FIXME: we have to request implied features here since
// negative features do not handle implied features above.
for &required in abi_feature_constraints.required.iter() {
let implied =
sess.target.implied_target_features(std::iter::once(required));
if implied.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "disabled",
reason: "this feature is required by the target ABI",
});
}
}
}
// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable);
}
}
// To be sure the ABI-relevant features are all in the right state, we explicitly
// (un)set them here. This means if the target spec sets those features wrong,
// we will silently correct them rather than silently producing wrong code.
// (The target sanity check tries to catch this, but we can't know which features are
// enabled in LLVM by default so we can't be fully sure about that check.)
// We add these at the beginning of the list so that `-Ctarget-features` can
// still override it... that's unsound, but more compatible with past behavior.
all_rust_features.splice(
0..0,
abi_feature_constraints
.required
.iter()
.map(|&f| (true, f))
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
);
// Translate this into LLVM features.
let feats = all_rust_features
.iter()
.filter_map(|s| {
let enable_disable = match s.chars().next() {
None => return None,
Some(c @ ('+' | '-')) => c,
Some(_) => {
if diagnostics {
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
}
return None;
}
};
// Get the backend feature name, if any.
// This excludes rustc-specific features, which do not get passed to LLVM.
let feature = backend_feature_name(sess, s)?;
// Warn against use of LLVM specific feature names and unstable features on the CLI.
if diagnostics {
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
match feature_state {
None => {
let rust_feature =
known_features.iter().find_map(|&(rust_feature, _, _)| {
let llvm_features = to_llvm_features(sess, rust_feature)?;
if llvm_features.contains(feature)
&& !llvm_features.contains(rust_feature)
{
Some(rust_feature)
} else {
None
}
});
let unknown_feature = if let Some(rust_feature) = rust_feature {
UnknownCTargetFeature {
feature,
rust_feature: PossibleFeature::Some { rust_feature },
}
} else {
UnknownCTargetFeature {
feature,
rust_feature: PossibleFeature::None,
}
};
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
if let Err(reason) =
stability.toggle_allowed(&sess.target, enable_disable == '+')
{
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. It makes little sense
// to hard-error here since we just warn about fully unknown
// features above.
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
}
}
// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable_disable == '+');
}
.filter_map(|&(enable, feature)| {
let enable_disable = if enable { '+' } else { '-' };
// We run through `to_llvm_features` when
// passing requests down to LLVM. This means that all in-language
// features also work on the command line instead of having two
@ -746,9 +809,9 @@ pub(crate) fn global_llvm_features(
enable_disable, llvm_feature.llvm_feature_name
))
.chain(llvm_feature.dependency.into_iter().filter_map(
move |feat| match (enable_disable, feat) {
('-' | '+', TargetFeatureFoldStrength::Both(f))
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
move |feat| match (enable, feat) {
(_, TargetFeatureFoldStrength::Both(f))
| (true, TargetFeatureFoldStrength::EnableOnly(f)) => {
Some(format!("{enable_disable}{f}"))
}
_ => None,
@ -780,22 +843,6 @@ pub(crate) fn global_llvm_features(
features
}
/// Returns a feature name for the given `+feature` or `-feature` string.
///
/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
// features must start with a `+` or `-`.
let feature = s
.strip_prefix(&['+', '-'][..])
.unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
// are not passed down to LLVM.
if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) {
return None;
}
Some(feature)
}
pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> {
let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
Some(handle_native(name))

View file

@ -67,7 +67,7 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
codegen_ssa_forbidden_target_feature_attr =
target feature `{$feature}` cannot be toggled with `#[target_feature]`: {$reason}
target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason}
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced

View file

@ -2451,10 +2451,12 @@ fn add_order_independent_options(
}
if sess.target.os == "emscripten" {
cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
"DISABLE_EXCEPTION_CATCHING=1"
cmd.cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
"-sDISABLE_EXCEPTION_CATCHING=1"
} else if sess.opts.unstable_opts.emscripten_wasm_eh {
"-fwasm-exceptions"
} else {
"DISABLE_EXCEPTION_CATCHING=0"
"-sDISABLE_EXCEPTION_CATCHING=0"
});
}

View file

@ -388,7 +388,8 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// exceptions. This means that the VM does the unwinding for
// us
pub fn wants_wasm_eh(sess: &Session) -> bool {
sess.target.is_like_wasm && sess.target.os != "emscripten"
sess.target.is_like_wasm
&& (sess.target.os != "emscripten" || sess.opts.unstable_opts.emscripten_wasm_eh)
}
/// Returns `true` if this session's target will use SEH-based unwinding.

View file

@ -19,7 +19,7 @@ use crate::errors;
pub(crate) fn from_target_feature_attr(
tcx: TyCtxt<'_>,
attr: &hir::Attribute,
rust_target_features: &UnordMap<String, target_features::StabilityComputed>,
rust_target_features: &UnordMap<String, target_features::Stability>,
target_features: &mut Vec<TargetFeature>,
) {
let Some(list) = attr.meta_item_list() else { return };
@ -32,7 +32,7 @@ pub(crate) fn from_target_feature_attr(
.emit();
};
let rust_features = tcx.features();
let mut added_target_features = Vec::new();
let abi_feature_constraints = tcx.sess.target.abi_required_features();
for item in list {
// Only `enable = ...` is accepted in the meta-item list.
if !item.has_name(sym::enable) {
@ -47,7 +47,7 @@ pub(crate) fn from_target_feature_attr(
};
// We allow comma separation to enable multiple features.
added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
for feature in value.as_str().split(',') {
let Some(stability) = rust_target_features.get(feature) else {
let msg = format!("the feature named `{feature}` is not valid for this target");
let mut err = tcx.dcx().struct_span_err(item.span(), msg);
@ -59,12 +59,12 @@ pub(crate) fn from_target_feature_attr(
}
}
err.emit();
return None;
continue;
};
// Only allow target features whose feature gates have been enabled
// and which are permitted to be toggled.
if let Err(reason) = stability.toggle_allowed(/*enable*/ true) {
if let Err(reason) = stability.toggle_allowed() {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature,
@ -80,31 +80,25 @@ pub(crate) fn from_target_feature_attr(
format!("the target feature `{feature}` is currently unstable"),
)
.emit();
} else {
// Add this and the implied features.
let feature_sym = Symbol::intern(feature);
for &name in tcx.implied_target_features(feature_sym) {
// But ensure the ABI does not forbid enabling this.
// Here we do assume that LLVM doesn't add even more implied features
// we don't know about, at least no features that would have ABI effects!
if abi_feature_constraints.incompatible.contains(&name.as_str()) {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature: name.as_str(),
reason: "this feature is incompatible with the target ABI",
});
}
target_features.push(TargetFeature { name, implied: name != feature_sym })
}
}
Some(Symbol::intern(feature))
}));
}
}
// Add explicit features
target_features.extend(
added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
);
// Add implied features
let mut implied_target_features = UnordSet::new();
for feature in added_target_features.iter() {
implied_target_features.extend(tcx.implied_target_features(*feature).clone());
}
for feature in added_target_features.iter() {
implied_target_features.remove(feature);
}
target_features.extend(
implied_target_features
.into_sorted_stable_ord()
.iter()
.copied()
.map(|name| TargetFeature { name, implied: true }),
)
}
/// Computes the set of target features used in a function for the purposes of
@ -147,25 +141,28 @@ pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
rust_target_features: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
let target = &tcx.sess.target;
if tcx.sess.opts.actually_rustdoc {
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
rustc_target::target_features::all_rust_features()
.map(|(a, b)| (a.to_string(), b.compute_toggleability(target)))
.map(|(a, b)| (a.to_string(), b))
.collect()
} else {
tcx.sess
.target
.rust_target_features()
.iter()
.map(|(a, b, _)| (a.to_string(), b.compute_toggleability(target)))
.map(|(a, b, _)| (a.to_string(), *b))
.collect()
}
},
implied_target_features: |tcx, feature| {
implied_target_features: |tcx, feature: Symbol| {
let feature = feature.as_str();
UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
.into_sorted_stable_ord()
.into_iter()
.map(|s| Symbol::intern(s))
.collect()
},
asm_target_features,
..*providers

View file

@ -704,8 +704,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, &str> {
let len = mplace.len(self)?;
let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?;
let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
interp_ok(str)
let s = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
interp_ok(s)
}
/// Read from a local of the current frame. Convenience method for [`InterpCx::local_at_frame_to_op`].

View file

@ -1017,9 +1017,9 @@ where
/// This is allocated in immutable global memory and deduplicated.
pub fn allocate_str_dedup(
&mut self,
str: &str,
s: &str,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let bytes = str.as_bytes();
let bytes = s.as_bytes();
let ptr = self.allocate_bytes_dedup(bytes)?;
// Create length metadata for the string.

View file

@ -52,8 +52,8 @@ use rustc_metadata::locator;
use rustc_middle::ty::TyCtxt;
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_session::config::{
CG_OPTIONS, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, Z_OPTIONS,
nightly_options,
CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions,
Z_OPTIONS, nightly_options,
};
use rustc_session::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId};
@ -1124,14 +1124,6 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
return true;
}
if cg_flags.iter().any(|x| *x == "no-stack-check") {
early_dcx.early_warn("the `-Cno-stack-check` flag is deprecated and does nothing");
}
if cg_flags.iter().any(|x| x.starts_with("inline-threshold")) {
early_dcx.early_warn("the `-Cinline-threshold` flag is deprecated and does nothing (consider using `-Cllvm-args=--inline-threshold=...`)");
}
if cg_flags.iter().any(|x| *x == "passes=list") {
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
@ -1156,18 +1148,16 @@ fn describe_codegen_flags() {
print_flag_list("-C", config::CG_OPTIONS);
}
fn print_flag_list<T>(
cmdline_opt: &str,
flag_list: &[(&'static str, T, &'static str, &'static str)],
) {
let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) {
let max_len =
flag_list.iter().map(|opt_desc| opt_desc.name().chars().count()).max().unwrap_or(0);
for &(name, _, _, desc) in flag_list {
for opt_desc in flag_list {
safe_println!(
" {} {:>width$}=val -- {}",
cmdline_opt,
name.replace('_', "-"),
desc,
opt_desc.name().replace('_', "-"),
opt_desc.desc(),
width = max_len
);
}
@ -1221,8 +1211,8 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto
let msg: Option<String> = match e {
getopts::Fail::UnrecognizedOption(ref opt) => CG_OPTIONS
.iter()
.map(|&(name, ..)| ('C', name))
.chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name)))
.map(|opt_desc| ('C', opt_desc.name()))
.chain(Z_OPTIONS.iter().map(|opt_desc| ('Z', opt_desc.name())))
.find(|&(_, name)| *opt == name.replace('_', "-"))
.map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
getopts::Fail::ArgumentMissing(ref opt) => {

View file

@ -37,6 +37,7 @@ const GATED_CFGS: &[GatedCfg] = &[
(sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
// this is consistent with naming of the compiler flag it's for
(sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
(sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh),
];
/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.

View file

@ -202,6 +202,8 @@ declare_features! (
(internal, allow_internal_unstable, "1.0.0", None),
/// Allows using anonymous lifetimes in argument-position impl-trait.
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
/// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind
(internal, cfg_emscripten_wasm_eh, "CURRENT_RUSTC_VERSION", None),
/// Allows identifying the `compiler_builtins` crate.
(internal, compiler_builtins, "1.13.0", None),
/// Allows writing custom MIR

View file

@ -1387,7 +1387,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(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) => {
@ -1414,7 +1414,7 @@ impl<'hir> Pat<'hir> {
use PatKind::*;
match self.kind {
Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(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) => {
@ -1566,6 +1566,9 @@ pub enum PatKind<'hir> {
/// A literal.
Lit(&'hir Expr<'hir>),
/// A guard pattern (e.g., `x if guard(x)`).
Guard(&'hir Pat<'hir>, &'hir Expr<'hir>),
/// A range pattern (e.g., `1..=2` or `1..2`).
Range(Option<&'hir Expr<'hir>>, Option<&'hir Expr<'hir>>, RangeEnd),

View file

@ -696,6 +696,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
visit_opt!(visitor, visit_pat, slice_pattern);
walk_list!(visitor, visit_pat, postpatterns);
}
PatKind::Guard(subpat, condition) => {
try_visit!(visitor.visit_pat(subpat));
try_visit!(visitor.visit_expr(condition));
}
}
V::Result::output()
}

View file

@ -1845,13 +1845,18 @@ pub(super) fn check_coroutine_obligations(
debug!(?typeck_results.coroutine_stalled_predicates);
let mode = if tcx.next_trait_solver_globally() {
TypingMode::post_borrowck_analysis(tcx, def_id)
} else {
TypingMode::analysis_in_body(tcx, def_id)
};
let infcx = tcx
.infer_ctxt()
// typeck writeback gives us predicates with their regions erased.
// As borrowck already has checked lifetimes, we do not need to do it again.
.ignoring_regions()
// FIXME(#132279): This should eventually use the already defined hidden types.
.build(TypingMode::analysis_in_body(tcx, def_id));
.build(mode);
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
@ -1864,12 +1869,14 @@ pub(super) fn check_coroutine_obligations(
return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
}
// Check that any hidden types found when checking these stalled coroutine obligations
// are valid.
for (key, ty) in infcx.take_opaque_types() {
let hidden_type = infcx.resolve_vars_if_possible(ty.hidden_type);
let key = infcx.resolve_vars_if_possible(key);
sanity_check_found_hidden_type(tcx, key, hidden_type)?;
if !tcx.next_trait_solver_globally() {
// Check that any hidden types found when checking these stalled coroutine obligations
// are valid.
for (key, ty) in infcx.take_opaque_types() {
let hidden_type = infcx.resolve_vars_if_possible(ty.hidden_type);
let key = infcx.resolve_vars_if_possible(key);
sanity_check_found_hidden_type(tcx, key, hidden_type)?;
}
}
Ok(())

View file

@ -654,6 +654,7 @@ fn resolve_local<'tcx>(
/// | ( ..., P&, ... )
/// | ... "|" P& "|" ...
/// | box P&
/// | P& if ...
/// ```
fn is_binding_pat(pat: &hir::Pat<'_>) -> bool {
// Note that the code below looks for *explicit* refs only, that is, it won't
@ -694,7 +695,9 @@ fn resolve_local<'tcx>(
| PatKind::TupleStruct(_, subpats, _)
| PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)),
PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat),
PatKind::Box(subpat) | PatKind::Deref(subpat) | PatKind::Guard(subpat, _) => {
is_binding_pat(subpat)
}
PatKind::Ref(_, _)
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)

View file

@ -128,21 +128,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
for param in &impl_generics.own_params {
match param.kind {
ty::GenericParamDefKind::Lifetime => {
let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
if lifetimes_in_associated_types.contains(&param_lt) // (*)
&& !input_parameters.contains(&param_lt)
{
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
span: tcx.def_span(param.def_id),
param_name: param.name,
param_def_kind: tcx.def_descr(param.def_id),
const_param_note: false,
const_param_note2: false,
});
diag.code(E0207);
res = Err(diag.emit());
}
// (*) This is a horrible concession to reality. I think it'd be
// This is a horrible concession to reality. I think it'd be
// better to just ban unconstrained lifetimes outright, but in
// practice people do non-hygienic macros like:
//
@ -160,6 +146,20 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
// permit those, so long as the lifetimes aren't used in
// associated types. I believe this is sound, because lifetimes
// used elsewhere are not projected back out.
let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
if lifetimes_in_associated_types.contains(&param_lt)
&& !input_parameters.contains(&param_lt)
{
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
span: tcx.def_span(param.def_id),
param_name: param.name,
param_def_kind: tcx.def_descr(param.def_id),
const_param_note: false,
const_param_note2: false,
});
diag.code(E0207);
res = Err(diag.emit());
}
}
ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
// Enforced in `enforce_impl_non_lifetime_params_are_constrained`.

View file

@ -1999,6 +1999,12 @@ impl<'a> State<'a> {
self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
self.word("]");
}
PatKind::Guard(inner, cond) => {
self.print_pat(inner);
self.space();
self.word_space("if");
self.print_expr(cond);
}
PatKind::Err(_) => {
self.popen();
self.word("/*ERROR*/");

View file

@ -456,6 +456,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Does not constitute a read.
hir::PatKind::Wild => false,
// Might not constitute a read, since the condition might be false.
hir::PatKind::Guard(_, _) => true,
// This is unnecessarily restrictive when the pattern that doesn't
// constitute a read is unreachable.
//

View file

@ -615,6 +615,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
| PatKind::Box(_)
| PatKind::Deref(_)
| PatKind::Ref(..)
| PatKind::Guard(..)
| PatKind::Wild
| PatKind::Err(_) => {
// If the PatKind is Or, Box, or Ref, the decision is made later
@ -1737,7 +1738,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}
}
PatKind::Binding(.., Some(subpat)) => {
PatKind::Binding(.., Some(subpat)) | PatKind::Guard(subpat, _) => {
self.cat_pattern(place_with_id, subpat, op)?;
}

View file

@ -40,13 +40,25 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// FIXME: Move this check out of typeck, since it'll easily cycle when revealing opaques,
/// and we shouldn't need to check anything here if the typeck results are tainted.
pub(crate) fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
let tcx = self.tcx;
let dl = &tcx.data_layout;
let span = tcx.hir().span(hir_id);
let normalize = |ty| {
let ty = self.resolve_vars_if_possible(ty);
self.tcx.normalize_erasing_regions(self.typing_env(self.param_env), ty)
if let Ok(ty) =
self.tcx.try_normalize_erasing_regions(self.typing_env(self.param_env), ty)
{
ty
} else {
Ty::new_error_with_message(
tcx,
span,
"tried to normalize non-wf type in check_transmute",
)
}
};
let from = normalize(from);
let to = normalize(to);

View file

@ -147,8 +147,23 @@ fn typeck_with_fallback<'tcx>(
check_abi(tcx, span, fn_sig.abi());
// Compute the function signature from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
let fn_sig = fcx.normalize(body.value.span, fn_sig);
let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
// for each type, preventing the HIR wf check from generating
// a nice error message.
let arg_span =
|idx| decl.inputs.get(idx).map_or(decl.output.span(), |arg: &hir::Ty<'_>| arg.span);
fn_sig.inputs_and_output = tcx.mk_type_list_from_iter(
fn_sig
.inputs_and_output
.iter()
.enumerate()
.map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)),
);
check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params());
} else {

View file

@ -14,7 +14,7 @@ use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
use rustc_hir::def::DefKind;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::lang_items::LangItem;
@ -690,6 +690,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
// Check if we wrote `Self::Assoc(1)` as if it were a tuple ctor.
if let SelfSource::QPath(ty) = source
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
&& let Res::SelfTyAlias { alias_to: impl_def_id, .. } = path.res
&& let DefKind::Impl { .. } = self.tcx.def_kind(impl_def_id)
&& let Some(candidate) = tcx.associated_items(impl_def_id).find_by_name_and_kind(
self.tcx,
item_name,
ty::AssocKind::Type,
impl_def_id,
)
&& let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
&& adt_def.is_struct()
&& adt_def.non_enum_variant().ctor_kind() == Some(CtorKind::Fn)
{
let def_path = tcx.def_path_str(adt_def.did());
err.span_suggestion(
ty.span.to(item_name.span),
format!("to construct a value of type `{}`, use the explicit path", def_path),
def_path,
Applicability::MachineApplicable,
);
}
err
};
if tcx.sess.source_map().is_multiline(sugg_span) {

View file

@ -284,6 +284,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Struct(ref qpath, fields, has_rest_pat) => {
self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
}
PatKind::Guard(pat, cond) => {
self.check_pat(pat, expected, pat_info);
self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
expected
}
PatKind::Or(pats) => {
for pat in pats {
self.check_pat(pat, expected, pat_info);
@ -422,7 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// An OR-pattern just propagates to each individual alternative.
// This is maximally flexible, allowing e.g., `Some(mut x) | &Some(mut x)`.
// In that example, `Some(mut x)` results in `Peel` whereas `&Some(mut x)` in `Reset`.
| PatKind::Or(_) => AdjustMode::Pass,
| PatKind::Or(_)
// Like or-patterns, guard patterns just propogate to their subpatterns.
| PatKind::Guard(..) => AdjustMode::Pass,
}
}
@ -901,6 +908,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
PatKind::Struct(..)
| PatKind::TupleStruct(..)
| PatKind::Or(..)
| PatKind::Guard(..)
| PatKind::Tuple(..)
| PatKind::Slice(..) => "binding",

View file

@ -582,6 +582,7 @@ fn test_codegen_options_tracking_hash() {
untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
untracked!(extra_filename, String::from("extra-filename"));
untracked!(incremental, Some(String::from("abc")));
untracked!(inline_threshold, Some(0xf007ba11));
// `link_arg` is omitted because it just forwards to `link_args`.
untracked!(link_args, vec![String::from("abc"), String::from("def")]);
untracked!(link_self_contained, LinkSelfContained::on());
@ -613,7 +614,6 @@ fn test_codegen_options_tracking_hash() {
tracked!(embed_bitcode, false);
tracked!(force_frame_pointers, FramePointer::Always);
tracked!(force_unwind_tables, Some(true));
tracked!(inline_threshold, Some(0xf007ba11));
tracked!(instrument_coverage, InstrumentCoverage::Yes);
tracked!(link_dead_code, Some(true));
tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
@ -782,6 +782,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(dwarf_version, Some(5));
tracked!(embed_source, true);
tracked!(emit_thin_lto, false);
tracked!(emscripten_wasm_eh, true);
tracked!(export_executable_symbols, true);
tracked!(fewer_names, Some(true));
tracked!(fixed_x18, true);

View file

@ -1244,8 +1244,8 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
declare_lint! {
/// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that
/// means neither directly accessible, nor reexported, nor leaked through things like return
/// types.
/// means neither directly accessible, nor reexported (with `pub use`), nor leaked through
/// things like return types (which the [`unnameable_types`] lint can detect if desired).
///
/// ### Example
///
@ -1272,8 +1272,10 @@ declare_lint! {
/// intent that the item is only visible within its own crate.
///
/// This lint is "allow" by default because it will trigger for a large
/// amount existing Rust code, and has some false-positives. Eventually it
/// amount of existing Rust code, and has some false-positives. Eventually it
/// is desired for this to become warn-by-default.
///
/// [`unnameable_types`]: #unnameable-types
pub UNREACHABLE_PUB,
Allow,
"`pub` items not reachable from crate root"

View file

@ -234,10 +234,10 @@ declare_lint! {
declare_lint_pass!(NonSnakeCase => [NON_SNAKE_CASE]);
impl NonSnakeCase {
fn to_snake_case(mut str: &str) -> String {
fn to_snake_case(mut name: &str) -> String {
let mut words = vec![];
// Preserve leading underscores
str = str.trim_start_matches(|c: char| {
name = name.trim_start_matches(|c: char| {
if c == '_' {
words.push(String::new());
true
@ -245,7 +245,7 @@ impl NonSnakeCase {
false
}
});
for s in str.split('_') {
for s in name.split('_') {
let mut last_upper = false;
let mut buf = String::new();
if s.is_empty() {

View file

@ -4362,7 +4362,7 @@ declare_lint! {
/// ### Explanation
///
/// It is often expected that if you can obtain an object of type `T`, then
/// you can name the type `T` as well, this lint attempts to enforce this rule.
/// you can name the type `T` as well; this lint attempts to enforce this rule.
/// The recommended action is to either reexport the type properly to make it nameable,
/// or document that users are not supposed to be able to name it for one reason or another.
///

View file

@ -1389,20 +1389,14 @@ static bool clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
return ClearDSOLocalOnDeclarations;
}
extern "C" bool LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data,
extern "C" void LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data,
LLVMModuleRef M,
LLVMTargetMachineRef TM) {
Module &Mod = *unwrap(M);
TargetMachine &Target = *unwrap(TM);
bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
if (error) {
LLVMRustSetLastError("renameModuleForThinLTO failed");
return false;
}
return true;
renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
}
extern "C" bool

View file

@ -54,6 +54,10 @@ using namespace llvm;
using namespace llvm::sys;
using namespace llvm::object;
// This opcode is an LLVM detail that could hypothetically change (?), so
// verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM.
static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000);
// LLVMAtomicOrdering is already an enum - don't create another
// one.
static AtomicOrdering fromRust(LLVMAtomicOrdering Ordering) {
@ -1397,18 +1401,6 @@ LLVMRustDILocationCloneWithBaseDiscriminator(LLVMMetadataRef Location,
return wrap(NewLoc.has_value() ? NewLoc.value() : nullptr);
}
extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
return dwarf::DW_OP_deref;
}
extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
return dwarf::DW_OP_plus_uconst;
}
extern "C" uint64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
return dwarf::DW_OP_LLVM_fragment;
}
extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) {
auto OS = RawRustStringOstream(Str);
unwrap<llvm::Type>(Ty)->print(OS);

View file

@ -130,11 +130,11 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
match cfg.backtrace {
Ok(str) => {
Ok(backtrace_target) => {
let fmt_layer = tracing_subscriber::fmt::layer()
.with_writer(io::stderr)
.without_time()
.event_format(BacktraceFormatter { backtrace_target: str });
.event_format(BacktraceFormatter { backtrace_target });
let subscriber = subscriber.with(fmt_layer);
tracing::subscriber::set_global_default(subscriber).unwrap();
}

View file

@ -156,14 +156,14 @@ impl Entries {
Entries { map: HashMap::with_capacity(capacity) }
}
fn insert(&mut self, span: Span, str: &str, errors: &mut Errors) -> u32 {
if let Some(prev) = self.map.get(str) {
errors.error(span, format!("Symbol `{str}` is duplicated"));
fn insert(&mut self, span: Span, s: &str, errors: &mut Errors) -> u32 {
if let Some(prev) = self.map.get(s) {
errors.error(span, format!("Symbol `{s}` is duplicated"));
errors.error(prev.span_of_name, "location of previous definition".to_string());
prev.idx
} else {
let idx = self.len();
self.map.insert(str.to_string(), Preinterned { idx, span_of_name: span });
self.map.insert(s.to_string(), Preinterned { idx, span_of_name: span });
idx
}
}
@ -192,14 +192,14 @@ fn symbols_with_errors(input: TokenStream) -> (TokenStream, Vec<syn::Error>) {
let mut entries = Entries::with_capacity(input.keywords.len() + input.symbols.len() + 10);
let mut prev_key: Option<(Span, String)> = None;
let mut check_order = |span: Span, str: &str, errors: &mut Errors| {
let mut check_order = |span: Span, s: &str, errors: &mut Errors| {
if let Some((prev_span, ref prev_str)) = prev_key {
if str < prev_str {
errors.error(span, format!("Symbol `{str}` must precede `{prev_str}`"));
if s < prev_str {
errors.error(span, format!("Symbol `{s}` must precede `{prev_str}`"));
errors.error(prev_span, format!("location of previous symbol `{prev_str}`"));
}
}
prev_key = Some((span, str.to_string()));
prev_key = Some((span, s.to_string()));
};
// Generate the listed keywords.

View file

@ -6,7 +6,6 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
derive-where = "1.2.7"
either = "1.5.0"
field-offset = "0.3.5"
gsgdt = "0.1.2"

View file

@ -28,6 +28,7 @@ pub struct CodegenFnAttrs {
pub link_ordinal: Option<u16>,
/// The `#[target_feature(enable = "...")]` attribute and the enabled
/// features (only enabled features are supported right now).
/// Implied target features have already been applied.
pub target_features: Vec<TargetFeature>,
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
pub linkage: Option<Linkage>,

View file

@ -3,7 +3,6 @@
use std::cell::Cell;
use std::fmt::{self, Debug};
use derive_where::derive_where;
use rustc_abi::{FieldIdx, VariantIdx};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::ErrorGuaranteed;
@ -225,29 +224,22 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
/// See also `rustc_const_eval::borrow_check::constraints`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
#[derive_where(PartialOrd, Ord)]
pub enum ConstraintCategory<'tcx> {
Return(ReturnConstraint),
Yield,
UseAsConst,
UseAsStatic,
TypeAnnotation,
TypeAnnotation(AnnotationSource),
Cast {
/// Whether this cast is a coercion that was automatically inserted by the compiler.
is_implicit_coercion: bool,
/// Whether this is an unsizing coercion and if yes, this contains the target type.
/// Region variables are erased to ReErased.
#[derive_where(skip)]
unsize_to: Option<Ty<'tcx>>,
},
/// A constraint that came from checking the body of a closure.
///
/// We try to get the category that the closure used when reporting this.
ClosureBounds,
/// Contains the function type if available.
CallArgument(#[derive_where(skip)] Option<Ty<'tcx>>),
CallArgument(Option<Ty<'tcx>>),
CopyBound,
SizedBound,
Assignment,
@ -276,13 +268,22 @@ pub enum ConstraintCategory<'tcx> {
IllegalUniverse,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
pub enum ReturnConstraint {
Normal,
ClosureUpvar(FieldIdx),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
pub enum AnnotationSource {
Ascription,
Declaration,
OpaqueCast,
GenericArg,
}
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
/// that must outlive some region.
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]

View file

@ -455,6 +455,8 @@ impl BorrowKind {
}
}
/// Returns whether borrows represented by this kind are allowed to be split into separate
/// Reservation and Activation phases.
pub fn allows_two_phase_borrow(&self) -> bool {
match *self {
BorrowKind::Shared

View file

@ -2357,7 +2357,7 @@ rustc_queries! {
}
/// Returns the Rust target features for the current target. These are not always the same as LLVM target features!
query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::StabilityComputed> {
query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::Stability> {
arena_cache
eval_always
desc { "looking up Rust target features" }

View file

@ -125,6 +125,15 @@ impl<'tcx> ObligationCause<'tcx> {
self
}
pub fn derived_host_cause(
mut self,
parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
variant: impl FnOnce(DerivedHostCause<'tcx>) -> ObligationCauseCode<'tcx>,
) -> ObligationCause<'tcx> {
self.code = variant(DerivedHostCause { parent_host_pred, parent_code: self.code }).into();
self
}
pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
match self.code() {
ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(),
@ -278,6 +287,14 @@ pub enum ObligationCauseCode<'tcx> {
/// Derived obligation for WF goals.
WellFormedDerived(DerivedCause<'tcx>),
/// Derived obligation (i.e. `where` clause) on an user-provided impl
/// or a trait alias.
ImplDerivedHost(Box<ImplDerivedHostCause<'tcx>>),
/// Derived obligation (i.e. `where` clause) on an user-provided impl
/// or a trait alias.
BuiltinDerivedHost(DerivedHostCause<'tcx>),
/// Derived obligation refined to point at a specific argument in
/// a call or method expression.
FunctionArg {
@ -437,36 +454,38 @@ pub enum WellFormedLoc {
},
}
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedCause<'tcx> {
pub derived: DerivedCause<'tcx>,
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
/// that exceptional case where appropriate.
pub impl_or_alias_def_id: DefId,
/// The index of the derived predicate in the parent impl's predicates.
pub impl_def_predicate_index: Option<usize>,
pub span: Span,
}
impl<'tcx> ObligationCauseCode<'tcx> {
/// Returns the base obligation, ignoring derived obligations.
pub fn peel_derives(&self) -> &Self {
let mut base_cause = self;
while let Some((parent_code, _)) = base_cause.parent() {
while let Some(parent_code) = base_cause.parent() {
base_cause = parent_code;
}
base_cause
}
pub fn parent(&self) -> Option<&Self> {
match self {
ObligationCauseCode::FunctionArg { parent_code, .. } => Some(parent_code),
ObligationCauseCode::BuiltinDerived(derived)
| ObligationCauseCode::WellFormedDerived(derived)
| ObligationCauseCode::ImplDerived(box ImplDerivedCause { derived, .. }) => {
Some(&derived.parent_code)
}
ObligationCauseCode::BuiltinDerivedHost(derived)
| ObligationCauseCode::ImplDerivedHost(box ImplDerivedHostCause { derived, .. }) => {
Some(&derived.parent_code)
}
_ => None,
}
}
/// Returns the base obligation and the base trait predicate, if any, ignoring
/// derived obligations.
pub fn peel_derives_with_predicate(&self) -> (&Self, Option<ty::PolyTraitPredicate<'tcx>>) {
let mut base_cause = self;
let mut base_trait_pred = None;
while let Some((parent_code, parent_pred)) = base_cause.parent() {
while let Some((parent_code, parent_pred)) = base_cause.parent_with_predicate() {
base_cause = parent_code;
if let Some(parent_pred) = parent_pred {
base_trait_pred = Some(parent_pred);
@ -476,7 +495,7 @@ impl<'tcx> ObligationCauseCode<'tcx> {
(base_cause, base_trait_pred)
}
pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
pub fn parent_with_predicate(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
match self {
ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)),
ObligationCauseCode::BuiltinDerived(derived)
@ -573,6 +592,42 @@ pub struct DerivedCause<'tcx> {
pub parent_code: InternedObligationCauseCode<'tcx>,
}
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedCause<'tcx> {
pub derived: DerivedCause<'tcx>,
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
/// that exceptional case where appropriate.
pub impl_or_alias_def_id: DefId,
/// The index of the derived predicate in the parent impl's predicates.
pub impl_def_predicate_index: Option<usize>,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct DerivedHostCause<'tcx> {
/// The trait predicate of the parent obligation that led to the
/// current obligation. Note that only trait obligations lead to
/// derived obligations, so we just store the trait predicate here
/// directly.
pub parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
/// The parent trait had this cause.
pub parent_code: InternedObligationCauseCode<'tcx>,
}
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedHostCause<'tcx> {
pub derived: DerivedHostCause<'tcx>,
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
pub impl_def_id: DefId,
pub span: Span,
}
#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
pub enum SelectionError<'tcx> {
/// The trait is not implemented.

View file

@ -634,6 +634,28 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyProjectionPredicate<'tcx>> for Clause<'t
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>>
for Predicate<'tcx>
{
fn upcast_from(
from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
tcx: TyCtxt<'tcx>,
) -> Self {
from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx)
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>>
for Clause<'tcx>
{
fn upcast_from(
from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
tcx: TyCtxt<'tcx>,
) -> Self {
from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx)
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, NormalizesTo<'tcx>> for Predicate<'tcx> {
fn upcast_from(from: NormalizesTo<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
PredicateKind::NormalizesTo(from).upcast(tcx)

View file

@ -45,10 +45,25 @@ pub trait Printer<'tcx>: Sized {
&mut self,
impl_def_id: DefId,
args: &'tcx [GenericArg<'tcx>],
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
self.default_print_impl_path(impl_def_id, args, self_ty, trait_ref)
let tcx = self.tcx();
let self_ty = tcx.type_of(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() {
(
self_ty.instantiate(tcx, args),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(tcx, args)),
)
} else {
// We are probably printing a nested item inside of an impl.
// Use the identity substitutions for the impl.
(
self_ty.instantiate_identity(),
impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
)
};
self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
}
fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
@ -107,23 +122,7 @@ pub trait Printer<'tcx>: Sized {
self.path_crate(def_id.krate)
}
DefPathData::Impl => {
let generics = self.tcx().generics_of(def_id);
let self_ty = self.tcx().type_of(def_id);
let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
let (self_ty, impl_trait_ref) = if args.len() >= generics.count() {
(
self_ty.instantiate(self.tcx(), args),
impl_trait_ref.map(|i| i.instantiate(self.tcx(), args)),
)
} else {
(
self_ty.instantiate_identity(),
impl_trait_ref.map(|i| i.instantiate_identity()),
)
};
self.print_impl_path(def_id, args, self_ty, impl_trait_ref)
}
DefPathData::Impl => self.print_impl_path(def_id, args),
_ => {
let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
@ -201,7 +200,6 @@ pub trait Printer<'tcx>: Sized {
fn default_print_impl_path(
&mut self,
impl_def_id: DefId,
_args: &'tcx [GenericArg<'tcx>],
self_ty: Ty<'tcx>,
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {

View file

@ -17,26 +17,29 @@ pub fn find_self_call<'tcx>(
debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
&body[block].terminator
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
**args
{
debug!("find_self_call: func={:?}", func);
if let Operand::Constant(box ConstOperand { const_, .. }) = func {
if let ty::FnDef(def_id, fn_args) = *const_.ty().kind() {
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
{
debug!("find_self_call: args={:?}", fn_args);
if let [
Spanned {
node: Operand::Move(self_place) | Operand::Copy(self_place), ..
},
..,
] = **args
{
if self_place.as_local() == Some(local) {
return Some((def_id, fn_args));
}
}
}
if self_place.as_local() == Some(local) {
return Some((def_id, fn_args));
}
// Handle the case where `self_place` gets reborrowed.
// This happens when the receiver is `&T`.
for stmt in &body[block].statements {
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
&& let Some(reborrow_local) = place.as_local()
&& self_place.as_local() == Some(reborrow_local)
&& let Rvalue::Ref(_, _, deref_place) = rvalue
&& let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } =
deref_place.as_ref()
&& deref_local == local
{
return Some((def_id, fn_args));
}
}
}

View file

@ -1131,15 +1131,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Schedule emission of a backwards incompatible drop lint hint.
/// Applicable only to temporary values for now.
#[instrument(level = "debug", skip(self))]
pub(crate) fn schedule_backwards_incompatible_drop(
&mut self,
span: Span,
region_scope: region::Scope,
local: Local,
) {
if !self.local_decls[local].ty.has_significant_drop(self.tcx, self.typing_env()) {
return;
}
// Note that we are *not* gating BIDs here on whether they have significant destructor.
// We need to know all of them so that we can capture potential borrow-checking errors.
for scope in self.scopes.scopes.iter_mut().rev() {
// Since we are inserting linting MIR statement, we have to invalidate the caches
scope.invalidate_cache();

View file

@ -1086,14 +1086,7 @@ fn find_fallback_pattern_typo<'tcx>(
let vis = cx.tcx.visibility(item.owner_id);
if vis.is_accessible_from(parent, cx.tcx) {
accessible.push(item_name);
let path = if item_name == name {
// We know that the const wasn't in scope because it has the exact
// same name, so we suggest the full path.
with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id))
} else {
// The const is likely just typoed, and nothing else.
cx.tcx.def_path_str(item.owner_id)
};
let path = with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id));
accessible_path.push(path);
} else if name == item_name {
// The const exists somewhere in this crate, but it can't be imported

View file

@ -435,6 +435,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
hir::PatKind::Or(pats) => PatKind::Or { pats: self.lower_patterns(pats) },
// FIXME(guard_patterns): implement guard pattern lowering
hir::PatKind::Guard(pat, _) => self.lower_pattern(pat).kind,
hir::PatKind::Err(guar) => PatKind::Error(guar),
};

View file

@ -29,13 +29,8 @@ fn build_ptr_tys<'tcx>(
pub(super) fn build_projection<'tcx>(
unique_ty: Ty<'tcx>,
nonnull_ty: Ty<'tcx>,
ptr_ty: Ty<'tcx>,
) -> [PlaceElem<'tcx>; 3] {
[
PlaceElem::Field(FieldIdx::ZERO, unique_ty),
PlaceElem::Field(FieldIdx::ZERO, nonnull_ty),
PlaceElem::Field(FieldIdx::ZERO, ptr_ty),
]
) -> [PlaceElem<'tcx>; 2] {
[PlaceElem::Field(FieldIdx::ZERO, unique_ty), PlaceElem::Field(FieldIdx::ZERO, nonnull_ty)]
}
struct ElaborateBoxDerefVisitor<'a, 'tcx> {
@ -75,10 +70,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
self.patch.add_assign(
location,
Place::from(ptr_local),
Rvalue::Use(Operand::Copy(
Place::from(place.local)
.project_deeper(&build_projection(unique_ty, nonnull_ty, ptr_ty), tcx),
)),
Rvalue::Cast(
CastKind::Transmute,
Operand::Copy(
Place::from(place.local)
.project_deeper(&build_projection(unique_ty, nonnull_ty), tcx),
),
ptr_ty,
),
);
place.local = ptr_local;
@ -133,8 +132,10 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
let (unique_ty, nonnull_ty, ptr_ty) =
build_ptr_tys(tcx, boxed_ty, unique_did, nonnull_did);
new_projections
.extend_from_slice(&build_projection(unique_ty, nonnull_ty, ptr_ty));
new_projections.extend_from_slice(&build_projection(unique_ty, nonnull_ty));
// While we can't project into `NonNull<_>` in a basic block
// due to MCP#807, this is debug info where it's fine.
new_projections.push(PlaceElem::Field(FieldIdx::ZERO, ptr_ty));
new_projections.push(PlaceElem::Deref);
} else if let Some(new_projections) = new_projections.as_mut() {
// Keep building up our projections list once we've started it.

View file

@ -351,6 +351,11 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
{
return;
}
// FIXME(typing_env): This should be able to reveal the opaques local to the
// body using the typeck results.
let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id);
// ## About BIDs in blocks ##
// Track the set of blocks that contain a backwards-incompatible drop (BID)
// and, for each block, the vector of locations.
@ -358,7 +363,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
// We group them per-block because they tend to scheduled in the same drop ladder block.
let mut bid_per_block = IndexMap::default();
let mut bid_places = UnordSet::new();
let typing_env = ty::TypingEnv::post_analysis(tcx, def_id);
let mut ty_dropped_components = UnordMap::default();
for (block, data) in body.basic_blocks.iter_enumerated() {
for (statement_index, stmt) in data.statements.iter().enumerate() {

View file

@ -103,7 +103,7 @@ where
|ecx| {
// Const conditions must hold for the implied const bound to hold.
ecx.add_goals(
GoalSource::Misc,
GoalSource::AliasBoundConstCondition,
cx.const_conditions(alias_ty.def_id)
.iter_instantiated(cx, alias_ty.args)
.map(|trait_ref| {
@ -353,7 +353,7 @@ where
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
ecx.add_goals(
GoalSource::Misc,
GoalSource::AliasBoundConstCondition,
const_conditions.into_iter().map(|trait_ref| {
goal.with(
cx,

View file

@ -305,6 +305,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
Deref,
Ref,
Lit,
Guard,
Range,
Slice,
Err

Some files were not shown because too many files have changed in this diff Show more