Auto merge of #3755 - rust-lang:rustup-2024-07-20, r=RalfJung

Automatic Rustup
This commit is contained in:
bors 2024-07-20 05:26:55 +00:00
commit 0c1448d75f
1242 changed files with 21167 additions and 11828 deletions

View file

@ -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"

View file

@ -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

View file

@ -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)

View file

@ -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']

View file

@ -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};

View file

@ -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

View file

@ -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) })
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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",
]

View file

@ -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),
}
}
}

View file

@ -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),

View file

@ -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,

View file

@ -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));

View file

@ -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,
},

View file

@ -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),
}
}))
}

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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,

View file

@ -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(),
);
}
}

View file

@ -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 {

View file

@ -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;

View file

@ -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,

View file

@ -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) });

View file

@ -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(

View file

@ -1 +1,3 @@
version = "Two"
use_small_heuristics = "Max"
merge_derives = false

View file

@ -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" => {

View file

@ -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(())

View file

@ -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(
&[

View file

@ -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)]

View file

@ -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() }
}
}

View file

@ -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(

View file

@ -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")

View file

@ -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) {

View file

@ -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> {

View file

@ -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);

View file

@ -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> {

View file

@ -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");

View file

@ -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();
}

View file

@ -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());
}
}
}

View file

@ -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,

View file

@ -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

View file

@ -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>,

View file

@ -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),
}
}
}

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;
}

View file

@ -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"

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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) },
}
}

View file

@ -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();

View file

@ -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: {}",

View file

@ -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)),
}
}
}

View file

@ -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)
}

View file

@ -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.

View file

@ -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;

View file

@ -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.

View file

@ -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::*;

View file

@ -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

View file

@ -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) {}

View file

@ -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 {

View 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)
}
```

View file

@ -536,6 +536,7 @@ E0794: 0794,
E0795: 0795,
E0796: 0796,
E0797: 0797,
E0798: 0798,
);
)
}

View file

@ -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

View file

@ -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))
}

View file

@ -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);

View file

@ -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)

View file

@ -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 =

View file

@ -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);

View file

@ -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,

View file

@ -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);
}
}
}

View file

@ -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(&parameter);
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.

View file

@ -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);
}
}

View file

@ -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)
}

View file

@ -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.
//

View file

@ -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) => {

View file

@ -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:?}"),
);
}
};

View file

@ -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,
}

View file

@ -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

View 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
}
}
}

View file

@ -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,
);

View file

@ -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)));

View file

@ -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.
//

View file

@ -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(&param_lt) && // (*)
lifetimes_in_associated_types.contains(&param_lt) && // (*)
!input_parameters.contains(&param_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()
}

View file

@ -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);
}
}
}

View file

@ -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,
);
}

View file

@ -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);

View file

@ -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),

View file

@ -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;

View file

@ -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()

View file

@ -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()

View file

@ -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,

View file

@ -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)
})

View file

@ -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,
);
}
}

View file

@ -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
};

View file

@ -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()

View file

@ -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