Merge pull request #4513 from rust-lang/rustup-2025-08-04

Automatic Rustup
This commit is contained in:
Ben Kimock 2025-08-04 13:10:09 +00:00 committed by GitHub
commit ee1b237215
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
905 changed files with 13159 additions and 8944 deletions

View file

@ -597,6 +597,7 @@ Sam Radhakrishnan <sk09idm@gmail.com>
Samuel Tardieu <sam@rfc1149.net>
Santiago Pastorino <spastorino@gmail.com>
Santiago Pastorino <spastorino@gmail.com> <santiago@wyeworks.com>
Sasha Pourcelot <sasha.pourcelot@protonmail.com> Sasha <sasha.pourcelot@protonmail.com>
Scott McMurray <scottmcm@users.noreply.github.com>
Scott McMurray <scottmcm@users.noreply.github.com> <smcmurray@acm.org>
Scott Olson <scott@solson.me> Scott Olson <scott@scott-olson.org>

View file

@ -518,9 +518,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.41"
version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
dependencies = [
"clap_builder",
"clap_derive",
@ -538,9 +538,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.41"
version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
dependencies = [
"anstream",
"anstyle",
@ -1171,7 +1171,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [
"libc",
"option-ext",
"redox_users 0.5.0",
"redox_users 0.5.2",
"windows-sys 0.60.2",
]
@ -2094,9 +2094,9 @@ dependencies = [
[[package]]
name = "jsonpath-rust"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d057f8fd19e20c3f14d3663983397155739b6bc1148dc5cd4c4a1a5b3130eb0"
checksum = "633a7320c4bb672863a3782e89b9094ad70285e097ff6832cddd0ec615beadfa"
dependencies = [
"pest",
"pest_derive",
@ -2190,7 +2190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-targets 0.53.2",
"windows-targets 0.53.3",
]
[[package]]
@ -2201,9 +2201,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
version = "0.1.6"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
dependencies = [
"bitflags",
"libc",
@ -2643,9 +2643,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.37.1"
version = "0.37.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a"
checksum = "b3e3d0a7419f081f4a808147e845310313a39f322d7ae1f996b7f001d6cbed04"
dependencies = [
"crc32fast",
"flate2",
@ -2653,7 +2653,7 @@ dependencies = [
"indexmap",
"memchr",
"ruzstd 0.8.1",
"wasmparser 0.234.0",
"wasmparser 0.236.0",
]
[[package]]
@ -3167,9 +3167,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.16"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7251471db004e509f4e75a62cca9435365b5ec7bcdff530d612ac7c87c44a792"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags",
]
@ -3187,9 +3187,9 @@ dependencies = [
[[package]]
name = "redox_users"
version = "0.5.0"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
"getrandom 0.2.16",
"libredox",
@ -3279,7 +3279,7 @@ dependencies = [
"build_helper",
"gimli 0.32.0",
"libc",
"object 0.37.1",
"object 0.37.2",
"regex",
"serde_json",
"similar",
@ -3301,9 +3301,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.25"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustc-hash"
@ -3569,7 +3569,7 @@ dependencies = [
"itertools",
"libc",
"measureme",
"object 0.37.1",
"object 0.37.2",
"rustc-demangle",
"rustc_abi",
"rustc_ast",
@ -3607,7 +3607,7 @@ dependencies = [
"cc",
"itertools",
"libc",
"object 0.37.1",
"object 0.37.2",
"pathdiff",
"regex",
"rustc_abi",
@ -4519,6 +4519,7 @@ name = "rustc_resolve"
version = "0.0.0"
dependencies = [
"bitflags",
"indexmap",
"itertools",
"pulldown-cmark",
"rustc_arena",
@ -4642,7 +4643,7 @@ name = "rustc_target"
version = "0.0.0"
dependencies = [
"bitflags",
"object 0.37.1",
"object 0.37.2",
"rustc_abi",
"rustc_data_structures",
"rustc_fs_util",
@ -5039,9 +5040,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.141"
version = "1.0.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
dependencies = [
"itoa",
"memchr",
@ -6099,12 +6100,12 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.235.0"
version = "0.236.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a"
checksum = "3108979166ab0d3c7262d2e16a2190ffe784b2a5beb963edef154b5e8e07680b"
dependencies = [
"leb128fmt",
"wasmparser 0.235.0",
"wasmparser 0.236.0",
]
[[package]]
@ -6144,9 +6145,9 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.235.0"
version = "0.236.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917"
checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2"
dependencies = [
"bitflags",
"indexmap",
@ -6155,22 +6156,22 @@ dependencies = [
[[package]]
name = "wast"
version = "235.0.0"
version = "236.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1eda4293f626c99021bb3a6fbe4fbbe90c0e31a5ace89b5f620af8925de72e13"
checksum = "11d6b6faeab519ba6fbf9b26add41617ca6f5553f99ebc33d876e591d2f4f3c6"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width 0.2.1",
"wasm-encoder 0.235.0",
"wasm-encoder 0.236.0",
]
[[package]]
name = "wat"
version = "1.235.0"
version = "1.236.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e777e0327115793cb96ab220b98f85327ec3d11f34ec9e8d723264522ef206aa"
checksum = "cc31704322400f461f7f31a5f9190d5488aaeafb63ae69ad2b5888d2704dcb08"
dependencies = [
"wast",
]
@ -6426,7 +6427,7 @@ version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.2",
"windows-targets 0.53.3",
]
[[package]]
@ -6462,10 +6463,11 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.53.2"
version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",

View file

@ -311,7 +311,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
);
self.with_parent(const_arg.hir_id, |this| {
intravisit::walk_ambig_const_arg(this, const_arg);
intravisit::walk_const_arg(this, const_arg);
});
}

View file

@ -675,7 +675,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let bodies = SortedMap::from_presorted_elements(bodies);
// Don't hash unless necessary, because it's expensive.
let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) =
let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash, delayed_lints_hash } =
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
let num_nodes = self.item_local_id_counter.as_usize();
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);

View file

@ -241,6 +241,10 @@ ast_passes_tilde_const_disallowed = `[const]` is not allowed here
.trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds
.trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds
.inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds
.struct = structs cannot have `[const]` trait bounds
.enum = enums cannot have `[const]` trait bounds
.union = unions cannot have `[const]` trait bounds
.anon_const = anonymous constants cannot have `[const]` trait bounds
.object = trait objects cannot have `[const]` trait bounds
.item = this item cannot have `[const]` trait bounds

View file

@ -1124,7 +1124,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
}
}
visit::walk_item(self, item)
self.with_tilde_const(Some(TildeConstReason::Enum { span: item.span }), |this| {
visit::walk_item(this, item)
});
}
ItemKind::Trait(box Trait {
constness,
@ -1175,26 +1177,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
visit::walk_item(self, item)
}
ItemKind::Struct(ident, generics, vdata) => match vdata {
VariantData::Struct { fields, .. } => {
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
self.visit_generics(generics);
walk_list!(self, visit_field_def, fields);
}
_ => visit::walk_item(self, item),
},
ItemKind::Struct(ident, generics, vdata) => {
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
match vdata {
VariantData::Struct { fields, .. } => {
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
this.visit_generics(generics);
walk_list!(this, visit_field_def, fields);
}
_ => visit::walk_item(this, item),
}
})
}
ItemKind::Union(ident, generics, vdata) => {
if vdata.fields().is_empty() {
self.dcx().emit_err(errors::FieldlessUnion { span: item.span });
}
match vdata {
VariantData::Struct { fields, .. } => {
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
self.visit_generics(generics);
walk_list!(self, visit_field_def, fields);
self.with_tilde_const(Some(TildeConstReason::Union { span: item.span }), |this| {
match vdata {
VariantData::Struct { fields, .. } => {
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
this.visit_generics(generics);
walk_list!(this, visit_field_def, fields);
}
_ => visit::walk_item(this, item),
}
_ => visit::walk_item(self, item),
}
});
}
ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
self.check_defaultness(item.span, *defaultness);
@ -1623,6 +1631,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
}
}
fn visit_anon_const(&mut self, anon_const: &'a AnonConst) {
self.with_tilde_const(
Some(TildeConstReason::AnonConst { span: anon_const.value.span }),
|this| visit::walk_anon_const(this, anon_const),
)
}
}
/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems

View file

@ -623,6 +623,26 @@ pub(crate) enum TildeConstReason {
#[primary_span]
span: Span,
},
#[note(ast_passes_struct)]
Struct {
#[primary_span]
span: Span,
},
#[note(ast_passes_enum)]
Enum {
#[primary_span]
span: Span,
},
#[note(ast_passes_union)]
Union {
#[primary_span]
span: Span,
},
#[note(ast_passes_anon_const)]
AnonConst {
#[primary_span]
span: Span,
},
#[note(ast_passes_object)]
TraitObject,
#[note(ast_passes_item)]

View file

@ -374,11 +374,3 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
features
}
}
pub(crate) struct OmitGdbPrettyPrinterSectionParser;
impl<S: Stage> NoArgsAttributeParser<S> for OmitGdbPrettyPrinterSectionParser {
const PATH: &[Symbol] = &[sym::omit_gdb_pretty_printer_section];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::OmitGdbPrettyPrinterSection;
}

View file

@ -17,9 +17,8 @@ use crate::attributes::allow_unstable::{
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
};
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser,
OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser,
UsedParser,
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
TargetFeatureParser, TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
@ -62,15 +61,23 @@ use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
use crate::parser::{ArgParser, MetaItemParser, PathParser};
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
macro_rules! group_type {
($stage: ty) => {
LazyLock<(
BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
)>
};
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
struct GroupTypeInner<S: Stage> {
accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
finalizers: Vec<FinalizeFn<S>>,
}
struct GroupTypeInnerAccept<S: Stage> {
template: AttributeTemplate,
accept_fn: AcceptFn<S>,
}
type AcceptFn<S> =
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>;
type FinalizeFn<S> =
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
macro_rules! attribute_parsers {
(
pub(crate) static $name: ident = [$($names: ty),* $(,)?];
@ -93,11 +100,11 @@ macro_rules! attribute_parsers {
}
};
(
@[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
) => {
pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
$(
{
thread_local! {
@ -105,11 +112,14 @@ macro_rules! attribute_parsers {
};
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
STATE_OBJECT.with_borrow_mut(|s| {
accept_fn(s, cx, args)
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
template: *template,
accept_fn: Box::new(|cx, args| {
STATE_OBJECT.with_borrow_mut(|s| {
accept_fn(s, cx, args)
})
})
})));
});
}
finalizes.push(Box::new(|cx| {
@ -119,7 +129,7 @@ macro_rules! attribute_parsers {
}
)*
(accepts, finalizes)
GroupTypeInner { accepters:accepts, finalizers:finalizes }
});
};
}
@ -187,7 +197,6 @@ attribute_parsers!(
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<OmitGdbPrettyPrinterSectionParser>>,
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
Single<WithoutArgs<PointeeParser>>,
@ -213,24 +222,24 @@ mod private {
#[allow(private_interfaces)]
pub trait Stage: Sized + 'static + Sealed {
type Id: Copy;
const SHOULD_EMIT_LINTS: bool;
fn parsers() -> &'static group_type!(Self);
fn parsers() -> &'static GroupType<Self>;
fn emit_err<'sess>(
&self,
sess: &'sess Session,
diag: impl for<'x> Diagnostic<'x>,
) -> ErrorGuaranteed;
fn should_emit(&self) -> ShouldEmit;
}
// allow because it's a sealed trait
#[allow(private_interfaces)]
impl Stage for Early {
type Id = NodeId;
const SHOULD_EMIT_LINTS: bool = false;
fn parsers() -> &'static group_type!(Self) {
fn parsers() -> &'static GroupType<Self> {
&early::ATTRIBUTE_PARSERS
}
fn emit_err<'sess>(
@ -244,15 +253,18 @@ impl Stage for Early {
sess.dcx().create_err(diag).delay_as_bug()
}
}
fn should_emit(&self) -> ShouldEmit {
self.emit_errors
}
}
// allow because it's a sealed trait
#[allow(private_interfaces)]
impl Stage for Late {
type Id = HirId;
const SHOULD_EMIT_LINTS: bool = true;
fn parsers() -> &'static group_type!(Self) {
fn parsers() -> &'static GroupType<Self> {
&late::ATTRIBUTE_PARSERS
}
fn emit_err<'sess>(
@ -262,6 +274,10 @@ impl Stage for Late {
) -> ErrorGuaranteed {
tcx.dcx().emit_err(diag)
}
fn should_emit(&self) -> ShouldEmit {
ShouldEmit::ErrorsAndLints
}
}
/// used when parsing attributes for miscellaneous things *before* ast lowering
@ -300,7 +316,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
/// must be delayed until after HIR is built. This method will take care of the details of
/// that.
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
if !S::SHOULD_EMIT_LINTS {
if !self.stage.should_emit().should_emit() {
return;
}
let id = self.target_id;
@ -811,8 +827,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
let args = parser.args();
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
for (template, accept) in accepts {
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
for accept in accepts {
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
shared: SharedContext {
cx: self,
@ -821,11 +837,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
emit_lint: &mut emit_lint,
},
attr_span: lower_span(attr.span),
template,
template: &accept.template,
attr_path: path.get_attribute_path(),
};
accept(&mut cx, args)
(accept.accept_fn)(&mut cx, args)
}
} else {
// If we're here, we must be compiling a tool attribute... Or someone
@ -856,7 +872,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
}
let mut parsed_attributes = Vec::new();
for f in &S::parsers().1 {
for f in &S::parsers().finalizers {
if let Some(attr) = f(&mut FinalizeContext {
shared: SharedContext {
cx: self,
@ -877,7 +893,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
/// Returns whether there is a parser for an attribute with this name
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
Late::parsers().0.contains_key(path)
Late::parsers().accepters.contains_key(path)
}
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {

View file

@ -3,7 +3,7 @@ use std::rc::Rc;
use rustc_errors::Diag;
use rustc_hir::def_id::LocalDefId;
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_infer::infer::region_constraints::{Constraint, ConstraintKind, RegionConstraintData};
use rustc_infer::infer::{
InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _,
};
@ -454,25 +454,24 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
_ => a_region == b_region,
};
let mut check =
|constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
Constraint::RegSubReg(sub, sup)
if ((exact && sup == placeholder_region)
|| (!exact && regions_the_same(sup, placeholder_region)))
&& sup != sub =>
{
Some((sub, cause.clone()))
}
Constraint::VarSubReg(vid, sup)
if (exact
&& sup == placeholder_region
&& !universe_of_region(vid).can_name(placeholder_universe))
|| (!exact && regions_the_same(sup, placeholder_region)) =>
{
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
}
_ => None,
};
let mut check = |c: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
ConstraintKind::RegSubReg
if ((exact && c.sup == placeholder_region)
|| (!exact && regions_the_same(c.sup, placeholder_region)))
&& c.sup != c.sub =>
{
Some((c.sub, cause.clone()))
}
ConstraintKind::VarSubReg
if (exact
&& c.sup == placeholder_region
&& !universe_of_region(c.sub.as_var()).can_name(placeholder_universe))
|| (!exact && regions_the_same(c.sup, placeholder_region)) =>
{
Some((c.sub, cause.clone()))
}
_ => None,
};
let mut find_culprit = |exact_match: bool| {
region_constraints

View file

@ -613,7 +613,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
/// name where required.
pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
// We need to add synthesized lifetimes where appropriate. We do
// this by hooking into the pretty printer and telling it to label the
@ -624,19 +624,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
| ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: br, .. },
..
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
}) => p.region_highlight_mode.highlighting_bound_region(br, counter),
_ => {}
}
}
ty.print(&mut printer).unwrap();
printer.into_buffer()
ty.print(&mut p).unwrap();
p.into_buffer()
}
/// Returns the name of the provided `Ty` (that must be a reference)'s region with a
/// synthesized lifetime name where required.
pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
let region = if let ty::Ref(region, ..) = ty.kind() {
match region.kind() {
@ -644,7 +644,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
| ty::RePlaceholder(ty::PlaceholderRegion {
bound: ty::BoundRegion { kind: br, .. },
..
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
}) => p.region_highlight_mode.highlighting_bound_region(br, counter),
_ => {}
}
region
@ -652,8 +652,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
bug!("ty for annotation of borrow region is not a reference");
};
region.print(&mut printer).unwrap();
printer.into_buffer()
region.print(&mut p).unwrap();
p.into_buffer()
}
/// Add a note to region errors and borrow explanations when higher-ranked regions in predicates

View file

@ -417,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// minimum values.
///
/// For example:
/// ```
/// ```ignore (illustrative)
/// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ }
/// ```
/// would initialize two variables like so:

View file

@ -86,7 +86,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// them with fresh ty vars.
resume_ty: next_ty_var(),
yield_ty: next_ty_var(),
witness: next_ty_var(),
},
)
.args,

View file

@ -187,7 +187,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
types: &mut |_bound_ty: ty::BoundTy| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_var: ty::BoundVar| {
consts: &mut |_bound_const: ty::BoundConst| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};
@ -226,7 +226,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
types: &mut |_bound_ty: ty::BoundTy| {
unreachable!("we only replace regions in nll_relate, not types")
},
consts: &mut |_bound_var: ty::BoundVar| {
consts: &mut |_bound_const: ty::BoundConst| {
unreachable!("we only replace regions in nll_relate, not consts")
},
};

View file

@ -31,7 +31,7 @@ pub fn run() -> Result<(), String> {
Some("clones/abi-cafe".as_ref()),
true,
)
.map_err(|err| (format!("Git clone failed with message: {err:?}!")))?;
.map_err(|err| format!("Git clone failed with message: {err:?}!"))?;
// Configure abi-cafe to use the exact same rustc version we use - this is crucial.
// Otherwise, the concept of ABI compatibility becomes meanignless.
std::fs::copy("rust-toolchain", "clones/abi-cafe/rust-toolchain")

View file

@ -43,18 +43,18 @@ pub fn run() -> Result<(), String> {
"--start" => {
start =
str::parse(&args.next().ok_or_else(|| "Fuzz start not provided!".to_string())?)
.map_err(|err| (format!("Fuzz start not a number {err:?}!")))?;
.map_err(|err| format!("Fuzz start not a number {err:?}!"))?;
}
"--count" => {
count =
str::parse(&args.next().ok_or_else(|| "Fuzz count not provided!".to_string())?)
.map_err(|err| (format!("Fuzz count not a number {err:?}!")))?;
.map_err(|err| format!("Fuzz count not a number {err:?}!"))?;
}
"-j" | "--jobs" => {
threads = str::parse(
&args.next().ok_or_else(|| "Fuzz thread count not provided!".to_string())?,
)
.map_err(|err| (format!("Fuzz thread count not a number {err:?}!")))?;
.map_err(|err| format!("Fuzz thread count not a number {err:?}!"))?;
}
_ => return Err(format!("Unknown option {arg}")),
}
@ -66,7 +66,7 @@ pub fn run() -> Result<(), String> {
Some("clones/rustlantis".as_ref()),
true,
)
.map_err(|err| (format!("Git clone failed with message: {err:?}!")))?;
.map_err(|err| format!("Git clone failed with message: {err:?}!"))?;
// Ensure that we are on the newest rustlantis commit.
let cmd: &[&dyn AsRef<OsStr>] = &[&"git", &"pull", &"origin"];

View file

@ -1,29 +1,28 @@
From b8f3eed3053c9333b5dfbeaeb2a6a65a4b3156df Mon Sep 17 00:00:00 2001
From: Antoni Boucher <bouanto@zoho.com>
Date: Tue, 29 Aug 2023 13:06:34 -0400
From 190e26c9274b3c93a9ee3516b395590e6bd9213b Mon Sep 17 00:00:00 2001
From: None <none@example.com>
Date: Sun, 3 Aug 2025 19:54:56 -0400
Subject: [PATCH] Patch 0001-Add-stdarch-Cargo.toml-for-testing.patch
---
library/stdarch/Cargo.toml | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
library/stdarch/Cargo.toml | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 library/stdarch/Cargo.toml
diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml
new file mode 100644
index 0000000..4c63700
index 0000000..bd6725c
--- /dev/null
+++ b/library/stdarch/Cargo.toml
@@ -0,0 +1,21 @@
@@ -0,0 +1,20 @@
+[workspace]
+resolver = "1"
+members = [
+ "crates/core_arch",
+ "crates/std_detect",
+ "crates/stdarch-gen-arm",
+ "crates/*",
+ #"examples/"
+]
+exclude = [
+ "crates/wasm-assert-instr-tests"
+ "crates/wasm-assert-instr-tests",
+ "rust_programs",
+]
+
+[profile.release]
@ -36,5 +35,5 @@ index 0000000..4c63700
+opt-level = 3
+incremental = true
--
2.42.0
2.50.1

View file

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2025-07-04"
channel = "nightly-2025-08-03"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]

View file

@ -99,11 +99,15 @@ fn create_const_value_function(
let func = context.new_function(None, FunctionType::Exported, output, &[], name, false);
#[cfg(feature = "master")]
func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc(
tcx.sess.default_visibility(),
)));
{
func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc(
tcx.sess.default_visibility(),
)));
func.add_attribute(FnAttribute::AlwaysInline);
// FIXME(antoyo): cg_llvm sets AlwaysInline, but AlwaysInline is different in GCC and using
// it here will causes linking errors when using LTO.
func.add_attribute(FnAttribute::Inline);
}
if tcx.sess.must_emit_unwind_tables() {
// TODO(antoyo): emit unwind tables.

View file

@ -540,9 +540,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
fn ret(&mut self, mut value: RValue<'gcc>) {
let expected_return_type = self.current_func().get_return_type();
if !expected_return_type.is_compatible_with(value.get_type()) {
// NOTE: due to opaque pointers now being used, we need to cast here.
value = self.context.new_cast(self.location, value, expected_return_type);
let value_type = value.get_type();
if !expected_return_type.is_compatible_with(value_type) {
// NOTE: due to opaque pointers now being used, we need to (bit)cast here.
if self.is_native_int_type(value_type) && self.is_native_int_type(expected_return_type)
{
value = self.context.new_cast(self.location, value, expected_return_type);
} else {
value = self.context.new_bitcast(self.location, value, expected_return_type);
}
}
self.llbb().end_with_return(self.location, value);
}
@ -1279,11 +1285,19 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
fn intcast(
&mut self,
value: RValue<'gcc>,
mut value: RValue<'gcc>,
dest_typ: Type<'gcc>,
_is_signed: bool,
is_signed: bool,
) -> RValue<'gcc> {
// NOTE: is_signed is for value, not dest_typ.
let value_type = value.get_type();
if is_signed && !value_type.is_signed(self.cx) {
let signed_type = value_type.to_signed(self.cx);
value = self.gcc_int_cast(value, signed_type);
} else if !is_signed && value_type.is_signed(self.cx) {
let unsigned_type = value_type.to_unsigned(self.cx);
value = self.gcc_int_cast(value, unsigned_type);
}
self.gcc_int_cast(value, dest_typ)
}

View file

@ -4,12 +4,15 @@
// cSpell:words cmpti divti modti mulodi muloti udivti umodti
use gccjit::{BinaryOp, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp};
use gccjit::{
BinaryOp, CType, ComparisonOp, FunctionType, Location, RValue, ToRValue, Type, UnaryOp,
};
use rustc_abi::{CanonAbi, Endian, ExternAbi};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeCodegenMethods, BuilderMethods, OverflowOp};
use rustc_middle::ty::{self, Ty};
use rustc_target::callconv::{ArgAbi, ArgAttributes, FnAbi, PassMode};
use rustc_type_ir::{Interner, TyKind};
use crate::builder::{Builder, ToGccComp};
use crate::common::{SignType, TypeReflection};
@ -167,9 +170,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
if a_type.is_vector() {
// Vector types need to be bitcast.
// TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
b = self.context.new_bitcast(self.location, b, a.get_type());
b = self.context.new_bitcast(self.location, b, a_type);
} else {
b = self.context.new_cast(self.location, b, a.get_type());
b = self.context.new_cast(self.location, b, a_type);
}
}
self.context.new_binary_op(self.location, operation, a_type, a, b)
@ -216,13 +219,22 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
operation_name: &str,
signed: bool,
a: RValue<'gcc>,
b: RValue<'gcc>,
mut b: RValue<'gcc>,
) -> RValue<'gcc> {
let a_type = a.get_type();
let b_type = b.get_type();
if (self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type))
|| (a_type.is_vector() && b_type.is_vector())
{
if !a_type.is_compatible_with(b_type) {
if a_type.is_vector() {
// Vector types need to be bitcast.
// TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
b = self.context.new_bitcast(self.location, b, a_type);
} else {
b = self.context.new_cast(self.location, b, a_type);
}
}
self.context.new_binary_op(self.location, operation, a_type, a, b)
} else {
debug_assert!(a_type.dyncast_array().is_some());
@ -351,6 +363,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo): is it correct to use rhs type instead of the parameter typ?
.new_local(self.location, rhs.get_type(), "binopResult")
.get_address(self.location);
let new_type = type_kind_to_gcc_type(new_kind);
let new_type = self.context.new_c_type(new_type);
let lhs = self.context.new_cast(self.location, lhs, new_type);
let rhs = self.context.new_cast(self.location, rhs, new_type);
let res = self.context.new_cast(self.location, res, new_type.make_pointer());
let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None);
(res.dereference(self.location).to_rvalue(), overflow)
}
@ -477,11 +494,27 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let lhs_low = self.context.new_cast(self.location, self.low(lhs), unsigned_type);
let rhs_low = self.context.new_cast(self.location, self.low(rhs), unsigned_type);
let mut lhs_high = self.high(lhs);
let mut rhs_high = self.high(rhs);
match op {
IntPredicate::IntUGT
| IntPredicate::IntUGE
| IntPredicate::IntULT
| IntPredicate::IntULE => {
lhs_high = self.context.new_cast(self.location, lhs_high, unsigned_type);
rhs_high = self.context.new_cast(self.location, rhs_high, unsigned_type);
}
// TODO(antoyo): we probably need to handle signed comparison for unsigned
// integers.
_ => (),
}
let condition = self.context.new_comparison(
self.location,
ComparisonOp::LessThan,
self.high(lhs),
self.high(rhs),
lhs_high,
rhs_high,
);
self.llbb().end_with_conditional(self.location, condition, block1, block2);
@ -495,8 +528,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let condition = self.context.new_comparison(
self.location,
ComparisonOp::GreaterThan,
self.high(lhs),
self.high(rhs),
lhs_high,
rhs_high,
);
block2.end_with_conditional(self.location, condition, block3, block4);
@ -620,7 +653,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
}
}
pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
pub fn gcc_xor(&self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
let a_type = a.get_type();
let b_type = b.get_type();
if a_type.is_vector() && b_type.is_vector() {
@ -628,6 +661,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
a ^ b
} else if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type)
{
if !a_type.is_compatible_with(b_type) {
b = self.context.new_cast(self.location, b, a_type);
}
a ^ b
} else {
self.concat_low_high_rvalues(
@ -1042,3 +1078,25 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
self.context.new_array_constructor(None, typ, &values)
}
}
fn type_kind_to_gcc_type<I: Interner>(kind: TyKind<I>) -> CType {
use rustc_middle::ty::IntTy::*;
use rustc_middle::ty::UintTy::*;
use rustc_middle::ty::{Int, Uint};
match kind {
Int(I8) => CType::Int8t,
Int(I16) => CType::Int16t,
Int(I32) => CType::Int32t,
Int(I64) => CType::Int64t,
Int(I128) => CType::Int128t,
Uint(U8) => CType::UInt8t,
Uint(U16) => CType::UInt16t,
Uint(U32) => CType::UInt32t,
Uint(U64) => CType::UInt64t,
Uint(U128) => CType::UInt128t,
_ => unimplemented!("Kind: {:?}", kind),
}
}

View file

@ -95,8 +95,11 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str {
"cubema" => "__builtin_amdgcn_cubema",
"cubesc" => "__builtin_amdgcn_cubesc",
"cubetc" => "__builtin_amdgcn_cubetc",
"cvt.f16.bf8" => "__builtin_amdgcn_cvt_f16_bf8",
"cvt.f16.fp8" => "__builtin_amdgcn_cvt_f16_fp8",
"cvt.f32.bf8" => "__builtin_amdgcn_cvt_f32_bf8",
"cvt.f32.fp8" => "__builtin_amdgcn_cvt_f32_fp8",
"cvt.f32.fp8.e5m3" => "__builtin_amdgcn_cvt_f32_fp8_e5m3",
"cvt.off.f32.i4" => "__builtin_amdgcn_cvt_off_f32_i4",
"cvt.pk.bf8.f32" => "__builtin_amdgcn_cvt_pk_bf8_f32",
"cvt.pk.f16.bf8" => "__builtin_amdgcn_cvt_pk_f16_bf8",
@ -181,6 +184,12 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str {
"dot4.f32.fp8.bf8" => "__builtin_amdgcn_dot4_f32_fp8_bf8",
"dot4.f32.fp8.fp8" => "__builtin_amdgcn_dot4_f32_fp8_fp8",
"ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn",
"ds.atomic.async.barrier.arrive.b64" => {
"__builtin_amdgcn_ds_atomic_async_barrier_arrive_b64"
}
"ds.atomic.barrier.arrive.rtn.b64" => {
"__builtin_amdgcn_ds_atomic_barrier_arrive_rtn_b64"
}
"ds.bpermute" => "__builtin_amdgcn_ds_bpermute",
"ds.bpermute.fi.b32" => "__builtin_amdgcn_ds_bpermute_fi_b32",
"ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier",
@ -198,8 +207,32 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str {
"fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16",
"fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16",
"fdot2c.f32.bf16" => "__builtin_amdgcn_fdot2c_f32_bf16",
"flat.prefetch" => "__builtin_amdgcn_flat_prefetch",
"fmul.legacy" => "__builtin_amdgcn_fmul_legacy",
"global.load.async.to.lds.b128" => {
"__builtin_amdgcn_global_load_async_to_lds_b128"
}
"global.load.async.to.lds.b32" => {
"__builtin_amdgcn_global_load_async_to_lds_b32"
}
"global.load.async.to.lds.b64" => {
"__builtin_amdgcn_global_load_async_to_lds_b64"
}
"global.load.async.to.lds.b8" => "__builtin_amdgcn_global_load_async_to_lds_b8",
"global.load.lds" => "__builtin_amdgcn_global_load_lds",
"global.prefetch" => "__builtin_amdgcn_global_prefetch",
"global.store.async.from.lds.b128" => {
"__builtin_amdgcn_global_store_async_from_lds_b128"
}
"global.store.async.from.lds.b32" => {
"__builtin_amdgcn_global_store_async_from_lds_b32"
}
"global.store.async.from.lds.b64" => {
"__builtin_amdgcn_global_store_async_from_lds_b64"
}
"global.store.async.from.lds.b8" => {
"__builtin_amdgcn_global_store_async_from_lds_b8"
}
"groupstaticsize" => "__builtin_amdgcn_groupstaticsize",
"iglp.opt" => "__builtin_amdgcn_iglp_opt",
"implicit.buffer.ptr" => "__builtin_amdgcn_implicit_buffer_ptr",
@ -291,6 +324,7 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str {
"s.incperflevel" => "__builtin_amdgcn_s_incperflevel",
"s.memrealtime" => "__builtin_amdgcn_s_memrealtime",
"s.memtime" => "__builtin_amdgcn_s_memtime",
"s.monitor.sleep" => "__builtin_amdgcn_s_monitor_sleep",
"s.sendmsg" => "__builtin_amdgcn_s_sendmsg",
"s.sendmsghalt" => "__builtin_amdgcn_s_sendmsghalt",
"s.setprio" => "__builtin_amdgcn_s_setprio",
@ -300,11 +334,15 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str {
"s.sleep.var" => "__builtin_amdgcn_s_sleep_var",
"s.ttracedata" => "__builtin_amdgcn_s_ttracedata",
"s.ttracedata.imm" => "__builtin_amdgcn_s_ttracedata_imm",
"s.wait.asynccnt" => "__builtin_amdgcn_s_wait_asynccnt",
"s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready",
"s.wait.tensorcnt" => "__builtin_amdgcn_s_wait_tensorcnt",
"s.waitcnt" => "__builtin_amdgcn_s_waitcnt",
"sad.hi.u8" => "__builtin_amdgcn_sad_hi_u8",
"sad.u16" => "__builtin_amdgcn_sad_u16",
"sad.u8" => "__builtin_amdgcn_sad_u8",
"sat.pk4.i4.i8" => "__builtin_amdgcn_sat_pk4_i4_i8",
"sat.pk4.u4.u8" => "__builtin_amdgcn_sat_pk4_u4_u8",
"sched.barrier" => "__builtin_amdgcn_sched_barrier",
"sched.group.barrier" => "__builtin_amdgcn_sched_group_barrier",
"sdot2" => "__builtin_amdgcn_sdot2",
@ -346,8 +384,13 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str {
"smfmac.i32.16x16x64.i8" => "__builtin_amdgcn_smfmac_i32_16x16x64_i8",
"smfmac.i32.32x32x32.i8" => "__builtin_amdgcn_smfmac_i32_32x32x32_i8",
"smfmac.i32.32x32x64.i8" => "__builtin_amdgcn_smfmac_i32_32x32x64_i8",
"struct.ptr.buffer.load.lds" => "__builtin_amdgcn_struct_ptr_buffer_load_lds",
"sudot4" => "__builtin_amdgcn_sudot4",
"sudot8" => "__builtin_amdgcn_sudot8",
"tensor.load.to.lds" => "__builtin_amdgcn_tensor_load_to_lds",
"tensor.load.to.lds.d2" => "__builtin_amdgcn_tensor_load_to_lds_d2",
"tensor.store.from.lds" => "__builtin_amdgcn_tensor_store_from_lds",
"tensor.store.from.lds.d2" => "__builtin_amdgcn_tensor_store_from_lds_d2",
"udot2" => "__builtin_amdgcn_udot2",
"udot4" => "__builtin_amdgcn_udot4",
"udot8" => "__builtin_amdgcn_udot8",
@ -6326,6 +6369,23 @@ fn map_arch_intrinsic(full_name: &str) -> &'static str {
}
s390(name, full_name)
}
"spv" => {
#[allow(non_snake_case)]
fn spv(name: &str, full_name: &str) -> &'static str {
match name {
// spv
"num.subgroups" => "__builtin_spirv_num_subgroups",
"subgroup.id" => "__builtin_spirv_subgroup_id",
"subgroup.local.invocation.id" => {
"__builtin_spirv_subgroup_local_invocation_id"
}
"subgroup.max.size" => "__builtin_spirv_subgroup_max_size",
"subgroup.size" => "__builtin_spirv_subgroup_size",
_ => unimplemented!("***** unsupported LLVM intrinsic {full_name}"),
}
}
spv(name, full_name)
}
"ve" => {
#[allow(non_snake_case)]
fn ve(name: &str, full_name: &str) -> &'static str {

View file

@ -925,10 +925,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
// TODO(antoyo): use width?
let arg_type = arg.get_type();
let result_type = self.u32_type;
let arg = if arg_type.is_signed(self.cx) {
let new_type = arg_type.to_unsigned(self.cx);
self.gcc_int_cast(arg, new_type)
} else {
arg
};
let arg_type = arg.get_type();
let count_leading_zeroes =
// TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here
// instead of using is_uint().
if arg_type.is_uint(self.cx) {
if arg_type.is_uchar(self.cx) || arg_type.is_ushort(self.cx) || arg_type.is_uint(self.cx) {
"__builtin_clz"
}
else if arg_type.is_ulong(self.cx) {

View file

@ -206,6 +206,28 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
);
}
#[cfg(feature = "master")]
if name == sym::simd_funnel_shl {
return Ok(simd_funnel_shift(
bx,
args[0].immediate(),
args[1].immediate(),
args[2].immediate(),
true,
));
}
#[cfg(feature = "master")]
if name == sym::simd_funnel_shr {
return Ok(simd_funnel_shift(
bx,
args[0].immediate(),
args[1].immediate(),
args[2].immediate(),
false,
));
}
if name == sym::simd_bswap {
return Ok(simd_bswap(bx, args[0].immediate()));
}
@ -1434,3 +1456,62 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
unimplemented!("simd {}", name);
}
#[cfg(feature = "master")]
fn simd_funnel_shift<'a, 'gcc, 'tcx>(
bx: &mut Builder<'a, 'gcc, 'tcx>,
a: RValue<'gcc>,
b: RValue<'gcc>,
shift: RValue<'gcc>,
shift_left: bool,
) -> RValue<'gcc> {
use crate::common::SignType;
let a_type = a.get_type();
let vector_type = a_type.unqualified().dyncast_vector().expect("vector type");
let num_units = vector_type.get_num_units();
let elem_type = vector_type.get_element_type();
let (new_int_type, int_shift_val, int_mask) = if elem_type.is_compatible_with(bx.u8_type)
|| elem_type.is_compatible_with(bx.i8_type)
{
(bx.u16_type, 8, u8::MAX as u64)
} else if elem_type.is_compatible_with(bx.u16_type) || elem_type.is_compatible_with(bx.i16_type)
{
(bx.u32_type, 16, u16::MAX as u64)
} else if elem_type.is_compatible_with(bx.u32_type) || elem_type.is_compatible_with(bx.i32_type)
{
(bx.u64_type, 32, u32::MAX as u64)
} else if elem_type.is_compatible_with(bx.u64_type) || elem_type.is_compatible_with(bx.i64_type)
{
(bx.u128_type, 64, u64::MAX)
} else {
unimplemented!("funnel shift on {:?}", elem_type);
};
let int_mask = bx.context.new_rvalue_from_long(new_int_type, int_mask as i64);
let int_shift_val = bx.context.new_rvalue_from_int(new_int_type, int_shift_val);
let mut elements = vec![];
let unsigned_type = elem_type.to_unsigned(bx);
for i in 0..num_units {
let index = bx.context.new_rvalue_from_int(bx.int_type, i as i32);
let a_val = bx.context.new_vector_access(None, a, index).to_rvalue();
let a_val = bx.context.new_bitcast(None, a_val, unsigned_type);
// TODO: we probably need to use gcc_int_cast instead.
let a_val = bx.gcc_int_cast(a_val, new_int_type);
let b_val = bx.context.new_vector_access(None, b, index).to_rvalue();
let b_val = bx.context.new_bitcast(None, b_val, unsigned_type);
let b_val = bx.gcc_int_cast(b_val, new_int_type);
let shift_val = bx.context.new_vector_access(None, shift, index).to_rvalue();
let shift_val = bx.gcc_int_cast(shift_val, new_int_type);
let mut val = a_val << int_shift_val | b_val;
if shift_left {
val = (val << shift_val) >> int_shift_val;
} else {
val = (val >> shift_val) & int_mask;
}
let val = bx.gcc_int_cast(val, elem_type);
elements.push(val);
}
bx.context.new_rvalue_from_vector(None, a_type, &elements)
}

View file

@ -50,6 +50,7 @@ extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_symbol_mangling;
extern crate rustc_target;
extern crate rustc_type_ir;
// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
@ -362,9 +363,9 @@ impl WriteBackendMethods for GccCodegenBackend {
_exported_symbols_for_lto: &[String],
each_linked_rlib_for_lto: &[PathBuf],
modules: Vec<FatLtoInput<Self>>,
diff_fncs: Vec<AutoDiffItem>,
diff_functions: Vec<AutoDiffItem>,
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
if !diff_fncs.is_empty() {
if !diff_functions.is_empty() {
unimplemented!();
}

View file

@ -28,6 +28,6 @@ tests/ui/macros/macro-comma-behavior-rpass.rs
tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs
tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs
tests/ui/macros/stringify.rs
tests/ui/reexport-test-harness-main.rs
tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-in-test.rs
tests/ui/binding/fn-arg-incomplete-pattern-drop-order.rs
tests/ui/lto/debuginfo-lto-alloc.rs

View file

@ -6,7 +6,6 @@ tests/run-make/doctests-keep-binaries/
tests/run-make/doctests-runtool/
tests/run-make/emit-shared-files/
tests/run-make/exit-code/
tests/run-make/issue-22131/
tests/run-make/issue-64153/
tests/run-make/llvm-ident/
tests/run-make/native-link-modifier-bundle/

View file

@ -10,11 +10,10 @@ tests/ui/iterators/iter-sum-overflow-overflow-checks.rs
tests/ui/mir/mir_drop_order.rs
tests/ui/mir/mir_let_chains_drop_order.rs
tests/ui/mir/mir_match_guard_let_chains_drop_order.rs
tests/ui/oom_unwind.rs
tests/ui/panics/oom-panic-unwind.rs
tests/ui/panic-runtime/abort-link-to-unwinding-crates.rs
tests/ui/panic-runtime/abort.rs
tests/ui/panic-runtime/link-to-abort.rs
tests/ui/unwind-no-uwtable.rs
tests/ui/parser/unclosed-delimiter-in-dep.rs
tests/ui/consts/missing_span_in_backtrace.rs
tests/ui/drop/dynamic-drop.rs
@ -82,3 +81,8 @@ tests/ui/coroutine/panic-drops.rs
tests/ui/coroutine/panic-safe.rs
tests/ui/process/nofile-limit.rs
tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
tests/ui/linking/no-gc-encapsulation-symbols.rs
tests/ui/panics/unwind-force-no-unwind-tables.rs
tests/ui/attributes/fn-align-dyn.rs
tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs
tests/ui/explicit-tail-calls/recursion-etc.rs

View file

@ -8,6 +8,7 @@ clzll
cmse
codegened
csky
ctfe
ctlz
ctpop
cttz
@ -25,6 +26,7 @@ fwrapv
gimple
hrtb
immediates
interner
liblto
llbb
llcx
@ -47,6 +49,7 @@ mavx
mcmodel
minimumf
minnumf
miri
monomorphization
monomorphizations
monomorphized

View file

@ -1,3 +1,4 @@
use std::assert_matches::assert_matches;
use std::sync::Arc;
use itertools::Itertools;
@ -5,6 +6,7 @@ use rustc_abi::Align;
use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
use rustc_data_structures::fx::FxIndexMap;
use rustc_index::IndexVec;
use rustc_macros::TryFromU32;
use rustc_middle::ty::TyCtxt;
use rustc_session::RemapFileNameExt;
use rustc_session::config::RemapPathScopeComponents;
@ -20,6 +22,23 @@ mod covfun;
mod spans;
mod unused;
/// Version number that will be included the `__llvm_covmap` section header.
/// Corresponds to LLVM's `llvm::coverage::CovMapVersion` (in `CoverageMapping.h`),
/// or at least the subset that we know and care about.
///
/// Note that version `n` is encoded as `(n-1)`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, TryFromU32)]
enum CovmapVersion {
/// Used by LLVM 18 onwards.
Version7 = 6,
}
impl CovmapVersion {
fn to_u32(self) -> u32 {
self as u32
}
}
/// Generates and exports the coverage map, which is embedded in special
/// linker sections in the final binary.
///
@ -29,19 +48,13 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) {
let tcx = cx.tcx;
// Ensure that LLVM is using a version of the coverage mapping format that
// agrees with our Rust-side code. Expected versions (encoded as n-1) are:
// - `CovMapVersion::Version7` (6) used by LLVM 18-19
let covmap_version = {
let llvm_covmap_version = llvm_cov::mapping_version();
let expected_versions = 6..=6;
assert!(
expected_versions.contains(&llvm_covmap_version),
"Coverage mapping version exposed by `llvm-wrapper` is out of sync; \
expected {expected_versions:?} but was {llvm_covmap_version}"
);
// This is the version number that we will embed in the covmap section:
llvm_covmap_version
};
// agrees with our Rust-side code. Expected versions are:
// - `Version7` (6) used by LLVM 18 onwards.
let covmap_version =
CovmapVersion::try_from(llvm_cov::mapping_version()).unwrap_or_else(|raw_version: u32| {
panic!("unknown coverage mapping version reported by `llvm-wrapper`: {raw_version}")
});
assert_matches!(covmap_version, CovmapVersion::Version7);
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
@ -201,7 +214,11 @@ impl VirtualFileMapping {
/// Generates the contents of the covmap record for this CGU, which mostly
/// consists of a header and a list of filenames. The record is then stored
/// as a global variable in the `__llvm_covmap` section.
fn generate_covmap_record<'ll>(cx: &mut CodegenCx<'ll, '_>, version: u32, filenames_buffer: &[u8]) {
fn generate_covmap_record<'ll>(
cx: &mut CodegenCx<'ll, '_>,
version: CovmapVersion,
filenames_buffer: &[u8],
) {
// A covmap record consists of four target-endian u32 values, followed by
// the encoded filenames table. Two of the header fields are unused in
// modern versions of the LLVM coverage mapping format, and are always 0.
@ -212,7 +229,7 @@ fn generate_covmap_record<'ll>(cx: &mut CodegenCx<'ll, '_>, version: u32, filena
cx.const_u32(0), // (unused)
cx.const_u32(filenames_buffer.len() as u32),
cx.const_u32(0), // (unused)
cx.const_u32(version),
cx.const_u32(version.to_u32()),
],
/* packed */ false,
);

View file

@ -27,6 +27,9 @@ use crate::llvm;
/// the final record that will be embedded in the `__llvm_covfun` section.
#[derive(Debug)]
pub(crate) struct CovfunRecord<'tcx> {
/// Not used directly, but helpful in debug messages.
_instance: Instance<'tcx>,
mangled_function_name: &'tcx str,
source_hash: u64,
is_used: bool,
@ -55,6 +58,7 @@ pub(crate) fn prepare_covfun_record<'tcx>(
let expressions = prepare_expressions(ids_info);
let mut covfun = CovfunRecord {
_instance: instance,
mangled_function_name: tcx.symbol_name(instance).name,
source_hash: if is_used { fn_cov_info.function_source_hash } else { 0 },
is_used,
@ -102,11 +106,21 @@ fn fill_region_tables<'tcx>(
ids_info: &'tcx CoverageIdsInfo,
covfun: &mut CovfunRecord<'tcx>,
) {
// If this function is unused, replace all counters with zero.
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
let term = if covfun.is_used {
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
} else {
CovTerm::Zero
};
ffi::Counter::from_term(term)
};
// Currently a function's mappings must all be in the same file, so use the
// first mapping's span to determine the file.
let source_map = tcx.sess.source_map();
let Some(first_span) = (try { fn_cov_info.mappings.first()?.span }) else {
debug_assert!(false, "function has no mappings: {:?}", covfun.mangled_function_name);
debug_assert!(false, "function has no mappings: {covfun:?}");
return;
};
let source_file = source_map.lookup_source_file(first_span.lo());
@ -117,7 +131,7 @@ fn fill_region_tables<'tcx>(
// codegen needs to handle that gracefully to avoid #133606.
// It's hard for tests to trigger this organically, so instead we set
// `-Zcoverage-options=discard-all-spans-in-codegen` to force it to occur.
let discard_all = tcx.sess.coverage_discard_all_spans_in_codegen();
let discard_all = tcx.sess.coverage_options().discard_all_spans_in_codegen;
let make_coords = |span: Span| {
if discard_all { None } else { spans::make_coords(source_map, &source_file, span) }
};
@ -133,16 +147,6 @@ fn fill_region_tables<'tcx>(
// For each counter/region pair in this function+file, convert it to a
// form suitable for FFI.
for &Mapping { ref kind, span } in &fn_cov_info.mappings {
// If this function is unused, replace all counters with zero.
let counter_for_bcb = |bcb: BasicCoverageBlock| -> ffi::Counter {
let term = if covfun.is_used {
ids_info.term_for_bcb[bcb].expect("every BCB in a mapping was given a term")
} else {
CovTerm::Zero
};
ffi::Counter::from_term(term)
};
let Some(coords) = make_coords(span) else { continue };
let cov_span = coords.make_coverage_span(local_file_id);
@ -184,6 +188,7 @@ pub(crate) fn generate_covfun_record<'tcx>(
covfun: &CovfunRecord<'tcx>,
) {
let &CovfunRecord {
_instance,
mangled_function_name,
source_hash,
is_used,

View file

@ -2,9 +2,7 @@
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
use rustc_codegen_ssa::traits::*;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::find_attr;
use rustc_middle::bug;
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerType;
use rustc_session::config::{CrateType, DebugInfo};
@ -86,9 +84,6 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
}
pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
let omit_gdb_pretty_printer_section =
find_attr!(cx.tcx.hir_krate_attrs(), AttributeKind::OmitGdbPrettyPrinterSection);
// To ensure the section `__rustc_debug_gdb_scripts_section__` will not create
// ODR violations at link time, this section will not be emitted for rlibs since
// each rlib could produce a different set of visualizers that would be embedded
@ -117,8 +112,7 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
}
});
!omit_gdb_pretty_printer_section
&& cx.sess().opts.debuginfo != DebugInfo::None
cx.sess().opts.debuginfo != DebugInfo::None
&& cx.sess().target.emit_debug_gdb_scripts
&& embed_visualizers
}

View file

@ -1011,11 +1011,12 @@ fn link_natively(
(Strip::Debuginfo, _) => {
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
}
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
// Per the manpage, --discard-all is the maximum safe strip level for dynamic libraries. (#93988)
(
Strip::Symbols,
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib,
) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]),
) => strip_with_external_utility(sess, stripcmd, out_filename, &["--discard-all"]),
(Strip::Symbols, _) => {
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"])
}

View file

@ -11,6 +11,7 @@ use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::sym;
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use tracing::field::Empty;
use tracing::{info, instrument, trace};
use super::{
@ -18,7 +19,8 @@ use super::{
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok,
throw_ub, throw_ub_custom, throw_unsup_format,
};
use crate::fluent_generated as fluent;
use crate::interpret::EnteredTraceSpan;
use crate::{enter_trace_span, fluent_generated as fluent};
/// An argument passed to a function.
#[derive(Clone, Debug)]
@ -344,6 +346,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
destination: &PlaceTy<'tcx, M::Provenance>,
mut cont: ReturnContinuation,
) -> InterpResult<'tcx> {
let _span = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty);
// Compute callee information.
// FIXME: for variadic support, do we have to somehow determine callee's extra_args?
let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?;
@ -523,7 +527,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
target: Option<mir::BasicBlock>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
trace!("init_fn_call: {:#?}", fn_val);
let _span =
enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val)
.or_if_tracing_disabled(|| trace!("init_fn_call: {:#?}", fn_val));
let instance = match fn_val {
FnVal::Instance(instance) => instance,

View file

@ -937,8 +937,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
if let Some(fn_val) = self.get_fn_alloc(id) {
let align = match fn_val {
FnVal::Instance(instance) => {
self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE)
FnVal::Instance(_instance) => {
// FIXME: Until we have a clear design for the effects of align(N) functions
// on the address of function pointers, we don't consider the align(N)
// attribute on functions in the interpreter.
// See <https://github.com/rust-lang/rust/issues/144661> for more context.
Align::ONE
}
// Machine-specific extra functions currently do not support alignment restrictions.
FnVal::Other(_) => Align::ONE,

View file

@ -13,6 +13,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, mir, span_bug, ty};
use rustc_span::DUMMY_SP;
use tracing::field::Empty;
use tracing::trace;
use super::{
@ -20,6 +21,7 @@ use super::{
OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub,
from_known_layout, interp_ok, mir_assign_valid_types, throw_ub,
};
use crate::enter_trace_span;
/// An `Immediate` represents a single immediate self-contained Rust value.
///
@ -186,18 +188,18 @@ pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> {
impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// Helper function for printing a scalar to a FmtPrinter
fn p<'a, 'tcx, Prov: Provenance>(
cx: &mut FmtPrinter<'a, 'tcx>,
fn print_scalar<'a, 'tcx, Prov: Provenance>(
p: &mut FmtPrinter<'a, 'tcx>,
s: Scalar<Prov>,
ty: Ty<'tcx>,
) -> Result<(), std::fmt::Error> {
match s {
Scalar::Int(int) => cx.pretty_print_const_scalar_int(int, ty, true),
Scalar::Int(int) => p.pretty_print_const_scalar_int(int, ty, true),
Scalar::Ptr(ptr, _sz) => {
// Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to
// print what is points to, which would fail since it has no access to the local
// memory.
cx.pretty_print_const_pointer(ptr, ty)
p.pretty_print_const_pointer(ptr, ty)
}
}
}
@ -205,8 +207,9 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
match self.imm {
Immediate::Scalar(s) => {
if let Some(ty) = tcx.lift(self.layout.ty) {
let s =
FmtPrinter::print_string(tcx, Namespace::ValueNS, |cx| p(cx, s, ty))?;
let s = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| {
print_scalar(p, s, ty)
})?;
f.write_str(&s)?;
return Ok(());
}
@ -770,6 +773,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
mir_place: mir::Place<'tcx>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
let _span = enter_trace_span!(
M,
step::eval_place_to_op,
?mir_place,
tracing_separate_thread = Empty
);
// Do not use the layout passed in as argument if the base we are looking at
// here is not the entire place.
let layout = if mir_place.projection.is_empty() { layout } else { None };
@ -813,6 +823,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
mir_op: &mir::Operand<'tcx>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
let _span =
enter_trace_span!(M, step::eval_operand, ?mir_op, tracing_separate_thread = Empty);
use rustc_middle::mir::Operand::*;
let op = match mir_op {
// FIXME: do some more logic on `move` to invalidate the old location

View file

@ -9,6 +9,7 @@ use rustc_abi::{BackendRepr, HasDataLayout, Size};
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, mir, span_bug};
use tracing::field::Empty;
use tracing::{instrument, trace};
use super::{
@ -16,6 +17,7 @@ use super::{
InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer,
Projectable, Provenance, Scalar, alloc_range, interp_ok, mir_assign_valid_types,
};
use crate::enter_trace_span;
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
/// Information required for the sound usage of a `MemPlace`.
@ -524,6 +526,9 @@ where
&self,
mir_place: mir::Place<'tcx>,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
let _span =
enter_trace_span!(M, step::eval_place, ?mir_place, tracing_separate_thread = Empty);
let mut place = self.local_to_place(mir_place.local)?;
// Using `try_fold` turned out to be bad for performance, hence the loop.
for elem in mir_place.projection.iter() {

View file

@ -199,6 +199,15 @@ where
base.offset_with_meta(offset, OffsetMode::Inbounds, meta, field_layout, self)
}
/// Projects multiple fields at once. See [`Self::project_field`] for details.
pub fn project_fields<P: Projectable<'tcx, M::Provenance>, const N: usize>(
&self,
base: &P,
fields: [FieldIdx; N],
) -> InterpResult<'tcx, [P; N]> {
fields.try_map(|field| self.project_field(base, field))
}
/// Downcasting to an enum variant.
pub fn project_downcast<P: Projectable<'tcx, M::Provenance>>(
&self,

View file

@ -9,13 +9,15 @@ use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::source_map::Spanned;
use rustc_target::callconv::FnAbi;
use tracing::field::Empty;
use tracing::{info, instrument, trace};
use super::{
FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy,
Projectable, Scalar, interp_ok, throw_ub, throw_unsup_format,
};
use crate::util;
use crate::interpret::EnteredTraceSpan;
use crate::{enter_trace_span, util};
struct EvaluatedCalleeAndArgs<'tcx, M: Machine<'tcx>> {
callee: FnVal<'tcx, M::ExtraFnVal>,
@ -74,7 +76,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
///
/// This does NOT move the statement counter forward, the caller has to do that!
pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
info!("{:?}", stmt);
let _span = enter_trace_span!(
M,
step::eval_statement,
stmt = ?stmt.kind,
span = ?stmt.source_info.span,
tracing_separate_thread = Empty,
)
.or_if_tracing_disabled(|| info!(stmt = ?stmt.kind));
use rustc_middle::mir::StatementKind::*;
@ -456,7 +465,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
info!("{:?}", terminator.kind);
let _span = enter_trace_span!(
M,
step::eval_terminator,
terminator = ?terminator.kind,
span = ?terminator.source_info.span,
tracing_separate_thread = Empty,
)
.or_if_tracing_disabled(|| info!(terminator = ?terminator.kind));
use rustc_middle::mir::TerminatorKind::*;
match terminator.kind {

View file

@ -48,10 +48,24 @@ pub(crate) fn create_static_alloc<'tcx>(
/// A marker trait returned by [crate::interpret::Machine::enter_trace_span], identifying either a
/// real [tracing::span::EnteredSpan] in case tracing is enabled, or the dummy type `()` when
/// tracing is disabled.
pub trait EnteredTraceSpan {}
impl EnteredTraceSpan for () {}
impl EnteredTraceSpan for tracing::span::EnteredSpan {}
/// tracing is disabled. Also see [crate::enter_trace_span!] below.
pub trait EnteredTraceSpan {
/// Allows executing an alternative function when tracing is disabled. Useful for example if you
/// want to open a trace span when tracing is enabled, and alternatively just log a line when
/// tracing is disabled.
fn or_if_tracing_disabled(self, f: impl FnOnce()) -> Self;
}
impl EnteredTraceSpan for () {
fn or_if_tracing_disabled(self, f: impl FnOnce()) -> Self {
f(); // tracing is disabled, execute the function
self
}
}
impl EnteredTraceSpan for tracing::span::EnteredSpan {
fn or_if_tracing_disabled(self, _f: impl FnOnce()) -> Self {
self // tracing is enabled, don't execute anything
}
}
/// Shortand for calling [crate::interpret::Machine::enter_trace_span] on a [tracing::info_span!].
/// This is supposed to be compiled out when [crate::interpret::Machine::enter_trace_span] has the
@ -112,6 +126,19 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {}
/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
/// let _span = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty);
/// ```
///
/// ### Executing something else when tracing is disabled
///
/// [crate::interpret::Machine::enter_trace_span] returns [EnteredTraceSpan], on which you can call
/// [EnteredTraceSpan::or_if_tracing_disabled], to e.g. log a line as an alternative to the tracing
/// span for when tracing is disabled. For example:
/// ```rust
/// # use rustc_const_eval::enter_trace_span;
/// # use rustc_const_eval::interpret::EnteredTraceSpan;
/// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
/// let _span = enter_trace_span!(M, step::eval_statement)
/// .or_if_tracing_disabled(|| tracing::info!("eval_statement"));
/// ```
#[macro_export]
macro_rules! enter_trace_span {
($machine:ty, $name:ident :: $subname:ident $($tt:tt)*) => {

View file

@ -121,25 +121,24 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
// `Box` has two fields: the pointer we care about, and the allocator.
assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields");
let (unique_ptr, alloc) = (
self.ecx().project_field(v, FieldIdx::ZERO)?,
self.ecx().project_field(v, FieldIdx::ONE)?,
);
let [unique_ptr, alloc] =
self.ecx().project_fields(v, [FieldIdx::ZERO, FieldIdx::ONE])?;
// Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`...
// (which means another 2 fields, the second of which is a `PhantomData`)
assert_eq!(unique_ptr.layout().fields.count(), 2);
let (nonnull_ptr, phantom) = (
self.ecx().project_field(&unique_ptr, FieldIdx::ZERO)?,
self.ecx().project_field(&unique_ptr, FieldIdx::ONE)?,
);
let [nonnull_ptr, phantom] =
self.ecx().project_fields(&unique_ptr, [FieldIdx::ZERO, FieldIdx::ONE])?;
assert!(
phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
"2nd field of `Unique` should be PhantomData but is {:?}",
phantom.layout().ty,
);
// ... that contains a `NonNull`... (gladly, only a single field here)
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
let raw_ptr = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // the actual raw ptr
// ... whose only field finally is a raw ptr we can dereference.
self.visit_box(ty, &raw_ptr)?;

View file

@ -2,6 +2,7 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![doc(rust_logo)]
#![feature(array_try_map)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]

View file

@ -42,12 +42,12 @@ fn alloc_caller_location<'tcx>(
let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();
// Initialize fields.
ecx.write_immediate(filename, &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap())
.expect("writing to memory we just allocated cannot fail");
ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap())
.expect("writing to memory we just allocated cannot fail");
ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap())
let [filename_field, line_field, col_field] =
ecx.project_fields(&location, [0, 1, 2].map(FieldIdx::from_u32)).unwrap();
ecx.write_immediate(filename, &filename_field)
.expect("writing to memory we just allocated cannot fail");
ecx.write_scalar(line, &line_field).expect("writing to memory we just allocated cannot fail");
ecx.write_scalar(col, &col_field).expect("writing to memory we just allocated cannot fail");
location
}

View file

@ -4,7 +4,7 @@ use rustc_data_structures::intern::Interned;
use rustc_hir::def_id::CrateNum;
use rustc_hir::definitions::DisambiguatedDefPathData;
use rustc_middle::bug;
use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer};
use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt};
struct AbsolutePathPrinter<'tcx> {
@ -18,7 +18,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
}
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
Ok(())
unreachable!(); // because `<Self As PrettyPrinter>::should_print_region` returns false
}
fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
@ -89,7 +89,6 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
fn path_append_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_disambiguated_data: &DisambiguatedDefPathData,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
@ -138,19 +137,6 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
false
}
fn comma_sep<T>(&mut self, mut elems: impl Iterator<Item = T>) -> Result<(), PrintError>
where
T: Print<'tcx, Self>,
{
if let Some(first) = elems.next() {
first.print(self)?;
for elem in elems {
self.path.push_str(", ");
elem.print(self)?;
}
}
Ok(())
}
fn generic_delimiters(
&mut self,
@ -179,7 +165,7 @@ impl Write for AbsolutePathPrinter<'_> {
}
pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
let mut printer = AbsolutePathPrinter { tcx, path: String::new() };
printer.print_type(ty).unwrap();
printer.path
let mut p = AbsolutePathPrinter { tcx, path: String::new() };
p.print_type(ty).unwrap();
p.path
}

View file

@ -1,5 +1,4 @@
Abstract return types (written `impl Trait` for some trait `Trait`) are only
allowed as function and inherent impl return types.
`impl Trait` is only allowed as a function return and argument type.
Erroneous code example:
@ -14,7 +13,7 @@ fn main() {
}
```
Make sure `impl Trait` only appears in return-type position.
Make sure `impl Trait` appears in a function signature.
```
fn count_to_n(n: usize) -> impl Iterator<Item=usize> {
@ -28,6 +27,6 @@ fn main() {
}
```
See [RFC 1522] for more details.
See the [reference] for more details on `impl Trait`.
[RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md
[reference]: https://doc.rust-lang.org/stable/reference/types/impl-trait.html

View file

@ -262,19 +262,11 @@ pub trait Emitter {
format!("help: {msg}")
} else {
// Show the default suggestion text with the substitution
format!(
"help: {}{}: `{}`",
msg,
if self
.source_map()
.is_some_and(|sm| is_case_difference(sm, snippet, part.span,))
{
" (notice the capitalization)"
} else {
""
},
snippet,
)
let confusion_type = self
.source_map()
.map(|sm| detect_confusion_type(sm, snippet, part.span))
.unwrap_or(ConfusionType::None);
format!("help: {}{}: `{}`", msg, confusion_type.label_text(), snippet,)
};
primary_span.push_span_label(part.span, msg);
@ -2031,12 +2023,12 @@ impl HumanEmitter {
buffer.append(0, ": ", Style::HeaderMsg);
let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)];
if suggestions
.iter()
.take(MAX_SUGGESTIONS)
.any(|(_, _, _, only_capitalization)| *only_capitalization)
if let Some(confusion_type) =
suggestions.iter().take(MAX_SUGGESTIONS).find_map(|(_, _, _, confusion_type)| {
if confusion_type.has_confusion() { Some(*confusion_type) } else { None }
})
{
msg.push((" (notice the capitalization difference)".into(), Style::NoStyle));
msg.push((confusion_type.label_text().into(), Style::NoStyle));
}
self.msgs_to_buffer(
&mut buffer,
@ -3531,24 +3523,107 @@ pub fn is_different(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
}
/// Whether the original and suggested code are visually similar enough to warrant extra wording.
pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
// FIXME: this should probably be extended to also account for `FO0` → `FOO` and unicode.
pub fn detect_confusion_type(sm: &SourceMap, suggested: &str, sp: Span) -> ConfusionType {
let found = match sm.span_to_snippet(sp) {
Ok(snippet) => snippet,
Err(e) => {
warn!(error = ?e, "Invalid span {:?}", sp);
return false;
return ConfusionType::None;
}
};
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
// All the chars that differ in capitalization are confusable (above):
let confusable = iter::zip(found.chars(), suggested.chars())
.filter(|(f, s)| f != s)
.all(|(f, s)| ascii_confusables.contains(&f) || ascii_confusables.contains(&s));
confusable && found.to_lowercase() == suggested.to_lowercase()
// FIXME: We sometimes suggest the same thing we already have, which is a
// bug, but be defensive against that here.
&& found != suggested
let mut has_case_confusion = false;
let mut has_digit_letter_confusion = false;
if found.len() == suggested.len() {
let mut has_case_diff = false;
let mut has_digit_letter_confusable = false;
let mut has_other_diff = false;
let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z'];
let digit_letter_confusables = [('0', 'O'), ('1', 'l'), ('5', 'S'), ('8', 'B'), ('9', 'g')];
for (f, s) in iter::zip(found.chars(), suggested.chars()) {
if f != s {
if f.to_lowercase().to_string() == s.to_lowercase().to_string() {
// Check for case differences (any character that differs only in case)
if ascii_confusables.contains(&f) || ascii_confusables.contains(&s) {
has_case_diff = true;
} else {
has_other_diff = true;
}
} else if digit_letter_confusables.contains(&(f, s))
|| digit_letter_confusables.contains(&(s, f))
{
// Check for digit-letter confusables (like 0 vs O, 1 vs l, etc.)
has_digit_letter_confusable = true;
} else {
has_other_diff = true;
}
}
}
// If we have case differences and no other differences
if has_case_diff && !has_other_diff && found != suggested {
has_case_confusion = true;
}
if has_digit_letter_confusable && !has_other_diff && found != suggested {
has_digit_letter_confusion = true;
}
}
match (has_case_confusion, has_digit_letter_confusion) {
(true, true) => ConfusionType::Both,
(true, false) => ConfusionType::Case,
(false, true) => ConfusionType::DigitLetter,
(false, false) => ConfusionType::None,
}
}
/// Represents the type of confusion detected between original and suggested code.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConfusionType {
/// No confusion detected
None,
/// Only case differences (e.g., "hello" vs "Hello")
Case,
/// Only digit-letter confusion (e.g., "0" vs "O", "1" vs "l")
DigitLetter,
/// Both case and digit-letter confusion
Both,
}
impl ConfusionType {
/// Returns the appropriate label text for this confusion type.
pub fn label_text(&self) -> &'static str {
match self {
ConfusionType::None => "",
ConfusionType::Case => " (notice the capitalization)",
ConfusionType::DigitLetter => " (notice the digit/letter confusion)",
ConfusionType::Both => " (notice the capitalization and digit/letter confusion)",
}
}
/// Combines two confusion types. If either is `Both`, the result is `Both`.
/// If one is `Case` and the other is `DigitLetter`, the result is `Both`.
/// Otherwise, returns the non-`None` type, or `None` if both are `None`.
pub fn combine(self, other: ConfusionType) -> ConfusionType {
match (self, other) {
(ConfusionType::None, other) => other,
(this, ConfusionType::None) => this,
(ConfusionType::Both, _) | (_, ConfusionType::Both) => ConfusionType::Both,
(ConfusionType::Case, ConfusionType::DigitLetter)
| (ConfusionType::DigitLetter, ConfusionType::Case) => ConfusionType::Both,
(ConfusionType::Case, ConfusionType::Case) => ConfusionType::Case,
(ConfusionType::DigitLetter, ConfusionType::DigitLetter) => ConfusionType::DigitLetter,
}
}
/// Returns true if this confusion type represents any kind of confusion.
pub fn has_confusion(&self) -> bool {
*self != ConfusionType::None
}
}
pub(crate) fn should_show_source_code(

View file

@ -50,7 +50,7 @@ pub use diagnostic_impls::{
IndicateAnonymousLifetime, SingleLabelManySpans,
};
pub use emitter::ColorConfig;
use emitter::{DynEmitter, Emitter, is_case_difference, is_different};
use emitter::{ConfusionType, DynEmitter, Emitter, detect_confusion_type, is_different};
use rustc_data_structures::AtomicRef;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::StableHasher;
@ -308,7 +308,7 @@ impl CodeSuggestion {
pub(crate) fn splice_lines(
&self,
sm: &SourceMap,
) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, ConfusionType)> {
// For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
// corresponds to the output snippet's lines, while the second level corresponds to the
// substrings within that line that should be highlighted.
@ -414,14 +414,15 @@ impl CodeSuggestion {
// We need to keep track of the difference between the existing code and the added
// or deleted code in order to point at the correct column *after* substitution.
let mut acc = 0;
let mut only_capitalization = false;
let mut confusion_type = ConfusionType::None;
for part in &mut substitution.parts {
// If this is a replacement of, e.g. `"a"` into `"ab"`, adjust the
// suggestion and snippet to look as if we just suggested to add
// `"b"`, which is typically much easier for the user to understand.
part.trim_trivial_replacements(sm);
only_capitalization |= is_case_difference(sm, &part.snippet, part.span);
let part_confusion = detect_confusion_type(sm, &part.snippet, part.span);
confusion_type = confusion_type.combine(part_confusion);
let cur_lo = sm.lookup_char_pos(part.span.lo());
if prev_hi.line == cur_lo.line {
let mut count =
@ -511,7 +512,7 @@ impl CodeSuggestion {
if highlights.iter().all(|parts| parts.is_empty()) {
None
} else {
Some((buf, substitution.parts, highlights, only_capitalization))
Some((buf, substitution.parts, highlights, confusion_type))
}
})
.collect()

View file

@ -1411,9 +1411,8 @@ impl InvocationCollectorNode for P<ast::Item> {
}
}
}
let mut idents = Vec::new();
collect_use_tree_leaves(ut, &mut idents);
collect_use_tree_leaves(&ut, &mut idents);
idents
} else {
self.kind.ident().into_iter().collect()

View file

@ -1257,11 +1257,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/),
DuplicatesOk, EncodeCrossCrate::No
),
gated!(
omit_gdb_pretty_printer_section, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No,
"the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
),
rustc_attr!(
TEST, pattern_complexity_limit, CrateLevel, template!(NameValueStr: "N"),
ErrorFollowing, EncodeCrossCrate::No,

View file

@ -199,6 +199,8 @@ declare_features! (
/// Renamed to `dyn_compatible_for_dispatch`.
(removed, object_safe_for_dispatch, "1.83.0", Some(43561),
Some("renamed to `dyn_compatible_for_dispatch`"), 131511),
/// Allows using `#[omit_gdb_pretty_printer_section]`.
(removed, omit_gdb_pretty_printer_section, "CURRENT_RUSTC_VERSION", None, None, 144738),
/// Allows using `#[on_unimplemented(..)]` on traits.
/// (Moved to `rustc_attrs`.)
(removed, on_unimplemented, "1.40.0", None, None, 65794),

View file

@ -225,8 +225,6 @@ declare_features! (
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
(internal, negative_bounds, "1.71.0", None),
/// Allows using `#[omit_gdb_pretty_printer_section]`.
(internal, omit_gdb_pretty_printer_section, "1.5.0", None),
/// Set the maximum pattern complexity allowed (not limited by default).
(internal, pattern_complexity_limit, "1.78.0", None),
/// Allows using pattern types.

View file

@ -391,9 +391,6 @@ pub enum AttributeKind {
/// Represents `#[non_exhaustive]`
NonExhaustive(Span),
/// Represents `#[omit_gdb_pretty_printer_section]`
OmitGdbPrettyPrinterSection,
/// Represents `#[optimize(size|speed)]`
Optimize(OptimizeAttr, Span),

View file

@ -55,7 +55,6 @@ impl AttributeKind {
NoImplicitPrelude(..) => No,
NoMangle(..) => Yes, // Needed for rustdoc
NonExhaustive(..) => Yes, // Needed for rustdoc
OmitGdbPrettyPrinterSection => No,
Optimize(..) => No,
ParenSugar(..) => No,
PassByValue(..) => Yes,

View file

@ -360,7 +360,7 @@ impl DefKind {
/// For example, everything prefixed with `/* Res */` in this example has
/// an associated `Res`:
///
/// ```
/// ```ignore (illustrative)
/// fn str_to_string(s: & /* Res */ str) -> /* Res */ String {
/// /* Res */ String::from(/* Res */ s)
/// }
@ -421,7 +421,7 @@ pub enum Res<Id = hir::HirId> {
/// }
///
/// impl Foo for Bar {
/// fn foo() -> Box<Self> { // SelfTyAlias
/// fn foo() -> Box<Self /* SelfTyAlias */> {
/// let _: Self; // SelfTyAlias
///
/// todo!()

View file

@ -412,10 +412,8 @@ impl<'hir> PathSegment<'hir> {
/// that are [just paths](ConstArgKind::Path) (currently just bare const params)
/// versus const args that are literals or have arbitrary computations (e.g., `{ 1 + 3 }`).
///
/// The `Unambig` generic parameter represents whether the position this const is from is
/// unambiguously a const or ambiguous as to whether it is a type or a const. When in an
/// ambiguous context the parameter is instantiated with an uninhabited type making the
/// [`ConstArgKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
#[derive(Clone, Copy, Debug, HashStable_Generic)]
#[repr(C)]
pub struct ConstArg<'hir, Unambig = ()> {
@ -427,7 +425,7 @@ pub struct ConstArg<'hir, Unambig = ()> {
impl<'hir> ConstArg<'hir, AmbigArg> {
/// Converts a `ConstArg` in an ambiguous position to one in an unambiguous position.
///
/// Functions accepting an unambiguous consts may expect the [`ConstArgKind::Infer`] variant
/// Functions accepting unambiguous consts may expect the [`ConstArgKind::Infer`] variant
/// to be used. Care should be taken to separately handle infer consts when calling this
/// function as it cannot be handled by downstream code making use of the returned const.
///
@ -3016,7 +3014,7 @@ impl fmt::Display for LoopIdError {
}
}
#[derive(Copy, Clone, Debug, HashStable_Generic)]
#[derive(Copy, Clone, Debug, PartialEq, HashStable_Generic)]
pub struct Destination {
/// This is `Some(_)` iff there is an explicit user-specified 'label
pub label: Option<Label>,
@ -3314,14 +3312,12 @@ impl<'hir> AssocItemConstraintKind<'hir> {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum AmbigArg {}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
#[repr(C)]
/// Represents a type in the `HIR`.
///
/// The `Unambig` generic parameter represents whether the position this type is from is
/// unambiguously a type or ambiguous as to whether it is a type or a const. When in an
/// ambiguous context the parameter is instantiated with an uninhabited type making the
/// [`TyKind::Infer`] variant unusable and [`GenericArg::Infer`] is used instead.
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
#[derive(Debug, Clone, Copy, HashStable_Generic)]
#[repr(C)]
pub struct Ty<'hir, Unambig = ()> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
@ -3656,9 +3652,12 @@ pub enum InferDelegationKind {
}
/// The various kinds of types recognized by the compiler.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
///
/// For an explanation of the `Unambig` generic parameter see the dev-guide:
/// <https://rustc-dev-guide.rust-lang.org/hir/ambig-unambig-ty-and-consts.html>
// SAFETY: `repr(u8)` is required so that `TyKind<()>` and `TyKind<!>` are layout compatible
#[repr(u8, C)]
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir, Unambig = ()> {
/// Actual type should be inherited from `DefId` signature
InferDelegation(DefId, InferDelegationKind),

View file

@ -364,9 +364,6 @@ pub trait Visitor<'v>: Sized {
/// All types are treated as ambiguous types for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// See the doc comments on [`Ty`] for an explanation of what it means for a type to be
/// ambiguous.
///
/// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result {
walk_ty(self, t)
@ -375,12 +372,9 @@ pub trait Visitor<'v>: Sized {
/// All consts are treated as ambiguous consts for the purposes of hir visiting in
/// order to ensure that visitors can handle infer vars without it being too error-prone.
///
/// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be
/// ambiguous.
///
/// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars.
fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result {
walk_ambig_const_arg(self, c)
walk_const_arg(self, c)
}
#[allow(unused_variables)]
@ -522,7 +516,7 @@ pub trait VisitorExt<'v>: Visitor<'v> {
/// Named `visit_const_arg_unambig` instead of `visit_unambig_const_arg` to aid in
/// discovery by IDes when `v.visit_const_arg` is written.
fn visit_const_arg_unambig(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
walk_const_arg(self, c)
walk_unambig_const_arg(self, c)
}
}
impl<'v, V: Visitor<'v>> VisitorExt<'v> for V {}
@ -985,7 +979,6 @@ pub fn walk_unambig_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) ->
Some(ambig_ty) => visitor.visit_ty(ambig_ty),
None => {
let Ty { hir_id, span, kind: _ } = typ;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_infer(*hir_id, *span, InferKind::Ty(typ))
}
}
@ -1043,7 +1036,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v, AmbigArg>) -
V::Result::output()
}
pub fn walk_const_arg<'v, V: Visitor<'v>>(
pub fn walk_unambig_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v>,
) -> V::Result {
@ -1051,13 +1044,12 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>(
Some(ambig_ct) => visitor.visit_const_arg(ambig_ct),
None => {
let ConstArg { hir_id, kind: _ } = const_arg;
try_visit!(visitor.visit_id(*hir_id));
visitor.visit_infer(*hir_id, const_arg.span(), InferKind::Const(const_arg))
}
}
}
pub fn walk_ambig_const_arg<'v, V: Visitor<'v>>(
pub fn walk_const_arg<'v, V: Visitor<'v>>(
visitor: &mut V,
const_arg: &'v ConstArg<'v, AmbigArg>,
) -> V::Result {

View file

@ -356,14 +356,14 @@ fn compare_method_predicate_entailment<'tcx>(
}
if !(impl_sig, trait_sig).references_error() {
ocx.register_obligation(traits::Obligation::new(
infcx.tcx,
cause,
param_env,
ty::ClauseKind::WellFormed(
Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)).into(),
),
));
for ty in unnormalized_impl_sig.inputs_and_output {
ocx.register_obligation(traits::Obligation::new(
infcx.tcx,
cause.clone(),
param_env,
ty::ClauseKind::WellFormed(ty.into()),
));
}
}
// Check that all obligations are satisfied by the implementation's
@ -425,7 +425,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'tcx> {
///
/// trait Foo {
/// fn bar() -> impl Deref<Target = impl Sized>;
/// // ^- RPITIT #1 ^- RPITIT #2
/// // ^- RPITIT #1 ^- RPITIT #2
/// }
///
/// impl Foo for () {
@ -2498,7 +2498,7 @@ fn param_env_with_gat_bounds<'tcx>(
ty::Const::new_bound(
tcx,
ty::INNERMOST,
ty::BoundVar::from_usize(bound_vars.len() - 1),
ty::BoundConst { var: ty::BoundVar::from_usize(bound_vars.len() - 1) },
)
.into()
}

View file

@ -493,7 +493,7 @@ fn suggestion_signature<'tcx>(
let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
tcx,
assoc.container_id(tcx),
impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).args,
impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args,
);
match assoc.kind {

View file

@ -379,20 +379,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// for info on the usage of each of these fields.
let dummy_args = match kind {
ClosureKind::Closure => &["<closure_kind>", "<closure_signature>", "<upvars>"][..],
ClosureKind::Coroutine(_) => &[
"<coroutine_kind>",
"<resume_ty>",
"<yield_ty>",
"<return_ty>",
"<witness>",
"<upvars>",
][..],
ClosureKind::Coroutine(_) => {
&["<coroutine_kind>", "<resume_ty>", "<yield_ty>", "<return_ty>", "<upvars>"][..]
}
ClosureKind::CoroutineClosure(_) => &[
"<closure_kind>",
"<closure_signature_parts>",
"<upvars>",
"<bound_captures_by_ref>",
"<witness>",
][..],
};

View file

@ -189,7 +189,7 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
}
ty::GenericArgKind::Const(ct) => {
if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
mapping.insert(bv, tcx.mk_param_from_def(param))
mapping.insert(bv.var, tcx.mk_param_from_def(param))
} else {
return None;
}
@ -307,16 +307,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
return ct;
}
if let ty::ConstKind::Bound(binder, old_var) = ct.kind()
if let ty::ConstKind::Bound(binder, old_bound) = ct.kind()
&& self.binder == binder
{
let mapped = if let Some(mapped) = self.mapping.get(&old_var) {
let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
mapped.expect_const()
} else {
let var = ty::BoundVar::from_usize(self.still_bound_vars.len());
self.still_bound_vars.push(ty::BoundVariableKind::Const);
let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, var);
self.mapping.insert(old_var, mapped.into());
let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, ty::BoundConst { var });
self.mapping.insert(old_bound.var, mapped.into());
mapped
};

View file

@ -1077,7 +1077,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
ty::ConstKind::Param(param) => {
self.params.insert(param.index);
}
ty::ConstKind::Bound(db, ty::BoundVar { .. }) if db >= self.depth => {
ty::ConstKind::Bound(db, _) if db >= self.depth => {
let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var");
return ControlFlow::Break(guar);
}

View file

@ -888,8 +888,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
// `<Foo as Iterator>::Item = String`.
let projection_term = pred.projection_term;
let quiet_projection_term =
projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
let quiet_projection_term = projection_term
.with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
let term = pred.term;
let obligation = format!("{projection_term} = {term}");

View file

@ -2107,9 +2107,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let name = tcx.item_name(param_def_id);
ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => ty::Const::new_bound(
tcx,
debruijn,
ty::BoundConst { var: ty::BoundVar::from_u32(index) },
),
Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar),
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", path_hir_id),
}

View file

@ -161,8 +161,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Resume type defaults to `()` if the coroutine has no argument.
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args);
// Coroutines that come from coroutine closures have not yet determined
// their kind ty, so make a fresh infer var which will be constrained
// later during upvar analysis. Regular coroutines always have the kind
@ -182,7 +180,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
resume_ty,
yield_ty,
return_ty: liberated_sig.output(),
witness: interior,
tupled_upvars_ty,
},
);
@ -210,7 +207,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
// Compute all of the variables that will be used to populate the coroutine.
let resume_ty = self.next_ty_var(expr_span);
let interior = self.next_ty_var(expr_span);
let closure_kind_ty = match expected_kind {
Some(kind) => Ty::from_closure_kind(tcx, kind),
@ -243,7 +239,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
tupled_upvars_ty,
coroutine_captures_by_ref_ty,
coroutine_witness_ty: interior,
},
);

View file

@ -1800,11 +1800,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
.kind()
.map_bound(|clause| match clause {
ty::ClauseKind::Trait(trait_pred) => Some(ty::ClauseKind::Trait(
trait_pred.with_self_ty(fcx.tcx, ty),
trait_pred.with_replaced_self_ty(fcx.tcx, ty),
)),
ty::ClauseKind::Projection(proj_pred) => Some(
ty::ClauseKind::Projection(proj_pred.with_self_ty(fcx.tcx, ty)),
),
ty::ClauseKind::Projection(proj_pred) => {
Some(ty::ClauseKind::Projection(
proj_pred.with_replaced_self_ty(fcx.tcx, ty),
))
}
_ => None,
})
.transpose()?;

View file

@ -2,7 +2,6 @@ use std::collections::BTreeMap;
use std::fmt;
use Context::*;
use rustc_ast::Label;
use rustc_hir as hir;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::DefKind;
@ -42,8 +41,8 @@ enum Context {
ConstBlock,
/// E.g. `#[loop_match] loop { state = 'label: { /* ... */ } }`.
LoopMatch {
/// The label of the labeled block (not of the loop itself).
labeled_block: Label,
/// The destination pointing to the labeled block (not to the loop itself).
labeled_block: Destination,
},
}
@ -186,18 +185,18 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
{
self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
}
hir::ExprKind::Break(break_label, ref opt_expr) => {
hir::ExprKind::Break(break_destination, ref opt_expr) => {
if let Some(e) = opt_expr {
self.visit_expr(e);
}
if self.require_label_in_labeled_block(e.span, &break_label, "break") {
if self.require_label_in_labeled_block(e.span, &break_destination, "break") {
// If we emitted an error about an unlabeled break in a labeled
// block, we don't need any further checking for this break any more
return;
}
let loop_id = match break_label.target_id {
let loop_id = match break_destination.target_id {
Ok(loop_id) => Some(loop_id),
Err(hir::LoopIdError::OutsideLoopScope) => None,
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
@ -212,18 +211,25 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
// A `#[const_continue]` must break to a block in a `#[loop_match]`.
if find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::ConstContinue(_)) {
if let Some(break_label) = break_label.label {
let is_target_label = |cx: &Context| match cx {
Context::LoopMatch { labeled_block } => {
break_label.ident.name == labeled_block.ident.name
}
_ => false,
};
let Some(label) = break_destination.label else {
let span = e.span;
self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span });
};
if !self.cx_stack.iter().rev().any(is_target_label) {
let span = break_label.ident.span;
self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span });
let is_target_label = |cx: &Context| match cx {
Context::LoopMatch { labeled_block } => {
// NOTE: with macro expansion, the label's span might be different here
// even though it does still refer to the same HIR node. A block
// can't have two labels, so the hir_id is a unique identifier.
assert!(labeled_block.target_id.is_ok()); // see `is_loop_match`.
break_destination.target_id == labeled_block.target_id
}
_ => false,
};
if !self.cx_stack.iter().rev().any(is_target_label) {
let span = label.ident.span;
self.tcx.dcx().emit_fatal(ConstContinueBadLabel { span });
}
}
@ -249,7 +255,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
Some(kind) => {
let suggestion = format!(
"break{}",
break_label
break_destination
.label
.map_or_else(String::new, |l| format!(" {}", l.ident))
);
@ -259,7 +265,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
kind: kind.name(),
suggestion,
loop_label,
break_label: break_label.label,
break_label: break_destination.label,
break_expr_kind: &break_expr.kind,
break_expr_span: break_expr.span,
});
@ -268,7 +274,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
}
let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32));
let label_sp = match break_label.label {
let label_sp = match break_destination.label {
Some(label) => sp_lo.with_hi(label.ident.span.hi()),
None => sp_lo.shrink_to_lo(),
};
@ -416,7 +422,7 @@ impl<'hir> CheckLoopVisitor<'hir> {
&self,
e: &'hir hir::Expr<'hir>,
body: &'hir hir::Block<'hir>,
) -> Option<Label> {
) -> Option<Destination> {
if !find_attr!(self.tcx.hir_attrs(e.hir_id), AttributeKind::LoopMatch(_)) {
return None;
}
@ -438,8 +444,8 @@ impl<'hir> CheckLoopVisitor<'hir> {
let hir::ExprKind::Assign(_, rhs_expr, _) = loop_body_expr.kind else { return None };
let hir::ExprKind::Block(_, label) = rhs_expr.kind else { return None };
let hir::ExprKind::Block(block, label) = rhs_expr.kind else { return None };
label
Some(Destination { label, target_id: Ok(block.hir_id) })
}
}

View file

@ -116,7 +116,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
// something which derefs to `Self` actually implements the trait and the caller
// wanted to make a static dispatch on it but forgot to import the trait.
// See test `tests/ui/issue-35976.rs`.
// See test `tests/ui/issues/issue-35976.rs`.
//
// In that case, we'll error anyway, but we'll also re-run the search with all traits
// in scope, and if we find another method which can be used, we'll output an
@ -142,7 +142,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let (method_sig, method_predicates) =
self.normalize(self.span, (method_sig, method_predicates));
let method_sig = ty::Binder::dummy(method_sig);
// Make sure nobody calls `drop()` explicitly.
self.check_for_illegal_method_calls(pick);
@ -154,20 +153,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// We won't add these if we encountered an illegal sized bound, so that we can use
// a custom error in that case.
if illegal_sized_bound.is_none() {
self.add_obligations(
Ty::new_fn_ptr(self.tcx, method_sig),
all_args,
method_predicates,
pick.item.def_id,
);
self.add_obligations(method_sig, all_args, method_predicates, pick.item.def_id);
}
// Create the final `MethodCallee`.
let callee = MethodCallee {
def_id: pick.item.def_id,
args: all_args,
sig: method_sig.skip_binder(),
};
let callee = MethodCallee { def_id: pick.item.def_id, args: all_args, sig: method_sig };
ConfirmResult { callee, illegal_sized_bound }
}
@ -601,14 +591,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
fn add_obligations(
&mut self,
fty: Ty<'tcx>,
sig: ty::FnSig<'tcx>,
all_args: GenericArgsRef<'tcx>,
method_predicates: ty::InstantiatedPredicates<'tcx>,
def_id: DefId,
) {
debug!(
"add_obligations: fty={:?} all_args={:?} method_predicates={:?} def_id={:?}",
fty, all_args, method_predicates, def_id
"add_obligations: sig={:?} all_args={:?} method_predicates={:?} def_id={:?}",
sig, all_args, method_predicates, def_id
);
// FIXME: could replace with the following, but we already calculated `method_predicates`,
@ -637,7 +627,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// the function type must also be well-formed (this is not
// implied by the args being well-formed because of inherent
// impls and late-bound regions - see issue #28609).
self.register_wf_obligation(fty.into(), self.span, ObligationCauseCode::WellFormed(None));
for ty in sig.inputs_and_output {
self.register_wf_obligation(
ty.into(),
self.span,
ObligationCauseCode::WellFormed(None),
);
}
}
///////////////////////////////////////////////////////////////////////////

View file

@ -428,19 +428,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
// Also add an obligation for the method type being well-formed.
let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
debug!(
"lookup_method_in_trait: matched method method_ty={:?} obligation={:?}",
method_ty, obligation
"lookup_method_in_trait: matched method fn_sig={:?} obligation={:?}",
fn_sig, obligation
);
obligations.push(traits::Obligation::new(
tcx,
obligation.cause,
self.param_env,
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
method_ty.into(),
))),
));
for ty in fn_sig.inputs_and_output {
obligations.push(traits::Obligation::new(
tcx,
obligation.cause.clone(),
self.param_env,
ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into()))),
));
}
let callee = MethodCallee { def_id, args, sig: fn_sig };
debug!("callee = {:?}", callee);

View file

@ -2051,7 +2051,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
/// probe. This will result in a pending obligation so when more type-info is available we can
/// make the final decision.
///
/// Example (`tests/ui/method-two-trait-defer-resolution-1.rs`):
/// Example (`tests/ui/methods/method-two-trait-defer-resolution-1.rs`):
///
/// ```ignore (illustrative)
/// trait Foo { ... }

View file

@ -1053,8 +1053,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let pred = bound_predicate.rebind(pred);
// `<Foo as Iterator>::Item = String`.
let projection_term = pred.skip_binder().projection_term;
let quiet_projection_term =
projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
let quiet_projection_term = projection_term
.with_replaced_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
let term = pred.skip_binder().term;
@ -2157,7 +2157,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx,
self.fresh_args_for_item(sugg_span, impl_did),
)
.with_self_ty(self.tcx, rcvr_ty),
.with_replaced_self_ty(self.tcx, rcvr_ty),
idx,
sugg_span,
item,
@ -2196,7 +2196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
trait_did,
self.fresh_args_for_item(sugg_span, trait_did),
)
.with_self_ty(self.tcx, rcvr_ty),
.with_replaced_self_ty(self.tcx, rcvr_ty),
idx,
sugg_span,
item,

View file

@ -167,7 +167,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
obligation.predicate.kind().rebind(
// (*) binder moved here
ty::PredicateKind::Clause(ty::ClauseKind::Trait(
tpred.with_self_ty(self.tcx, new_self_ty),
tpred.with_replaced_self_ty(self.tcx, new_self_ty),
)),
),
);

View file

@ -2391,13 +2391,11 @@ fn migration_suggestion_for_2229(
/// let mut p = Point { x: 10, y: 10 };
///
/// let c = || {
/// p.x += 10;
/// // ^ E1 ^
/// p.x += 10; // E1
/// // ...
/// // More code
/// // ...
/// p.x += 10; // E2
/// // ^ E2 ^
/// };
/// ```
/// `CaptureKind` associated with both `E1` and `E2` will be ByRef(MutBorrow),

View file

@ -752,7 +752,8 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
) -> Ty<'tcx> {
debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var)));
let var = self.canonical_var(var_kind, ty_var.into());
Ty::new_bound(self.tcx, self.binder_index, var.into())
let bt = ty::BoundTy { var, kind: ty::BoundTyKind::Anon };
Ty::new_bound(self.tcx, self.binder_index, bt)
}
/// Given a type variable `const_var` of the given kind, first check
@ -768,6 +769,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
!self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var))
);
let var = self.canonical_var(var_kind, ct_var.into());
ty::Const::new_bound(self.tcx, self.binder_index, var)
let bc = ty::BoundConst { var };
ty::Const::new_bound(self.tcx, self.binder_index, bc)
}
}

View file

@ -133,7 +133,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
match ct.kind() {
ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
self.var_values[bound_const.as_usize()].expect_const()
self.var_values[bound_const.var.as_usize()].expect_const()
}
_ => ct.super_fold_with(self),
}
@ -217,7 +217,7 @@ fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize {
if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind()
&& debruijn == self.current_index
{
self.max_var = self.max_var.max(bound_const.as_usize());
self.max_var = self.max_var.max(bound_const.var.as_usize());
} else if ct.has_vars_bound_at_or_above(self.current_index) {
ct.super_visit_with(self);
}

View file

@ -21,7 +21,7 @@ use crate::infer::canonical::{
Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
QueryRegionConstraints, QueryResponse,
};
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::{
DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin, TypeOutlivesConstraint,
};
@ -105,8 +105,6 @@ impl<'tcx> InferCtxt<'tcx> {
where
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
let tcx = self.tcx;
// Select everything, returning errors.
let errors = fulfill_cx.select_all_or_error(self);
@ -120,7 +118,6 @@ impl<'tcx> InferCtxt<'tcx> {
debug!(?region_obligations);
let region_constraints = self.with_region_constraints(|region_constraints| {
make_query_region_constraints(
tcx,
region_obligations,
region_constraints,
region_assumptions,
@ -433,12 +430,12 @@ impl<'tcx> InferCtxt<'tcx> {
}
GenericArgKind::Lifetime(result_value) => {
// e.g., here `result_value` might be `'?1` in the example above...
if let ty::ReBound(debruijn, br) = result_value.kind() {
if let ty::ReBound(debruijn, b) = result_value.kind() {
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.
// We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[br.var] = Some(*original_value);
opt_values[b.var] = Some(*original_value);
}
}
GenericArgKind::Const(result_value) => {
@ -447,7 +444,7 @@ impl<'tcx> InferCtxt<'tcx> {
// We only allow a `ty::INNERMOST` index in generic parameters.
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b] = Some(*original_value);
opt_values[b.var] = Some(*original_value);
}
}
}
@ -587,7 +584,6 @@ impl<'tcx> InferCtxt<'tcx> {
/// Given the region obligations and constraints scraped from the infcx,
/// creates query region constraints.
pub fn make_query_region_constraints<'tcx>(
tcx: TyCtxt<'tcx>,
outlives_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
region_constraints: &RegionConstraintData<'tcx>,
assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
@ -600,22 +596,9 @@ pub fn make_query_region_constraints<'tcx>(
let outlives: Vec<_> = constraints
.iter()
.map(|(k, origin)| {
let constraint = match *k {
// Swap regions because we are going from sub (<=) to outlives
// (>=).
Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate(
ty::Region::new_var(tcx, v2).into(),
ty::Region::new_var(tcx, v1),
),
Constraint::VarSubReg(v1, r2) => {
ty::OutlivesPredicate(r2.into(), ty::Region::new_var(tcx, v1))
}
Constraint::RegSubVar(r1, v2) => {
ty::OutlivesPredicate(ty::Region::new_var(tcx, v2).into(), r1)
}
Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1),
};
.map(|(c, origin)| {
// Swap regions because we are going from sub (<=) to outlives (>=).
let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub);
(constraint, origin.to_constraint_category())
})
.chain(outlives_obligations.into_iter().map(|obl| {

View file

@ -19,7 +19,7 @@ use tracing::{debug, instrument};
use super::outlives::test_type_match;
use crate::infer::region_constraints::{
Constraint, GenericKind, RegionConstraintData, VarInfos, VerifyBound,
Constraint, ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound,
};
use crate::infer::{RegionRelations, RegionVariableOrigin, SubregionOrigin};
@ -187,91 +187,96 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
let mut constraints = IndexVec::from_elem(Vec::new(), &var_values.values);
// Tracks the changed region vids.
let mut changes = Vec::new();
for (constraint, _) in &self.data.constraints {
match *constraint {
Constraint::RegSubVar(a_region, b_vid) => {
let b_data = var_values.value_mut(b_vid);
for (c, _) in &self.data.constraints {
match c.kind {
ConstraintKind::RegSubVar => {
let sup_vid = c.sup.as_var();
let sup_data = var_values.value_mut(sup_vid);
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
if self.expand_node(c.sub, sup_vid, sup_data) {
changes.push(sup_vid);
}
}
Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
VarValue::ErrorValue => continue,
VarValue::Empty(a_universe) => {
let b_data = var_values.value_mut(b_vid);
ConstraintKind::VarSubVar => {
let sub_vid = c.sub.as_var();
let sup_vid = c.sup.as_var();
match *var_values.value(sub_vid) {
VarValue::ErrorValue => continue,
VarValue::Empty(sub_universe) => {
let sup_data = var_values.value_mut(sup_vid);
let changed = match *b_data {
VarValue::Empty(b_universe) => {
// Empty regions are ordered according to the universe
// they are associated with.
let ui = a_universe.min(b_universe);
let changed = match *sup_data {
VarValue::Empty(sup_universe) => {
// Empty regions are ordered according to the universe
// they are associated with.
let ui = sub_universe.min(sup_universe);
debug!(
"Expanding value of {:?} \
debug!(
"Expanding value of {:?} \
from empty lifetime with universe {:?} \
to empty lifetime with universe {:?}",
b_vid, b_universe, ui
);
sup_vid, sup_universe, ui
);
*b_data = VarValue::Empty(ui);
true
}
VarValue::Value(cur_region) => {
match cur_region.kind() {
// If this empty region is from a universe that can name the
// placeholder universe, then the LUB is the Placeholder region
// (which is the cur_region). Otherwise, the LUB is the Static
// lifetime.
RePlaceholder(placeholder)
if !a_universe.can_name(placeholder.universe) =>
{
let lub = self.tcx().lifetimes.re_static;
debug!(
"Expanding value of {:?} from {:?} to {:?}",
b_vid, cur_region, lub
);
*sup_data = VarValue::Empty(ui);
true
}
VarValue::Value(cur_region) => {
match cur_region.kind() {
// If this empty region is from a universe that can name
// the placeholder universe, then the LUB is the
// Placeholder region (which is the cur_region). Otherwise,
// the LUB is the Static lifetime.
RePlaceholder(placeholder)
if !sub_universe.can_name(placeholder.universe) =>
{
let lub = self.tcx().lifetimes.re_static;
debug!(
"Expanding value of {:?} from {:?} to {:?}",
sup_vid, cur_region, lub
);
*b_data = VarValue::Value(lub);
true
*sup_data = VarValue::Value(lub);
true
}
_ => false,
}
}
_ => false,
VarValue::ErrorValue => false,
};
if changed {
changes.push(sup_vid);
}
match sup_data {
VarValue::Value(Region(Interned(ReStatic, _)))
| VarValue::ErrorValue => (),
_ => {
constraints[sub_vid].push((sub_vid, sup_vid));
constraints[sup_vid].push((sub_vid, sup_vid));
}
}
VarValue::ErrorValue => false,
};
if changed {
changes.push(b_vid);
}
match b_data {
VarValue::Value(Region(Interned(ReStatic, _)))
| VarValue::ErrorValue => (),
_ => {
constraints[a_vid].push((a_vid, b_vid));
constraints[b_vid].push((a_vid, b_vid));
VarValue::Value(sub_region) => {
let sup_data = var_values.value_mut(sup_vid);
if self.expand_node(sub_region, sup_vid, sup_data) {
changes.push(sup_vid);
}
match sup_data {
VarValue::Value(Region(Interned(ReStatic, _)))
| VarValue::ErrorValue => (),
_ => {
constraints[sub_vid].push((sub_vid, sup_vid));
constraints[sup_vid].push((sub_vid, sup_vid));
}
}
}
}
VarValue::Value(a_region) => {
let b_data = var_values.value_mut(b_vid);
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
match b_data {
VarValue::Value(Region(Interned(ReStatic, _)))
| VarValue::ErrorValue => (),
_ => {
constraints[a_vid].push((a_vid, b_vid));
constraints[b_vid].push((a_vid, b_vid));
}
}
}
},
Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
}
ConstraintKind::RegSubReg | ConstraintKind::VarSubReg => {
// These constraints are checked after expansion
// is done, in `collect_errors`.
continue;
@ -528,49 +533,48 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
var_data: &mut LexicalRegionResolutions<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
for (constraint, origin) in &self.data.constraints {
debug!(?constraint, ?origin);
match *constraint {
Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
for (c, origin) in &self.data.constraints {
debug!(?c, ?origin);
match c.kind {
ConstraintKind::RegSubVar | ConstraintKind::VarSubVar => {
// Expansion will ensure that these constraints hold. Ignore.
}
Constraint::RegSubReg(sub, sup) => {
if self.sub_concrete_regions(sub, sup) {
ConstraintKind::RegSubReg => {
if self.sub_concrete_regions(c.sub, c.sup) {
continue;
}
debug!(
"region error at {:?}: \
cannot verify that {:?} <= {:?}",
origin, sub, sup
"region error at {:?}: cannot verify that {:?} <= {:?}",
origin, c.sub, c.sup
);
errors.push(RegionResolutionError::ConcreteFailure(
(*origin).clone(),
sub,
sup,
c.sub,
c.sup,
));
}
Constraint::VarSubReg(a_vid, b_region) => {
let a_data = var_data.value_mut(a_vid);
debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);
ConstraintKind::VarSubReg => {
let sub_vid = c.sub.as_var();
let sub_data = var_data.value_mut(sub_vid);
debug!("contraction: {:?} == {:?}, {:?}", sub_vid, sub_data, c.sup);
let VarValue::Value(a_region) = *a_data else {
let VarValue::Value(sub_region) = *sub_data else {
continue;
};
// Do not report these errors immediately:
// instead, set the variable value to error and
// collect them later.
if !self.sub_concrete_regions(a_region, b_region) {
if !self.sub_concrete_regions(sub_region, c.sup) {
debug!(
"region error at {:?}: \
cannot verify that {:?}={:?} <= {:?}",
origin, a_vid, a_region, b_region
"region error at {:?}: cannot verify that {:?}={:?} <= {:?}",
origin, sub_vid, sub_region, c.sup
);
*a_data = VarValue::ErrorValue;
*sub_data = VarValue::ErrorValue;
}
}
}
@ -682,18 +686,20 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
let dummy_source = graph.add_node(());
let dummy_sink = graph.add_node(());
for (constraint, _) in &self.data.constraints {
match *constraint {
Constraint::VarSubVar(a_id, b_id) => {
graph.add_edge(NodeIndex(a_id.index()), NodeIndex(b_id.index()), *constraint);
for (c, _) in &self.data.constraints {
match c.kind {
ConstraintKind::VarSubVar => {
let sub_vid = c.sub.as_var();
let sup_vid = c.sup.as_var();
graph.add_edge(NodeIndex(sub_vid.index()), NodeIndex(sup_vid.index()), *c);
}
Constraint::RegSubVar(_, b_id) => {
graph.add_edge(dummy_source, NodeIndex(b_id.index()), *constraint);
ConstraintKind::RegSubVar => {
graph.add_edge(dummy_source, NodeIndex(c.sup.as_var().index()), *c);
}
Constraint::VarSubReg(a_id, _) => {
graph.add_edge(NodeIndex(a_id.index()), dummy_sink, *constraint);
ConstraintKind::VarSubReg => {
graph.add_edge(NodeIndex(c.sub.as_var().index()), dummy_sink, *c);
}
Constraint::RegSubReg(..) => {
ConstraintKind::RegSubReg => {
// this would be an edge from `dummy_source` to
// `dummy_sink`; just ignore it.
}
@ -878,26 +884,30 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
let source_node_index = NodeIndex(source_vid.index());
for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
match edge.data {
Constraint::VarSubVar(from_vid, to_vid) => {
let get_origin =
|| this.constraints.iter().find(|(c, _)| *c == edge.data).unwrap().1.clone();
match edge.data.kind {
ConstraintKind::VarSubVar => {
let from_vid = edge.data.sub.as_var();
let to_vid = edge.data.sup.as_var();
let opp_vid = if from_vid == source_vid { to_vid } else { from_vid };
if state.set.insert(opp_vid) {
state.stack.push(opp_vid);
}
}
Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => {
let origin = this
.constraints
.iter()
.find(|(c, _)| *c == edge.data)
.unwrap()
.1
.clone();
state.result.push(RegionAndOrigin { region, origin });
ConstraintKind::RegSubVar => {
let origin = get_origin();
state.result.push(RegionAndOrigin { region: edge.data.sub, origin });
}
Constraint::RegSubReg(..) => panic!(
ConstraintKind::VarSubReg => {
let origin = get_origin();
state.result.push(RegionAndOrigin { region: edge.data.sup, origin });
}
ConstraintKind::RegSubReg => panic!(
"cannot reach reg-sub-reg edge in region inference \
post-processing"
),

View file

@ -1265,8 +1265,8 @@ impl<'tcx> InferCtxt<'tcx> {
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
self.args[bt.var.index()].expect_ty()
}
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
self.args[bv.index()].expect_const()
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> {
self.args[bc.var.index()].expect_const()
}
}
let delegate = ToFreshVars { args };

View file

@ -10,7 +10,7 @@ use super::region_constraints::{RegionConstraintData, UndoLog};
use super::{InferCtxt, RegionResolutionError, SubregionOrigin};
use crate::infer::free_regions::RegionRelations;
use crate::infer::lexical_region_resolve;
use crate::infer::region_constraints::Constraint;
use crate::infer::region_constraints::ConstraintKind;
pub mod env;
pub mod for_liveness;
@ -70,10 +70,10 @@ impl<'tcx> InferCtxt<'tcx> {
// Filter out any region-region outlives assumptions that are implied by
// coroutine well-formedness.
if self.tcx.sess.opts.unstable_opts.higher_ranked_assumptions {
storage.data.constraints.retain(|(constraint, _)| match *constraint {
Constraint::RegSubReg(r1, r2) => !outlives_env
storage.data.constraints.retain(|(c, _)| match c.kind {
ConstraintKind::RegSubReg => !outlives_env
.higher_ranked_assumptions()
.contains(&ty::OutlivesPredicate(r2.into(), r1)),
.contains(&ty::OutlivesPredicate(c.sup.into(), c.sub)),
_ => true,
});
}

View file

@ -36,7 +36,7 @@
//! fn bar<T>(a: T, b: impl for<'a> Fn(&'a T)) {}
//! fn foo<T>(x: T) {
//! bar(x, |y| { /* ... */})
//! // ^ closure arg
//! // ^ closure arg
//! }
//! ```
//!

View file

@ -83,7 +83,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
return Ok(());
}
let mini_graph = MiniGraph::new(tcx, &self, only_consider_snapshot);
let mini_graph = MiniGraph::new(&self, only_consider_snapshot);
let mut leak_check = LeakCheck::new(tcx, outer_universe, max_universe, mini_graph, self);
leak_check.assign_placeholder_values()?;
@ -359,7 +359,6 @@ struct MiniGraph<'tcx> {
impl<'tcx> MiniGraph<'tcx> {
fn new(
tcx: TyCtxt<'tcx>,
region_constraints: &RegionConstraintCollector<'_, 'tcx>,
only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>,
) -> Self {
@ -368,7 +367,6 @@ impl<'tcx> MiniGraph<'tcx> {
// Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
Self::iterate_region_constraints(
tcx,
region_constraints,
only_consider_snapshot,
|target, source| {
@ -384,33 +382,18 @@ impl<'tcx> MiniGraph<'tcx> {
/// Invokes `each_edge(R1, R2)` for each edge where `R2: R1`
fn iterate_region_constraints(
tcx: TyCtxt<'tcx>,
region_constraints: &RegionConstraintCollector<'_, 'tcx>,
only_consider_snapshot: Option<&CombinedSnapshot<'tcx>>,
mut each_edge: impl FnMut(ty::Region<'tcx>, ty::Region<'tcx>),
) {
let mut each_constraint = |constraint| match constraint {
&Constraint::VarSubVar(a, b) => {
each_edge(ty::Region::new_var(tcx, a), ty::Region::new_var(tcx, b));
}
&Constraint::RegSubVar(a, b) => {
each_edge(a, ty::Region::new_var(tcx, b));
}
&Constraint::VarSubReg(a, b) => {
each_edge(ty::Region::new_var(tcx, a), b);
}
&Constraint::RegSubReg(a, b) => {
each_edge(a, b);
}
};
if let Some(snapshot) = only_consider_snapshot {
for undo_entry in
region_constraints.undo_log.region_constraints_in_snapshot(&snapshot.undo_snapshot)
{
match undo_entry {
&AddConstraint(i) => {
each_constraint(&region_constraints.data().constraints[i].0);
let c = region_constraints.data().constraints[i].0;
each_edge(c.sub, c.sup);
}
&AddVerify(i) => span_bug!(
region_constraints.data().verifys[i].origin.span(),
@ -420,11 +403,7 @@ impl<'tcx> MiniGraph<'tcx> {
}
}
} else {
region_constraints
.data()
.constraints
.iter()
.for_each(|(constraint, _)| each_constraint(constraint));
region_constraints.data().constraints.iter().for_each(|(c, _)| each_edge(c.sub, c.sup))
}
}

View file

@ -80,31 +80,37 @@ pub struct RegionConstraintData<'tcx> {
/// Represents a constraint that influences the inference process.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum Constraint<'tcx> {
pub enum ConstraintKind {
/// A region variable is a subregion of another.
VarSubVar(RegionVid, RegionVid),
VarSubVar,
/// A concrete region is a subregion of region variable.
RegSubVar(Region<'tcx>, RegionVid),
RegSubVar,
/// A region variable is a subregion of a concrete region. This does not
/// directly affect inference, but instead is checked after
/// inference is complete.
VarSubReg(RegionVid, Region<'tcx>),
VarSubReg,
/// A constraint where neither side is a variable. This does not
/// directly affect inference, but instead is checked after
/// inference is complete.
RegSubReg(Region<'tcx>, Region<'tcx>),
RegSubReg,
}
/// Represents a constraint that influences the inference process.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Constraint<'tcx> {
pub kind: ConstraintKind,
// If `kind` is `VarSubVar` or `VarSubReg`, this must be a `ReVar`.
pub sub: Region<'tcx>,
// If `kind` is `VarSubVar` or `RegSubVar`, this must be a `ReVar`.
pub sup: Region<'tcx>,
}
impl Constraint<'_> {
pub fn involves_placeholders(&self) -> bool {
match self {
Constraint::VarSubVar(_, _) => false,
Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(),
Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(),
}
self.sub.is_placeholder() || self.sup.is_placeholder()
}
}
@ -471,16 +477,24 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
// all regions are subregions of static, so we can ignore this
}
(ReVar(sub_id), ReVar(sup_id)) => {
self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin);
}
(_, ReVar(sup_id)) => {
self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin);
}
(ReVar(sub_id), _) => {
self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin);
if sub_id != sup_id {
self.add_constraint(
Constraint { kind: ConstraintKind::VarSubVar, sub, sup },
origin,
);
}
}
(_, ReVar(_)) => self
.add_constraint(Constraint { kind: ConstraintKind::RegSubVar, sub, sup }, origin),
(ReVar(_), _) => self
.add_constraint(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }, origin),
_ => {
self.add_constraint(Constraint::RegSubReg(sub, sup), origin);
if sub != sup {
self.add_constraint(
Constraint { kind: ConstraintKind::RegSubReg, sub, sup },
origin,
)
}
}
}
}

View file

@ -45,10 +45,10 @@ impl<'tcx> InferCtxt<'tcx> {
ty::PlaceholderType { universe: next_universe, bound: bound_ty },
)
},
consts: &mut |bound_var: ty::BoundVar| {
consts: &mut |bound_const: ty::BoundConst| {
ty::Const::new_placeholder(
self.tcx,
ty::PlaceholderConst { universe: next_universe, bound: bound_var },
ty::PlaceholderConst { universe: next_universe, bound: bound_const },
)
},
};

View file

@ -1151,7 +1151,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
parallel!(
{
tcx.ensure_ok().check_private_in_public(());
tcx.par_hir_for_each_module(|module| {
tcx.ensure_ok().check_private_in_public(module)
})
},
{
tcx.par_hir_for_each_module(|module| {

View file

@ -778,8 +778,8 @@ fn test_unstable_options_tracking_hash() {
coverage_options,
CoverageOptions {
level: CoverageLevel::Mcdc,
no_mir_spans: true,
discard_all_spans_in_codegen: true
// (don't collapse test-only options onto the same line)
discard_all_spans_in_codegen: true,
}
);
tracked!(crate_attr, vec!["abc".to_string()]);

View file

@ -207,6 +207,12 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped
.ret_ty = return type of the {$fn_kind} is `{$ret_ty}`
.local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind}
.created_at = dangling pointer created here
.note = pointers do not have a lifetime; after returning, the `{$local_var_ty}` will be deallocated at the end of the {$fn_kind} because nothing is referencing it as far as the type system is concerned
lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
.label_ptr = this pointer will immediately be invalid
.label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime

View file

@ -756,22 +756,22 @@ impl<'tcx> LateContext<'tcx> {
}
fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
Ok(())
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
}
fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
Ok(())
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
}
fn print_dyn_existential(
&mut self,
_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
) -> Result<(), PrintError> {
Ok(())
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
}
fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
Ok(())
unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
}
fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
@ -784,10 +784,10 @@ impl<'tcx> LateContext<'tcx> {
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
if trait_ref.is_none() {
if let ty::Adt(def, args) = self_ty.kind() {
return self.print_def_path(def.did(), args);
}
if trait_ref.is_none()
&& let ty::Adt(def, args) = self_ty.kind()
{
return self.print_def_path(def.did(), args);
}
// This shouldn't ever be needed, but just in case:
@ -803,7 +803,6 @@ impl<'tcx> LateContext<'tcx> {
fn path_append_impl(
&mut self,
print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_disambiguated_data: &DisambiguatedDefPathData,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
) -> Result<(), PrintError> {
@ -854,9 +853,9 @@ impl<'tcx> LateContext<'tcx> {
}
}
let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
printer.print_def_path(def_id, &[]).unwrap();
printer.path
let mut p = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
p.print_def_path(def_id, &[]).unwrap();
p.path
}
/// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`.

View file

@ -1,13 +1,14 @@
use rustc_ast::visit::{visit_opt, walk_list};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::Res;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, find_attr};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, LangItem, TyKind, find_attr};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::{declare_lint, impl_lint_pass};
use rustc_span::{Span, sym};
use crate::lints::DanglingPointersFromTemporaries;
use crate::lints::{DanglingPointersFromLocals, DanglingPointersFromTemporaries};
use crate::{LateContext, LateLintPass};
declare_lint! {
@ -42,6 +43,36 @@ declare_lint! {
"detects getting a pointer from a temporary"
}
declare_lint! {
/// The `dangling_pointers_from_locals` lint detects getting a pointer to data
/// of a local that will be dropped at the end of the function.
///
/// ### Example
///
/// ```rust
/// fn f() -> *const u8 {
/// let x = 0;
/// &x // returns a dangling ptr to `x`
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Returning a pointer from a local value will not prolong its lifetime,
/// which means that the value can be dropped and the allocation freed
/// while the pointer still exists, making the pointer dangling.
/// This is not an error (as far as the type system is concerned)
/// but probably is not what the user intended either.
///
/// If you need stronger guarantees, consider using references instead,
/// as they are statically verified by the borrow-checker to never dangle.
pub DANGLING_POINTERS_FROM_LOCALS,
Warn,
"detects returning a pointer from a local variable"
}
/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
/// 1. Ways to get a temporary that are not recognized:
/// - `owning_temporary.field`
@ -53,20 +84,123 @@ declare_lint! {
#[derive(Clone, Copy, Default)]
pub(crate) struct DanglingPointers;
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES, DANGLING_POINTERS_FROM_LOCALS]);
// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
_: FnKind<'tcx>,
_: &'tcx FnDecl<'tcx>,
fn_kind: FnKind<'tcx>,
fn_decl: &'tcx FnDecl<'tcx>,
body: &'tcx Body<'tcx>,
_: Span,
_: LocalDefId,
def_id: LocalDefId,
) {
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body);
if let FnRetTy::Return(ret_ty) = &fn_decl.output
&& let TyKind::Ptr(_) = ret_ty.kind
{
// get the return type of the function or closure
let ty = match cx.tcx.type_of(def_id).instantiate_identity().kind() {
ty::FnDef(..) => cx.tcx.fn_sig(def_id).instantiate_identity(),
ty::Closure(_, args) => args.as_closure().sig(),
_ => return,
};
let ty = ty.output();
// this type is only used for layout computation and pretty-printing, neither of them rely on regions
let ty = cx.tcx.instantiate_bound_regions_with_erased(ty);
// verify that we have a pointer type
let inner_ty = match ty.kind() {
ty::RawPtr(inner_ty, _) => *inner_ty,
_ => return,
};
if cx
.tcx
.layout_of(cx.typing_env().as_query_input(inner_ty))
.is_ok_and(|layout| !layout.is_1zst())
{
let dcx = &DanglingPointerLocalContext {
body: def_id,
fn_ret: ty,
fn_ret_span: ret_ty.span,
fn_ret_inner: inner_ty,
fn_kind: match fn_kind {
FnKind::ItemFn(..) => "function",
FnKind::Method(..) => "method",
FnKind::Closure => "closure",
},
};
// look for `return`s
DanglingPointerReturnSearcher { cx, dcx }.visit_body(body);
// analyze implicit return expression
if let ExprKind::Block(block, None) = &body.value.kind
&& let innermost_block = block.innermost_block()
&& let Some(expr) = innermost_block.expr
{
lint_addr_of_local(cx, dcx, expr);
}
}
}
}
}
struct DanglingPointerLocalContext<'tcx> {
body: LocalDefId,
fn_ret: Ty<'tcx>,
fn_ret_span: Span,
fn_ret_inner: Ty<'tcx>,
fn_kind: &'static str,
}
struct DanglingPointerReturnSearcher<'lcx, 'tcx> {
cx: &'lcx LateContext<'tcx>,
dcx: &'lcx DanglingPointerLocalContext<'tcx>,
}
impl<'tcx> Visitor<'tcx> for DanglingPointerReturnSearcher<'_, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) -> Self::Result {
if let ExprKind::Ret(Some(expr)) = expr.kind {
lint_addr_of_local(self.cx, self.dcx, expr);
}
walk_expr(self, expr)
}
}
/// Look for `&<path_to_local_in_same_body>` pattern and emit lint for it
fn lint_addr_of_local<'a>(
cx: &LateContext<'a>,
dcx: &DanglingPointerLocalContext<'a>,
expr: &'a Expr<'a>,
) {
// peel casts as they do not interest us here, we want the inner expression.
let (inner, _) = super::utils::peel_casts(cx, expr);
if let ExprKind::AddrOf(_, _, inner_of) = inner.kind
&& let ExprKind::Path(ref qpath) = inner_of.peel_blocks().kind
&& let Res::Local(from) = cx.qpath_res(qpath, inner_of.hir_id)
&& cx.tcx.hir_enclosing_body_owner(from) == dcx.body
{
cx.tcx.emit_node_span_lint(
DANGLING_POINTERS_FROM_LOCALS,
expr.hir_id,
expr.span,
DanglingPointersFromLocals {
ret_ty: dcx.fn_ret,
ret_ty_span: dcx.fn_ret_span,
fn_kind: dcx.fn_kind,
local_var: cx.tcx.hir_span(from),
local_var_name: cx.tcx.hir_ident(from),
local_var_ty: dcx.fn_ret_inner,
created_at: (expr.hir_id != inner.hir_id).then_some(inner.span),
},
);
}
}

View file

@ -1188,6 +1188,22 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
pub temporary_span: Span,
}
#[derive(LintDiagnostic)]
#[diag(lint_dangling_pointers_from_locals)]
#[note]
pub(crate) struct DanglingPointersFromLocals<'tcx> {
pub ret_ty: Ty<'tcx>,
#[label(lint_ret_ty)]
pub ret_ty_span: Span,
pub fn_kind: &'static str,
#[label(lint_local_var)]
pub local_var: Span,
pub local_var_name: Ident,
pub local_var_ty: Ty<'tcx>,
#[label(lint_created_at)]
pub created_at: Option<Span>,
}
// multiple_supertrait_upcastable.rs
#[derive(LintDiagnostic)]
#[diag(lint_multiple_supertrait_upcastable)]

View file

@ -125,6 +125,7 @@ declare_lint_pass! {
UNSAFE_OP_IN_UNSAFE_FN,
UNSTABLE_NAME_COLLISIONS,
UNSTABLE_SYNTAX_PRE_EXPANSION,
UNSUPPORTED_CALLING_CONVENTIONS,
UNUSED_ASSIGNMENTS,
UNUSED_ASSOCIATED_TYPE_BOUNDS,
UNUSED_ATTRIBUTES,

View file

@ -533,8 +533,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// ```
/// fn foo(x: usize) -> bool {
/// if x == 1 {
/// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding
/// } else { // to this, it will return `foo`'s `HirId`.
/// // If `get_fn_id_for_return_block` gets passed the `id` corresponding to this, it
/// // will return `foo`'s `HirId`.
/// true
/// } else {
/// false
/// }
/// }
@ -543,8 +545,10 @@ impl<'tcx> TyCtxt<'tcx> {
/// ```compile_fail,E0308
/// fn foo(x: usize) -> bool {
/// loop {
/// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding
/// } // to this, it will return `None`.
/// // If `get_fn_id_for_return_block` gets passed the `id` corresponding to this, it
/// // will return `None`.
/// true
/// }
/// false
/// }
/// ```

View file

@ -174,36 +174,52 @@ impl<'tcx> TyCtxt<'tcx> {
attrs: &SortedMap<ItemLocalId, &[Attribute]>,
delayed_lints: &[DelayedLint],
define_opaque: Option<&[(Span, LocalDefId)]>,
) -> (Option<Fingerprint>, Option<Fingerprint>, Option<Fingerprint>) {
if self.needs_crate_hash() {
self.with_stable_hashing_context(|mut hcx| {
let mut stable_hasher = StableHasher::new();
node.hash_stable(&mut hcx, &mut stable_hasher);
// Bodies are stored out of line, so we need to pull them explicitly in the hash.
bodies.hash_stable(&mut hcx, &mut stable_hasher);
let h1 = stable_hasher.finish();
let mut stable_hasher = StableHasher::new();
attrs.hash_stable(&mut hcx, &mut stable_hasher);
// Hash the defined opaque types, which are not present in the attrs.
define_opaque.hash_stable(&mut hcx, &mut stable_hasher);
let h2 = stable_hasher.finish();
// hash lints emitted during ast lowering
let mut stable_hasher = StableHasher::new();
delayed_lints.hash_stable(&mut hcx, &mut stable_hasher);
let h3 = stable_hasher.finish();
(Some(h1), Some(h2), Some(h3))
})
} else {
(None, None, None)
) -> Hashes {
if !self.needs_crate_hash() {
return Hashes {
opt_hash_including_bodies: None,
attrs_hash: None,
delayed_lints_hash: None,
};
}
self.with_stable_hashing_context(|mut hcx| {
let mut stable_hasher = StableHasher::new();
node.hash_stable(&mut hcx, &mut stable_hasher);
// Bodies are stored out of line, so we need to pull them explicitly in the hash.
bodies.hash_stable(&mut hcx, &mut stable_hasher);
let h1 = stable_hasher.finish();
let mut stable_hasher = StableHasher::new();
attrs.hash_stable(&mut hcx, &mut stable_hasher);
// Hash the defined opaque types, which are not present in the attrs.
define_opaque.hash_stable(&mut hcx, &mut stable_hasher);
let h2 = stable_hasher.finish();
// hash lints emitted during ast lowering
let mut stable_hasher = StableHasher::new();
delayed_lints.hash_stable(&mut hcx, &mut stable_hasher);
let h3 = stable_hasher.finish();
Hashes {
opt_hash_including_bodies: Some(h1),
attrs_hash: Some(h2),
delayed_lints_hash: Some(h3),
}
})
}
}
/// Hashes computed by [`TyCtxt::hash_owner_nodes`] if necessary.
#[derive(Clone, Copy, Debug)]
pub struct Hashes {
pub opt_hash_including_bodies: Option<Fingerprint>,
pub attrs_hash: Option<Fingerprint>,
pub delayed_lints_hash: Option<Fingerprint>,
}
pub fn provide(providers: &mut Providers) {
providers.hir_crate_items = map::hir_crate_items;
providers.crate_hash = map::crate_hash;

View file

@ -57,6 +57,7 @@
#![feature(sized_hierarchy)]
#![feature(try_blocks)]
#![feature(try_trait_v2)]
#![feature(try_trait_v2_residual)]
#![feature(try_trait_v2_yeet)]
#![feature(type_alias_impl_trait)]
#![feature(yeet_expr)]

View file

@ -793,36 +793,37 @@ impl Drop for Guard {
/// We also make things panic if this type is ever implicitly dropped.
#[derive(Debug)]
#[must_use]
pub struct InterpResult_<'tcx, T> {
pub struct InterpResult<'tcx, T = ()> {
res: Result<T, InterpErrorInfo<'tcx>>,
guard: Guard,
}
// Type alias to be able to set a default type argument.
pub type InterpResult<'tcx, T = ()> = InterpResult_<'tcx, T>;
impl<'tcx, T> ops::Try for InterpResult_<'tcx, T> {
impl<'tcx, T> ops::Try for InterpResult<'tcx, T> {
type Output = T;
type Residual = InterpResult_<'tcx, convert::Infallible>;
type Residual = InterpResult<'tcx, convert::Infallible>;
#[inline]
fn from_output(output: Self::Output) -> Self {
InterpResult_::new(Ok(output))
InterpResult::new(Ok(output))
}
#[inline]
fn branch(self) -> ops::ControlFlow<Self::Residual, Self::Output> {
match self.disarm() {
Ok(v) => ops::ControlFlow::Continue(v),
Err(e) => ops::ControlFlow::Break(InterpResult_::new(Err(e))),
Err(e) => ops::ControlFlow::Break(InterpResult::new(Err(e))),
}
}
}
impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> {
impl<'tcx, T> ops::Residual<T> for InterpResult<'tcx, convert::Infallible> {
type TryType = InterpResult<'tcx, T>;
}
impl<'tcx, T> ops::FromResidual for InterpResult<'tcx, T> {
#[inline]
#[track_caller]
fn from_residual(residual: InterpResult_<'tcx, convert::Infallible>) -> Self {
fn from_residual(residual: InterpResult<'tcx, convert::Infallible>) -> Self {
match residual.disarm() {
Err(e) => Self::new(Err(e)),
}
@ -830,7 +831,7 @@ impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> {
}
// Allow `yeet`ing `InterpError` in functions returning `InterpResult_`.
impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult_<'tcx, T> {
impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResult<'tcx, T> {
#[inline]
fn from_residual(ops::Yeet(e): ops::Yeet<InterpErrorKind<'tcx>>) -> Self {
Self::new(Err(e.into()))
@ -840,7 +841,7 @@ impl<'tcx, T> ops::FromResidual<ops::Yeet<InterpErrorKind<'tcx>>> for InterpResu
// Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`.
// This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`.
impl<'tcx, T, E: Into<InterpErrorInfo<'tcx>>> ops::FromResidual<Result<convert::Infallible, E>>
for InterpResult_<'tcx, T>
for InterpResult<'tcx, T>
{
#[inline]
fn from_residual(residual: Result<convert::Infallible, E>) -> Self {
@ -863,7 +864,7 @@ impl<'tcx, T, V: FromIterator<T>> FromIterator<InterpResult<'tcx, T>> for Interp
}
}
impl<'tcx, T> InterpResult_<'tcx, T> {
impl<'tcx, T> InterpResult<'tcx, T> {
#[inline(always)]
fn new(res: Result<T, InterpErrorInfo<'tcx>>) -> Self {
Self { res, guard: Guard }
@ -890,7 +891,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
#[inline]
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> {
InterpResult_::new(self.disarm().map(f))
InterpResult::new(self.disarm().map(f))
}
#[inline]
@ -898,7 +899,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
self,
f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>,
) -> InterpResult<'tcx, T> {
InterpResult_::new(self.disarm().map_err(f))
InterpResult::new(self.disarm().map_err(f))
}
#[inline]
@ -906,7 +907,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
self,
f: impl FnOnce(InterpErrorKind<'tcx>) -> InterpErrorKind<'tcx>,
) -> InterpResult<'tcx, T> {
InterpResult_::new(self.disarm().map_err(|mut e| {
InterpResult::new(self.disarm().map_err(|mut e| {
e.0.kind = f(e.0.kind);
e
}))
@ -914,7 +915,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
#[inline]
pub fn inspect_err_kind(self, f: impl FnOnce(&InterpErrorKind<'tcx>)) -> InterpResult<'tcx, T> {
InterpResult_::new(self.disarm().inspect_err(|e| f(&e.0.kind)))
InterpResult::new(self.disarm().inspect_err(|e| f(&e.0.kind)))
}
#[inline]
@ -937,7 +938,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
#[inline]
pub fn and_then<U>(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> {
InterpResult_::new(self.disarm().and_then(|t| f(t).disarm()))
InterpResult::new(self.disarm().and_then(|t| f(t).disarm()))
}
/// Returns success if both `self` and `other` succeed, while ensuring we don't
@ -952,7 +953,7 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
// Discard the other error.
drop(other.disarm());
// Return `self`.
InterpResult_::new(Err(e))
InterpResult::new(Err(e))
}
}
}
@ -960,5 +961,5 @@ impl<'tcx, T> InterpResult_<'tcx, T> {
#[inline(always)]
pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> {
InterpResult_::new(Ok(x))
InterpResult::new(Ok(x))
}

View file

@ -1017,7 +1017,8 @@ pub struct LocalDecl<'tcx> {
/// ```
/// fn foo(x: &str) {
/// #[allow(unused_mut)]
/// let mut x: u32 = { // <- one unused mut
/// let mut x: u32 = {
/// //^ one unused mut
/// let mut y: u32 = x.parse().unwrap();
/// y + 2
/// };

View file

@ -970,11 +970,11 @@ impl<'tcx> TerminatorKind<'tcx> {
Call { func, args, destination, .. } => {
write!(fmt, "{destination:?} = ")?;
write!(fmt, "{func:?}(")?;
for (index, arg) in args.iter().map(|a| &a.node).enumerate() {
for (index, arg) in args.iter().enumerate() {
if index > 0 {
write!(fmt, ", ")?;
}
write!(fmt, "{arg:?}")?;
write!(fmt, "{:?}", arg.node)?;
}
write!(fmt, ")")
}
@ -984,7 +984,7 @@ impl<'tcx> TerminatorKind<'tcx> {
if index > 0 {
write!(fmt, ", ")?;
}
write!(fmt, "{:?}", arg)?;
write!(fmt, "{:?}", arg.node)?;
}
write!(fmt, ")")
}
@ -1197,8 +1197,8 @@ impl<'tcx> Debug for Rvalue<'tcx> {
ty::tls::with(|tcx| {
let variant_def = &tcx.adt_def(adt_did).variant(variant);
let args = tcx.lift(args).expect("could not lift for printing");
let name = FmtPrinter::print_string(tcx, Namespace::ValueNS, |cx| {
cx.print_def_path(variant_def.def_id, args)
let name = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| {
p.print_def_path(variant_def.def_id, args)
})?;
match variant_def.ctor_kind() {
@ -1473,9 +1473,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
};
let fmt_valtree = |cv: &ty::Value<'tcx>| {
let mut cx = FmtPrinter::new(self.tcx, Namespace::ValueNS);
cx.pretty_print_const_valtree(*cv, /*print_ty*/ true).unwrap();
cx.into_buffer()
let mut p = FmtPrinter::new(self.tcx, Namespace::ValueNS);
p.pretty_print_const_valtree(*cv, /*print_ty*/ true).unwrap();
p.into_buffer()
};
let val = match const_ {
@ -1967,10 +1967,10 @@ fn pretty_print_const_value_tcx<'tcx>(
.expect("destructed mir constant of adt without variant idx");
let variant_def = &def.variant(variant_idx);
let args = tcx.lift(args).unwrap();
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.print_alloc_ids = true;
cx.print_value_path(variant_def.def_id, args)?;
fmt.write_str(&cx.into_buffer())?;
let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
p.print_alloc_ids = true;
p.print_value_path(variant_def.def_id, args)?;
fmt.write_str(&p.into_buffer())?;
match variant_def.ctor_kind() {
Some(CtorKind::Const) => {}
@ -2001,18 +2001,18 @@ fn pretty_print_const_value_tcx<'tcx>(
}
}
(ConstValue::Scalar(scalar), _) => {
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.print_alloc_ids = true;
let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
p.print_alloc_ids = true;
let ty = tcx.lift(ty).unwrap();
cx.pretty_print_const_scalar(scalar, ty)?;
fmt.write_str(&cx.into_buffer())?;
p.pretty_print_const_scalar(scalar, ty)?;
fmt.write_str(&p.into_buffer())?;
return Ok(());
}
(ConstValue::ZeroSized, ty::FnDef(d, s)) => {
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.print_alloc_ids = true;
cx.print_value_path(*d, s)?;
fmt.write_str(&cx.into_buffer())?;
let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
p.print_alloc_ids = true;
p.print_value_path(*d, s)?;
fmt.write_str(&p.into_buffer())?;
return Ok(());
}
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading

View file

@ -1390,8 +1390,11 @@ rustc_queries! {
eval_always
desc { "checking effective visibilities" }
}
query check_private_in_public(_: ()) {
desc { "checking for private elements in public interfaces" }
query check_private_in_public(module_def_id: LocalModDefId) {
desc { |tcx|
"checking for private elements in public interfaces for {}",
describe_as_module(module_def_id, tcx)
}
}
query reachable_set(_: ()) -> &'tcx LocalDefIdSet {

View file

@ -93,9 +93,9 @@ impl<'tcx> Const<'tcx> {
pub fn new_bound(
tcx: TyCtxt<'tcx>,
debruijn: ty::DebruijnIndex,
var: ty::BoundVar,
bound_const: ty::BoundConst,
) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Bound(debruijn, var))
Const::new(tcx, ty::ConstKind::Bound(debruijn, bound_const))
}
#[inline]
@ -168,12 +168,16 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
Const::new_var(tcx, vid)
}
fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
Const::new_bound(interner, debruijn, var)
fn new_bound(
interner: TyCtxt<'tcx>,
debruijn: ty::DebruijnIndex,
bound_const: ty::BoundConst,
) -> Self {
Const::new_bound(interner, debruijn, bound_const)
}
fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
Const::new_bound(tcx, debruijn, var)
Const::new_bound(tcx, debruijn, ty::BoundConst { var })
}
fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self {

View file

@ -152,7 +152,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type PlaceholderConst = ty::PlaceholderConst;
type ParamConst = ty::ParamConst;
type BoundConst = ty::BoundVar;
type BoundConst = ty::BoundConst;
type ValueConst = ty::Value<'tcx>;
type ExprConst = ty::Expr<'tcx>;
type ValTree = ty::ValTree<'tcx>;
@ -1381,7 +1381,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
let bodies = Default::default();
let attrs = hir::AttributeMap::EMPTY;
let (opt_hash_including_bodies, _, _) =
let rustc_middle::hir::Hashes { opt_hash_including_bodies, .. } =
self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &[], attrs.define_opaque);
let node = node.into();
self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes {

View file

@ -213,13 +213,13 @@ impl<'tcx> Ty<'tcx> {
}
impl<'tcx> TyCtxt<'tcx> {
pub fn string_with_limit<T>(self, p: T, length_limit: usize) -> String
pub fn string_with_limit<T>(self, t: T, length_limit: usize) -> String
where
T: Copy + for<'a, 'b> Lift<TyCtxt<'b>, Lifted: Print<'b, FmtPrinter<'a, 'b>>>,
{
let mut type_limit = 50;
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
self.lift(p).expect("could not lift for printing").print(cx)
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |p| {
self.lift(t).expect("could not lift for printing").print(p)
})
.expect("could not write to `String`");
if regular.len() <= length_limit {
@ -229,16 +229,16 @@ impl<'tcx> TyCtxt<'tcx> {
loop {
// Look for the longest properly trimmed path that still fits in length_limit.
short = with_forced_trimmed_paths!({
let mut cx = FmtPrinter::new_with_limit(
let mut p = FmtPrinter::new_with_limit(
self,
hir::def::Namespace::TypeNS,
rustc_session::Limit(type_limit),
);
self.lift(p)
self.lift(t)
.expect("could not lift for printing")
.print(&mut cx)
.print(&mut p)
.expect("could not print type");
cx.into_buffer()
p.into_buffer()
});
if short.len() <= length_limit || type_limit == 0 {
break;
@ -252,12 +252,12 @@ impl<'tcx> TyCtxt<'tcx> {
/// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps
/// the existence of a "long type" anywhere in the diagnostic, so the note telling the user
/// where we wrote the file to is only printed once.
pub fn short_string<T>(self, p: T, path: &mut Option<PathBuf>) -> String
pub fn short_string<T>(self, t: T, path: &mut Option<PathBuf>) -> String
where
T: Copy + Hash + for<'a, 'b> Lift<TyCtxt<'b>, Lifted: Print<'b, FmtPrinter<'a, 'b>>>,
{
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| {
self.lift(p).expect("could not lift for printing").print(cx)
let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |p| {
self.lift(t).expect("could not lift for printing").print(p)
})
.expect("could not write to `String`");
@ -270,13 +270,13 @@ impl<'tcx> TyCtxt<'tcx> {
if regular.len() <= width * 2 / 3 {
return regular;
}
let short = self.string_with_limit(p, length_limit);
let short = self.string_with_limit(t, length_limit);
if regular == short {
return regular;
}
// Ensure we create an unique file for the type passed in when we create a file.
let mut s = DefaultHasher::new();
p.hash(&mut s);
t.hash(&mut s);
let hash = s.finish();
*path = Some(path.take().unwrap_or_else(|| {
self.output_filenames(()).temp_path_for_diagnostic(&format!("long-type-{hash}.txt"))

View file

@ -3,7 +3,7 @@ use rustc_hir::def_id::DefId;
use rustc_type_ir::data_structures::DelayedMap;
use crate::ty::{
self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
self, Binder, BoundConst, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
};
@ -60,7 +60,7 @@ where
pub trait BoundVarReplacerDelegate<'tcx> {
fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>;
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>;
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>;
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx>;
}
/// A simple delegate taking 3 mutable functions. The used functions must
@ -69,7 +69,7 @@ pub trait BoundVarReplacerDelegate<'tcx> {
pub struct FnMutDelegate<'a, 'tcx> {
pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a),
pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a),
pub consts: &'a mut (dyn FnMut(ty::BoundVar) -> ty::Const<'tcx> + 'a),
pub consts: &'a mut (dyn FnMut(ty::BoundConst) -> ty::Const<'tcx> + 'a),
}
impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> {
@ -79,8 +79,8 @@ impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> {
fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
(self.types)(bt)
}
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
(self.consts)(bv)
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> {
(self.consts)(bc)
}
}
@ -300,7 +300,13 @@ impl<'tcx> TyCtxt<'tcx> {
ty::BoundTy { var: shift_bv(t.var), kind: t.kind },
)
},
consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)),
consts: &mut |c| {
ty::Const::new_bound(
self,
ty::INNERMOST,
ty::BoundConst { var: shift_bv(c.var) },
)
},
},
)
}
@ -343,12 +349,12 @@ impl<'tcx> TyCtxt<'tcx> {
.expect_ty();
Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind })
}
fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> {
let entry = self.map.entry(bv);
fn replace_const(&mut self, bc: ty::BoundConst) -> ty::Const<'tcx> {
let entry = self.map.entry(bc.var);
let index = entry.index();
let var = ty::BoundVar::from_usize(index);
let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const();
ty::Const::new_bound(self.tcx, ty::INNERMOST, var)
ty::Const::new_bound(self.tcx, ty::INNERMOST, BoundConst { var })
}
}

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