Merge ref '32e7a4b92b' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: 32e7a4b92b
Filtered ref: d39f3479bfafb04026ed3afec68aa671d13e9c3c

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The rustc-josh-sync Cronjob Bot 2025-07-31 04:17:04 +00:00
commit 7cab27d73a
789 changed files with 13870 additions and 8025 deletions

View file

@ -117,7 +117,7 @@ jobs:
with:
fetch-depth: 2
# Free up disk space on Linux by removing preinstalled components that
# Free up disk space on Linux and Windows by removing preinstalled components that
# we do not need. We do this to enable some of the less resource
# intensive jobs to run on free runners, which however also have
# less disk space.
@ -125,6 +125,13 @@ jobs:
run: src/ci/scripts/free-disk-space.sh
if: matrix.free_disk
# If we don't need to free up disk space then just report how much space we have
- name: print disk usage
run: |
echo "disk usage:"
df -h
if: matrix.free_disk == false
# Rust Log Analyzer can't currently detect the PR number of a GitHub
# Actions build on its own, so a hint in the log message is needed to
# point it in the right direction.

View file

@ -441,20 +441,6 @@ dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "cargo_metadata"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
dependencies = [
"camino",
"cargo-platform 0.1.9",
"semver",
"serde",
"serde_json",
"thiserror 2.0.12",
]
[[package]]
name = "cargo_metadata"
version = "0.21.0"
@ -480,6 +466,8 @@ version = "1.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
dependencies = [
"jobserver",
"libc",
"shlex",
]
@ -669,6 +657,26 @@ dependencies = [
"serde",
]
[[package]]
name = "cmake"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
dependencies = [
"cc",
]
[[package]]
name = "codespan-reporting"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
dependencies = [
"serde",
"termcolor",
"unicode-width 0.2.1",
]
[[package]]
name = "collect-license-metadata"
version = "0.1.0"
@ -927,6 +935,68 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "cxx"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df"
dependencies = [
"cc",
"cxxbridge-cmd",
"cxxbridge-flags",
"cxxbridge-macro",
"foldhash",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909"
dependencies = [
"cc",
"codespan-reporting",
"indexmap",
"proc-macro2",
"quote",
"scratch",
"syn 2.0.104",
]
[[package]]
name = "cxxbridge-cmd"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a"
dependencies = [
"clap",
"codespan-reporting",
"indexmap",
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d"
[[package]]
name = "cxxbridge-macro"
version = "1.0.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4"
dependencies = [
"indexmap",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.104",
]
[[package]]
name = "darling"
version = "0.20.11"
@ -1364,7 +1434,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"askama",
"cargo_metadata 0.18.1",
"cargo_metadata 0.21.0",
"serde",
"serde_json",
"thiserror 1.0.69",
@ -1387,6 +1457,17 @@ dependencies = [
"version_check",
]
[[package]]
name = "genmc-sys"
version = "0.1.0"
dependencies = [
"cc",
"cmake",
"cxx",
"cxx-build",
"git2",
]
[[package]]
name = "getopts"
version = "0.2.23"
@ -1441,6 +1522,21 @@ dependencies = [
"stable_deref_trait",
]
[[package]]
name = "git2"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
dependencies = [
"bitflags",
"libc",
"libgit2-sys",
"log",
"openssl-probe",
"openssl-sys",
"url",
]
[[package]]
name = "glob"
version = "0.3.2"
@ -1890,16 +1986,16 @@ dependencies = [
[[package]]
name = "ipc-channel"
version = "0.20.0"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b1c98b70019c830a1fc39cecfe1f60ff99c4122f0a189697c810c90ec545c14"
checksum = "1700f6b8b9f00cdd675f32fbb3a5be882213140dfe045805273221ca266c43f8"
dependencies = [
"bincode",
"crossbeam-channel",
"fnv",
"libc",
"mio",
"rand 0.9.1",
"rand 0.9.2",
"serde",
"tempfile",
"uuid",
@ -2074,6 +2170,19 @@ dependencies = [
"cc",
]
[[package]]
name = "libgit2-sys"
version = "0.18.2+1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
dependencies = [
"cc",
"libc",
"libz-sys",
"openssl-sys",
"pkg-config",
]
[[package]]
name = "libloading"
version = "0.8.8"
@ -2113,6 +2222,15 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "link-cplusplus"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212"
dependencies = [
"cc",
]
[[package]]
name = "linkchecker"
version = "0.1.0"
@ -2322,6 +2440,7 @@ dependencies = [
"chrono-tz",
"colored 3.0.0",
"directories",
"genmc-sys",
"getrandom 0.3.3",
"ipc-channel",
"libc",
@ -2329,7 +2448,7 @@ dependencies = [
"libloading",
"measureme",
"nix",
"rand 0.9.1",
"rand 0.9.2",
"regex",
"rustc_version",
"serde",
@ -2962,9 +3081,9 @@ dependencies = [
[[package]]
name = "rand"
version = "0.9.1"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
@ -3048,9 +3167,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.13"
version = "0.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
checksum = "7251471db004e509f4e75a62cca9435365b5ec7bcdff530d612ac7c87c44a792"
dependencies = [
"bitflags",
]
@ -3245,7 +3364,7 @@ name = "rustc_abi"
version = "0.0.0"
dependencies = [
"bitflags",
"rand 0.9.1",
"rand 0.9.2",
"rand_xoshiro",
"rustc_data_structures",
"rustc_hashes",
@ -3880,7 +3999,7 @@ dependencies = [
name = "rustc_incremental"
version = "0.0.0"
dependencies = [
"rand 0.9.1",
"rand 0.9.2",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
@ -4493,7 +4612,7 @@ dependencies = [
"bitflags",
"getopts",
"libc",
"rand 0.9.1",
"rand 0.9.2",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
@ -4578,7 +4697,7 @@ dependencies = [
"crossbeam-deque",
"crossbeam-utils",
"libc",
"rand 0.9.1",
"rand 0.9.2",
"rand_xorshift",
"scoped-tls",
"smallvec",
@ -4891,6 +5010,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scratch"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52"
[[package]]
name = "self_cell"
version = "1.2.0"
@ -5284,7 +5409,7 @@ version = "0.1.0"
dependencies = [
"indicatif",
"num",
"rand 0.9.1",
"rand 0.9.2",
"rand_chacha 0.9.0",
"rayon",
]
@ -5370,7 +5495,7 @@ name = "tidy"
version = "0.1.0"
dependencies = [
"build_helper",
"cargo_metadata 0.19.2",
"cargo_metadata 0.21.0",
"fluent-syntax",
"ignore",
"miropt-test-tools",

View file

@ -465,6 +465,11 @@
# What custom diff tool to use for displaying compiletest tests.
#build.compiletest-diff-tool = <none>
# Whether to allow `compiletest` self-tests and `compiletest`-managed test
# suites to be run against the stage 0 rustc. This is only intended to be used
# when the stage 0 compiler is actually built from in-tree sources.
#build.compiletest-allow-stage0 = false
# Whether to use the precompiled stage0 libtest with compiletest.
#build.compiletest-use-stage0-libtest = true
@ -475,6 +480,9 @@
# Note that if any value is manually given to bootstrap such as
# `./x test tidy --extra-checks=js`, this value is ignored.
# Use `--extra-checks=''` to temporarily disable all extra checks.
#
# Automatically enabled in the "tools" profile.
# Set to the empty string to force disable (recommeded for hdd systems).
#build.tidy-extra-checks = ""
# Indicates whether ccache is used when building certain artifacts (e.g. LLVM).

View file

@ -1,3 +1,4 @@
use std::collections::BTreeSet;
use std::fmt::{self, Write};
use std::ops::{Bound, Deref};
use std::{cmp, iter};
@ -5,7 +6,7 @@ use std::{cmp, iter};
use rustc_hashes::Hash64;
use rustc_index::Idx;
use rustc_index::bit_set::BitMatrix;
use tracing::debug;
use tracing::{debug, trace};
use crate::{
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
@ -766,30 +767,63 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
let niche_filling_layout = calculate_niche_filling_layout();
let (mut min, mut max) = (i128::MAX, i128::MIN);
let discr_type = repr.discr_type();
let bits = Integer::from_attr(dl, discr_type).size().bits();
for (i, mut val) in discriminants {
if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) {
continue;
}
if discr_type.is_signed() {
// sign extend the raw representation to be an i128
val = (val << (128 - bits)) >> (128 - bits);
}
if val < min {
min = val;
}
if val > max {
max = val;
}
}
// We might have no inhabited variants, so pretend there's at least one.
if (min, max) == (i128::MAX, i128::MIN) {
min = 0;
max = 0;
}
assert!(min <= max, "discriminant range is {min}...{max}");
let discr_int = Integer::from_attr(dl, discr_type);
// Because we can only represent one range of valid values, we'll look for the
// largest range of invalid values and pick everything else as the range of valid
// values.
// First we need to sort the possible discriminant values so that we can look for the largest gap:
let valid_discriminants: BTreeSet<i128> = discriminants
.filter(|&(i, _)| repr.c() || variants[i].iter().all(|f| !f.is_uninhabited()))
.map(|(_, val)| {
if discr_type.is_signed() {
// sign extend the raw representation to be an i128
// FIXME: do this at the discriminant iterator creation sites
discr_int.size().sign_extend(val as u128)
} else {
val
}
})
.collect();
trace!(?valid_discriminants);
let discriminants = valid_discriminants.iter().copied();
//let next_discriminants = discriminants.clone().cycle().skip(1);
let next_discriminants =
discriminants.clone().chain(valid_discriminants.first().copied()).skip(1);
// Iterate over pairs of each discriminant together with the next one.
// Since they were sorted, we can now compute the niche sizes and pick the largest.
let discriminants = discriminants.zip(next_discriminants);
let largest_niche = discriminants.max_by_key(|&(start, end)| {
trace!(?start, ?end);
// If this is a wraparound range, the niche size is `MAX - abs(diff)`, as the diff between
// the two end points is actually the size of the valid discriminants.
let dist = if start > end {
// Overflow can happen for 128 bit discriminants if `end` is negative.
// But in that case casting to `u128` still gets us the right value,
// as the distance must be positive if the lhs of the subtraction is larger than the rhs.
let dist = start.wrapping_sub(end);
if discr_type.is_signed() {
discr_int.signed_max().wrapping_sub(dist) as u128
} else {
discr_int.size().unsigned_int_max() - dist as u128
}
} else {
// Overflow can happen for 128 bit discriminants if `start` is negative.
// But in that case casting to `u128` still gets us the right value,
// as the distance must be positive if the lhs of the subtraction is larger than the rhs.
end.wrapping_sub(start) as u128
};
trace!(?dist);
dist
});
trace!(?largest_niche);
// `max` is the last valid discriminant before the largest niche
// `min` is the first valid discriminant after the largest niche
let (max, min) = largest_niche
// We might have no inhabited variants, so pretend there's at least one.
.unwrap_or((0, 0));
let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
let mut align = dl.aggregate_align;

View file

@ -1205,6 +1205,19 @@ impl Integer {
}
}
/// Returns the smallest signed value that can be represented by this Integer.
#[inline]
pub fn signed_min(self) -> i128 {
use Integer::*;
match self {
I8 => i8::MIN as i128,
I16 => i16::MIN as i128,
I32 => i32::MIN as i128,
I64 => i64::MIN as i128,
I128 => i128::MIN,
}
}
/// Finds the smallest Integer type which can represent the signed value.
#[inline]
pub fn fit_signed(x: i128) -> Integer {

View file

@ -95,7 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
// Let statements are allowed to have impl trait in bindings.
let super_ = l.super_;
let super_ = l.super_.map(|span| self.lower_span(span));
let ty = l.ty.as_ref().map(|t| {
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
});

View file

@ -282,9 +282,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Field(el, ident) => {
hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
}
ExprKind::Index(el, er, brackets_span) => {
hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
}
ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index(
self.lower_expr(el),
self.lower_expr(er),
self.lower_span(*brackets_span),
),
ExprKind::Range(e1, e2, lims) => {
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
}
@ -334,7 +336,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Struct(se) => {
let rest = match &se.rest {
StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)),
StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp),
StructRest::Rest(sp) => {
hir::StructTailExpr::DefaultFields(self.lower_span(*sp))
}
StructRest::None => hir::StructTailExpr::None,
};
hir::ExprKind::Struct(
@ -678,6 +682,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::Arm { hir_id, pat, guard, body, span }
}
fn lower_capture_clause(&mut self, capture_clause: CaptureBy) -> CaptureBy {
match capture_clause {
CaptureBy::Ref => CaptureBy::Ref,
CaptureBy::Use { use_kw } => CaptureBy::Use { use_kw: self.lower_span(use_kw) },
CaptureBy::Value { move_kw } => CaptureBy::Value { move_kw: self.lower_span(move_kw) },
}
}
/// Lower/desugar a coroutine construct.
///
/// In particular, this creates the correct async resume argument and `_task_context`.
@ -769,7 +781,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
def_id: closure_def_id,
binder: hir::ClosureBinder::Default,
capture_clause,
capture_clause: self.lower_capture_clause(capture_clause),
bound_generic_params: &[],
fn_decl,
body,
@ -1035,7 +1047,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
hir::ExprKind::Use(self.lower_expr(expr), use_kw_span)
hir::ExprKind::Use(self.lower_expr(expr), self.lower_span(use_kw_span))
}
fn lower_expr_closure(
@ -1083,7 +1095,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let c = self.arena.alloc(hir::Closure {
def_id: closure_def_id,
binder: binder_clause,
capture_clause,
capture_clause: self.lower_capture_clause(capture_clause),
bound_generic_params,
fn_decl,
body: body_id,
@ -1197,7 +1209,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let c = self.arena.alloc(hir::Closure {
def_id: closure_def_id,
binder: binder_clause,
capture_clause,
capture_clause: self.lower_capture_clause(capture_clause),
bound_generic_params,
fn_decl,
body,
@ -2101,7 +2113,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> {
let lit = hir::Lit {
span: sp,
span: self.lower_span(sp),
node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)),
};
self.expr(sp, hir::ExprKind::Lit(lit))
@ -2120,7 +2132,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
let lit = hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) };
let lit = hir::Lit {
span: self.lower_span(sp),
node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
};
self.expr(sp, hir::ExprKind::Lit(lit))
}
@ -2206,7 +2221,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc(hir::Path {
span: self.lower_span(span),
res,
segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)],
segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
}),
));

View file

@ -402,6 +402,8 @@ fn expand_format_args<'hir>(
fmt: &FormatArgs,
allow_const: bool,
) -> hir::ExprKind<'hir> {
let macsp = ctx.lower_span(macsp);
let mut incomplete_lit = String::new();
let lit_pieces =
ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {

View file

@ -164,11 +164,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug_assert_eq!(i.owner_id, self.owner);
self.with_parent(i.hir_id(), |this| {
if let ItemKind::Struct(_, _, struct_def) = &i.kind {
if let ItemKind::Struct(_, _, struct_def) = &i.kind
// If this is a tuple or unit-like struct, register the constructor.
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
}
&& let Some(ctor_hir_id) = struct_def.ctor_hir_id()
{
this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
}
intravisit::walk_item(this, i);
});

View file

@ -627,6 +627,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} else {
// For non-empty lists we can just drop all the data, the prefix is already
// present in HIR as a part of nested imports.
let span = self.lower_span(span);
self.arena.alloc(hir::UsePath { res: PerNS::default(), segments: &[], span })
};
hir::ItemKind::Use(path, hir::UseKind::ListStem)
@ -1567,7 +1568,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
attrs: &[hir::Attribute],
) -> hir::FnHeader {
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
hir::IsAsync::Async(span)
hir::IsAsync::Async(self.lower_span(span))
} else {
hir::IsAsync::NotAsync
};
@ -1804,7 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let res = Res::Def(DefKind::TyParam, def_id);
let ident = self.lower_ident(ident);
let ty_path = self.arena.alloc(hir::Path {
span: param_span,
span: self.lower_span(param_span),
res,
segments: self
.arena

View file

@ -2368,7 +2368,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
modifiers: TraitBoundModifiers,
) -> hir::TraitBoundModifiers {
hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity }
let constness = match modifiers.constness {
BoundConstness::Never => BoundConstness::Never,
BoundConstness::Always(span) => BoundConstness::Always(self.lower_span(span)),
BoundConstness::Maybe(span) => BoundConstness::Maybe(self.lower_span(span)),
};
let polarity = match modifiers.polarity {
BoundPolarity::Positive => BoundPolarity::Positive,
BoundPolarity::Negative(span) => BoundPolarity::Negative(self.lower_span(span)),
BoundPolarity::Maybe(span) => BoundPolarity::Maybe(self.lower_span(span)),
};
hir::TraitBoundModifiers { constness, polarity }
}
// Helper methods for building HIR.
@ -2414,6 +2424,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
init: Option<&'hir hir::Expr<'hir>>,
) -> hir::Stmt<'hir> {
let hir_id = self.next_id();
let span = self.lower_span(span);
let local = hir::LetStmt {
super_: Some(span),
hir_id,
@ -2421,7 +2432,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
pat,
els: None,
source: hir::LocalSource::Normal,
span: self.lower_span(span),
span,
ty: None,
};
self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))

View file

@ -640,16 +640,16 @@ impl<'a> AstValidator<'a> {
return;
}
if let Some(header) = fk.header() {
if let Const::Yes(const_span) = header.constness {
let mut spans = variadic_spans.clone();
spans.push(const_span);
self.dcx().emit_err(errors::ConstAndCVariadic {
spans,
const_span,
variadic_spans: variadic_spans.clone(),
});
}
if let Some(header) = fk.header()
&& let Const::Yes(const_span) = header.constness
{
let mut spans = variadic_spans.clone();
spans.push(const_span);
self.dcx().emit_err(errors::ConstAndCVariadic {
spans,
const_span,
variadic_spans: variadic_spans.clone(),
});
}
match (fk.ctxt(), fk.header()) {

View file

@ -630,16 +630,11 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
.iter()
.filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2))
{
if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) {
if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
{
let spans = vec![f1_span, f2_span];
sess.dcx().emit_err(errors::IncompatibleFeatures {
spans,
f1: f1_name,
f2: f2_name,
});
}
if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1)
&& let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
{
let spans = vec![f1_span, f2_span];
sess.dcx().emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
}
}
}

View file

@ -572,10 +572,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
}
fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
if let Some(cmnts) = self.comments_mut() {
if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
self.print_comment(cmnt);
}
if let Some(cmnts) = self.comments_mut()
&& let Some(cmnt) = cmnts.trailing_comment(span, next_pos)
{
self.print_comment(cmnt);
}
}

View file

@ -110,18 +110,10 @@ pub enum DeprecatedSince {
Err,
}
#[derive(
Copy,
Debug,
Eq,
PartialEq,
Encodable,
Decodable,
Clone,
HashStable_Generic,
PrintAttribute
)]
pub enum CoverageStatus {
/// Successfully-parsed value of a `#[coverage(..)]` attribute.
#[derive(Copy, Debug, Eq, PartialEq, Encodable, Decodable, Clone)]
#[derive(HashStable_Generic, PrintAttribute)]
pub enum CoverageAttrKind {
On,
Off,
}
@ -304,8 +296,8 @@ pub enum AttributeKind {
/// Represents `#[const_trait]`.
ConstTrait(Span),
/// Represents `#[coverage]`.
Coverage(Span, CoverageStatus),
/// Represents `#[coverage(..)]`.
Coverage(Span, CoverageAttrKind),
///Represents `#[rustc_deny_explicit_impl]`.
DenyExplicitImpl(Span),
@ -416,12 +408,24 @@ pub enum AttributeKind {
/// Represents `#[pointee]`
Pointee(Span),
/// Represents `#[proc_macro]`
ProcMacro(Span),
/// Represents `#[proc_macro_attribute]`
ProcMacroAttribute(Span),
/// Represents `#[proc_macro_derive]`
ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
PubTransparent(Span),
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
/// Represents `#[rustc_builtin_macro]`.
RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),

View file

@ -61,8 +61,12 @@ impl AttributeKind {
PassByValue(..) => Yes,
Path(..) => No,
Pointee(..) => No,
ProcMacro(..) => No,
ProcMacroAttribute(..) => No,
ProcMacroDerive { .. } => No,
PubTransparent(..) => Yes,
Repr { .. } => No,
RustcBuiltinMacro { .. } => Yes,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcObjectLifetimeDefault => No,

View file

@ -1,4 +1,4 @@
use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
use rustc_attr_data_structures::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy};
use rustc_feature::{AttributeTemplate, template};
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
@ -78,16 +78,16 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
return None;
};
let status = match arg.path().word_sym() {
Some(sym::off) => CoverageStatus::Off,
Some(sym::on) => CoverageStatus::On,
let kind = match arg.path().word_sym() {
Some(sym::off) => CoverageAttrKind::Off,
Some(sym::on) => CoverageAttrKind::On,
None | Some(_) => {
fail_incorrect_argument(arg.span());
return None;
}
};
Some(AttributeKind::Coverage(cx.attr_span, status))
Some(AttributeKind::Coverage(cx.attr_span, kind))
}
}

View file

@ -41,6 +41,7 @@ pub(crate) mod must_use;
pub(crate) mod no_implicit_prelude;
pub(crate) mod non_exhaustive;
pub(crate) mod path;
pub(crate) mod proc_macro_attrs;
pub(crate) mod repr;
pub(crate) mod rustc_internal;
pub(crate) mod semantics;

View file

@ -0,0 +1,139 @@
use rustc_attr_data_structures::AttributeKind;
use rustc_feature::{AttributeTemplate, template};
use rustc_span::{Span, Symbol, sym};
use thin_vec::ThinVec;
use crate::attributes::{
AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
pub(crate) struct ProcMacroParser;
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
const PATH: &[Symbol] = &[sym::proc_macro];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
}
pub(crate) struct ProcMacroAttributeParser;
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
const PATH: &[Symbol] = &[sym::proc_macro_attribute];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
}
pub(crate) struct ProcMacroDeriveParser;
impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
const PATH: &[Symbol] = &[sym::proc_macro_derive];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate =
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
Some(AttributeKind::ProcMacroDerive {
trait_name: trait_name.expect("Trait name is mandatory, so it is present"),
helper_attrs,
span: cx.attr_span,
})
}
}
pub(crate) struct RustcBuiltinMacroParser;
impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate =
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span })
}
}
fn parse_derive_like<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser<'_>,
trait_name_mandatory: bool,
) -> Option<(Option<Symbol>, ThinVec<Symbol>)> {
let Some(list) = args.list() else {
// For #[rustc_builtin_macro], it is permitted to leave out the trait name
if args.no_args().is_ok() && !trait_name_mandatory {
return Some((None, ThinVec::new()));
}
cx.expected_list(cx.attr_span);
return None;
};
let mut items = list.mixed();
// Parse the name of the trait that is derived.
let Some(trait_attr) = items.next() else {
cx.expected_at_least_one_argument(list.span);
return None;
};
let Some(trait_attr) = trait_attr.meta_item() else {
cx.unexpected_literal(trait_attr.span());
return None;
};
let Some(trait_ident) = trait_attr.path().word() else {
cx.expected_identifier(trait_attr.path().span());
return None;
};
if !trait_ident.name.can_be_raw() {
cx.expected_identifier(trait_ident.span);
return None;
}
if let Err(e) = trait_attr.args().no_args() {
cx.expected_no_args(e);
return None;
};
// Parse optional attributes
let mut attributes = ThinVec::new();
if let Some(attrs) = items.next() {
let Some(attr_list) = attrs.meta_item() else {
cx.expected_list(attrs.span());
return None;
};
if !attr_list.path().word_is(sym::attributes) {
cx.expected_specific_argument(attrs.span(), vec!["attributes"]);
return None;
}
let Some(attr_list) = attr_list.args().list() else {
cx.expected_list(attrs.span());
return None;
};
// Parse item in `attributes(...)` argument
for attr in attr_list.mixed() {
let Some(attr) = attr.meta_item() else {
cx.expected_identifier(attr.span());
return None;
};
if let Err(e) = attr.args().no_args() {
cx.expected_no_args(e);
return None;
};
let Some(ident) = attr.path().word() else {
cx.expected_identifier(attr.path().span());
return None;
};
if !ident.name.can_be_raw() {
cx.expected_identifier(ident.span);
return None;
}
attributes.push(ident.name);
}
}
// If anything else is specified, we should reject it
if let Some(next) = items.next() {
cx.expected_no_args(next.span());
}
Some((Some(trait_ident.name), attributes))
}

View file

@ -38,6 +38,9 @@ use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser;
use crate::attributes::path::PathParser as PathAttributeParser;
use crate::attributes::proc_macro_attrs::{
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
};
use crate::attributes::repr::{AlignParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@ -154,6 +157,8 @@ attribute_parsers!(
Single<MustUseParser>,
Single<OptimizeParser>,
Single<PathAttributeParser>,
Single<ProcMacroDeriveParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcForceInlineParser>,
Single<RustcLayoutScalarValidRangeEnd>,
Single<RustcLayoutScalarValidRangeStart>,
@ -186,6 +191,8 @@ attribute_parsers!(
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
Single<WithoutArgs<PointeeParser>>,
Single<WithoutArgs<ProcMacroAttributeParser>>,
Single<WithoutArgs<ProcMacroParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,

View file

@ -2384,7 +2384,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
if let Some(body_expr) = finder.body_expr
&& let Some(loop_span) = finder.loop_span
&& let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id)
&& let Some(trait_did) = tcx.trait_of_item(def_id)
&& let Some(trait_did) = tcx.trait_of_assoc(def_id)
&& tcx.is_diagnostic_item(sym::Iterator, trait_did)
{
if let Some(loop_bind) = finder.loop_bind {
@ -2533,13 +2533,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// Check that the parent of the closure is a method call,
// with receiver matching with local's type (modulo refs)
if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) {
if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
let recv_ty = typeck_results.expr_ty(recv);
if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id)
&& let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind
{
let recv_ty = typeck_results.expr_ty(recv);
if recv_ty.peel_refs() != local_ty {
return;
}
if recv_ty.peel_refs() != local_ty {
return;
}
}
@ -2805,16 +2805,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// With the place of a union and a field access into it, we traverse the second
// borrowed place and look for an access to a different field of the same union.
for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
if let ProjectionElem::Field(field, _) = elem {
if let Some(union_ty) = union_ty(place_base) {
if field != target_field && place_base == target_base {
return Some((
self.describe_any_place(place_base),
self.describe_any_place(first_borrowed_place.as_ref()),
self.describe_any_place(second_borrowed_place.as_ref()),
union_ty.to_string(),
));
}
if let ProjectionElem::Field(field, _) = elem
&& let Some(union_ty) = union_ty(place_base)
{
if field != target_field && place_base == target_base {
return Some((
self.describe_any_place(place_base),
self.describe_any_place(first_borrowed_place.as_ref()),
self.describe_any_place(second_borrowed_place.as_ref()),
union_ty.to_string(),
));
}
}
}
@ -3001,16 +3001,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
from_closure: false,
..
} = explanation
{
if let Err(diag) = self.try_report_cannot_return_reference_to_local(
&& let Err(diag) = self.try_report_cannot_return_reference_to_local(
borrow,
borrow_span,
span,
category,
opt_place_desc.as_ref(),
) {
return diag;
}
)
{
return diag;
}
let name = format!("`{name}`");
@ -3772,30 +3771,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let loan_span = loan_spans.args_or_use();
let descr_place = self.describe_any_place(place.as_ref());
if let BorrowKind::Fake(_) = loan.kind {
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
let mut err = self.cannot_mutate_in_immutable_section(
span,
loan_span,
&descr_place,
section,
"assign",
);
if let BorrowKind::Fake(_) = loan.kind
&& let Some(section) = self.classify_immutable_section(loan.assigned_place)
{
let mut err = self.cannot_mutate_in_immutable_section(
span,
loan_span,
&descr_place,
section,
"assign",
);
loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
BorrowUseInClosure { var_span }
}
loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
use crate::session_diagnostics::CaptureVarCause::*;
match kind {
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
BorrowUseInClosure { var_span }
}
});
}
});
self.buffer_error(err);
self.buffer_error(err);
return;
}
return;
}
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
@ -4048,119 +4047,116 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
target, stmt
);
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
if let Some(assigned_to) = place.as_local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
&& let Some(assigned_to) = place.as_local()
{
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
rvalue={:?}",
assigned_to, rvalue
);
// Check if our `target` was captured by a closure.
if let Rvalue::Aggregate(
box AggregateKind::Closure(def_id, args),
operands,
) = rvalue
{
let def_id = def_id.expect_local();
for operand in operands {
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
operand
else {
continue;
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from
);
assigned_to, rvalue
);
// Check if our `target` was captured by a closure.
if let Rvalue::Aggregate(box AggregateKind::Closure(def_id, args), operands) =
rvalue
{
let def_id = def_id.expect_local();
for operand in operands {
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
operand
else {
continue;
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from
);
// Find the local from the operand.
let Some(assigned_from_local) =
assigned_from.local_or_deref_local()
else {
continue;
};
// Find the local from the operand.
let Some(assigned_from_local) = assigned_from.local_or_deref_local()
else {
continue;
};
if assigned_from_local != target {
continue;
}
// If a closure captured our `target` and then assigned
// into a place then we should annotate the closure in
// case it ends up being assigned into the return place.
annotated_closure =
self.annotate_fn_sig(def_id, args.as_closure().sig());
debug!(
"annotate_argument_and_return_for_borrow: \
annotated_closure={:?} assigned_from_local={:?} \
assigned_to={:?}",
annotated_closure, assigned_from_local, assigned_to
);
if assigned_to == mir::RETURN_PLACE {
// If it was assigned directly into the return place, then
// return now.
return annotated_closure;
} else {
// Otherwise, update the target.
target = assigned_to;
}
if assigned_from_local != target {
continue;
}
// If none of our closure's operands matched, then skip to the next
// statement.
continue;
// If a closure captured our `target` and then assigned
// into a place then we should annotate the closure in
// case it ends up being assigned into the return place.
annotated_closure =
self.annotate_fn_sig(def_id, args.as_closure().sig());
debug!(
"annotate_argument_and_return_for_borrow: \
annotated_closure={:?} assigned_from_local={:?} \
assigned_to={:?}",
annotated_closure, assigned_from_local, assigned_to
);
if assigned_to == mir::RETURN_PLACE {
// If it was assigned directly into the return place, then
// return now.
return annotated_closure;
} else {
// Otherwise, update the target.
target = assigned_to;
}
}
// Otherwise, look at other types of assignment.
let assigned_from = match rvalue {
Rvalue::Ref(_, _, assigned_from) => assigned_from,
Rvalue::Use(operand) => match operand {
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from
}
_ => continue,
},
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from={:?}",
assigned_from,
);
// Find the local from the rvalue.
let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
continue;
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?}",
assigned_from_local,
);
// Check if our local matches the target - if so, we've assigned our
// borrow to a new place.
if assigned_from_local != target {
continue;
}
// If we assigned our `target` into a new place, then we should
// check if it was the return place.
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?} assigned_to={:?}",
assigned_from_local, assigned_to
);
if assigned_to == mir::RETURN_PLACE {
// If it was then return the annotated closure if there was one,
// else, annotate this function.
return annotated_closure.or_else(fallback);
}
// If we didn't assign into the return place, then we just update
// the target.
target = assigned_to;
// If none of our closure's operands matched, then skip to the next
// statement.
continue;
}
// Otherwise, look at other types of assignment.
let assigned_from = match rvalue {
Rvalue::Ref(_, _, assigned_from) => assigned_from,
Rvalue::Use(operand) => match operand {
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
assigned_from
}
_ => continue,
},
_ => continue,
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from={:?}",
assigned_from,
);
// Find the local from the rvalue.
let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
continue;
};
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?}",
assigned_from_local,
);
// Check if our local matches the target - if so, we've assigned our
// borrow to a new place.
if assigned_from_local != target {
continue;
}
// If we assigned our `target` into a new place, then we should
// check if it was the return place.
debug!(
"annotate_argument_and_return_for_borrow: \
assigned_from_local={:?} assigned_to={:?}",
assigned_from_local, assigned_to
);
if assigned_to == mir::RETURN_PLACE {
// If it was then return the annotated closure if there was one,
// else, annotate this function.
return annotated_closure.or_else(fallback);
}
// If we didn't assign into the return place, then we just update
// the target.
target = assigned_to;
}
}
@ -4172,32 +4168,31 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
);
if let TerminatorKind::Call { destination, target: Some(_), args, .. } =
&terminator.kind
&& let Some(assigned_to) = destination.as_local()
{
if let Some(assigned_to) = destination.as_local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
assigned_to, args
);
for operand in args {
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
&operand.node
else {
continue;
};
debug!(
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
assigned_to, args
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from,
);
for operand in args {
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
&operand.node
else {
continue;
};
if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
assigned_from,
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
assigned_from_local,
);
if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
debug!(
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
assigned_from_local,
);
if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
return annotated_closure.or_else(fallback);
}
if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
return annotated_closure.or_else(fallback);
}
}
}
@ -4296,10 +4291,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// as the HIR doesn't have full types for closure arguments.
let return_ty = sig.output().skip_binder();
let mut return_span = fn_decl.output.span();
if let hir::FnRetTy::Return(ty) = &fn_decl.output {
if let hir::TyKind::Ref(lifetime, _) = ty.kind {
return_span = lifetime.ident.span;
}
if let hir::FnRetTy::Return(ty) = &fn_decl.output
&& let hir::TyKind::Ref(lifetime, _) = ty.kind
{
return_span = lifetime.ident.span;
}
Some(AnnotatedBorrowFnSignature::NamedFunction {

View file

@ -341,7 +341,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
let sp = info.span.find_oldest_ancestor_in_same_ctxt();
let sp = info.span.find_ancestor_not_from_macro().unwrap_or(info.span);
if info.tail_result_is_ignored {
// #85581: If the first mutable borrow's scope contains
// the second borrow, this suggestion isn't helpful.
@ -917,30 +917,29 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
if let TerminatorKind::Call { destination, target: Some(block), args, .. } =
&terminator.kind
&& let Some(dest) = destination.as_local()
{
if let Some(dest) = destination.as_local() {
debug!(
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
target, dest, args
);
// Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| {
if let Operand::Move(place) = arg.node {
if let Some(potential) = place.as_local() {
potential == target
} else {
false
}
debug!(
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
target, dest, args
);
// Check if one of the arguments to this function is the target place.
let found_target = args.iter().any(|arg| {
if let Operand::Move(place) = arg.node {
if let Some(potential) = place.as_local() {
potential == target
} else {
false
}
});
// If it is, follow this to the next block and update the target.
if found_target {
target = dest;
queue.push(block.start_location());
} else {
false
}
});
// If it is, follow this to the next block and update the target.
if found_target {
target = dest;
queue.push(block.start_location());
}
}
}

View file

@ -266,48 +266,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
args,
..
} = &terminator.kind
&& let ty::FnDef(id, _) = *const_.ty().kind()
{
if let ty::FnDef(id, _) = *const_.ty().kind() {
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
let closure = match args.first() {
Some(Spanned {
node: Operand::Copy(place) | Operand::Move(place), ..
}) if target == place.local_or_deref_local() => {
place.local_or_deref_local().unwrap()
}
_ => return false,
};
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
let closure = match args.first() {
Some(Spanned { node: Operand::Copy(place) | Operand::Move(place), .. })
if target == place.local_or_deref_local() =>
{
place.local_or_deref_local().unwrap()
}
_ => return false,
};
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.subdiagnostic(OnClosureNote::InvokedTwice {
place_name: &ty::place_to_string_for_capture(
self.infcx.tcx,
hir_place,
),
span: *span,
});
return true;
}
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.subdiagnostic(OnClosureNote::InvokedTwice {
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
span: *span,
});
return true;
}
}
}
}
// Check if we are just moving a closure after it has been invoked.
if let Some(target) = target {
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.subdiagnostic(OnClosureNote::MovedTwice {
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
span: *span,
});
return true;
}
if let Some(target) = target
&& let ty::Closure(did, _) = self.body.local_decls[target].ty.kind()
{
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
diag.subdiagnostic(OnClosureNote::MovedTwice {
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
span: *span,
});
return true;
}
}
false
@ -942,7 +938,7 @@ impl<'tcx> BorrowedContentSource<'tcx> {
fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
match *func.kind() {
ty::FnDef(def_id, args) => {
let trait_id = tcx.trait_of_item(def_id)?;
let trait_id = tcx.trait_of_assoc(def_id)?;
if tcx.is_lang_item(trait_id, LangItem::Deref)
|| tcx.is_lang_item(trait_id, LangItem::DerefMut)

View file

@ -126,36 +126,35 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
.statements
.get(location.statement_index)
.map(|stmt| &stmt.kind)
&& let Some(local) = place.as_local()
{
if let Some(local) = place.as_local() {
let local_decl = &self.body.local_decls[local];
// opt_match_place is the
// match_span is the span of the expression being matched on
// match *x.y { ... } match_place is Some(*x.y)
// ^^^^ match_span is the span of *x.y
//
// opt_match_place is None for let [mut] x = ... statements,
// whether or not the right-hand side is a place expression
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
opt_match_place: Some((opt_match_place, match_span)),
binding_mode: _,
opt_ty_info: _,
pat_span: _,
})) = *local_decl.local_info()
{
let stmt_source_info = self.body.source_info(location);
self.append_binding_error(
grouped_errors,
kind,
original_path,
*move_from,
local,
opt_match_place,
match_span,
stmt_source_info.span,
);
return;
}
let local_decl = &self.body.local_decls[local];
// opt_match_place is the
// match_span is the span of the expression being matched on
// match *x.y { ... } match_place is Some(*x.y)
// ^^^^ match_span is the span of *x.y
//
// opt_match_place is None for let [mut] x = ... statements,
// whether or not the right-hand side is a place expression
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
opt_match_place: Some((opt_match_place, match_span)),
binding_mode: _,
opt_ty_info: _,
pat_span: _,
})) = *local_decl.local_info()
{
let stmt_source_info = self.body.source_info(location);
self.append_binding_error(
grouped_errors,
kind,
original_path,
*move_from,
local,
opt_match_place,
match_span,
stmt_source_info.span,
);
return;
}
}

View file

@ -682,7 +682,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
let my_def = self.body.source.def_id();
let Some(td) =
self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
else {
return (false, false, None);
};
@ -880,7 +880,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let opt_suggestions = tcx
.typeck(path_segment.hir_id.owner.def_id)
.type_dependent_def_id(expr.hir_id)
.and_then(|def_id| tcx.impl_of_method(def_id))
.and_then(|def_id| tcx.impl_of_assoc(def_id))
.map(|def_id| tcx.associated_items(def_id))
.map(|assoc_items| {
assoc_items
@ -1056,7 +1056,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
.tcx
.typeck(path_segment.hir_id.owner.def_id)
.type_dependent_def_id(cur_expr.hir_id)
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
.and_then(|def_id| self.infcx.tcx.impl_of_assoc(def_id))
.map(|def_id| self.infcx.tcx.associated_items(def_id))
.map(|assoc_items| {
assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()

View file

@ -528,15 +528,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
// match_adt_and_segment in this case.
Res::Def(DefKind::TyAlias, _) => (),
_ => {
if let Some(last_segment) = path.segments.last() {
if let Some(highlight) = self.match_adt_and_segment(
if let Some(last_segment) = path.segments.last()
&& let Some(highlight) = self.match_adt_and_segment(
args,
needle_fr,
last_segment,
search_stack,
) {
return Some(highlight);
}
)
{
return Some(highlight);
}
}
}

View file

@ -822,10 +822,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
continue;
}
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
continue;
}
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements
&& self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements)
{
continue;
}
// Type-test failed. Report the error.
@ -1479,40 +1479,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
shorter_fr: RegionVid,
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
) -> RegionRelationCheckResult {
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements
// Shrink `longer_fr` until we find a non-local region (if we do).
// We'll call it `fr-` -- it's ever so slightly smaller than
// `longer_fr`.
if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
{
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
&& let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
{
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
let blame_span_category = self.find_outlives_blame_span(
longer_fr,
NllRegionVariableOrigin::FreeRegion,
shorter_fr,
);
let blame_span_category = self.find_outlives_blame_span(
longer_fr,
NllRegionVariableOrigin::FreeRegion,
shorter_fr,
);
// Grow `shorter_fr` until we find some non-local regions. (We
// always will.) We'll call them `shorter_fr+` -- they're ever
// so slightly larger than `shorter_fr`.
let shorter_fr_plus =
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
debug!(
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
shorter_fr_plus
);
for fr in shorter_fr_plus {
// Push the constraint `fr-: shorter_fr+`
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject: ClosureOutlivesSubject::Region(fr_minus),
outlived_free_region: fr,
blame_span: blame_span_category.1.span,
category: blame_span_category.0,
});
}
return RegionRelationCheckResult::Propagated;
// Grow `shorter_fr` until we find some non-local regions. (We
// always will.) We'll call them `shorter_fr+` -- they're ever
// so slightly larger than `shorter_fr`.
let shorter_fr_plus =
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
for fr in shorter_fr_plus {
// Push the constraint `fr-: shorter_fr+`
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject: ClosureOutlivesSubject::Region(fr_minus),
outlived_free_region: fr,
blame_span: blame_span_category.1.span,
category: blame_span_category.0,
});
}
return RegionRelationCheckResult::Propagated;
}
RegionRelationCheckResult::Error
@ -2085,11 +2081,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let locations = self.scc_values.locations_outlived_by(scc);
for location in locations {
let bb = &body[location.block];
if let Some(terminator) = &bb.terminator {
if let Some(terminator) = &bb.terminator
// terminator of a loop should be TerminatorKind::FalseUnwind
if let TerminatorKind::FalseUnwind { .. } = terminator.kind {
return Some(location);
}
&& let TerminatorKind::FalseUnwind { .. } = terminator.kind
{
return Some(location);
}
}
None

View file

@ -669,24 +669,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
if let Some(annotation_index) = self.rvalue_user_ty(rv) {
if let Err(terr) = self.relate_type_and_user_type(
if let Some(annotation_index) = self.rvalue_user_ty(rv)
&& let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Invariant,
&UserTypeProjection { base: annotation_index, projs: vec![] },
location.to_locations(),
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg),
) {
let annotation = &self.user_type_annotations[annotation_index];
span_mirbug!(
self,
stmt,
"bad user type on rvalue ({:?} = {:?}): {:?}",
annotation,
rv_ty,
terr
);
}
)
{
let annotation = &self.user_type_annotations[annotation_index];
span_mirbug!(
self,
stmt,
"bad user type on rvalue ({:?} = {:?}): {:?}",
annotation,
rv_ty,
terr
);
}
if !self.unsized_feature_enabled() {
@ -1761,7 +1761,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
assert!(!matches!(
tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)),
tcx.impl_of_assoc(def_id).map(|imp| tcx.def_kind(imp)),
Some(DefKind::Impl { of_trait: true })
));
self.prove_predicates(

View file

@ -969,13 +969,28 @@ fn for_each_late_bound_region_in_item<'tcx>(
mir_def_id: LocalDefId,
mut f: impl FnMut(ty::Region<'tcx>),
) {
if !tcx.def_kind(mir_def_id).is_fn_like() {
return;
}
let bound_vars = match tcx.def_kind(mir_def_id) {
DefKind::Fn | DefKind::AssocFn => {
tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id))
}
// We extract the bound vars from the deduced closure signature, since we may have
// only deduced that a param in the closure signature is late-bound from a constraint
// that we discover during typeck.
DefKind::Closure => {
let ty = tcx.type_of(mir_def_id).instantiate_identity();
match *ty.kind() {
ty::Closure(_, args) => args.as_closure().sig().bound_vars(),
ty::CoroutineClosure(_, args) => {
args.as_coroutine_closure().coroutine_closure_sig().bound_vars()
}
ty::Coroutine(_, _) | ty::Error(_) => return,
_ => unreachable!("unexpected type for closure: {ty}"),
}
}
_ => return,
};
for (idx, bound_var) in
tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)).iter().enumerate()
{
for (idx, bound_var) in bound_vars.iter().enumerate() {
if let ty::BoundVariableKind::Region(kind) = bound_var {
let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);
let liberated_region = ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), kind);

View file

@ -1,11 +1,13 @@
use std::mem;
use std::{mem, slice};
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, NodeId, attr};
use rustc_ast::{self as ast, HasNodeId, NodeId, attr};
use rustc_ast_pretty::pprust;
use rustc_attr_data_structures::AttributeKind;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::DiagCtxtHandle;
use rustc_expand::base::{ExtCtxt, ResolverExpand, parse_macro_name_and_helper_attrs};
use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_feature::Features;
use rustc_session::Session;
@ -22,7 +24,7 @@ struct ProcMacroDerive {
trait_name: Symbol,
function_ident: Ident,
span: Span,
attrs: Vec<Symbol>,
attrs: ThinVec<Symbol>,
}
struct ProcMacroDef {
@ -41,6 +43,7 @@ struct CollectProcMacros<'a> {
macros: Vec<ProcMacro>,
in_root: bool,
dcx: DiagCtxtHandle<'a>,
session: &'a Session,
source_map: &'a SourceMap,
is_proc_macro_crate: bool,
is_test_crate: bool,
@ -63,6 +66,7 @@ pub fn inject(
macros: Vec::new(),
in_root: true,
dcx,
session: sess,
source_map: sess.source_map(),
is_proc_macro_crate,
is_test_crate,
@ -98,8 +102,18 @@ impl<'a> CollectProcMacros<'a> {
function_ident: Ident,
attr: &'a ast::Attribute,
) {
let Some((trait_name, proc_attrs)) =
parse_macro_name_and_helper_attrs(self.dcx, attr, "derive")
let Some(rustc_hir::Attribute::Parsed(AttributeKind::ProcMacroDerive {
trait_name,
helper_attrs,
..
})) = AttributeParser::parse_limited(
self.session,
slice::from_ref(attr),
sym::proc_macro_derive,
item.span,
item.node_id(),
None,
)
else {
return;
};
@ -110,7 +124,7 @@ impl<'a> CollectProcMacros<'a> {
span: item.span,
trait_name,
function_ident,
attrs: proc_attrs,
attrs: helper_attrs,
}));
} else {
let msg = if !self.in_root {

View file

@ -47,8 +47,6 @@ pub fn inject(
ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)),
);
krate.items.insert(0, item);
let root = (edition == Edition2015).then_some(kw::PathRoot);
let import_path = root
@ -75,6 +73,6 @@ pub fn inject(
}),
);
krate.items.insert(0, use_item);
krate.items.splice(0..0, [item, use_item]);
krate.items.len() - orig_num_items
}

View file

@ -19,7 +19,7 @@ index 1e336bf..35e6f54 100644
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
#![feature(array_chunks)]
#![feature(array_ptr_get)]
diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
index b735957..ea728b6 100644
--- a/coretests/tests/atomic.rs

View file

@ -33,6 +33,7 @@ rustc = "$(pwd)/../dist/bin/rustc-clif"
cargo = "$(rustup which cargo)"
full-bootstrap = true
local-rebuild = true
compiletest-allow-stage0 = true
[rust]
download-rustc = false

View file

@ -166,5 +166,5 @@ index 073116933bd..c3e4578204d 100644
EOF
echo "[TEST] rustc test suite"
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
popd

View file

@ -561,8 +561,6 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
// FIXME: create a function "display_if_not_quiet" or something along the line.
println!("[TEST] rustc asm test suite");
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
let codegen_backend_path = format!(
"{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
pwd = std::env::current_dir()
@ -588,6 +586,8 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
&"always",
&"--stage",
&"0",
&"--set",
&"build.compiletest-allow-stage0=true",
&"tests/assembly-llvm/asm",
&"--compiletest-rustc-args",
&rustc_args,
@ -1047,7 +1047,6 @@ where
// FIXME: create a function "display_if_not_quiet" or something along the line.
println!("[TEST] rustc {test_type} test suite");
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
let extra =
if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" };
@ -1070,6 +1069,8 @@ where
&"always",
&"--stage",
&"0",
&"--set",
&"build.compiletest-allow-stage0=true",
&format!("tests/{test_type}"),
&"--compiletest-rustc-args",
&rustc_args,

View file

@ -4,7 +4,6 @@ use gccjit::{Context, OutputKind};
use rustc_codegen_ssa::back::link::ensure_removed;
use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
use rustc_errors::DiagCtxtHandle;
use rustc_fs_util::link_or_copy;
use rustc_session::config::OutputType;
use rustc_span::fatal_error::FatalError;
@ -258,14 +257,6 @@ pub(crate) fn codegen(
))
}
pub(crate) fn link(
_cgcx: &CodegenContext<GccCodegenBackend>,
_dcx: DiagCtxtHandle<'_>,
mut _modules: Vec<ModuleCodegen<GccContext>>,
) -> Result<ModuleCodegen<GccContext>, FatalError> {
unimplemented!();
}
pub(crate) fn save_temp_bitcode(
cgcx: &CodegenContext<GccCodegenBackend>,
_module: &ModuleCodegen<GccContext>,

View file

@ -426,14 +426,6 @@ impl WriteBackendMethods for GccCodegenBackend {
fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
unimplemented!();
}
fn run_link(
cgcx: &CodegenContext<Self>,
dcx: DiagCtxtHandle<'_>,
modules: Vec<ModuleCodegen<Self::Module>>,
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::write::link(cgcx, dcx, modules)
}
}
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit

View file

@ -12,7 +12,7 @@ codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$err})
codegen_llvm_mismatch_data_layout =
data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`

View file

@ -7,6 +7,7 @@ use std::sync::Arc;
use std::{io, iter, slice};
use object::read::archive::ArchiveFile;
use object::{Object, ObjectSection};
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
use rustc_codegen_ssa::traits::*;
@ -105,31 +106,15 @@ fn get_bitcode_slice_from_object_data<'a>(
// name" which in the public API for sections gets treated as part of the section name, but
// internally in MachOObjectFile.cpp gets treated separately.
let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,");
let mut len = 0;
let data = unsafe {
llvm::LLVMRustGetSliceFromObjectDataByName(
obj.as_ptr(),
obj.len(),
section_name.as_ptr(),
section_name.len(),
&mut len,
)
};
if !data.is_null() {
assert!(len != 0);
let bc = unsafe { slice::from_raw_parts(data, len) };
// `bc` must be a sub-slice of `obj`.
assert!(obj.as_ptr() <= bc.as_ptr());
assert!(bc[bc.len()..bc.len()].as_ptr() <= obj[obj.len()..obj.len()].as_ptr());
let obj =
object::File::parse(obj).map_err(|err| LtoBitcodeFromRlib { err: err.to_string() })?;
Ok(bc)
} else {
assert!(len == 0);
Err(LtoBitcodeFromRlib {
llvm_err: llvm::last_error().unwrap_or_else(|| "unknown LLVM error".to_string()),
})
}
let section = obj
.section_by_name(section_name)
.ok_or_else(|| LtoBitcodeFromRlib { err: format!("Can't find section {section_name}") })?;
section.data().map_err(|err| LtoBitcodeFromRlib { err: err.to_string() })
}
/// Performs fat LTO by merging all modules into a single one and returning it
@ -505,10 +490,10 @@ fn thin_lto(
// Save the current ThinLTO import information for the next compilation
// session, overwriting the previous serialized data (if any).
if let Some(path) = key_map_path {
if let Err(err) = curr_key_map.save_to_file(&path) {
return Err(write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err }));
}
if let Some(path) = key_map_path
&& let Err(err) = curr_key_map.save_to_file(&path)
{
return Err(write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err }));
}
Ok((opt_jobs, copy_jobs))

View file

@ -796,29 +796,6 @@ pub(crate) fn optimize(
Ok(())
}
pub(crate) fn link(
cgcx: &CodegenContext<LlvmCodegenBackend>,
dcx: DiagCtxtHandle<'_>,
mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
use super::lto::{Linker, ModuleBuffer};
// Sort the modules by name to ensure deterministic behavior.
modules.sort_by(|a, b| a.name.cmp(&b.name));
let (first, elements) =
modules.split_first().expect("Bug! modules must contain at least one module.");
let mut linker = Linker::new(first.module_llvm.llmod());
for module in elements {
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_link_module", &*module.name);
let buffer = ModuleBuffer::new(module.module_llvm.llmod());
linker
.add(buffer.data())
.map_err(|()| llvm_err(dcx, LlvmError::SerializeModule { name: &module.name }))?;
}
drop(linker);
Ok(modules.remove(0))
}
pub(crate) fn codegen(
cgcx: &CodegenContext<LlvmCodegenBackend>,
module: ModuleCodegen<ModuleLlvm>,

View file

@ -687,10 +687,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
bx.nonnull_metadata(load);
}
if let Some(pointee) = layout.pointee_info_at(bx, offset) {
if let Some(_) = pointee.safe {
bx.align_metadata(load, pointee.align);
}
if let Some(pointee) = layout.pointee_info_at(bx, offset)
&& let Some(_) = pointee.safe
{
bx.align_metadata(load, pointee.align);
}
}
abi::Primitive::Float(_) => {}

View file

@ -46,21 +46,17 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) {
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
// FIXME(#132395): Can this be none even when coverage is enabled?
let instances_used = match cx.coverage_cx {
Some(ref cx) => cx.instances_used.borrow(),
None => return,
};
let Some(ref coverage_cx) = cx.coverage_cx else { return };
let mut covfun_records = instances_used
.iter()
.copied()
let mut covfun_records = coverage_cx
.instances_used()
.into_iter()
// Sort by symbol name, so that the global file table is built in an
// order that doesn't depend on the stable-hash-based order in which
// instances were visited during codegen.
.sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name)
.filter_map(|instance| prepare_covfun_record(tcx, instance, true))
.collect::<Vec<_>>();
drop(instances_used);
// In a single designated CGU, also prepare covfun records for functions
// in this crate that were instrumented for coverage, but are unused.

View file

@ -5,7 +5,7 @@ use rustc_abi::Size;
use rustc_codegen_ssa::traits::{
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::ty::Instance;
use tracing::{debug, instrument};
@ -20,9 +20,14 @@ mod mapgen;
/// Extra per-CGU context/state needed for coverage instrumentation.
pub(crate) struct CguCoverageContext<'ll, 'tcx> {
/// Coverage data for each instrumented function identified by DefId.
pub(crate) instances_used: RefCell<FxIndexSet<Instance<'tcx>>>,
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
/// Associates function instances with an LLVM global that holds the
/// function's symbol name, as needed by LLVM coverage intrinsics.
///
/// Instances in this map are also considered "used" for the purposes of
/// emitting covfun records. Every covfun record holds a hash of its
/// symbol name, and `llvm-cov` will exit fatally if it can't resolve that
/// hash back to an entry in the binary's `__llvm_prf_names` linker section.
pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>,
pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
covfun_section_name: OnceCell<CString>,
@ -31,7 +36,6 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> {
impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
pub(crate) fn new() -> Self {
Self {
instances_used: RefCell::<FxIndexSet<_>>::default(),
pgo_func_name_var_map: Default::default(),
mcdc_condition_bitmap_map: Default::default(),
covfun_section_name: Default::default(),
@ -53,6 +57,14 @@ impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
.and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
.copied() // Dereference Option<&&Value> to Option<&Value>
}
/// Returns the list of instances considered "used" in this CGU, as
/// inferred from the keys of `pgo_func_name_var_map`.
pub(crate) fn instances_used(&self) -> Vec<Instance<'tcx>> {
// Collecting into a Vec is way easier than trying to juggle RefCell
// projections, and this should only run once per CGU anyway.
self.pgo_func_name_var_map.borrow().keys().copied().collect::<Vec<_>>()
}
}
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
@ -78,7 +90,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
/// string, to hold the function name passed to LLVM intrinsic
/// `instrprof.increment()`. The `Value` is only created once per instance.
/// Multiple invocations with the same instance return the same `Value`.
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
///
/// This has the side-effect of causing coverage codegen to consider this
/// function "used", making it eligible to emit an associated covfun record.
fn ensure_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
debug!("getting pgo_func_name_var for instance={:?}", instance);
let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
pgo_func_name_var_map.entry(instance).or_insert_with(|| {
@ -102,7 +117,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
return;
}
let fn_name = self.get_pgo_func_name_var(instance);
let fn_name = self.ensure_pgo_func_name_var(instance);
let hash = self.const_u64(function_coverage_info.function_source_hash);
let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
self.mcdc_parameters(fn_name, hash, bitmap_bits);
@ -151,11 +166,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
return;
};
// Mark the instance as used in this CGU, for coverage purposes.
// This includes functions that were not partitioned into this CGU,
// but were MIR-inlined into one of this CGU's functions.
coverage_cx.instances_used.borrow_mut().insert(instance);
match *kind {
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
@ -163,7 +173,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
CoverageKind::VirtualCounter { bcb }
if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
{
let fn_name = bx.get_pgo_func_name_var(instance);
let fn_name = bx.ensure_pgo_func_name_var(instance);
let hash = bx.const_u64(function_coverage_info.function_source_hash);
let num_counters = bx.const_u32(ids_info.num_counters);
let index = bx.const_u32(id.as_u32());
@ -193,7 +203,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
"bitmap index of the decision out of range"
);
let fn_name = bx.get_pgo_func_name_var(instance);
let fn_name = bx.ensure_pgo_func_name_var(instance);
let hash = bx.const_u64(function_coverage_info.function_source_hash);
let bitmap_index = bx.const_u32(bitmap_idx);
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);

View file

@ -285,8 +285,8 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
// Item(T),
// }
// ```
let is_expanding_recursive =
debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
let is_expanding_recursive = adt_def.is_enum()
&& debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
if def_id == *parent_def_id {
args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| {
if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type())

View file

@ -533,7 +533,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// First, let's see if this is a method within an inherent impl. Because
// if yes, we want to make the result subroutine DIE a child of the
// subroutine's self-type.
if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) {
if let Some(impl_def_id) = cx.tcx.impl_of_assoc(instance.def_id()) {
// If the method does *not* belong to a trait, proceed
if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(

View file

@ -39,7 +39,7 @@ pub(crate) struct AutoDiffWithoutEnable;
#[derive(Diagnostic)]
#[diag(codegen_llvm_lto_bitcode_from_rlib)]
pub(crate) struct LtoBitcodeFromRlib {
pub llvm_err: String,
pub err: String,
}
#[derive(Diagnostic)]

View file

@ -168,13 +168,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();
print!("{stats}");
}
fn run_link(
cgcx: &CodegenContext<Self>,
dcx: DiagCtxtHandle<'_>,
modules: Vec<ModuleCodegen<Self::Module>>,
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
back::write::link(cgcx, dcx, modules)
}
fn run_and_optimize_fat_lto(
cgcx: &CodegenContext<Self>,
exported_symbols_for_lto: &[String],

View file

@ -2612,13 +2612,6 @@ unsafe extern "C" {
len: usize,
Identifier: *const c_char,
) -> Option<&Module>;
pub(crate) fn LLVMRustGetSliceFromObjectDataByName(
data: *const u8,
len: usize,
name: *const u8,
name_len: usize,
out_len: &mut usize,
) -> *const u8;
pub(crate) fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
pub(crate) fn LLVMRustLinkerAdd(

View file

@ -8,8 +8,8 @@ edition = "2024"
ar_archive_writer = "0.4.2"
bitflags = "2.4.1"
bstr = "1.11.3"
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
# `cc` in `rustc_llvm` if you update the `cc` here.
# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
# per crate", so if you change this, you need to also change it in `rustc_llvm`.
cc = "=1.2.16"
itertools = "0.12"
pathdiff = "0.2.0"

View file

@ -3369,12 +3369,12 @@ fn warn_if_linked_with_gold(sess: &Session, path: &Path) -> Result<(), Box<dyn s
let section =
elf.sections(endian, data)?.section_by_name(endian, b".note.gnu.gold-version");
if let Some((_, section)) = section {
if let Some(mut notes) = section.notes(endian, data)? {
return Ok(notes.any(|note| {
note.is_ok_and(|note| note.n_type(endian) == elf::NT_GNU_GOLD_VERSION)
}));
}
if let Some((_, section)) = section
&& let Some(mut notes) = section.notes(endian, data)?
{
return Ok(notes.any(|note| {
note.is_ok_and(|note| note.n_type(endian) == elf::NT_GNU_GOLD_VERSION)
}));
}
Ok(false)

View file

@ -86,7 +86,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
// Only consider nodes that actually have exported symbols.
match tcx.def_kind(def_id) {
DefKind::Fn | DefKind::Static { .. } => {}
DefKind::AssocFn if tcx.impl_of_method(def_id.to_def_id()).is_some() => {}
DefKind::AssocFn if tcx.impl_of_assoc(def_id.to_def_id()).is_some() => {}
_ => return None,
};

View file

@ -1,4 +1,3 @@
use std::any::Any;
use std::assert_matches::assert_matches;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
@ -372,8 +371,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
/// The incremental compilation session directory, or None if we are not
/// compiling incrementally
pub incr_comp_session_dir: Option<PathBuf>,
/// Channel back to the main control thread to send messages to
pub coordinator_send: Sender<Box<dyn Any + Send>>,
/// `true` if the codegen should be run in parallel.
///
/// Depends on [`ExtraBackendMethods::supports_parallel()`] and `-Zno_parallel_backend`.
@ -800,10 +797,6 @@ pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
/// The backend has finished compiling a CGU, nothing more required.
Finished(CompiledModule),
/// The backend has finished compiling a CGU, which now needs linking
/// because `-Zcombine-cgu` was specified.
NeedsLink(ModuleCodegen<B::Module>),
/// The backend has finished compiling a CGU, which now needs to go through
/// fat LTO.
NeedsFatLto(FatLtoInput<B>),
@ -887,7 +880,10 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
};
match lto_type {
ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
ComputedLtoType::No => {
let module = B::codegen(cgcx, module, module_config)?;
Ok(WorkItemResult::Finished(module))
}
ComputedLtoType::Thin => {
let (name, thin_buffer) = B::prepare_thin(module, false);
if let Some(path) = bitcode {
@ -1027,20 +1023,8 @@ fn execute_thin_lto_work_item<B: ExtraBackendMethods>(
module_config: &ModuleConfig,
) -> Result<WorkItemResult<B>, FatalError> {
let module = B::optimize_thin(cgcx, module)?;
finish_intra_module_work(cgcx, module, module_config)
}
fn finish_intra_module_work<B: ExtraBackendMethods>(
cgcx: &CodegenContext<B>,
module: ModuleCodegen<B::Module>,
module_config: &ModuleConfig,
) -> Result<WorkItemResult<B>, FatalError> {
if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator {
let module = B::codegen(cgcx, module, module_config)?;
Ok(WorkItemResult::Finished(module))
} else {
Ok(WorkItemResult::NeedsLink(module))
}
let module = B::codegen(cgcx, module, module_config)?;
Ok(WorkItemResult::Finished(module))
}
/// Messages sent to the coordinator.
@ -1122,10 +1106,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
autodiff_items: &[AutoDiffItem],
shared_emitter: SharedEmitter,
codegen_worker_send: Sender<CguMessage>,
coordinator_receive: Receiver<Box<dyn Any + Send>>,
coordinator_receive: Receiver<Message<B>>,
regular_config: Arc<ModuleConfig>,
allocator_config: Arc<ModuleConfig>,
tx_to_llvm_workers: Sender<Box<dyn Any + Send>>,
tx_to_llvm_workers: Sender<Message<B>>,
) -> thread::JoinHandle<Result<CompiledModules, ()>> {
let coordinator_send = tx_to_llvm_workers;
let sess = tcx.sess;
@ -1153,7 +1137,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
let coordinator_send2 = coordinator_send.clone();
let helper = jobserver::client()
.into_helper_thread(move |token| {
drop(coordinator_send2.send(Box::new(Message::Token::<B>(token))));
drop(coordinator_send2.send(Message::Token::<B>(token)));
})
.expect("failed to spawn helper thread");
@ -1187,7 +1171,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
remark: sess.opts.cg.remark.clone(),
remark_dir,
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
coordinator_send,
expanded_args: tcx.sess.expanded_args.clone(),
diag_emitter: shared_emitter.clone(),
output_filenames: Arc::clone(tcx.output_filenames(())),
@ -1347,7 +1330,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
// through codegen and LLVM.
let mut compiled_modules = vec![];
let mut compiled_allocator_module = None;
let mut needs_link = Vec::new();
let mut needs_fat_lto = Vec::new();
let mut needs_thin_lto = Vec::new();
let mut lto_import_only_modules = Vec::new();
@ -1423,7 +1405,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
let (item, _) =
work_items.pop().expect("queue empty - queue_full_enough() broken?");
main_thread_state = MainThreadState::Lending;
spawn_work(&cgcx, &mut llvm_start_time, item);
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
}
}
} else if codegen_state == Completed {
@ -1502,7 +1484,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
MainThreadState::Idle => {
if let Some((item, _)) = work_items.pop() {
main_thread_state = MainThreadState::Lending;
spawn_work(&cgcx, &mut llvm_start_time, item);
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
} else {
// There is no unstarted work, so let the main thread
// take over for a running worker. Otherwise the
@ -1538,7 +1520,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
while running_with_own_token < tokens.len()
&& let Some((item, _)) = work_items.pop()
{
spawn_work(&cgcx, &mut llvm_start_time, item);
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
running_with_own_token += 1;
}
}
@ -1546,8 +1528,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
// Relinquish accidentally acquired extra tokens.
tokens.truncate(running_with_own_token);
let msg = coordinator_receive.recv().unwrap();
match *msg.downcast::<Message<B>>().ok().unwrap() {
match coordinator_receive.recv().unwrap() {
// Save the token locally and the next turn of the loop will use
// this to spawn a new unit of work, or it may get dropped
// immediately if we have no more work to spawn.
@ -1630,7 +1611,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
Ok(WorkItemResult::Finished(compiled_module)) => {
match compiled_module.kind {
ModuleKind::Regular => {
assert!(needs_link.is_empty());
compiled_modules.push(compiled_module);
}
ModuleKind::Allocator => {
@ -1639,10 +1619,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
}
}
}
Ok(WorkItemResult::NeedsLink(module)) => {
assert!(compiled_modules.is_empty());
needs_link.push(module);
}
Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => {
assert!(!started_lto);
assert!(needs_thin_lto.is_empty());
@ -1679,17 +1655,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
return Err(());
}
let needs_link = mem::take(&mut needs_link);
if !needs_link.is_empty() {
assert!(compiled_modules.is_empty());
let dcx = cgcx.create_dcx();
let dcx = dcx.handle();
let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?;
let module =
B::codegen(&cgcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?;
compiled_modules.push(module);
}
// Drop to print timings
drop(llvm_start_time);
@ -1769,6 +1734,7 @@ pub(crate) struct WorkerFatalError;
fn spawn_work<'a, B: ExtraBackendMethods>(
cgcx: &'a CodegenContext<B>,
coordinator_send: Sender<Message<B>>,
llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
work: WorkItem<B>,
) {
@ -1782,7 +1748,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
// Set up a destructor which will fire off a message that we're done as
// we exit.
struct Bomb<B: ExtraBackendMethods> {
coordinator_send: Sender<Box<dyn Any + Send>>,
coordinator_send: Sender<Message<B>>,
result: Option<Result<WorkItemResult<B>, FatalError>>,
}
impl<B: ExtraBackendMethods> Drop for Bomb<B> {
@ -1794,11 +1760,11 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
}
None => Message::WorkItem::<B> { result: Err(None) },
};
drop(self.coordinator_send.send(Box::new(msg)));
drop(self.coordinator_send.send(msg));
}
}
let mut bomb = Bomb::<B> { coordinator_send: cgcx.coordinator_send.clone(), result: None };
let mut bomb = Bomb::<B> { coordinator_send, result: None };
// Execute the work itself, and if it finishes successfully then flag
// ourselves as a success as well.
@ -2003,7 +1969,7 @@ impl SharedEmitterMain {
}
pub struct Coordinator<B: ExtraBackendMethods> {
pub sender: Sender<Box<dyn Any + Send>>,
sender: Sender<Message<B>>,
future: Option<thread::JoinHandle<Result<CompiledModules, ()>>>,
// Only used for the Message type.
phantom: PhantomData<B>,
@ -2020,7 +1986,7 @@ impl<B: ExtraBackendMethods> Drop for Coordinator<B> {
if let Some(future) = self.future.take() {
// If we haven't joined yet, signal to the coordinator that it should spawn no more
// work, and wait for worker threads to finish.
drop(self.sender.send(Box::new(Message::CodegenAborted::<B>)));
drop(self.sender.send(Message::CodegenAborted::<B>));
drop(future.join());
}
}
@ -2079,7 +2045,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
pub(crate) fn codegen_finished(&self, tcx: TyCtxt<'_>) {
self.wait_for_signal_to_codegen_item();
self.check_for_errors(tcx.sess);
drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>)));
drop(self.coordinator.sender.send(Message::CodegenComplete::<B>));
}
pub(crate) fn check_for_errors(&self, sess: &Session) {
@ -2100,28 +2066,25 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
}
pub(crate) fn submit_codegened_module_to_llvm<B: ExtraBackendMethods>(
_backend: &B,
tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
coordinator: &Coordinator<B>,
module: ModuleCodegen<B::Module>,
cost: u64,
) {
let llvm_work_item = WorkItem::Optimize(module);
drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone::<B> { llvm_work_item, cost })));
drop(coordinator.sender.send(Message::CodegenDone::<B> { llvm_work_item, cost }));
}
pub(crate) fn submit_post_lto_module_to_llvm<B: ExtraBackendMethods>(
_backend: &B,
tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
coordinator: &Coordinator<B>,
module: CachedModuleCodegen,
) {
let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module);
drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone::<B> { llvm_work_item, cost: 0 })));
drop(coordinator.sender.send(Message::CodegenDone::<B> { llvm_work_item, cost: 0 }));
}
pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
_backend: &B,
tcx: TyCtxt<'_>,
tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
coordinator: &Coordinator<B>,
module: CachedModuleCodegen,
) {
let filename = pre_lto_bitcode_filename(&module.name);
@ -2135,10 +2098,10 @@ pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
})
};
// Schedule the module to be loaded
drop(tx_to_llvm_workers.send(Box::new(Message::AddImportOnlyModule::<B> {
drop(coordinator.sender.send(Message::AddImportOnlyModule::<B> {
module_data: SerializedModule::FromUncompressedFile(mmap),
work_product: module.source,
})));
}));
}
fn pre_lto_bitcode_filename(module_name: &str) -> String {

View file

@ -702,8 +702,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// These modules are generally cheap and won't throw off scheduling.
let cost = 0;
submit_codegened_module_to_llvm(
&backend,
&ongoing_codegen.coordinator.sender,
&ongoing_codegen.coordinator,
ModuleCodegen::new_allocator(llmod_id, module_llvm),
cost,
);
@ -800,18 +799,12 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// compilation hang on post-monomorphization errors.
tcx.dcx().abort_if_errors();
submit_codegened_module_to_llvm(
&backend,
&ongoing_codegen.coordinator.sender,
module,
cost,
);
submit_codegened_module_to_llvm(&ongoing_codegen.coordinator, module, cost);
}
CguReuse::PreLto => {
submit_pre_lto_module_to_llvm(
&backend,
tcx,
&ongoing_codegen.coordinator.sender,
&ongoing_codegen.coordinator,
CachedModuleCodegen {
name: cgu.name().to_string(),
source: cgu.previous_work_product(tcx),
@ -820,8 +813,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
}
CguReuse::PostLto => {
submit_post_lto_module_to_llvm(
&backend,
&ongoing_codegen.coordinator.sender,
&ongoing_codegen.coordinator,
CachedModuleCodegen {
name: cgu.name().to_string(),
source: cgu.previous_work_product(tcx),

View file

@ -4,12 +4,12 @@ use rustc_abi::{Align, ExternAbi};
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
use rustc_attr_data_structures::{
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, UsedBy, find_attr,
AttributeKind, InlineAttr, InstructionSetAttr, UsedBy, find_attr,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
use rustc_hir::{self as hir, LangItem, lang_items};
use rustc_hir::{self as hir, Attribute, LangItem, lang_items};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
};
@ -53,77 +53,196 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
}
}
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
if cfg!(debug_assertions) {
let def_kind = tcx.def_kind(did);
assert!(
def_kind.has_codegen_attrs(),
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
);
/// In some cases, attributes are only valid on functions, but it's the `check_attr`
/// pass that checks that they aren't used anywhere else, rather than this module.
/// In these cases, we bail from performing further checks that are only meaningful for
/// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
/// report a delayed bug, just in case `check_attr` isn't doing its job.
fn try_fn_sig<'tcx>(
tcx: TyCtxt<'tcx>,
did: LocalDefId,
attr_span: Span,
) -> Option<ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>>> {
use DefKind::*;
let def_kind = tcx.def_kind(did);
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
Some(tcx.fn_sig(did))
} else {
tcx.dcx().span_delayed_bug(attr_span, "this attribute can only be applied to functions");
None
}
}
// FIXME(jdonszelmann): remove when instruction_set becomes a parsed attr
fn parse_instruction_set_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<InstructionSetAttr> {
let list = attr.meta_item_list()?;
match &list[..] {
[MetaItemInner::MetaItem(set)] => {
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
match segments.as_slice() {
[sym::arm, sym::a32 | sym::t32] if !tcx.sess.target.has_thumb_interworking => {
tcx.dcx().emit_err(errors::UnsupportedInstructionSet { span: attr.span() });
None
}
[sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
[sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
_ => {
tcx.dcx().emit_err(errors::InvalidInstructionSet { span: attr.span() });
None
}
}
}
[] => {
tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
None
}
_ => {
tcx.dcx().emit_err(errors::MultipleInstructionSet { span: attr.span() });
None
}
}
}
// FIXME(jdonszelmann): remove when linkage becomes a parsed attr
fn parse_linkage_attr(tcx: TyCtxt<'_>, did: LocalDefId, attr: &Attribute) -> Option<Linkage> {
let val = attr.value_str()?;
let linkage = linkage_by_name(tcx, did, val.as_str());
Some(linkage)
}
// FIXME(jdonszelmann): remove when no_sanitize becomes a parsed attr
fn parse_no_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<SanitizerSet> {
let list = attr.meta_item_list()?;
let mut sanitizer_set = SanitizerSet::empty();
for item in list.iter() {
match item.name() {
Some(sym::address) => {
sanitizer_set |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
}
Some(sym::cfi) => sanitizer_set |= SanitizerSet::CFI,
Some(sym::kcfi) => sanitizer_set |= SanitizerSet::KCFI,
Some(sym::memory) => sanitizer_set |= SanitizerSet::MEMORY,
Some(sym::memtag) => sanitizer_set |= SanitizerSet::MEMTAG,
Some(sym::shadow_call_stack) => sanitizer_set |= SanitizerSet::SHADOWCALLSTACK,
Some(sym::thread) => sanitizer_set |= SanitizerSet::THREAD,
Some(sym::hwaddress) => sanitizer_set |= SanitizerSet::HWADDRESS,
_ => {
tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
}
}
}
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did));
let mut codegen_fn_attrs = CodegenFnAttrs::new();
if tcx.should_inherit_track_caller(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
Some(sanitizer_set)
}
// FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr
fn parse_patchable_function_entry(
tcx: TyCtxt<'_>,
attr: &Attribute,
) -> Option<PatchableFunctionEntry> {
attr.meta_item_list().and_then(|l| {
let mut prefix = None;
let mut entry = None;
for item in l {
let Some(meta_item) = item.meta_item() else {
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
continue;
};
let Some(name_value_lit) = meta_item.name_value_literal() else {
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
continue;
};
let attrib_to_write = match meta_item.name() {
Some(sym::prefix_nops) => &mut prefix,
Some(sym::entry_nops) => &mut entry,
_ => {
tcx.dcx().emit_err(errors::UnexpectedParameterName {
span: item.span(),
prefix_nops: sym::prefix_nops,
entry_nops: sym::entry_nops,
});
continue;
}
};
let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
tcx.dcx().emit_err(errors::InvalidLiteralValue { span: name_value_lit.span });
continue;
};
let Ok(val) = val.get().try_into() else {
tcx.dcx().emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
continue;
};
*attrib_to_write = Some(val);
}
if let (None, None) = (prefix, entry) {
tcx.dcx().span_err(attr.span(), "must specify at least one parameter");
}
Some(PatchableFunctionEntry::from_prefix_and_entry(prefix.unwrap_or(0), entry.unwrap_or(0)))
})
}
/// Spans that are collected when processing built-in attributes,
/// that are useful for emitting diagnostics later.
#[derive(Default)]
struct InterestingAttributeDiagnosticSpans {
link_ordinal: Option<Span>,
no_sanitize: Option<Span>,
inline: Option<Span>,
no_mangle: Option<Span>,
}
/// Process the builtin attrs ([`hir::Attribute`]) on the item.
/// Many of them directly translate to codegen attrs.
fn process_builtin_attrs(
tcx: TyCtxt<'_>,
did: LocalDefId,
attrs: &[Attribute],
codegen_fn_attrs: &mut CodegenFnAttrs,
) -> InterestingAttributeDiagnosticSpans {
let mut interesting_spans = InterestingAttributeDiagnosticSpans::default();
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
// If our rustc version supports autodiff/enzyme, then we call our handler
// to check for any `#[rustc_autodiff(...)]` attributes.
// FIXME(jdonszelmann): merge with loop below
if cfg!(llvm_enzyme) {
let ad = autodiff_attrs(tcx, did.into());
codegen_fn_attrs.autodiff_item = ad;
}
// When `no_builtins` is applied at the crate level, we should add the
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
if no_builtins {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
}
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;
for attr in attrs.iter() {
// In some cases, attribute are only valid on functions, but it's the `check_attr`
// pass that check that they aren't used anywhere else, rather this module.
// In these cases, we bail from performing further checks that are only meaningful for
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
// report a delayed bug, just in case `check_attr` isn't doing its job.
let fn_sig = |attr_span| {
use DefKind::*;
let def_kind = tcx.def_kind(did);
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
Some(tcx.fn_sig(did))
} else {
tcx.dcx()
.span_delayed_bug(attr_span, "this attribute can only be applied to functions");
None
}
};
if let hir::Attribute::Parsed(p) = attr {
match p {
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
AttributeKind::ExportName { name, .. } => {
codegen_fn_attrs.export_name = Some(*name);
codegen_fn_attrs.export_name = Some(*name)
}
AttributeKind::Inline(inline, span) => {
codegen_fn_attrs.inline = *inline;
interesting_spans.inline = Some(*span);
}
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
AttributeKind::LinkOrdinal { ordinal, span } => {
codegen_fn_attrs.link_ordinal = Some(*ordinal);
link_ordinal_span = Some(*span);
interesting_spans.link_ordinal = Some(*span);
}
AttributeKind::LinkSection { name, .. } => {
codegen_fn_attrs.link_section = Some(*name)
}
AttributeKind::NoMangle(attr_span) => {
interesting_spans.no_mangle = Some(*attr_span);
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
} else {
@ -137,6 +256,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
});
}
}
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
AttributeKind::TargetFeature(features, attr_span) => {
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
@ -184,7 +304,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
let is_closure = tcx.is_closure_like(did.to_def_id());
if !is_closure
&& let Some(fn_sig) = fn_sig(*attr_span)
&& let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span)
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
{
tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span });
@ -232,155 +352,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
sym::linkage => {
if let Some(val) = attr.value_str() {
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
if tcx.is_foreign_item(did) {
codegen_fn_attrs.import_linkage = linkage;
let linkage = parse_linkage_attr(tcx, did, attr);
if tcx.is_mutable_static(did.into()) {
let mut diag = tcx.dcx().struct_span_err(
attr.span(),
"extern mutable statics are not allowed with `#[linkage]`",
);
diag.note(
"marking the extern static mutable would allow changing which \
symbol the static references rather than make the target of the \
symbol mutable",
);
diag.emit();
}
} else {
codegen_fn_attrs.linkage = linkage;
if tcx.is_foreign_item(did) {
codegen_fn_attrs.import_linkage = linkage;
if tcx.is_mutable_static(did.into()) {
let mut diag = tcx.dcx().struct_span_err(
attr.span(),
"extern mutable statics are not allowed with `#[linkage]`",
);
diag.note(
"marking the extern static mutable would allow changing which \
symbol the static references rather than make the target of the \
symbol mutable",
);
diag.emit();
}
} else {
codegen_fn_attrs.linkage = linkage;
}
}
sym::no_sanitize => {
no_sanitize_span = Some(attr.span());
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
match item.name() {
Some(sym::address) => {
codegen_fn_attrs.no_sanitize |=
SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
}
Some(sym::cfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI,
Some(sym::kcfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI,
Some(sym::memory) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY
}
Some(sym::memtag) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG
}
Some(sym::shadow_call_stack) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK
}
Some(sym::thread) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD
}
Some(sym::hwaddress) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
}
_ => {
tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
}
}
}
}
interesting_spans.no_sanitize = Some(attr.span());
codegen_fn_attrs.no_sanitize |=
parse_no_sanitize_attr(tcx, attr).unwrap_or_default();
}
sym::instruction_set => {
codegen_fn_attrs.instruction_set =
attr.meta_item_list().and_then(|l| match &l[..] {
[MetaItemInner::MetaItem(set)] => {
let segments =
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
match segments.as_slice() {
[sym::arm, sym::a32 | sym::t32]
if !tcx.sess.target.has_thumb_interworking =>
{
tcx.dcx().emit_err(errors::UnsupportedInstructionSet {
span: attr.span(),
});
None
}
[sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
[sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
_ => {
tcx.dcx().emit_err(errors::InvalidInstructionSet {
span: attr.span(),
});
None
}
}
}
[] => {
tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
None
}
_ => {
tcx.dcx()
.emit_err(errors::MultipleInstructionSet { span: attr.span() });
None
}
})
codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
}
sym::patchable_function_entry => {
codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| {
let mut prefix = None;
let mut entry = None;
for item in l {
let Some(meta_item) = item.meta_item() else {
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
continue;
};
let Some(name_value_lit) = meta_item.name_value_literal() else {
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
continue;
};
let attrib_to_write = match meta_item.name() {
Some(sym::prefix_nops) => &mut prefix,
Some(sym::entry_nops) => &mut entry,
_ => {
tcx.dcx().emit_err(errors::UnexpectedParameterName {
span: item.span(),
prefix_nops: sym::prefix_nops,
entry_nops: sym::entry_nops,
});
continue;
}
};
let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
tcx.dcx().emit_err(errors::InvalidLiteralValue {
span: name_value_lit.span,
});
continue;
};
let Ok(val) = val.get().try_into() else {
tcx.dcx()
.emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
continue;
};
*attrib_to_write = Some(val);
}
if let (None, None) = (prefix, entry) {
tcx.dcx().span_err(attr.span(), "must specify at least one parameter");
}
Some(PatchableFunctionEntry::from_prefix_and_entry(
prefix.unwrap_or(0),
entry.unwrap_or(0),
))
})
codegen_fn_attrs.patchable_function_entry =
parse_patchable_function_entry(tcx, attr);
}
_ => {}
}
}
interesting_spans
}
/// Applies overrides for codegen fn attrs. These often have a specific reason why they're necessary.
/// Please comment why when adding a new one!
fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut CodegenFnAttrs) {
// Apply the minimum function alignment here. This ensures that a function's alignment is
// determined by the `-C` flags of the crate it is defined in, not the `-C` flags of the crate
// it happens to be codegen'd (or const-eval'd) in.
@ -390,15 +404,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// On trait methods, inherit the `#[align]` of the trait's method prototype.
codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did));
let inline_span;
(codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) =
find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span))
{
(inline_attr, Some(span))
} else {
(InlineAttr::None, None)
};
// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
// but not for the code generation backend because at that point the naked function will just be
// a declaration, with a definition provided in global assembly.
@ -406,9 +411,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs.inline = InlineAttr::Never;
}
codegen_fn_attrs.optimize =
find_attr!(attrs, AttributeKind::Optimize(i, _) => *i).unwrap_or(OptimizeAttr::Default);
// #73631: closures inherit `#[target_feature]` annotations
//
// If this closure is marked `#[inline(always)]`, simply skip adding `#[target_feature]`.
@ -431,6 +433,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
// When `no_builtins` is applied at the crate level, we should add the
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
if no_builtins {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
}
// inherit track-caller properly
if tcx.should_inherit_track_caller(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
}
fn check_result(
tcx: TyCtxt<'_>,
did: LocalDefId,
interesting_spans: InterestingAttributeDiagnosticSpans,
codegen_fn_attrs: &CodegenFnAttrs,
) {
// If a function uses `#[target_feature]` it can't be inlined into general
// purpose functions as they wouldn't have the right target features
// enabled. For that reason we also forbid `#[inline(always)]` as it can't be
@ -446,14 +468,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// llvm/llvm-project#70563).
if !codegen_fn_attrs.target_features.is_empty()
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
&& let Some(span) = inline_span
&& let Some(span) = interesting_spans.inline
{
tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
}
// warn that inline has no effect when no_sanitize is present
if !codegen_fn_attrs.no_sanitize.is_empty()
&& codegen_fn_attrs.inline.always()
&& let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span)
&& let (Some(no_sanitize_span), Some(inline_span)) =
(interesting_spans.no_sanitize, interesting_spans.inline)
{
let hir_id = tcx.local_def_id_to_hir_id(did);
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| {
@ -462,53 +486,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
})
}
// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only
// strippable by the linker.
//
// Additionally weak lang items have predetermined symbol names.
if let Some((name, _)) = lang_items::extract(attrs)
&& let Some(lang_item) = LangItem::from_name(name)
// error when specifying link_name together with link_ordinal
if let Some(_) = codegen_fn_attrs.link_name
&& let Some(_) = codegen_fn_attrs.link_ordinal
{
if WEAK_LANG_ITEMS.contains(&lang_item) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
if let Some(span) = interesting_spans.link_ordinal {
tcx.dcx().span_err(span, msg);
} else {
tcx.dcx().err(msg);
}
if let Some(link_name) = lang_item.link_name() {
codegen_fn_attrs.export_name = Some(link_name);
codegen_fn_attrs.link_name = Some(link_name);
}
}
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
&& codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
{
let no_mangle_span =
find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span)
.unwrap_or_default();
let lang_item =
lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name));
let mut err = tcx
.dcx()
.struct_span_err(
no_mangle_span,
"`#[no_mangle]` cannot be used on internal language items",
)
.with_note("Rustc requires this item to have a specific mangled name.")
.with_span_label(tcx.def_span(did), "should be the internal language item");
if let Some(lang_item) = lang_item {
if let Some(link_name) = lang_item.link_name() {
err = err
.with_note("If you are trying to prevent mangling to ease debugging, many")
.with_note(format!(
"debuggers support a command such as `rbreak {link_name}` to"
))
.with_note(format!(
"match `.*{link_name}.*` instead of `break {link_name}` on a specific name"
))
}
}
err.emit();
}
if let Some(features) = check_tied_features(
@ -531,6 +518,84 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
})
.emit();
}
}
fn handle_lang_items(
tcx: TyCtxt<'_>,
did: LocalDefId,
interesting_spans: &InterestingAttributeDiagnosticSpans,
attrs: &[Attribute],
codegen_fn_attrs: &mut CodegenFnAttrs,
) {
// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only
// strippable by the linker.
//
// Additionally weak lang items have predetermined symbol names.
if let Some((name, _)) = lang_items::extract(attrs)
&& let Some(lang_item) = LangItem::from_name(name)
{
if WEAK_LANG_ITEMS.contains(&lang_item) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
if let Some(link_name) = lang_item.link_name() {
codegen_fn_attrs.export_name = Some(link_name);
codegen_fn_attrs.link_name = Some(link_name);
}
}
// error when using no_mangle on a lang item item
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
&& codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
{
let lang_item =
lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name));
let mut err = tcx
.dcx()
.struct_span_err(
interesting_spans.no_mangle.unwrap_or_default(),
"`#[no_mangle]` cannot be used on internal language items",
)
.with_note("Rustc requires this item to have a specific mangled name.")
.with_span_label(tcx.def_span(did), "should be the internal language item");
if let Some(lang_item) = lang_item
&& let Some(link_name) = lang_item.link_name()
{
err = err
.with_note("If you are trying to prevent mangling to ease debugging, many")
.with_note(format!("debuggers support a command such as `rbreak {link_name}` to"))
.with_note(format!(
"match `.*{link_name}.*` instead of `break {link_name}` on a specific name"
))
}
err.emit();
}
}
/// Generate the [`CodegenFnAttrs`] for an item (identified by the [`LocalDefId`]).
///
/// This happens in 4 stages:
/// - apply built-in attributes that directly translate to codegen attributes.
/// - handle lang items. These have special codegen attrs applied to them.
/// - apply overrides, like minimum requirements for alignment and other settings that don't rely directly the built-in attrs on the item.
/// overrides come after applying built-in attributes since they may only apply when certain attributes were already set in the stage before.
/// - check that the result is valid. There's various ways in which this may not be the case, such as certain combinations of attrs.
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
if cfg!(debug_assertions) {
let def_kind = tcx.def_kind(did);
assert!(
def_kind.has_codegen_attrs(),
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
);
}
let mut codegen_fn_attrs = CodegenFnAttrs::new();
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did));
let interesting_spans = process_builtin_attrs(tcx, did, attrs, &mut codegen_fn_attrs);
handle_lang_items(tcx, did, &interesting_spans, attrs, &mut codegen_fn_attrs);
apply_overrides(tcx, did, &mut codegen_fn_attrs);
check_result(tcx, did, interesting_spans, &codegen_fn_attrs);
codegen_fn_attrs
}
@ -557,27 +622,12 @@ fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> {
tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment
}
fn check_link_name_xor_ordinal(
tcx: TyCtxt<'_>,
codegen_fn_attrs: &CodegenFnAttrs,
inline_span: Option<Span>,
) {
if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
return;
}
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
if let Some(span) = inline_span {
tcx.dcx().span_err(span, msg);
} else {
tcx.dcx().err(msg);
}
}
/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]
/// macros. There are two forms. The pure one without args to mark primal functions (the functions
/// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the
/// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never
/// panic, unless we introduced a bug when parsing the autodiff macro.
//FIXME(jdonszelmann): put in the main loop. No need to have two..... :/ Let's do that when we make autodiff parsed.
fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
let attrs = tcx.get_attrs(id, sym::rustc_autodiff);

View file

@ -16,12 +16,6 @@ pub trait WriteBackendMethods: Clone + 'static {
type ThinData: Send + Sync;
type ThinBuffer: ThinBufferMethods;
/// Merge all modules into main_module and returning it
fn run_link(
cgcx: &CodegenContext<Self>,
dcx: DiagCtxtHandle<'_>,
modules: Vec<ModuleCodegen<Self::Module>>,
) -> Result<ModuleCodegen<Self::Module>, FatalError>;
/// Performs fat LTO by merging all modules into a single one, running autodiff
/// if necessary and running any further optimizations
fn run_and_optimize_fat_lto(

View file

@ -128,15 +128,15 @@ const_eval_frame_note_inner = inside {$where_ ->
const_eval_frame_note_last = the failure occurred here
const_eval_incompatible_arg_types =
calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty}
const_eval_incompatible_calling_conventions =
calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}"
const_eval_incompatible_return_types =
calling a function with return type {$callee_ty} passing return place of type {$caller_ty}
const_eval_incompatible_types =
calling a function with argument of type {$callee_ty} passing data of type {$caller_ty}
const_eval_interior_mutable_borrow_escaping =
interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed
.label = this borrow of an interior mutable value refers to such a temporary

View file

@ -714,10 +714,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
self.super_operand(op, location);
if let Operand::Constant(c) = op {
if let Some(def_id) = c.check_static_ptr(self.tcx) {
self.check_static(def_id, self.span);
}
if let Operand::Constant(c) = op
&& let Some(def_id) = c.check_static_ptr(self.tcx)
{
self.check_static(def_id, self.span);
}
}
@ -784,7 +784,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.revalidate_conditional_constness(callee, fn_args, *fn_span);
// Attempting to call a trait method?
if let Some(trait_did) = tcx.trait_of_item(callee) {
if let Some(trait_did) = tcx.trait_of_assoc(callee) {
// We can't determine the actual callee here, so we have to do different checks
// than usual.

View file

@ -295,21 +295,18 @@ fn build_error_for_const_call<'tcx>(
}
let deref = "*".repeat(num_refs);
if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
if let Some(eq_idx) = call_str.find("==") {
if let Some(rhs_idx) =
call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
{
let rhs_pos =
span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
sugg = Some(errors::ConsiderDereferencing {
deref,
span: span.shrink_to_lo(),
rhs_span,
});
}
}
if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span)
&& let Some(eq_idx) = call_str.find("==")
&& let Some(rhs_idx) =
call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
{
let rhs_pos = span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
sugg = Some(errors::ConsiderDereferencing {
deref,
span: span.shrink_to_lo(),
rhs_span,
});
}
}
_ => {}

View file

@ -369,7 +369,7 @@ where
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
// Don't peek inside trait associated constants.
if promoted.is_none() && cx.tcx.trait_of_item(def).is_none() {
if promoted.is_none() && cx.tcx.trait_of_assoc(def).is_none() {
let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
if !Q::in_qualifs(&qualifs) {

View file

@ -137,14 +137,14 @@ where
// If a local with no projections is moved from (e.g. `x` in `y = x`), record that
// it no longer needs to be dropped.
if let mir::Operand::Move(place) = operand {
if let Some(local) = place.as_local() {
// For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
// implementation we retain qualif if a local had been borrowed before. This might
// not be strictly necessary since the local is no longer initialized.
if !self.state.borrow.contains(local) {
self.state.qualif.remove(local);
}
if let mir::Operand::Move(place) = operand
&& let Some(local) = place.as_local()
{
// For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
// implementation we retain qualif if a local had been borrowed before. This might
// not be strictly necessary since the local is no longer initialized.
if !self.state.borrow.contains(local) {
self.state.qualif.remove(local);
}
}
}

View file

@ -500,7 +500,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
InvalidNichedEnumVariantWritten { .. } => {
const_eval_invalid_niched_enum_variant_written
}
AbiMismatchArgument { .. } => const_eval_incompatible_types,
AbiMismatchArgument { .. } => const_eval_incompatible_arg_types,
AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
}
}
@ -625,12 +625,16 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
diag.arg("data_size", info.data_size);
}
InvalidNichedEnumVariantWritten { enum_ty } => {
diag.arg("ty", enum_ty.to_string());
diag.arg("ty", enum_ty);
}
AbiMismatchArgument { caller_ty, callee_ty }
| AbiMismatchReturn { caller_ty, callee_ty } => {
diag.arg("caller_ty", caller_ty.to_string());
diag.arg("callee_ty", callee_ty.to_string());
AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => {
diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output
diag.arg("caller_ty", caller_ty);
diag.arg("callee_ty", callee_ty);
}
AbiMismatchReturn { caller_ty, callee_ty } => {
diag.arg("caller_ty", caller_ty);
diag.arg("callee_ty", callee_ty);
}
}
}

View file

@ -270,6 +270,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>),
>,
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
callee_arg_idx: usize,
callee_arg: &mir::Place<'tcx>,
callee_ty: Ty<'tcx>,
already_live: bool,
@ -298,6 +299,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Check compatibility
if !self.check_argument_compat(caller_abi, callee_abi)? {
throw_ub!(AbiMismatchArgument {
arg_idx: callee_arg_idx,
caller_ty: caller_abi.layout.ty,
callee_ty: callee_abi.layout.ty
});
@ -424,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// this is a single iterator (that handles `spread_arg`), then
// `pass_argument` would be the loop body. It takes care to
// not advance `caller_iter` for ignored arguments.
let mut callee_args_abis = callee_fn_abi.args.iter();
let mut callee_args_abis = callee_fn_abi.args.iter().enumerate();
for local in body.args_iter() {
// Construct the destination place for this argument. At this point all
// locals are still dead, so we cannot construct a `PlaceTy`.
@ -445,10 +447,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
&[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
*self.tcx,
);
let callee_abi = callee_args_abis.next().unwrap();
let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument(
&mut caller_args,
callee_abi,
idx,
&dest,
field_ty,
/* already_live */ true,
@ -456,10 +459,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
} else {
// Normal argument. Cannot mark it as live yet, it might be unsized!
let callee_abi = callee_args_abis.next().unwrap();
let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument(
&mut caller_args,
callee_abi,
idx,
&dest,
ty,
/* already_live */ false,
@ -721,7 +725,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) {
let tcx = *self.tcx;
let trait_def_id = tcx.trait_of_item(def_id).unwrap();
let trait_def_id = tcx.trait_of_assoc(def_id).unwrap();
let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args);
let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref);
let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty);

View file

@ -442,10 +442,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// # First compute the dynamic alignment
// Packed type alignment needs to be capped.
if let ty::Adt(def, _) = layout.ty.kind() {
if let Some(packed) = def.repr().pack {
unsized_align = unsized_align.min(packed);
}
if let ty::Adt(def, _) = layout.ty.kind()
&& let Some(packed) = def.repr().pack
{
unsized_align = unsized_align.min(packed);
}
// Choose max of two known alignments (combined value must

View file

@ -320,10 +320,10 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
// for a coroutine).
let var_hir_id = captured_place.get_root_variable();
let node = self.ecx.tcx.hir_node(var_hir_id);
if let hir::Node::Pat(pat) = node {
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
name = Some(ident.name);
}
if let hir::Node::Pat(pat) = node
&& let hir::PatKind::Binding(_, _, ident, _) = pat.kind
{
name = Some(ident.name);
}
}
}

View file

@ -713,8 +713,7 @@ impl HumanEmitter {
Style::LineNumber,
);
}
buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber);
self.draw_line_num(buffer, line_index, line_offset, width_offset - 3);
self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2);
left
}
@ -2128,11 +2127,11 @@ impl HumanEmitter {
// Account for a suggestion to completely remove a line(s) with whitespace (#94192).
let line_end = sm.lookup_char_pos(parts[0].span.hi()).line;
for line in line_start..=line_end {
buffer.puts(
self.draw_line_num(
&mut buffer,
line,
row_num - 1 + line - line_start,
0,
&self.maybe_anonymized(line),
Style::LineNumber,
max_line_num_len,
);
buffer.puts(
row_num - 1 + line - line_start,
@ -2612,12 +2611,7 @@ impl HumanEmitter {
// For more info: https://github.com/rust-lang/rust/issues/92741
let lines_to_remove = file_lines.lines.iter().take(file_lines.lines.len() - 1);
for (index, line_to_remove) in lines_to_remove.enumerate() {
buffer.puts(
*row_num - 1,
0,
&self.maybe_anonymized(line_num + index),
Style::LineNumber,
);
self.draw_line_num(buffer, line_num + index, *row_num - 1, max_line_num_len);
buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
let line = normalize_whitespace(
&file_lines.file.get_line(line_to_remove.line_index).unwrap(),
@ -2634,11 +2628,11 @@ impl HumanEmitter {
let last_line_index = file_lines.lines[file_lines.lines.len() - 1].line_index;
let last_line = &file_lines.file.get_line(last_line_index).unwrap();
if last_line != line_to_add {
buffer.puts(
self.draw_line_num(
buffer,
line_num + file_lines.lines.len() - 1,
*row_num - 1,
0,
&self.maybe_anonymized(line_num + file_lines.lines.len() - 1),
Style::LineNumber,
max_line_num_len,
);
buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
buffer.puts(
@ -2661,7 +2655,7 @@ impl HumanEmitter {
// 2 - .await
// |
// *row_num -= 1;
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
} else {
@ -2671,7 +2665,7 @@ impl HumanEmitter {
*row_num -= 2;
}
} else if is_multiline {
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
match &highlight_parts {
[SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => {
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
@ -2702,11 +2696,11 @@ impl HumanEmitter {
Style::NoStyle,
);
} else if let DisplaySuggestion::Add = show_code_change {
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
} else {
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
self.draw_line_num(buffer, line_num, *row_num, max_line_num_len);
self.draw_col_separator(buffer, *row_num, max_line_num_len + 1);
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
}
@ -3016,6 +3010,22 @@ impl HumanEmitter {
OutputTheme::Unicode => "",
}
}
fn draw_line_num(
&self,
buffer: &mut StyledBuffer,
line_num: usize,
line_offset: usize,
max_line_num_len: usize,
) {
let line_num = self.maybe_anonymized(line_num);
buffer.puts(
line_offset,
max_line_num_len.saturating_sub(str_width(&line_num)),
&line_num,
Style::LineNumber,
);
}
}
#[derive(Debug, Clone, Copy)]

View file

@ -153,12 +153,11 @@ impl StyledBuffer {
/// 1. That line and column exist in `StyledBuffer`
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
if let Some(ref mut line) = self.lines.get_mut(line) {
if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
if overwrite || matches!(s, Style::NoStyle | Style::Quotation) {
*s = style;
}
}
if let Some(ref mut line) = self.lines.get_mut(line)
&& let Some(StyledChar { style: s, .. }) = line.get_mut(col)
&& (overwrite || matches!(s, Style::NoStyle | Style::Quotation))
{
*s = style;
}
}
}

View file

@ -1,26 +1,8 @@
expand_arg_not_attributes =
second argument must be `attributes`
expand_attr_no_arguments =
attribute must have either one or two arguments
expand_attribute_meta_item =
attribute must be a meta item, not a literal
expand_attribute_single_word =
attribute must only be a single word
expand_attributes_on_expressions_experimental =
attributes on expressions are experimental
.help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//`
.help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
expand_attributes_wrong_form =
attribute must be of form: `attributes(foo, bar)`
expand_cannot_be_name_of_macro =
`{$trait_ident}` cannot be a name of {$macro_type} macro
expand_collapse_debuginfo_illegal =
illegal value for attribute #[collapse_debuginfo(no|external|yes)]
@ -71,9 +53,6 @@ expand_glob_delegation_outside_impls =
expand_glob_delegation_traitless_qpath =
qualified path without a trait in glob delegation
expand_helper_attribute_name_invalid =
`{$name}` cannot be a name of derive helper attribute
expand_incomplete_parse =
macro expansion ignores {$descr} and any tokens following
.label = caused by the macro expansion here
@ -165,12 +144,6 @@ expand_mve_unrecognized_var =
expand_non_inline_modules_in_proc_macro_input_are_unstable =
non-inline modules in proc macro input are unstable
expand_not_a_meta_item =
not a meta item
expand_only_one_word =
must only be one word
expand_proc_macro_back_compat = using an old version of `{$crate_name}`
.note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives

View file

@ -861,7 +861,7 @@ impl SyntaxExtension {
/// | (unspecified) | no | if-ext | if-ext | yes |
/// | external | no | if-ext | if-ext | yes |
/// | yes | yes | yes | yes | yes |
fn get_collapse_debuginfo(sess: &Session, attrs: &[impl AttributeExt], ext: bool) -> bool {
fn get_collapse_debuginfo(sess: &Session, attrs: &[hir::Attribute], ext: bool) -> bool {
let flag = sess.opts.cg.collapse_macro_debuginfo;
let attr = ast::attr::find_by_name(attrs, sym::collapse_debuginfo)
.and_then(|attr| {
@ -872,7 +872,7 @@ impl SyntaxExtension {
.ok()
})
.unwrap_or_else(|| {
if ast::attr::contains_name(attrs, sym::rustc_builtin_macro) {
if find_attr!(attrs, AttributeKind::RustcBuiltinMacro { .. }) {
CollapseMacroDebuginfo::Yes
} else {
CollapseMacroDebuginfo::Unspecified
@ -915,16 +915,18 @@ impl SyntaxExtension {
let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local);
tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
let (builtin_name, helper_attrs) = ast::attr::find_by_name(attrs, sym::rustc_builtin_macro)
.map(|attr| {
// Override `helper_attrs` passed above if it's a built-in macro,
// marking `proc_macro_derive` macros as built-in is not a realistic use case.
parse_macro_name_and_helper_attrs(sess.dcx(), attr, "built-in").map_or_else(
|| (Some(name), Vec::new()),
|(name, helper_attrs)| (Some(name), helper_attrs),
)
})
.unwrap_or_else(|| (None, helper_attrs));
let (builtin_name, helper_attrs) = match find_attr!(attrs, AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, .. } => (builtin_name, helper_attrs))
{
// Override `helper_attrs` passed above if it's a built-in macro,
// marking `proc_macro_derive` macros as built-in is not a realistic use case.
Some((Some(name), helper_attrs)) => {
(Some(*name), helper_attrs.iter().copied().collect())
}
Some((None, _)) => (Some(name), Vec::new()),
// Not a built-in macro
None => (None, helper_attrs),
};
let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability);
@ -1390,80 +1392,6 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
}
}
pub fn parse_macro_name_and_helper_attrs(
dcx: DiagCtxtHandle<'_>,
attr: &impl AttributeExt,
macro_type: &str,
) -> Option<(Symbol, Vec<Symbol>)> {
// Once we've located the `#[proc_macro_derive]` attribute, verify
// that it's of the form `#[proc_macro_derive(Foo)]` or
// `#[proc_macro_derive(Foo, attributes(A, ..))]`
let list = attr.meta_item_list()?;
let ([trait_attr] | [trait_attr, _]) = list.as_slice() else {
dcx.emit_err(errors::AttrNoArguments { span: attr.span() });
return None;
};
let Some(trait_attr) = trait_attr.meta_item() else {
dcx.emit_err(errors::NotAMetaItem { span: trait_attr.span() });
return None;
};
let trait_ident = match trait_attr.ident() {
Some(trait_ident) if trait_attr.is_word() => trait_ident,
_ => {
dcx.emit_err(errors::OnlyOneWord { span: trait_attr.span });
return None;
}
};
if !trait_ident.name.can_be_raw() {
dcx.emit_err(errors::CannotBeNameOfMacro {
span: trait_attr.span,
trait_ident,
macro_type,
});
}
let attributes_attr = list.get(1);
let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
if !attr.has_name(sym::attributes) {
dcx.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
}
attr.meta_item_list()
.unwrap_or_else(|| {
dcx.emit_err(errors::AttributesWrongForm { span: attr.span() });
&[]
})
.iter()
.filter_map(|attr| {
let Some(attr) = attr.meta_item() else {
dcx.emit_err(errors::AttributeMetaItem { span: attr.span() });
return None;
};
let ident = match attr.ident() {
Some(ident) if attr.is_word() => ident,
_ => {
dcx.emit_err(errors::AttributeSingleWord { span: attr.span });
return None;
}
};
if !ident.name.can_be_raw() {
dcx.emit_err(errors::HelperAttributeNameInvalid {
span: attr.span,
name: ident,
});
}
Some(ident.name)
})
.collect()
} else {
Vec::new()
};
Some((trait_ident.name, proc_attrs))
}
/// If this item looks like a specific enums from `rental`, emit a fatal error.
/// See #73345 and #83125 for more details.
/// FIXME(#73933): Remove this eventually.

View file

@ -78,72 +78,6 @@ pub(crate) struct MacroBodyStability {
pub head_span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_attr_no_arguments)]
pub(crate) struct AttrNoArguments {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_not_a_meta_item)]
pub(crate) struct NotAMetaItem {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_only_one_word)]
pub(crate) struct OnlyOneWord {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_cannot_be_name_of_macro)]
pub(crate) struct CannotBeNameOfMacro<'a> {
#[primary_span]
pub span: Span,
pub trait_ident: Ident,
pub macro_type: &'a str,
}
#[derive(Diagnostic)]
#[diag(expand_arg_not_attributes)]
pub(crate) struct ArgumentNotAttributes {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_attributes_wrong_form)]
pub(crate) struct AttributesWrongForm {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_attribute_meta_item)]
pub(crate) struct AttributeMetaItem {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_attribute_single_word)]
pub(crate) struct AttributeSingleWord {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(expand_helper_attribute_name_invalid)]
pub(crate) struct HelperAttributeNameInvalid {
#[primary_span]
pub span: Span,
pub name: Ident,
}
#[derive(Diagnostic)]
#[diag(expand_feature_removed, code = E0557)]
#[note]

View file

@ -295,6 +295,10 @@ impl DefKind {
}
}
pub fn is_assoc(self) -> bool {
matches!(self, DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy)
}
/// This is a "module" in name resolution sense.
#[inline]
pub fn is_module_like(self) -> bool {

View file

@ -148,6 +148,11 @@ impl From<Ident> for LifetimeSyntax {
/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing`
/// — there's no way to "elide" these lifetimes.
#[derive(Debug, Copy, Clone, HashStable_Generic)]
// Raise the aligement to at least 4 bytes - this is relied on in other parts of the compiler(for pointer tagging):
// https://github.com/rust-lang/rust/blob/ce5fdd7d42aba9a2925692e11af2bd39cf37798a/compiler/rustc_data_structures/src/tagged_ptr.rs#L163
// Removing this `repr(4)` will cause the compiler to not build on platforms like `m68k` Linux, where the aligement of u32 and usize is only 2.
// Since `repr(align)` may only raise aligement, this has no effect on platforms where the aligement is already sufficient.
#[repr(align(4))]
pub struct Lifetime {
#[stable_hasher(ignore)]
pub hir_id: HirId,
@ -1363,6 +1368,17 @@ impl AttributeExt for Attribute {
_ => None,
}
}
fn is_proc_macro_attr(&self) -> bool {
matches!(
self,
Attribute::Parsed(
AttributeKind::ProcMacro(..)
| AttributeKind::ProcMacroAttribute(..)
| AttributeKind::ProcMacroDerive { .. }
)
)
}
}
// FIXME(fn_delegation): use function delegation instead of manually forwarding

View file

@ -768,7 +768,9 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
check_static_inhabited(tcx, def_id);
check_static_linkage(tcx, def_id);
let ty = tcx.type_of(def_id).instantiate_identity();
res = res.and(wfcheck::check_static_item(tcx, def_id, ty, true));
res = res.and(wfcheck::check_static_item(
tcx, def_id, ty, /* should_check_for_sync */ true,
));
}
DefKind::Const => res = res.and(wfcheck::check_const_item(tcx, def_id)),
_ => unreachable!(),

View file

@ -530,13 +530,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
.iter()
.enumerate()
.map(|(i, a)| {
if let hir::TyKind::Infer(()) = a.kind {
if let Some(suggested_ty) =
if let hir::TyKind::Infer(()) = a.kind
&& let Some(suggested_ty) =
self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i))
{
infer_replacements.push((a.span, suggested_ty.to_string()));
return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
}
{
infer_replacements.push((a.span, suggested_ty.to_string()));
return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string());
}
self.lowerer().lower_ty(a)

View file

@ -221,7 +221,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
let ty = icx.lower_ty(ty);
// MIR relies on references to statics being scalars.
// Verify that here to avoid ill-formed MIR.
match check_static_item(tcx, def_id, ty, false) {
// We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
// relying on the fact that non-Sync statics don't ICE the rest of the compiler.
match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
Ok(()) => ty,
Err(guar) => Ty::new_error(tcx, guar),
}
@ -286,7 +288,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
let ty = icx.lower_ty(ty);
// MIR relies on references to statics being scalars.
// Verify that here to avoid ill-formed MIR.
match check_static_item(tcx, def_id, ty, false) {
// We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
// relying on the fact that non-Sync statics don't ICE the rest of the compiler.
match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
Ok(()) => ty,
Err(guar) => Ty::new_error(tcx, guar),
}

View file

@ -759,7 +759,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
&self,
err: &mut Diag<'_, impl EmissionGuarantee>,
) {
let trait_ = match self.tcx.trait_of_item(self.def_id) {
let trait_ = match self.tcx.trait_of_assoc(self.def_id) {
Some(def_id) => def_id,
None => return,
};

View file

@ -617,18 +617,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
});
// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
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));
}
if let Some(const_arg) = constraint.ct()
&& 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

View file

@ -755,7 +755,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let limit = if candidates.len() == 5 { 5 } else { 4 };
for (index, &item) in candidates.iter().take(limit).enumerate() {
let impl_ = tcx.impl_of_method(item).unwrap();
let impl_ = tcx.impl_of_assoc(item).unwrap();
let note_span = if item.is_local() {
Some(tcx.def_span(item))

View file

@ -103,16 +103,15 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>(
// over less-specific types (e.g. `Option<MyStruct<u8>>`)
if self.depth >= self.cause_depth {
self.cause = Some(error.obligation.cause);
if let hir::TyKind::TraitObject(..) = ty.kind {
if let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn =
if let hir::TyKind::TraitObject(..) = ty.kind
&& let DefKind::AssocTy | DefKind::AssocConst | DefKind::AssocFn =
self.tcx.def_kind(self.def_id)
{
self.cause = Some(ObligationCause::new(
ty.span,
self.def_id,
ObligationCauseCode::DynCompatible(ty.span),
));
}
{
self.cause = Some(ObligationCause::new(
ty.span,
self.def_id,
ObligationCauseCode::DynCompatible(ty.span),
));
}
self.cause_depth = self.depth
}

View file

@ -694,7 +694,7 @@ impl<'tcx> Visitor<'tcx> for AnnotateUnitFallbackVisitor<'_, 'tcx> {
// i.e. changing `Default::default()` to `<() as Default>::default()`.
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
&& let Res::Def(DefKind::AssocFn, def_id) = path.res
&& self.fcx.tcx.trait_of_item(def_id).is_some()
&& self.fcx.tcx.trait_of_assoc(def_id).is_some()
&& let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(expr.hir_id)
&& let self_ty = args.type_at(0)
&& let Some(vid) = self.fcx.root_vid(self_ty)

View file

@ -2136,10 +2136,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
};
if let hir::ExprKind::If(_, _, Some(el)) = expr.kind {
if let Some(rslt) = check_in_progress(el) {
return rslt;
}
if let hir::ExprKind::If(_, _, Some(el)) = expr.kind
&& let Some(rslt) = check_in_progress(el)
{
return rslt;
}
if let hir::ExprKind::Match(_, arms, _) = expr.kind {

View file

@ -615,31 +615,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool {
if let (ty::FnPtr(..), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
// Report upto four upvars being captured to reduce the amount error messages
// reported back to the user.
let spans_and_labels = upvars
.iter()
.take(4)
.map(|(var_hir_id, upvar)| {
let var_name = self.tcx.hir_name(*var_hir_id).to_string();
let msg = format!("`{var_name}` captured here");
(upvar.span, msg)
})
.collect::<Vec<_>>();
if let (ty::FnPtr(..), ty::Closure(def_id, _)) = (expected.kind(), found.kind())
&& let Some(upvars) = self.tcx.upvars_mentioned(*def_id)
{
// Report upto four upvars being captured to reduce the amount error messages
// reported back to the user.
let spans_and_labels = upvars
.iter()
.take(4)
.map(|(var_hir_id, upvar)| {
let var_name = self.tcx.hir_name(*var_hir_id).to_string();
let msg = format!("`{var_name}` captured here");
(upvar.span, msg)
})
.collect::<Vec<_>>();
let mut multi_span: MultiSpan =
spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
for (sp, label) in spans_and_labels {
multi_span.push_span_label(sp, label);
}
err.span_note(
multi_span,
"closures can only be coerced to `fn` types if they do not capture any variables"
);
return true;
let mut multi_span: MultiSpan =
spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
for (sp, label) in spans_and_labels {
multi_span.push_span_label(sp, label);
}
err.span_note(
multi_span,
"closures can only be coerced to `fn` types if they do not capture any variables",
);
return true;
}
false
}
@ -1302,7 +1302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => ".clone()".to_string(),
};
let span = expr.span.find_oldest_ancestor_in_same_ctxt().shrink_to_hi();
let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span).shrink_to_hi();
diag.span_suggestion_verbose(
span,
@ -1395,7 +1395,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.macro_backtrace()
.any(|x| matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..)))
{
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
let span = expr
.span
.find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
.unwrap_or(expr.span);
let mut sugg = if self.precedence(expr) >= ExprPrecedence::Unambiguous {
vec![(span.shrink_to_hi(), ".into()".to_owned())]
@ -2062,7 +2065,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => sugg.to_string(),
};
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
let span = expr
.span
.find_ancestor_not_from_extern_macro(&self.tcx.sess.source_map())
.unwrap_or(expr.span);
err.span_suggestion_verbose(span.shrink_to_hi(), msg, sugg, Applicability::HasPlaceholders);
true
}
@ -3008,13 +3014,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Returns whether the given expression is an `else if`.
fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
if let hir::ExprKind::If(..) = expr.kind {
if let Node::Expr(hir::Expr {
kind: hir::ExprKind::If(_, _, Some(else_expr)), ..
}) = self.tcx.parent_hir_node(expr.hir_id)
{
return else_expr.hir_id == expr.hir_id;
}
if let hir::ExprKind::If(..) = expr.kind
&& let Node::Expr(hir::Expr { kind: hir::ExprKind::If(_, _, Some(else_expr)), .. }) =
self.tcx.parent_hir_node(expr.hir_id)
{
return else_expr.hir_id == expr.hir_id;
}
false
}

View file

@ -53,7 +53,7 @@ use rustc_hir_analysis::check::{check_abi, check_custom_abi};
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::{bug, span_bug};
use rustc_session::config;
use rustc_span::Span;
@ -259,6 +259,21 @@ fn typeck_with_inspect<'tcx>(
let typeck_results = fcx.resolve_type_vars_in_body(body);
// Handle potentially region dependent goals, see `InferCtxt::in_hir_typeck`.
if let None = fcx.infcx.tainted_by_errors() {
for obligation in fcx.take_hir_typeck_potentially_region_dependent_goals() {
let obligation = fcx.resolve_vars_if_possible(obligation);
if obligation.has_non_region_infer() {
bug!("unexpected inference variable after writeback: {obligation:?}");
}
fcx.register_predicate(obligation);
}
fcx.select_obligations_where_possible(|_| {});
if let None = fcx.infcx.tainted_by_errors() {
fcx.report_ambiguity_errors();
}
}
fcx.detect_opaque_types_added_during_writeback();
// Consistency check our TypeckResults instance can hold all ItemLocalIds

View file

@ -669,17 +669,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
fn check_for_illegal_method_calls(&self, pick: &probe::Pick<'_>) {
// Disallow calls to the method `drop` defined in the `Drop` trait.
if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
if let Err(e) = callee::check_legal_trait_for_method_call(
if let Some(trait_def_id) = pick.item.trait_container(self.tcx)
&& let Err(e) = callee::check_legal_trait_for_method_call(
self.tcx,
self.span,
Some(self.self_expr.span),
self.call_expr.span,
trait_def_id,
self.body_id.to_def_id(),
) {
self.set_tainted_by_errors(e);
}
)
{
self.set_tainted_by_errors(e);
}
}

View file

@ -85,8 +85,11 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
let infcx =
tcx.infer_ctxt().ignoring_regions().build(TypingMode::typeck_for_body(tcx, def_id));
let infcx = tcx
.infer_ctxt()
.ignoring_regions()
.in_hir_typeck()
.build(TypingMode::typeck_for_body(tcx, def_id));
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
let fulfillment_cx = RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx));
@ -165,13 +168,12 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) =
obligation.predicate.kind().skip_binder()
{
// If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
// we need to make it into one.
if let Some(vid) = predicate.term.as_type().and_then(|ty| ty.ty_vid()) {
debug!("infer_var_info: {:?}.output = true", vid);
infer_var_info.entry(vid).or_default().output = true;
}
&& let Some(vid) = predicate.term.as_type().and_then(|ty| ty.ty_vid())
{
debug!("infer_var_info: {:?}.output = true", vid);
infer_var_info.entry(vid).or_default().output = true;
}
}
}

View file

@ -227,21 +227,19 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
self.typeck_results.type_dependent_defs_mut().remove(e.hir_id);
self.typeck_results.node_args_mut().remove(e.hir_id);
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id) {
if let Some(a) = self.typeck_results.adjustments_mut().get_mut(base.hir_id)
// Discard the need for a mutable borrow
// Extra adjustment made when indexing causes a drop
// of size information - we need to get rid of it
// Since this is "after" the other adjustment to be
// discarded, we do an extra `pop()`
if let Some(Adjustment {
&& let Some(Adjustment {
kind: Adjust::Pointer(PointerCoercion::Unsize),
..
}) = a.pop()
{
// So the borrow discard actually happens here
a.pop();
}
{
// So the borrow discard actually happens here
a.pop();
}
}
}

View file

@ -71,6 +71,7 @@ impl<'tcx> InferCtxt<'tcx> {
tcx: self.tcx,
typing_mode: self.typing_mode,
considering_regions: self.considering_regions,
in_hir_typeck: self.in_hir_typeck,
skip_leak_check: self.skip_leak_check,
inner: self.inner.clone(),
lexical_region_resolutions: self.lexical_region_resolutions.clone(),
@ -95,6 +96,7 @@ impl<'tcx> InferCtxt<'tcx> {
tcx: self.tcx,
typing_mode,
considering_regions: self.considering_regions,
in_hir_typeck: self.in_hir_typeck,
skip_leak_check: self.skip_leak_check,
inner: self.inner.clone(),
lexical_region_resolutions: self.lexical_region_resolutions.clone(),

View file

@ -22,6 +22,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
self.next_trait_solver
}
fn in_hir_typeck(&self) -> bool {
self.in_hir_typeck
}
fn typing_mode(&self) -> ty::TypingMode<'tcx> {
self.typing_mode()
}

View file

@ -37,10 +37,11 @@ use snapshot::undo_log::InferCtxtUndoLogs;
use tracing::{debug, instrument};
use type_variable::TypeVariableOrigin;
use crate::infer::region_constraints::UndoLog;
use crate::infer::snapshot::undo_log::UndoLog;
use crate::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey};
use crate::traits::{
self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine,
self, ObligationCause, ObligationInspector, PredicateObligation, PredicateObligations,
TraitEngine,
};
pub mod at;
@ -156,6 +157,12 @@ pub struct InferCtxtInner<'tcx> {
/// which may cause types to no longer be considered well-formed.
region_assumptions: Vec<ty::ArgOutlivesPredicate<'tcx>>,
/// `-Znext-solver`: Successfully proven goals during HIR typeck which
/// reference inference variables and get reproven after writeback.
///
/// See the documentation of `InferCtxt::in_hir_typeck` for more details.
hir_typeck_potentially_region_dependent_goals: Vec<PredicateObligation<'tcx>>,
/// Caches for opaque type inference.
opaque_type_storage: OpaqueTypeStorage<'tcx>,
}
@ -173,6 +180,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
region_constraint_storage: Some(Default::default()),
region_obligations: Default::default(),
region_assumptions: Default::default(),
hir_typeck_potentially_region_dependent_goals: Default::default(),
opaque_type_storage: Default::default(),
}
}
@ -244,9 +252,29 @@ pub struct InferCtxt<'tcx> {
typing_mode: TypingMode<'tcx>,
/// Whether this inference context should care about region obligations in
/// the root universe. Most notably, this is used during hir typeck as region
/// the root universe. Most notably, this is used during HIR typeck as region
/// solving is left to borrowck instead.
pub considering_regions: bool,
/// `-Znext-solver`: Whether this inference context is used by HIR typeck. If so, we
/// need to make sure we don't rely on region identity in the trait solver or when
/// relating types. This is necessary as borrowck starts by replacing each occurrence of a
/// free region with a unique inference variable. If HIR typeck ends up depending on two
/// regions being equal we'd get unexpected mismatches between HIR typeck and MIR typeck,
/// resulting in an ICE.
///
/// The trait solver sometimes depends on regions being identical. As a concrete example
/// the trait solver ignores other candidates if one candidate exists without any constraints.
/// The goal `&'a u32: Equals<&'a u32>` has no constraints right now. If we replace each
/// occurrence of `'a` with a unique region the goal now equates these regions. See
/// the tests in trait-system-refactor-initiative#27 for concrete examples.
///
/// We handle this by *uniquifying* region when canonicalizing root goals during HIR typeck.
/// This is still insufficient as inference variables may *hide* region variables, so e.g.
/// `dyn TwoSuper<?x, ?x>: Super<?x>` may hold but MIR typeck could end up having to prove
/// `dyn TwoSuper<&'0 (), &'1 ()>: Super<&'2 ()>` which is now ambiguous. Because of this we
/// stash all successfully proven goals which reference inference variables and then reprove
/// them after writeback.
pub in_hir_typeck: bool,
/// If set, this flag causes us to skip the 'leak check' during
/// higher-ranked subtyping operations. This flag is a temporary one used
@ -506,6 +534,7 @@ pub struct TypeOutlivesConstraint<'tcx> {
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
considering_regions: bool,
in_hir_typeck: bool,
skip_leak_check: bool,
/// Whether we should use the new trait solver in the local inference context,
/// which affects things like which solver is used in `predicate_may_hold`.
@ -518,6 +547,7 @@ impl<'tcx> TyCtxt<'tcx> {
InferCtxtBuilder {
tcx: self,
considering_regions: true,
in_hir_typeck: false,
skip_leak_check: false,
next_trait_solver: self.next_trait_solver_globally(),
}
@ -535,6 +565,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
self
}
pub fn in_hir_typeck(mut self) -> Self {
self.in_hir_typeck = true;
self
}
pub fn skip_leak_check(mut self, skip_leak_check: bool) -> Self {
self.skip_leak_check = skip_leak_check;
self
@ -568,12 +603,18 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
}
pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } =
*self;
let InferCtxtBuilder {
tcx,
considering_regions,
in_hir_typeck,
skip_leak_check,
next_trait_solver,
} = *self;
InferCtxt {
tcx,
typing_mode,
considering_regions,
in_hir_typeck,
skip_leak_check,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
@ -978,6 +1019,22 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
pub fn push_hir_typeck_potentially_region_dependent_goal(
&self,
goal: PredicateObligation<'tcx>,
) {
let mut inner = self.inner.borrow_mut();
inner.undo_log.push(UndoLog::PushHirTypeckPotentiallyRegionDependentGoal);
inner.hir_typeck_potentially_region_dependent_goals.push(goal);
}
pub fn take_hir_typeck_potentially_region_dependent_goals(
&self,
) -> Vec<PredicateObligation<'tcx>> {
assert!(!self.in_snapshot(), "cannot take goals in a snapshot");
std::mem::take(&mut self.inner.borrow_mut().hir_typeck_potentially_region_dependent_goals)
}
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
self.resolve_vars_if_possible(t).to_string()
}

View file

@ -177,6 +177,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
pub fn take_registered_region_assumptions(&self) -> Vec<ty::ArgOutlivesPredicate<'tcx>> {
assert!(!self.in_snapshot(), "cannot take registered region assumptions in a snapshot");
std::mem::take(&mut self.inner.borrow_mut().region_assumptions)
}

View file

@ -29,6 +29,7 @@ pub(crate) enum UndoLog<'tcx> {
ProjectionCache(traits::UndoLog<'tcx>),
PushTypeOutlivesConstraint,
PushRegionAssumption,
PushHirTypeckPotentiallyRegionDependentGoal,
}
macro_rules! impl_from {
@ -79,7 +80,12 @@ impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
assert_matches!(popped, Some(_), "pushed region constraint but could not pop it");
}
UndoLog::PushRegionAssumption => {
self.region_assumptions.pop();
let popped = self.region_assumptions.pop();
assert_matches!(popped, Some(_), "pushed region assumption but could not pop it");
}
UndoLog::PushHirTypeckPotentiallyRegionDependentGoal => {
let popped = self.hir_typeck_potentially_region_dependent_goals.pop();
assert_matches!(popped, Some(_), "pushed goal but could not pop it");
}
}
}

View file

@ -2446,16 +2446,16 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
/// Determine if this expression is a "dangerous initialization".
fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
if let hir::ExprKind::Call(path_expr, args) = expr.kind {
if let hir::ExprKind::Call(path_expr, args) = expr.kind
// Find calls to `mem::{uninitialized,zeroed}` methods.
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
_ => {}
}
&& let hir::ExprKind::Path(ref qpath) = path_expr.kind
{
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::mem_zeroed) => return Some(InitKind::Zeroed),
Some(sym::mem_uninitialized) => return Some(InitKind::Uninit),
Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed),
_ => {}
}
} else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind {
// Find problematic calls to `MaybeUninit::assume_init`.
@ -2463,14 +2463,14 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
if let hir::ExprKind::Call(path_expr, _) = receiver.kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
_ => {}
}
if let hir::ExprKind::Call(path_expr, _) = receiver.kind
&& let hir::ExprKind::Path(ref qpath) = path_expr.kind
{
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed),
Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit),
_ => {}
}
}
}
@ -2724,13 +2724,13 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
}
// check for call to `core::ptr::null` or `core::ptr::null_mut`
hir::ExprKind::Call(path, _) => {
if let hir::ExprKind::Path(ref qpath) = path.kind {
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
return matches!(
cx.tcx.get_diagnostic_name(def_id),
Some(sym::ptr_null | sym::ptr_null_mut)
);
}
if let hir::ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
{
return matches!(
cx.tcx.get_diagnostic_name(def_id),
Some(sym::ptr_null | sym::ptr_null_mut)
);
}
}
_ => {}

View file

@ -411,22 +411,21 @@ declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
impl EarlyLintPass for LintPassImpl {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind {
if let Some(last) = lint_pass.path.segments.last() {
if last.ident.name == sym::LintPass {
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
let call_site = expn_data.call_site;
if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
&& call_site.ctxt().outer_expn_data().kind
!= ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
{
cx.emit_span_lint(
LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span,
LintPassByHand,
);
}
}
if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind
&& let Some(last) = lint_pass.path.segments.last()
&& last.ident.name == sym::LintPass
{
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
let call_site = expn_data.call_site;
if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
&& call_site.ctxt().outer_expn_data().kind
!= ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
{
cx.emit_span_lint(
LINT_PASS_IMPL_WITHOUT_MACRO,
lint_pass.path.span,
LintPassByHand,
);
}
}
}

View file

@ -43,56 +43,50 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn {
return;
}
if let StmtKind::Semi(expr) = stmt.kind {
if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind {
if path.ident.name.as_str() == "map" {
if receiver.span.from_expansion()
|| args.iter().any(|e| e.span.from_expansion())
|| !is_impl_slice(cx, receiver)
|| !is_diagnostic_name(cx, expr.hir_id, "IteratorMap")
{
return;
if let StmtKind::Semi(expr) = stmt.kind
&& let ExprKind::MethodCall(path, receiver, args, span) = expr.kind
{
if path.ident.name.as_str() == "map" {
if receiver.span.from_expansion()
|| args.iter().any(|e| e.span.from_expansion())
|| !is_impl_slice(cx, receiver)
|| !is_diagnostic_name(cx, expr.hir_id, "IteratorMap")
{
return;
}
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
let default_span = args[0].span;
if let ty::FnDef(id, _) = arg_ty.kind() {
let fn_ty = cx.tcx.fn_sig(id).skip_binder();
let ret_ty = fn_ty.output().skip_binder();
if is_unit_type(ret_ty) {
cx.emit_span_lint(
MAP_UNIT_FN,
span,
MappingToUnit {
function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span),
argument_label: args[0].span,
map_label: span,
suggestion: path.ident.span,
replace: "for_each".to_string(),
},
)
}
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
let default_span = args[0].span;
if let ty::FnDef(id, _) = arg_ty.kind() {
let fn_ty = cx.tcx.fn_sig(id).skip_binder();
let ret_ty = fn_ty.output().skip_binder();
if is_unit_type(ret_ty) {
cx.emit_span_lint(
MAP_UNIT_FN,
span,
MappingToUnit {
function_label: cx
.tcx
.span_of_impl(*id)
.unwrap_or(default_span),
argument_label: args[0].span,
map_label: span,
suggestion: path.ident.span,
replace: "for_each".to_string(),
},
)
}
} else if let ty::Closure(id, subs) = arg_ty.kind() {
let cl_ty = subs.as_closure().sig();
let ret_ty = cl_ty.output().skip_binder();
if is_unit_type(ret_ty) {
cx.emit_span_lint(
MAP_UNIT_FN,
span,
MappingToUnit {
function_label: cx
.tcx
.span_of_impl(*id)
.unwrap_or(default_span),
argument_label: args[0].span,
map_label: span,
suggestion: path.ident.span,
replace: "for_each".to_string(),
},
)
}
} else if let ty::Closure(id, subs) = arg_ty.kind() {
let cl_ty = subs.as_closure().sig();
let ret_ty = cl_ty.output().skip_binder();
if is_unit_type(ret_ty) {
cx.emit_span_lint(
MAP_UNIT_FN,
span,
MappingToUnit {
function_label: cx.tcx.span_of_impl(*id).unwrap_or(default_span),
argument_label: args[0].span,
map_label: span,
suggestion: path.ident.span,
replace: "for_each".to_string(),
},
)
}
}
}
@ -101,10 +95,10 @@ impl<'tcx> LateLintPass<'tcx> for MapUnitFn {
}
fn is_impl_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
if let Some(impl_id) = cx.tcx.impl_of_method(method_id) {
return cx.tcx.type_of(impl_id).skip_binder().is_slice();
}
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_assoc(method_id)
{
return cx.tcx.type_of(impl_id).skip_binder().is_slice();
}
false
}
@ -114,11 +108,11 @@ fn is_unit_type(ty: Ty<'_>) -> bool {
}
fn is_diagnostic_name(cx: &LateContext<'_>, id: HirId, name: &str) -> bool {
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id) {
if let Some(item) = cx.tcx.get_diagnostic_name(def_id) {
if item.as_str() == name {
return true;
}
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(id)
&& let Some(item) = cx.tcx.get_diagnostic_name(def_id)
{
if item.as_str() == name {
return true;
}
}
false

View file

@ -48,38 +48,38 @@ declare_lint_pass!(NonPanicFmt => [NON_FMT_PANICS]);
impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);
if let hir::ExprKind::Call(f, [arg]) = &expr.kind
&& let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind()
{
let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);
if cx.tcx.is_lang_item(def_id, LangItem::BeginPanic)
|| cx.tcx.is_lang_item(def_id, LangItem::Panic)
|| f_diagnostic_name == Some(sym::panic_str_2015)
if cx.tcx.is_lang_item(def_id, LangItem::BeginPanic)
|| cx.tcx.is_lang_item(def_id, LangItem::Panic)
|| f_diagnostic_name == Some(sym::panic_str_2015)
{
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if matches!(
cx.tcx.get_diagnostic_name(id),
Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
) {
check_panic(cx, f, arg);
}
}
} else if f_diagnostic_name == Some(sym::unreachable_display) {
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id
&& cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id)
{
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if matches!(
cx.tcx.get_diagnostic_name(id),
Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro)
) {
check_panic(cx, f, arg);
}
}
} else if f_diagnostic_name == Some(sym::unreachable_display) {
if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
if cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id) {
check_panic(
cx,
f,
// This is safe because we checked above that the callee is indeed
// unreachable_display
match &arg.kind {
// Get the borrowed arg not the borrow
hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
_ => bug!("call to unreachable_display without borrow"),
},
);
}
}
check_panic(
cx,
f,
// This is safe because we checked above that the callee is indeed
// unreachable_display
match &arg.kind {
// Get the borrowed arg not the borrow
hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
_ => bug!("call to unreachable_display without borrow"),
},
);
}
}
}

View file

@ -623,15 +623,15 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
..
}) = p.kind
{
if let Res::Def(DefKind::Const, _) = path.res {
if let [segment] = path.segments {
NonUpperCaseGlobals::check_upper_case(
cx,
"constant in pattern",
None,
&segment.ident,
);
}
if let Res::Def(DefKind::Const, _) = path.res
&& let [segment] = path.segments
{
NonUpperCaseGlobals::check_upper_case(
cx,
"constant in pattern",
None,
&segment.ident,
);
}
}
}

View file

@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
return;
};
let Some(trait_id) = cx.tcx.trait_of_item(did) else { return };
let Some(trait_id) = cx.tcx.trait_of_assoc(did) else { return };
let Some(trait_) = cx.tcx.get_diagnostic_name(trait_id) else { return };

View file

@ -24,7 +24,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
match &ty.kind {
TyKind::Ref(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
if let Some(impl_did) = cx.tcx.impl_of_assoc(ty.hir_id.owner.to_def_id()) {
if cx.tcx.impl_trait_ref(impl_did).is_some() {
return;
}

View file

@ -1904,7 +1904,7 @@ impl InvalidAtomicOrdering {
if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind
&& recognized_names.contains(&method_path.ident.name)
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
&& let Some(impl_did) = cx.tcx.impl_of_assoc(m_def_id)
&& let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
// skip extension traits, only lint functions from the standard library
&& cx.tcx.trait_id_of_impl(impl_did).is_none()

View file

@ -185,7 +185,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
let mut op_warned = false;
if let Some(must_use_op) = must_use_op {
let span = expr.span.find_oldest_ancestor_in_same_ctxt();
let span = expr.span.find_ancestor_not_from_macro().unwrap_or(expr.span);
cx.emit_span_lint(
UNUSED_MUST_USE,
expr.span,
@ -511,7 +511,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
);
}
MustUsePath::Def(span, def_id, reason) => {
let span = span.find_oldest_ancestor_in_same_ctxt();
let span = span.find_ancestor_not_from_macro().unwrap_or(*span);
cx.emit_span_lint(
UNUSED_MUST_USE,
span,
@ -562,20 +562,19 @@ declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
impl<'tcx> LateLintPass<'tcx> for PathStatements {
fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
if let hir::StmtKind::Semi(expr) = s.kind {
if let hir::ExprKind::Path(_) = expr.kind {
let ty = cx.typeck_results().expr_ty(expr);
if ty.needs_drop(cx.tcx, cx.typing_env()) {
let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span)
{
PathStatementDropSub::Suggestion { span: s.span, snippet }
} else {
PathStatementDropSub::Help { span: s.span }
};
cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
if let hir::StmtKind::Semi(expr) = s.kind
&& let hir::ExprKind::Path(_) = expr.kind
{
let ty = cx.typeck_results().expr_ty(expr);
if ty.needs_drop(cx.tcx, cx.typing_env()) {
let sub = if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
PathStatementDropSub::Suggestion { span: s.span, snippet }
} else {
cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
}
PathStatementDropSub::Help { span: s.span }
};
cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementDrop { sub })
} else {
cx.emit_span_lint(PATH_STATEMENTS, s.span, PathStatementNoEffect);
}
}
}
@ -1517,21 +1516,19 @@ impl UnusedDelimLint for UnusedBraces {
// let _: A<{produces_literal!()}>;
// ```
// FIXME(const_generics): handle paths when #67075 is fixed.
if let [stmt] = inner.stmts.as_slice() {
if let ast::StmtKind::Expr(ref expr) = stmt.kind {
if !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
&& (ctx != UnusedDelimsCtx::AnonConst
|| (matches!(expr.kind, ast::ExprKind::Lit(_))
&& !expr.span.from_expansion()))
&& ctx != UnusedDelimsCtx::ClosureBody
&& !cx.sess().source_map().is_multiline(value.span)
&& value.attrs.is_empty()
&& !value.span.from_expansion()
&& !inner.span.from_expansion()
{
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
}
}
if let [stmt] = inner.stmts.as_slice()
&& let ast::StmtKind::Expr(ref expr) = stmt.kind
&& !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
&& (ctx != UnusedDelimsCtx::AnonConst
|| (matches!(expr.kind, ast::ExprKind::Lit(_))
&& !expr.span.from_expansion()))
&& ctx != UnusedDelimsCtx::ClosureBody
&& !cx.sess().source_map().is_multiline(value.span)
&& value.attrs.is_empty()
&& !value.span.from_expansion()
&& !inner.span.from_expansion()
{
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
}
}
ast::ExprKind::Let(_, ref expr, _, _) => {

View file

@ -10,8 +10,8 @@ libc = "0.2.73"
[build-dependencies]
# tidy-alphabetical-start
# Pinned so `cargo update` bumps don't cause breakage. Please also update the
# pinned `cc` in `rustc_codegen_ssa` if you update `cc` here.
# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version
# per crate", so if you change this, you need to also change it in `rustc_codegen_ssa`.
cc = "=1.2.16"
# tidy-alphabetical-end

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