Auto merge of #3844 - rust-lang:rustup-2024-08-26, r=RalfJung
Automatic Rustup
This commit is contained in:
commit
2f13379dd1
859 changed files with 10948 additions and 6946 deletions
7
.github/workflows/dependencies.yml
vendored
7
.github/workflows/dependencies.yml
vendored
|
|
@ -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
4
.gitignore
vendored
|
|
@ -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
|
||||
*~
|
||||
|
|
|
|||
45
Cargo.lock
45
Cargo.lock
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ pub struct AbiSpecifiedMultipleTimes {
|
|||
#[label]
|
||||
pub prev_span: Span,
|
||||
#[note]
|
||||
pub equivalent: Option<()>,
|
||||
pub equivalent: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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: (),
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ pub(crate) struct DeprecatedItemSuggestion {
|
|||
pub span: Span,
|
||||
|
||||
#[help]
|
||||
pub is_nightly: Option<()>,
|
||||
pub is_nightly: bool,
|
||||
|
||||
#[note]
|
||||
pub details: (),
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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" }
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
),
|
||||
|
||||
|
||||
// ==========================================================================
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(¶m.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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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 }]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(..) => {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);`.
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>) {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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}`
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -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, ¶m_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
306
compiler/rustc_lint/src/tail_expr_drop_order.rs
Normal file
306
compiler/rustc_lint/src/tail_expr_drop_order.rs
Normal 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>,
|
||||
}
|
||||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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]`.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue