Auto merge of #3755 - rust-lang:rustup-2024-07-20, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
0c1448d75f
1242 changed files with 21167 additions and 11828 deletions
193
Cargo.lock
193
Cargo.lock
|
|
@ -228,19 +228,13 @@ dependencies = [
|
|||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ar"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69"
|
||||
|
||||
[[package]]
|
||||
name = "ar_archive_writer"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a"
|
||||
checksum = "f8412a2d690663356cba5a2532f3ed55d1e8090743bc6695b88403b27df67733"
|
||||
dependencies = [
|
||||
"object 0.32.2",
|
||||
"object 0.35.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1618,6 +1612,17 @@ dependencies = [
|
|||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
|
||||
dependencies = [
|
||||
"fallible-iterator",
|
||||
"indexmap",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
|
|
@ -1671,6 +1676,7 @@ dependencies = [
|
|||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1880,6 +1886,12 @@ dependencies = [
|
|||
"syn 2.0.67",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "id-arena"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
|
@ -2109,6 +2121,12 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
|
||||
|
||||
[[package]]
|
||||
name = "lexopt"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
|
|
@ -2623,7 +2641,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"memchr",
|
||||
"ruzstd 0.5.0",
|
||||
"wasmparser",
|
||||
"wasmparser 0.118.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2637,6 +2655,15 @@ dependencies = [
|
|||
"ruzstd 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.0"
|
||||
|
|
@ -3418,14 +3445,13 @@ dependencies = [
|
|||
name = "run_make_support"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"ar",
|
||||
"bstr",
|
||||
"build_helper",
|
||||
"gimli 0.28.1",
|
||||
"gimli 0.31.0",
|
||||
"object 0.34.0",
|
||||
"regex",
|
||||
"similar",
|
||||
"wasmparser",
|
||||
"wasmparser 0.118.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3812,7 +3838,7 @@ dependencies = [
|
|||
"thin-vec",
|
||||
"thorin-dwp",
|
||||
"tracing",
|
||||
"wasm-encoder",
|
||||
"wasm-encoder 0.200.0",
|
||||
"windows",
|
||||
]
|
||||
|
||||
|
|
@ -4385,6 +4411,7 @@ dependencies = [
|
|||
name = "rustc_mir_build"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"either",
|
||||
"itertools",
|
||||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
|
|
@ -5256,6 +5283,15 @@ dependencies = [
|
|||
"color-eyre",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spdx-expression"
|
||||
version = "0.5.2"
|
||||
|
|
@ -6304,6 +6340,28 @@ version = "0.2.92"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-component-ld"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "314d932d5e84c9678751b85498b1482b2f32f185744e449d3ce0b1d400376dad"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"lexopt",
|
||||
"tempfile",
|
||||
"wasmparser 0.210.0",
|
||||
"wat",
|
||||
"wit-component",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-component-ld-wrapper"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"wasm-component-ld",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.200.0"
|
||||
|
|
@ -6313,6 +6371,40 @@ dependencies = [
|
|||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.210.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7e3764d9d6edabd8c9e16195e177be0d20f6ab942ad18af52860f12f82bc59a"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.211.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e7d931a1120ef357f32b74547646b6fa68ea25e377772b72874b131a9ed70d4"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-metadata"
|
||||
version = "0.210.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "012729d1294907fcb0866f08460ab95426a6d0b176a599619b84cac7653452b4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"spdx",
|
||||
"wasm-encoder 0.210.0",
|
||||
"wasmparser 0.210.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.118.2"
|
||||
|
|
@ -6323,6 +6415,42 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.210.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7bbcd21e7581619d9f6ca00f8c4f08f1cacfe58bf63f83af57cd0476f1026f5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bitflags 2.5.0",
|
||||
"hashbrown",
|
||||
"indexmap",
|
||||
"semver",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "211.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b25506dd82d00da6b14a87436b3d52b1d264083fa79cdb72a0d1b04a8595ccaa"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128",
|
||||
"memchr",
|
||||
"unicode-width",
|
||||
"wasm-encoder 0.211.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.211.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb716ca6c86eecac2d82541ffc39860118fc0af9309c4f2670637bea2e1bdd7d"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
@ -6550,6 +6678,43 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-component"
|
||||
version = "0.210.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a450bdb5d032acf1fa0865451fa0c6f50e62f2d31eaa8dba967c2e2d068694a4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.5.0",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"wasm-encoder 0.210.0",
|
||||
"wasm-metadata",
|
||||
"wasmparser 0.210.0",
|
||||
"wit-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.210.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a965cbd439af19a4b44a54a97ab8957d86f02d01320efc9e31c1d3605c6710"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"id-arena",
|
||||
"indexmap",
|
||||
"log",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-xid",
|
||||
"wasmparser 0.210.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ members = [
|
|||
"src/tools/opt-dist",
|
||||
"src/tools/coverage-dump",
|
||||
"src/tools/rustc-perf-wrapper",
|
||||
"src/tools/wasm-component-ld",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
|
|
@ -104,6 +105,9 @@ rustc-demangle.debug = 0
|
|||
[profile.release.package.lld-wrapper]
|
||||
debug = 0
|
||||
strip = true
|
||||
[profile.release.package.wasm-component-ld-wrapper]
|
||||
debug = 0
|
||||
strip = true
|
||||
|
||||
[patch.crates-io]
|
||||
# See comments in `library/rustc-std-workspace-core/README.md` for what's going on
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Stabilized APIs
|
|||
- [`NonNull::byte_add`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_add)
|
||||
- [`NonNull::sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.sub)
|
||||
- [`NonNull::byte_sub`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_sub)
|
||||
- [`NonNull:offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
|
||||
- [`NonNull::offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.offset_from)
|
||||
- [`NonNull::byte_offset_from`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.byte_offset_from)
|
||||
- [`NonNull::read`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read)
|
||||
- [`NonNull::read_volatile`](https://doc.rust-lang.org/beta/std/ptr/struct.NonNull.html#method.read_volatile)
|
||||
|
|
@ -91,9 +91,9 @@ Stabilized APIs
|
|||
- [`str::trim_ascii`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii)
|
||||
- [`str::trim_ascii_start`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_start)
|
||||
- [`str::trim_ascii_end`](https://doc.rust-lang.org/beta/std/primitive.str.html#method.trim_ascii_end)
|
||||
- [`<[AsciiChar]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
|
||||
- [`<[AsciiChar]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
|
||||
- [`<[AsciiChar]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
|
||||
- [`<[u8]>::trim_ascii`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii)
|
||||
- [`<[u8]>::trim_ascii_start`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_start)
|
||||
- [`<[u8]>::trim_ascii_end`](https://doc.rust-lang.org/beta/core/primitive.slice.html#method.trim_ascii_end)
|
||||
- [`Ipv4Addr::BITS`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#associatedconstant.BITS)
|
||||
- [`Ipv4Addr::to_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.to_bits)
|
||||
- [`Ipv4Addr::from_bits`](https://doc.rust-lang.org/beta/core/net/struct.Ipv4Addr.html#method.from_bits)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ features = ['unprefixed_malloc_on_supported_platforms']
|
|||
|
||||
[features]
|
||||
# tidy-alphabetical-start
|
||||
jemalloc = ['jemalloc-sys']
|
||||
jemalloc = ['dep:jemalloc-sys']
|
||||
llvm = ['rustc_driver_impl/llvm']
|
||||
max_level_info = ['rustc_driver_impl/max_level_info']
|
||||
rustc_use_parallel_compiler = ['rustc_driver_impl/rustc_use_parallel_compiler']
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
fn main() {
|
||||
// See the comment at the top of this file for an explanation of this.
|
||||
#[cfg(feature = "jemalloc-sys")]
|
||||
#[cfg(feature = "jemalloc")]
|
||||
{
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,10 +21,10 @@ default = ["nightly", "randomize"]
|
|||
# rust-analyzer depends on this crate and we therefore require it to built on a stable toolchain
|
||||
# without depending on rustc_data_structures, rustc_macros and rustc_serialize
|
||||
nightly = [
|
||||
"rustc_data_structures",
|
||||
"dep:rustc_data_structures",
|
||||
"dep:rustc_macros",
|
||||
"dep:rustc_serialize",
|
||||
"rustc_index/nightly",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
]
|
||||
randomize = ["rand", "rand_xoshiro", "nightly"]
|
||||
randomize = ["dep:rand", "dep:rand_xoshiro", "nightly"]
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -627,7 +627,7 @@ impl Step for Size {
|
|||
|
||||
#[inline]
|
||||
unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
|
||||
Self::from_bytes(u64::forward_unchecked(start.bytes(), count))
|
||||
Self::from_bytes(unsafe { u64::forward_unchecked(start.bytes(), count) })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -642,7 +642,7 @@ impl Step for Size {
|
|||
|
||||
#[inline]
|
||||
unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
|
||||
Self::from_bytes(u64::backward_unchecked(start.bytes(), count))
|
||||
Self::from_bytes(unsafe { u64::backward_unchecked(start.bytes(), count) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
|||
TyKind::Slice(ty) => vis.visit_ty(ty),
|
||||
TyKind::Ptr(mt) => vis.visit_mt(mt),
|
||||
TyKind::Ref(lt, mt) => {
|
||||
visit_opt(lt, |lt| noop_visit_lifetime(lt, vis));
|
||||
visit_opt(lt, |lt| vis.visit_lifetime(lt));
|
||||
vis.visit_mt(mt);
|
||||
}
|
||||
TyKind::BareFn(bft) => {
|
||||
|
|
@ -925,7 +925,7 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
|
|||
vis.visit_id(id);
|
||||
visit_attrs(attrs, vis);
|
||||
vis.visit_ident(ident);
|
||||
visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
||||
match kind {
|
||||
GenericParamKind::Lifetime => {}
|
||||
GenericParamKind::Type { default } => {
|
||||
|
|
@ -983,7 +983,7 @@ fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis: &mu
|
|||
}
|
||||
WherePredicate::RegionPredicate(rp) => {
|
||||
let WhereRegionPredicate { span, lifetime, bounds } = rp;
|
||||
noop_visit_lifetime(lifetime, vis);
|
||||
vis.visit_lifetime(lifetime);
|
||||
visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -699,8 +699,7 @@ impl Token {
|
|||
false
|
||||
}
|
||||
|
||||
/// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
|
||||
/// That is, is this a pre-parsed expression dropped into the token stream
|
||||
/// Is this a pre-parsed expression dropped into the token stream
|
||||
/// (which happens while parsing the result of macro expansion)?
|
||||
pub fn is_whole_expr(&self) -> bool {
|
||||
if let Interpolated(nt) = &self.kind
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ rustc_span = { path = "../rustc_span", optional = true }
|
|||
[features]
|
||||
default = ["nightly"]
|
||||
nightly = [
|
||||
"rustc_serialize",
|
||||
"rustc_data_structures",
|
||||
"rustc_macros",
|
||||
"rustc_span",
|
||||
"dep:rustc_serialize",
|
||||
"dep:rustc_data_structures",
|
||||
"dep:rustc_macros",
|
||||
"dep:rustc_span",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
.emit();
|
||||
}
|
||||
hir::InlineAsmOperand::Const {
|
||||
anon_const: self.lower_anon_const(anon_const),
|
||||
anon_const: self.lower_anon_const_to_anon_const(anon_const),
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Sym { sym } => {
|
||||
|
|
@ -222,18 +222,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
};
|
||||
|
||||
// Wrap the expression in an AnonConst.
|
||||
let parent_def_id = self.current_hir_id_owner;
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let node_id = self.next_node_id();
|
||||
self.create_def(
|
||||
parent_def_id.def_id,
|
||||
node_id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
*op_sp,
|
||||
);
|
||||
// HACK(min_generic_const_args): see lower_anon_const
|
||||
if !expr.is_potential_trivial_const_arg() {
|
||||
self.create_def(
|
||||
parent_def_id,
|
||||
node_id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
*op_sp,
|
||||
);
|
||||
}
|
||||
let anon_const = AnonConst { id: node_id, value: P(expr) };
|
||||
hir::InlineAsmOperand::SymFn {
|
||||
anon_const: self.lower_anon_const(&anon_const),
|
||||
anon_const: self.lower_anon_const_to_anon_const(&anon_const),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
use crate::{ImplTraitPosition, ResolverAstLoweringExt};
|
||||
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode};
|
||||
use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
||||
|
||||
use ast::visit::Visitor;
|
||||
use hir::def::{DefKind, PartialRes, Res};
|
||||
|
|
@ -259,8 +259,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self_param_id: pat_node_id,
|
||||
};
|
||||
self_resolver.visit_block(block);
|
||||
let block = this.lower_block(block, false);
|
||||
this.mk_expr(hir::ExprKind::Block(block, None), block.span)
|
||||
this.lower_target_expr(&block)
|
||||
} else {
|
||||
let pat_hir_id = this.lower_node_id(pat_node_id);
|
||||
this.generate_arg(pat_hir_id, span)
|
||||
|
|
@ -273,26 +272,81 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
})
|
||||
}
|
||||
|
||||
// Generates fully qualified call for the resulting body.
|
||||
// FIXME(fn_delegation): Alternatives for target expression lowering:
|
||||
// https://github.com/rust-lang/rfcs/pull/3530#issuecomment-2197170600.
|
||||
fn lower_target_expr(&mut self, block: &Block) -> hir::Expr<'hir> {
|
||||
if block.stmts.len() == 1
|
||||
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
|
||||
{
|
||||
return self.lower_expr_mut(expr);
|
||||
}
|
||||
|
||||
let block = self.lower_block(block, false);
|
||||
self.mk_expr(hir::ExprKind::Block(block, None), block.span)
|
||||
}
|
||||
|
||||
// Generates expression for the resulting body. If possible, `MethodCall` is used
|
||||
// to allow autoref/autoderef for target expression. For example in:
|
||||
//
|
||||
// trait Trait : Sized {
|
||||
// fn by_value(self) -> i32 { 1 }
|
||||
// fn by_mut_ref(&mut self) -> i32 { 2 }
|
||||
// fn by_ref(&self) -> i32 { 3 }
|
||||
// }
|
||||
//
|
||||
// struct NewType(SomeType);
|
||||
// impl Trait for NewType {
|
||||
// reuse Trait::* { self.0 }
|
||||
// }
|
||||
//
|
||||
// `self.0` will automatically coerce.
|
||||
fn finalize_body_lowering(
|
||||
&mut self,
|
||||
delegation: &Delegation,
|
||||
args: Vec<hir::Expr<'hir>>,
|
||||
span: Span,
|
||||
) -> hir::Expr<'hir> {
|
||||
let path = self.lower_qpath(
|
||||
delegation.id,
|
||||
&delegation.qself,
|
||||
&delegation.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
||||
let args = self.arena.alloc_from_iter(args);
|
||||
let path_expr = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
|
||||
let call = self.arena.alloc(self.mk_expr(hir::ExprKind::Call(path_expr, args), span));
|
||||
|
||||
let has_generic_args =
|
||||
delegation.path.segments.iter().rev().skip(1).any(|segment| segment.args.is_some());
|
||||
|
||||
let call = if self
|
||||
.get_resolution_id(delegation.id, span)
|
||||
.and_then(|def_id| Ok(self.has_self(def_id, span)))
|
||||
.unwrap_or_default()
|
||||
&& delegation.qself.is_none()
|
||||
&& !has_generic_args
|
||||
{
|
||||
let ast_segment = delegation.path.segments.last().unwrap();
|
||||
let segment = self.lower_path_segment(
|
||||
delegation.path.span,
|
||||
ast_segment,
|
||||
ParamMode::Optional,
|
||||
ParenthesizedGenericArgs::Err,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
let segment = self.arena.alloc(segment);
|
||||
|
||||
self.arena.alloc(hir::Expr {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ExprKind::MethodCall(segment, &args[0], &args[1..], span),
|
||||
span,
|
||||
})
|
||||
} else {
|
||||
let path = self.lower_qpath(
|
||||
delegation.id,
|
||||
&delegation.qself,
|
||||
&delegation.path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
||||
let callee_path = self.arena.alloc(self.mk_expr(hir::ExprKind::Path(path), span));
|
||||
self.arena.alloc(self.mk_expr(hir::ExprKind::Call(callee_path, args), span))
|
||||
};
|
||||
let block = self.arena.alloc(hir::Block {
|
||||
stmts: &[],
|
||||
expr: Some(call),
|
||||
|
|
|
|||
|
|
@ -75,10 +75,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::ConstBlock(c) => {
|
||||
let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock {
|
||||
def_id: this.local_def_id(c.id),
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
let c = self.with_new_scopes(c.value.span, |this| {
|
||||
let def_id = this.local_def_id(c.id);
|
||||
hir::ConstBlock {
|
||||
def_id,
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(c.value.span, Some(&c.value))
|
||||
}),
|
||||
}
|
||||
});
|
||||
hir::ExprKind::ConstBlock(c)
|
||||
}
|
||||
|
|
@ -377,17 +382,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let mut generic_args = ThinVec::new();
|
||||
for (idx, arg) in args.into_iter().enumerate() {
|
||||
if legacy_args_idx.contains(&idx) {
|
||||
let parent_def_id = self.current_hir_id_owner;
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
// Add a definition for the in-band const def.
|
||||
self.create_def(
|
||||
parent_def_id.def_id,
|
||||
node_id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
f.span,
|
||||
);
|
||||
// HACK(min_generic_const_args): see lower_anon_const
|
||||
if !arg.is_potential_trivial_const_arg() {
|
||||
// Add a definition for the in-band const def.
|
||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
|
||||
}
|
||||
|
||||
let anon_const = AnonConst { id: node_id, value: arg };
|
||||
generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const)));
|
||||
|
|
@ -622,6 +624,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
coroutine_source: hir::CoroutineSource,
|
||||
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let closure_def_id = self.local_def_id(closure_node_id);
|
||||
let coroutine_kind = hir::CoroutineKind::Desugared(desugaring_kind, coroutine_source);
|
||||
|
||||
// The `async` desugaring takes a resume argument and maintains a `task_context`,
|
||||
|
|
@ -672,22 +675,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
lifetime_elision_allowed: false,
|
||||
});
|
||||
|
||||
let body = self.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(coroutine_kind);
|
||||
let body = self.with_def_id_parent(closure_def_id, move |this| {
|
||||
this.lower_body(move |this| {
|
||||
this.coroutine_kind = Some(coroutine_kind);
|
||||
|
||||
let old_ctx = this.task_context;
|
||||
if task_context.is_some() {
|
||||
this.task_context = task_context;
|
||||
}
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
let old_ctx = this.task_context;
|
||||
if task_context.is_some() {
|
||||
this.task_context = task_context;
|
||||
}
|
||||
let res = body(this);
|
||||
this.task_context = old_ctx;
|
||||
|
||||
(params, res)
|
||||
(params, res)
|
||||
})
|
||||
});
|
||||
|
||||
// `static |<_task_context?>| -> <return_ty> { <body> }`:
|
||||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_node_id),
|
||||
def_id: closure_def_id,
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
bound_generic_params: &[],
|
||||
|
|
@ -966,27 +971,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn_decl_span: Span,
|
||||
fn_arg_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let closure_def_id = self.local_def_id(closure_id);
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let mut coroutine_kind = if this
|
||||
.attrs
|
||||
.get(&closure_hir_id.local_id)
|
||||
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
|
||||
{
|
||||
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
let e = this.lower_expr_mut(body);
|
||||
coroutine_kind = this.coroutine_kind;
|
||||
e
|
||||
});
|
||||
let coroutine_option =
|
||||
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
(body_id, coroutine_option)
|
||||
this.with_def_id_parent(closure_def_id, move |this| {
|
||||
let mut coroutine_kind = if this
|
||||
.attrs
|
||||
.get(&closure_hir_id.local_id)
|
||||
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
|
||||
{
|
||||
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
let e = this.lower_expr_mut(body);
|
||||
coroutine_kind = this.coroutine_kind;
|
||||
e
|
||||
});
|
||||
let coroutine_option =
|
||||
this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability);
|
||||
(body_id, coroutine_option)
|
||||
})
|
||||
});
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
|
|
@ -994,7 +1002,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let fn_decl = self.lower_fn_decl(decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_id),
|
||||
def_id: closure_def_id,
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
bound_generic_params,
|
||||
|
|
@ -1066,6 +1074,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn_decl_span: Span,
|
||||
fn_arg_span: Span,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let closure_def_id = self.local_def_id(closure_id);
|
||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
assert_matches!(
|
||||
|
|
@ -1075,27 +1084,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
|
||||
let body = self.with_new_scopes(fn_decl_span, |this| {
|
||||
let inner_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
this.with_def_id_parent(closure_def_id, |this| {
|
||||
let inner_decl =
|
||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|x: u8| || -> X { ... }`.
|
||||
let body_id = this.lower_body(|this| {
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
&inner_decl,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
fn_decl_span,
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Closure,
|
||||
);
|
||||
// Transform `async |x: u8| -> X { ... }` into
|
||||
// `|x: u8| || -> X { ... }`.
|
||||
let body_id = this.lower_body(|this| {
|
||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||
&inner_decl,
|
||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||
fn_decl_span,
|
||||
body.span,
|
||||
coroutine_kind,
|
||||
hir::CoroutineSource::Closure,
|
||||
);
|
||||
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
||||
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
||||
|
||||
(parameters, expr)
|
||||
});
|
||||
body_id
|
||||
(parameters, expr)
|
||||
});
|
||||
body_id
|
||||
})
|
||||
});
|
||||
|
||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||
|
|
@ -1106,7 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_fn_decl(&decl, closure_id, fn_decl_span, FnDeclKind::Closure, None);
|
||||
|
||||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: self.local_def_id(closure_id),
|
||||
def_id: closure_def_id,
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
bound_generic_params,
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
intravisit::walk_generic_param(self, param);
|
||||
}
|
||||
|
||||
fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
|
||||
fn visit_const_param_default(&mut self, param: HirId, ct: &'hir ConstArg<'hir>) {
|
||||
self.with_parent(param, |this| {
|
||||
intravisit::walk_const_param_default(this, ct);
|
||||
})
|
||||
|
|
@ -229,6 +229,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn visit_anon_const(&mut self, constant: &'hir AnonConst) {
|
||||
// FIXME: use real span?
|
||||
self.insert(DUMMY_SP, constant.hir_id, Node::AnonConst(constant));
|
||||
|
||||
self.with_parent(constant.hir_id, |this| {
|
||||
|
|
@ -244,6 +245,15 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir>) {
|
||||
// FIXME: use real span?
|
||||
self.insert(DUMMY_SP, const_arg.hir_id, Node::ConstArg(const_arg));
|
||||
|
||||
self.with_parent(const_arg.hir_id, |this| {
|
||||
intravisit::walk_const_arg(this, const_arg);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
|
||||
self.insert(expr.span, expr.hir_id, Node::Expr(expr));
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,10 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
|
||||
for (def_id, info) in lctx.children {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
debug_assert!(matches!(owner, hir::MaybeOwner::Phantom));
|
||||
debug_assert!(
|
||||
matches!(owner, hir::MaybeOwner::Phantom),
|
||||
"duplicate copy of {def_id:?} in lctx.children"
|
||||
);
|
||||
*owner = info;
|
||||
}
|
||||
}
|
||||
|
|
@ -713,7 +716,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir_id,
|
||||
def_id: self.local_def_id(v.id),
|
||||
data: self.lower_variant_data(hir_id, &v.data),
|
||||
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
|
||||
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
|
||||
ident: self.lower_ident(v.ident),
|
||||
span: self.lower_span(v.span),
|
||||
}
|
||||
|
|
@ -1601,7 +1604,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
if let Some((span, hir_id, def_id)) = host_param_parts {
|
||||
let const_node_id = self.next_node_id();
|
||||
let anon_const =
|
||||
let anon_const_did =
|
||||
self.create_def(def_id, const_node_id, kw::Empty, DefKind::AnonConst, span);
|
||||
|
||||
let const_id = self.next_id();
|
||||
|
|
@ -1609,7 +1612,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let bool_id = self.next_id();
|
||||
|
||||
self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
|
||||
self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id)));
|
||||
self.children.push((anon_const_did, hir::MaybeOwner::NonOwner(const_id)));
|
||||
|
||||
let const_body = self.lower_body(|this| {
|
||||
(
|
||||
|
|
@ -1624,6 +1627,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
});
|
||||
|
||||
let default_ac = self.arena.alloc(hir::AnonConst {
|
||||
def_id: anon_const_did,
|
||||
hir_id: const_id,
|
||||
body: const_body,
|
||||
span,
|
||||
});
|
||||
let default_ct = self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(default_ac),
|
||||
is_desugared_from_effects: false,
|
||||
});
|
||||
let param = hir::GenericParam {
|
||||
def_id,
|
||||
hir_id,
|
||||
|
|
@ -1648,12 +1662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)),
|
||||
)),
|
||||
// FIXME(effects) we might not need a default.
|
||||
default: Some(self.arena.alloc(hir::AnonConst {
|
||||
def_id: anon_const,
|
||||
hir_id: const_id,
|
||||
body: const_body,
|
||||
span,
|
||||
})),
|
||||
default: Some(default_ct),
|
||||
is_host_effect: true,
|
||||
synthetic: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -120,6 +120,18 @@ struct LoweringContext<'a, 'hir> {
|
|||
is_in_dyn_type: bool,
|
||||
|
||||
current_hir_id_owner: hir::OwnerId,
|
||||
/// Why do we need this in addition to [`Self::current_hir_id_owner`]?
|
||||
///
|
||||
/// Currently (as of June 2024), anonymous constants are not HIR owners; however,
|
||||
/// they do get their own DefIds. Some of these DefIds have to be created during
|
||||
/// AST lowering, rather than def collection, because we can't tell until after
|
||||
/// name resolution whether an anonymous constant will end up instead being a
|
||||
/// [`hir::ConstArgKind::Path`]. However, to compute which generics are
|
||||
/// available to an anonymous constant nested inside another, we need to make
|
||||
/// sure that the parent is recorded as the parent anon const, not the enclosing
|
||||
/// item. So we need to track parent defs differently from HIR owners, since they
|
||||
/// will be finer-grained in the case of anon consts.
|
||||
current_def_id_parent: LocalDefId,
|
||||
item_local_id_counter: hir::ItemLocalId,
|
||||
trait_map: ItemLocalMap<Box<[TraitCandidate]>>,
|
||||
|
||||
|
|
@ -162,6 +174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
attrs: SortedMap::default(),
|
||||
children: Vec::default(),
|
||||
current_hir_id_owner: hir::CRATE_OWNER_ID,
|
||||
current_def_id_parent: CRATE_DEF_ID,
|
||||
item_local_id_counter: hir::ItemLocalId::ZERO,
|
||||
node_id_to_local_id: Default::default(),
|
||||
trait_map: Default::default(),
|
||||
|
|
@ -592,7 +605,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
|
||||
debug_assert_eq!(_old, None);
|
||||
|
||||
let item = f(self);
|
||||
let item = self.with_def_id_parent(def_id, f);
|
||||
debug_assert_eq!(def_id, item.def_id().def_id);
|
||||
// `f` should have consumed all the elements in these vectors when constructing `item`.
|
||||
debug_assert!(self.impl_trait_defs.is_empty());
|
||||
|
|
@ -612,6 +625,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.children.push((def_id, hir::MaybeOwner::Owner(info)));
|
||||
}
|
||||
|
||||
fn with_def_id_parent<T>(&mut self, parent: LocalDefId, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||
let current_def_id_parent = std::mem::replace(&mut self.current_def_id_parent, parent);
|
||||
let result = f(self);
|
||||
self.current_def_id_parent = current_def_id_parent;
|
||||
result
|
||||
}
|
||||
|
||||
/// Installs the remapping `remap` in scope while `f` is being executed.
|
||||
/// This causes references to the `LocalDefId` keys to be changed to
|
||||
/// refer to the values instead.
|
||||
|
|
@ -806,7 +826,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
LifetimeRes::Fresh { param, kind, .. } => {
|
||||
// Late resolution delegates to us the creation of the `LocalDefId`.
|
||||
let _def_id = self.create_def(
|
||||
self.current_hir_id_owner.def_id,
|
||||
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
|
||||
param,
|
||||
kw::UnderscoreLifetime,
|
||||
DefKind::LifetimeParam,
|
||||
|
|
@ -1044,7 +1064,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
AssocItemConstraintKind::Equality { term } => {
|
||||
let term = match term {
|
||||
Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
|
||||
Term::Const(c) => self.lower_anon_const(c).into(),
|
||||
Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(),
|
||||
};
|
||||
hir::AssocItemConstraintKind::Equality { term }
|
||||
}
|
||||
|
|
@ -1150,42 +1170,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ty,
|
||||
);
|
||||
|
||||
// Construct an AnonConst where the expr is the "ty"'s path.
|
||||
|
||||
let parent_def_id = self.current_hir_id_owner;
|
||||
let node_id = self.next_node_id();
|
||||
let span = self.lower_span(ty.span);
|
||||
|
||||
// Add a definition for the in-band const def.
|
||||
let def_id = self.create_def(
|
||||
parent_def_id.def_id,
|
||||
node_id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
span,
|
||||
);
|
||||
|
||||
let path_expr = Expr {
|
||||
id: ty.id,
|
||||
kind: ExprKind::Path(None, path.clone()),
|
||||
span,
|
||||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
};
|
||||
|
||||
let ct = self.with_new_scopes(span, |this| {
|
||||
self.arena.alloc(hir::AnonConst {
|
||||
def_id,
|
||||
hir_id: this.lower_node_id(node_id),
|
||||
body: this
|
||||
.lower_const_body(path_expr.span, Some(&path_expr)),
|
||||
span,
|
||||
})
|
||||
});
|
||||
return GenericArg::Const(ConstArg {
|
||||
value: ct,
|
||||
is_desugared_from_effects: false,
|
||||
});
|
||||
let ct =
|
||||
self.lower_const_path_to_const_arg(path, res, ty.id, ty.span);
|
||||
return GenericArg::Const(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1193,10 +1180,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
GenericArg::Type(self.lower_ty(ty, itctx))
|
||||
}
|
||||
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
|
||||
value: self.lower_anon_const(ct),
|
||||
is_desugared_from_effects: false,
|
||||
}),
|
||||
ast::GenericArg::Const(ct) => GenericArg::Const(self.lower_anon_const_to_const_arg(ct)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1355,7 +1339,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
TyKind::Array(ty, length) => {
|
||||
hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
|
||||
}
|
||||
TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
|
||||
TyKind::Typeof(expr) => hir::TyKind::Typeof(self.lower_anon_const_to_anon_const(expr)),
|
||||
TyKind::TraitObject(bounds, kind) => {
|
||||
let mut lifetime_bound = None;
|
||||
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
|
||||
|
|
@ -1429,7 +1413,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
);
|
||||
|
||||
self.create_def(
|
||||
self.current_hir_id_owner.def_id,
|
||||
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
|
||||
*def_node_id,
|
||||
ident.name,
|
||||
DefKind::TyParam,
|
||||
|
|
@ -1637,7 +1621,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
|
||||
) -> hir::TyKind<'hir> {
|
||||
let opaque_ty_def_id = self.create_def(
|
||||
self.current_hir_id_owner.def_id,
|
||||
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
|
||||
opaque_ty_node_id,
|
||||
kw::Empty,
|
||||
DefKind::OpaqueTy,
|
||||
|
|
@ -2222,7 +2206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
false
|
||||
}
|
||||
})
|
||||
.map(|def| self.lower_anon_const(def));
|
||||
.map(|def| self.lower_anon_const_to_const_arg(def));
|
||||
|
||||
(
|
||||
hir::ParamName::Plain(self.lower_ident(param.ident)),
|
||||
|
|
@ -2360,19 +2344,153 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
"using `_` for array lengths is unstable",
|
||||
)
|
||||
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
|
||||
hir::ArrayLen::Body(self.lower_anon_const(c))
|
||||
hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c))
|
||||
}
|
||||
}
|
||||
_ => hir::ArrayLen::Body(self.lower_anon_const(c)),
|
||||
_ => hir::ArrayLen::Body(self.lower_anon_const_to_const_arg(c)),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
|
||||
self.arena.alloc(self.with_new_scopes(c.value.span, |this| hir::AnonConst {
|
||||
def_id: this.local_def_id(c.id),
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
span: this.lower_span(c.value.span),
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_const_path_to_const_arg(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
res: Res<NodeId>,
|
||||
ty_id: NodeId,
|
||||
span: Span,
|
||||
) -> &'hir hir::ConstArg<'hir> {
|
||||
let ct_kind = match res {
|
||||
Res::Def(DefKind::ConstParam, _) => {
|
||||
let qpath = self.lower_qpath(
|
||||
ty_id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
hir::ConstArgKind::Path(qpath)
|
||||
}
|
||||
_ => {
|
||||
// Construct an AnonConst where the expr is the "ty"'s path.
|
||||
|
||||
let parent_def_id = self.current_def_id_parent;
|
||||
let node_id = self.next_node_id();
|
||||
let span = self.lower_span(span);
|
||||
|
||||
// Add a definition for the in-band const def.
|
||||
let def_id =
|
||||
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span);
|
||||
let hir_id = self.lower_node_id(node_id);
|
||||
|
||||
let path_expr = Expr {
|
||||
id: ty_id,
|
||||
kind: ExprKind::Path(None, path.clone()),
|
||||
span,
|
||||
attrs: AttrVec::new(),
|
||||
tokens: None,
|
||||
};
|
||||
|
||||
let ct = self.with_new_scopes(span, |this| {
|
||||
self.arena.alloc(hir::AnonConst {
|
||||
def_id,
|
||||
hir_id,
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(path_expr.span, Some(&path_expr))
|
||||
}),
|
||||
span,
|
||||
})
|
||||
});
|
||||
hir::ConstArgKind::Anon(ct)
|
||||
}
|
||||
};
|
||||
|
||||
self.arena.alloc(hir::ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: ct_kind,
|
||||
is_desugared_from_effects: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
/// [`Self::lower_anon_const_to_anon_const`].
|
||||
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
|
||||
self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
|
||||
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
|
||||
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
|
||||
let expr = if let ExprKind::Block(block, _) = &anon.value.kind
|
||||
&& let [stmt] = block.stmts.as_slice()
|
||||
&& let StmtKind::Expr(expr) = &stmt.kind
|
||||
&& let ExprKind::Path(..) = &expr.kind
|
||||
{
|
||||
expr
|
||||
} else {
|
||||
&anon.value
|
||||
};
|
||||
let maybe_res =
|
||||
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
|
||||
debug!("res={:?}", maybe_res);
|
||||
// FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path
|
||||
if let Some(res) = maybe_res
|
||||
&& let Res::Def(DefKind::ConstParam, _) = res
|
||||
&& let ExprKind::Path(qself, path) = &expr.kind
|
||||
{
|
||||
let qpath = self.lower_qpath(
|
||||
expr.id,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
);
|
||||
|
||||
return ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Path(qpath),
|
||||
is_desugared_from_effects: false,
|
||||
};
|
||||
}
|
||||
|
||||
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
|
||||
ConstArg {
|
||||
hir_id: self.next_id(),
|
||||
kind: hir::ConstArgKind::Anon(lowered_anon),
|
||||
is_desugared_from_effects: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`hir::ConstArg`] for when to use this function vs
|
||||
/// [`Self::lower_anon_const_to_const_arg`].
|
||||
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
|
||||
if c.value.is_potential_trivial_const_arg() {
|
||||
// HACK(min_generic_const_args): see DefCollector::visit_anon_const
|
||||
// Over there, we guess if this is a bare param and only create a def if
|
||||
// we think it's not. However we may can guess wrong (see there for example)
|
||||
// in which case we have to create the def here.
|
||||
self.create_def(
|
||||
self.current_def_id_parent,
|
||||
c.id,
|
||||
kw::Empty,
|
||||
DefKind::AnonConst,
|
||||
c.value.span,
|
||||
);
|
||||
}
|
||||
|
||||
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
|
||||
let def_id = this.local_def_id(c.id);
|
||||
let hir_id = this.lower_node_id(c.id);
|
||||
hir::AnonConst {
|
||||
def_id,
|
||||
hir_id,
|
||||
body: this.with_def_id_parent(def_id, |this| {
|
||||
this.lower_const_body(c.value.span, Some(&c.value))
|
||||
}),
|
||||
span: this.lower_span(c.value.span),
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -159,9 +159,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
|
|||
.type = inherent impl for this type
|
||||
.only_trait = only trait implementations may be annotated with {$annotation}
|
||||
|
||||
ast_passes_invalid_label =
|
||||
invalid label name `{$name}`
|
||||
|
||||
ast_passes_invalid_unnamed_field =
|
||||
unnamed fields are not allowed outside of structs or unions
|
||||
.label = unnamed field declared here
|
||||
|
|
@ -176,9 +173,6 @@ ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot
|
|||
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
||||
.label = `_` is not a valid name for this `{$kind}` item
|
||||
|
||||
ast_passes_keyword_lifetime =
|
||||
lifetimes cannot use keyword names
|
||||
|
||||
ast_passes_match_arm_with_no_body =
|
||||
`match` arm with no body
|
||||
.suggestion = add a body after the pattern
|
||||
|
|
@ -275,6 +269,9 @@ ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
|
|||
.negative = negative because of this
|
||||
.unsafe = unsafe because of this
|
||||
|
||||
ast_passes_unsafe_static =
|
||||
static items cannot be declared with `unsafe` safety qualifier outside of `extern` block
|
||||
|
||||
ast_passes_visibility_not_permitted =
|
||||
visibility qualifiers are not permitted here
|
||||
.enum_variant = enum variants and their fields always share the visibility of the enum they are in
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ use std::mem;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::{self, TildeConstReason};
|
||||
|
||||
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
|
||||
enum SelfSemantic {
|
||||
|
|
@ -46,27 +46,12 @@ enum SelfSemantic {
|
|||
No,
|
||||
}
|
||||
|
||||
/// What is the context that prevents using `~const`?
|
||||
// FIXME(effects): Consider getting rid of this in favor of `errors::TildeConstReason`, they're
|
||||
// almost identical. This gets rid of an abstraction layer which might be considered bad.
|
||||
enum DisallowTildeConstContext<'a> {
|
||||
TraitObject,
|
||||
Fn(FnKind<'a>),
|
||||
Trait(Span),
|
||||
TraitImpl(Span),
|
||||
Impl(Span),
|
||||
TraitAssocTy(Span),
|
||||
TraitImplAssocTy(Span),
|
||||
InherentAssocTy(Span),
|
||||
Item,
|
||||
}
|
||||
|
||||
enum TraitOrTraitImpl<'a> {
|
||||
enum TraitOrTraitImpl {
|
||||
Trait { span: Span, constness: Option<Span> },
|
||||
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: &'a TraitRef },
|
||||
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref: Span },
|
||||
}
|
||||
|
||||
impl<'a> TraitOrTraitImpl<'a> {
|
||||
impl TraitOrTraitImpl {
|
||||
fn constness(&self) -> Option<Span> {
|
||||
match self {
|
||||
Self::Trait { constness: Some(span), .. }
|
||||
|
|
@ -81,9 +66,9 @@ struct AstValidator<'a> {
|
|||
features: &'a Features,
|
||||
|
||||
/// The span of the `extern` in an `extern { ... }` block, if any.
|
||||
extern_mod: Option<&'a Item>,
|
||||
extern_mod: Option<Span>,
|
||||
|
||||
outer_trait_or_trait_impl: Option<TraitOrTraitImpl<'a>>,
|
||||
outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
|
||||
|
||||
has_proc_macro_decls: bool,
|
||||
|
||||
|
|
@ -92,7 +77,7 @@ struct AstValidator<'a> {
|
|||
/// e.g., `impl Iterator<Item = impl Debug>`.
|
||||
outer_impl_trait: Option<Span>,
|
||||
|
||||
disallow_tilde_const: Option<DisallowTildeConstContext<'a>>,
|
||||
disallow_tilde_const: Option<TildeConstReason>,
|
||||
|
||||
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
|
||||
/// or `Foo::Bar<impl Trait>`
|
||||
|
|
@ -115,7 +100,7 @@ impl<'a> AstValidator<'a> {
|
|||
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
|
||||
constness,
|
||||
polarity,
|
||||
trait_ref,
|
||||
trait_ref: trait_ref.path.span,
|
||||
}),
|
||||
);
|
||||
f(self);
|
||||
|
|
@ -145,7 +130,7 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
fn with_tilde_const(
|
||||
&mut self,
|
||||
disallowed: Option<DisallowTildeConstContext<'a>>,
|
||||
disallowed: Option<TildeConstReason>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old = mem::replace(&mut self.disallow_tilde_const, disallowed);
|
||||
|
|
@ -224,7 +209,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
TyKind::TraitObject(..) => self
|
||||
.with_tilde_const(Some(DisallowTildeConstContext::TraitObject), |this| {
|
||||
.with_tilde_const(Some(TildeConstReason::TraitObject), |this| {
|
||||
visit::walk_ty(this, t)
|
||||
}),
|
||||
TyKind::Path(qself, path) => {
|
||||
|
|
@ -284,19 +269,6 @@ impl<'a> AstValidator<'a> {
|
|||
self.session.dcx()
|
||||
}
|
||||
|
||||
fn check_lifetime(&self, ident: Ident) {
|
||||
let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
|
||||
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
|
||||
self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
|
||||
}
|
||||
}
|
||||
|
||||
fn check_label(&self, ident: Ident) {
|
||||
if ident.without_first_quote().is_reserved() {
|
||||
self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
|
||||
}
|
||||
}
|
||||
|
||||
fn visibility_not_permitted(&self, vis: &Visibility, note: errors::VisibilityNotPermittedNote) {
|
||||
if let VisibilityKind::Inherited = vis.kind {
|
||||
return;
|
||||
|
|
@ -354,7 +326,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl<'a>) {
|
||||
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
|
||||
let Const::Yes(span) = constness else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -367,7 +339,7 @@ impl<'a> AstValidator<'a> {
|
|||
..
|
||||
} = parent
|
||||
{
|
||||
Some(trait_ref.path.span.shrink_to_lo())
|
||||
Some(trait_ref.shrink_to_lo())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
@ -466,6 +438,11 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// This ensures that items can only be `unsafe` (or unmarked) outside of extern
|
||||
/// blocks.
|
||||
///
|
||||
/// This additionally ensures that within extern blocks, items can only be
|
||||
/// `safe`/`unsafe` inside of a `unsafe`-adorned extern block.
|
||||
fn check_item_safety(&self, span: Span, safety: Safety) {
|
||||
match self.extern_mod_safety {
|
||||
Some(extern_safety) => {
|
||||
|
|
@ -579,7 +556,7 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
|
||||
fn current_extern_span(&self) -> Span {
|
||||
self.session.source_map().guess_head_span(self.extern_mod.unwrap().span)
|
||||
self.session.source_map().guess_head_span(self.extern_mod.unwrap())
|
||||
}
|
||||
|
||||
/// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
|
||||
|
|
@ -923,16 +900,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.walk_ty(ty)
|
||||
}
|
||||
|
||||
fn visit_label(&mut self, label: &'a Label) {
|
||||
self.check_label(label.ident);
|
||||
visit::walk_label(self, label);
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lifetime: &'a Lifetime, _: visit::LifetimeCtxt) {
|
||||
self.check_lifetime(lifetime.ident);
|
||||
visit::walk_lifetime(self, lifetime);
|
||||
}
|
||||
|
||||
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
||||
self.deny_unnamed_field(field);
|
||||
visit::walk_field_def(self, field)
|
||||
|
|
@ -980,7 +947,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
let disallowed = matches!(constness, Const::No)
|
||||
.then(|| DisallowTildeConstContext::TraitImpl(item.span));
|
||||
.then(|| TildeConstReason::TraitImpl { span: item.span });
|
||||
this.with_tilde_const(disallowed, |this| this.visit_generics(generics));
|
||||
this.visit_trait_ref(t);
|
||||
this.visit_ty(self_ty);
|
||||
|
|
@ -1035,7 +1002,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
this.visit_vis(&item.vis);
|
||||
this.visit_ident(item.ident);
|
||||
this.with_tilde_const(
|
||||
Some(DisallowTildeConstContext::Impl(item.span)),
|
||||
Some(TildeConstReason::Impl { span: item.span }),
|
||||
|this| this.visit_generics(generics),
|
||||
);
|
||||
this.visit_ty(self_ty);
|
||||
|
|
@ -1080,7 +1047,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => {
|
||||
self.with_in_extern_mod(*safety, |this| {
|
||||
let old_item = mem::replace(&mut this.extern_mod, Some(item));
|
||||
let old_item = mem::replace(&mut this.extern_mod, Some(item.span));
|
||||
this.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualForeignItems,
|
||||
|
|
@ -1154,7 +1121,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
this.visit_ident(item.ident);
|
||||
let disallowed = is_const_trait
|
||||
.is_none()
|
||||
.then(|| DisallowTildeConstContext::Trait(item.span));
|
||||
.then(|| TildeConstReason::Trait { span: item.span });
|
||||
this.with_tilde_const(disallowed, |this| {
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
||||
|
|
@ -1215,6 +1182,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
ItemKind::Static(box StaticItem { expr, safety, .. }) => {
|
||||
self.check_item_safety(item.span, *safety);
|
||||
if matches!(safety, Safety::Unsafe(_)) {
|
||||
self.dcx().emit_err(errors::UnsafeStatic { span: item.span });
|
||||
}
|
||||
|
||||
if expr.is_none() {
|
||||
self.dcx().emit_err(errors::StaticWithoutBody {
|
||||
|
|
@ -1371,13 +1341,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, param: &'a GenericParam) {
|
||||
if let GenericParamKind::Lifetime { .. } = param.kind {
|
||||
self.check_lifetime(param.ident);
|
||||
}
|
||||
visit::walk_generic_param(self, param);
|
||||
}
|
||||
|
||||
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
|
||||
match bound {
|
||||
GenericBound::Trait(trait_ref, modifiers) => {
|
||||
|
|
@ -1399,40 +1362,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::ConstBoundTraitObject { span: trait_ref.span });
|
||||
}
|
||||
(_, BoundConstness::Maybe(span), BoundPolarity::Positive)
|
||||
if let Some(reason) = &self.disallow_tilde_const =>
|
||||
if let Some(reason) = self.disallow_tilde_const =>
|
||||
{
|
||||
let reason = match reason {
|
||||
DisallowTildeConstContext::Fn(FnKind::Closure(..)) => {
|
||||
errors::TildeConstReason::Closure
|
||||
}
|
||||
DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => {
|
||||
errors::TildeConstReason::Function { ident: ident.span }
|
||||
}
|
||||
&DisallowTildeConstContext::Trait(span) => {
|
||||
errors::TildeConstReason::Trait { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImpl(span) => {
|
||||
errors::TildeConstReason::TraitImpl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::Impl(span) => {
|
||||
// FIXME(effects): Consider providing a help message or even a structured
|
||||
// suggestion for moving such bounds to the assoc const fns if available.
|
||||
errors::TildeConstReason::Impl { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::TraitImplAssocTy(span) => {
|
||||
errors::TildeConstReason::TraitImplAssocTy { span }
|
||||
}
|
||||
&DisallowTildeConstContext::InherentAssocTy(span) => {
|
||||
errors::TildeConstReason::InherentAssocTy { span }
|
||||
}
|
||||
DisallowTildeConstContext::TraitObject => {
|
||||
errors::TildeConstReason::TraitObject
|
||||
}
|
||||
DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
|
||||
};
|
||||
self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
|
||||
}
|
||||
(
|
||||
|
|
@ -1569,7 +1500,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
.and_then(TraitOrTraitImpl::constness)
|
||||
.is_some();
|
||||
|
||||
let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
|
||||
let disallowed = (!tilde_const_allowed).then(|| match fk {
|
||||
FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
|
||||
FnKind::Closure(_, _, _) => TildeConstReason::Closure,
|
||||
});
|
||||
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
|
||||
}
|
||||
|
||||
|
|
@ -1664,12 +1598,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
AssocItemKind::Type(_) => {
|
||||
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
|
||||
Some(TraitOrTraitImpl::Trait { .. }) => {
|
||||
DisallowTildeConstContext::TraitAssocTy(item.span)
|
||||
TildeConstReason::TraitAssocTy { span: item.span }
|
||||
}
|
||||
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
|
||||
DisallowTildeConstContext::TraitImplAssocTy(item.span)
|
||||
TildeConstReason::TraitImplAssocTy { span: item.span }
|
||||
}
|
||||
None => DisallowTildeConstContext::InherentAssocTy(item.span),
|
||||
None => TildeConstReason::InherentAssocTy { span: item.span },
|
||||
});
|
||||
self.with_tilde_const(disallowed, |this| {
|
||||
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
|
||||
|
|
@ -1852,7 +1786,7 @@ pub fn check_crate(
|
|||
outer_trait_or_trait_impl: None,
|
||||
has_proc_macro_decls: false,
|
||||
outer_impl_trait: None,
|
||||
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
|
||||
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||
is_impl_trait_banned: false,
|
||||
extern_mod_safety: None,
|
||||
lint_buffer: lints,
|
||||
|
|
|
|||
|
|
@ -9,21 +9,6 @@ use rustc_span::{symbol::Ident, Span, Symbol};
|
|||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_keyword_lifetime)]
|
||||
pub struct KeywordLifetime {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_invalid_label)]
|
||||
pub struct InvalidLabel {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_visibility_not_permitted, code = E0449)]
|
||||
pub struct VisibilityNotPermitted {
|
||||
|
|
@ -239,6 +224,13 @@ pub struct InvalidSafetyOnBareFn {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_unsafe_static)]
|
||||
pub struct UnsafeStatic {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_bound_in_context)]
|
||||
pub struct BoundInContext<'a> {
|
||||
|
|
@ -612,7 +604,7 @@ pub struct TildeConstDisallowed {
|
|||
pub reason: TildeConstReason,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[derive(Subdiagnostic, Copy, Clone)]
|
||||
pub enum TildeConstReason {
|
||||
#[note(ast_passes_closure)]
|
||||
Closure,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_errors::Diag;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::error_reporting::infer::nice_region_error::NiceRegionError;
|
||||
use rustc_infer::infer::canonical::Canonical;
|
||||
use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use rustc_infer::infer::region_constraints::Constraint;
|
||||
use rustc_infer::infer::region_constraints::RegionConstraintData;
|
||||
use rustc_infer::infer::RegionVariableOrigin;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use either::Either;
|
||||
use hir::ClosureKind;
|
||||
use hir::{ClosureKind, Path};
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan};
|
||||
|
|
@ -16,6 +16,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, LangItem};
|
|||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter::OnlyBodies;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::VarDebugInfoContents;
|
||||
use rustc_middle::mir::{
|
||||
self, AggregateKind, BindingForm, BorrowKind, CallSource, ClearCrossCrate, ConstraintCategory,
|
||||
FakeBorrowKind, FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, MutBorrowKind,
|
||||
|
|
@ -204,9 +205,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
is_loop_move = true;
|
||||
}
|
||||
|
||||
let mut has_suggest_reborrow = false;
|
||||
if !seen_spans.contains(&move_span) {
|
||||
if !closure {
|
||||
self.suggest_ref_or_clone(mpi, &mut err, &mut in_pattern, move_spans);
|
||||
self.suggest_ref_or_clone(
|
||||
mpi,
|
||||
&mut err,
|
||||
&mut in_pattern,
|
||||
move_spans,
|
||||
moved_place.as_ref(),
|
||||
&mut has_suggest_reborrow,
|
||||
);
|
||||
}
|
||||
|
||||
let msg_opt = CapturedMessageOpt {
|
||||
|
|
@ -214,6 +223,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
is_loop_message,
|
||||
is_move_msg,
|
||||
is_loop_move,
|
||||
has_suggest_reborrow,
|
||||
maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations
|
||||
.is_empty(),
|
||||
};
|
||||
|
|
@ -258,17 +268,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) {
|
||||
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
|
||||
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
format!(
|
||||
"consider creating a fresh reborrow of {} here",
|
||||
self.describe_place(moved_place)
|
||||
.map(|n| format!("`{n}`"))
|
||||
.unwrap_or_else(|| "the mutable reference".to_string()),
|
||||
),
|
||||
"&mut *",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
self.suggest_reborrow(&mut err, span, moved_place);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -345,6 +345,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
err: &mut Diag<'infcx>,
|
||||
in_pattern: &mut bool,
|
||||
move_spans: UseSpans<'tcx>,
|
||||
moved_place: PlaceRef<'tcx>,
|
||||
has_suggest_reborrow: &mut bool,
|
||||
) {
|
||||
let move_span = match move_spans {
|
||||
UseSpans::ClosureUse { capture_kind_span, .. } => capture_kind_span,
|
||||
|
|
@ -434,20 +436,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
|
||||
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
|
||||
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
|
||||
{
|
||||
(def_id.as_local(), args, 1)
|
||||
(typeck.type_dependent_def_id(parent_expr.hir_id), args, 1)
|
||||
} else if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
|
||||
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
|
||||
{
|
||||
(def_id.as_local(), args, 0)
|
||||
(Some(*def_id), args, 0)
|
||||
} else {
|
||||
(None, &[][..], 0)
|
||||
};
|
||||
|
||||
// If the moved value is a mut reference, it is used in a
|
||||
// generic function and it's type is a generic param, it can be
|
||||
// reborrowed to avoid moving.
|
||||
// for example:
|
||||
// struct Y(u32);
|
||||
// x's type is '& mut Y' and it is used in `fn generic<T>(x: T) {}`.
|
||||
if let Some(def_id) = def_id
|
||||
&& self.infcx.tcx.def_kind(def_id).is_fn_like()
|
||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
||||
&& let ty::Param(_) =
|
||||
self.infcx.tcx.fn_sig(def_id).skip_binder().skip_binder().inputs()
|
||||
[pos + offset]
|
||||
.kind()
|
||||
{
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
|
||||
*has_suggest_reborrow = true;
|
||||
self.suggest_reborrow(err, expr.span, moved_place);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut can_suggest_clone = true;
|
||||
if let Some(def_id) = def_id
|
||||
&& let node = self.infcx.tcx.hir_node_by_def_id(def_id)
|
||||
&& let Some(local_def_id) = def_id.as_local()
|
||||
&& let node = self.infcx.tcx.hir_node_by_def_id(local_def_id)
|
||||
&& let Some(fn_sig) = node.fn_sig()
|
||||
&& let Some(ident) = node.ident()
|
||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
||||
|
|
@ -546,7 +572,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
self.suggest_cloning(err, ty, expr, None, Some(move_spans));
|
||||
}
|
||||
}
|
||||
if let Some(pat) = finder.pat {
|
||||
|
||||
self.suggest_ref_for_dbg_args(expr, place, move_span, err);
|
||||
|
||||
// it's useless to suggest inserting `ref` when the span don't comes from local code
|
||||
if let Some(pat) = finder.pat
|
||||
&& !move_span.is_dummy()
|
||||
&& !self.infcx.tcx.sess.source_map().is_imported(move_span)
|
||||
{
|
||||
*in_pattern = true;
|
||||
let mut sugg = vec![(pat.span.shrink_to_lo(), "ref ".to_string())];
|
||||
if let Some(pat) = finder.parent_pat {
|
||||
|
|
@ -561,6 +594,78 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// for dbg!(x) which may take ownership, suggest dbg!(&x) instead
|
||||
// but here we actually do not check whether the macro name is `dbg!`
|
||||
// so that we may extend the scope a bit larger to cover more cases
|
||||
fn suggest_ref_for_dbg_args(
|
||||
&self,
|
||||
body: &hir::Expr<'_>,
|
||||
place: &Place<'tcx>,
|
||||
move_span: Span,
|
||||
err: &mut Diag<'infcx>,
|
||||
) {
|
||||
let var_info = self.body.var_debug_info.iter().find(|info| match info.value {
|
||||
VarDebugInfoContents::Place(ref p) => p == place,
|
||||
_ => false,
|
||||
});
|
||||
let arg_name = if let Some(var_info) = var_info {
|
||||
var_info.name
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
struct MatchArgFinder {
|
||||
expr_span: Span,
|
||||
match_arg_span: Option<Span>,
|
||||
arg_name: Symbol,
|
||||
}
|
||||
impl Visitor<'_> for MatchArgFinder {
|
||||
fn visit_expr(&mut self, e: &hir::Expr<'_>) {
|
||||
// dbg! is expanded into a match pattern, we need to find the right argument span
|
||||
if let hir::ExprKind::Match(expr, ..) = &e.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
path @ Path { segments: [seg], .. },
|
||||
)) = &expr.kind
|
||||
&& seg.ident.name == self.arg_name
|
||||
&& self.expr_span.source_callsite().contains(expr.span)
|
||||
{
|
||||
self.match_arg_span = Some(path.span);
|
||||
}
|
||||
hir::intravisit::walk_expr(self, e);
|
||||
}
|
||||
}
|
||||
|
||||
let mut finder = MatchArgFinder { expr_span: move_span, match_arg_span: None, arg_name };
|
||||
finder.visit_expr(body);
|
||||
if let Some(macro_arg_span) = finder.match_arg_span {
|
||||
err.span_suggestion_verbose(
|
||||
macro_arg_span.shrink_to_lo(),
|
||||
"consider borrowing instead of transferring ownership",
|
||||
"&",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_reborrow(
|
||||
&self,
|
||||
err: &mut Diag<'infcx>,
|
||||
span: Span,
|
||||
moved_place: PlaceRef<'tcx>,
|
||||
) {
|
||||
err.span_suggestion_verbose(
|
||||
span.shrink_to_lo(),
|
||||
format!(
|
||||
"consider creating a fresh reborrow of {} here",
|
||||
self.describe_place(moved_place)
|
||||
.map(|n| format!("`{n}`"))
|
||||
.unwrap_or_else(|| "the mutable reference".to_string()),
|
||||
),
|
||||
"&mut *",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
fn report_use_of_uninitialized(
|
||||
&self,
|
||||
mpi: MovePathIndex,
|
||||
|
|
|
|||
|
|
@ -768,10 +768,11 @@ struct CapturedMessageOpt {
|
|||
is_loop_message: bool,
|
||||
is_move_msg: bool,
|
||||
is_loop_move: bool,
|
||||
has_suggest_reborrow: bool,
|
||||
maybe_reinitialized_locations_is_empty: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
|
||||
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
||||
/// Finds the spans associated to a move or copy of move_place at location.
|
||||
pub(super) fn move_spans(
|
||||
&self,
|
||||
|
|
@ -997,7 +998,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
|
|||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn explain_captures(
|
||||
&mut self,
|
||||
err: &mut Diag<'_>,
|
||||
err: &mut Diag<'infcx>,
|
||||
span: Span,
|
||||
move_span: Span,
|
||||
move_spans: UseSpans<'tcx>,
|
||||
|
|
@ -1009,6 +1010,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
|
|||
is_loop_message,
|
||||
is_move_msg,
|
||||
is_loop_move,
|
||||
has_suggest_reborrow,
|
||||
maybe_reinitialized_locations_is_empty,
|
||||
} = msg_opt;
|
||||
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
|
||||
|
|
@ -1182,18 +1184,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
|
|||
if let ty::Ref(_, _, hir::Mutability::Mut) =
|
||||
moved_place.ty(self.body, self.infcx.tcx).ty.kind()
|
||||
{
|
||||
// If we are in a loop this will be suggested later.
|
||||
if !is_loop_move {
|
||||
err.span_suggestion_verbose(
|
||||
// Suggest `reborrow` in other place for following situations:
|
||||
// 1. If we are in a loop this will be suggested later.
|
||||
// 2. If the moved value is a mut reference, it is used in a
|
||||
// generic function and the corresponding arg's type is generic param.
|
||||
if !is_loop_move && !has_suggest_reborrow {
|
||||
self.suggest_reborrow(
|
||||
err,
|
||||
move_span.shrink_to_lo(),
|
||||
format!(
|
||||
"consider creating a fresh reborrow of {} here",
|
||||
self.describe_place(moved_place.as_ref())
|
||||
.map(|n| format!("`{n}`"))
|
||||
.unwrap_or_else(|| "the mutable reference".to_string()),
|
||||
),
|
||||
"&mut *",
|
||||
Applicability::MachineApplicable,
|
||||
moved_place.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,6 +554,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
|||
is_loop_message: false,
|
||||
is_move_msg: false,
|
||||
is_loop_move: false,
|
||||
has_suggest_reborrow: false,
|
||||
maybe_reinitialized_locations_is_empty: true,
|
||||
};
|
||||
if let Some(use_spans) = use_spans {
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ use rustc_hir::GenericBound::Trait;
|
|||
use rustc_hir::QPath::Resolved;
|
||||
use rustc_hir::WherePredicate::BoundPredicate;
|
||||
use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
|
||||
use rustc_infer::infer::error_reporting::nice_region_error::{
|
||||
use rustc_infer::error_reporting::infer::nice_region_error::{
|
||||
self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params,
|
||||
HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor,
|
||||
};
|
||||
use rustc_infer::infer::error_reporting::region::unexpected_hidden_region_diagnostic;
|
||||
use rustc_infer::error_reporting::infer::region::unexpected_hidden_region_diagnostic;
|
||||
use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
|
|
|
|||
|
|
@ -309,14 +309,10 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.type_checker.infcx.tcx
|
||||
}
|
||||
|
||||
fn tag(&self) -> &'static str {
|
||||
"nll::subtype"
|
||||
}
|
||||
|
||||
#[instrument(skip(self, info), level = "trace", ret)]
|
||||
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
|
||||
&mut self,
|
||||
|
|
@ -370,7 +366,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx
|
|||
// shouldn't ever fail. Instead, it unconditionally emits an
|
||||
// alias-relate goal.
|
||||
assert!(!self.type_checker.infcx.next_trait_solver());
|
||||
self.tcx().dcx().span_delayed_bug(
|
||||
self.cx().dcx().span_delayed_bug(
|
||||
self.span(),
|
||||
"failure to relate an opaque to itself should result in an error later on",
|
||||
);
|
||||
|
|
@ -540,7 +536,7 @@ impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating
|
|||
&mut self,
|
||||
obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
let tcx = self.cx();
|
||||
let param_env = self.param_env();
|
||||
self.register_goals(
|
||||
obligations.into_iter().map(|to_pred| Goal::new(tcx, param_env, to_pred)),
|
||||
|
|
@ -559,7 +555,7 @@ impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating
|
|||
.into_iter()
|
||||
.map(|goal| {
|
||||
Obligation::new(
|
||||
self.tcx(),
|
||||
self.cx(),
|
||||
ObligationCause::dummy_with_span(self.span()),
|
||||
goal.param_env,
|
||||
goal.predicate,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use crate::errors;
|
|||
use rustc_ast::attr::mk_attr;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::{self as ast, AttrItem, AttrStyle};
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
|
@ -17,13 +18,14 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
|||
));
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) {
|
||||
Ok(ai) => ai,
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let AttrItem { unsafety, path, args, tokens: _ } =
|
||||
match parser.parse_attr_item(ForceCollect::No) {
|
||||
Ok(ai) => ai,
|
||||
Err(err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let end_span = parser.token.span;
|
||||
if parser.token != token::Eof {
|
||||
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rustc_codegen_ssa::back::archive::{
|
||||
get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
|
||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ pub(crate) struct ArArchiveBuilderBuilder;
|
|||
|
||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
||||
Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
|
||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
||||
}
|
||||
|
||||
fn create_dll_import_lib(
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
version = "Two"
|
||||
use_small_heuristics = "Max"
|
||||
merge_derives = false
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ impl Args {
|
|||
"--out-path" => match args.next() {
|
||||
Some(path) if !path.is_empty() => out_path = Some(path),
|
||||
_ => {
|
||||
return Err("Expected an argument after `--out-path`, found nothing".into())
|
||||
return Err("Expected an argument after `--out-path`, found nothing".into());
|
||||
}
|
||||
},
|
||||
"--help" => {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ impl ConfigFile {
|
|||
config.gcc_path = Some(value.as_str().to_string())
|
||||
}
|
||||
("gcc-path", _) => {
|
||||
return failed_config_parsing(config_file, "Expected a string for `gcc-path`")
|
||||
return failed_config_parsing(config_file, "Expected a string for `gcc-path`");
|
||||
}
|
||||
("download-gccjit", TomlValue::Boolean(value)) => {
|
||||
config.download_gccjit = Some(*value)
|
||||
|
|
@ -63,7 +63,7 @@ impl ConfigFile {
|
|||
return failed_config_parsing(
|
||||
config_file,
|
||||
"Expected a boolean for `download-gccjit`",
|
||||
)
|
||||
);
|
||||
}
|
||||
_ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)),
|
||||
}
|
||||
|
|
@ -73,7 +73,7 @@ impl ConfigFile {
|
|||
return failed_config_parsing(
|
||||
config_file,
|
||||
"At least one of `gcc-path` or `download-gccjit` value must be set",
|
||||
)
|
||||
);
|
||||
}
|
||||
(Some(_), Some(true)) => {
|
||||
println!(
|
||||
|
|
@ -144,7 +144,7 @@ impl ConfigInfo {
|
|||
_ => {
|
||||
return Err(
|
||||
"Expected a value after `--target-triple`, found nothing".to_string()
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
"--out-dir" => match args.next() {
|
||||
|
|
@ -158,7 +158,7 @@ impl ConfigInfo {
|
|||
self.config_file = Some(arg.to_string());
|
||||
}
|
||||
_ => {
|
||||
return Err("Expected a value after `--config-file`, found nothing".to_string())
|
||||
return Err("Expected a value after `--config-file`, found nothing".to_string());
|
||||
}
|
||||
},
|
||||
"--release-sysroot" => self.sysroot_release_channel = true,
|
||||
|
|
@ -169,7 +169,7 @@ impl ConfigInfo {
|
|||
self.cg_gcc_path = Some(arg.into());
|
||||
}
|
||||
_ => {
|
||||
return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string())
|
||||
return Err("Expected a value after `--cg_gcc-path`, found nothing".to_string());
|
||||
}
|
||||
},
|
||||
"--use-backend" => match args.next() {
|
||||
|
|
@ -277,7 +277,7 @@ impl ConfigInfo {
|
|||
self.gcc_path = match gcc_path {
|
||||
Some(path) => path,
|
||||
None => {
|
||||
return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),))
|
||||
return Err(format!("missing `gcc-path` value from `{}`", config_file.display(),));
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ impl TestArg {
|
|||
test_arg.flags.extend_from_slice(&["--features".into(), feature]);
|
||||
}
|
||||
_ => {
|
||||
return Err("Expected an argument after `--features`, found nothing".into())
|
||||
return Err("Expected an argument after `--features`, found nothing".into());
|
||||
}
|
||||
},
|
||||
"--use-system-gcc" => {
|
||||
|
|
@ -458,11 +458,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
|||
.map_err(|error| format!("Failed to retrieve cargo path: {:?}", error))
|
||||
.and_then(|cargo| {
|
||||
let cargo = cargo.trim().to_owned();
|
||||
if cargo.is_empty() {
|
||||
Err(format!("`cargo` path is empty"))
|
||||
} else {
|
||||
Ok(cargo)
|
||||
}
|
||||
if cargo.is_empty() { Err(format!("`cargo` path is empty")) } else { Ok(cargo) }
|
||||
})?;
|
||||
let rustc = String::from_utf8(
|
||||
run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))?
|
||||
|
|
@ -471,11 +467,7 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
|||
.map_err(|error| format!("Failed to retrieve rustc path: {:?}", error))
|
||||
.and_then(|rustc| {
|
||||
let rustc = rustc.trim().to_owned();
|
||||
if rustc.is_empty() {
|
||||
Err(format!("`rustc` path is empty"))
|
||||
} else {
|
||||
Ok(rustc)
|
||||
}
|
||||
if rustc.is_empty() { Err(format!("`rustc` path is empty")) } else { Ok(rustc) }
|
||||
})?;
|
||||
let llvm_filecheck = match run_command_with_env(
|
||||
&[
|
||||
|
|
|
|||
|
|
@ -175,11 +175,7 @@ pub fn cargo_install(to_install: &str) -> Result<(), String> {
|
|||
pub fn get_os_name() -> Result<String, String> {
|
||||
let output = run_command(&[&"uname"], None)?;
|
||||
let name = std::str::from_utf8(&output.stdout).unwrap_or("").trim().to_string();
|
||||
if !name.is_empty() {
|
||||
Ok(name)
|
||||
} else {
|
||||
Err("Failed to retrieve the OS name".to_string())
|
||||
}
|
||||
if !name.is_empty() { Ok(name) } else { Err("Failed to retrieve the OS name".to_string()) }
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -26,11 +26,7 @@ impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
} else {
|
||||
false
|
||||
};
|
||||
if on_stack {
|
||||
param.to_lvalue().get_address(None)
|
||||
} else {
|
||||
param.to_rvalue()
|
||||
}
|
||||
if on_stack { param.to_lvalue().get_address(None) } else { param.to_rvalue() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rustc_codegen_ssa::back::archive::{
|
||||
get_native_object_symbols, ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder,
|
||||
ArArchiveBuilder, ArchiveBuilder, ArchiveBuilderBuilder, DEFAULT_OBJECT_READER,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ pub(crate) struct ArArchiveBuilderBuilder;
|
|||
|
||||
impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
|
||||
Box::new(ArArchiveBuilder::new(sess, get_native_object_symbols))
|
||||
Box::new(ArArchiveBuilder::new(sess, &DEFAULT_OBJECT_READER))
|
||||
}
|
||||
|
||||
fn create_dll_import_lib(
|
||||
|
|
|
|||
|
|
@ -858,11 +858,7 @@ fn modifier_to_gcc(
|
|||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
|
||||
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
|
||||
if modifier == Some('v') {
|
||||
None
|
||||
} else {
|
||||
modifier
|
||||
}
|
||||
if modifier == Some('v') { None } else { modifier }
|
||||
}
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
|
|
|
|||
|
|
@ -1043,11 +1043,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
let llty = place.layout.scalar_pair_element_gcc_type(self, i);
|
||||
let load = self.load(llty, llptr, align);
|
||||
scalar_load_metadata(self, load, scalar);
|
||||
if scalar.is_bool() {
|
||||
self.trunc(load, self.type_i1())
|
||||
} else {
|
||||
load
|
||||
}
|
||||
if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
|
||||
};
|
||||
|
||||
OperandValue::Pair(
|
||||
|
|
@ -1795,18 +1791,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
// This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
|
||||
let int_max = |signed: bool, int_width: u64| -> u128 {
|
||||
let shift_amount = 128 - int_width;
|
||||
if signed {
|
||||
i128::MAX as u128 >> shift_amount
|
||||
} else {
|
||||
u128::MAX >> shift_amount
|
||||
}
|
||||
if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
|
||||
};
|
||||
let int_min = |signed: bool, int_width: u64| -> i128 {
|
||||
if signed {
|
||||
i128::MIN >> (128 - int_width)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
if signed { i128::MIN >> (128 - int_width) } else { 0 }
|
||||
};
|
||||
|
||||
let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
|
||||
|
|
|
|||
|
|
@ -58,11 +58,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool {
|
|||
|
||||
impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||
fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
|
||||
if type_is_pointer(typ) {
|
||||
self.context.new_null(typ)
|
||||
} else {
|
||||
self.const_int(typ, 0)
|
||||
}
|
||||
if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) }
|
||||
}
|
||||
|
||||
fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
|
||||
|
|
|
|||
|
|
@ -21,14 +21,16 @@ pub(crate) unsafe fn codegen(
|
|||
) {
|
||||
let llcx = &*module_llvm.llcx;
|
||||
let llmod = module_llvm.llmod();
|
||||
let usize = match tcx.sess.target.pointer_width {
|
||||
16 => llvm::LLVMInt16TypeInContext(llcx),
|
||||
32 => llvm::LLVMInt32TypeInContext(llcx),
|
||||
64 => llvm::LLVMInt64TypeInContext(llcx),
|
||||
tws => bug!("Unsupported target word size for int: {}", tws),
|
||||
let usize = unsafe {
|
||||
match tcx.sess.target.pointer_width {
|
||||
16 => llvm::LLVMInt16TypeInContext(llcx),
|
||||
32 => llvm::LLVMInt32TypeInContext(llcx),
|
||||
64 => llvm::LLVMInt64TypeInContext(llcx),
|
||||
tws => bug!("Unsupported target word size for int: {}", tws),
|
||||
}
|
||||
};
|
||||
let i8 = llvm::LLVMInt8TypeInContext(llcx);
|
||||
let i8p = llvm::LLVMPointerTypeInContext(llcx, 0);
|
||||
let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) };
|
||||
let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) };
|
||||
|
||||
if kind == AllocatorKind::Default {
|
||||
for method in ALLOCATOR_METHODS {
|
||||
|
|
@ -73,23 +75,25 @@ pub(crate) unsafe fn codegen(
|
|||
true,
|
||||
);
|
||||
|
||||
// __rust_alloc_error_handler_should_panic
|
||||
let name = OomStrategy::SYMBOL;
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||
if tcx.sess.default_hidden_visibility() {
|
||||
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
|
||||
}
|
||||
let val = tcx.sess.opts.unstable_opts.oom.should_panic();
|
||||
let llval = llvm::LLVMConstInt(i8, val as u64, False);
|
||||
llvm::LLVMSetInitializer(ll_g, llval);
|
||||
unsafe {
|
||||
// __rust_alloc_error_handler_should_panic
|
||||
let name = OomStrategy::SYMBOL;
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||
if tcx.sess.default_hidden_visibility() {
|
||||
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
|
||||
}
|
||||
let val = tcx.sess.opts.unstable_opts.oom.should_panic();
|
||||
let llval = llvm::LLVMConstInt(i8, val as u64, False);
|
||||
llvm::LLVMSetInitializer(ll_g, llval);
|
||||
|
||||
let name = NO_ALLOC_SHIM_IS_UNSTABLE;
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||
if tcx.sess.default_hidden_visibility() {
|
||||
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
|
||||
let name = NO_ALLOC_SHIM_IS_UNSTABLE;
|
||||
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||
if tcx.sess.default_hidden_visibility() {
|
||||
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
|
||||
}
|
||||
let llval = llvm::LLVMConstInt(i8, 0, False);
|
||||
llvm::LLVMSetInitializer(ll_g, llval);
|
||||
}
|
||||
let llval = llvm::LLVMConstInt(i8, 0, False);
|
||||
llvm::LLVMSetInitializer(ll_g, llval);
|
||||
|
||||
if tcx.sess.opts.debuginfo != DebugInfo::None {
|
||||
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ use crate::errors::{
|
|||
use crate::llvm::archive_ro::{ArchiveRO, Child};
|
||||
use crate::llvm::{self, ArchiveKind, LLVMMachineType, LLVMRustCOFFShortExport};
|
||||
use rustc_codegen_ssa::back::archive::{
|
||||
get_native_object_symbols, try_extract_macho_fat_archive, ArArchiveBuilder,
|
||||
ArchiveBuildFailure, ArchiveBuilder, ArchiveBuilderBuilder, UnknownArchiveKind,
|
||||
try_extract_macho_fat_archive, ArArchiveBuilder, ArchiveBuildFailure, ArchiveBuilder,
|
||||
ArchiveBuilderBuilder, ObjectReader, UnknownArchiveKind, DEFAULT_OBJECT_READER,
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
|||
if true {
|
||||
Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
|
||||
} else {
|
||||
Box::new(ArArchiveBuilder::new(sess, get_llvm_object_symbols))
|
||||
Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -291,57 +291,82 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
|||
|
||||
// The object crate doesn't know how to get symbols for LLVM bitcode and COFF bigobj files.
|
||||
// As such we need to use LLVM for them.
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
fn get_llvm_object_symbols(
|
||||
buf: &[u8],
|
||||
f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
|
||||
) -> io::Result<bool> {
|
||||
|
||||
static LLVM_OBJECT_READER: ObjectReader = ObjectReader {
|
||||
get_symbols: get_llvm_object_symbols,
|
||||
is_64_bit_object_file: llvm_is_64_bit_object_file,
|
||||
is_ec_object_file: llvm_is_ec_object_file,
|
||||
get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment,
|
||||
};
|
||||
|
||||
fn should_use_llvm_reader(buf: &[u8]) -> bool {
|
||||
let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) };
|
||||
|
||||
// COFF bigobj file, msvc LTO file or import library. See
|
||||
// https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51
|
||||
let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF");
|
||||
|
||||
if is_bitcode || is_unsupported_windows_obj_file {
|
||||
let mut state = Box::new(f);
|
||||
is_bitcode || is_unsupported_windows_obj_file
|
||||
}
|
||||
|
||||
let err = unsafe {
|
||||
llvm::LLVMRustGetSymbols(
|
||||
buf.as_ptr(),
|
||||
buf.len(),
|
||||
std::ptr::addr_of_mut!(*state) as *mut c_void,
|
||||
callback,
|
||||
error_callback,
|
||||
)
|
||||
};
|
||||
|
||||
if err.is_null() {
|
||||
return Ok(true);
|
||||
} else {
|
||||
return Err(unsafe { *Box::from_raw(err as *mut io::Error) });
|
||||
}
|
||||
|
||||
unsafe extern "C" fn callback(
|
||||
state: *mut c_void,
|
||||
symbol_name: *const c_char,
|
||||
) -> *mut c_void {
|
||||
let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) };
|
||||
match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) {
|
||||
Ok(()) => std::ptr::null_mut(),
|
||||
Err(err) => Box::into_raw(Box::new(err)) as *mut c_void,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void {
|
||||
let error = unsafe { CStr::from_ptr(error) };
|
||||
Box::into_raw(Box::new(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("LLVM error: {}", error.to_string_lossy()),
|
||||
))) as *mut c_void
|
||||
}
|
||||
} else {
|
||||
get_native_object_symbols(buf, f)
|
||||
#[deny(unsafe_op_in_unsafe_fn)]
|
||||
fn get_llvm_object_symbols(
|
||||
buf: &[u8],
|
||||
f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
|
||||
) -> io::Result<bool> {
|
||||
if !should_use_llvm_reader(buf) {
|
||||
return (DEFAULT_OBJECT_READER.get_symbols)(buf, f);
|
||||
}
|
||||
|
||||
let mut state = Box::new(f);
|
||||
|
||||
let err = unsafe {
|
||||
llvm::LLVMRustGetSymbols(
|
||||
buf.as_ptr(),
|
||||
buf.len(),
|
||||
std::ptr::addr_of_mut!(*state) as *mut c_void,
|
||||
callback,
|
||||
error_callback,
|
||||
)
|
||||
};
|
||||
|
||||
if err.is_null() {
|
||||
return Ok(true);
|
||||
} else {
|
||||
return Err(unsafe { *Box::from_raw(err as *mut io::Error) });
|
||||
}
|
||||
|
||||
unsafe extern "C" fn callback(state: *mut c_void, symbol_name: *const c_char) -> *mut c_void {
|
||||
let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) };
|
||||
match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) {
|
||||
Ok(()) => std::ptr::null_mut(),
|
||||
Err(err) => Box::into_raw(Box::new(err)) as *mut c_void,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn error_callback(error: *const c_char) -> *mut c_void {
|
||||
let error = unsafe { CStr::from_ptr(error) };
|
||||
Box::into_raw(Box::new(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("LLVM error: {}", error.to_string_lossy()),
|
||||
))) as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool {
|
||||
if !should_use_llvm_reader(buf) {
|
||||
return (DEFAULT_OBJECT_READER.is_64_bit_object_file)(buf);
|
||||
}
|
||||
|
||||
unsafe { llvm::LLVMRustIs64BitSymbolicFile(buf.as_ptr(), buf.len()) }
|
||||
}
|
||||
|
||||
fn llvm_is_ec_object_file(buf: &[u8]) -> bool {
|
||||
if !should_use_llvm_reader(buf) {
|
||||
return (DEFAULT_OBJECT_READER.is_ec_object_file)(buf);
|
||||
}
|
||||
|
||||
unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) }
|
||||
}
|
||||
|
||||
impl<'a> LlvmArchiveBuilder<'a> {
|
||||
|
|
|
|||
|
|
@ -727,7 +727,7 @@ pub unsafe fn optimize_thin_module(
|
|||
// into that context. One day, however, we may do this for upstream
|
||||
// crates but for locally codegened modules we may be able to reuse
|
||||
// that LLVM Context and Module.
|
||||
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
|
||||
let llcx = unsafe { llvm::LLVMRustContextCreate(cgcx.fewer_names) };
|
||||
let llmod_raw = parse_module(llcx, module_name, thin_module.data(), dcx)? as *const _;
|
||||
let mut module = ModuleCodegen {
|
||||
module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) },
|
||||
|
|
@ -750,7 +750,9 @@ pub unsafe fn optimize_thin_module(
|
|||
{
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
|
||||
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
|
||||
if unsafe {
|
||||
!llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target)
|
||||
} {
|
||||
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
|
||||
|
|
@ -760,7 +762,8 @@ pub unsafe fn optimize_thin_module(
|
|||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name());
|
||||
if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
|
||||
if unsafe { !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) }
|
||||
{
|
||||
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
|
||||
|
|
@ -770,7 +773,8 @@ pub unsafe fn optimize_thin_module(
|
|||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name());
|
||||
if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
|
||||
if unsafe { !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) }
|
||||
{
|
||||
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
|
||||
|
|
@ -779,7 +783,9 @@ pub unsafe fn optimize_thin_module(
|
|||
{
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
|
||||
if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) {
|
||||
if unsafe {
|
||||
!llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target)
|
||||
} {
|
||||
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
|
||||
}
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
|
||||
|
|
|
|||
|
|
@ -46,13 +46,15 @@ pub unsafe extern "C" fn selfprofile_before_pass_callback(
|
|||
pass_name: *const c_char,
|
||||
ir_name: *const c_char,
|
||||
) {
|
||||
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
|
||||
let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8");
|
||||
let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8");
|
||||
llvm_self_profiler.before_pass_callback(pass_name, ir_name);
|
||||
unsafe {
|
||||
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
|
||||
let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8");
|
||||
let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8");
|
||||
llvm_self_profiler.before_pass_callback(pass_name, ir_name);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) {
|
||||
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
|
||||
let llvm_self_profiler = unsafe { &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>) };
|
||||
llvm_self_profiler.after_pass_callback();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -428,9 +428,10 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
|
|||
if user.is_null() {
|
||||
return;
|
||||
}
|
||||
let (cgcx, dcx) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>));
|
||||
let (cgcx, dcx) =
|
||||
unsafe { *(user as *const (&CodegenContext<LlvmCodegenBackend>, DiagCtxtHandle<'_>)) };
|
||||
|
||||
match llvm::diagnostic::Diagnostic::unpack(info) {
|
||||
match unsafe { llvm::diagnostic::Diagnostic::unpack(info) } {
|
||||
llvm::diagnostic::InlineAsm(inline) => {
|
||||
report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source);
|
||||
}
|
||||
|
|
@ -454,14 +455,14 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
|
|||
});
|
||||
}
|
||||
llvm::diagnostic::PGO(diagnostic_ref) | llvm::diagnostic::Linker(diagnostic_ref) => {
|
||||
let message = llvm::build_string(|s| {
|
||||
let message = llvm::build_string(|s| unsafe {
|
||||
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
|
||||
})
|
||||
.expect("non-UTF8 diagnostic");
|
||||
dcx.emit_warn(FromLlvmDiag { message });
|
||||
}
|
||||
llvm::diagnostic::Unsupported(diagnostic_ref) => {
|
||||
let message = llvm::build_string(|s| {
|
||||
let message = llvm::build_string(|s| unsafe {
|
||||
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
|
||||
})
|
||||
.expect("non-UTF8 diagnostic");
|
||||
|
|
@ -564,37 +565,39 @@ pub(crate) unsafe fn llvm_optimize(
|
|||
|
||||
let llvm_plugins = config.llvm_plugins.join(",");
|
||||
|
||||
let result = llvm::LLVMRustOptimize(
|
||||
module.module_llvm.llmod(),
|
||||
&*module.module_llvm.tm,
|
||||
to_pass_builder_opt_level(opt_level),
|
||||
opt_stage,
|
||||
cgcx.opts.cg.linker_plugin_lto.enabled(),
|
||||
config.no_prepopulate_passes,
|
||||
config.verify_llvm_ir,
|
||||
using_thin_buffers,
|
||||
config.merge_functions,
|
||||
unroll_loops,
|
||||
config.vectorize_slp,
|
||||
config.vectorize_loop,
|
||||
config.no_builtins,
|
||||
config.emit_lifetime_markers,
|
||||
sanitizer_options.as_ref(),
|
||||
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
config.instrument_coverage,
|
||||
instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
config.instrument_gcov,
|
||||
pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
config.debug_info_for_profiling,
|
||||
llvm_selfprofiler,
|
||||
selfprofile_before_pass_callback,
|
||||
selfprofile_after_pass_callback,
|
||||
extra_passes.as_ptr().cast(),
|
||||
extra_passes.len(),
|
||||
llvm_plugins.as_ptr().cast(),
|
||||
llvm_plugins.len(),
|
||||
);
|
||||
let result = unsafe {
|
||||
llvm::LLVMRustOptimize(
|
||||
module.module_llvm.llmod(),
|
||||
&*module.module_llvm.tm,
|
||||
to_pass_builder_opt_level(opt_level),
|
||||
opt_stage,
|
||||
cgcx.opts.cg.linker_plugin_lto.enabled(),
|
||||
config.no_prepopulate_passes,
|
||||
config.verify_llvm_ir,
|
||||
using_thin_buffers,
|
||||
config.merge_functions,
|
||||
unroll_loops,
|
||||
config.vectorize_slp,
|
||||
config.vectorize_loop,
|
||||
config.no_builtins,
|
||||
config.emit_lifetime_markers,
|
||||
sanitizer_options.as_ref(),
|
||||
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
config.instrument_coverage,
|
||||
instr_profile_output_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
config.instrument_gcov,
|
||||
pgo_sample_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
config.debug_info_for_profiling,
|
||||
llvm_selfprofiler,
|
||||
selfprofile_before_pass_callback,
|
||||
selfprofile_after_pass_callback,
|
||||
extra_passes.as_ptr().cast(),
|
||||
extra_passes.len(),
|
||||
llvm_plugins.as_ptr().cast(),
|
||||
llvm_plugins.len(),
|
||||
)
|
||||
};
|
||||
result.into_result().map_err(|()| llvm_err(dcx, LlvmError::RunLlvmPasses))
|
||||
}
|
||||
|
||||
|
|
@ -617,7 +620,7 @@ pub(crate) unsafe fn optimize(
|
|||
if config.emit_no_opt_bc {
|
||||
let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
|
||||
let out = path_to_c_string(&out);
|
||||
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
|
||||
unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) };
|
||||
}
|
||||
|
||||
if let Some(opt_level) = config.opt_level {
|
||||
|
|
@ -627,7 +630,7 @@ pub(crate) unsafe fn optimize(
|
|||
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
|
||||
_ => llvm::OptStage::PreLinkNoLTO,
|
||||
};
|
||||
return llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage);
|
||||
return unsafe { llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) };
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -692,10 +695,12 @@ pub(crate) unsafe fn codegen(
|
|||
where
|
||||
F: FnOnce(&'ll mut PassManager<'ll>) -> R,
|
||||
{
|
||||
let cpm = llvm::LLVMCreatePassManager();
|
||||
llvm::LLVMAddAnalysisPasses(tm, cpm);
|
||||
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
|
||||
f(cpm)
|
||||
unsafe {
|
||||
let cpm = llvm::LLVMCreatePassManager();
|
||||
llvm::LLVMAddAnalysisPasses(tm, cpm);
|
||||
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
|
||||
f(cpm)
|
||||
}
|
||||
}
|
||||
|
||||
// Two things to note:
|
||||
|
|
@ -757,7 +762,9 @@ pub(crate) unsafe fn codegen(
|
|||
let _timer = cgcx
|
||||
.prof
|
||||
.generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name);
|
||||
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
|
||||
unsafe {
|
||||
embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -793,7 +800,8 @@ pub(crate) unsafe fn codegen(
|
|||
cursor.position() as size_t
|
||||
}
|
||||
|
||||
let result = llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback);
|
||||
let result =
|
||||
unsafe { llvm::LLVMRustPrintModule(llmod, out_c.as_ptr(), demangle_callback) };
|
||||
|
||||
if result == llvm::LLVMRustResult::Success {
|
||||
record_artifact_size(&cgcx.prof, "llvm_ir", &out);
|
||||
|
|
@ -812,22 +820,24 @@ pub(crate) unsafe fn codegen(
|
|||
// binaries. So we must clone the module to produce the asm output
|
||||
// if we are also producing object code.
|
||||
let llmod = if let EmitObj::ObjectCode(_) = config.emit_obj {
|
||||
llvm::LLVMCloneModule(llmod)
|
||||
unsafe { llvm::LLVMCloneModule(llmod) }
|
||||
} else {
|
||||
llmod
|
||||
};
|
||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||
write_output_file(
|
||||
dcx,
|
||||
tm,
|
||||
cpm,
|
||||
llmod,
|
||||
&path,
|
||||
None,
|
||||
llvm::FileType::AssemblyFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
unsafe {
|
||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||
write_output_file(
|
||||
dcx,
|
||||
tm,
|
||||
cpm,
|
||||
llmod,
|
||||
&path,
|
||||
None,
|
||||
llvm::FileType::AssemblyFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
match config.emit_obj {
|
||||
|
|
@ -851,18 +861,20 @@ pub(crate) unsafe fn codegen(
|
|||
(_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
|
||||
};
|
||||
|
||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||
write_output_file(
|
||||
dcx,
|
||||
tm,
|
||||
cpm,
|
||||
llmod,
|
||||
&obj_out,
|
||||
dwo_out,
|
||||
llvm::FileType::ObjectFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
unsafe {
|
||||
with_codegen(tm, llmod, config.no_builtins, |cpm| {
|
||||
write_output_file(
|
||||
dcx,
|
||||
tm,
|
||||
cpm,
|
||||
llmod,
|
||||
&obj_out,
|
||||
dwo_out,
|
||||
llvm::FileType::ObjectFile,
|
||||
&cgcx.prof,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
EmitObj::Bitcode => {
|
||||
|
|
@ -1013,44 +1025,46 @@ unsafe fn embed_bitcode(
|
|||
// reason (see issue #90326 for historical background).
|
||||
let is_aix = target_is_aix(cgcx);
|
||||
let is_apple = target_is_apple(cgcx);
|
||||
if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") {
|
||||
// We don't need custom section flags, create LLVM globals.
|
||||
let llconst = common::bytes_in_context(llcx, bitcode);
|
||||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
c"rustc.embedded.module".as_ptr().cast(),
|
||||
);
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
unsafe {
|
||||
if is_apple || is_aix || cgcx.opts.target_triple.triple().starts_with("wasm") {
|
||||
// We don't need custom section flags, create LLVM globals.
|
||||
let llconst = common::bytes_in_context(llcx, bitcode);
|
||||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
c"rustc.embedded.module".as_ptr().cast(),
|
||||
);
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
|
||||
let section = bitcode_section_name(cgcx);
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
||||
let section = bitcode_section_name(cgcx);
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
|
||||
|
||||
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
|
||||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
c"rustc.embedded.cmdline".as_ptr().cast(),
|
||||
);
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
let section = if is_apple {
|
||||
c"__LLVM,__cmdline"
|
||||
} else if is_aix {
|
||||
c".info"
|
||||
let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
|
||||
let llglobal = llvm::LLVMAddGlobal(
|
||||
llmod,
|
||||
common::val_ty(llconst),
|
||||
c"rustc.embedded.cmdline".as_ptr().cast(),
|
||||
);
|
||||
llvm::LLVMSetInitializer(llglobal, llconst);
|
||||
let section = if is_apple {
|
||||
c"__LLVM,__cmdline"
|
||||
} else if is_aix {
|
||||
c".info"
|
||||
} else {
|
||||
c".llvmcmd"
|
||||
};
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
} else {
|
||||
c".llvmcmd"
|
||||
};
|
||||
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
|
||||
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
|
||||
} else {
|
||||
// We need custom section flags, so emit module-level inline assembly.
|
||||
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
|
||||
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
|
||||
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
|
||||
// We need custom section flags, so emit module-level inline assembly.
|
||||
let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
|
||||
let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
|
||||
let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
|
||||
llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -495,8 +495,14 @@ impl<'ll> CodegenCx<'ll, '_> {
|
|||
}
|
||||
|
||||
// Wasm statics with custom link sections get special treatment as they
|
||||
// go into custom sections of the wasm executable.
|
||||
if self.tcx.sess.target.is_like_wasm {
|
||||
// go into custom sections of the wasm executable. The exception to this
|
||||
// is the `.init_array` section which are treated specially by the wasm linker.
|
||||
if self.tcx.sess.target.is_like_wasm
|
||||
&& attrs
|
||||
.link_section
|
||||
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
if let Some(section) = attrs.link_section {
|
||||
let section = llvm::LLVMMDStringInContext2(
|
||||
self.llcx,
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ pub unsafe fn create_module<'ll>(
|
|||
) -> &'ll llvm::Module {
|
||||
let sess = tcx.sess;
|
||||
let mod_name = SmallCStr::new(mod_name);
|
||||
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
|
||||
let llmod = unsafe { llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx) };
|
||||
|
||||
let mut target_data_layout = sess.target.data_layout.to_string();
|
||||
let llvm_version = llvm_util::get_version();
|
||||
|
|
@ -153,11 +153,14 @@ pub unsafe fn create_module<'ll>(
|
|||
// Ensure the data-layout values hardcoded remain the defaults.
|
||||
{
|
||||
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
|
||||
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
|
||||
unsafe {
|
||||
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm);
|
||||
}
|
||||
|
||||
let llvm_data_layout = llvm::LLVMGetDataLayoutStr(llmod);
|
||||
let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes())
|
||||
.expect("got a non-UTF8 data-layout from LLVM");
|
||||
let llvm_data_layout = unsafe { llvm::LLVMGetDataLayoutStr(llmod) };
|
||||
let llvm_data_layout =
|
||||
str::from_utf8(unsafe { CStr::from_ptr(llvm_data_layout) }.to_bytes())
|
||||
.expect("got a non-UTF8 data-layout from LLVM");
|
||||
|
||||
if target_data_layout != llvm_data_layout {
|
||||
tcx.dcx().emit_err(crate::errors::MismatchedDataLayout {
|
||||
|
|
@ -170,20 +173,28 @@ pub unsafe fn create_module<'ll>(
|
|||
}
|
||||
|
||||
let data_layout = SmallCStr::new(&target_data_layout);
|
||||
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
|
||||
unsafe {
|
||||
llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
|
||||
}
|
||||
|
||||
let llvm_target = SmallCStr::new(&sess.target.llvm_target);
|
||||
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
|
||||
unsafe {
|
||||
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
|
||||
}
|
||||
|
||||
let reloc_model = sess.relocation_model();
|
||||
if matches!(reloc_model, RelocModel::Pic | RelocModel::Pie) {
|
||||
llvm::LLVMRustSetModulePICLevel(llmod);
|
||||
unsafe {
|
||||
llvm::LLVMRustSetModulePICLevel(llmod);
|
||||
}
|
||||
// PIE is potentially more effective than PIC, but can only be used in executables.
|
||||
// If all our outputs are executables, then we can relax PIC to PIE.
|
||||
if reloc_model == RelocModel::Pie
|
||||
|| tcx.crate_types().iter().all(|ty| *ty == CrateType::Executable)
|
||||
{
|
||||
llvm::LLVMRustSetModulePIELevel(llmod);
|
||||
unsafe {
|
||||
llvm::LLVMRustSetModulePIELevel(llmod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,95 +203,109 @@ pub unsafe fn create_module<'ll>(
|
|||
// longer jumps) if a larger code model is used with a smaller one.
|
||||
//
|
||||
// See https://reviews.llvm.org/D52322 and https://reviews.llvm.org/D52323.
|
||||
llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model()));
|
||||
unsafe {
|
||||
llvm::LLVMRustSetModuleCodeModel(llmod, to_llvm_code_model(sess.code_model()));
|
||||
}
|
||||
|
||||
// If skipping the PLT is enabled, we need to add some module metadata
|
||||
// to ensure intrinsic calls don't use it.
|
||||
if !sess.needs_plt() {
|
||||
let avoid_plt = c"RtLibUseGOT".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
|
||||
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
|
||||
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
canonical_jump_tables,
|
||||
1,
|
||||
);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
canonical_jump_tables,
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
|
||||
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
|
||||
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
enable_split_lto_unit,
|
||||
1,
|
||||
);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
enable_split_lto_unit,
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
|
||||
if sess.is_sanitizer_kcfi_enabled() {
|
||||
let kcfi = c"kcfi".as_ptr().cast();
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
|
||||
if sess.target.is_like_msvc {
|
||||
match sess.opts.cg.control_flow_guard {
|
||||
CFGuard::Disabled => {}
|
||||
CFGuard::NoChecks => {
|
||||
// Set `cfguard=1` module flag to emit metadata only.
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
1,
|
||||
)
|
||||
}
|
||||
CFGuard::Checks => {
|
||||
// Set `cfguard=2` module flag to emit metadata and checks.
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
2,
|
||||
)
|
||||
unsafe {
|
||||
match sess.opts.cg.control_flow_guard {
|
||||
CFGuard::Disabled => {}
|
||||
CFGuard::NoChecks => {
|
||||
// Set `cfguard=1` module flag to emit metadata only.
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
1,
|
||||
)
|
||||
}
|
||||
CFGuard::Checks => {
|
||||
// Set `cfguard=2` module flag to emit metadata and checks.
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"cfguard".as_ptr() as *const _,
|
||||
2,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
|
||||
if sess.target.arch == "aarch64" {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"branch-target-enforcement".as_ptr().cast(),
|
||||
bti.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address".as_ptr().cast(),
|
||||
pac_ret.is_some().into(),
|
||||
);
|
||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-all".as_ptr().cast(),
|
||||
pac_opts.leaf.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-with-bkey".as_ptr().cast(),
|
||||
u32::from(pac_opts.key == PAuthKey::B),
|
||||
);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"branch-target-enforcement".as_ptr().cast(),
|
||||
bti.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address".as_ptr().cast(),
|
||||
pac_ret.is_some().into(),
|
||||
);
|
||||
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-all".as_ptr().cast(),
|
||||
pac_opts.leaf.into(),
|
||||
);
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Min,
|
||||
c"sign-return-address-with-bkey".as_ptr().cast(),
|
||||
u32::from(pac_opts.key == PAuthKey::B),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
bug!(
|
||||
"branch-protection used on non-AArch64 target; \
|
||||
|
|
@ -291,39 +316,47 @@ pub unsafe fn create_module<'ll>(
|
|||
|
||||
// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
|
||||
if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-branch".as_ptr().cast(),
|
||||
1,
|
||||
)
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-branch".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-return".as_ptr().cast(),
|
||||
1,
|
||||
)
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Override,
|
||||
c"cf-protection-return".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if sess.opts.unstable_opts.virtual_function_elimination {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"Virtual Function Elim".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"Virtual Function Elim".as_ptr().cast(),
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Set module flag to enable Windows EHCont Guard (/guard:ehcont).
|
||||
if sess.opts.unstable_opts.ehcont_guard {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"ehcontguard".as_ptr() as *const _,
|
||||
1,
|
||||
)
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagU32(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Warning,
|
||||
c"ehcontguard".as_ptr() as *const _,
|
||||
1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert `llvm.ident` metadata.
|
||||
|
|
@ -333,16 +366,20 @@ pub unsafe fn create_module<'ll>(
|
|||
#[allow(clippy::option_env_unwrap)]
|
||||
let rustc_producer =
|
||||
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
|
||||
let name_metadata = llvm::LLVMMDStringInContext(
|
||||
llcx,
|
||||
rustc_producer.as_ptr().cast(),
|
||||
rustc_producer.as_bytes().len() as c_uint,
|
||||
);
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
llmod,
|
||||
c"llvm.ident".as_ptr(),
|
||||
llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
|
||||
);
|
||||
let name_metadata = unsafe {
|
||||
llvm::LLVMMDStringInContext(
|
||||
llcx,
|
||||
rustc_producer.as_ptr().cast(),
|
||||
rustc_producer.as_bytes().len() as c_uint,
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
llvm::LLVMAddNamedMetadataOperand(
|
||||
llmod,
|
||||
c"llvm.ident".as_ptr(),
|
||||
llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
|
||||
);
|
||||
}
|
||||
|
||||
// Emit RISC-V specific target-abi metadata
|
||||
// to workaround lld as the LTO plugin not
|
||||
|
|
@ -351,13 +388,15 @@ pub unsafe fn create_module<'ll>(
|
|||
// If llvm_abiname is empty, emit nothing.
|
||||
let llvm_abiname = &sess.target.options.llvm_abiname;
|
||||
if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() {
|
||||
llvm::LLVMRustAddModuleFlagString(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"target-abi".as_ptr(),
|
||||
llvm_abiname.as_ptr().cast(),
|
||||
llvm_abiname.len(),
|
||||
);
|
||||
unsafe {
|
||||
llvm::LLVMRustAddModuleFlagString(
|
||||
llmod,
|
||||
llvm::LLVMModFlagBehavior::Error,
|
||||
c"target-abi".as_ptr(),
|
||||
llvm_abiname.as_ptr().cast(),
|
||||
llvm_abiname.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add module flags specified via -Z llvm_module_flag
|
||||
|
|
@ -375,7 +414,7 @@ pub unsafe fn create_module<'ll>(
|
|||
// We already checked this during option parsing
|
||||
_ => unreachable!(),
|
||||
};
|
||||
llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value)
|
||||
unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) }
|
||||
}
|
||||
|
||||
llmod
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
module: &ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<(), FatalError> {
|
||||
back::write::optimize(cgcx, dcx, module, config)
|
||||
unsafe { back::write::optimize(cgcx, dcx, module, config) }
|
||||
}
|
||||
fn optimize_fat(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
|
|
@ -230,7 +230,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
cgcx: &CodegenContext<Self>,
|
||||
thin: ThinModule<Self>,
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
back::lto::optimize_thin_module(thin, cgcx)
|
||||
unsafe { back::lto::optimize_thin_module(thin, cgcx) }
|
||||
}
|
||||
unsafe fn codegen(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
|
|
@ -238,7 +238,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
module: ModuleCodegen<Self::Module>,
|
||||
config: &ModuleConfig,
|
||||
) -> Result<CompiledModule, FatalError> {
|
||||
back::write::codegen(cgcx, dcx, module, config)
|
||||
unsafe { back::write::codegen(cgcx, dcx, module, config) }
|
||||
}
|
||||
fn prepare_thin(
|
||||
module: ModuleCodegen<Self::Module>,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ impl<'ll> OptimizationDiagnostic<'ll> {
|
|||
let mut filename = None;
|
||||
let pass_name = super::build_string(|pass_name| {
|
||||
message = super::build_string(|message| {
|
||||
filename = super::build_string(|filename| {
|
||||
filename = super::build_string(|filename| unsafe {
|
||||
super::LLVMRustUnpackOptimizationDiagnostic(
|
||||
di,
|
||||
pass_name,
|
||||
|
|
@ -91,7 +91,7 @@ impl SrcMgrDiagnostic {
|
|||
let mut ranges = [0; 8];
|
||||
let mut num_ranges = ranges.len() / 2;
|
||||
let message = super::build_string(|message| {
|
||||
buffer = super::build_string(|buffer| {
|
||||
buffer = super::build_string(|buffer| unsafe {
|
||||
have_source = super::LLVMRustUnpackSMDiagnostic(
|
||||
diag,
|
||||
message,
|
||||
|
|
@ -134,7 +134,9 @@ impl InlineAsmDiagnostic {
|
|||
let mut message = None;
|
||||
let mut level = super::DiagnosticLevel::Error;
|
||||
|
||||
super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);
|
||||
unsafe {
|
||||
super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);
|
||||
}
|
||||
|
||||
InlineAsmDiagnostic {
|
||||
level,
|
||||
|
|
@ -146,7 +148,8 @@ impl InlineAsmDiagnostic {
|
|||
|
||||
unsafe fn unpackSrcMgr(di: &DiagnosticInfo) -> Self {
|
||||
let mut cookie = 0;
|
||||
let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie));
|
||||
let smdiag =
|
||||
unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) };
|
||||
InlineAsmDiagnostic {
|
||||
level: smdiag.level,
|
||||
cookie: cookie.into(),
|
||||
|
|
@ -170,44 +173,46 @@ pub enum Diagnostic<'ll> {
|
|||
impl<'ll> Diagnostic<'ll> {
|
||||
pub unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
|
||||
use super::DiagnosticKind as Dk;
|
||||
let kind = super::LLVMRustGetDiagInfoKind(di);
|
||||
|
||||
match kind {
|
||||
Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),
|
||||
unsafe {
|
||||
let kind = super::LLVMRustGetDiagInfoKind(di);
|
||||
match kind {
|
||||
Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),
|
||||
|
||||
Dk::OptimizationRemark => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
|
||||
Dk::OptimizationRemark => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
|
||||
}
|
||||
Dk::OptimizationRemarkOther => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di))
|
||||
}
|
||||
Dk::OptimizationRemarkMissed => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationRemarkAnalysis => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationRemarkAnalysisFPCommute => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationRemarkAnalysisAliasing => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationFailure => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di))
|
||||
}
|
||||
|
||||
Dk::PGOProfile => PGO(di),
|
||||
Dk::Linker => Linker(di),
|
||||
Dk::Unsupported => Unsupported(di),
|
||||
|
||||
Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)),
|
||||
|
||||
_ => UnknownDiagnostic(di),
|
||||
}
|
||||
Dk::OptimizationRemarkOther => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationRemarkOther, di))
|
||||
}
|
||||
Dk::OptimizationRemarkMissed => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationMissed, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationRemarkAnalysis => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysis, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationRemarkAnalysisFPCommute => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisFPCommute, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationRemarkAnalysisAliasing => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationAnalysisAliasing, di))
|
||||
}
|
||||
|
||||
Dk::OptimizationFailure => {
|
||||
Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di))
|
||||
}
|
||||
|
||||
Dk::PGOProfile => PGO(di),
|
||||
Dk::Linker => Linker(di),
|
||||
Dk::Unsupported => Unsupported(di),
|
||||
|
||||
Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)),
|
||||
|
||||
_ => UnknownDiagnostic(di),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2440,4 +2440,8 @@ extern "C" {
|
|||
callback: GetSymbolsCallback,
|
||||
error_callback: GetSymbolsErrorCallback,
|
||||
) -> *mut c_void;
|
||||
|
||||
pub fn LLVMRustIs64BitSymbolicFile(buf_ptr: *const u8, buf_len: usize) -> bool;
|
||||
|
||||
pub fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,12 +49,16 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||
let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
|
||||
let mut llvm_args = Vec::with_capacity(n_args + 1);
|
||||
|
||||
llvm::LLVMRustInstallErrorHandlers();
|
||||
unsafe {
|
||||
llvm::LLVMRustInstallErrorHandlers();
|
||||
}
|
||||
// On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog
|
||||
// box for the purpose of launching a debugger. However, on CI this will
|
||||
// cause it to hang until it times out, which can take several hours.
|
||||
if std::env::var_os("CI").is_some() {
|
||||
llvm::LLVMRustDisableSystemDialogsOnCrash();
|
||||
unsafe {
|
||||
llvm::LLVMRustDisableSystemDialogsOnCrash();
|
||||
}
|
||||
}
|
||||
|
||||
fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
|
||||
|
|
@ -124,12 +128,12 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||
}
|
||||
|
||||
if sess.opts.unstable_opts.llvm_time_trace {
|
||||
llvm::LLVMRustTimeTraceProfilerInitialize();
|
||||
unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() };
|
||||
}
|
||||
|
||||
rustc_llvm::initialize_available_targets();
|
||||
|
||||
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
|
||||
unsafe { llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()) };
|
||||
}
|
||||
|
||||
pub fn time_trace_profiler_finish(file_name: &Path) {
|
||||
|
|
@ -442,8 +446,8 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) {
|
|||
let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
|
||||
.unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
|
||||
unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) {
|
||||
let out = &mut *(out as *mut &mut String);
|
||||
let bytes = slice::from_raw_parts(string as *const u8, len);
|
||||
let out = unsafe { &mut *(out as *mut &mut String) };
|
||||
let bytes = unsafe { slice::from_raw_parts(string as *const u8, len) };
|
||||
write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap();
|
||||
}
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -108,8 +108,8 @@ impl CodegenCx<'_, '_> {
|
|||
llval: &llvm::Value,
|
||||
is_declaration: bool,
|
||||
) -> bool {
|
||||
let linkage = llvm::LLVMRustGetLinkage(llval);
|
||||
let visibility = llvm::LLVMRustGetVisibility(llval);
|
||||
let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) };
|
||||
let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) };
|
||||
|
||||
if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
|
||||
return true;
|
||||
|
|
@ -145,8 +145,8 @@ impl CodegenCx<'_, '_> {
|
|||
}
|
||||
|
||||
// Thread-local variables generally don't support copy relocations.
|
||||
let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
|
||||
.is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True);
|
||||
let is_thread_local_var = unsafe { llvm::LLVMIsAGlobalVariable(llval) }
|
||||
.is_some_and(|v| unsafe { llvm::LLVMIsThreadLocal(v) } == llvm::True);
|
||||
if is_thread_local_var {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
ar_archive_writer = "0.2.0"
|
||||
ar_archive_writer = "0.3.0"
|
||||
arrayvec = { version = "0.7", default-features = false }
|
||||
bitflags = "2.4.1"
|
||||
cc = "1.0.90"
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use rustc_span::symbol::Symbol;
|
|||
|
||||
use super::metadata::search_for_section;
|
||||
|
||||
pub use ar_archive_writer::get_native_object_symbols;
|
||||
use ar_archive_writer::{write_archive_to_stream, ArchiveKind, NewArchiveMember};
|
||||
pub use ar_archive_writer::{ObjectReader, DEFAULT_OBJECT_READER};
|
||||
use object::read::archive::ArchiveFile;
|
||||
use object::read::macho::FatArch;
|
||||
use tempfile::Builder as TempFileBuilder;
|
||||
|
|
@ -89,8 +89,7 @@ pub trait ArchiveBuilder {
|
|||
#[must_use = "must call build() to finish building the archive"]
|
||||
pub struct ArArchiveBuilder<'a> {
|
||||
sess: &'a Session,
|
||||
get_object_symbols:
|
||||
fn(buf: &[u8], f: &mut dyn FnMut(&[u8]) -> io::Result<()>) -> io::Result<bool>,
|
||||
object_reader: &'static ObjectReader,
|
||||
|
||||
src_archives: Vec<(PathBuf, Mmap)>,
|
||||
// Don't use an `HashMap` here, as the order is important. `lib.rmeta` needs
|
||||
|
|
@ -105,14 +104,8 @@ enum ArchiveEntry {
|
|||
}
|
||||
|
||||
impl<'a> ArArchiveBuilder<'a> {
|
||||
pub fn new(
|
||||
sess: &'a Session,
|
||||
get_object_symbols: fn(
|
||||
buf: &[u8],
|
||||
f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
|
||||
) -> io::Result<bool>,
|
||||
) -> ArArchiveBuilder<'a> {
|
||||
ArArchiveBuilder { sess, get_object_symbols, src_archives: vec![], entries: vec![] }
|
||||
pub fn new(sess: &'a Session, object_reader: &'static ObjectReader) -> ArArchiveBuilder<'a> {
|
||||
ArArchiveBuilder { sess, object_reader, src_archives: vec![], entries: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +260,7 @@ impl<'a> ArArchiveBuilder<'a> {
|
|||
|
||||
entries.push(NewArchiveMember {
|
||||
buf: data,
|
||||
get_symbols: self.get_object_symbols,
|
||||
object_reader: self.object_reader,
|
||||
member_name: String::from_utf8(entry_name).unwrap(),
|
||||
mtime: 0,
|
||||
uid: 0,
|
||||
|
|
@ -294,7 +287,13 @@ impl<'a> ArArchiveBuilder<'a> {
|
|||
let mut archive_tmpfile = File::create_new(&archive_tmpfile_path)
|
||||
.map_err(|err| io_error_context("couldn't create the temp file", err))?;
|
||||
|
||||
write_archive_to_stream(&mut archive_tmpfile, &entries, archive_kind, false)?;
|
||||
write_archive_to_stream(
|
||||
&mut archive_tmpfile,
|
||||
&entries,
|
||||
archive_kind,
|
||||
false,
|
||||
/* is_ec = */ self.sess.target.arch == "arm64ec",
|
||||
)?;
|
||||
|
||||
let any_entries = !entries.is_empty();
|
||||
drop(entries);
|
||||
|
|
|
|||
|
|
@ -750,7 +750,7 @@ fn link_natively(
|
|||
|
||||
for print in &sess.opts.prints {
|
||||
if print.kind == PrintKind::LinkArgs {
|
||||
let content = format!("{cmd:?}");
|
||||
let content = format!("{cmd:?}\n");
|
||||
print.out.overwrite(&content, sess);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
|
|||
B::optimize_fat(cgcx, &mut module)?;
|
||||
Ok(module)
|
||||
}
|
||||
LtoModuleCodegen::Thin(thin) => B::optimize_thin(cgcx, thin),
|
||||
LtoModuleCodegen::Thin(thin) => unsafe { B::optimize_thin(cgcx, thin) },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,13 +37,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
pub fn eval_unevaluated_mir_constant_to_valtree(
|
||||
&self,
|
||||
constant: &mir::ConstOperand<'tcx>,
|
||||
) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
|
||||
) -> Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled> {
|
||||
let uv = match self.monomorphize(constant.const_) {
|
||||
mir::Const::Unevaluated(uv, _) => uv.shrink(),
|
||||
mir::Const::Ty(_, c) => match c.kind() {
|
||||
// A constant that came from a const generic but was then used as an argument to old-style
|
||||
// simd_shuffle (passing as argument instead of as a generic param).
|
||||
rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Some(valtree)),
|
||||
rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)),
|
||||
other => span_bug!(constant.span, "{other:#?}"),
|
||||
},
|
||||
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
|
||||
|
|
@ -70,6 +70,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let val = self
|
||||
.eval_unevaluated_mir_constant_to_valtree(constant)
|
||||
.ok()
|
||||
.map(|x| x.ok())
|
||||
.flatten()
|
||||
.map(|val| {
|
||||
let field_ty = ty.builtin_index().unwrap();
|
||||
|
|
|
|||
|
|
@ -27,15 +27,15 @@ pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value};
|
|||
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
|
||||
const VALTREE_MAX_NODES: usize = 100000;
|
||||
|
||||
pub(crate) enum ValTreeCreationError {
|
||||
pub(crate) enum ValTreeCreationError<'tcx> {
|
||||
NodesOverflow,
|
||||
/// Values of this type, or this particular value, are not supported as valtrees.
|
||||
NonSupportedType,
|
||||
NonSupportedType(Ty<'tcx>),
|
||||
}
|
||||
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
|
||||
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>;
|
||||
|
||||
impl From<InterpErrorInfo<'_>> for ValTreeCreationError {
|
||||
fn from(err: InterpErrorInfo<'_>) -> Self {
|
||||
impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
|
||||
fn from(err: InterpErrorInfo<'tcx>) -> Self {
|
||||
ty::tls::with(|tcx| {
|
||||
bug!(
|
||||
"Unexpected Undefined Behavior error during valtree construction: {}",
|
||||
|
|
|
|||
|
|
@ -120,13 +120,13 @@ fn const_to_valtree_inner<'tcx>(
|
|||
// We could allow wide raw pointers where both sides are integers in the future,
|
||||
// but for now we reject them.
|
||||
if matches!(val.layout.abi, Abi::ScalarPair(..)) {
|
||||
return Err(ValTreeCreationError::NonSupportedType);
|
||||
return Err(ValTreeCreationError::NonSupportedType(ty));
|
||||
}
|
||||
let val = val.to_scalar();
|
||||
// We are in the CTFE machine, so ptr-to-int casts will fail.
|
||||
// This can only be `Ok` if `val` already is an integer.
|
||||
let Ok(val) = val.try_to_scalar_int() else {
|
||||
return Err(ValTreeCreationError::NonSupportedType);
|
||||
return Err(ValTreeCreationError::NonSupportedType(ty));
|
||||
};
|
||||
// It's just a ScalarInt!
|
||||
Ok(ty::ValTree::Leaf(val))
|
||||
|
|
@ -134,7 +134,7 @@ fn const_to_valtree_inner<'tcx>(
|
|||
|
||||
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
|
||||
// agree with runtime equality tests.
|
||||
ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType),
|
||||
ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType(ty)),
|
||||
|
||||
ty::Ref(_, _, _) => {
|
||||
let derefd_place = ecx.deref_pointer(place)?;
|
||||
|
|
@ -148,7 +148,7 @@ fn const_to_valtree_inner<'tcx>(
|
|||
// resolving their backing type, even if we can do that at const eval time. We may
|
||||
// hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future,
|
||||
// but it is unclear if this is useful.
|
||||
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
|
||||
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
|
||||
|
||||
ty::Tuple(elem_tys) => {
|
||||
branches(ecx, place, elem_tys.len(), None, num_nodes)
|
||||
|
|
@ -156,7 +156,7 @@ fn const_to_valtree_inner<'tcx>(
|
|||
|
||||
ty::Adt(def, _) => {
|
||||
if def.is_union() {
|
||||
return Err(ValTreeCreationError::NonSupportedType);
|
||||
return Err(ValTreeCreationError::NonSupportedType(ty));
|
||||
} else if def.variants().is_empty() {
|
||||
bug!("uninhabited types should have errored and never gotten converted to valtree")
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ fn const_to_valtree_inner<'tcx>(
|
|||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
|
||||
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
|
|||
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
|
||||
|
||||
match valtree_result {
|
||||
Ok(valtree) => Ok(Some(valtree)),
|
||||
Ok(valtree) => Ok(Ok(valtree)),
|
||||
Err(err) => {
|
||||
let did = cid.instance.def_id();
|
||||
let global_const_id = cid.display(tcx);
|
||||
|
|
@ -262,7 +262,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
|
|||
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
|
||||
Err(handled.into())
|
||||
}
|
||||
ValTreeCreationError::NonSupportedType => Ok(None),
|
||||
ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -401,15 +401,46 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
(ty::Dynamic(data_a, _, ty::Dyn), ty::Dynamic(data_b, _, ty::Dyn)) => {
|
||||
let val = self.read_immediate(src)?;
|
||||
if data_a.principal() == data_b.principal() {
|
||||
// A NOP cast that doesn't actually change anything, should be allowed even with mismatching vtables.
|
||||
// (But currently mismatching vtables violate the validity invariant so UB is triggered anyway.)
|
||||
return self.write_immediate(*val, dest);
|
||||
}
|
||||
// Take apart the old pointer, and find the dynamic type.
|
||||
let (old_data, old_vptr) = val.to_scalar_pair();
|
||||
let old_data = old_data.to_pointer(self)?;
|
||||
let old_vptr = old_vptr.to_pointer(self)?;
|
||||
let ty = self.get_ptr_vtable_ty(old_vptr, Some(data_a))?;
|
||||
|
||||
// Sanity-check that `supertrait_vtable_slot` in this type's vtable indeed produces
|
||||
// our destination trait.
|
||||
if cfg!(debug_assertions) {
|
||||
let vptr_entry_idx =
|
||||
self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty));
|
||||
let vtable_entries = self.vtable_entries(data_a.principal(), ty);
|
||||
if let Some(entry_idx) = vptr_entry_idx {
|
||||
let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) =
|
||||
vtable_entries.get(entry_idx)
|
||||
else {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"invalid vtable entry index in {} -> {} upcast",
|
||||
src_pointee_ty,
|
||||
dest_pointee_ty
|
||||
);
|
||||
};
|
||||
let erased_trait_ref = upcast_trait_ref
|
||||
.map_bound(|r| ty::ExistentialTraitRef::erase_self_ty(*self.tcx, r));
|
||||
assert!(
|
||||
data_b
|
||||
.principal()
|
||||
.is_some_and(|b| self.eq_in_param_env(erased_trait_ref, b))
|
||||
);
|
||||
} else {
|
||||
// In this case codegen would keep using the old vtable. We don't want to do
|
||||
// that as it has the wrong trait. The reason codegen can do this is that
|
||||
// one vtable is a prefix of the other, so we double-check that.
|
||||
let vtable_entries_b = self.vtable_entries(data_b.principal(), ty);
|
||||
assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b);
|
||||
};
|
||||
}
|
||||
|
||||
// Get the destination trait vtable and return that.
|
||||
let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?;
|
||||
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@ use std::cell::Cell;
|
|||
use std::{fmt, mem};
|
||||
|
||||
use either::{Either, Left, Right};
|
||||
use rustc_infer::infer::at::ToTrace;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use tracing::{debug, info, info_span, instrument, trace};
|
||||
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{
|
||||
CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo,
|
||||
|
|
@ -640,6 +644,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check if the two things are equal in the current param_env, using an infctx to get proper
|
||||
/// equality checks.
|
||||
pub(super) fn eq_in_param_env<T>(&self, a: T, b: T) -> bool
|
||||
where
|
||||
T: PartialEq + TypeFoldable<TyCtxt<'tcx>> + ToTrace<'tcx>,
|
||||
{
|
||||
// Fast path: compare directly.
|
||||
if a == b {
|
||||
return true;
|
||||
}
|
||||
// Slow path: spin up an inference context to check if these traits are sufficiently equal.
|
||||
let infcx = self.tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let cause = ObligationCause::dummy_with_span(self.cur_span());
|
||||
// equate the two trait refs after normalization
|
||||
let a = ocx.normalize(&cause, self.param_env, a);
|
||||
let b = ocx.normalize(&cause, self.param_env, b);
|
||||
if ocx.eq(&cause, self.param_env, a, b).is_ok() {
|
||||
if ocx.select_all_or_error().is_empty() {
|
||||
// All good.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
|
||||
/// frame which is not `#[track_caller]`. This matches the `caller_location` intrinsic,
|
||||
/// and is primarily intended for the panic machinery.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use either::Either;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::trace;
|
||||
|
||||
use rustc_middle::{
|
||||
|
|
@ -867,7 +866,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
};
|
||||
|
||||
// Obtain the underlying trait we are working on, and the adjusted receiver argument.
|
||||
let (dyn_trait, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) =
|
||||
let (trait_, dyn_ty, adjusted_recv) = if let ty::Dynamic(data, _, ty::DynStar) =
|
||||
receiver_place.layout.ty.kind()
|
||||
{
|
||||
let recv = self.unpack_dyn_star(&receiver_place, data)?;
|
||||
|
|
@ -898,20 +897,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
(receiver_trait.principal(), dyn_ty, receiver_place.ptr())
|
||||
};
|
||||
|
||||
// Now determine the actual method to call. We can do that in two different ways and
|
||||
// compare them to ensure everything fits.
|
||||
let vtable_entries = if let Some(dyn_trait) = dyn_trait {
|
||||
let trait_ref = dyn_trait.with_self_ty(*self.tcx, dyn_ty);
|
||||
let trait_ref = self.tcx.erase_regions(trait_ref);
|
||||
self.tcx.vtable_entries(trait_ref)
|
||||
} else {
|
||||
TyCtxt::COMMON_VTABLE_ENTRIES
|
||||
};
|
||||
// Now determine the actual method to call. Usually we use the easy way of just
|
||||
// looking up the method at index `idx`.
|
||||
let vtable_entries = self.vtable_entries(trait_, dyn_ty);
|
||||
let Some(ty::VtblEntry::Method(fn_inst)) = vtable_entries.get(idx).copied() else {
|
||||
// FIXME(fee1-dead) these could be variants of the UB info enum instead of this
|
||||
throw_ub_custom!(fluent::const_eval_dyn_call_not_a_method);
|
||||
};
|
||||
trace!("Virtual call dispatches to {fn_inst:#?}");
|
||||
// We can also do the lookup based on `def_id` and `dyn_ty`, and check that that
|
||||
// produces the same result.
|
||||
if cfg!(debug_assertions) {
|
||||
let tcx = *self.tcx;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,7 @@
|
|||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::mir::interpret::{InterpResult, Pointer};
|
||||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, VtblEntry};
|
||||
use rustc_target::abi::{Align, Size};
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use tracing::trace;
|
||||
|
||||
use super::util::ensure_monomorphic_enough;
|
||||
|
|
@ -47,6 +44,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
Ok((layout.size, layout.align.abi))
|
||||
}
|
||||
|
||||
pub(super) fn vtable_entries(
|
||||
&self,
|
||||
trait_: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
dyn_ty: Ty<'tcx>,
|
||||
) -> &'tcx [VtblEntry<'tcx>] {
|
||||
if let Some(trait_) = trait_ {
|
||||
let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty);
|
||||
let trait_ref = self.tcx.erase_regions(trait_ref);
|
||||
self.tcx.vtable_entries(trait_ref)
|
||||
} else {
|
||||
TyCtxt::COMMON_VTABLE_ENTRIES
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the given vtable trait is valid for a pointer/reference/place with the given
|
||||
/// expected trait type.
|
||||
pub(super) fn check_vtable_for_type(
|
||||
|
|
@ -54,28 +65,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
vtable_trait: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
expected_trait: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// Fast path: if they are equal, it's all fine.
|
||||
if expected_trait.principal() == vtable_trait {
|
||||
return Ok(());
|
||||
let eq = match (expected_trait.principal(), vtable_trait) {
|
||||
(Some(a), Some(b)) => self.eq_in_param_env(a, b),
|
||||
(None, None) => true,
|
||||
_ => false,
|
||||
};
|
||||
if !eq {
|
||||
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
|
||||
}
|
||||
if let (Some(expected_trait), Some(vtable_trait)) =
|
||||
(expected_trait.principal(), vtable_trait)
|
||||
{
|
||||
// Slow path: spin up an inference context to check if these traits are sufficiently equal.
|
||||
let infcx = self.tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
let cause = ObligationCause::dummy_with_span(self.cur_span());
|
||||
// equate the two trait refs after normalization
|
||||
let expected_trait = ocx.normalize(&cause, self.param_env, expected_trait);
|
||||
let vtable_trait = ocx.normalize(&cause, self.param_env, vtable_trait);
|
||||
if ocx.eq(&cause, self.param_env, expected_trait, vtable_trait).is_ok() {
|
||||
if ocx.select_all_or_error().is_empty() {
|
||||
// All good.
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
throw_ub!(InvalidVTableTrait { expected_trait, vtable_trait });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ use super::{
|
|||
Pointer, Projectable, Scalar, ValueVisitor,
|
||||
};
|
||||
|
||||
// for the validation errors
|
||||
use super::InterpError::UndefinedBehavior as Ub;
|
||||
use super::InterpError::Unsupported as Unsup;
|
||||
use super::UndefinedBehaviorInfo::*;
|
||||
|
|
|
|||
|
|
@ -56,5 +56,5 @@ portable-atomic = "1.5.1"
|
|||
|
||||
[features]
|
||||
# tidy-alphabetical-start
|
||||
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon"]
|
||||
rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "dep:rustc-rayon"]
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
Drop was implemented on a trait, which is not allowed: only structs and
|
||||
enums can implement Drop.
|
||||
`Drop` was implemented on a trait object or reference, which is not allowed;
|
||||
only structs, enums, and unions can implement Drop.
|
||||
|
||||
Erroneous code example:
|
||||
Erroneous code examples:
|
||||
|
||||
```compile_fail,E0120
|
||||
trait MyTrait {}
|
||||
|
|
@ -11,8 +11,16 @@ impl Drop for MyTrait {
|
|||
}
|
||||
```
|
||||
|
||||
A workaround for this problem is to wrap the trait up in a struct, and implement
|
||||
Drop on that:
|
||||
```compile_fail,E0120
|
||||
struct Concrete {}
|
||||
|
||||
impl Drop for &'_ mut Concrete {
|
||||
fn drop(&mut self) {}
|
||||
}
|
||||
```
|
||||
|
||||
A workaround for traits is to create a wrapper struct with a generic type,
|
||||
add a trait bound to the type, and implement `Drop` on the wrapper:
|
||||
|
||||
```
|
||||
trait MyTrait {}
|
||||
|
|
@ -24,13 +32,13 @@ impl <T: MyTrait> Drop for MyWrapper<T> {
|
|||
|
||||
```
|
||||
|
||||
Alternatively, wrapping trait objects requires something:
|
||||
Alternatively, the `Drop` wrapper can contain the trait object:
|
||||
|
||||
```
|
||||
trait MyTrait {}
|
||||
|
||||
//or Box<MyTrait>, if you wanted an owned trait object
|
||||
struct MyWrapper<'a> { foo: &'a MyTrait }
|
||||
// or Box<dyn MyTrait>, if you wanted an owned trait object
|
||||
struct MyWrapper<'a> { foo: &'a dyn MyTrait }
|
||||
|
||||
impl <'a> Drop for MyWrapper<'a> {
|
||||
fn drop(&mut self) {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
An associated `const`, `const` parameter or `static` has been referenced
|
||||
in a pattern.
|
||||
A generic parameter or `static` has been referenced in a pattern.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
|
@ -15,25 +14,25 @@ trait Bar {
|
|||
|
||||
fn test<A: Bar>(arg: Foo) {
|
||||
match arg {
|
||||
A::X => println!("A::X"), // error: E0158: associated consts cannot be
|
||||
// referenced in patterns
|
||||
A::X => println!("A::X"), // error: E0158: constant pattern depends
|
||||
// on a generic parameter
|
||||
Foo::Two => println!("Two")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Associated `const`s cannot be referenced in patterns because it is impossible
|
||||
Generic parameters cannot be referenced in patterns because it is impossible
|
||||
for the compiler to prove exhaustiveness (that some pattern will always match).
|
||||
Take the above example, because Rust does type checking in the *generic*
|
||||
method, not the *monomorphized* specific instance. So because `Bar` could have
|
||||
theoretically infinite implementations, there's no way to always be sure that
|
||||
theoretically arbitrary implementations, there's no way to always be sure that
|
||||
`A::X` is `Foo::One`. So this code must be rejected. Even if code can be
|
||||
proven exhaustive by a programmer, the compiler cannot currently prove this.
|
||||
|
||||
The same holds true of `const` parameters and `static`s.
|
||||
The same holds true of `static`s.
|
||||
|
||||
If you want to match against an associated `const`, `const` parameter or
|
||||
`static` consider using a guard instead:
|
||||
If you want to match against a `const` that depends on a generic parameter or a
|
||||
`static`, consider using a guard instead:
|
||||
|
||||
```
|
||||
trait Trait {
|
||||
|
|
|
|||
39
compiler/rustc_error_codes/src/error_codes/E0798.md
Normal file
39
compiler/rustc_error_codes/src/error_codes/E0798.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
Functions marked as `C-cmse-nonsecure-call` place restrictions on their
|
||||
inputs and outputs.
|
||||
|
||||
- inputs must fit in the 4 available 32-bit argument registers. Alignment
|
||||
is relevant.
|
||||
- outputs must either fit in 4 bytes, or be a foundational type of
|
||||
size 8 (`i64`, `u64`, `f64`).
|
||||
- no generics can be used in the signature
|
||||
|
||||
For more information,
|
||||
see [arm's aapcs32](https://github.com/ARM-software/abi-aa/releases).
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```ignore (only fails on supported targets)
|
||||
#![feature(abi_c_cmse_nonsecure_call)]
|
||||
|
||||
#[no_mangle]
|
||||
pub fn test(
|
||||
f: extern "C-cmse-nonsecure-call" fn(u32, u32, u32, u32, u32) -> u32,
|
||||
) -> u32 {
|
||||
f(1, 2, 3, 4, 5)
|
||||
}
|
||||
```
|
||||
|
||||
Arguments' alignment is respected. In the example below, padding is inserted
|
||||
so that the `u64` argument is passed in registers r2 and r3. There is then no
|
||||
room left for the final `f32` argument
|
||||
|
||||
```ignore (only fails on supported targets)
|
||||
#![feature(abi_c_cmse_nonsecure_call)]
|
||||
|
||||
#[no_mangle]
|
||||
pub fn test(
|
||||
f: extern "C-cmse-nonsecure-call" fn(u32, u64, f32) -> u32,
|
||||
) -> u32 {
|
||||
f(1, 2, 3.0)
|
||||
}
|
||||
```
|
||||
|
|
@ -536,6 +536,7 @@ E0794: 0794,
|
|||
E0795: 0795,
|
||||
E0796: 0796,
|
||||
E0797: 0797,
|
||||
E0798: 0798,
|
||||
);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ impl MetaVarExpr {
|
|||
}
|
||||
}
|
||||
|
||||
/// Indicates what is placed in a `concat` parameter. For example, literals
|
||||
/// (`${concat("foo", "bar")}`) or adhoc identifiers (`${concat(foo, bar)}`).
|
||||
#[derive(Debug, Decodable, Encodable, PartialEq)]
|
||||
pub(crate) enum MetaVarExprConcatElem {
|
||||
/// Identifier WITHOUT a preceding dollar sign, which means that this identifier should be
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*};
|
|||
use crate::mbe::metavar_expr::{MetaVarExprConcatElem, RAW_IDENT_ERR};
|
||||
use crate::mbe::{self, KleeneOp, MetaVarExpr};
|
||||
use rustc_ast::mut_visit::{self, MutVisitor};
|
||||
use rustc_ast::token::IdentIsRaw;
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::token::{IdentIsRaw, Lit, LitKind};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::ExprKind;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{pluralize, Diag, DiagCtxtHandle, PResult};
|
||||
use rustc_parse::lexer::nfc_normalize;
|
||||
|
|
@ -17,7 +18,7 @@ use rustc_session::parse::ParseSess;
|
|||
use rustc_session::parse::SymbolGallery;
|
||||
use rustc_span::hygiene::{LocalExpnId, Transparency};
|
||||
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
|
||||
use rustc_span::{with_metavar_spans, Span, SyntaxContext};
|
||||
use rustc_span::{with_metavar_spans, Span, Symbol, SyntaxContext};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::mem;
|
||||
|
||||
|
|
@ -691,12 +692,12 @@ fn transcribe_metavar_expr<'a>(
|
|||
MetaVarExpr::Concat(ref elements) => {
|
||||
let mut concatenated = String::new();
|
||||
for element in elements.into_iter() {
|
||||
let string = match element {
|
||||
MetaVarExprConcatElem::Ident(elem) => elem.to_string(),
|
||||
MetaVarExprConcatElem::Literal(elem) => elem.as_str().into(),
|
||||
MetaVarExprConcatElem::Var(elem) => extract_ident(dcx, *elem, interp)?,
|
||||
let symbol = match element {
|
||||
MetaVarExprConcatElem::Ident(elem) => elem.name,
|
||||
MetaVarExprConcatElem::Literal(elem) => *elem,
|
||||
MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?,
|
||||
};
|
||||
concatenated.push_str(&string);
|
||||
concatenated.push_str(symbol.as_str());
|
||||
}
|
||||
let symbol = nfc_normalize(&concatenated);
|
||||
let concatenated_span = visited_span();
|
||||
|
|
@ -750,32 +751,42 @@ fn transcribe_metavar_expr<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Extracts an identifier that can be originated from a `$var:ident` variable or from a token tree.
|
||||
fn extract_ident<'a>(
|
||||
/// Extracts an metavariable symbol that can be an identifier, a token tree or a literal.
|
||||
fn extract_var_symbol<'a>(
|
||||
dcx: DiagCtxtHandle<'a>,
|
||||
ident: Ident,
|
||||
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
|
||||
) -> PResult<'a, String> {
|
||||
) -> PResult<'a, Symbol> {
|
||||
if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? {
|
||||
if let ParseNtResult::Ident(nt_ident, is_raw) = pnr {
|
||||
if let IdentIsRaw::Yes = is_raw {
|
||||
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
|
||||
}
|
||||
return Ok(nt_ident.to_string());
|
||||
return Ok(nt_ident.name);
|
||||
}
|
||||
if let ParseNtResult::Tt(TokenTree::Token(
|
||||
Token { kind: TokenKind::Ident(token_ident, is_raw), .. },
|
||||
_,
|
||||
)) = pnr
|
||||
{
|
||||
if let IdentIsRaw::Yes = is_raw {
|
||||
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
|
||||
|
||||
if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr {
|
||||
if let TokenKind::Ident(symbol, is_raw) = kind {
|
||||
if let IdentIsRaw::Yes = is_raw {
|
||||
return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR));
|
||||
}
|
||||
return Ok(*symbol);
|
||||
}
|
||||
return Ok(token_ident.to_string());
|
||||
|
||||
if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind {
|
||||
return Ok(*symbol);
|
||||
}
|
||||
}
|
||||
|
||||
if let ParseNtResult::Nt(nt) = pnr
|
||||
&& let Nonterminal::NtLiteral(expr) = &**nt
|
||||
&& let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind
|
||||
{
|
||||
return Ok(*symbol);
|
||||
}
|
||||
}
|
||||
Err(dcx.struct_span_err(
|
||||
ident.span,
|
||||
"`${concat(..)}` currently only accepts identifiers or meta-variables as parameters",
|
||||
))
|
||||
Err(dcx
|
||||
.struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`")
|
||||
.with_note("currently only string literals are supported")
|
||||
.with_span(ident.span))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,13 +228,53 @@ impl<'hir> PathSegment<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A constant that enters the type system, used for arguments to const generics (e.g. array lengths).
|
||||
///
|
||||
/// These are distinct from [`AnonConst`] as anon consts in the type system are not allowed
|
||||
/// to use any generic parameters, therefore we must represent `N` differently. Additionally
|
||||
/// future designs for supporting generic parameters in const arguments will likely not use
|
||||
/// an anon const based design.
|
||||
///
|
||||
/// So, `ConstArg` (specifically, [`ConstArgKind`]) distinguishes between const args
|
||||
/// 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 }`).
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub struct ConstArg<'hir> {
|
||||
pub value: &'hir AnonConst,
|
||||
#[stable_hasher(ignore)]
|
||||
pub hir_id: HirId,
|
||||
pub kind: ConstArgKind<'hir>,
|
||||
/// Indicates whether this comes from a `~const` desugaring.
|
||||
pub is_desugared_from_effects: bool,
|
||||
}
|
||||
|
||||
impl<'hir> ConstArg<'hir> {
|
||||
pub fn anon_const_hir_id(&self) -> Option<HirId> {
|
||||
match self.kind {
|
||||
ConstArgKind::Anon(ac) => Some(ac.hir_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
match self.kind {
|
||||
ConstArgKind::Path(path) => path.span(),
|
||||
ConstArgKind::Anon(anon) => anon.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`ConstArg`].
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub enum ConstArgKind<'hir> {
|
||||
/// **Note:** Currently this is only used for bare const params
|
||||
/// (`N` where `fn foo<const N: usize>(...)`),
|
||||
/// not paths to any const (`N` where `const N: usize = ...`).
|
||||
///
|
||||
/// However, in the future, we'll be using it for all of those.
|
||||
Path(QPath<'hir>),
|
||||
Anon(&'hir AnonConst),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, HashStable_Generic)]
|
||||
pub struct InferArg {
|
||||
pub hir_id: HirId,
|
||||
|
|
@ -251,7 +291,7 @@ impl InferArg {
|
|||
pub enum GenericArg<'hir> {
|
||||
Lifetime(&'hir Lifetime),
|
||||
Type(&'hir Ty<'hir>),
|
||||
Const(ConstArg<'hir>),
|
||||
Const(&'hir ConstArg<'hir>),
|
||||
Infer(InferArg),
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +300,7 @@ impl GenericArg<'_> {
|
|||
match self {
|
||||
GenericArg::Lifetime(l) => l.ident.span,
|
||||
GenericArg::Type(t) => t.span,
|
||||
GenericArg::Const(c) => c.value.span,
|
||||
GenericArg::Const(c) => c.span(),
|
||||
GenericArg::Infer(i) => i.span,
|
||||
}
|
||||
}
|
||||
|
|
@ -269,7 +309,7 @@ impl GenericArg<'_> {
|
|||
match self {
|
||||
GenericArg::Lifetime(l) => l.hir_id,
|
||||
GenericArg::Type(t) => t.hir_id,
|
||||
GenericArg::Const(c) => c.value.hir_id,
|
||||
GenericArg::Const(c) => c.hir_id,
|
||||
GenericArg::Infer(i) => i.hir_id,
|
||||
}
|
||||
}
|
||||
|
|
@ -524,7 +564,7 @@ pub enum GenericParamKind<'hir> {
|
|||
Const {
|
||||
ty: &'hir Ty<'hir>,
|
||||
/// Optional default value for the const generic param
|
||||
default: Option<&'hir AnonConst>,
|
||||
default: Option<&'hir ConstArg<'hir>>,
|
||||
is_host_effect: bool,
|
||||
synthetic: bool,
|
||||
},
|
||||
|
|
@ -1598,13 +1638,13 @@ pub type Lit = Spanned<LitKind>;
|
|||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||
pub enum ArrayLen<'hir> {
|
||||
Infer(InferArg),
|
||||
Body(&'hir AnonConst),
|
||||
Body(&'hir ConstArg<'hir>),
|
||||
}
|
||||
|
||||
impl ArrayLen<'_> {
|
||||
pub fn hir_id(&self) -> HirId {
|
||||
match self {
|
||||
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(AnonConst { hir_id, .. }) => {
|
||||
ArrayLen::Infer(InferArg { hir_id, .. }) | ArrayLen::Body(ConstArg { hir_id, .. }) => {
|
||||
*hir_id
|
||||
}
|
||||
}
|
||||
|
|
@ -2434,7 +2474,7 @@ impl<'hir> AssocItemConstraint<'hir> {
|
|||
}
|
||||
|
||||
/// Obtain the const on the RHS of an assoc const equality constraint if applicable.
|
||||
pub fn ct(self) -> Option<&'hir AnonConst> {
|
||||
pub fn ct(self) -> Option<&'hir ConstArg<'hir>> {
|
||||
match self.kind {
|
||||
AssocItemConstraintKind::Equality { term: Term::Const(ct) } => Some(ct),
|
||||
_ => None,
|
||||
|
|
@ -2445,7 +2485,7 @@ impl<'hir> AssocItemConstraint<'hir> {
|
|||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub enum Term<'hir> {
|
||||
Ty(&'hir Ty<'hir>),
|
||||
Const(&'hir AnonConst),
|
||||
Const(&'hir ConstArg<'hir>),
|
||||
}
|
||||
|
||||
impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
|
||||
|
|
@ -2454,8 +2494,8 @@ impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'hir> From<&'hir AnonConst> for Term<'hir> {
|
||||
fn from(c: &'hir AnonConst) -> Self {
|
||||
impl<'hir> From<&'hir ConstArg<'hir>> for Term<'hir> {
|
||||
fn from(c: &'hir ConstArg<'hir>) -> Self {
|
||||
Term::Const(c)
|
||||
}
|
||||
}
|
||||
|
|
@ -3689,6 +3729,7 @@ pub enum Node<'hir> {
|
|||
Field(&'hir FieldDef<'hir>),
|
||||
AnonConst(&'hir AnonConst),
|
||||
ConstBlock(&'hir ConstBlock),
|
||||
ConstArg(&'hir ConstArg<'hir>),
|
||||
Expr(&'hir Expr<'hir>),
|
||||
ExprField(&'hir ExprField<'hir>),
|
||||
Stmt(&'hir Stmt<'hir>),
|
||||
|
|
@ -3750,6 +3791,7 @@ impl<'hir> Node<'hir> {
|
|||
Node::Param(..)
|
||||
| Node::AnonConst(..)
|
||||
| Node::ConstBlock(..)
|
||||
| Node::ConstArg(..)
|
||||
| Node::Expr(..)
|
||||
| Node::Stmt(..)
|
||||
| Node::Block(..)
|
||||
|
|
@ -3966,7 +4008,7 @@ mod size_asserts {
|
|||
static_assert_size!(FnDecl<'_>, 40);
|
||||
static_assert_size!(ForeignItem<'_>, 72);
|
||||
static_assert_size!(ForeignItemKind<'_>, 40);
|
||||
static_assert_size!(GenericArg<'_>, 24);
|
||||
static_assert_size!(GenericArg<'_>, 16);
|
||||
static_assert_size!(GenericBound<'_>, 48);
|
||||
static_assert_size!(Generics<'_>, 56);
|
||||
static_assert_size!(Impl<'_>, 80);
|
||||
|
|
|
|||
|
|
@ -347,6 +347,9 @@ pub trait Visitor<'v>: Sized {
|
|||
fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result {
|
||||
walk_inline_const(self, c)
|
||||
}
|
||||
fn visit_const_arg(&mut self, c: &'v ConstArg<'v>) -> Self::Result {
|
||||
walk_const_arg(self, c)
|
||||
}
|
||||
fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result {
|
||||
walk_expr(self, ex)
|
||||
}
|
||||
|
|
@ -364,7 +367,7 @@ pub trait Visitor<'v>: Sized {
|
|||
fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
|
||||
walk_generic_param(self, p)
|
||||
}
|
||||
fn visit_const_param_default(&mut self, _param: HirId, ct: &'v AnonConst) -> Self::Result {
|
||||
fn visit_const_param_default(&mut self, _param: HirId, ct: &'v ConstArg<'v>) -> Self::Result {
|
||||
walk_const_param_default(self, ct)
|
||||
}
|
||||
fn visit_generics(&mut self, g: &'v Generics<'v>) -> Self::Result {
|
||||
|
|
@ -708,7 +711,7 @@ pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen<'v>
|
|||
match len {
|
||||
// FIXME: Use `visit_infer` here.
|
||||
ArrayLen::Infer(InferArg { hir_id, span: _ }) => visitor.visit_id(*hir_id),
|
||||
ArrayLen::Body(c) => visitor.visit_anon_const(c),
|
||||
ArrayLen::Body(c) => visitor.visit_const_arg(c),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -725,6 +728,17 @@ pub fn walk_inline_const<'v, V: Visitor<'v>>(
|
|||
visitor.visit_nested_body(constant.body)
|
||||
}
|
||||
|
||||
pub fn walk_const_arg<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
const_arg: &'v ConstArg<'v>,
|
||||
) -> V::Result {
|
||||
try_visit!(visitor.visit_id(const_arg.hir_id));
|
||||
match &const_arg.kind {
|
||||
ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, const_arg.hir_id, qpath.span()),
|
||||
ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result {
|
||||
try_visit!(visitor.visit_id(expression.hir_id));
|
||||
match expression.kind {
|
||||
|
|
@ -928,9 +942,9 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(
|
|||
|
||||
pub fn walk_const_param_default<'v, V: Visitor<'v>>(
|
||||
visitor: &mut V,
|
||||
ct: &'v AnonConst,
|
||||
ct: &'v ConstArg<'v>,
|
||||
) -> V::Result {
|
||||
visitor.visit_anon_const(ct)
|
||||
visitor.visit_const_arg(ct)
|
||||
}
|
||||
|
||||
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) -> V::Result {
|
||||
|
|
@ -1216,7 +1230,7 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>(
|
|||
match generic_arg {
|
||||
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
|
||||
GenericArg::Type(ty) => visitor.visit_ty(ty),
|
||||
GenericArg::Const(ct) => visitor.visit_anon_const(&ct.value),
|
||||
GenericArg::Const(ct) => visitor.visit_const_arg(ct),
|
||||
GenericArg::Infer(inf) => visitor.visit_infer(inf),
|
||||
}
|
||||
}
|
||||
|
|
@ -1278,7 +1292,7 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>(
|
|||
match constraint.kind {
|
||||
AssocItemConstraintKind::Equality { ref term } => match term {
|
||||
Term::Ty(ref ty) => try_visit!(visitor.visit_ty(ty)),
|
||||
Term::Const(ref c) => try_visit!(visitor.visit_anon_const(c)),
|
||||
Term::Const(ref c) => try_visit!(visitor.visit_const_arg(c)),
|
||||
},
|
||||
AssocItemConstraintKind::Bound { bounds } => {
|
||||
walk_list!(visitor, visit_param_bound, bounds)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,23 @@ hir_analysis_cannot_capture_late_bound_ty =
|
|||
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
|
||||
.label = `for<...>` is here
|
||||
|
||||
hir_analysis_cmse_call_generic =
|
||||
function pointers with the `"C-cmse-nonsecure-call"` ABI cannot contain generics in their type
|
||||
|
||||
hir_analysis_cmse_call_inputs_stack_spill =
|
||||
arguments for `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||
.label = {$plural ->
|
||||
[false] this argument doesn't
|
||||
*[true] these arguments don't
|
||||
} fit in the available registers
|
||||
.note = functions with the `"C-cmse-nonsecure-call"` ABI must pass all their arguments via the 4 32-bit available argument registers
|
||||
|
||||
hir_analysis_cmse_call_output_stack_spill =
|
||||
return value of `"C-cmse-nonsecure-call"` function too large to pass via registers
|
||||
.label = this type doesn't fit in the available registers
|
||||
.note1 = functions with the `"C-cmse-nonsecure-call"` ABI must pass their result via the available return registers
|
||||
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
|
||||
|
||||
hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
|
||||
|
||||
hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions
|
||||
|
|
@ -382,6 +399,10 @@ hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is no
|
|||
hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias
|
||||
.label = `Self` is not a generic argument, but an alias to the type of the {$what}
|
||||
|
||||
hir_analysis_recursive_generic_parameter = {$param_def_kind} `{$param_name}` is only used recursively
|
||||
.label = {$param_def_kind} must be used non-recursively in the definition
|
||||
.note = all type parameters must be used in a non-recursive way in order to constrain their variance
|
||||
|
||||
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
|
||||
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
|
||||
|
||||
|
|
@ -515,6 +536,11 @@ hir_analysis_typeof_reserved_keyword_used =
|
|||
.suggestion = consider replacing `typeof(...)` with an actual type
|
||||
.label = reserved keyword
|
||||
|
||||
hir_analysis_unconstrained_generic_parameter = the {$param_def_kind} `{$param_name}` is not constrained by the impl trait, self type, or predicates
|
||||
.label = unconstrained {$param_def_kind}
|
||||
.const_param_note = expressions using a const parameter must map each value to a distinct output value
|
||||
.const_param_note2 = proving the result of expressions other than the parameter are unique is not supported
|
||||
|
||||
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
|
||||
.note = `{$name}` must be used in combination with a concrete type within the same {$what}
|
||||
|
||||
|
|
@ -549,6 +575,8 @@ hir_analysis_unused_generic_parameter =
|
|||
{$param_def_kind} `{$param_name}` is never used
|
||||
.label = unused {$param_def_kind}
|
||||
.const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead
|
||||
.usage_spans = `{$param_name}` is named here, but is likely unused in the containing type
|
||||
|
||||
hir_analysis_unused_generic_parameter_adt_help =
|
||||
consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}`
|
||||
hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
|
||||
|
|
|
|||
|
|
@ -1572,6 +1572,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
|
|||
param_name,
|
||||
param_def_kind: tcx.def_descr(param.def_id),
|
||||
help: errors::UnusedGenericParameterHelp::TyAlias { param_name },
|
||||
usage_spans: vec![],
|
||||
const_param_help,
|
||||
});
|
||||
diag.code(E0091);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir_pretty::qpath_to_string;
|
||||
use rustc_lint_defs::builtin::STATIC_MUT_REFS;
|
||||
use rustc_middle::ty::{Mutability, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
|
@ -12,9 +11,17 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
|
|||
let hir_id = expr.hir_id;
|
||||
if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind
|
||||
&& matches!(borrow_kind, hir::BorrowKind::Ref)
|
||||
&& let Some(var) = path_if_static_mut(tcx, expr)
|
||||
&& path_if_static_mut(expr)
|
||||
{
|
||||
handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id);
|
||||
handle_static_mut_ref(
|
||||
tcx,
|
||||
span,
|
||||
span.with_hi(expr.span.lo()),
|
||||
span.shrink_to_hi(),
|
||||
span.edition().at_least_rust_2024(),
|
||||
m,
|
||||
hir_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -24,12 +31,13 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
|
|||
&& let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
|
||||
&& let hir::ByRef::Yes(rmutbl) = ba.0
|
||||
&& let Some(init) = loc.init
|
||||
&& let Some(var) = path_if_static_mut(tcx, init)
|
||||
&& path_if_static_mut(init)
|
||||
{
|
||||
handle_static_mut_ref(
|
||||
tcx,
|
||||
init.span,
|
||||
var,
|
||||
init.span.shrink_to_lo(),
|
||||
init.span.shrink_to_hi(),
|
||||
loc.span.edition().at_least_rust_2024(),
|
||||
rmutbl,
|
||||
stmt.hir_id,
|
||||
|
|
@ -37,38 +45,39 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> {
|
||||
fn path_if_static_mut(expr: &hir::Expr<'_>) -> bool {
|
||||
if let hir::ExprKind::Path(qpath) = expr.kind
|
||||
&& let hir::QPath::Resolved(_, path) = qpath
|
||||
&& let hir::def::Res::Def(def_kind, _) = path.res
|
||||
&& let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } =
|
||||
def_kind
|
||||
{
|
||||
return Some(qpath_to_string(&tcx, &qpath));
|
||||
return true;
|
||||
}
|
||||
None
|
||||
false
|
||||
}
|
||||
|
||||
fn handle_static_mut_ref(
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
var: String,
|
||||
lo: Span,
|
||||
hi: Span,
|
||||
e2024: bool,
|
||||
mutable: Mutability,
|
||||
hir_id: hir::HirId,
|
||||
) {
|
||||
if e2024 {
|
||||
let (sugg, shared) = if mutable == Mutability::Mut {
|
||||
(errors::StaticMutRefSugg::Mut { span, var }, "mutable")
|
||||
(errors::MutRefSugg::Mut { lo, hi }, "mutable")
|
||||
} else {
|
||||
(errors::StaticMutRefSugg::Shared { span, var }, "shared")
|
||||
(errors::MutRefSugg::Shared { lo, hi }, "shared")
|
||||
};
|
||||
tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared });
|
||||
} else {
|
||||
let (sugg, shared) = if mutable == Mutability::Mut {
|
||||
(errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
|
||||
(errors::MutRefSugg::Mut { lo, hi }, "mutable")
|
||||
} else {
|
||||
(errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
|
||||
(errors::MutRefSugg::Shared { lo, hi }, "shared")
|
||||
};
|
||||
tcx.emit_node_span_lint(
|
||||
STATIC_MUT_REFS,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag};
|
|||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
|
||||
use rustc_infer::error_reporting::infer::ObligationCauseExt as _;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{self, TyCtxtInferExt as _};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
|
|
@ -166,21 +166,42 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
|
|||
return;
|
||||
}
|
||||
|
||||
// For the wasm32 target statics with `#[link_section]` are placed into custom
|
||||
// sections of the final output file, but this isn't link custom sections of
|
||||
// other executable formats. Namely we can only embed a list of bytes,
|
||||
// nothing with provenance (pointers to anything else). If any provenance
|
||||
// show up, reject it here.
|
||||
// For the wasm32 target statics with `#[link_section]` other than `.init_array`
|
||||
// are placed into custom sections of the final output file, but this isn't like
|
||||
// custom sections of other executable formats. Namely we can only embed a list
|
||||
// of bytes, nothing with provenance (pointers to anything else). If any
|
||||
// provenance show up, reject it here.
|
||||
// `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
|
||||
// the consumer's responsibility to ensure all bytes that have been read
|
||||
// have defined values.
|
||||
//
|
||||
// The `.init_array` section is left to go through the normal custom section code path.
|
||||
// When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
|
||||
// in workarounds in user-code.
|
||||
//
|
||||
// * The linker fails to merge multiple items in a crate into the .init_array section.
|
||||
// To work around this, a single array can be used placing multiple items in the array.
|
||||
// #[link_section = ".init_array"]
|
||||
// static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
|
||||
// * Even symbols marked used get gc'd from dependant crates unless at least one symbol
|
||||
// in the crate is marked with an `#[export_name]`
|
||||
//
|
||||
// Once `.init_array` support in wasm-ld is complete, the user code workarounds should
|
||||
// continue to work, but would no longer be necessary.
|
||||
|
||||
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
|
||||
&& alloc.inner().provenance().ptrs().len() != 0
|
||||
{
|
||||
let msg = "statics with a custom `#[link_section]` must be a \
|
||||
if attrs
|
||||
.link_section
|
||||
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
|
||||
.unwrap()
|
||||
{
|
||||
let msg = "statics with a custom `#[link_section]` must be a \
|
||||
simple list of bytes on the wasm target with no \
|
||||
extra levels of indirection such as references";
|
||||
tcx.dcx().span_err(tcx.def_span(id), msg);
|
||||
tcx.dcx().span_err(tcx.def_span(id), msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par
|
|||
use crate::errors;
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
use hir::intravisit::Visitor;
|
||||
use hir::intravisit::{self, Visitor};
|
||||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::ItemKind;
|
||||
|
|
@ -1799,7 +1799,7 @@ fn receiver_is_implemented<'tcx>(
|
|||
|
||||
fn check_variances_for_type_defn<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item: &hir::Item<'tcx>,
|
||||
item: &'tcx hir::Item<'tcx>,
|
||||
hir_generics: &hir::Generics<'tcx>,
|
||||
) {
|
||||
let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id);
|
||||
|
|
@ -1886,21 +1886,21 @@ fn check_variances_for_type_defn<'tcx>(
|
|||
hir::ParamName::Error => {}
|
||||
_ => {
|
||||
let has_explicit_bounds = explicitly_bounded_params.contains(¶meter);
|
||||
report_bivariance(tcx, hir_param, has_explicit_bounds, item.kind);
|
||||
report_bivariance(tcx, hir_param, has_explicit_bounds, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn report_bivariance(
|
||||
tcx: TyCtxt<'_>,
|
||||
param: &rustc_hir::GenericParam<'_>,
|
||||
fn report_bivariance<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param: &'tcx hir::GenericParam<'tcx>,
|
||||
has_explicit_bounds: bool,
|
||||
item_kind: ItemKind<'_>,
|
||||
item: &'tcx hir::Item<'tcx>,
|
||||
) -> ErrorGuaranteed {
|
||||
let param_name = param.name.ident();
|
||||
|
||||
let help = match item_kind {
|
||||
let help = match item.kind {
|
||||
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
|
||||
if let Some(def_id) = tcx.lang_items().phantom_data() {
|
||||
errors::UnusedGenericParameterHelp::Adt {
|
||||
|
|
@ -1915,6 +1915,41 @@ fn report_bivariance(
|
|||
item_kind => bug!("report_bivariance: unexpected item kind: {item_kind:?}"),
|
||||
};
|
||||
|
||||
let mut usage_spans = vec![];
|
||||
intravisit::walk_item(
|
||||
&mut CollectUsageSpans { spans: &mut usage_spans, param_def_id: param.def_id.to_def_id() },
|
||||
item,
|
||||
);
|
||||
|
||||
if !usage_spans.is_empty() {
|
||||
// First, check if the ADT/LTA is (probably) cyclical. We say probably here, since we're
|
||||
// not actually looking into substitutions, just walking through fields / the "RHS".
|
||||
// We don't recurse into the hidden types of opaques or anything else fancy.
|
||||
let item_def_id = item.owner_id.to_def_id();
|
||||
let is_probably_cyclical =
|
||||
IsProbablyCyclical { tcx, item_def_id, seen: Default::default() }
|
||||
.visit_def(item_def_id)
|
||||
.is_break();
|
||||
// If the ADT/LTA is cyclical, then if at least one usage of the type parameter or
|
||||
// the `Self` alias is present in the, then it's probably a cyclical struct/ type
|
||||
// alias, and we should call those parameter usages recursive rather than just saying
|
||||
// they're unused...
|
||||
//
|
||||
// We currently report *all* of the parameter usages, since computing the exact
|
||||
// subset is very involved, and the fact we're mentioning recursion at all is
|
||||
// likely to guide the user in the right direction.
|
||||
if is_probably_cyclical {
|
||||
return tcx.dcx().emit_err(errors::RecursiveGenericParameter {
|
||||
spans: usage_spans,
|
||||
param_span: param.span,
|
||||
param_name,
|
||||
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
|
||||
help,
|
||||
note: (),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let const_param_help =
|
||||
matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds)
|
||||
.then_some(());
|
||||
|
|
@ -1923,6 +1958,7 @@ fn report_bivariance(
|
|||
span: param.span,
|
||||
param_name,
|
||||
param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
|
||||
usage_spans,
|
||||
help,
|
||||
const_param_help,
|
||||
});
|
||||
|
|
@ -1930,6 +1966,86 @@ fn report_bivariance(
|
|||
diag.emit()
|
||||
}
|
||||
|
||||
/// Detects cases where an ADT/LTA is trivially cyclical -- we want to detect this so
|
||||
/// we only mention that its parameters are used cyclically if the ADT/LTA is truly
|
||||
/// cyclical.
|
||||
///
|
||||
/// Notably, we don't consider substitutions here, so this may have false positives.
|
||||
struct IsProbablyCyclical<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
item_def_id: DefId,
|
||||
seen: FxHashSet<DefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> IsProbablyCyclical<'tcx> {
|
||||
fn visit_def(&mut self, def_id: DefId) -> ControlFlow<(), ()> {
|
||||
match self.tcx.def_kind(def_id) {
|
||||
DefKind::Struct | DefKind::Enum | DefKind::Union => {
|
||||
self.tcx.adt_def(def_id).all_fields().try_for_each(|field| {
|
||||
self.tcx.type_of(field.did).instantiate_identity().visit_with(self)
|
||||
})
|
||||
}
|
||||
DefKind::TyAlias if self.tcx.type_alias_is_lazy(def_id) => {
|
||||
self.tcx.type_of(def_id).instantiate_identity().visit_with(self)
|
||||
}
|
||||
_ => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsProbablyCyclical<'tcx> {
|
||||
type Result = ControlFlow<(), ()>;
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
let def_id = match ty.kind() {
|
||||
ty::Adt(adt_def, _) => Some(adt_def.did()),
|
||||
ty::Alias(ty::Weak, alias_ty) => Some(alias_ty.def_id),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(def_id) = def_id {
|
||||
if def_id == self.item_def_id {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
if self.seen.insert(def_id) {
|
||||
self.visit_def(def_id)?;
|
||||
}
|
||||
}
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect usages of the `param_def_id` and `Res::SelfTyAlias` in the HIR.
|
||||
///
|
||||
/// This is used to report places where the user has used parameters in a
|
||||
/// non-variance-constraining way for better bivariance errors.
|
||||
struct CollectUsageSpans<'a> {
|
||||
spans: &'a mut Vec<Span>,
|
||||
param_def_id: DefId,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CollectUsageSpans<'_> {
|
||||
type Result = ();
|
||||
|
||||
fn visit_generics(&mut self, _g: &'tcx rustc_hir::Generics<'tcx>) -> Self::Result {
|
||||
// Skip the generics. We only care about fields, not where clause/param bounds.
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
|
||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, qpath)) = t.kind {
|
||||
if let Res::Def(DefKind::TyParam, def_id) = qpath.res
|
||||
&& def_id == self.param_def_id
|
||||
{
|
||||
self.spans.push(t.span);
|
||||
return;
|
||||
} else if let Res::SelfTyAlias { .. } = qpath.res {
|
||||
self.spans.push(t.span);
|
||||
return;
|
||||
}
|
||||
}
|
||||
intravisit::walk_ty(self, t);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
|
||||
/// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that
|
||||
/// aren't true.
|
||||
|
|
|
|||
|
|
@ -304,7 +304,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
|||
self.tcx.ensure().type_of(param.def_id);
|
||||
if let Some(default) = default {
|
||||
// need to store default and type of default
|
||||
self.tcx.ensure().type_of(default.def_id);
|
||||
if let hir::ConstArgKind::Anon(ac) = default.kind {
|
||||
self.tcx.ensure().type_of(ac.def_id);
|
||||
}
|
||||
self.tcx.ensure().const_param_default(param.def_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_session::lint;
|
|||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
#[instrument(level = "debug", skip(tcx))]
|
||||
#[instrument(level = "debug", skip(tcx), ret)]
|
||||
pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
use rustc_hir::*;
|
||||
|
||||
|
|
@ -102,6 +102,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
None
|
||||
} else if tcx.features().generic_const_exprs {
|
||||
let parent_node = tcx.parent_hir_node(hir_id);
|
||||
debug!(?parent_node);
|
||||
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
|
||||
&& constant.hir_id == hir_id
|
||||
{
|
||||
|
|
@ -164,13 +165,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||
}
|
||||
} else {
|
||||
let parent_node = tcx.parent_hir_node(hir_id);
|
||||
let parent_node = match parent_node {
|
||||
Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
|
||||
_ => parent_node,
|
||||
};
|
||||
match parent_node {
|
||||
// HACK(eddyb) this provides the correct generics for repeat
|
||||
// expressions' count (i.e. `N` in `[x; N]`), and explicit
|
||||
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
|
||||
// as they shouldn't be able to cause query cycle errors.
|
||||
Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
|
||||
if constant.hir_id() == hir_id =>
|
||||
Node::Expr(Expr { kind: ExprKind::Repeat(_, ArrayLen::Body(ct)), .. })
|
||||
if ct.anon_const_hir_id() == Some(hir_id) =>
|
||||
{
|
||||
Some(parent_did)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ fn const_evaluatable_predicates_of(
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::AnonConst) {
|
||||
fn visit_const_param_default(&mut self, _param: HirId, _ct: &'tcx hir::ConstArg<'tcx>) {
|
||||
// Do not look into const param defaults,
|
||||
// these get checked when they are actually instantiated.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -954,7 +954,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
|||
GenericParamKind::Const { ty, default, .. } => {
|
||||
self.visit_ty(ty);
|
||||
if let Some(default) = default {
|
||||
self.visit_body(self.tcx.hir().body(default.body));
|
||||
self.visit_const_arg(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1594,7 +1594,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
|||
i += 1;
|
||||
}
|
||||
GenericArg::Const(ct) => {
|
||||
self.visit_anon_const(&ct.value);
|
||||
self.visit_const_arg(ct);
|
||||
i += 1;
|
||||
}
|
||||
GenericArg::Infer(inf) => {
|
||||
|
|
|
|||
|
|
@ -35,16 +35,32 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
let parent_node_id = tcx.parent_hir_id(hir_id);
|
||||
let parent_node = tcx.hir_node(parent_node_id);
|
||||
|
||||
let (generics, arg_idx) = match parent_node {
|
||||
// Easy case: arrays repeat expressions.
|
||||
Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
|
||||
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
|
||||
if constant.hir_id() == hir_id =>
|
||||
match parent_node {
|
||||
// Anon consts "inside" the type system.
|
||||
Node::ConstArg(&ConstArg {
|
||||
hir_id: arg_hir_id,
|
||||
kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }),
|
||||
..
|
||||
}) if anon_hir_id == hir_id => const_arg_anon_type_of(tcx, arg_hir_id, span),
|
||||
|
||||
// Anon consts outside the type system.
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
|
||||
if asm.operands.iter().any(|(op, _op_sp)| match op {
|
||||
hir::InlineAsmOperand::Const { anon_const }
|
||||
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
|
||||
_ => false,
|
||||
}) =>
|
||||
{
|
||||
return tcx.types.usize;
|
||||
tcx.typeck(def_id).node_type(hir_id)
|
||||
}
|
||||
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
|
||||
tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
|
||||
}
|
||||
// Sort of affects the type system, but only for the purpose of diagnostics
|
||||
// so no need for ConstArg.
|
||||
Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), span, .. }) if e.hir_id == hir_id => {
|
||||
let ty = tcx.typeck(def_id).node_type(e.hir_id);
|
||||
let ty = tcx.typeck(def_id).node_type(tcx.local_def_id_to_hir_id(def_id));
|
||||
let ty = tcx.fold_regions(ty, |r, _| {
|
||||
if r.is_erased() { ty::Region::new_error_misc(tcx) } else { r }
|
||||
});
|
||||
|
|
@ -56,24 +72,35 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg });
|
||||
return ty;
|
||||
}
|
||||
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
|
||||
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
|
||||
if asm.operands.iter().any(|(op, _op_sp)| match op {
|
||||
hir::InlineAsmOperand::Const { anon_const }
|
||||
| hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
|
||||
_ => false,
|
||||
}) =>
|
||||
|
||||
_ => Ty::new_error_with_message(
|
||||
tcx,
|
||||
span,
|
||||
format!("unexpected anon const parent in type_of(): {parent_node:?}"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn const_arg_anon_type_of<'tcx>(tcx: TyCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> {
|
||||
use hir::*;
|
||||
use rustc_middle::ty::Ty;
|
||||
|
||||
let parent_node_id = tcx.parent_hir_id(arg_hir_id);
|
||||
let parent_node = tcx.hir_node(parent_node_id);
|
||||
|
||||
let (generics, arg_idx) = match parent_node {
|
||||
// Easy case: arrays repeat expressions.
|
||||
Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. })
|
||||
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
|
||||
if constant.hir_id() == arg_hir_id =>
|
||||
{
|
||||
return tcx.typeck(def_id).node_type(hir_id);
|
||||
}
|
||||
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
|
||||
return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx);
|
||||
return tcx.types.usize;
|
||||
}
|
||||
Node::GenericParam(&GenericParam {
|
||||
def_id: param_def_id,
|
||||
kind: GenericParamKind::Const { default: Some(ct), .. },
|
||||
..
|
||||
}) if ct.hir_id == hir_id => {
|
||||
}) if ct.hir_id == arg_hir_id => {
|
||||
return tcx
|
||||
.type_of(param_def_id)
|
||||
.no_bound_vars()
|
||||
|
|
@ -104,7 +131,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
// to a ty::Alias(ty::Projection, `<Self as Foo>::Assoc<3>`).
|
||||
let item_def_id = tcx
|
||||
.hir()
|
||||
.parent_owner_iter(hir_id)
|
||||
.parent_owner_iter(arg_hir_id)
|
||||
.find(|(_, node)| matches!(node, OwnerNode::Item(_)))
|
||||
.unwrap()
|
||||
.0
|
||||
|
|
@ -124,7 +151,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
args.args
|
||||
.iter()
|
||||
.filter(|arg| arg.is_ty_or_const())
|
||||
.position(|arg| arg.hir_id() == hir_id)
|
||||
.position(|arg| arg.hir_id() == arg_hir_id)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
bug!("no arg matching AnonConst in segment");
|
||||
|
|
@ -145,7 +172,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
|
||||
..
|
||||
}) => {
|
||||
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
|
||||
let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id);
|
||||
let tables = tcx.typeck(body_owner);
|
||||
// This may fail in case the method/path does not actually exist.
|
||||
// As there is no relevant param for `def_id`, we simply return
|
||||
|
|
@ -163,10 +190,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
args.args
|
||||
.iter()
|
||||
.filter(|arg| arg.is_ty_or_const())
|
||||
.position(|arg| arg.hir_id() == hir_id)
|
||||
.position(|arg| arg.hir_id() == arg_hir_id)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
bug!("no arg matching AnonConst in segment");
|
||||
bug!("no arg matching ConstArg in segment");
|
||||
});
|
||||
|
||||
(tcx.generics_of(type_dependent_def), idx)
|
||||
|
|
@ -185,18 +212,18 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
| ExprKind::Struct(&QPath::Resolved(_, path), ..),
|
||||
..
|
||||
}) => {
|
||||
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
|
||||
let body_owner = tcx.hir().enclosing_body_owner(arg_hir_id);
|
||||
let _tables = tcx.typeck(body_owner);
|
||||
&*path
|
||||
}
|
||||
Node::Pat(pat) => {
|
||||
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
|
||||
if let Some(path) = get_path_containing_arg_in_pat(pat, arg_hir_id) {
|
||||
path
|
||||
} else {
|
||||
return Ty::new_error_with_message(
|
||||
tcx,
|
||||
span,
|
||||
format!("unable to find const parent for {hir_id} in pat {pat:?}"),
|
||||
format!("unable to find const parent for {arg_hir_id} in pat {pat:?}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -217,14 +244,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
args.args
|
||||
.iter()
|
||||
.filter(|arg| arg.is_ty_or_const())
|
||||
.position(|arg| arg.hir_id() == hir_id)
|
||||
.position(|arg| arg.hir_id() == arg_hir_id)
|
||||
.map(|index| (index, seg))
|
||||
.or_else(|| {
|
||||
args.constraints
|
||||
.iter()
|
||||
.copied()
|
||||
.filter_map(AssocItemConstraint::ct)
|
||||
.position(|ct| ct.hir_id == hir_id)
|
||||
.position(|ct| ct.hir_id == arg_hir_id)
|
||||
.map(|idx| (idx, seg))
|
||||
})
|
||||
}) else {
|
||||
|
|
@ -249,7 +276,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
|
|||
return Ty::new_error_with_message(
|
||||
tcx,
|
||||
span,
|
||||
format!("unexpected const parent in type_of(): {parent_node:?}"),
|
||||
format!("unexpected const arg parent in type_of(): {parent_node:?}"),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1500,33 +1500,33 @@ pub struct StaticMutRef<'a> {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: StaticMutRefSugg,
|
||||
pub sugg: MutRefSugg,
|
||||
pub shared: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum StaticMutRefSugg {
|
||||
#[suggestion(
|
||||
pub enum MutRefSugg {
|
||||
#[multipart_suggestion(
|
||||
hir_analysis_suggestion,
|
||||
style = "verbose",
|
||||
code = "addr_of!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Shared {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
#[suggestion_part(code = "addr_of!(")]
|
||||
lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
hi: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
#[multipart_suggestion(
|
||||
hir_analysis_suggestion_mut,
|
||||
style = "verbose",
|
||||
code = "addr_of_mut!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
#[suggestion_part(code = "addr_of_mut!(")]
|
||||
lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
hi: Span,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -1539,36 +1539,10 @@ pub struct RefOfMutStatic<'a> {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: RefOfMutStaticSugg,
|
||||
pub sugg: MutRefSugg,
|
||||
pub shared: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum RefOfMutStaticSugg {
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion,
|
||||
style = "verbose",
|
||||
code = "addr_of!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Shared {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
},
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion_mut,
|
||||
style = "verbose",
|
||||
code = "addr_of_mut!({var})",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
Mut {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
var: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_not_supported_delegation)]
|
||||
pub struct NotSupportedDelegation<'a> {
|
||||
|
|
@ -1597,12 +1571,29 @@ pub(crate) struct UnusedGenericParameter {
|
|||
pub span: Span,
|
||||
pub param_name: Ident,
|
||||
pub param_def_kind: &'static str,
|
||||
#[label(hir_analysis_usage_spans)]
|
||||
pub usage_spans: Vec<Span>,
|
||||
#[subdiagnostic]
|
||||
pub help: UnusedGenericParameterHelp,
|
||||
#[help(hir_analysis_const_param_help)]
|
||||
pub const_param_help: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_recursive_generic_parameter)]
|
||||
pub(crate) struct RecursiveGenericParameter {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
#[label]
|
||||
pub param_span: Span,
|
||||
pub param_name: Ident,
|
||||
pub param_def_kind: &'static str,
|
||||
#[subdiagnostic]
|
||||
pub help: UnusedGenericParameterHelp,
|
||||
#[note]
|
||||
pub note: (),
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum UnusedGenericParameterHelp {
|
||||
#[help(hir_analysis_unused_generic_parameter_adt_help)]
|
||||
|
|
@ -1613,6 +1604,20 @@ pub(crate) enum UnusedGenericParameterHelp {
|
|||
TyAlias { param_name: Ident },
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_unconstrained_generic_parameter)]
|
||||
pub(crate) struct UnconstrainedGenericParameter {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub param_name: Symbol,
|
||||
pub param_def_kind: &'static str,
|
||||
#[note(hir_analysis_const_param_note)]
|
||||
pub const_param_note: Option<()>,
|
||||
#[note(hir_analysis_const_param_note2)]
|
||||
pub const_param_note2: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
pub enum UnnamedFieldsRepr<'a> {
|
||||
#[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)]
|
||||
|
|
@ -1682,3 +1687,30 @@ pub struct InvalidReceiverTy<'tcx> {
|
|||
#[note]
|
||||
#[help]
|
||||
pub struct EffectsWithoutNextSolver;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_cmse_call_inputs_stack_spill, code = E0798)]
|
||||
#[note]
|
||||
pub struct CmseCallInputsStackSpill {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub plural: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_cmse_call_output_stack_spill, code = E0798)]
|
||||
#[note(hir_analysis_note1)]
|
||||
#[note(hir_analysis_note2)]
|
||||
pub struct CmseCallOutputStackSpill {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_cmse_call_generic, code = E0798)]
|
||||
pub struct CmseCallGeneric {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -413,12 +413,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
});
|
||||
|
||||
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
|
||||
if let Some(anon_const) = constraint.ct() {
|
||||
let ty = alias_term
|
||||
.map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
|
||||
let ty =
|
||||
check_assoc_const_binding_type(self, constraint.ident, ty, constraint.hir_id);
|
||||
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
|
||||
if let Some(const_arg) = constraint.ct() {
|
||||
if let hir::ConstArgKind::Anon(anon_const) = const_arg.kind {
|
||||
let ty = alias_term
|
||||
.map_bound(|alias| tcx.type_of(alias.def_id).instantiate(tcx, alias.args));
|
||||
let ty = check_assoc_const_binding_type(
|
||||
self,
|
||||
constraint.ident,
|
||||
ty,
|
||||
constraint.hir_id,
|
||||
);
|
||||
tcx.feed_anon_const_type(anon_const.def_id, ty::EarlyBinder::bind(ty));
|
||||
}
|
||||
}
|
||||
|
||||
alias_term
|
||||
|
|
@ -435,7 +441,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
hir::AssocItemConstraintKind::Equality { term } => {
|
||||
let term = match term {
|
||||
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
|
||||
hir::Term::Const(ct) => ty::Const::from_anon_const(tcx, ct.def_id).into(),
|
||||
hir::Term::Const(ct) => {
|
||||
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No).into()
|
||||
}
|
||||
};
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
|
|
|
|||
156
compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Normal file
156
compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_middle::ty::layout::LayoutError;
|
||||
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
/// Check conditions on inputs and outputs that the cmse ABIs impose: arguments and results MUST be
|
||||
/// returned via registers (i.e. MUST NOT spill to the stack). LLVM will also validate these
|
||||
/// conditions, but by checking them here rustc can emit nicer error messages.
|
||||
pub fn validate_cmse_abi<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
hir_id: HirId,
|
||||
abi: abi::Abi,
|
||||
fn_sig: ty::PolyFnSig<'tcx>,
|
||||
) {
|
||||
if let abi::Abi::CCmseNonSecureCall = abi {
|
||||
let hir_node = tcx.hir_node(hir_id);
|
||||
let hir::Node::Ty(hir::Ty {
|
||||
span: bare_fn_span,
|
||||
kind: hir::TyKind::BareFn(bare_fn_ty),
|
||||
..
|
||||
}) = hir_node
|
||||
else {
|
||||
// might happen when this ABI is used incorrectly. That will be handled elsewhere
|
||||
return;
|
||||
};
|
||||
|
||||
match is_valid_cmse_inputs(tcx, fn_sig) {
|
||||
Ok(Ok(())) => {}
|
||||
Ok(Err(index)) => {
|
||||
// fn(x: u32, u32, u32, u16, y: u16) -> u32,
|
||||
// ^^^^^^
|
||||
let span = bare_fn_ty.param_names[index]
|
||||
.span
|
||||
.to(bare_fn_ty.decl.inputs[index].span)
|
||||
.to(bare_fn_ty.decl.inputs.last().unwrap().span);
|
||||
let plural = bare_fn_ty.param_names.len() - index != 1;
|
||||
dcx.emit_err(errors::CmseCallInputsStackSpill { span, plural });
|
||||
}
|
||||
Err(layout_err) => {
|
||||
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
|
||||
dcx.emit_err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match is_valid_cmse_output(tcx, fn_sig) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
let span = bare_fn_ty.decl.output.span();
|
||||
dcx.emit_err(errors::CmseCallOutputStackSpill { span });
|
||||
}
|
||||
Err(layout_err) => {
|
||||
if let Some(err) = cmse_layout_err(layout_err, *bare_fn_span) {
|
||||
dcx.emit_err(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the inputs will fit into the available registers
|
||||
fn is_valid_cmse_inputs<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Result<Result<(), usize>, &'tcx LayoutError<'tcx>> {
|
||||
let mut span = None;
|
||||
let mut accum = 0u64;
|
||||
|
||||
for (index, arg_def) in fn_sig.inputs().iter().enumerate() {
|
||||
let layout = tcx.layout_of(ParamEnv::reveal_all().and(*arg_def.skip_binder()))?;
|
||||
|
||||
let align = layout.layout.align().abi.bytes();
|
||||
let size = layout.layout.size().bytes();
|
||||
|
||||
accum += size;
|
||||
accum = accum.next_multiple_of(Ord::max(4, align));
|
||||
|
||||
// i.e. exceeds 4 32-bit registers
|
||||
if accum > 16 {
|
||||
span = span.or(Some(index));
|
||||
}
|
||||
}
|
||||
|
||||
match span {
|
||||
None => Ok(Ok(())),
|
||||
Some(span) => Ok(Err(span)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the output will fit into the available registers
|
||||
fn is_valid_cmse_output<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_sig: ty::PolyFnSig<'tcx>,
|
||||
) -> Result<bool, &'tcx LayoutError<'tcx>> {
|
||||
let mut ret_ty = fn_sig.output().skip_binder();
|
||||
let layout = tcx.layout_of(ParamEnv::reveal_all().and(ret_ty))?;
|
||||
let size = layout.layout.size().bytes();
|
||||
|
||||
if size <= 4 {
|
||||
return Ok(true);
|
||||
} else if size > 8 {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// next we need to peel any repr(transparent) layers off
|
||||
'outer: loop {
|
||||
let ty::Adt(adt_def, args) = ret_ty.kind() else {
|
||||
break;
|
||||
};
|
||||
|
||||
if !adt_def.repr().transparent() {
|
||||
break;
|
||||
}
|
||||
|
||||
// the first field with non-trivial size and alignment must be the data
|
||||
for variant_def in adt_def.variants() {
|
||||
for field_def in variant_def.fields.iter() {
|
||||
let ty = field_def.ty(tcx, args);
|
||||
let layout = tcx.layout_of(ParamEnv::reveal_all().and(ty))?;
|
||||
|
||||
if !layout.layout.is_1zst() {
|
||||
ret_ty = ty;
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret_ty == tcx.types.i64 || ret_ty == tcx.types.u64 || ret_ty == tcx.types.f64)
|
||||
}
|
||||
|
||||
fn cmse_layout_err<'tcx>(
|
||||
layout_err: &'tcx LayoutError<'tcx>,
|
||||
span: Span,
|
||||
) -> Option<crate::errors::CmseCallGeneric> {
|
||||
use LayoutError::*;
|
||||
|
||||
match layout_err {
|
||||
Unknown(ty) => {
|
||||
if ty.is_impl_trait() {
|
||||
None // prevent double reporting of this error
|
||||
} else {
|
||||
Some(errors::CmseCallGeneric { span })
|
||||
}
|
||||
}
|
||||
SizeOverflow(..) | NormalizationFailure(..) | ReferencesError(..) | Cycle(..) => {
|
||||
None // not our job to report these
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -340,7 +340,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
{
|
||||
let span = match term {
|
||||
hir::Term::Ty(ty) => ty.span,
|
||||
hir::Term::Const(ct) => tcx.def_span(ct.def_id),
|
||||
hir::Term::Const(ct) => ct.span(),
|
||||
};
|
||||
(span, Some(ident.span), assoc_item.kind, assoc_kind)
|
||||
} else {
|
||||
|
|
@ -1257,14 +1257,12 @@ pub fn prohibit_assoc_item_constraint(
|
|||
};
|
||||
|
||||
// Now emit the suggestion
|
||||
if let Ok(suggestion) = tcx.sess.source_map().span_to_snippet(removal_span) {
|
||||
e.span_suggestion_verbose(
|
||||
removal_span,
|
||||
format!("consider removing this associated item {}", constraint.kind.descr()),
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
e.span_suggestion_verbose(
|
||||
removal_span,
|
||||
format!("consider removing this associated item {}", constraint.kind.descr()),
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
};
|
||||
|
||||
// Suggest replacing the associated item binding with a generic argument.
|
||||
|
|
@ -1296,8 +1294,7 @@ pub fn prohibit_assoc_item_constraint(
|
|||
hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(c) },
|
||||
GenericParamDefKind::Const { .. },
|
||||
) => {
|
||||
let span = tcx.hir().span(c.hir_id);
|
||||
suggest_direct_use(&mut err, span);
|
||||
suggest_direct_use(&mut err, c.span());
|
||||
}
|
||||
(hir::AssocItemConstraintKind::Bound { bounds }, _) => {
|
||||
// Suggest `impl<T: Bound> Trait<T> for Foo` when finding
|
||||
|
|
@ -1340,11 +1337,13 @@ pub fn prohibit_assoc_item_constraint(
|
|||
format!("<{lifetimes}{type_with_constraints}>"),
|
||||
)
|
||||
};
|
||||
let suggestions =
|
||||
vec![param_decl, (constraint.span, format!("{}", matching_param.name))];
|
||||
let suggestions = vec![
|
||||
param_decl,
|
||||
(constraint.span.with_lo(constraint.ident.span.hi()), String::new()),
|
||||
];
|
||||
|
||||
err.multipart_suggestion_verbose(
|
||||
format!("declare the type parameter right after the `impl` keyword"),
|
||||
"declare the type parameter right after the `impl` keyword",
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -113,8 +113,12 @@ fn generic_arg_mismatch_err(
|
|||
}
|
||||
}
|
||||
(GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
|
||||
let body = tcx.hir().body(cnst.value.body);
|
||||
if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind
|
||||
// FIXME(min_generic_const_args): once ConstArgKind::Path is used for non-params too,
|
||||
// this should match against that instead of ::Anon
|
||||
if let hir::ConstArgKind::Anon(anon) = cnst.kind
|
||||
&& let body = tcx.hir().body(anon.body)
|
||||
&& let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) =
|
||||
body.value.kind
|
||||
{
|
||||
if let Res::Def(DefKind::Fn { .. }, id) = path.res {
|
||||
err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
//! trait references and bounds.
|
||||
|
||||
mod bounds;
|
||||
mod cmse;
|
||||
pub mod errors;
|
||||
pub mod generics;
|
||||
mod lint;
|
||||
|
|
@ -471,11 +472,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
handle_ty_args(has_default, &inf.to_ty())
|
||||
}
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
|
||||
let did = ct.value.def_id;
|
||||
tcx.feed_anon_const_type(did, tcx.type_of(param.def_id));
|
||||
ty::Const::from_anon_const(tcx, did).into()
|
||||
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::Param(param.def_id))
|
||||
.into()
|
||||
}
|
||||
(&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => {
|
||||
(&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
|
||||
self.lowerer.ct_infer(Some(param), inf.span).into()
|
||||
}
|
||||
(kind, arg) => span_bug!(
|
||||
|
|
@ -912,7 +912,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let term: ty::Term<'_> = match term {
|
||||
hir::Term::Ty(ty) => self.lower_ty(ty).into(),
|
||||
hir::Term::Const(ct) => {
|
||||
ty::Const::from_anon_const(tcx, ct.def_id).into()
|
||||
ty::Const::from_const_arg(tcx, ct, ty::FeedConstTy::No)
|
||||
.into()
|
||||
}
|
||||
};
|
||||
// FIXME(#97583): This isn't syntactically well-formed!
|
||||
|
|
@ -1087,7 +1088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
);
|
||||
|
||||
let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
|
||||
if let Some(suggested_name) = find_best_match_for_name(
|
||||
if let Some(variant_name) = find_best_match_for_name(
|
||||
&adt_def
|
||||
.variants()
|
||||
.iter()
|
||||
|
|
@ -1095,12 +1096,66 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
.collect::<Vec<Symbol>>(),
|
||||
assoc_ident.name,
|
||||
None,
|
||||
) {
|
||||
err.span_suggestion(
|
||||
assoc_ident.span,
|
||||
) && let Some(variant) =
|
||||
adt_def.variants().iter().find(|s| s.name == variant_name)
|
||||
{
|
||||
let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())];
|
||||
if let hir::Node::Stmt(hir::Stmt {
|
||||
kind: hir::StmtKind::Semi(ref expr),
|
||||
..
|
||||
})
|
||||
| hir::Node::Expr(ref expr) = tcx.parent_hir_node(hir_ref_id)
|
||||
&& let hir::ExprKind::Struct(..) = expr.kind
|
||||
{
|
||||
match variant.ctor {
|
||||
None => {
|
||||
// struct
|
||||
suggestion = vec![(
|
||||
assoc_ident.span.with_hi(expr.span.hi()),
|
||||
if variant.fields.is_empty() {
|
||||
format!("{variant_name} {{}}")
|
||||
} else {
|
||||
format!(
|
||||
"{variant_name} {{ {} }}",
|
||||
variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| format!("{}: /* value */", f.name))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
},
|
||||
)];
|
||||
}
|
||||
Some((hir::def::CtorKind::Fn, def_id)) => {
|
||||
// tuple
|
||||
let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
|
||||
let inputs = fn_sig.inputs().skip_binder();
|
||||
suggestion = vec![(
|
||||
assoc_ident.span.with_hi(expr.span.hi()),
|
||||
format!(
|
||||
"{variant_name}({})",
|
||||
inputs
|
||||
.iter()
|
||||
.map(|i| format!("/* {i} */"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
)];
|
||||
}
|
||||
Some((hir::def::CtorKind::Const, _)) => {
|
||||
// unit
|
||||
suggestion = vec![(
|
||||
assoc_ident.span.with_hi(expr.span.hi()),
|
||||
variant_name.to_string(),
|
||||
)];
|
||||
}
|
||||
}
|
||||
}
|
||||
err.multipart_suggestion_verbose(
|
||||
"there is a variant with a similar name",
|
||||
suggested_name,
|
||||
Applicability::MaybeIncorrect,
|
||||
suggestion,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.span_label(
|
||||
|
|
@ -2140,7 +2195,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let length = match length {
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
|
||||
hir::ArrayLen::Body(constant) => {
|
||||
ty::Const::from_anon_const(tcx, constant.def_id)
|
||||
ty::Const::from_const_arg(tcx, constant, ty::FeedConstTy::No)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -2324,6 +2379,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
|
||||
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
|
||||
|
||||
// reject function types that violate cmse ABI requirements
|
||||
cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, bare_fn_ty);
|
||||
|
||||
// Find any late-bound regions declared in return type that do
|
||||
// not appear in the arguments. These are not well-formed.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@
|
|||
//! specialization errors. These things can (and probably should) be
|
||||
//! fixed, but for the moment it's easier to do these checks early.
|
||||
|
||||
use crate::constrained_generic_params as cgp;
|
||||
use crate::{constrained_generic_params as cgp, errors::UnconstrainedGenericParameter};
|
||||
use min_specialization::check_min_specialization;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{codes::*, struct_span_code_err};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
mod min_specialization;
|
||||
|
||||
|
|
@ -117,43 +117,34 @@ fn enforce_impl_params_are_constrained(
|
|||
|
||||
let mut res = Ok(());
|
||||
for param in &impl_generics.own_params {
|
||||
match param.kind {
|
||||
let err = match param.kind {
|
||||
// Disallow ANY unconstrained type parameters.
|
||||
ty::GenericParamDefKind::Type { .. } => {
|
||||
let param_ty = ty::ParamTy::for_def(param);
|
||||
if !input_parameters.contains(&cgp::Parameter::from(param_ty)) {
|
||||
res = Err(report_unused_parameter(
|
||||
tcx,
|
||||
tcx.def_span(param.def_id),
|
||||
"type",
|
||||
param_ty.name,
|
||||
));
|
||||
}
|
||||
!input_parameters.contains(&cgp::Parameter::from(param_ty))
|
||||
}
|
||||
ty::GenericParamDefKind::Lifetime => {
|
||||
let param_lt = cgp::Parameter::from(param.to_early_bound_region_data());
|
||||
if lifetimes_in_associated_types.contains(¶m_lt) && // (*)
|
||||
lifetimes_in_associated_types.contains(¶m_lt) && // (*)
|
||||
!input_parameters.contains(¶m_lt)
|
||||
{
|
||||
res = Err(report_unused_parameter(
|
||||
tcx,
|
||||
tcx.def_span(param.def_id),
|
||||
"lifetime",
|
||||
param.name,
|
||||
));
|
||||
}
|
||||
}
|
||||
ty::GenericParamDefKind::Const { .. } => {
|
||||
let param_ct = ty::ParamConst::for_def(param);
|
||||
if !input_parameters.contains(&cgp::Parameter::from(param_ct)) {
|
||||
res = Err(report_unused_parameter(
|
||||
tcx,
|
||||
tcx.def_span(param.def_id),
|
||||
"const",
|
||||
param_ct.name,
|
||||
));
|
||||
}
|
||||
!input_parameters.contains(&cgp::Parameter::from(param_ct))
|
||||
}
|
||||
};
|
||||
if err {
|
||||
let const_param_note =
|
||||
matches!(param.kind, ty::GenericParamDefKind::Const { .. }).then_some(());
|
||||
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
|
||||
span: tcx.def_span(param.def_id),
|
||||
param_name: param.name,
|
||||
param_def_kind: tcx.def_descr(param.def_id),
|
||||
const_param_note,
|
||||
const_param_note2: const_param_note,
|
||||
});
|
||||
diag.code(E0207);
|
||||
res = Err(diag.emit());
|
||||
}
|
||||
}
|
||||
res
|
||||
|
|
@ -177,30 +168,3 @@ fn enforce_impl_params_are_constrained(
|
|||
// associated types. I believe this is sound, because lifetimes
|
||||
// used elsewhere are not projected back out.
|
||||
}
|
||||
|
||||
fn report_unused_parameter(
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
kind: &str,
|
||||
name: Symbol,
|
||||
) -> ErrorGuaranteed {
|
||||
let mut err = struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
span,
|
||||
E0207,
|
||||
"the {} parameter `{}` is not constrained by the \
|
||||
impl trait, self type, or predicates",
|
||||
kind,
|
||||
name
|
||||
);
|
||||
err.span_label(span, format!("unconstrained {kind} parameter"));
|
||||
if kind == "const" {
|
||||
err.note(
|
||||
"expressions using a const parameter must map each value to a distinct output value",
|
||||
);
|
||||
err.note(
|
||||
"proving the result of expressions other than the parameter are unique is not supported",
|
||||
);
|
||||
}
|
||||
err.emit()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ use rustc_ast_pretty::pp::{self, Breaks};
|
|||
use rustc_ast_pretty::pprust::{Comments, PrintState};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{
|
||||
BindingMode, ByRef, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId,
|
||||
LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TraitBoundModifier,
|
||||
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
|
||||
HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
|
||||
TraitBoundModifier,
|
||||
};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
|
|
@ -87,6 +88,7 @@ impl<'a> State<'a> {
|
|||
Node::Variant(a) => self.print_variant(a),
|
||||
Node::AnonConst(a) => self.print_anon_const(a),
|
||||
Node::ConstBlock(a) => self.print_inline_const(a),
|
||||
Node::ConstArg(a) => self.print_const_arg(a),
|
||||
Node::Expr(a) => self.print_expr(a),
|
||||
Node::ExprField(a) => self.print_expr_field(a),
|
||||
Node::Stmt(a) => self.print_stmt(a),
|
||||
|
|
@ -983,7 +985,7 @@ impl<'a> State<'a> {
|
|||
fn print_array_length(&mut self, len: &hir::ArrayLen<'_>) {
|
||||
match len {
|
||||
hir::ArrayLen::Infer(..) => self.word("_"),
|
||||
hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
|
||||
hir::ArrayLen::Body(ct) => self.print_const_arg(ct),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -991,6 +993,13 @@ impl<'a> State<'a> {
|
|||
self.ann.nested(self, Nested::Body(constant.body))
|
||||
}
|
||||
|
||||
fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) {
|
||||
match &const_arg.kind {
|
||||
ConstArgKind::Path(qpath) => self.print_qpath(qpath, true),
|
||||
ConstArgKind::Anon(anon) => self.print_anon_const(anon),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_call_post(&mut self, args: &[hir::Expr<'_>]) {
|
||||
self.popen();
|
||||
self.commasep_exprs(Inconsistent, args);
|
||||
|
|
@ -1679,7 +1688,7 @@ impl<'a> State<'a> {
|
|||
GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt),
|
||||
GenericArg::Lifetime(_) => {}
|
||||
GenericArg::Type(ty) => s.print_type(ty),
|
||||
GenericArg::Const(ct) => s.print_anon_const(&ct.value),
|
||||
GenericArg::Const(ct) => s.print_const_arg(ct),
|
||||
GenericArg::Infer(_inf) => s.word("_"),
|
||||
}
|
||||
});
|
||||
|
|
@ -1720,7 +1729,7 @@ impl<'a> State<'a> {
|
|||
self.word_space("=");
|
||||
match term {
|
||||
Term::Ty(ty) => self.print_type(ty),
|
||||
Term::Const(ref c) => self.print_anon_const(c),
|
||||
Term::Const(ref c) => self.print_const_arg(c),
|
||||
}
|
||||
}
|
||||
hir::AssocItemConstraintKind::Bound { bounds } => {
|
||||
|
|
@ -2155,7 +2164,7 @@ impl<'a> State<'a> {
|
|||
if let Some(default) = default {
|
||||
self.space();
|
||||
self.word_space("=");
|
||||
self.print_anon_const(default);
|
||||
self.print_const_arg(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -519,7 +519,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Ty::new_error(tcx, e)
|
||||
}
|
||||
Res::Def(DefKind::Variant, _) => {
|
||||
let e = report_unexpected_variant_res(tcx, res, qpath, expr.span, E0533, "value");
|
||||
let e = report_unexpected_variant_res(
|
||||
tcx,
|
||||
res,
|
||||
Some(expr),
|
||||
qpath,
|
||||
expr.span,
|
||||
E0533,
|
||||
"value",
|
||||
);
|
||||
Ty::new_error(tcx, e)
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -1439,9 +1447,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return;
|
||||
};
|
||||
if let hir::TyKind::Array(_, length) = ty.peel_refs().kind
|
||||
&& let hir::ArrayLen::Body(&hir::AnonConst { hir_id, .. }) = length
|
||||
&& let hir::ArrayLen::Body(ct) = length
|
||||
{
|
||||
let span = self.tcx.hir().span(hir_id);
|
||||
let span = ct.span();
|
||||
self.dcx().try_steal_modify_and_emit_err(
|
||||
span,
|
||||
StashKey::UnderscoreForArrayLengths,
|
||||
|
|
@ -2210,8 +2218,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
);
|
||||
|
||||
let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap();
|
||||
match variant.ctor_kind() {
|
||||
Some(CtorKind::Fn) => match ty.kind() {
|
||||
match variant.ctor {
|
||||
Some((CtorKind::Fn, def_id)) => match ty.kind() {
|
||||
ty::Adt(adt, ..) if adt.is_enum() => {
|
||||
err.span_label(
|
||||
variant_ident_span,
|
||||
|
|
@ -2222,28 +2230,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
),
|
||||
);
|
||||
err.span_label(field.ident.span, "field does not exist");
|
||||
let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
|
||||
let inputs = fn_sig.inputs().skip_binder();
|
||||
let fields = format!(
|
||||
"({})",
|
||||
inputs.iter().map(|i| format!("/* {i} */")).collect::<Vec<_>>().join(", ")
|
||||
);
|
||||
let (replace_span, sugg) = match expr.kind {
|
||||
hir::ExprKind::Struct(qpath, ..) => {
|
||||
(qpath.span().shrink_to_hi().with_hi(expr.span.hi()), fields)
|
||||
}
|
||||
_ => {
|
||||
(expr.span, format!("{ty}::{variant}{fields}", variant = variant.name))
|
||||
}
|
||||
};
|
||||
err.span_suggestion_verbose(
|
||||
expr.span,
|
||||
replace_span,
|
||||
format!(
|
||||
"`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
|
||||
adt = ty,
|
||||
variant = variant.name,
|
||||
),
|
||||
format!(
|
||||
"{adt}::{variant}(/* fields */)",
|
||||
adt = ty,
|
||||
variant = variant.name,
|
||||
),
|
||||
sugg,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
err.span_label(variant_ident_span, format!("`{ty}` defined here"));
|
||||
err.span_label(field.ident.span, "field does not exist");
|
||||
let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
|
||||
let inputs = fn_sig.inputs().skip_binder();
|
||||
let fields = format!(
|
||||
"({})",
|
||||
inputs.iter().map(|i| format!("/* {i} */")).collect::<Vec<_>>().join(", ")
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
expr.span,
|
||||
format!("`{ty}` is a tuple {kind_name}, use the appropriate syntax",),
|
||||
format!("{ty}(/* fields */)"),
|
||||
format!("{ty}{fields}"),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use rustc_hir_analysis::hir_ty_lowering::{
|
|||
GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason,
|
||||
};
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
use rustc_infer::infer::need_type_info::TypeAnnotationNeeded;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
|
||||
use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
|
||||
|
|
@ -457,22 +457,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> {
|
||||
match length {
|
||||
hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span),
|
||||
hir::ArrayLen::Body(anon_const) => {
|
||||
let span = self.tcx.def_span(anon_const.def_id);
|
||||
let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id);
|
||||
hir::ArrayLen::Body(const_arg) => {
|
||||
let span = const_arg.span();
|
||||
let c = ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::No);
|
||||
self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None));
|
||||
self.normalize(span, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_const_arg(&self, hir_ct: &hir::AnonConst, param_def_id: DefId) -> ty::Const<'tcx> {
|
||||
let did = hir_ct.def_id;
|
||||
self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id));
|
||||
let ct = ty::Const::from_anon_const(self.tcx, did);
|
||||
pub fn lower_const_arg(
|
||||
&self,
|
||||
const_arg: &'tcx hir::ConstArg<'tcx>,
|
||||
param_def_id: DefId,
|
||||
) -> ty::Const<'tcx> {
|
||||
let ct =
|
||||
ty::Const::from_const_arg(self.tcx, const_arg, ty::FeedConstTy::Param(param_def_id));
|
||||
self.register_wf_obligation(
|
||||
ct.into(),
|
||||
self.tcx.hir().span(hir_ct.hir_id),
|
||||
self.tcx.hir().span(const_arg.hir_id),
|
||||
ObligationCauseCode::WellFormed(None),
|
||||
);
|
||||
ct
|
||||
|
|
@ -1298,7 +1301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.fcx.lower_ty(ty).raw.into()
|
||||
}
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
|
||||
self.fcx.lower_const_arg(&ct.value, param.def_id).into()
|
||||
self.fcx.lower_const_arg(ct, param.def_id).into()
|
||||
}
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
|
||||
self.fcx.ty_infer(Some(param), inf.span).into()
|
||||
|
|
@ -1519,7 +1522,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
let e = self.tainted_by_errors().unwrap_or_else(|| {
|
||||
self.err_ctxt()
|
||||
.emit_inference_failure_err(self.body_id, sp, ty.into(), E0282, true)
|
||||
.emit_inference_failure_err(
|
||||
self.body_id,
|
||||
sp,
|
||||
ty.into(),
|
||||
TypeAnnotationNeeded::E0282,
|
||||
true,
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
let err = Ty::new_error(self.tcx, e);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
|
|||
use rustc_hir_analysis::check::potentially_plural_count;
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
|
||||
use rustc_infer::error_reporting::infer::{FailureCode, ObligationCauseExt};
|
||||
use rustc_infer::infer::TypeTrace;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
|
|
@ -1105,7 +1105,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
labels.push((provided_span, format!("unexpected argument{provided_ty_name}")));
|
||||
let idx = if provided_arg_tys.len() == 1 {
|
||||
"".to_string()
|
||||
} else {
|
||||
format!(" #{}", arg_idx.as_usize() + 1)
|
||||
};
|
||||
labels.push((
|
||||
provided_span,
|
||||
format!("unexpected argument{idx}{provided_ty_name}"),
|
||||
));
|
||||
let mut span = provided_span;
|
||||
if span.can_be_used_for_suggestions()
|
||||
&& error_span.can_be_used_for_suggestions()
|
||||
|
|
@ -1186,7 +1194,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
labels.push((span, format!("an argument{rendered} is missing")));
|
||||
labels.push((
|
||||
span,
|
||||
format!(
|
||||
"argument #{}{rendered} is missing",
|
||||
expected_idx.as_usize() + 1
|
||||
),
|
||||
));
|
||||
|
||||
suggestion_text = match suggestion_text {
|
||||
SuggestionText::None => SuggestionText::Provide(false),
|
||||
SuggestionText::Provide(_) => SuggestionText::Provide(true),
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ use hir::def_id::CRATE_DEF_ID;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
|
||||
use rustc_infer::error_reporting::infer::sub_relations::SubRelations;
|
||||
use rustc_infer::error_reporting::infer::TypeErrCtxt;
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
|
||||
use rustc_infer::infer::error_reporting::TypeErrCtxt;
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ use crate::expectation::Expectation;
|
|||
use crate::fn_ctxt::LoweredTy;
|
||||
use crate::gather_locals::GatherLocalsVisitor;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
|
||||
use rustc_errors::{codes::*, struct_span_code_err, Applicability, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
|
|
@ -346,6 +346,7 @@ impl<'tcx> EnclosingBreakables<'tcx> {
|
|||
fn report_unexpected_variant_res(
|
||||
tcx: TyCtxt<'_>,
|
||||
res: Res,
|
||||
expr: Option<&hir::Expr<'_>>,
|
||||
qpath: &hir::QPath<'_>,
|
||||
span: Span,
|
||||
err_code: ErrCode,
|
||||
|
|
@ -356,7 +357,7 @@ fn report_unexpected_variant_res(
|
|||
_ => res.descr(),
|
||||
};
|
||||
let path_str = rustc_hir_pretty::qpath_to_string(&tcx, qpath);
|
||||
let err = tcx
|
||||
let mut err = tcx
|
||||
.dcx()
|
||||
.struct_span_err(span, format!("expected {expected}, found {res_descr} `{path_str}`"))
|
||||
.with_code(err_code);
|
||||
|
|
@ -366,6 +367,61 @@ fn report_unexpected_variant_res(
|
|||
err.with_span_label(span, "`fn` calls are not allowed in patterns")
|
||||
.with_help(format!("for more information, visit {patterns_url}"))
|
||||
}
|
||||
Res::Def(DefKind::Variant, _) if let Some(expr) = expr => {
|
||||
err.span_label(span, format!("not a {expected}"));
|
||||
let variant = tcx.expect_variant_res(res);
|
||||
let sugg = if variant.fields.is_empty() {
|
||||
" {}".to_string()
|
||||
} else {
|
||||
format!(
|
||||
" {{ {} }}",
|
||||
variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| format!("{}: /* value */", f.name))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
};
|
||||
let descr = "you might have meant to create a new value of the struct";
|
||||
let mut suggestion = vec![];
|
||||
match tcx.parent_hir_node(expr.hir_id) {
|
||||
hir::Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::Call(..),
|
||||
span: call_span,
|
||||
..
|
||||
}) => {
|
||||
suggestion.push((span.shrink_to_hi().with_hi(call_span.hi()), sugg));
|
||||
}
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(..), hir_id, .. }) => {
|
||||
suggestion.push((expr.span.shrink_to_lo(), "(".to_string()));
|
||||
if let hir::Node::Expr(drop_temps) = tcx.parent_hir_node(*hir_id)
|
||||
&& let hir::ExprKind::DropTemps(_) = drop_temps.kind
|
||||
&& let hir::Node::Expr(parent) = tcx.parent_hir_node(drop_temps.hir_id)
|
||||
&& let hir::ExprKind::If(condition, block, None) = parent.kind
|
||||
&& condition.hir_id == drop_temps.hir_id
|
||||
&& let hir::ExprKind::Block(block, _) = block.kind
|
||||
&& block.stmts.is_empty()
|
||||
&& let Some(expr) = block.expr
|
||||
&& let hir::ExprKind::Path(..) = expr.kind
|
||||
{
|
||||
// Special case: you can incorrectly write an equality condition:
|
||||
// if foo == Struct { field } { /* if body */ }
|
||||
// which should have been written
|
||||
// if foo == (Struct { field }) { /* if body */ }
|
||||
suggestion.push((block.span.shrink_to_hi(), ")".to_string()));
|
||||
} else {
|
||||
suggestion.push((span.shrink_to_hi().with_hi(expr.span.hi()), sugg));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
suggestion.push((span.shrink_to_hi(), sugg));
|
||||
}
|
||||
}
|
||||
|
||||
err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect);
|
||||
err
|
||||
}
|
||||
_ => err.with_span_label(span, format!("not a {expected}")),
|
||||
}
|
||||
.emit()
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
self.cfcx.lower_ty(ty).raw.into()
|
||||
}
|
||||
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
|
||||
self.cfcx.lower_const_arg(&ct.value, param.def_id).into()
|
||||
self.cfcx.lower_const_arg(ct, param.def_id).into()
|
||||
}
|
||||
(GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
|
||||
self.cfcx.ty_infer(Some(param), inf.span).into()
|
||||
|
|
|
|||
|
|
@ -182,8 +182,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self_expr: &'tcx hir::Expr<'tcx>,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
) -> Result<MethodCallee<'tcx>, MethodError<'tcx>> {
|
||||
let pick =
|
||||
self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
|
||||
let scope = if let Some(only_method) = segment.res.opt_def_id() {
|
||||
ProbeScope::Single(only_method)
|
||||
} else {
|
||||
ProbeScope::TraitsInScope
|
||||
};
|
||||
|
||||
let pick = self.lookup_probe(segment.ident, self_ty, call_expr, scope)?;
|
||||
|
||||
self.lint_edition_dependent_dot_call(
|
||||
self_ty, segment, span, call_expr, self_expr, &pick, args,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_hir::HirId;
|
|||
use rustc_hir_analysis::autoderef::{self, Autoderef};
|
||||
use rustc_infer::infer::canonical::OriginalQueryValues;
|
||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
use rustc_infer::infer::need_type_info::TypeAnnotationNeeded;
|
||||
use rustc_infer::infer::DefineOpaqueTypes;
|
||||
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
|
|
@ -20,6 +20,7 @@ use rustc_middle::middle::stability;
|
|||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
|
||||
use rustc_middle::ty::AssocItem;
|
||||
use rustc_middle::ty::AssocItemContainer;
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::Upcast;
|
||||
use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
|
||||
|
|
@ -216,6 +217,9 @@ pub enum Mode {
|
|||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub enum ProbeScope {
|
||||
// Single candidate coming from pre-resolved delegation method.
|
||||
Single(DefId),
|
||||
|
||||
// Assemble candidates coming only from traits in scope.
|
||||
TraitsInScope,
|
||||
|
||||
|
|
@ -441,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.body_id,
|
||||
span,
|
||||
ty.into(),
|
||||
E0282,
|
||||
TypeAnnotationNeeded::E0282,
|
||||
!raw_ptr_call,
|
||||
);
|
||||
if raw_ptr_call {
|
||||
|
|
@ -480,12 +484,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
is_suggestion,
|
||||
);
|
||||
|
||||
probe_cx.assemble_inherent_candidates();
|
||||
match scope {
|
||||
ProbeScope::TraitsInScope => {
|
||||
probe_cx.assemble_extension_candidates_for_traits_in_scope()
|
||||
probe_cx.assemble_inherent_candidates();
|
||||
probe_cx.assemble_extension_candidates_for_traits_in_scope();
|
||||
}
|
||||
ProbeScope::AllTraits => {
|
||||
probe_cx.assemble_inherent_candidates();
|
||||
probe_cx.assemble_extension_candidates_for_all_traits();
|
||||
}
|
||||
ProbeScope::Single(def_id) => {
|
||||
let item = self.tcx.associated_item(def_id);
|
||||
// FIXME(fn_delegation): Delegation to inherent methods is not yet supported.
|
||||
assert_eq!(item.container, AssocItemContainer::TraitContainer);
|
||||
|
||||
let trait_def_id = self.tcx.parent(def_id);
|
||||
let trait_span = self.tcx.def_span(trait_def_id);
|
||||
|
||||
let trait_args = self.fresh_args_for_item(trait_span, trait_def_id);
|
||||
let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, trait_args);
|
||||
|
||||
probe_cx.push_candidate(
|
||||
Candidate {
|
||||
item,
|
||||
kind: CandidateKind::TraitCandidate(ty::Binder::dummy(trait_ref)),
|
||||
import_ids: smallvec![],
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
|
||||
};
|
||||
op(probe_cx)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1596,16 +1596,127 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// that had unsatisfied trait bounds
|
||||
if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
|
||||
let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
|
||||
if let Some(suggestion) = edit_distance::find_best_match_for_name(
|
||||
if let Some(var_name) = edit_distance::find_best_match_for_name(
|
||||
&adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
|
||||
item_name.name,
|
||||
None,
|
||||
) {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
) && let Some(variant) = adt_def.variants().iter().find(|s| s.name == var_name)
|
||||
{
|
||||
let mut suggestion = vec![(span, var_name.to_string())];
|
||||
if let SelfSource::QPath(ty) = source
|
||||
&& let hir::Node::Expr(ref path_expr) = self.tcx.parent_hir_node(ty.hir_id)
|
||||
&& let hir::ExprKind::Path(_) = path_expr.kind
|
||||
&& let hir::Node::Stmt(hir::Stmt {
|
||||
kind: hir::StmtKind::Semi(ref parent), ..
|
||||
})
|
||||
| hir::Node::Expr(ref parent) = self.tcx.parent_hir_node(path_expr.hir_id)
|
||||
{
|
||||
let replacement_span =
|
||||
if let hir::ExprKind::Call(..) | hir::ExprKind::Struct(..) = parent.kind {
|
||||
// We want to replace the parts that need to go, like `()` and `{}`.
|
||||
span.with_hi(parent.span.hi())
|
||||
} else {
|
||||
span
|
||||
};
|
||||
match (variant.ctor, parent.kind) {
|
||||
(None, hir::ExprKind::Struct(..)) => {
|
||||
// We want a struct and we have a struct. We won't suggest changing
|
||||
// the fields (at least for now).
|
||||
suggestion = vec![(span, var_name.to_string())];
|
||||
}
|
||||
(None, _) => {
|
||||
// struct
|
||||
suggestion = vec![(
|
||||
replacement_span,
|
||||
if variant.fields.is_empty() {
|
||||
format!("{var_name} {{}}")
|
||||
} else {
|
||||
format!(
|
||||
"{var_name} {{ {} }}",
|
||||
variant
|
||||
.fields
|
||||
.iter()
|
||||
.map(|f| format!("{}: /* value */", f.name))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
},
|
||||
)];
|
||||
}
|
||||
(Some((hir::def::CtorKind::Const, _)), _) => {
|
||||
// unit, remove the `()`.
|
||||
suggestion = vec![(replacement_span, var_name.to_string())];
|
||||
}
|
||||
(
|
||||
Some((hir::def::CtorKind::Fn, def_id)),
|
||||
hir::ExprKind::Call(rcvr, args),
|
||||
) => {
|
||||
let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
|
||||
let inputs = fn_sig.inputs().skip_binder();
|
||||
// FIXME: reuse the logic for "change args" suggestion to account for types
|
||||
// involved and detect things like substitution.
|
||||
match (inputs, args) {
|
||||
(inputs, []) => {
|
||||
// Add arguments.
|
||||
suggestion.push((
|
||||
rcvr.span.shrink_to_hi().with_hi(parent.span.hi()),
|
||||
format!(
|
||||
"({})",
|
||||
inputs
|
||||
.iter()
|
||||
.map(|i| format!("/* {i} */"))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
),
|
||||
));
|
||||
}
|
||||
(_, [arg]) if inputs.len() != args.len() => {
|
||||
// Replace arguments.
|
||||
suggestion.push((
|
||||
arg.span,
|
||||
inputs
|
||||
.iter()
|
||||
.map(|i| format!("/* {i} */"))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
));
|
||||
}
|
||||
(_, [arg_start, .., arg_end]) if inputs.len() != args.len() => {
|
||||
// Replace arguments.
|
||||
suggestion.push((
|
||||
arg_start.span.to(arg_end.span),
|
||||
inputs
|
||||
.iter()
|
||||
.map(|i| format!("/* {i} */"))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", "),
|
||||
));
|
||||
}
|
||||
// Argument count is the same, keep as is.
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
(Some((hir::def::CtorKind::Fn, def_id)), _) => {
|
||||
let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
|
||||
let inputs = fn_sig.inputs().skip_binder();
|
||||
suggestion = vec![(
|
||||
replacement_span,
|
||||
format!(
|
||||
"{var_name}({})",
|
||||
inputs
|
||||
.iter()
|
||||
.map(|i| format!("/* {i} */"))
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
),
|
||||
)];
|
||||
}
|
||||
}
|
||||
}
|
||||
err.multipart_suggestion_verbose(
|
||||
"there is a variant with a similar name",
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1023,7 +1023,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
|
||||
let expected = "unit struct, unit variant or constant";
|
||||
let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0533, expected);
|
||||
let e =
|
||||
report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0533, expected);
|
||||
return Ty::new_error(tcx, e);
|
||||
}
|
||||
Res::SelfCtor(def_id) => {
|
||||
|
|
@ -1036,6 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let e = report_unexpected_variant_res(
|
||||
tcx,
|
||||
res,
|
||||
None,
|
||||
qpath,
|
||||
pat.span,
|
||||
E0533,
|
||||
|
|
@ -1189,7 +1191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
let report_unexpected_res = |res: Res| {
|
||||
let expected = "tuple struct or tuple variant";
|
||||
let e = report_unexpected_variant_res(tcx, res, qpath, pat.span, E0164, expected);
|
||||
let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
|
||||
on_error(e);
|
||||
e
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_errors::{ErrorGuaranteed, StashKey};
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
use rustc_infer::infer::need_type_info::TypeAnnotationNeeded;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
|
||||
|
|
@ -783,7 +783,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
|
|||
self.fcx.tcx.hir().body_owner_def_id(self.body.id()),
|
||||
self.span.to_span(self.fcx.tcx),
|
||||
p.into(),
|
||||
E0282,
|
||||
TypeAnnotationNeeded::E0282,
|
||||
false,
|
||||
)
|
||||
.emit()
|
||||
|
|
|
|||
|
|
@ -15,5 +15,9 @@ smallvec = "1.8.1"
|
|||
[features]
|
||||
# tidy-alphabetical-start
|
||||
default = ["nightly"]
|
||||
nightly = ["rustc_serialize", "rustc_macros", "rustc_index_macros/nightly"]
|
||||
nightly = [
|
||||
"dep:rustc_serialize",
|
||||
"dep:rustc_macros",
|
||||
"rustc_index_macros/nightly",
|
||||
]
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
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