Auto merge of #3844 - rust-lang:rustup-2024-08-26, r=RalfJung

Automatic Rustup
This commit is contained in:
bors 2024-08-26 08:02:14 +00:00
commit 2f13379dd1
859 changed files with 10948 additions and 6946 deletions

View file

@ -64,6 +64,10 @@ jobs:
- name: cargo update
# Remove first line that always just says "Updating crates.io index"
run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update library
run: |
echo -e "\nlibrary dependencies:" >> cargo_update.log
cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update rustbook
run: |
echo -e "\nrustbook dependencies:" >> cargo_update.log
@ -74,6 +78,7 @@ jobs:
name: Cargo-lock
path: |
Cargo.lock
library/Cargo.lock
src/tools/rustbook/Cargo.lock
retention-days: 1
- name: upload cargo-update log artifact for use in PR
@ -119,7 +124,7 @@ jobs:
git config user.name github-actions
git config user.email github-actions@github.com
git switch --force-create cargo_update
git add ./Cargo.lock ./src/tools/rustbook/Cargo.lock
git add ./Cargo.lock ./library/Cargo.lock ./src/tools/rustbook/Cargo.lock
git commit --no-verify --file=commit.txt
- name: push

4
.gitignore vendored
View file

@ -56,7 +56,9 @@ build/
/src/tools/x/target
# Created by default with `src/ci/docker/run.sh`
/obj/
/rustc-ice*
## ICE reports
rustc-ice-*.txt
## Temporary files
*~

View file

@ -94,16 +94,6 @@ dependencies = [
"yansi-term",
]
[[package]]
name = "annotate-snippets"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d9b665789884a7e8fb06c84b295e923b03ca51edbb7d08f91a6a50322ecbfe6"
dependencies = [
"anstyle",
"unicode-width",
]
[[package]]
name = "annotate-snippets"
version = "0.11.4"
@ -205,9 +195,9 @@ dependencies = [
[[package]]
name = "ar_archive_writer"
version = "0.4.0"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de11a9d32db3327f981143bdf699ade4d637c6887b13b97e6e91a9154666963c"
checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4"
dependencies = [
"object 0.36.3",
]
@ -420,12 +410,9 @@ version = "0.1.0"
[[package]]
name = "cc"
version = "1.1.13"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
dependencies = [
"shlex",
]
checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437"
[[package]]
name = "cfg-if"
@ -549,6 +536,7 @@ name = "clippy"
version = "0.1.82"
dependencies = [
"anstream",
"cargo_metadata 0.18.1",
"clippy_config",
"clippy_lints",
"clippy_utils",
@ -562,6 +550,7 @@ dependencies = [
"regex",
"rustc_tools_util",
"serde",
"serde_json",
"syn 2.0.75",
"tempfile",
"termize",
@ -576,7 +565,6 @@ name = "clippy_config"
version = "0.1.82"
dependencies = [
"itertools",
"rustc-semver",
"serde",
"toml 0.7.8",
"walkdir",
@ -608,7 +596,6 @@ dependencies = [
"quine-mc_cluskey",
"regex",
"regex-syntax 0.8.4",
"rustc-semver",
"semver",
"serde",
"serde_json",
@ -627,7 +614,6 @@ dependencies = [
"arrayvec",
"clippy_config",
"itertools",
"rustc-semver",
"rustc_apfloat",
]
@ -2240,9 +2226,12 @@ dependencies = [
[[package]]
name = "minifier"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95bbbf96b9ac3482c2a25450b67a15ed851319bc5fabf3b40742ea9066e84282"
checksum = "9aa3f302fe0f8de065d4a2d1ed64f60204623cac58b80cd3c2a83a25d5a7d437"
dependencies = [
"clap",
]
[[package]]
name = "minimal-lexical"
@ -3139,6 +3128,7 @@ dependencies = [
"bstr",
"build_helper",
"gimli 0.31.0",
"libc",
"object 0.36.3",
"regex",
"serde_json",
@ -3211,12 +3201,6 @@ dependencies = [
"num_cpus",
]
[[package]]
name = "rustc-semver"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84"
[[package]]
name = "rustc-stable-hash"
version = "0.1.0"
@ -3642,7 +3626,7 @@ dependencies = [
name = "rustc_errors"
version = "0.0.0"
dependencies = [
"annotate-snippets 0.10.2",
"annotate-snippets 0.11.4",
"derive_setters",
"rustc_ast",
"rustc_ast_pretty",
@ -3702,7 +3686,7 @@ dependencies = [
name = "rustc_fluent_macro"
version = "0.0.0"
dependencies = [
"annotate-snippets 0.10.2",
"annotate-snippets 0.11.4",
"fluent-bundle",
"fluent-syntax",
"proc-macro2",
@ -4552,6 +4536,7 @@ dependencies = [
"bitflags 2.6.0",
"derive-where",
"indexmap",
"rustc-hash",
"rustc_ast_ir",
"rustc_data_structures",
"rustc_index",

View file

@ -143,6 +143,8 @@ Compatibility Notes
- [Turn `proc_macro_back_compat` lint into a hard error.](https://github.com/rust-lang/rust/pull/125596/)
- [Detect unused structs even when implementing private traits](https://github.com/rust-lang/rust/pull/122382/)
- [`std::sync::ReentrantLockGuard<T>` is no longer `Sync` if `T: !Sync`](https://github.com/rust-lang/rust/pull/125527) which means [`std::io::StdoutLock` and `std::io::StderrLock` are no longer Sync](https://github.com/rust-lang/rust/issues/127340)
- [Type inference will fail in some cases due to new implementations of `FromIterator for Box<str>`.](https://github.com/rust-lang/rust/pull/99969/)
Notably, this breaks versions of the `time` crate before 0.3.35, due to no longer inferring the implementation for `Box<[_]>`.
<a id="1.80-Internal-Changes"></a>

View file

@ -2902,6 +2902,17 @@ pub struct AttrItem {
pub tokens: Option<LazyAttrTokenStream>,
}
impl AttrItem {
pub fn is_valid_for_outer_style(&self) -> bool {
self.path == sym::cfg_attr
|| self.path == sym::cfg
|| self.path == sym::forbid
|| self.path == sym::warn
|| self.path == sym::allow
|| self.path == sym::deny
}
}
/// `TraitRef`s appear in impls.
///
/// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all

View file

@ -86,9 +86,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Multiple different abi names may actually be the same ABI
// If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
let source_map = self.tcx.sess.source_map();
let equivalent = (source_map.span_to_snippet(*prev_sp)
!= source_map.span_to_snippet(*abi_span))
.then_some(());
let equivalent = source_map.span_to_snippet(*prev_sp)
!= source_map.span_to_snippet(*abi_span);
self.dcx().emit_err(AbiSpecifiedMultipleTimes {
abi_span: *abi_span,
@ -221,7 +220,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let parent_def_id = self.current_def_id_parent;
let node_id = self.next_node_id();
// HACK(min_generic_const_args): see lower_anon_const
if !expr.is_potential_trivial_const_arg() {
if !self.tcx.features().const_arg_path
|| !expr.is_potential_trivial_const_arg()
{
self.create_def(
parent_def_id,
node_id,

View file

@ -184,7 +184,7 @@ pub struct AbiSpecifiedMultipleTimes {
#[label]
pub prev_span: Span,
#[note]
pub equivalent: Option<()>,
pub equivalent: bool,
}
#[derive(Diagnostic)]

View file

@ -387,7 +387,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let node_id = self.next_node_id();
// HACK(min_generic_const_args): see lower_anon_const
if !arg.is_potential_trivial_const_arg() {
if !self.tcx.features().const_arg_path || !arg.is_potential_trivial_const_arg() {
// Add a definition for the in-band const def.
self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span);
}

View file

@ -1421,7 +1421,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
};
hir::FnHeader {
safety: self.lower_safety(h.safety, default_safety),
asyncness: asyncness,
asyncness,
constness: self.lower_constness(h.constness),
abi: self.lower_extern(h.ext),
}

View file

@ -2358,7 +2358,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
) -> &'hir hir::ConstArg<'hir> {
let ct_kind = match res {
Res::Def(DefKind::ConstParam, _) => {
Res::Def(DefKind::ConstParam, _) if self.tcx.features().const_arg_path => {
let qpath = self.lower_qpath(
ty_id,
&None,
@ -2433,7 +2433,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res());
debug!("res={:?}", maybe_res);
// FIXME(min_generic_const_args): for now we only lower params to ConstArgKind::Path
if let Some(res) = maybe_res
if self.tcx.features().const_arg_path
&& let Some(res) = maybe_res
&& let Res::Def(DefKind::ConstParam, _) = res
&& let ExprKind::Path(qself, path) = &expr.kind
{
@ -2464,7 +2465,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_const_arg`].
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
if c.value.is_potential_trivial_const_arg() {
if self.tcx.features().const_arg_path && c.value.is_potential_trivial_const_arg() {
// HACK(min_generic_const_args): see DefCollector::visit_anon_const
// Over there, we guess if this is a bare param and only create a def if
// we think it's not. However we may can guess wrong (see there for example)

View file

@ -562,10 +562,8 @@ impl<'a> AstValidator<'a> {
FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader,
) {
let report_err = |span| {
self.dcx().emit_err(errors::FnQualifierInExtern {
span: span,
block: self.current_extern_span(),
});
self.dcx()
.emit_err(errors::FnQualifierInExtern { span, block: self.current_extern_span() });
};
match coroutine_kind {
Some(knd) => report_err(knd.span()),
@ -963,14 +961,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self_ty,
items,
}) => {
let error =
|annotation_span, annotation, only_trait: bool| errors::InherentImplCannot {
span: self_ty.span,
annotation_span,
annotation,
self_ty: self_ty.span,
only_trait: only_trait.then_some(()),
};
let error = |annotation_span, annotation, only_trait| errors::InherentImplCannot {
span: self_ty.span,
annotation_span,
annotation,
self_ty: self_ty.span,
only_trait,
};
self.with_in_trait_impl(None, |this| {
this.visibility_not_permitted(
@ -1195,7 +1192,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
} else if where_clauses.after.has_where_token {
self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
span: where_clauses.after.span,
help: self.session.is_nightly_build().then_some(()),
help: self.session.is_nightly_build(),
});
}
}

View file

@ -484,7 +484,7 @@ pub struct InherentImplCannot<'a> {
#[label(ast_passes_type)]
pub self_ty: Span,
#[note(ast_passes_only_trait)]
pub only_trait: Option<()>,
pub only_trait: bool,
}
#[derive(Diagnostic)]
@ -528,7 +528,7 @@ pub struct WhereClauseAfterTypeAlias {
#[primary_span]
pub span: Span,
#[help]
pub help: Option<()>,
pub help: bool,
}
#[derive(Diagnostic)]

View file

@ -556,7 +556,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
gate_all!(postfix_match, "postfix match is experimental");
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
gate_all!(global_registration, "global registration is experimental");
gate_all!(return_type_notation, "return type notation is experimental");

View file

@ -846,7 +846,7 @@ pub fn find_deprecation(
sess.dcx().emit_err(
session_diagnostics::DeprecatedItemSuggestion {
span: mi.span,
is_nightly: sess.is_nightly_build().then_some(()),
is_nightly: sess.is_nightly_build(),
details: (),
},
);

View file

@ -342,7 +342,7 @@ pub(crate) struct DeprecatedItemSuggestion {
pub span: Span,
#[help]
pub is_nightly: Option<()>,
pub is_nightly: bool,
#[note]
pub details: (),

View file

@ -290,7 +290,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
ty: Ty<'_>,
is_index: Option<bool>,
) -> Diag<'infcx> {
let type_name = match (&ty.kind(), is_index) {
let type_name = match (ty.kind(), is_index) {
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
(&ty::Slice(_), _) => "slice",
_ => span_bug!(move_from_span, "this path should not cause illegal move"),

View file

@ -201,7 +201,7 @@ fn place_components_conflict<'tcx>(
let base_ty = base.ty(body, tcx).ty;
match (elem, &base_ty.kind(), access) {
match (elem, base_ty.kind(), access) {
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
| (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {
// The array length is like additional fields on the

View file

@ -2043,9 +2043,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
if let Err(terr) = self.eq_types(
*ty,
if let Err(terr) = self.sub_types(
ty_fn_ptr_from,
*ty,
location.to_locations(),
ConstraintCategory::Cast { unsize_to: None },
) {

View file

@ -149,7 +149,7 @@ fn create_wrapper_function(
}
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr().cast());
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr());
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);

View file

@ -616,7 +616,7 @@ pub(crate) fn run_pass_manager(
llvm::LLVMRustAddModuleFlagU32(
module.module_llvm.llmod(),
llvm::LLVMModFlagBehavior::Error,
c"LTOPostLink".as_ptr().cast(),
c"LTOPostLink".as_ptr(),
1,
);
}

View file

@ -1031,7 +1031,7 @@ unsafe fn embed_bitcode(
let llglobal = llvm::LLVMAddGlobal(
llmod,
common::val_ty(llconst),
c"rustc.embedded.module".as_ptr().cast(),
c"rustc.embedded.module".as_ptr(),
);
llvm::LLVMSetInitializer(llglobal, llconst);
@ -1044,7 +1044,7 @@ unsafe fn embed_bitcode(
let llglobal = llvm::LLVMAddGlobal(
llmod,
common::val_ty(llconst),
c"rustc.embedded.cmdline".as_ptr().cast(),
c"rustc.embedded.cmdline".as_ptr(),
);
llvm::LLVMSetInitializer(llglobal, llconst);
let section = if is_apple {
@ -1054,7 +1054,7 @@ unsafe fn embed_bitcode(
} else {
c".llvmcmd"
};
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
llvm::LLVMSetSection(llglobal, section.as_ptr());
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
} else {
// We need custom section flags, so emit module-level inline assembly.
@ -1107,7 +1107,7 @@ fn create_msvc_imps(
.collect::<Vec<_>>();
for (imp_name, val) in globals {
let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr().cast());
let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr());
llvm::LLVMSetInitializer(imp, val);
llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
}

View file

@ -525,7 +525,7 @@ impl<'ll> CodegenCx<'ll, '_> {
let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
llvm::LLVMAddNamedMetadataOperand(
self.llmod,
c"wasm.custom_sections".as_ptr().cast(),
c"wasm.custom_sections".as_ptr(),
val,
);
}

View file

@ -11,6 +11,7 @@ use rustc_data_structures::base_n::{ToBaseN, ALPHANUMERIC_ONLY};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry;
use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
@ -207,7 +208,7 @@ pub unsafe fn create_module<'ll>(
// If skipping the PLT is enabled, we need to add some module metadata
// to ensure intrinsic calls don't use it.
if !sess.needs_plt() {
let avoid_plt = c"RtLibUseGOT".as_ptr().cast();
let avoid_plt = c"RtLibUseGOT".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
}
@ -215,7 +216,7 @@ pub unsafe fn create_module<'ll>(
// Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast();
let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
@ -226,9 +227,23 @@ pub unsafe fn create_module<'ll>(
}
}
// If we're normalizing integers with CFI, ensure LLVM generated functions do the same.
// See https://github.com/llvm/llvm-project/pull/104826
if sess.is_sanitizer_cfi_normalize_integers_enabled() {
let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr().cast();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
cfi_normalize_integers,
1,
);
}
}
// Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast();
let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
@ -241,10 +256,26 @@ pub unsafe fn create_module<'ll>(
// Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
if sess.is_sanitizer_kcfi_enabled() {
let kcfi = c"kcfi".as_ptr().cast();
let kcfi = c"kcfi".as_ptr();
unsafe {
llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
}
// Add "kcfi-offset" module flag with -Z patchable-function-entry (See
// https://reviews.llvm.org/D141172).
let pfe =
PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry);
if pfe.prefix() > 0 {
let kcfi_offset = c"kcfi-offset".as_ptr().cast();
unsafe {
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
kcfi_offset,
pfe.prefix().into(),
);
}
}
}
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
@ -280,26 +311,26 @@ pub unsafe fn create_module<'ll>(
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"branch-target-enforcement".as_ptr().cast(),
c"branch-target-enforcement".as_ptr(),
bti.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address".as_ptr().cast(),
c"sign-return-address".as_ptr(),
pac_ret.is_some().into(),
);
let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-all".as_ptr().cast(),
c"sign-return-address-all".as_ptr(),
pac_opts.leaf.into(),
);
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Min,
c"sign-return-address-with-bkey".as_ptr().cast(),
c"sign-return-address-with-bkey".as_ptr(),
u32::from(pac_opts.key == PAuthKey::B),
);
}
@ -317,7 +348,7 @@ pub unsafe fn create_module<'ll>(
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-branch".as_ptr().cast(),
c"cf-protection-branch".as_ptr(),
1,
);
}
@ -327,7 +358,7 @@ pub unsafe fn create_module<'ll>(
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Override,
c"cf-protection-return".as_ptr().cast(),
c"cf-protection-return".as_ptr(),
1,
);
}
@ -338,7 +369,7 @@ pub unsafe fn create_module<'ll>(
llvm::LLVMRustAddModuleFlagU32(
llmod,
llvm::LLVMModFlagBehavior::Error,
c"Virtual Function Elim".as_ptr().cast(),
c"Virtual Function Elim".as_ptr(),
1,
);
}

View file

@ -34,8 +34,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, '
let c_section_var_name = c"__rustc_debug_gdb_scripts_section__";
let section_var_name = c_section_var_name.to_str().unwrap();
let section_var =
unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr().cast()) };
let section_var = unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr()) };
section_var.unwrap_or_else(|| {
let mut section_contents = Vec::new();
@ -70,7 +69,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global<'ll>(cx: &CodegenCx<'ll, '
let section_var = cx
.define_global(section_var_name, llvm_type)
.unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name));
llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr().cast());
llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr());
llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);

View file

@ -952,7 +952,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
producer.as_ptr().cast(),
producer.len(),
tcx.sess.opts.optimize != config::OptLevel::No,
c"".as_ptr().cast(),
c"".as_ptr(),
0,
// NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead
// put the path supplied to `MCSplitDwarfFile` into the debug info of the final

View file

@ -109,7 +109,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
llvm::LLVMRustAddModuleFlagU32(
self.llmod,
llvm::LLVMModFlagBehavior::Warning,
c"Dwarf Version".as_ptr().cast(),
c"Dwarf Version".as_ptr(),
dwarf_version,
);
} else {
@ -117,7 +117,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
llvm::LLVMRustAddModuleFlagU32(
self.llmod,
llvm::LLVMModFlagBehavior::Warning,
c"CodeView".as_ptr().cast(),
c"CodeView".as_ptr(),
1,
)
}
@ -126,7 +126,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
llvm::LLVMRustAddModuleFlagU32(
self.llmod,
llvm::LLVMModFlagBehavior::Warning,
c"Debug Info Version".as_ptr().cast(),
c"Debug Info Version".as_ptr(),
llvm::LLVMRustDebugMetadataVersion(),
);
}
@ -570,7 +570,17 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
inlined_at: Option<&'ll DILocation>,
span: Span,
) -> &'ll DILocation {
let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
// When emitting debugging information, DWARF (i.e. everything but MSVC)
// treats line 0 as a magic value meaning that the code could not be
// attributed to any line in the source. That's also exactly what dummy
// spans are. Make that equivalence here, rather than passing dummy spans
// to lookup_debug_loc, which will return line 1 for them.
let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
(0, 0)
} else {
let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
(line, col)
};
unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) }
}

View file

@ -5,10 +5,10 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
ar_archive_writer = "0.4.0"
ar_archive_writer = "0.4.2"
arrayvec = { version = "0.7", default-features = false }
bitflags = "2.4.1"
cc = "1.0.90"
cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013
either = "1.5.0"
itertools = "0.12"
jobserver = "0.1.28"

View file

@ -108,7 +108,11 @@ pub trait ArchiveBuilderBuilder {
&exports,
machine,
!sess.target.is_like_msvc,
/*comdat=*/ false,
// Enable compatibility with MSVC's `/WHOLEARCHIVE` flag.
// Without this flag a duplicate symbol error would be emitted
// when linking a rust staticlib using `/WHOLEARCHIVE`.
// See #129020
true,
) {
sess.dcx()
.emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() });
@ -121,7 +125,7 @@ pub trait ArchiveBuilderBuilder {
rlib: &'a Path,
outdir: &Path,
bundled_lib_file_names: &FxIndexSet<Symbol>,
) -> Result<(), ExtractBundledLibsError<'_>> {
) -> Result<(), ExtractBundledLibsError<'a>> {
let archive_map = unsafe {
Mmap::map(
File::open(rlib)

View file

@ -1500,7 +1500,7 @@ impl<'a> Linker for L4Bender<'a> {
impl<'a> L4Bender<'a> {
pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
L4Bender { cmd, sess: sess, hinted_static: false }
L4Bender { cmd, sess, hinted_static: false }
}
fn hint_static(&mut self) {
@ -1520,7 +1520,7 @@ pub struct AixLinker<'a> {
impl<'a> AixLinker<'a> {
pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
AixLinker { cmd, sess: sess, hinted_static: None }
AixLinker { cmd, sess, hinted_static: None }
}
fn hint_static(&mut self) {

View file

@ -419,7 +419,7 @@ const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
const_eval_unstable_in_stable =
const-stable function cannot use `#[feature({$gate})]`
.unstable_sugg = if it is not part of the public API, make this function unstably const
.bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
.bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (but requires team approval)
const_eval_unterminated_c_string =
reading a null-terminated string starting at {$pointer} with no null found before end of allocation

View file

@ -575,10 +575,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::UnaryOp(_, operand) => {
let ty = operand.ty(self.body, self.tcx);
if is_int_bool_or_char(ty) {
// Int, bool, and char operations are fine.
} else if ty.is_floating_point() {
self.check_op(ops::FloatingPointOp);
if is_int_bool_float_or_char(ty) {
// Int, bool, float, and char operations are fine.
} else {
span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty);
}
@ -588,8 +586,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
let lhs_ty = lhs.ty(self.body, self.tcx);
let rhs_ty = rhs.ty(self.body, self.tcx);
if is_int_bool_or_char(lhs_ty) && is_int_bool_or_char(rhs_ty) {
// Int, bool, and char operations are fine.
if is_int_bool_float_or_char(lhs_ty) && is_int_bool_float_or_char(rhs_ty) {
// Int, bool, float, and char operations are fine.
} else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() {
assert_matches!(
op,
@ -603,8 +601,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
);
self.check_op(ops::RawPtrComparison);
} else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() {
self.check_op(ops::FloatingPointOp);
} else {
span_bug!(
self.span,
@ -1009,8 +1005,8 @@ fn place_as_reborrow<'tcx>(
}
}
fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
ty.is_bool() || ty.is_integral() || ty.is_char()
fn is_int_bool_float_or_char(ty: Ty<'_>) -> bool {
ty.is_bool() || ty.is_integral() || ty.is_char() || ty.is_floating_point()
}
fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {

View file

@ -55,28 +55,6 @@ pub trait NonConstOp<'tcx>: std::fmt::Debug {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx>;
}
#[derive(Debug)]
pub struct FloatingPointOp;
impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() == hir::ConstContext::ConstFn {
Status::Unstable(sym::const_fn_floating_point_arithmetic)
} else {
Status::Allowed
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
feature_err(
&ccx.tcx.sess,
sym::const_fn_floating_point_arithmetic,
span,
format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
)
}
}
/// A function call where the callee is a pointer.
#[derive(Debug)]
pub struct FnCallIndirect;
@ -384,7 +362,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
ccx.dcx().create_err(errors::UnallowedHeapAllocations {
span,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0010).then_some(()),
teach: ccx.tcx.sess.teach(E0010),
})
}
}
@ -440,22 +418,12 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow {
DiagImportance::Secondary
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
// FIXME: Maybe a more elegant solution to this if else case
if let hir::ConstContext::Static(_) = ccx.const_kind() {
ccx.dcx().create_err(errors::InteriorMutableDataRefer {
span,
opt_help: Some(()),
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0492).then_some(()),
})
} else {
ccx.dcx().create_err(errors::InteriorMutableDataRefer {
span,
opt_help: None,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0492).then_some(()),
})
}
ccx.dcx().create_err(errors::InteriorMutableDataRefer {
span,
opt_help: matches!(ccx.const_kind(), hir::ConstContext::Static(_)),
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0492),
})
}
}
@ -481,12 +449,12 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
hir::BorrowKind::Raw => ccx.tcx.dcx().create_err(errors::UnallowedMutableRaw {
span,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0764).then_some(()),
teach: ccx.tcx.sess.teach(E0764),
}),
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs {
span,
kind: ccx.const_kind(),
teach: ccx.tcx.sess.teach(E0764).then_some(()),
teach: ccx.tcx.sess.teach(E0764),
}),
}
}

View file

@ -22,6 +22,7 @@ pub enum ConstEvalErrKind {
RecursiveStatic,
AssertFailure(AssertKind<ConstInt>),
Panic { msg: Symbol, line: u32, col: u32, file: Symbol },
WriteThroughImmutablePointer,
}
impl MachineStopType for ConstEvalErrKind {
@ -35,12 +36,16 @@ impl MachineStopType for ConstEvalErrKind {
Panic { .. } => const_eval_panic,
RecursiveStatic => const_eval_recursive_static,
AssertFailure(x) => x.diagnostic_message(),
WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer,
}
}
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) {
use ConstEvalErrKind::*;
match *self {
RecursiveStatic | ConstAccessesMutGlobal | ModifiedGlobal => {}
RecursiveStatic
| ConstAccessesMutGlobal
| ModifiedGlobal
| WriteThroughImmutablePointer => {}
AssertFailure(kind) => kind.add_args(adder),
Panic { msg, line, col, file } => {
adder("msg".into(), msg.into_diag_arg());
@ -159,6 +164,7 @@ where
/// Emit a lint from a const-eval situation, with a backtrace.
// Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future!
#[allow(unused)]
pub(super) fn lint<'tcx, L>(
tcx: TyCtxtAt<'tcx>,
machine: &CompileTimeMachine<'tcx>,

View file

@ -12,7 +12,6 @@ use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::{bug, mir};
use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::abi::{Align, Size};
@ -40,7 +39,10 @@ const TINY_LINT_TERMINATOR_LIMIT: usize = 20;
/// power of two of interpreted terminators.
const PROGRESS_INDICATOR_START: usize = 4_000_000;
/// Extra machine state for CTFE, and the Machine instance
/// Extra machine state for CTFE, and the Machine instance.
//
// Should be public because out-of-tree rustc consumers need this
// if they want to interact with constant values.
pub struct CompileTimeMachine<'tcx> {
/// The number of terminators that have been evaluated.
///
@ -160,7 +162,7 @@ impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
}
}
pub(crate) type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum MemoryKind {
@ -729,8 +731,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
}
fn before_memory_write(
tcx: TyCtxtAt<'tcx>,
machine: &mut Self,
_tcx: TyCtxtAt<'tcx>,
_machine: &mut Self,
_alloc_extra: &mut Self::AllocExtra,
(_alloc_id, immutable): (AllocId, bool),
range: AllocRange,
@ -741,9 +743,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
}
// Reject writes through immutable pointers.
if immutable {
super::lint(tcx, machine, WRITES_THROUGH_IMMUTABLE_POINTER, |frames| {
crate::errors::WriteThroughImmutablePointer { frames }
});
return Err(ConstEvalErrKind::WriteThroughImmutablePointer.into());
}
// Everything else is fine.
Ok(())

View file

@ -151,7 +151,7 @@ pub(crate) struct UnallowedMutableRefs {
pub span: Span,
pub kind: ConstContext,
#[note(const_eval_teach_note)]
pub teach: Option<()>,
pub teach: bool,
}
#[derive(Diagnostic)]
@ -161,7 +161,7 @@ pub(crate) struct UnallowedMutableRaw {
pub span: Span,
pub kind: ConstContext,
#[note(const_eval_teach_note)]
pub teach: Option<()>,
pub teach: bool,
}
#[derive(Diagnostic)]
#[diag(const_eval_non_const_fmt_macro_call, code = E0015)]
@ -196,7 +196,7 @@ pub(crate) struct UnallowedHeapAllocations {
pub span: Span,
pub kind: ConstContext,
#[note(const_eval_teach_note)]
pub teach: Option<()>,
pub teach: bool,
}
#[derive(Diagnostic)]
@ -214,10 +214,10 @@ pub(crate) struct InteriorMutableDataRefer {
#[label]
pub span: Span,
#[help]
pub opt_help: Option<()>,
pub opt_help: bool,
pub kind: ConstContext,
#[note(const_eval_teach_note)]
pub teach: Option<()>,
pub teach: bool,
}
#[derive(Diagnostic)]
@ -407,13 +407,6 @@ pub struct ConstEvalError {
pub frame_notes: Vec<FrameNote>,
}
#[derive(LintDiagnostic)]
#[diag(const_eval_write_through_immutable_pointer)]
pub struct WriteThroughImmutablePointer {
#[subdiagnostic]
pub frames: Vec<FrameNote>,
}
#[derive(Diagnostic)]
#[diag(const_eval_nullary_intrinsic_fail)]
pub struct NullaryIntrinsicError {

View file

@ -388,7 +388,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (src_pointee_ty, dest_pointee_ty) =
self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);
match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
match (src_pointee_ty.kind(), dest_pointee_ty.kind()) {
(&ty::Array(_, length), &ty::Slice(_)) => {
let ptr = self.read_pointer(src)?;
let val = Immediate::new_slice(
@ -478,9 +478,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
dest: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
match (src.layout.ty.kind(), cast_ty.ty.kind()) {
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(c, _))
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, *s, *c),
| (&ty::RawPtr(s, _), &ty::RawPtr(c, _)) => self.unsize_into_ptr(src, dest, s, c),
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b); // implies same number of fields

View file

@ -319,6 +319,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
// some fieldless enum variants can have non-zero size but still `Aggregate` ABI... try
// to detect those here and also give them no data
_ if matches!(layout.abi, Abi::Aggregate { .. })
&& matches!(layout.variants, abi::Variants::Single { .. })
&& matches!(&layout.fields, abi::FieldsShape::Arbitrary { offsets, .. } if offsets.len() == 0) =>
{
Immediate::Uninit
@ -328,8 +329,9 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
assert_eq!(offset.bytes(), 0);
assert!(
match (self.layout.abi, layout.abi) {
(Abi::Scalar(..), Abi::Scalar(..)) => true,
(Abi::ScalarPair(..), Abi::ScalarPair(..)) => true,
(Abi::Scalar(l), Abi::Scalar(r)) => l.size(cx) == r.size(cx),
(Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) =>
l1.size(cx) == r1.size(cx) && l2.size(cx) == r2.size(cx),
_ => false,
},
"cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}",
@ -344,16 +346,23 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
(Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => {
assert_matches!(layout.abi, Abi::Scalar(..));
Immediate::from(if offset.bytes() == 0 {
debug_assert_eq!(layout.size, a.size(cx));
// It is "okay" to transmute from `usize` to a pointer (GVN relies on that).
// So only compare the size.
assert_eq!(layout.size, a.size(cx));
a_val
} else {
debug_assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi));
debug_assert_eq!(layout.size, b.size(cx));
assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi));
assert_eq!(layout.size, b.size(cx));
b_val
})
}
// everything else is a bug
_ => bug!("invalid field access on immediate {}, layout {:#?}", self, self.layout),
_ => bug!(
"invalid field access on immediate {} at offset {}, original layout {:#?}",
self,
offset.bytes(),
self.layout
),
};
ImmTy::from_immediate(inner_val, layout)

View file

@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
annotate-snippets = "0.10"
annotate-snippets = "0.11"
derive_setters = "0.1.6"
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }

View file

@ -5,7 +5,7 @@
//!
//! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/
use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
use annotate_snippets::{Renderer, Snippet};
use rustc_data_structures::sync::Lrc;
use rustc_error_messages::FluentArgs;
use rustc_span::source_map::SourceMap;
@ -83,15 +83,17 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default()
}
/// Maps `diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType {
/// Maps [`crate::Level`] to [`annotate_snippets::Level`]
fn annotation_level_for_level(level: Level) -> annotate_snippets::Level {
match level {
Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => AnnotationType::Error,
Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning,
Level::Note | Level::OnceNote => AnnotationType::Note,
Level::Help | Level::OnceHelp => AnnotationType::Help,
Level::Bug | Level::Fatal | Level::Error | Level::DelayedBug => {
annotate_snippets::Level::Error
}
Level::ForceWarning(_) | Level::Warning => annotate_snippets::Level::Warning,
Level::Note | Level::OnceNote => annotate_snippets::Level::Note,
Level::Help | Level::OnceHelp => annotate_snippets::Level::Help,
// FIXME(#59346): Not sure how to map this level
Level::FailureNote => AnnotationType::Error,
Level::FailureNote => annotate_snippets::Level::Error,
Level::Allow => panic!("Should not call with Allow"),
Level::Expect(_) => panic!("Should not call with Expect"),
}
@ -180,42 +182,29 @@ impl AnnotateSnippetEmitter {
})
.collect();
let code = code.map(|code| code.to_string());
let snippet = Snippet {
title: Some(Annotation {
label: Some(&message),
id: code.as_deref(),
annotation_type: annotation_type_for_level(*level),
}),
footer: vec![],
slices: annotated_files
.iter()
.map(|(file_name, source, line_index, annotations)| {
Slice {
source,
line_start: *line_index,
origin: Some(file_name),
// FIXME(#59346): Not really sure when `fold` should be true or false
fold: false,
annotations: annotations
.iter()
.map(|annotation| SourceAnnotation {
range: (
annotation.start_col.display,
annotation.end_col.display,
),
label: annotation.label.as_deref().unwrap_or_default(),
annotation_type: annotation_type_for_level(*level),
})
.collect(),
}
})
.collect(),
};
let snippets =
annotated_files.iter().map(|(file_name, source, line_index, annotations)| {
Snippet::source(source)
.line_start(*line_index)
.origin(file_name)
// FIXME(#59346): Not really sure when `fold` should be true or false
.fold(false)
.annotations(annotations.iter().map(|annotation| {
annotation_level_for_level(*level)
.span(annotation.start_col.display..annotation.end_col.display)
.label(annotation.label.as_deref().unwrap_or_default())
}))
});
let mut message = annotation_level_for_level(*level).title(&message).snippets(snippets);
if let Some(code) = code.as_deref() {
message = message.id(code)
}
// FIXME(#59346): Figure out if we can _always_ print to stderr or not.
// `emitter.rs` has the `Destination` enum that lists various possible output
// destinations.
let renderer = Renderer::plain().anonymized_line_numbers(self.ui_testing);
eprintln!("{}", renderer.render(snippet))
eprintln!("{}", renderer.render(message))
}
// FIXME(#59346): Is it ok to return None if there's no source_map?
}

View file

@ -80,7 +80,7 @@ pub fn entrypoint(txt: &str) -> MdStream<'_> {
}
/// Parse a buffer with specified context
fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'_> {
fn parse_recursive<'a>(buf: &'a [u8], ctx: Context) -> MdStream<'a> {
use ParseOpt as Po;
use Prev::{Escape, Newline, Whitespace};

View file

@ -59,7 +59,7 @@ pub trait Translate {
&'a self,
message: &'a DiagMessage,
args: &'a FluentArgs<'_>,
) -> Result<Cow<'_, str>, TranslateError<'_>> {
) -> Result<Cow<'a, str>, TranslateError<'a>> {
trace!(?message, ?args);
let (identifier, attr) = match message {
DiagMessage::Str(msg) | DiagMessage::Translated(msg) => {

View file

@ -281,7 +281,7 @@ pub(crate) struct IncompleteParse<'a> {
pub macro_path: &'a ast::Path,
pub kind_name: &'a str,
#[note(expand_macro_expands_to_match_arm)]
pub expands_to_match_arm: Option<()>,
pub expands_to_match_arm: bool,
#[suggestion(
expand_suggestion_add_semi,

View file

@ -1031,7 +1031,7 @@ pub(crate) fn ensure_complete_parse<'a>(
label_span: span,
macro_path,
kind_name,
expands_to_match_arm: expands_to_match_arm.then_some(()),
expands_to_match_arm,
add_semicolon,
});
}

View file

@ -115,6 +115,8 @@ declare_features! (
(accepted, conservative_impl_trait, "1.26.0", Some(34511)),
/// Allows calling constructor functions in `const fn`.
(accepted, const_constructor, "1.40.0", Some(61456)),
/// Allows basic arithmetic on floating point types in a `const fn`.
(accepted, const_fn_floating_point_arithmetic, "CURRENT_RUSTC_VERSION", Some(57241)),
/// Allows using and casting function pointers in a `const fn`.
(accepted, const_fn_fn_ptr_basics, "1.61.0", Some(57563)),
/// Allows trait bounds in `const fn`.
@ -309,6 +311,8 @@ declare_features! (
(accepted, param_attrs, "1.39.0", Some(60406)),
/// Allows parentheses in patterns.
(accepted, pattern_parentheses, "1.31.0", Some(51087)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
(accepted, precise_capturing, "CURRENT_RUSTC_VERSION", Some(123432)),
/// Allows procedural macros in `proc-macro` crates.
(accepted, proc_macro, "1.29.0", Some(38356)),
/// Allows multi-segment paths in attributes and derives.

View file

@ -641,6 +641,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ErrorFollowing, EncodeCrossCrate::Yes,
"rustc_deprecated_safe_2024 is supposed to be used in libstd only",
),
rustc_attr!(
rustc_pub_transparent, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
"used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
),
// ==========================================================================

View file

@ -193,6 +193,8 @@ declare_features! (
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
/// Allows identifying the `compiler_builtins` crate.
(internal, compiler_builtins, "1.13.0", None),
/// Gating for a new desugaring of const arguments of usages of const parameters
(internal, const_arg_path, "1.81.0", None),
/// Allows writing custom MIR
(internal, custom_mir, "1.65.0", None),
/// Outputs useful `assert!` messages
@ -400,8 +402,6 @@ declare_features! (
(incomplete, const_closures, "1.68.0", Some(106003)),
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
(unstable, const_extern_fn, "1.40.0", Some(64926)),
/// Allows basic arithmetic on floating point types in a `const fn`.
(unstable, const_fn_floating_point_arithmetic, "1.48.0", Some(57241)),
/// Allows `for _ in _` loops in const contexts.
(unstable, const_for, "1.56.0", Some(87575)),
/// Allows using `&mut` in constant functions.
@ -561,8 +561,6 @@ declare_features! (
(unstable, patchable_function_entry, "1.81.0", Some(123115)),
/// Allows postfix match `expr.match { ... }`
(unstable, postfix_match, "1.79.0", Some(121618)),
/// Allows `use<'a, 'b, A, B>` in `impl Trait + use<...>` for precise capture of generic args.
(unstable, precise_capturing, "1.79.0", Some(123432)),
/// Allows macro attributes on expressions, statements and non-inline modules.
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.

View file

@ -8,7 +8,7 @@ proc-macro = true
[dependencies]
# tidy-alphabetical-start
annotate-snippets = "0.10"
annotate-snippets = "0.11"
fluent-bundle = "0.15.2"
fluent-syntax = "0.11"
proc-macro2 = "1"

View file

@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use std::fs::read_to_string;
use std::path::{Path, PathBuf};
use annotate_snippets::{Annotation, AnnotationType, Renderer, Slice, Snippet, SourceAnnotation};
use annotate_snippets::{Renderer, Snippet};
use fluent_bundle::{FluentBundle, FluentError, FluentResource};
use fluent_syntax::ast::{
Attribute, Entry, Expression, Identifier, InlineExpression, Message, Pattern, PatternElement,
@ -154,27 +154,15 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
.unwrap()
.0;
let snippet = Snippet {
title: Some(Annotation {
label: Some(&err),
id: None,
annotation_type: AnnotationType::Error,
}),
footer: vec![],
slices: vec![Slice {
source: this.source(),
line_start,
origin: Some(&relative_ftl_path),
fold: true,
annotations: vec![SourceAnnotation {
label: "",
annotation_type: AnnotationType::Error,
range: (pos.start, pos.end - 1),
}],
}],
};
let message = annotate_snippets::Level::Error.title(&err).snippet(
Snippet::source(this.source())
.line_start(line_start)
.origin(&relative_ftl_path)
.fold(true)
.annotation(annotate_snippets::Level::Error.span(pos.start..pos.end - 1)),
);
let renderer = Renderer::plain();
eprintln!("{}\n", renderer.render(snippet));
eprintln!("{}\n", renderer.render(message));
}
return failed(&crate_name);

View file

@ -2773,7 +2773,6 @@ impl PreciseCapturingArg<'_> {
/// resolution to. Lifetimes don't have this problem, and for them, it's actually
/// kind of detrimental to use a custom node type versus just using [`Lifetime`],
/// since resolve_bound_vars operates on `Lifetime`s.
// FIXME(precise_capturing): Investigate storing this as a path instead?
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PreciseCapturingNonLifetimeArg {
pub hir_id: HirId,

View file

@ -529,7 +529,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
match tcx.named_bound_var(hir_id) {
Some(ResolvedArg::EarlyBound(def_id)) => {
expected_captures.insert(def_id);
expected_captures.insert(def_id.to_def_id());
// Make sure we allow capturing these lifetimes through `Self` and
// `T::Assoc` projection syntax, too. These will occur when we only
@ -538,7 +538,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
// feature -- see <https://github.com/rust-lang/rust/pull/115659>.
if let DefKind::LifetimeParam = tcx.def_kind(def_id)
&& let Some(def_id) = tcx
.map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
.map_opaque_lifetime_to_parent_lifetime(def_id)
.opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))
{
shadowed_captures.insert(def_id);
@ -1259,7 +1259,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
ty::Adt(def, args) => {
if !def.did().is_local() {
if !def.did().is_local() && !tcx.has_attr(def.did(), sym::rustc_pub_transparent)
{
let non_exhaustive = def.is_variant_list_non_exhaustive()
|| def
.variants()
@ -1564,7 +1565,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD
// * compare the param span to the pred span to detect lone user-written `Sized` bounds
let has_explicit_bounds = bounded_params.is_empty()
|| (*bounded_params).get(&param.index).is_some_and(|&&pred_sp| pred_sp != span);
let const_param_help = (!has_explicit_bounds).then_some(());
let const_param_help = !has_explicit_bounds;
let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
span,

View file

@ -7,7 +7,8 @@ use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT
use rustc_middle::span_bug;
use rustc_middle::traits::{ObligationCause, Reveal};
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor,
};
use rustc_span::Span;
use rustc_trait_selection::regions::InferCtxtRegionExt;
@ -177,6 +178,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
return;
};
if trait_bounds.references_error() || impl_bounds.references_error() {
return;
}
// For quicker lookup, use an `IndexSet` (we don't use one earlier because
// it's not foldable..).
// Also, We have to anonymize binders in these types because they may contain

View file

@ -216,7 +216,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
}
if sig.header.asyncness.is_async() {
let span = tcx.def_span(it.owner_id);
tcx.dcx().emit_err(errors::StartAsync { span: span });
tcx.dcx().emit_err(errors::StartAsync { span });
error = true;
}

View file

@ -747,7 +747,7 @@ fn region_known_to_outlive<'tcx>(
region_b: ty::Region<'tcx>,
) -> bool {
test_region_obligations(tcx, id, param_env, wf_tys, |infcx| {
infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP), region_b, region_a);
infcx.sub_regions(infer::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a);
})
}
@ -1972,8 +1972,7 @@ fn report_bivariance<'tcx>(
}
let const_param_help =
matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds)
.then_some(());
matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds);
let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
span: param.span,

View file

@ -392,7 +392,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
}
fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
if let RegionInferReason::BorrowedObjectLifetimeDefault = reason {
if let RegionInferReason::ObjectLifetimeDefault = reason {
let e = struct_span_code_err!(
self.dcx(),
span,

View file

@ -13,7 +13,6 @@ use rustc_ast::visit::walk_list;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node};
use rustc_macros::extension;
@ -22,7 +21,7 @@ use rustc_middle::middle::resolve_bound_vars::*;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
@ -32,7 +31,7 @@ use crate::errors;
impl ResolvedArg {
fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
debug!("ResolvedArg::early: def_id={:?}", param.def_id);
(param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id()))
(param.def_id, ResolvedArg::EarlyBound(param.def_id))
}
fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
@ -41,10 +40,10 @@ impl ResolvedArg {
"ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
idx, param, depth, param.def_id,
);
(param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id()))
(param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id))
}
fn id(&self) -> Option<DefId> {
fn id(&self) -> Option<LocalDefId> {
match *self {
ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None,
@ -288,13 +287,14 @@ fn late_arg_as_bound_arg<'tcx>(
) -> ty::BoundVariableKind {
match arg {
ResolvedArg::LateBound(_, _, def_id) => {
let name = tcx.hir().name(tcx.local_def_id_to_hir_id(def_id.expect_local()));
let def_id = def_id.to_def_id();
let name = tcx.item_name(def_id);
match param.kind {
GenericParamKind::Lifetime { .. } => {
ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name))
ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
}
GenericParamKind::Type { .. } => {
ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(*def_id, name))
ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
}
GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
}
@ -717,7 +717,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
// In the future, this should be fixed and this error should be removed.
let def = self.map.defs.get(&lifetime.hir_id).copied();
let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue };
let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id))
@ -1150,7 +1149,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
.param_def_id_to_index(self.tcx, region_def_id.to_def_id())
.is_some()
{
break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id()));
break Some(ResolvedArg::EarlyBound(region_def_id));
}
break None;
}
@ -1259,7 +1258,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
kind => span_bug!(
use_span,
"did not expect to resolve lifetime to {}",
kind.descr(param_def_id)
kind.descr(param_def_id.to_def_id())
),
};
def = ResolvedArg::Error(guar);
@ -1277,10 +1276,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
kind: hir::ImplItemKind::Fn(..),
..
}) => {
def = ResolvedArg::Free(owner_id.to_def_id(), def.id().unwrap());
def = ResolvedArg::Free(owner_id.def_id, def.id().unwrap());
}
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => {
def = ResolvedArg::Free(closure.def_id.to_def_id(), def.id().unwrap());
def = ResolvedArg::Free(closure.def_id, def.id().unwrap());
}
_ => {}
}
@ -1351,7 +1350,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
.param_def_id_to_index(self.tcx, param_def_id.to_def_id())
.is_some()
{
break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id()));
break Some(ResolvedArg::EarlyBound(param_def_id));
}
break None;
}

View file

@ -331,7 +331,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
owner_def_id: LocalDefId,
) -> Ty<'_> {
) -> Ty<'tcx> {
let tables = tcx.typeck(owner_def_id);
// Check that all of the opaques we inferred during HIR are compatible.

View file

@ -1606,7 +1606,7 @@ pub(crate) struct UnusedGenericParameter {
#[subdiagnostic]
pub help: UnusedGenericParameterHelp,
#[help(hir_analysis_const_param_help)]
pub const_param_help: Option<()>,
pub const_param_help: bool,
}
#[derive(Diagnostic)]
@ -1643,9 +1643,9 @@ pub(crate) struct UnconstrainedGenericParameter {
pub param_name: Symbol,
pub param_def_kind: &'static str,
#[note(hir_analysis_const_param_note)]
pub const_param_note: Option<()>,
pub const_param_note: bool,
#[note(hir_analysis_const_param_note2)]
pub const_param_note2: Option<()>,
pub const_param_note2: bool,
}
#[derive(Diagnostic)]

View file

@ -608,7 +608,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
match &self_ty.kind() {
match self_ty.kind() {
// Point at the type that couldn't satisfy the bound.
ty::Adt(def, _) => {
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)

View file

@ -15,11 +15,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
///
/// *Bare* trait object types are ones that aren't preceded by the keyword `dyn`.
/// In edition 2021 and onward we emit a hard error for them.
pub(super) fn prohibit_or_lint_bare_trait_object_ty(
&self,
self_ty: &hir::Ty<'_>,
in_path: bool,
) {
pub(super) fn prohibit_or_lint_bare_trait_object_ty(&self, self_ty: &hir::Ty<'_>) {
let tcx = self.tcx();
let hir::TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
@ -28,6 +24,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
return;
};
let in_path = match tcx.parent_hir_node(self_ty.hir_id) {
hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Path(hir::QPath::TypeRelative(qself, _)),
..
})
| hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
..
})
| hir::Node::Pat(hir::Pat {
kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)),
..
}) if qself.hir_id == self_ty.hir_id => true,
_ => false,
};
let needs_bracket = in_path
&& !tcx
.sess

View file

@ -85,10 +85,9 @@ pub enum PredicateFilter {
#[derive(Debug)]
pub enum RegionInferReason<'a> {
/// Lifetime on a trait object behind a reference.
/// This allows inferring information from the reference.
BorrowedObjectLifetimeDefault,
/// A trait object's lifetime.
/// Lifetime on a trait object that is spelled explicitly, e.g. `+ 'a` or `+ '_`.
ExplicitObjectLifetime,
/// A trait object's lifetime when it is elided, e.g. `dyn Any`.
ObjectLifetimeDefault,
/// Generic lifetime parameter
Param(&'a ty::GenericParamDef),
@ -296,25 +295,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static,
Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
let name = lifetime_name(def_id.expect_local());
let name = lifetime_name(def_id);
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(index),
kind: ty::BrNamed(def_id, name),
kind: ty::BrNamed(def_id.to_def_id(), name),
};
ty::Region::new_bound(tcx, debruijn, br)
}
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
let name = tcx.hir().ty_param_name(def_id.expect_local());
let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
let name = tcx.hir().ty_param_name(def_id);
let item_def_id = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name })
}
Some(rbv::ResolvedArg::Free(scope, id)) => {
let name = lifetime_name(id.expect_local());
ty::Region::new_late_param(tcx, scope, ty::BrNamed(id, name))
let name = lifetime_name(id);
ty::Region::new_late_param(
tcx,
scope.to_def_id(),
ty::BrNamed(id.to_def_id(), name),
)
// (*) -- not late-bound, won't change
}
@ -959,11 +962,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
\n where\n T: {qself_str},\n{}",
where_bounds.join(",\n"),
));
}
let reported = err.emit();
if !where_bounds.is_empty() {
let reported = err.emit();
return Err(reported);
}
err.emit();
}
Ok(bound)
@ -1054,7 +1056,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&qself_ty.kind(), qself_res) {
let bound = match (qself_ty.kind(), qself_res) {
(_, Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. }) => {
// `Self` in an impl of a trait -- we have a concrete self type and a
// trait reference.
@ -1954,15 +1956,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let tcx = self.tcx();
match tcx.named_bound_var(hir_id) {
Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
let name = tcx.item_name(def_id);
let name = tcx.item_name(def_id.to_def_id());
let br = ty::BoundTy {
var: ty::BoundVar::from_u32(index),
kind: ty::BoundTyKind::Param(def_id, name),
kind: ty::BoundTyKind::Param(def_id.to_def_id(), name),
};
Ty::new_bound(tcx, debruijn, br)
}
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
let def_id = def_id.expect_local();
let item_def_id = tcx.hir().ty_param_owner(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
@ -1983,10 +1984,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let item_def_id = tcx.parent(def_id);
let item_def_id = tcx.local_parent(def_id);
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.item_name(def_id);
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
let name = tcx.item_name(def_id.to_def_id());
ty::Const::new_param(tcx, ty::ParamConst::new(index, name))
}
Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => {
@ -1997,16 +1998,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
/// Lower a type from the HIR to our internal notion of a type.
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
self.lower_ty_common(hir_ty, false, false)
}
/// Lower a type inside of a path from the HIR to our internal notion of a type.
pub fn lower_ty_in_path(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
self.lower_ty_common(hir_ty, false, true)
}
fn lower_delegation_ty(&self, idx: hir::InferDelegationKind) -> Ty<'tcx> {
let delegation_sig = self.tcx().inherit_sig_for_delegation_item(self.item_def_id());
match idx {
@ -2024,7 +2015,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// 2. `in_path`: Whether the type appears inside of a path.
/// Used to provide correct diagnostics for bare trait object types.
#[instrument(level = "debug", skip(self), ret)]
fn lower_ty_common(&self, hir_ty: &hir::Ty<'tcx>, borrowed: bool, in_path: bool) -> Ty<'tcx> {
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
let tcx = self.tcx();
let result_ty = match &hir_ty.kind {
@ -2034,7 +2025,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir::TyKind::Ref(region, mt) => {
let r = self.lower_lifetime(region, RegionInferReason::Reference);
debug!(?r);
let t = self.lower_ty_common(mt.ty, true, false);
let t = self.lower_ty(mt.ty);
Ty::new_ref(tcx, r, t, mt.mutbl)
}
hir::TyKind::Never => tcx.types.never,
@ -2063,20 +2054,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
)
}
hir::TyKind::TraitObject(bounds, lifetime, repr) => {
self.prohibit_or_lint_bare_trait_object_ty(hir_ty, in_path);
self.prohibit_or_lint_bare_trait_object_ty(hir_ty);
let repr = match repr {
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn,
TraitObjectSyntax::DynStar => ty::DynStar,
};
self.lower_trait_object_ty(
hir_ty.span,
hir_ty.hir_id,
bounds,
lifetime,
borrowed,
repr,
)
self.lower_trait_object_ty(hir_ty.span, hir_ty.hir_id, bounds, lifetime, repr)
}
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
debug!(?maybe_qself, ?path);
@ -2104,7 +2088,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => {
debug!(?qself, ?segment);
let ty = self.lower_ty_common(qself, false, true);
let ty = self.lower_ty(qself);
self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false)
.map(|(ty, _, _)| ty)
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))

View file

@ -30,7 +30,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
hir_id: hir::HirId,
hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)],
lifetime: &hir::Lifetime,
borrowed: bool,
representation: DynKind,
) -> Ty<'tcx> {
let tcx = self.tcx();
@ -325,22 +324,32 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
v.dedup();
let existential_predicates = tcx.mk_poly_existential_predicates(&v);
// Use explicitly-specified region bound.
// Use explicitly-specified region bound, unless the bound is missing.
let region_bound = if !lifetime.is_elided() {
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
} else {
self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| {
// Curiously, we prefer object lifetime default for `+ '_`...
if tcx.named_bound_var(lifetime.hir_id).is_some() {
self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault)
self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
} else {
self.re_infer(
span,
if borrowed {
RegionInferReason::ObjectLifetimeDefault
let reason =
if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res {
if let hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Ref(parent_lifetime, _),
..
}) = tcx.parent_hir_node(hir_id)
&& tcx.named_bound_var(parent_lifetime.hir_id).is_none()
{
// Parent lifetime must have failed to resolve. Don't emit a redundant error.
RegionInferReason::ExplicitObjectLifetime
} else {
RegionInferReason::ObjectLifetimeDefault
}
} else {
RegionInferReason::BorrowedObjectLifetimeDefault
},
)
RegionInferReason::ExplicitObjectLifetime
};
self.re_infer(span, reason)
}
})
};

View file

@ -137,8 +137,7 @@ fn enforce_impl_params_are_constrained(
}
};
if err {
let const_param_note =
matches!(param.kind, ty::GenericParamDefKind::Const { .. }).then_some(());
let const_param_note = matches!(param.kind, ty::GenericParamDefKind::Const { .. });
let mut diag = tcx.dcx().create_err(UnconstrainedGenericParameter {
span: tcx.def_span(param.def_id),
param_name: param.name,

View file

@ -1,18 +1,36 @@
use std::fmt::Write;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_middle::ty::TyCtxt;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_middle::ty::{GenericArgs, TyCtxt};
use rustc_span::symbol::sym;
fn format_variances(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String {
let variances = tcx.variances_of(def_id);
let generics = GenericArgs::identity_for_item(tcx, def_id);
// 7 = 2-letter parameter + ": " + 1-letter variance + ", "
let mut ret = String::with_capacity(2 + 7 * variances.len());
ret.push('[');
for (arg, variance) in generics.iter().zip(variances.iter()) {
write!(ret, "{arg}: {variance:?}, ").unwrap();
}
// Remove trailing `, `.
if !variances.is_empty() {
ret.pop();
ret.pop();
}
ret.push(']');
ret
}
pub(crate) fn variances(tcx: TyCtxt<'_>) {
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
for id in tcx.hir().items() {
let DefKind::OpaqueTy = tcx.def_kind(id.owner_id) else { continue };
let variances = tcx.variances_of(id.owner_id);
tcx.dcx().emit_err(crate::errors::VariancesOf {
span: tcx.def_span(id.owner_id),
variances: format!("{variances:?}"),
variances: format_variances(tcx, id.owner_id.def_id),
});
}
}
@ -22,11 +40,9 @@ pub(crate) fn variances(tcx: TyCtxt<'_>) {
continue;
}
let variances = tcx.variances_of(id.owner_id);
tcx.dcx().emit_err(crate::errors::VariancesOf {
span: tcx.def_span(id.owner_id),
variances: format!("{variances:?}"),
variances: format_variances(tcx, id.owner_id.def_id),
});
}
}

View file

@ -505,7 +505,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
span: self.span,
expr_ty: self.expr_ty,
cast_ty: fcx.ty_to_string(self.cast_ty),
teach: fcx.tcx.sess.teach(E0607).then_some(()),
teach: fcx.tcx.sess.teach(E0607),
});
}
CastError::IntToFatCast(known_metadata) => {

View file

@ -106,7 +106,7 @@ fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> {
vec![]
}
fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'_>> {
fn simple<'tcx>(kind: Adjust<'tcx>) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
move |target| vec![Adjustment { kind, target }]
}

View file

@ -706,7 +706,7 @@ pub(crate) struct CastThinPointerToFatPointer<'tcx> {
pub expr_ty: Ty<'tcx>,
pub cast_ty: String,
#[note(hir_typeck_teach_help)]
pub(crate) teach: Option<()>,
pub(crate) teach: bool,
}
#[derive(Diagnostic)]
@ -720,7 +720,7 @@ pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
pub sugg_span: Option<Span>,
pub replace: String,
#[help]
pub help: Option<()>,
pub help: bool,
#[note(hir_typeck_teach_help)]
pub(crate) teach: Option<()>,
pub(crate) teach: bool,
}

View file

@ -841,6 +841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ret_ty = ret_coercion.borrow().expected_ty();
let return_expr_ty = self.check_expr_with_hint(return_expr, ret_ty);
let mut span = return_expr.span;
let mut hir_id = return_expr.hir_id;
// Use the span of the trailing expression for our cause,
// not the span of the entire function
if !explicit_return
@ -848,6 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Some(last_expr) = body.expr
{
span = last_expr.span;
hir_id = last_expr.hir_id;
}
ret_coercion.borrow_mut().coerce(
self,
@ -864,6 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.select_obligations_where_possible(|errors| {
self.point_at_return_for_opaque_ty_error(
errors,
hir_id,
span,
return_expr_ty,
return_expr.span,
@ -921,6 +924,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn point_at_return_for_opaque_ty_error(
&self,
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
hir_id: HirId,
span: Span,
return_expr_ty: Ty<'tcx>,
return_span: Span,
@ -935,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let new_cause = ObligationCause::new(
cause.span,
cause.body_id,
ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, span))),
ObligationCauseCode::OpaqueReturnType(Some((return_expr_ty, hir_id))),
);
*cause = new_cause;
}

View file

@ -798,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// to be object-safe.
// We manually call `register_wf_obligation` in the success path
// below.
let ty = self.lowerer().lower_ty_in_path(qself);
let ty = self.lowerer().lower_ty(qself);
(LoweredTy::from_raw(self, span, ty), qself, segment)
}
QPath::LangItem(..) => {

View file

@ -406,9 +406,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let (sugg_span, replace, help) =
if let Ok(snippet) = sess.source_map().span_to_snippet(span) {
(Some(span), format!("{snippet} as {cast_ty}"), None)
(Some(span), format!("{snippet} as {cast_ty}"), false)
} else {
(None, "".to_string(), Some(()))
(None, "".to_string(), true)
};
sess.dcx().emit_err(errors::PassToVariadicFunction {
@ -418,7 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
help,
replace,
sugg_span,
teach: sess.teach(E0617).then_some(()),
teach: sess.teach(E0617),
});
}

View file

@ -2975,7 +2975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut suffix_suggestion = sugg.clone();
suffix_suggestion.push((
if matches!(
(&expected_ty.kind(), &checked_ty.kind()),
(expected_ty.kind(), checked_ty.kind()),
(ty::Int(_) | ty::Uint(_), ty::Float(_))
) {
// Remove fractional part from literal, for example `42.0f32` into `42`
@ -3077,7 +3077,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
};
match (&expected_ty.kind(), &checked_ty.kind()) {
match (expected_ty.kind(), checked_ty.kind()) {
(ty::Int(exp), ty::Int(found)) => {
let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
{

View file

@ -87,14 +87,17 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef
&tcx.typeck(def_id).used_trait_imports
}
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
let fallback = move || tcx.type_of(def_id.to_def_id()).instantiate_identity();
typeck_with_fallback(tcx, def_id, fallback, None)
}
/// Used only to get `TypeckResults` for type inference during error recovery.
/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors.
fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
fn diagnostic_only_typeck<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> &'tcx ty::TypeckResults<'tcx> {
let fallback = move || {
let span = tcx.hir().span(tcx.local_def_id_to_hir_id(def_id));
Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used")

View file

@ -527,7 +527,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
if self.check_and_add_sugg_binding(LetStmt {
ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None },
binding_id: binding_id,
binding_id,
span: pat.span,
init_hir_id: init.hir_id,
}) {
@ -1012,7 +1012,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut bound_span_label = |self_ty: Ty<'_>, obligation: &str, quiet: &str| {
let msg = format!("`{}`", if obligation.len() > 50 { quiet } else { obligation });
match &self_ty.kind() {
match self_ty.kind() {
// Point at the type that couldn't satisfy the bound.
ty::Adt(def, _) => {
bound_spans.get_mut_or_insert_default(tcx.def_span(def.did())).push(msg)

View file

@ -1336,7 +1336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// More generally, the expected type wants a tuple variant with one field of an
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
let missing_parentheses = match (&expected.kind(), fields, had_err) {
let missing_parentheses = match (expected.kind(), fields, had_err) {
// #67037: only do this if we could successfully type-check the expected type against
// the tuple struct pattern. Otherwise the args could get out of range on e.g.,
// `let P() = U;` where `P != U` with `struct P<T>(T);`.

View file

@ -99,6 +99,4 @@ incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err}
incremental_write_new = failed to write {$name} to `{$path}`: {$err}

View file

@ -189,10 +189,10 @@ pub struct CreateLock<'a> {
pub lock_err: std::io::Error,
pub session_dir: &'a Path,
#[note(incremental_lock_unsupported)]
pub is_unsupported_lock: Option<()>,
pub is_unsupported_lock: bool,
#[help(incremental_cargo_help_1)]
#[help(incremental_cargo_help_2)]
pub is_cargo: Option<()>,
pub is_cargo: bool,
}
#[derive(Diagnostic)]
@ -272,13 +272,6 @@ pub struct LoadDepGraph {
pub err: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(incremental_write_dep_graph)]
pub struct WriteDepGraph<'a> {
pub path: &'a Path,
pub err: std::io::Error,
}
#[derive(Diagnostic)]
#[diag(incremental_move_dep_graph)]
pub struct MoveDepGraph<'a> {

View file

@ -486,12 +486,12 @@ fn lock_directory(
// the lock should be exclusive
Ok(lock) => Ok((lock, lock_file_path)),
Err(lock_err) => {
let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err).then_some(());
let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err);
Err(sess.dcx().emit_err(errors::CreateLock {
lock_err,
session_dir,
is_unsupported_lock,
is_cargo: rustc_session::utils::was_invoked_from_cargo().then_some(()),
is_cargo: rustc_session::utils::was_invoked_from_cargo(),
}))
}
}
@ -851,7 +851,7 @@ fn delete_old(sess: &Session, path: &Path) {
debug!("garbage_collect_session_directories() - deleting `{}`", path.display());
if let Err(err) = safe_remove_dir_all(path) {
sess.dcx().emit_warn(errors::SessionGcFailed { path: path, err });
sess.dcx().emit_warn(errors::SessionGcFailed { path, err });
} else {
delete_session_dir_lock_file(sess, &lock_file_path(path));
}

View file

@ -2,6 +2,7 @@
#![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
#![cfg_attr(feature = "nightly", allow(internal_features))]
#![cfg_attr(feature = "nightly", feature(extend_one, new_uninit, step_trait, test))]
#![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))]
// tidy-alphabetical-end
pub mod bit_set;

View file

@ -167,7 +167,7 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> {
}
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), sub, sup)
}
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {

View file

@ -390,7 +390,7 @@ pub enum SubregionOrigin<'tcx> {
/// The given region parameter was instantiated with a region
/// that must outlive some other region.
RelateRegionParamBound(Span),
RelateRegionParamBound(Span, Option<Ty<'tcx>>),
/// Creating a pointer `b` to contents of another reference.
Reborrow(Span),
@ -859,7 +859,7 @@ impl<'tcx> InferCtxt<'tcx> {
) {
self.enter_forall(predicate, |ty::OutlivesPredicate(r_a, r_b)| {
let origin = SubregionOrigin::from_obligation_cause(cause, || {
RelateRegionParamBound(cause.span)
RelateRegionParamBound(cause.span, None)
});
self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
})
@ -1685,7 +1685,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
Subtype(ref a) => a.span(),
RelateObjectBound(a) => a,
RelateParamBound(a, ..) => a,
RelateRegionParamBound(a) => a,
RelateRegionParamBound(a, _) => a,
Reborrow(a) => a,
ReferenceOutlivesReferent(_, a) => a,
CompareImplItemObligation { span, .. } => span,
@ -1726,6 +1726,10 @@ impl<'tcx> SubregionOrigin<'tcx> {
SubregionOrigin::AscribeUserTypeProvePredicate(span)
}
traits::ObligationCauseCode::ObjectTypeBound(ty, _reg) => {
SubregionOrigin::RelateRegionParamBound(cause.span, Some(ty))
}
_ => default(),
}
}

View file

@ -98,7 +98,7 @@ impl<'tcx> Queries<'tcx> {
self.parse.compute(|| passes::parse(&self.compiler.sess))
}
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'tcx, &'tcx GlobalCtxt<'tcx>>> {
self.gcx.compute(|| {
let krate = self.parse()?.steal();

View file

@ -361,6 +361,11 @@ lint_improper_ctypes_box = box cannot be represented as a single pointer
lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
lint_improper_ctypes_char_reason = the `char` type has no C equivalent
lint_improper_ctypes_cstr_help =
consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`
lint_improper_ctypes_cstr_reason = `CStr`/`CString` do not have a guaranteed layout
lint_improper_ctypes_dyn = trait objects have no C equivalent
lint_improper_ctypes_enum_repr_help =
@ -758,6 +763,9 @@ lint_suspicious_double_ref_clone =
lint_suspicious_double_ref_deref =
using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
lint_tail_expr_drop_order = these values and local bindings have significant drop implementation that will have a different drop order from that of Edition 2021
.label = these values have significant drop implementation and will observe changes in drop order under Edition 2024
lint_trailing_semi_macro = trailing semicolon in macro used in expression position
.note1 = macro invocations at the end of a block are treated as expressions
.note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`

View file

@ -1330,7 +1330,7 @@ impl UnreachablePub {
BuiltinUnreachablePub {
what,
suggestion: (vis_span, applicability),
help: exportable.then_some(()),
help: exportable,
},
);
}
@ -1925,8 +1925,8 @@ impl ExplicitOutlivesRequirements {
fn lifetimes_outliving_lifetime<'tcx>(
tcx: TyCtxt<'tcx>,
inferred_outlives: impl Iterator<Item = &'tcx (ty::Clause<'tcx>, Span)>,
item: DefId,
lifetime: DefId,
item: LocalDefId,
lifetime: LocalDefId,
) -> Vec<ty::Region<'tcx>> {
let item_generics = tcx.generics_of(item);
@ -1934,7 +1934,7 @@ impl ExplicitOutlivesRequirements {
.filter_map(|(clause, _)| match clause.kind().skip_binder() {
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
ty::ReEarlyParam(ebr)
if item_generics.region_param(ebr, tcx).def_id == lifetime =>
if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() =>
{
Some(b)
}
@ -1982,7 +1982,7 @@ impl ExplicitOutlivesRequirements {
let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
.iter()
.any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id })),
.any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })),
_ => false,
};
@ -2097,7 +2097,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
inferred_outlives
.iter()
.filter(|(_, span)| !predicate.span.contains(*span)),
item.owner_id.to_def_id(),
item.owner_id.def_id,
region_def_id,
),
&predicate.bounds,

View file

@ -151,10 +151,11 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
&& let Node::Stmt(stmt) = node
&& let StmtKind::Semi(e) = stmt.kind
&& e.hir_id == expr.hir_id
&& let Some(arg_span) = arg.span.find_ancestor_inside(expr.span)
{
UseLetUnderscoreIgnoreSuggestion::Suggestion {
start_span: expr.span.shrink_to_lo().until(arg.span),
end_span: arg.span.shrink_to_hi().until(expr.span.shrink_to_hi()),
start_span: expr.span.shrink_to_lo().until(arg_span),
end_span: arg_span.shrink_to_hi().until(expr.span.shrink_to_hi()),
}
} else {
UseLetUnderscoreIgnoreSuggestion::Note

View file

@ -77,7 +77,7 @@ pub struct UnknownToolInScopedLint {
pub tool_name: Symbol,
pub lint_name: String,
#[help]
pub is_nightly_build: Option<()>,
pub is_nightly_build: bool,
}
#[derive(Diagnostic)]

View file

@ -24,7 +24,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
{
let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
let note = expectation.is_unfulfilled_lint_expectations.then_some(());
let note = expectation.is_unfulfilled_lint_expectations;
tcx.emit_node_span_lint(
UNFULFILLED_LINT_EXPECTATIONS,
*hir_id,

View file

@ -27,8 +27,6 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(precise_capturing)]
/// # #![allow(incomplete_features)]
/// # #![deny(impl_trait_overcaptures)]
/// # use std::fmt::Display;
/// let mut x = vec![];
@ -56,7 +54,6 @@ declare_lint! {
pub IMPL_TRAIT_OVERCAPTURES,
Allow,
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
@feature_gate = precise_capturing;
//@future_incompatible = FutureIncompatibleInfo {
// reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
// reference: "<FIXME>",
@ -75,8 +72,7 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
/// # #![allow(incomplete_features)]
/// # #![feature(lifetime_capture_rules_2024)]
/// # #![deny(impl_trait_redundant_captures)]
/// fn test<'a>(x: &'a i32) -> impl Sized + use<'a> { x }
/// ```
@ -90,7 +86,6 @@ declare_lint! {
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
Warn,
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
@feature_gate = precise_capturing;
}
declare_lint_pass!(
@ -305,16 +300,17 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
Some(
ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id),
) => {
if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy {
if self.tcx.def_kind(self.tcx.local_parent(def_id)) == DefKind::OpaqueTy
{
let def_id = self
.tcx
.map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
.map_opaque_lifetime_to_parent_lifetime(def_id)
.opt_param_def_id(self.tcx, self.parent_def_id.to_def_id())
.expect("variable should have been duplicated from parent");
explicitly_captured.insert(def_id);
} else {
explicitly_captured.insert(def_id);
explicitly_captured.insert(def_id.to_def_id());
}
}
_ => {

View file

@ -8,7 +8,7 @@ use rustc_hir::{
BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat, PatKind,
Path, PathSegment, QPath, Ty, TyKind,
};
use rustc_middle::ty::{self, Ty as MiddleTy};
use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::symbol::{kw, sym, Symbol};
@ -415,14 +415,17 @@ declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE
impl LateLintPass<'_> for Diagnostics {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
let collect_args_tys_and_spans = |args: &[Expr<'_>], reserve_one_extra: bool| {
let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra));
result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span)));
result
};
// Only check function calls and method calls.
let (span, def_id, fn_gen_args, call_tys) = match expr.kind {
let (span, def_id, fn_gen_args, arg_tys_and_spans) = match expr.kind {
ExprKind::Call(callee, args) => {
match cx.typeck_results().node_type(callee.hir_id).kind() {
&ty::FnDef(def_id, fn_gen_args) => {
let call_tys: Vec<_> =
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
(callee.span, def_id, fn_gen_args, call_tys)
(callee.span, def_id, fn_gen_args, collect_args_tys_and_spans(args, false))
}
_ => return, // occurs for fns passed as args
}
@ -432,38 +435,40 @@ impl LateLintPass<'_> for Diagnostics {
else {
return;
};
let mut call_tys: Vec<_> =
args.iter().map(|arg| cx.typeck_results().expr_ty(arg)).collect();
call_tys.insert(0, cx.tcx.types.self_param); // dummy inserted for `self`
(span, def_id, fn_gen_args, call_tys)
let mut args = collect_args_tys_and_spans(args, true);
args.insert(0, (cx.tcx.types.self_param, _recv.span)); // dummy inserted for `self`
(span, def_id, fn_gen_args, args)
}
_ => return,
};
// Is the callee marked with `#[rustc_lint_diagnostics]`?
let has_attr = ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args)
.ok()
.flatten()
.is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args);
Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans);
}
}
// Closure: is the type `{D,Subd}iagMessage`?
let is_diag_message = |ty: MiddleTy<'_>| {
if let Some(adt_def) = ty.ty_adt_def()
&& let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
&& matches!(name, sym::DiagMessage | sym::SubdiagMessage)
{
true
} else {
false
}
};
impl Diagnostics {
// Is the type `{D,Subd}iagMessage`?
fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: MiddleTy<'cx>) -> bool {
if let Some(adt_def) = ty.ty_adt_def()
&& let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
&& matches!(name, sym::DiagMessage | sym::SubdiagMessage)
{
true
} else {
false
}
}
// Does the callee have one or more `impl Into<{D,Subd}iagMessage>` parameters?
let mut impl_into_diagnostic_message_params = vec![];
fn untranslatable_diagnostic<'cx>(
cx: &LateContext<'cx>,
def_id: DefId,
arg_tys_and_spans: &[(MiddleTy<'cx>, Span)],
) {
let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates;
for (i, &param_ty) in fn_sig.inputs().iter().enumerate() {
if let ty::Param(p) = param_ty.kind() {
if let ty::Param(sig_param) = param_ty.kind() {
// It is a type parameter. Check if it is `impl Into<{D,Subd}iagMessage>`.
for pred in predicates.iter() {
if let Some(trait_pred) = pred.as_trait_clause()
@ -471,27 +476,53 @@ impl LateLintPass<'_> for Diagnostics {
&& trait_ref.self_ty() == param_ty // correct predicate for the param?
&& cx.tcx.is_diagnostic_item(sym::Into, trait_ref.def_id)
&& let ty1 = trait_ref.args.type_at(1)
&& is_diag_message(ty1)
&& Self::is_diag_message(cx, ty1)
{
impl_into_diagnostic_message_params.push((i, p.name));
// Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg
// with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an
// `UNTRANSLATABLE_DIAGNOSTIC` lint.
let (arg_ty, arg_span) = arg_tys_and_spans[i];
// Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`?
let is_translatable = Self::is_diag_message(cx, arg_ty)
|| matches!(arg_ty.kind(), ty::Param(arg_param) if arg_param.name == sig_param.name);
if !is_translatable {
cx.emit_span_lint(
UNTRANSLATABLE_DIAGNOSTIC,
arg_span,
UntranslatableDiag,
);
}
}
}
}
}
}
// Is the callee interesting?
if !has_attr && impl_into_diagnostic_message_params.is_empty() {
fn diagnostic_outside_of_impl<'cx>(
cx: &LateContext<'cx>,
span: Span,
current_id: HirId,
def_id: DefId,
fn_gen_args: GenericArgsRef<'cx>,
) {
// Is the callee marked with `#[rustc_lint_diagnostics]`?
let Some(inst) =
ty::Instance::try_resolve(cx.tcx, cx.param_env, def_id, fn_gen_args).ok().flatten()
else {
return;
}
};
let has_attr = cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics);
if !has_attr {
return;
};
// Is the parent method marked with `#[rustc_lint_diagnostics]`?
let mut parent_has_attr = false;
for (hir_id, _parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
for (hir_id, _parent) in cx.tcx.hir().parent_iter(current_id) {
if let Some(owner_did) = hir_id.as_owner()
&& cx.tcx.has_attr(owner_did, sym::rustc_lint_diagnostics)
{
parent_has_attr = true;
break;
// The parent method is marked with `#[rustc_lint_diagnostics]`
return;
}
}
@ -500,37 +531,22 @@ impl LateLintPass<'_> for Diagnostics {
// - inside a parent function that is itself marked with `#[rustc_lint_diagnostics]`.
//
// Otherwise, emit a `DIAGNOSTIC_OUTSIDE_OF_IMPL` lint.
if has_attr && !parent_has_attr {
let mut is_inside_appropriate_impl = false;
for (_hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) {
debug!(?parent);
if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
&& let Impl { of_trait: Some(of_trait), .. } = impl_
&& let Some(def_id) = of_trait.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
&& matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
{
is_inside_appropriate_impl = true;
break;
}
}
debug!(?is_inside_appropriate_impl);
if !is_inside_appropriate_impl {
cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
let mut is_inside_appropriate_impl = false;
for (_hir_id, parent) in cx.tcx.hir().parent_iter(current_id) {
debug!(?parent);
if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
&& let Impl { of_trait: Some(of_trait), .. } = impl_
&& let Some(def_id) = of_trait.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
&& matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
{
is_inside_appropriate_impl = true;
break;
}
}
// Calls to methods with an `impl Into<{D,Subd}iagMessage>` parameter must be passed an arg
// with type `{D,Subd}iagMessage` or `impl Into<{D,Subd}iagMessage>`. Otherwise, emit an
// `UNTRANSLATABLE_DIAGNOSTIC` lint.
for (param_i, param_i_p_name) in impl_into_diagnostic_message_params {
// Is the arg type `{Sub,D}iagMessage`or `impl Into<{Sub,D}iagMessage>`?
let arg_ty = call_tys[param_i];
let is_translatable = is_diag_message(arg_ty)
|| matches!(arg_ty.kind(), ty::Param(p) if p.name == param_i_p_name);
if !is_translatable {
cx.emit_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, UntranslatableDiag);
}
debug!(?is_inside_appropriate_impl);
if !is_inside_appropriate_impl {
cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
}
}
}

View file

@ -936,7 +936,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
span: tool_ident.map(|ident| ident.span),
tool_name: tool_name.unwrap(),
lint_name: pprust::path_to_string(&meta_item.path),
is_nightly_build: sess.is_nightly_build().then_some(()),
is_nightly_build: sess.is_nightly_build(),
});
continue;
}

View file

@ -78,6 +78,7 @@ mod ptr_nulls;
mod redundant_semicolon;
mod reference_casting;
mod shadowed_into_iter;
mod tail_expr_drop_order;
mod traits;
mod types;
mod unit_bindings;
@ -115,6 +116,7 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use shadowed_into_iter::ShadowedIntoIter;
pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
use tail_expr_drop_order::TailExprDropOrder;
use traits::*;
use types::*;
use unit_bindings::*;
@ -238,6 +240,7 @@ late_lint_methods!(
AsyncFnInTrait: AsyncFnInTrait,
NonLocalDefinitions: NonLocalDefinitions::default(),
ImplTraitOvercaptures: ImplTraitOvercaptures,
TailExprDropOrder: TailExprDropOrder,
]
]
);
@ -569,7 +572,8 @@ fn register_builtins(store: &mut LintStore) {
"byte_slice_in_packed_struct_with_derive",
"converted into hard error, see issue #107457 \
<https://github.com/rust-lang/rust/issues/107457> for more information",
)
);
store.register_removed("writes_through_immutable_pointer", "converted into hard error");
}
fn register_internals(store: &mut LintStore) {

View file

@ -257,7 +257,7 @@ pub struct BuiltinUnreachablePub<'a> {
#[suggestion(code = "pub(crate)")]
pub suggestion: (Span, Applicability),
#[help]
pub help: Option<()>,
pub help: bool,
}
#[derive(LintDiagnostic)]
@ -572,7 +572,7 @@ pub struct Expectation {
#[subdiagnostic]
pub rationale: Option<ExpectationNote>,
#[note]
pub note: Option<()>,
pub note: bool,
}
#[derive(Subdiagnostic)]
@ -756,7 +756,7 @@ pub enum InvalidReferenceCastingDiag<'tcx> {
#[label]
orig_cast: Option<Span>,
#[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
ty_has_interior_mutability: Option<()>,
ty_has_interior_mutability: bool,
},
#[diag(lint_invalid_reference_casting_assign_to_ref)]
#[note(lint_invalid_reference_casting_note_book)]
@ -764,7 +764,7 @@ pub enum InvalidReferenceCastingDiag<'tcx> {
#[label]
orig_cast: Option<Span>,
#[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
ty_has_interior_mutability: Option<()>,
ty_has_interior_mutability: bool,
},
#[diag(lint_invalid_reference_casting_bigger_layout)]
#[note(lint_layout)]

View file

@ -54,8 +54,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
&& let Some(ty_has_interior_mutability) =
is_cast_from_ref_to_mut_ptr(cx, init, &mut peel_casts)
{
let ty_has_interior_mutability = ty_has_interior_mutability.then_some(());
cx.emit_span_lint(
INVALID_REFERENCE_CASTING,
expr.span,

View file

@ -0,0 +1,306 @@
use std::mem::swap;
use rustc_ast::UnOp;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, Block, Expr, ExprKind, LetStmt, Pat, PatKind, QPath, StmtKind};
use rustc_macros::LintDiagnostic;
use rustc_middle::ty;
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_session::{declare_lint, declare_lint_pass};
use rustc_span::edition::Edition;
use rustc_span::Span;
use crate::{LateContext, LateLintPass};
declare_lint! {
/// The `tail_expr_drop_order` lint looks for those values generated at the tail expression location, that of type
/// with a significant `Drop` implementation, such as locks.
/// In case there are also local variables of type with significant `Drop` implementation as well,
/// this lint warns you of a potential transposition in the drop order.
/// Your discretion on the new drop order introduced by Edition 2024 is required.
///
/// ### Example
/// ```rust,edition2024
/// #![feature(shorter_tail_lifetimes)]
/// #![warn(tail_expr_drop_order)]
/// struct Droppy(i32);
/// impl Droppy {
/// fn get(&self) -> i32 {
/// self.0
/// }
/// }
/// impl Drop for Droppy {
/// fn drop(&mut self) {
/// // This is a custom destructor and it induces side-effects that is observable
/// // especially when the drop order at a tail expression changes.
/// println!("loud drop {}", self.0);
/// }
/// }
/// fn edition_2024() -> i32 {
/// let another_droppy = Droppy(0);
/// Droppy(1).get()
/// }
/// fn main() {
/// edition_2024();
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// In tail expression of blocks or function bodies,
/// values of type with significant `Drop` implementation has an ill-specified drop order
/// before Edition 2024 so that they are dropped only after dropping local variables.
/// Edition 2024 introduces a new rule with drop orders for them,
/// so that they are dropped first before dropping local variables.
///
/// A significant `Drop::drop` destructor here refers to an explicit, arbitrary
/// implementation of the `Drop` trait on the type, with exceptions including `Vec`,
/// `Box`, `Rc`, `BTreeMap` and `HashMap` that are marked by the compiler otherwise
/// so long that the generic types have no significant destructor recursively.
/// In other words, a type has a significant drop destructor when it has a `Drop` implementation
/// or its destructor invokes a significant destructor on a type.
/// Since we cannot completely reason about the change by just inspecting the existence of
/// a significant destructor, this lint remains only a suggestion and is set to `allow` by default.
///
/// This lint only points out the issue with `Droppy`, which will be dropped before `another_droppy`
/// does in Edition 2024.
/// No fix will be proposed by this lint.
/// However, the most probable fix is to hoist `Droppy` into its own local variable binding.
/// ```rust
/// struct Droppy(i32);
/// impl Droppy {
/// fn get(&self) -> i32 {
/// self.0
/// }
/// }
/// fn edition_2024() -> i32 {
/// let value = Droppy(0);
/// let another_droppy = Droppy(1);
/// value.get()
/// }
/// ```
pub TAIL_EXPR_DROP_ORDER,
Allow,
"Detect and warn on significant change in drop order in tail expression location",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
reference: "issue #123739 <https://github.com/rust-lang/rust/issues/123739>",
};
}
declare_lint_pass!(TailExprDropOrder => [TAIL_EXPR_DROP_ORDER]);
impl TailExprDropOrder {
fn check_fn_or_closure<'tcx>(
cx: &LateContext<'tcx>,
fn_kind: hir::intravisit::FnKind<'tcx>,
body: &'tcx hir::Body<'tcx>,
def_id: rustc_span::def_id::LocalDefId,
) {
let mut locals = vec![];
if matches!(fn_kind, hir::intravisit::FnKind::Closure) {
for &capture in cx.tcx.closure_captures(def_id) {
if matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue)
&& capture.place.ty().has_significant_drop(cx.tcx, cx.param_env)
{
locals.push(capture.var_ident.span);
}
}
}
for param in body.params {
if cx
.typeck_results()
.node_type(param.hir_id)
.has_significant_drop(cx.tcx, cx.param_env)
{
locals.push(param.span);
}
}
if let hir::ExprKind::Block(block, _) = body.value.kind {
LintVisitor { cx, locals }.check_block_inner(block);
} else {
LintTailExpr { cx, locals: &locals, is_root_tail_expr: true }.visit_expr(body.value);
}
}
}
impl<'tcx> LateLintPass<'tcx> for TailExprDropOrder {
fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
fn_kind: hir::intravisit::FnKind<'tcx>,
_: &'tcx hir::FnDecl<'tcx>,
body: &'tcx hir::Body<'tcx>,
_: Span,
def_id: rustc_span::def_id::LocalDefId,
) {
if cx.tcx.sess.at_least_rust_2024() && cx.tcx.features().shorter_tail_lifetimes {
Self::check_fn_or_closure(cx, fn_kind, body, def_id);
}
}
}
struct LintVisitor<'tcx, 'a> {
cx: &'a LateContext<'tcx>,
// We only record locals that have significant drops
locals: Vec<Span>,
}
struct LocalCollector<'tcx, 'a> {
cx: &'a LateContext<'tcx>,
locals: &'a mut Vec<Span>,
}
impl<'tcx, 'a> Visitor<'tcx> for LocalCollector<'tcx, 'a> {
type Result = ();
fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
if let PatKind::Binding(_binding_mode, id, ident, pat) = pat.kind {
let ty = self.cx.typeck_results().node_type(id);
if ty.has_significant_drop(self.cx.tcx, self.cx.param_env) {
self.locals.push(ident.span);
}
if let Some(pat) = pat {
self.visit_pat(pat);
}
} else {
intravisit::walk_pat(self, pat);
}
}
}
impl<'tcx, 'a> Visitor<'tcx> for LintVisitor<'tcx, 'a> {
fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
let mut locals = <_>::default();
swap(&mut locals, &mut self.locals);
self.check_block_inner(block);
swap(&mut locals, &mut self.locals);
}
fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
LocalCollector { cx: self.cx, locals: &mut self.locals }.visit_local(local);
}
}
impl<'tcx, 'a> LintVisitor<'tcx, 'a> {
fn check_block_inner(&mut self, block: &Block<'tcx>) {
if !block.span.at_least_rust_2024() {
// We only lint for Edition 2024 onwards
return;
}
let Some(tail_expr) = block.expr else { return };
for stmt in block.stmts {
match stmt.kind {
StmtKind::Let(let_stmt) => self.visit_local(let_stmt),
StmtKind::Item(_) => {}
StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e),
}
}
if self.locals.is_empty() {
return;
}
LintTailExpr { cx: self.cx, locals: &self.locals, is_root_tail_expr: true }
.visit_expr(tail_expr);
}
}
struct LintTailExpr<'tcx, 'a> {
cx: &'a LateContext<'tcx>,
is_root_tail_expr: bool,
locals: &'a [Span],
}
impl<'tcx, 'a> LintTailExpr<'tcx, 'a> {
fn expr_eventually_point_into_local(mut expr: &Expr<'tcx>) -> bool {
loop {
match expr.kind {
ExprKind::Index(access, _, _) | ExprKind::Field(access, _) => expr = access,
ExprKind::AddrOf(_, _, referee) | ExprKind::Unary(UnOp::Deref, referee) => {
expr = referee
}
ExprKind::Path(_)
if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind
&& let [local, ..] = path.segments
&& let Res::Local(_) = local.res =>
{
return true;
}
_ => return false,
}
}
}
fn expr_generates_nonlocal_droppy_value(&self, expr: &Expr<'tcx>) -> bool {
if Self::expr_eventually_point_into_local(expr) {
return false;
}
self.cx.typeck_results().expr_ty(expr).has_significant_drop(self.cx.tcx, self.cx.param_env)
}
}
impl<'tcx, 'a> Visitor<'tcx> for LintTailExpr<'tcx, 'a> {
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
if self.is_root_tail_expr {
self.is_root_tail_expr = false;
} else if self.expr_generates_nonlocal_droppy_value(expr) {
self.cx.tcx.emit_node_span_lint(
TAIL_EXPR_DROP_ORDER,
expr.hir_id,
expr.span,
TailExprDropOrderLint { spans: self.locals.to_vec() },
);
return;
}
match expr.kind {
ExprKind::Match(scrutinee, _, _) => self.visit_expr(scrutinee),
ExprKind::ConstBlock(_)
| ExprKind::Array(_)
| ExprKind::Break(_, _)
| ExprKind::Continue(_)
| ExprKind::Ret(_)
| ExprKind::Become(_)
| ExprKind::Yield(_, _)
| ExprKind::InlineAsm(_)
| ExprKind::If(_, _, _)
| ExprKind::Loop(_, _, _, _)
| ExprKind::Closure(_)
| ExprKind::DropTemps(_)
| ExprKind::OffsetOf(_, _)
| ExprKind::Assign(_, _, _)
| ExprKind::AssignOp(_, _, _)
| ExprKind::Lit(_)
| ExprKind::Err(_) => {}
ExprKind::MethodCall(_, _, _, _)
| ExprKind::Call(_, _)
| ExprKind::Type(_, _)
| ExprKind::Tup(_)
| ExprKind::Binary(_, _, _)
| ExprKind::Unary(_, _)
| ExprKind::Path(_)
| ExprKind::Let(_)
| ExprKind::Cast(_, _)
| ExprKind::Field(_, _)
| ExprKind::Index(_, _, _)
| ExprKind::AddrOf(_, _, _)
| ExprKind::Struct(_, _, _)
| ExprKind::Repeat(_, _) => intravisit::walk_expr(self, expr),
ExprKind::Block(_, _) => {
// We do not lint further because the drop order stays the same inside the block
}
}
}
fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
LintVisitor { cx: self.cx, locals: <_>::default() }.check_block_inner(block);
}
}
#[derive(LintDiagnostic)]
#[diag(lint_tail_expr_drop_order)]
struct TailExprDropOrderLint {
#[label]
pub spans: Vec<Span>,
}

View file

@ -985,6 +985,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
mode: CItemKind,
}
/// Accumulator for recursive ffi type checking
struct CTypesVisitorState<'tcx> {
cache: FxHashSet<Ty<'tcx>>,
/// The original type being checked, before we recursed
/// to any other types it contains.
base_ty: Ty<'tcx>,
}
enum FfiResult<'tcx> {
FfiSafe,
FfiPhantom(Ty<'tcx>),
@ -1213,7 +1221,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Checks if the given field's type is "ffi-safe".
fn check_field_type_for_ffi(
&self,
cache: &mut FxHashSet<Ty<'tcx>>,
acc: &mut CTypesVisitorState<'tcx>,
field: &ty::FieldDef,
args: GenericArgsRef<'tcx>,
) -> FfiResult<'tcx> {
@ -1223,13 +1231,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
.tcx
.try_normalize_erasing_regions(self.cx.param_env, field_ty)
.unwrap_or(field_ty);
self.check_type_for_ffi(cache, field_ty)
self.check_type_for_ffi(acc, field_ty)
}
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
fn check_variant_for_ffi(
&self,
cache: &mut FxHashSet<Ty<'tcx>>,
acc: &mut CTypesVisitorState<'tcx>,
ty: Ty<'tcx>,
def: ty::AdtDef<'tcx>,
variant: &ty::VariantDef,
@ -1239,7 +1247,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let transparent_with_all_zst_fields = if def.repr().transparent() {
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
// Transparent newtypes have at most one non-ZST field which needs to be checked..
match self.check_field_type_for_ffi(cache, field, args) {
match self.check_field_type_for_ffi(acc, field, args) {
FfiUnsafe { ty, .. } if ty.is_unit() => (),
r => return r,
}
@ -1257,7 +1265,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
let mut all_phantom = !variant.fields.is_empty();
for field in &variant.fields {
all_phantom &= match self.check_field_type_for_ffi(cache, field, args) {
all_phantom &= match self.check_field_type_for_ffi(acc, field, args) {
FfiSafe => false,
// `()` fields are FFI-safe!
FfiUnsafe { ty, .. } if ty.is_unit() => false,
@ -1277,7 +1285,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult<'tcx> {
fn check_type_for_ffi(
&self,
acc: &mut CTypesVisitorState<'tcx>,
ty: Ty<'tcx>,
) -> FfiResult<'tcx> {
use FfiResult::*;
let tcx = self.cx.tcx;
@ -1286,7 +1298,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// `struct S(*mut S);`.
// FIXME: A recursion limit is necessary as well, for irregular
// recursive types.
if !cache.insert(ty) {
if !acc.cache.insert(ty) {
return FfiSafe;
}
@ -1308,6 +1320,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
match def.adt_kind() {
AdtKind::Struct | AdtKind::Union => {
if let Some(sym::cstring_type | sym::cstr_type) =
tcx.get_diagnostic_name(def.did())
&& !acc.base_ty.is_mutable_ptr()
{
return FfiUnsafe {
ty,
reason: fluent::lint_improper_ctypes_cstr_reason,
help: Some(fluent::lint_improper_ctypes_cstr_help),
};
}
if !def.repr().c() && !def.repr().transparent() {
return FfiUnsafe {
ty,
@ -1354,7 +1377,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
};
}
self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), args)
self.check_variant_for_ffi(acc, ty, def, def.non_enum_variant(), args)
}
AdtKind::Enum => {
if def.variants().is_empty() {
@ -1378,7 +1401,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if let Some(ty) =
repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
{
return self.check_type_for_ffi(cache, ty);
return self.check_type_for_ffi(acc, ty);
}
return FfiUnsafe {
@ -1399,7 +1422,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
};
}
match self.check_variant_for_ffi(cache, ty, def, variant, args) {
match self.check_variant_for_ffi(acc, ty, def, variant, args) {
FfiSafe => (),
r => return r,
}
@ -1469,9 +1492,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiSafe
}
ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(cache, ty),
ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty),
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty),
ty::FnPtr(sig_tys, hdr) => {
let sig = sig_tys.with(hdr);
@ -1485,7 +1508,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let sig = tcx.instantiate_bound_regions_with_erased(sig);
for arg in sig.inputs() {
match self.check_type_for_ffi(cache, *arg) {
match self.check_type_for_ffi(acc, *arg) {
FfiSafe => {}
r => return r,
}
@ -1496,7 +1519,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return FfiSafe;
}
self.check_type_for_ffi(cache, ret_ty)
self.check_type_for_ffi(acc, ret_ty)
}
ty::Foreign(..) => FfiSafe,
@ -1619,7 +1642,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
return;
}
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
let mut acc = CTypesVisitorState { cache: FxHashSet::default(), base_ty: ty };
match self.check_type_for_ffi(&mut acc, ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => {
self.emit_ffi_unsafe_type_lint(

View file

@ -142,7 +142,6 @@ declare_lint_pass! {
USELESS_DEPRECATED,
WARNINGS,
WASM_C_ABI,
WRITES_THROUGH_IMMUTABLE_POINTER,
// tidy-alphabetical-end
]
}
@ -251,7 +250,7 @@ declare_lint! {
Deny,
"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
reference: "issue #68585 <https://github.com/rust-lang/rust/issues/68585>",
};
}
@ -4696,40 +4695,6 @@ declare_lint! {
};
}
declare_lint! {
/// The `writes_through_immutable_pointer` lint detects writes through pointers derived from
/// shared references.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![feature(const_mut_refs)]
/// const WRITE_AFTER_CAST: () = unsafe {
/// let mut x = 0;
/// let ptr = &x as *const i32 as *mut i32;
/// *ptr = 0;
/// };
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Shared references are immutable (when there is no `UnsafeCell` involved),
/// and writing through them or through pointers derived from them is Undefined Behavior.
/// The compiler recently learned to detect such Undefined Behavior during compile-time
/// evaluation, and in the future this will raise a hard error.
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub WRITES_THROUGH_IMMUTABLE_POINTER,
Warn,
"shared references are immutable, and pointers derived from them must not be written to",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
reference: "issue #X <https://github.com/rust-lang/rust/issues/X>",
};
}
declare_lint! {
/// The `private_macro_use` lint detects private macros that are imported
/// with `#[macro_use]`.

View file

@ -10,5 +10,5 @@ libc = "0.2.73"
[build-dependencies]
# tidy-alphabetical-start
cc = "1.0.97"
cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013
# tidy-alphabetical-end

View file

@ -1607,8 +1607,13 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
const auto &ExportList = Data->ExportLists.lookup(ModId);
const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
#if LLVM_VERSION_GE(20, 0)
DenseSet<GlobalValue::GUID> CfiFunctionDefs;
DenseSet<GlobalValue::GUID> CfiFunctionDecls;
#else
std::set<GlobalValue::GUID> CfiFunctionDefs;
std::set<GlobalValue::GUID> CfiFunctionDecls;
#endif
// Based on the 'InProcessThinBackend' constructor in LLVM
for (auto &Name : Data->Index.cfiFunctionDefs())
@ -1618,9 +1623,15 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
CfiFunctionDecls.insert(
GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
#if LLVM_VERSION_GE(20, 0)
Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList,
ExportList, ResolvedODR, DefinedGlobals,
CfiFunctionDefs, CfiFunctionDecls);
#else
llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, ImportList,
ExportList, ResolvedODR, DefinedGlobals,
CfiFunctionDefs, CfiFunctionDecls);
#endif
LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size());
}

View file

@ -1002,11 +1002,7 @@ impl CrateError {
if !locator.crate_rejections.via_filename.is_empty() {
let mismatches = locator.crate_rejections.via_filename.iter();
for CrateMismatch { path, .. } in mismatches {
dcx.emit_err(errors::CrateLocationUnknownType {
span,
path: path,
crate_name,
});
dcx.emit_err(errors::CrateLocationUnknownType { span, path, crate_name });
dcx.emit_err(errors::LibFilenameForm {
span,
dll_prefix: &locator.dll_prefix,
@ -1035,7 +1031,7 @@ impl CrateError {
}
dcx.emit_err(errors::NewerCrateVersion {
span,
crate_name: crate_name,
crate_name,
add_info,
found_crates,
});

View file

@ -1487,7 +1487,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.decode((self, sess))
}
fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator<Item = ForeignModule> + '_ {
fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator<Item = ForeignModule> + 'a {
self.root.foreign_modules.decode((self, sess))
}

View file

@ -160,7 +160,7 @@ pub struct TypeLengthLimit {
pub span: Span,
pub shrunk: String,
#[note(middle_written_to_path)]
pub was_written: Option<()>,
pub was_written: bool,
pub path: PathBuf,
pub type_length: usize,
}

View file

@ -34,6 +34,7 @@
#![feature(allocator_api)]
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(box_as_ptr)]
#![feature(box_patterns)]
#![feature(closure_track_caller)]
#![feature(const_option)]

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