Merge pull request #4513 from rust-lang/rustup-2025-08-04
Automatic Rustup
This commit is contained in:
commit
ee1b237215
905 changed files with 13159 additions and 8944 deletions
1
.mailmap
1
.mailmap
|
|
@ -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>
|
||||
|
|
|
|||
78
Cargo.lock
78
Cargo.lock
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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"];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-07-04"
|
||||
channel = "nightly-2025-08-03"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)*) => {
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>",
|
||||
][..],
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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()?;
|
||||
|
|
|
|||
|
|
@ -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) })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 { ... }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
),
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -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(®ion_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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
)
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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()]);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
/// };
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue