Merge from rustc
This commit is contained in:
commit
1e2813fa0f
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@ -67,7 +67,7 @@ jobs:
|
||||
- name: disable git crlf conversion
|
||||
run: git config --global core.autocrlf false
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: configure the PR in which the error message will be posted
|
||||
@ -393,7 +393,7 @@ jobs:
|
||||
- name: dist-x86_64-msvc
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
|
||||
SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths
|
||||
SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: windows-2019-8core-32gb
|
||||
- name: dist-i686-msvc
|
||||
@ -435,7 +435,7 @@ jobs:
|
||||
- name: disable git crlf conversion
|
||||
run: git config --global core.autocrlf false
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: configure the PR in which the error message will be posted
|
||||
@ -555,7 +555,7 @@ jobs:
|
||||
- name: disable git crlf conversion
|
||||
run: git config --global core.autocrlf false
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: configure the PR in which the error message will be posted
|
||||
@ -662,7 +662,7 @@ jobs:
|
||||
if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
|
||||
steps:
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: publish toolstate
|
||||
|
4
.github/workflows/dependencies.yml
vendored
4
.github/workflows/dependencies.yml
vendored
@ -50,7 +50,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: install the bootstrap toolchain
|
||||
@ -87,7 +87,7 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: download Cargo.lock from update job
|
||||
uses: actions/download-artifact@v3
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -58,7 +58,6 @@ build/
|
||||
\#*
|
||||
\#*\#
|
||||
.#*
|
||||
rustc-ice-*.txt
|
||||
|
||||
## Tags
|
||||
tags
|
||||
|
5
.mailmap
5
.mailmap
@ -328,7 +328,8 @@ Kyle J Strand <batmanaod@gmail.com> <BatmanAoD@users.noreply.github.com>
|
||||
Kyle J Strand <batmanaod@gmail.com> <kyle.j.strand@gmail.com>
|
||||
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
|
||||
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.com>
|
||||
Laurențiu Nicola <lnicola@dend.ro>
|
||||
Laurențiu Nicola <lnicola@dend.ro> Laurentiu Nicola <lnicola@dend.ro>
|
||||
Laurențiu Nicola <lnicola@dend.ro> <lnicola@users.noreply.github.com>
|
||||
lcnr <rust@lcnr.de> <bastian_kauschke@hotmail.de>
|
||||
Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
|
||||
Lee Wondong <wdlee91@gmail.com>
|
||||
@ -549,6 +550,8 @@ Timothy Maloney <tmaloney@pdx.edu>
|
||||
Tomas Koutsky <tomas@stepnivlk.net>
|
||||
Torsten Weber <TorstenWeber12@gmail.com>
|
||||
Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
|
||||
Trevor Gross <tmgross@umich.edu> <t.gross35@gmail.com>
|
||||
Trevor Gross <tmgross@umich.edu> <tgross@intrepidcs.com>
|
||||
Trevor Spiteri <tspiteri@ieee.org> <trevor.spiteri@um.edu.mt>
|
||||
Tshepang Mbambo <tshepang@gmail.com>
|
||||
Ty Overby <ty@pre-alpha.com>
|
||||
|
76
Cargo.lock
76
Cargo.lock
@ -859,14 +859,38 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||
dependencies = [
|
||||
"darling_core 0.14.4",
|
||||
"darling_macro 0.14.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
"darling_core 0.20.3",
|
||||
"darling_macro 0.20.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -883,13 +907,24 @@ dependencies = [
|
||||
"syn 2.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||
dependencies = [
|
||||
"darling_core 0.14.4",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_core 0.20.3",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
]
|
||||
@ -920,6 +955,37 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
|
||||
dependencies = [
|
||||
"darling 0.14.4",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
@ -939,7 +1005,7 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"darling 0.20.3",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
@ -2594,6 +2660,8 @@ dependencies = [
|
||||
"anyhow",
|
||||
"build_helper",
|
||||
"camino",
|
||||
"clap",
|
||||
"derive_builder",
|
||||
"env_logger 0.10.0",
|
||||
"fs_extra",
|
||||
"glob",
|
||||
|
@ -99,6 +99,22 @@ impl Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_matches(&self, name: &[Symbol]) -> bool {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
normal.item.path.segments.len() == name.len()
|
||||
&& normal
|
||||
.item
|
||||
.path
|
||||
.segments
|
||||
.iter()
|
||||
.zip(name)
|
||||
.all(|(s, n)| s.args.is_none() && s.ident.name == *n)
|
||||
}
|
||||
AttrKind::DocComment(..) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_word(&self) -> bool {
|
||||
if let AttrKind::Normal(normal) = &self.kind {
|
||||
matches!(normal.item.args, AttrArgs::Empty)
|
||||
|
@ -442,8 +442,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
span: Span,
|
||||
counter: usize,
|
||||
) -> RegionNameHighlight {
|
||||
let mut highlight = RegionHighlightMode::new(self.infcx.tcx);
|
||||
highlight.highlighting_region_vid(needle_fr, counter);
|
||||
let mut highlight = RegionHighlightMode::default();
|
||||
highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter);
|
||||
let type_name =
|
||||
self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
|
||||
|
||||
@ -804,8 +804,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut highlight = RegionHighlightMode::new(tcx);
|
||||
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
||||
let mut highlight = RegionHighlightMode::default();
|
||||
highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap());
|
||||
let type_name =
|
||||
self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
|
||||
|
||||
|
@ -137,6 +137,8 @@ builtin_macros_format_positional_after_named = positional arguments cannot follo
|
||||
.label = positional arguments must be before named arguments
|
||||
.named_args = named argument
|
||||
|
||||
builtin_macros_format_remove_raw_ident = remove the `r#`
|
||||
|
||||
builtin_macros_format_requires_string = requires at least a format string argument
|
||||
|
||||
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
||||
@ -165,6 +167,8 @@ builtin_macros_format_unused_arg = {$named ->
|
||||
builtin_macros_format_unused_args = multiple unused formatting arguments
|
||||
.label = multiple missing formatting specifiers
|
||||
|
||||
builtin_macros_format_use_positional = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
|
||||
|
||||
builtin_macros_invalid_crate_attribute = invalid crate attribute
|
||||
@ -205,8 +209,6 @@ builtin_macros_requires_cfg_pattern =
|
||||
|
||||
builtin_macros_should_panic = functions using `#[should_panic]` must return `()`
|
||||
|
||||
builtin_macros_sugg = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_test_arg_non_lifetime = functions used as tests can not have any non-lifetime generic parameters
|
||||
|
||||
builtin_macros_test_args = functions used as tests can not have any arguments
|
||||
|
@ -18,6 +18,20 @@ pub fn expand_deriving_eq(
|
||||
is_const: bool,
|
||||
) {
|
||||
let span = cx.with_def_site_ctxt(span);
|
||||
|
||||
let structural_trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(marker::StructuralEq),
|
||||
skip_path_as_bound: true, // crucial!
|
||||
needs_copy_as_bound_if_packed: false,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: true,
|
||||
methods: Vec::new(),
|
||||
associated_types: Vec::new(),
|
||||
is_const: false,
|
||||
};
|
||||
structural_trait_def.expand(cx, mitem, item, push);
|
||||
|
||||
let trait_def = TraitDef {
|
||||
span,
|
||||
path: path_std!(cmp::Eq),
|
||||
@ -44,9 +58,6 @@ pub fn expand_deriving_eq(
|
||||
associated_types: Vec::new(),
|
||||
is_const,
|
||||
};
|
||||
|
||||
super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);
|
||||
|
||||
trait_def.expand_ext(cx, mitem, item, push, true)
|
||||
}
|
||||
|
||||
|
@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq(
|
||||
BlockOrExpr::new_expr(expr)
|
||||
}
|
||||
|
||||
super::inject_impl_of_structural_trait(
|
||||
cx,
|
||||
let structural_trait_def = TraitDef {
|
||||
span,
|
||||
item,
|
||||
path_std!(marker::StructuralPartialEq),
|
||||
push,
|
||||
);
|
||||
path: path_std!(marker::StructuralPartialEq),
|
||||
skip_path_as_bound: true, // crucial!
|
||||
needs_copy_as_bound_if_packed: false,
|
||||
additional_bounds: Vec::new(),
|
||||
// We really don't support unions, but that's already checked by the impl generated below;
|
||||
// a second check here would lead to redundant error messages.
|
||||
supports_unions: true,
|
||||
methods: Vec::new(),
|
||||
associated_types: Vec::new(),
|
||||
is_const: false,
|
||||
};
|
||||
structural_trait_def.expand(cx, mitem, item, push);
|
||||
|
||||
// No need to generate `ne`, the default suffices, and not generating it is
|
||||
// faster.
|
||||
|
@ -88,7 +88,7 @@
|
||||
//!
|
||||
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! ```text
|
||||
//! Struct(vec![FieldInfo {
|
||||
//! span: <span of x>
|
||||
//! name: Some(<ident of x>),
|
||||
@ -99,7 +99,7 @@
|
||||
//!
|
||||
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! ```text
|
||||
//! Struct(vec![FieldInfo {
|
||||
//! span: <span of `i32`>,
|
||||
//! name: None,
|
||||
@ -113,7 +113,7 @@
|
||||
//! When generating the `expr` for a call with `self == C0(a)` and `other
|
||||
//! == C0(b)`, the SubstructureFields is
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! ```text
|
||||
//! EnumMatching(0, <ast::Variant for C0>,
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of i32>
|
||||
@ -125,7 +125,7 @@
|
||||
//!
|
||||
//! For `C1 {x}` and `C1 {x}`,
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! ```text
|
||||
//! EnumMatching(1, <ast::Variant for C1>,
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of x>
|
||||
@ -137,7 +137,7 @@
|
||||
//!
|
||||
//! For the tags,
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! ```text
|
||||
//! EnumTag(
|
||||
//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
|
||||
//! ```
|
||||
@ -149,7 +149,7 @@
|
||||
//!
|
||||
//! A static method on the types above would result in,
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! ```text
|
||||
//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
|
||||
//!
|
||||
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
|
||||
@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> {
|
||||
.collect();
|
||||
|
||||
// Require the current trait.
|
||||
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
|
||||
if !self.skip_path_as_bound {
|
||||
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
|
||||
}
|
||||
|
||||
// Add a `Copy` bound if required.
|
||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||
@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> {
|
||||
));
|
||||
}
|
||||
|
||||
let predicate = ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: field_ty_param.bound_generic_params,
|
||||
bounded_ty: field_ty_param.ty,
|
||||
bounds,
|
||||
};
|
||||
if !bounds.is_empty() {
|
||||
let predicate = ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: field_ty_param.bound_generic_params,
|
||||
bounded_ty: field_ty_param.ty,
|
||||
bounds,
|
||||
};
|
||||
|
||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
||||
where_clause.predicates.push(predicate);
|
||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
||||
where_clause.predicates.push(predicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem};
|
||||
use rustc_ast::{GenericArg, MetaItem};
|
||||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
@ -116,100 +116,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
|
||||
}))
|
||||
}
|
||||
|
||||
// Injects `impl<...> Structural for ItemType<...> { }`. In particular,
|
||||
// does *not* add `where T: Structural` for parameters `T` in `...`.
|
||||
// (That's the main reason we cannot use TraitDef here.)
|
||||
fn inject_impl_of_structural_trait(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
span: Span,
|
||||
item: &Annotatable,
|
||||
structural_path: generic::ty::Path,
|
||||
push: &mut dyn FnMut(Annotatable),
|
||||
) {
|
||||
let Annotatable::Item(item) = item else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let generics = match &item.kind {
|
||||
ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics,
|
||||
// Do not inject `impl Structural for Union`. (`PartialEq` does not
|
||||
// support unions, so we will see error downstream.)
|
||||
ItemKind::Union(..) => return,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// Create generics param list for where clauses and impl headers
|
||||
let mut generics = generics.clone();
|
||||
|
||||
let ctxt = span.ctxt();
|
||||
|
||||
// Create the type of `self`.
|
||||
//
|
||||
// in addition, remove defaults from generic params (impls cannot have them).
|
||||
let self_params: Vec<_> = generics
|
||||
.params
|
||||
.iter_mut()
|
||||
.map(|param| match &mut param.kind {
|
||||
ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
|
||||
cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
|
||||
),
|
||||
ast::GenericParamKind::Type { default } => {
|
||||
*default = None;
|
||||
ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
|
||||
}
|
||||
ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
|
||||
*default = None;
|
||||
ast::GenericArg::Const(
|
||||
cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let type_ident = item.ident;
|
||||
|
||||
let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
|
||||
let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));
|
||||
|
||||
// It would be nice to also encode constraint `where Self: Eq` (by adding it
|
||||
// onto `generics` cloned above). Unfortunately, that strategy runs afoul of
|
||||
// rust-lang/rust#48214. So we perform that additional check in the compiler
|
||||
// itself, instead of encoding it here.
|
||||
|
||||
// Keep the lint and stability attributes of the original item, to control
|
||||
// how the generated implementation is linted.
|
||||
let mut attrs = ast::AttrVec::new();
|
||||
attrs.extend(
|
||||
item.attrs
|
||||
.iter()
|
||||
.filter(|a| {
|
||||
[sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
|
||||
.contains(&a.name_or_empty())
|
||||
})
|
||||
.cloned(),
|
||||
);
|
||||
// Mark as `automatically_derived` to avoid some silly lints.
|
||||
attrs.push(cx.attr_word(sym::automatically_derived, span));
|
||||
|
||||
let newitem = cx.item(
|
||||
span,
|
||||
Ident::empty(),
|
||||
attrs,
|
||||
ItemKind::Impl(Box::new(Impl {
|
||||
unsafety: ast::Unsafe::No,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Const::No,
|
||||
generics,
|
||||
of_trait: Some(trait_ref),
|
||||
self_ty: self_type,
|
||||
items: ThinVec::new(),
|
||||
})),
|
||||
);
|
||||
|
||||
push(Annotatable::Item(newitem));
|
||||
}
|
||||
|
||||
fn assert_ty_bounds(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
stmts: &mut ThinVec<ast::Stmt>,
|
||||
|
@ -539,18 +539,29 @@ pub(crate) struct InvalidFormatStringLabel {
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_sugg,
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct InvalidFormatStringSuggestion {
|
||||
#[suggestion_part(code = "{len}")]
|
||||
pub(crate) captured: Span,
|
||||
pub(crate) len: String,
|
||||
#[suggestion_part(code = ", {arg}")]
|
||||
pub(crate) span: Span,
|
||||
pub(crate) arg: String,
|
||||
pub(crate) enum InvalidFormatStringSuggestion {
|
||||
#[multipart_suggestion(
|
||||
builtin_macros_format_use_positional,
|
||||
style = "verbose",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
UsePositional {
|
||||
#[suggestion_part(code = "{len}")]
|
||||
captured: Span,
|
||||
len: String,
|
||||
#[suggestion_part(code = ", {arg}")]
|
||||
span: Span,
|
||||
arg: String,
|
||||
},
|
||||
#[suggestion(
|
||||
builtin_macros_format_remove_raw_ident,
|
||||
code = "",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
RemoveRawIdent {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -260,20 +260,29 @@ fn make_format_args(
|
||||
if let Some((label, span)) = err.secondary_label && is_source_literal {
|
||||
e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } );
|
||||
}
|
||||
if err.should_be_replaced_with_positional_argument {
|
||||
let captured_arg_span =
|
||||
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
|
||||
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
|
||||
let span = match args.unnamed_args().last() {
|
||||
Some(arg) => arg.expr.span,
|
||||
None => fmt_span,
|
||||
};
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion {
|
||||
captured: captured_arg_span,
|
||||
len: args.unnamed_args().len().to_string(),
|
||||
span: span.shrink_to_hi(),
|
||||
arg,
|
||||
});
|
||||
match err.suggestion {
|
||||
parse::Suggestion::None => {}
|
||||
parse::Suggestion::UsePositional => {
|
||||
let captured_arg_span =
|
||||
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
|
||||
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
|
||||
let span = match args.unnamed_args().last() {
|
||||
Some(arg) => arg.expr.span,
|
||||
None => fmt_span,
|
||||
};
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UsePositional {
|
||||
captured: captured_arg_span,
|
||||
len: args.unnamed_args().len().to_string(),
|
||||
span: span.shrink_to_hi(),
|
||||
arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
parse::Suggestion::RemoveRawIdent(span) => {
|
||||
if is_source_literal {
|
||||
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
|
||||
}
|
||||
}
|
||||
}
|
||||
ecx.emit_err(e);
|
||||
|
@ -100,11 +100,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.abi),
|
||||
},
|
||||
PassMode::Cast(ref cast, pad_i32) => {
|
||||
PassMode::Cast { ref cast, pad_i32 } => {
|
||||
assert!(!pad_i32, "padding support not yet implemented");
|
||||
cast_target_to_abi_params(cast)
|
||||
}
|
||||
PassMode::Indirect { attrs, extra_attrs: None, on_stack } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
||||
if on_stack {
|
||||
// Abi requires aligning struct size to pointer size
|
||||
let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
|
||||
@ -117,11 +117,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
|
||||
}
|
||||
}
|
||||
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
|
||||
assert!(!on_stack);
|
||||
smallvec![
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs),
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -148,14 +148,14 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.abi),
|
||||
},
|
||||
PassMode::Cast(ref cast, _) => {
|
||||
PassMode::Cast { ref cast, .. } => {
|
||||
(None, cast_target_to_abi_params(cast).into_iter().collect())
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => {
|
||||
assert!(!on_stack);
|
||||
(Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
unreachable!("unsized return value")
|
||||
}
|
||||
}
|
||||
@ -229,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
|
||||
let (a, b) = arg.load_scalar_pair(fx);
|
||||
smallvec![a, b]
|
||||
}
|
||||
PassMode::Cast(ref cast, _) => to_casted_value(fx, arg, cast),
|
||||
PassMode::Cast { ref cast, .. } => to_casted_value(fx, arg, cast),
|
||||
PassMode::Indirect { .. } => {
|
||||
if is_owned {
|
||||
match arg.force_stack(fx) {
|
||||
@ -287,14 +287,14 @@ pub(super) fn cvalue_for_param<'tcx>(
|
||||
assert_eq!(block_params.len(), 2, "{:?}", block_params);
|
||||
Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout))
|
||||
}
|
||||
PassMode::Cast(ref cast, _) => {
|
||||
PassMode::Cast { ref cast, .. } => {
|
||||
Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
|
||||
assert_eq!(block_params.len(), 1, "{:?}", block_params);
|
||||
Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout))
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
assert_eq!(block_params.len(), 2, "{:?}", block_params);
|
||||
Some(CValue::by_ref_unsized(
|
||||
Pointer::new(block_params[0]),
|
||||
|
@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>(
|
||||
block_params_iter: &mut impl Iterator<Item = Value>,
|
||||
) -> CPlace<'tcx> {
|
||||
let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
|
||||
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => {
|
||||
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => {
|
||||
let is_ssa =
|
||||
ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty);
|
||||
(
|
||||
@ -26,7 +26,7 @@ pub(super) fn codegen_return_param<'tcx>(
|
||||
smallvec![],
|
||||
)
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
|
||||
let ret_param = block_params_iter.next().unwrap();
|
||||
assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
|
||||
(
|
||||
@ -34,7 +34,7 @@ pub(super) fn codegen_return_param<'tcx>(
|
||||
smallvec![ret_param],
|
||||
)
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
unreachable!("unsized return value")
|
||||
}
|
||||
};
|
||||
@ -62,7 +62,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
|
||||
) {
|
||||
let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
|
||||
PassMode::Ignore => (None, None),
|
||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
|
||||
if let Some(ret_ptr) = ret_place.try_to_ptr() {
|
||||
// This is an optimization to prevent unnecessary copies of the return value when
|
||||
// the return place is already a memory place as opposed to a register.
|
||||
@ -73,10 +73,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
|
||||
(Some(place), Some(place.to_ptr().get_addr(fx)))
|
||||
}
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
unreachable!("unsized return value")
|
||||
}
|
||||
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => (None, None),
|
||||
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None),
|
||||
};
|
||||
|
||||
let call_inst = f(fx, return_ptr);
|
||||
@ -93,21 +93,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
|
||||
ret_place
|
||||
.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
|
||||
}
|
||||
PassMode::Cast(ref cast, _) => {
|
||||
PassMode::Cast { ref cast, .. } => {
|
||||
let results =
|
||||
fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
|
||||
let result =
|
||||
super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
|
||||
ret_place.write_cvalue(fx, result);
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
|
||||
if let Some(ret_temp_place) = ret_temp_place {
|
||||
// If ret_temp_place is None, it is not necessary to copy the return value.
|
||||
let ret_temp_value = ret_temp_place.to_cvalue(fx);
|
||||
ret_place.write_cvalue(fx, ret_temp_value);
|
||||
}
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
unreachable!("unsized return value")
|
||||
}
|
||||
}
|
||||
@ -116,10 +116,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
|
||||
/// Codegen a return instruction with the right return value(s) if any.
|
||||
pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
|
||||
match fx.fn_abi.as_ref().unwrap().ret.mode {
|
||||
PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
|
||||
PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
|
||||
fx.bcx.ins().return_(&[]);
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
unreachable!("unsized return value")
|
||||
}
|
||||
PassMode::Direct(_) => {
|
||||
@ -132,7 +132,7 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
|
||||
let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
|
||||
fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
|
||||
}
|
||||
PassMode::Cast(ref cast, _) => {
|
||||
PassMode::Cast { ref cast, .. } => {
|
||||
let place = fx.get_local_place(RETURN_PLACE);
|
||||
let ret_val = place.to_cvalue(fx);
|
||||
let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
|
||||
|
@ -250,7 +250,10 @@ pub(crate) fn verify_func(
|
||||
}
|
||||
|
||||
fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
|
||||
if !crate::constant::check_constants(fx) {
|
||||
if let Err(err) =
|
||||
fx.mir.post_mono_checks(fx.tcx, ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
|
||||
{
|
||||
err.emit_err(fx.tcx);
|
||||
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
|
||||
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
|
||||
// compilation should have been aborted
|
||||
|
@ -2,9 +2,7 @@
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::interpret::{
|
||||
read_target_uint, AllocId, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
|
||||
};
|
||||
use rustc_middle::mir::interpret::{read_target_uint, AllocId, ConstValue, GlobalAlloc, Scalar};
|
||||
|
||||
use cranelift_module::*;
|
||||
|
||||
@ -33,16 +31,6 @@ impl ConstantCx {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
|
||||
let mut all_constants_ok = true;
|
||||
for constant in &fx.mir.required_consts {
|
||||
if eval_mir_constant(fx, constant).is_none() {
|
||||
all_constants_ok = false;
|
||||
}
|
||||
}
|
||||
all_constants_ok
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
|
||||
let mut constants_cx = ConstantCx::new();
|
||||
constants_cx.todo.push(TodoItem::Static(def_id));
|
||||
@ -76,30 +64,20 @@ pub(crate) fn codegen_tls_ref<'tcx>(
|
||||
pub(crate) fn eval_mir_constant<'tcx>(
|
||||
fx: &FunctionCx<'_, '_, 'tcx>,
|
||||
constant: &Constant<'tcx>,
|
||||
) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
|
||||
) -> (ConstValue<'tcx>, Ty<'tcx>) {
|
||||
let cv = fx.monomorphize(constant.literal);
|
||||
// This cannot fail because we checked all required_consts in advance.
|
||||
let val = cv
|
||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||
.map_err(|err| match err {
|
||||
ErrorHandled::Reported(_) => {
|
||||
fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
|
||||
}
|
||||
ErrorHandled::TooGeneric => {
|
||||
span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
val.map(|val| (val, cv.ty()))
|
||||
.expect("erroneous constant not captured by required_consts");
|
||||
(val, cv.ty())
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_constant_operand<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
constant: &Constant<'tcx>,
|
||||
) -> CValue<'tcx> {
|
||||
let (const_val, ty) = eval_mir_constant(fx, constant).unwrap_or_else(|| {
|
||||
span_bug!(constant.span, "erroneous constant not captured by required_consts")
|
||||
});
|
||||
|
||||
let (const_val, ty) = eval_mir_constant(fx, constant);
|
||||
codegen_const_value(fx, const_val, ty)
|
||||
}
|
||||
|
||||
@ -459,7 +437,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||
operand: &Operand<'tcx>,
|
||||
) -> Option<ConstValue<'tcx>> {
|
||||
match operand {
|
||||
Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).unwrap().0),
|
||||
Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).0),
|
||||
// FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
|
||||
// inside a temporary before being passed to the intrinsic requiring the const argument.
|
||||
// This code tries to find a single constant defining definition of the referenced local.
|
||||
|
@ -242,8 +242,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { ref value } => {
|
||||
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value)
|
||||
.unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved"));
|
||||
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value);
|
||||
let value = rustc_codegen_ssa::common::asm_const_to_str(
|
||||
fx.tcx,
|
||||
span,
|
||||
|
@ -113,7 +113,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
match self.ret.mode {
|
||||
PassMode::Ignore => cx.type_void(),
|
||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
|
||||
PassMode::Cast(ref cast, _) => cast.gcc_type(cx),
|
||||
PassMode::Cast { ref cast, .. } => cast.gcc_type(cx),
|
||||
PassMode::Indirect { .. } => {
|
||||
argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
|
||||
cx.type_void()
|
||||
@ -129,21 +129,21 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1));
|
||||
continue;
|
||||
}
|
||||
PassMode::Indirect { extra_attrs: Some(_), .. } => {
|
||||
PassMode::Indirect { meta_attrs: Some(_), .. } => {
|
||||
unimplemented!();
|
||||
}
|
||||
PassMode::Cast(ref cast, pad_i32) => {
|
||||
PassMode::Cast { ref cast, pad_i32 } => {
|
||||
// add padding
|
||||
if pad_i32 {
|
||||
argument_tys.push(Reg::i32().gcc_type(cx));
|
||||
}
|
||||
cast.gcc_type(cx)
|
||||
}
|
||||
PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => {
|
||||
PassMode::Indirect { meta_attrs: None, on_stack: true, .. } => {
|
||||
on_stack_param_indices.insert(argument_tys.len());
|
||||
arg.memory_ty(cx)
|
||||
},
|
||||
PassMode::Indirect { extra_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
|
||||
PassMode::Indirect { meta_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
|
||||
};
|
||||
argument_tys.push(arg_ty);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
sym::volatile_load | sym::unaligned_volatile_load => {
|
||||
let tp_ty = fn_args.type_at(0);
|
||||
let mut ptr = args[0].immediate();
|
||||
if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
|
||||
if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
|
||||
ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
|
||||
}
|
||||
let load = self.volatile_load(ptr.get_type(), ptr);
|
||||
@ -353,7 +353,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
|
||||
if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
|
||||
let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
|
||||
let ptr = self.pointercast(result.llval, ptr_llty);
|
||||
self.store(llval, ptr, result.align);
|
||||
@ -449,7 +449,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
else if self.is_unsized_indirect() {
|
||||
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
|
||||
}
|
||||
else if let PassMode::Cast(ref cast, _) = self.mode {
|
||||
else if let PassMode::Cast { ref cast, .. } = self.mode {
|
||||
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
|
||||
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
|
||||
let can_store_through_cast_ptr = false;
|
||||
@ -511,10 +511,10 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
PassMode::Pair(..) => {
|
||||
OperandValue::Pair(next(), next()).store(bx, dst);
|
||||
},
|
||||
PassMode::Indirect { extra_attrs: Some(_), .. } => {
|
||||
PassMode::Indirect { meta_attrs: Some(_), .. } => {
|
||||
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
|
||||
},
|
||||
PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => {
|
||||
PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } | PassMode::Cast { .. } => {
|
||||
let next_arg = next();
|
||||
self.store(bx, next_arg, dst);
|
||||
},
|
||||
|
@ -211,7 +211,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
|
||||
} else if self.is_unsized_indirect() {
|
||||
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
|
||||
} else if let PassMode::Cast(cast, _) = &self.mode {
|
||||
} else if let PassMode::Cast { cast, pad_i32: _ } = &self.mode {
|
||||
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
|
||||
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
|
||||
let can_store_through_cast_ptr = false;
|
||||
@ -274,12 +274,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
PassMode::Pair(..) => {
|
||||
OperandValue::Pair(next(), next()).store(bx, dst);
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
|
||||
}
|
||||
PassMode::Direct(_)
|
||||
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
|
||||
| PassMode::Cast(..) => {
|
||||
| PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }
|
||||
| PassMode::Cast { .. } => {
|
||||
let next_arg = next();
|
||||
self.store(bx, next_arg, dst);
|
||||
}
|
||||
@ -332,7 +332,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
let llreturn_ty = match &self.ret.mode {
|
||||
PassMode::Ignore => cx.type_void(),
|
||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
|
||||
PassMode::Cast(cast, _) => cast.llvm_type(cx),
|
||||
PassMode::Cast { cast, pad_i32: _ } => cast.llvm_type(cx),
|
||||
PassMode::Indirect { .. } => {
|
||||
llargument_tys.push(cx.type_ptr());
|
||||
cx.type_void()
|
||||
@ -351,6 +351,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
// guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
|
||||
// aggregates...
|
||||
if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
|
||||
assert!(
|
||||
arg.layout.is_sized(),
|
||||
"`PassMode::Direct` for unsized type: {}",
|
||||
arg.layout.ty
|
||||
);
|
||||
// This really shouldn't happen, since `immediate_llvm_type` will use
|
||||
// `layout.fields` to turn this Rust type into an LLVM type. This means all
|
||||
// sorts of Rust type details leak into the ABI. However wasm sadly *does*
|
||||
@ -378,8 +383,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
|
||||
continue;
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
||||
assert!(arg.layout.is_unsized());
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack } => {
|
||||
// `Indirect` with metadata is only for unsized types, and doesn't work with
|
||||
// on-stack passing.
|
||||
assert!(arg.layout.is_unsized() && !on_stack);
|
||||
// Construct the type of a (wide) pointer to `ty`, and pass its two fields.
|
||||
// Any two ABI-compatible unsized types have the same metadata type and
|
||||
// moreover the same metadata value leads to the same dynamic size and
|
||||
@ -390,7 +397,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
|
||||
continue;
|
||||
}
|
||||
PassMode::Cast(cast, pad_i32) => {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
|
||||
assert!(arg.layout.is_sized());
|
||||
cx.type_ptr()
|
||||
}
|
||||
PassMode::Cast { cast, pad_i32 } => {
|
||||
// `Cast` means "transmute to `CastType`"; that only makes sense for sized types.
|
||||
assert!(arg.layout.is_sized());
|
||||
// add padding
|
||||
if *pad_i32 {
|
||||
llargument_tys.push(Reg::i32().llvm_type(cx));
|
||||
@ -399,7 +412,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
// We assume here that ABI-compatible Rust types have the same cast type.
|
||||
cast.llvm_type(cx)
|
||||
}
|
||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(),
|
||||
};
|
||||
llargument_tys.push(llarg_ty);
|
||||
}
|
||||
@ -442,13 +454,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
PassMode::Direct(attrs) => {
|
||||
attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
|
||||
}
|
||||
PassMode::Indirect { attrs, extra_attrs: _, on_stack } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
|
||||
assert!(!on_stack);
|
||||
let i = apply(attrs);
|
||||
let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
|
||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
|
||||
}
|
||||
PassMode::Cast(cast, _) => {
|
||||
PassMode::Cast { cast, pad_i32: _ } => {
|
||||
cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
|
||||
}
|
||||
_ => {}
|
||||
@ -456,25 +468,25 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
for arg in self.args.iter() {
|
||||
match &arg.mode {
|
||||
PassMode::Ignore => {}
|
||||
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
|
||||
let i = apply(attrs);
|
||||
let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx));
|
||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
|
||||
}
|
||||
PassMode::Direct(attrs)
|
||||
| PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => {
|
||||
| PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
|
||||
apply(attrs);
|
||||
}
|
||||
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
|
||||
assert!(!on_stack);
|
||||
apply(attrs);
|
||||
apply(extra_attrs);
|
||||
apply(meta_attrs);
|
||||
}
|
||||
PassMode::Pair(a, b) => {
|
||||
apply(a);
|
||||
apply(b);
|
||||
}
|
||||
PassMode::Cast(cast, pad_i32) => {
|
||||
PassMode::Cast { cast, pad_i32 } => {
|
||||
if *pad_i32 {
|
||||
apply(&ArgAttributes::new());
|
||||
}
|
||||
@ -504,13 +516,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
PassMode::Direct(attrs) => {
|
||||
attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite);
|
||||
}
|
||||
PassMode::Indirect { attrs, extra_attrs: _, on_stack } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
|
||||
assert!(!on_stack);
|
||||
let i = apply(bx.cx, attrs);
|
||||
let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
|
||||
attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
|
||||
}
|
||||
PassMode::Cast(cast, _) => {
|
||||
PassMode::Cast { cast, pad_i32: _ } => {
|
||||
cast.attrs.apply_attrs_to_callsite(
|
||||
llvm::AttributePlace::ReturnValue,
|
||||
&bx.cx,
|
||||
@ -532,7 +544,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
for arg in self.args.iter() {
|
||||
match &arg.mode {
|
||||
PassMode::Ignore => {}
|
||||
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
|
||||
let i = apply(bx.cx, attrs);
|
||||
let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx));
|
||||
attributes::apply_to_callsite(
|
||||
@ -542,18 +554,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
);
|
||||
}
|
||||
PassMode::Direct(attrs)
|
||||
| PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => {
|
||||
| PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
|
||||
apply(bx.cx, attrs);
|
||||
}
|
||||
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack: _ } => {
|
||||
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack: _ } => {
|
||||
apply(bx.cx, attrs);
|
||||
apply(bx.cx, extra_attrs);
|
||||
apply(bx.cx, meta_attrs);
|
||||
}
|
||||
PassMode::Pair(a, b) => {
|
||||
apply(bx.cx, a);
|
||||
apply(bx.cx, b);
|
||||
}
|
||||
PassMode::Cast(cast, pad_i32) => {
|
||||
PassMode::Cast { cast, pad_i32 } => {
|
||||
if *pad_i32 {
|
||||
apply(bx.cx, &ArgAttributes::new());
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
sym::volatile_load | sym::unaligned_volatile_load => {
|
||||
let tp_ty = fn_args.type_at(0);
|
||||
let ptr = args[0].immediate();
|
||||
let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
|
||||
let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode {
|
||||
let llty = ty.llvm_type(self);
|
||||
self.volatile_load(llty, ptr)
|
||||
} else {
|
||||
@ -386,7 +386,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
if let PassMode::Cast(_, _) = &fn_abi.ret.mode {
|
||||
if let PassMode::Cast { .. } = &fn_abi.ret.mode {
|
||||
self.store(llval, result.llval, result.align);
|
||||
} else {
|
||||
OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
|
||||
|
@ -19,8 +19,6 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
|
||||
|
||||
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
|
||||
|
||||
codegen_ssa_erroneous_constant = erroneous constant encountered
|
||||
|
||||
codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
|
||||
|
||||
codegen_ssa_expected_coverage_symbol = expected `coverage(off)` or `coverage(on)`
|
||||
@ -174,8 +172,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
|
||||
|
||||
codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
|
||||
|
||||
codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
|
||||
|
||||
codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
|
||||
.note = {$output}
|
||||
|
||||
|
@ -595,20 +595,6 @@ pub struct InvalidWindowsSubsystem {
|
||||
pub subsystem: Symbol,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_erroneous_constant)]
|
||||
pub struct ErroneousConstant {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_polymorphic_constant_too_generic)]
|
||||
pub struct PolymorphicConstantTooGeneric {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_shuffle_indices_evaluation)]
|
||||
pub struct ShuffleIndicesEvaluation {
|
||||
|
@ -416,7 +416,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
}
|
||||
|
||||
PassMode::Cast(cast_ty, _) => {
|
||||
PassMode::Cast { cast: cast_ty, pad_i32: _ } => {
|
||||
let op = match self.locals[mir::RETURN_PLACE] {
|
||||
LocalRef::Operand(op) => op,
|
||||
LocalRef::PendingOperand => bug!("use of return before def"),
|
||||
@ -1088,9 +1088,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
|
||||
}
|
||||
mir::InlineAsmOperand::Const { ref value } => {
|
||||
let const_value = self
|
||||
.eval_mir_constant(value)
|
||||
.unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved"));
|
||||
let const_value = self.eval_mir_constant(value);
|
||||
let string = common::asm_const_to_str(
|
||||
bx.tcx(),
|
||||
span,
|
||||
@ -1310,7 +1308,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
) {
|
||||
match arg.mode {
|
||||
PassMode::Ignore => return,
|
||||
PassMode::Cast(_, true) => {
|
||||
PassMode::Cast { pad_i32: true, .. } => {
|
||||
// Fill padding with undef value, where applicable.
|
||||
llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32())));
|
||||
}
|
||||
@ -1322,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
_ => bug!("codegen_argument: {:?} invalid for pair argument", op),
|
||||
},
|
||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => match op.val {
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val {
|
||||
Ref(a, Some(b), _) => {
|
||||
llargs.push(a);
|
||||
llargs.push(b);
|
||||
@ -1347,7 +1345,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
op.val.store(bx, scratch);
|
||||
(scratch.llval, scratch.align, true)
|
||||
}
|
||||
PassMode::Cast(..) => {
|
||||
PassMode::Cast { .. } => {
|
||||
let scratch = PlaceRef::alloca(bx, arg.layout);
|
||||
op.val.store(bx, scratch);
|
||||
(scratch.llval, scratch.align, true)
|
||||
@ -1400,7 +1398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
|
||||
if by_ref && !arg.is_indirect() {
|
||||
// Have to load the argument, maybe while casting it.
|
||||
if let PassMode::Cast(ty, _) = &arg.mode {
|
||||
if let PassMode::Cast { cast: ty, .. } = &arg.mode {
|
||||
let llty = bx.cast_backend_type(ty);
|
||||
llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
|
||||
} else {
|
||||
@ -1744,7 +1742,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
DirectOperand(index) => {
|
||||
// If there is a cast, we have to store and reload.
|
||||
let op = if let PassMode::Cast(..) = ret_abi.mode {
|
||||
let op = if let PassMode::Cast { .. } = ret_abi.mode {
|
||||
let tmp = PlaceRef::alloca(bx, ret_abi.layout);
|
||||
tmp.storage_live(bx);
|
||||
bx.store_arg(&ret_abi, llval, tmp);
|
||||
|
@ -14,34 +14,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
|
||||
let val = self.eval_mir_constant(constant)?;
|
||||
) -> OperandRef<'tcx, Bx::Value> {
|
||||
let val = self.eval_mir_constant(constant);
|
||||
let ty = self.monomorphize(constant.ty());
|
||||
Ok(OperandRef::from_const(bx, val, ty))
|
||||
OperandRef::from_const(bx, val, ty)
|
||||
}
|
||||
|
||||
pub fn eval_mir_constant(
|
||||
&self,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
||||
pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> ConstValue<'tcx> {
|
||||
self.monomorphize(constant.literal)
|
||||
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||
.map_err(|err| {
|
||||
match err {
|
||||
ErrorHandled::Reported(_) => {
|
||||
self.cx
|
||||
.tcx()
|
||||
.sess
|
||||
.emit_err(errors::ErroneousConstant { span: constant.span });
|
||||
}
|
||||
ErrorHandled::TooGeneric => {
|
||||
self.cx.tcx().sess.diagnostic().emit_bug(
|
||||
errors::PolymorphicConstantTooGeneric { span: constant.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
err
|
||||
})
|
||||
.expect("erroneous constant not captured by required_consts")
|
||||
}
|
||||
|
||||
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
|
||||
|
@ -579,23 +579,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
if let Some(dbg_var) = dbg_var {
|
||||
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
|
||||
|
||||
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
|
||||
self.set_debug_loc(bx, var.source_info);
|
||||
let base = Self::spill_operand_to_stack(
|
||||
operand,
|
||||
Some(var.name.to_string()),
|
||||
bx,
|
||||
);
|
||||
let operand = self.eval_mir_constant_to_operand(bx, &c);
|
||||
self.set_debug_loc(bx, var.source_info);
|
||||
let base =
|
||||
Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
|
||||
|
||||
bx.dbg_var_addr(
|
||||
dbg_var,
|
||||
dbg_loc,
|
||||
base.llval,
|
||||
Size::ZERO,
|
||||
&[],
|
||||
fragment,
|
||||
);
|
||||
}
|
||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
};
|
||||
|
||||
if !fn_abi.ret.is_ignore() {
|
||||
if let PassMode::Cast(..) = &fn_abi.ret.mode {
|
||||
if let PassMode::Cast { .. } = &fn_abi.ret.mode {
|
||||
bx.store(llval, result.llval, result.align);
|
||||
} else {
|
||||
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
|
||||
|
@ -3,7 +3,6 @@ use crate::traits::*;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::mir::traversal;
|
||||
use rustc_middle::mir::UnwindTerminateReason;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
|
||||
@ -212,23 +211,14 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
||||
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
|
||||
|
||||
// Evaluate all required consts; codegen later assumes that CTFE will never fail.
|
||||
let mut all_consts_ok = true;
|
||||
for const_ in &mir.required_consts {
|
||||
if let Err(err) = fx.eval_mir_constant(const_) {
|
||||
all_consts_ok = false;
|
||||
match err {
|
||||
// errored or at least linted
|
||||
ErrorHandled::Reported(_) => {}
|
||||
ErrorHandled::TooGeneric => {
|
||||
span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !all_consts_ok {
|
||||
// We leave the IR in some half-built state here, and rely on this code not even being
|
||||
// submitted to LLVM once an error was raised.
|
||||
// Rust post-monomorphization checks; we later rely on them.
|
||||
if let Err(err) =
|
||||
mir.post_mono_checks(cx.tcx(), ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
|
||||
{
|
||||
err.emit_err(cx.tcx());
|
||||
// This IR shouldn't ever be emitted, but let's try to guard against any of this code
|
||||
// ever running.
|
||||
start_bx.abort();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -327,7 +317,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
for i in 0..tupled_arg_tys.len() {
|
||||
let arg = &fx.fn_abi.args[idx];
|
||||
idx += 1;
|
||||
if let PassMode::Cast(_, true) = arg.mode {
|
||||
if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
|
||||
llarg_idx += 1;
|
||||
}
|
||||
let pr_field = place.project_field(bx, i);
|
||||
@ -351,7 +341,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
||||
let arg = &fx.fn_abi.args[idx];
|
||||
idx += 1;
|
||||
if let PassMode::Cast(_, true) = arg.mode {
|
||||
if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
|
||||
llarg_idx += 1;
|
||||
}
|
||||
|
||||
|
@ -575,12 +575,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
self.codegen_consume(bx, place.as_ref())
|
||||
}
|
||||
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
// This cannot fail because we checked all required_consts in advance.
|
||||
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| {
|
||||
span_bug!(constant.span, "erroneous constant not captured by required_consts")
|
||||
})
|
||||
}
|
||||
mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,9 +83,6 @@ const_eval_dyn_call_vtable_mismatch =
|
||||
const_eval_dyn_star_call_vtable_mismatch =
|
||||
`dyn*` call on a pointer whose vtable does not match its type
|
||||
|
||||
const_eval_erroneous_constant =
|
||||
erroneous constant used
|
||||
|
||||
const_eval_error = {$error_kind ->
|
||||
[static] could not evaluate static initializer
|
||||
[const] evaluation of constant value failed
|
||||
|
@ -4,7 +4,7 @@ use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDi
|
||||
use rustc_middle::mir::AssertKind;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{layout::LayoutError, ConstInt};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
|
||||
|
||||
use super::InterpCx;
|
||||
use crate::errors::{self, FrameNote, ReportErrorExt};
|
||||
@ -134,11 +134,11 @@ where
|
||||
// Don't emit a new diagnostic for these errors, they are already reported elsewhere or
|
||||
// should remain silent.
|
||||
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
||||
ErrorHandled::TooGeneric
|
||||
ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))
|
||||
}
|
||||
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar),
|
||||
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)),
|
||||
err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
|
||||
ErrorHandled::Reported(guar.into())
|
||||
ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP))
|
||||
}
|
||||
// Report remaining errors.
|
||||
_ => {
|
||||
@ -152,7 +152,7 @@ where
|
||||
|
||||
// Use *our* span to label the interp error
|
||||
err.span_label(our_span, msg);
|
||||
ErrorHandled::Reported(err.emit().into())
|
||||
ErrorHandled::Reported(err.emit().into(), span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
|
||||
key.param_env = key.param_env.with_user_facing();
|
||||
match tcx.eval_to_const_value_raw(key) {
|
||||
// try again with reveal all as requested
|
||||
Err(ErrorHandled::TooGeneric) => {}
|
||||
Err(ErrorHandled::TooGeneric(_)) => {}
|
||||
// deduplicate calls
|
||||
other => return other,
|
||||
}
|
||||
@ -259,7 +259,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
||||
key.param_env = key.param_env.with_user_facing();
|
||||
match tcx.eval_to_allocation_raw(key) {
|
||||
// try again with reveal all as requested
|
||||
Err(ErrorHandled::TooGeneric) => {}
|
||||
Err(ErrorHandled::TooGeneric(_)) => {}
|
||||
// deduplicate calls
|
||||
other => return other,
|
||||
}
|
||||
|
@ -239,13 +239,6 @@ pub struct LongRunningWarn {
|
||||
pub item_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(const_eval_erroneous_constant)]
|
||||
pub(crate) struct ErroneousConstUsed {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(const_eval_non_const_impl)]
|
||||
pub(crate) struct NonConstImplNote {
|
||||
|
@ -7,7 +7,7 @@ use hir::CRATE_HIR_ID;
|
||||
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidMetaKind, ReportedErrorInfo};
|
||||
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{
|
||||
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
|
||||
@ -21,10 +21,10 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
|
||||
|
||||
use super::{
|
||||
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
|
||||
MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
|
||||
MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
|
||||
Projectable, Provenance, Scalar, StackPopJump,
|
||||
};
|
||||
use crate::errors::{self, ErroneousConstUsed};
|
||||
use crate::errors;
|
||||
use crate::util;
|
||||
use crate::{fluent_generated as fluent, ReportErrorExt};
|
||||
|
||||
@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
>(
|
||||
&self,
|
||||
value: T,
|
||||
) -> Result<T, InterpError<'tcx>> {
|
||||
) -> Result<T, ErrorHandled> {
|
||||
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
|
||||
}
|
||||
|
||||
@ -566,7 +566,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&self,
|
||||
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
|
||||
value: T,
|
||||
) -> Result<T, InterpError<'tcx>> {
|
||||
) -> Result<T, ErrorHandled> {
|
||||
frame
|
||||
.instance
|
||||
.try_subst_mir_and_normalize_erasing_regions(
|
||||
@ -574,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.param_env,
|
||||
ty::EarlyBinder::bind(value),
|
||||
)
|
||||
.map_err(|_| err_inval!(TooGeneric))
|
||||
.map_err(|_| ErrorHandled::TooGeneric(self.cur_span()))
|
||||
}
|
||||
|
||||
/// The `args` are assumed to already be in our interpreter "universe" (param_env).
|
||||
@ -750,11 +750,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
|
||||
if M::POST_MONO_CHECKS {
|
||||
for ct in &body.required_consts {
|
||||
let span = ct.span;
|
||||
let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
|
||||
self.eval_mir_constant(&ct, Some(span), None)?;
|
||||
}
|
||||
// `ctfe_query` does some error message decoration that we want to be in effect here.
|
||||
self.ctfe_query(None, |tcx| {
|
||||
body.post_mono_checks(*tcx, self.param_env, |c| {
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(c)
|
||||
})
|
||||
})?;
|
||||
}
|
||||
|
||||
// done
|
||||
@ -1059,28 +1060,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&self,
|
||||
span: Option<Span>,
|
||||
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
|
||||
) -> InterpResult<'tcx, T> {
|
||||
) -> Result<T, ErrorHandled> {
|
||||
// Use a precise span for better cycle errors.
|
||||
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
|
||||
match err {
|
||||
ErrorHandled::Reported(err) => {
|
||||
if !err.is_tainted_by_errors() && let Some(span) = span {
|
||||
// To make it easier to figure out where this error comes from, also add a note at the current location.
|
||||
self.tcx.sess.emit_note(ErroneousConstUsed { span });
|
||||
}
|
||||
err_inval!(AlreadyReported(err))
|
||||
}
|
||||
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
|
||||
}
|
||||
.into()
|
||||
err.emit_note(*self.tcx);
|
||||
err
|
||||
})
|
||||
}
|
||||
|
||||
pub fn eval_global(
|
||||
&self,
|
||||
gid: GlobalId<'tcx>,
|
||||
span: Option<Span>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
||||
let gid = GlobalId { instance, promoted: None };
|
||||
// For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
|
||||
// and thus don't care about the parameter environment. While we could just use
|
||||
// `self.param_env`, that would mean we invoke the query to evaluate the static
|
||||
@ -1091,10 +1083,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
} else {
|
||||
self.param_env
|
||||
};
|
||||
let val = self.ctfe_query(span, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
|
||||
let val = self.ctfe_query(None, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
|
||||
self.raw_const_to_mplace(val)
|
||||
}
|
||||
|
||||
pub fn eval_mir_constant(
|
||||
&self,
|
||||
val: &mir::ConstantKind<'tcx>,
|
||||
span: Option<Span>,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
let const_val = self.ctfe_query(span, |tcx| val.eval(*tcx, self.param_env, span))?;
|
||||
self.const_val_to_op(const_val, val.ty(), layout)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn dump_place(
|
||||
&self,
|
||||
|
@ -8,15 +8,14 @@ use either::{Either, Left, Right};
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
|
||||
use rustc_middle::ty::{ConstInt, Ty, ValTree};
|
||||
use rustc_middle::ty::{ConstInt, Ty};
|
||||
use rustc_middle::{mir, ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
|
||||
|
||||
use super::{
|
||||
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId,
|
||||
InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer,
|
||||
Projectable, Provenance, Scalar,
|
||||
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, InterpCx,
|
||||
InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, Projectable,
|
||||
Provenance, Scalar,
|
||||
};
|
||||
|
||||
/// An `Immediate` represents a single immediate self-contained Rust value.
|
||||
@ -136,7 +135,11 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
|
||||
|
||||
impl<Prov: Provenance> std::fmt::Debug for ImmTy<'_, Prov> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ImmTy").field("imm", &self.imm).field("ty", &self.layout.ty).finish()
|
||||
// Printing `layout` results in too much noise; just print a nice version of the type.
|
||||
f.debug_struct("ImmTy")
|
||||
.field("imm", &self.imm)
|
||||
.field("ty", &format_args!("{}", self.layout.ty))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +308,11 @@ pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
|
||||
|
||||
impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("OpTy").field("op", &self.op).field("ty", &self.layout.ty).finish()
|
||||
// Printing `layout` results in too much noise; just print a nice version of the type.
|
||||
f.debug_struct("OpTy")
|
||||
.field("op", &self.op)
|
||||
.field("ty", &format_args!("{}", self.layout.ty))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@ -693,54 +700,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Ok(op)
|
||||
}
|
||||
|
||||
fn eval_ty_constant(
|
||||
&self,
|
||||
val: ty::Const<'tcx>,
|
||||
span: Option<Span>,
|
||||
) -> InterpResult<'tcx, ValTree<'tcx>> {
|
||||
Ok(match val.kind() {
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
|
||||
throw_inval!(TooGeneric)
|
||||
}
|
||||
// FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated
|
||||
ty::ConstKind::Expr(_) => throw_inval!(TooGeneric),
|
||||
ty::ConstKind::Error(reported) => {
|
||||
throw_inval!(AlreadyReported(reported.into()))
|
||||
}
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
let instance = self.resolve(uv.def, uv.args)?;
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
self.ctfe_query(span, |tcx| tcx.eval_to_valtree(self.param_env.and(cid)))?
|
||||
.unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"))
|
||||
}
|
||||
ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
|
||||
span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {val:?}")
|
||||
}
|
||||
ty::ConstKind::Value(valtree) => valtree,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn eval_mir_constant(
|
||||
&self,
|
||||
val: &mir::ConstantKind<'tcx>,
|
||||
span: Option<Span>,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
match *val {
|
||||
mir::ConstantKind::Ty(ct) => {
|
||||
let ty = ct.ty();
|
||||
let valtree = self.eval_ty_constant(ct, span)?;
|
||||
let const_val = self.tcx.valtree_to_const_val((ty, valtree));
|
||||
self.const_val_to_op(const_val, ty, layout)
|
||||
}
|
||||
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout),
|
||||
mir::ConstantKind::Unevaluated(uv, _) => {
|
||||
let instance = self.resolve(uv.def, uv.args)?;
|
||||
Ok(self.eval_global(GlobalId { instance, promoted: uv.promoted }, span)?.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn const_val_to_op(
|
||||
&self,
|
||||
val_val: ConstValue<'tcx>,
|
||||
|
@ -117,9 +117,10 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
|
||||
|
||||
impl<Prov: Provenance> std::fmt::Debug for MPlaceTy<'_, Prov> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Printing `layout` results in too much noise; just print a nice version of the type.
|
||||
f.debug_struct("MPlaceTy")
|
||||
.field("mplace", &self.mplace)
|
||||
.field("ty", &self.layout.ty)
|
||||
.field("ty", &format_args!("{}", self.layout.ty))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@ -237,7 +238,11 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
|
||||
|
||||
impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("PlaceTy").field("place", &self.place).field("ty", &self.layout.ty).finish()
|
||||
// Printing `layout` results in too much noise; just print a nice version of the type.
|
||||
f.debug_struct("PlaceTy")
|
||||
.field("place", &self.place)
|
||||
.field("ty", &format_args!("{}", self.layout.ty))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
|
||||
// Traverse the graph, collecting a number of things:
|
||||
//
|
||||
// * Preorder mapping (to it, and back to the actual ordering)
|
||||
// * Postorder mapping (used exclusively for rank_partial_cmp on the final product)
|
||||
// * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product)
|
||||
// * Parents for each vertex in the preorder tree
|
||||
//
|
||||
// These are all done here rather than through one of the 'standard'
|
||||
@ -342,8 +342,8 @@ impl<Node: Idx> Dominators<Node> {
|
||||
/// relationship, the dominator will always precede the dominated. (The relative ordering
|
||||
/// of two unrelated nodes will also be consistent, but otherwise the order has no
|
||||
/// meaning.) This method cannot be used to determine if either Node dominates the other.
|
||||
pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
|
||||
self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
|
||||
pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
|
||||
self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs])
|
||||
}
|
||||
|
||||
/// Returns true if `a` dominates `b`.
|
||||
|
@ -1,9 +1,11 @@
|
||||
#### Note: this error code is no longer emitted by the compiler.
|
||||
|
||||
A struct, enum, or union with the `repr(transparent)` representation hint
|
||||
contains a zero-sized field that requires non-trivial alignment.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0691
|
||||
```ignore (error is no longer emitted)
|
||||
#![feature(repr_align)]
|
||||
|
||||
#[repr(align(32))]
|
||||
|
@ -401,6 +401,8 @@ declare_features! (
|
||||
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
|
||||
/// instrumentation of that function.
|
||||
(active, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605), None),
|
||||
/// Allows users to provide classes for fenced code block using `class:classname`.
|
||||
(active, custom_code_classes_in_docs, "CURRENT_RUSTC_VERSION", Some(79483), None),
|
||||
/// Allows non-builtin attributes in inner attribute position.
|
||||
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
|
||||
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
|
||||
@ -414,7 +416,7 @@ declare_features! (
|
||||
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
||||
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
|
||||
/// Allows using the `#[diagnostic]` attribute tool namespace
|
||||
(active, diagnostic_namespace, "1.73.0", Some(94785), None),
|
||||
(active, diagnostic_namespace, "1.73.0", Some(111996), None),
|
||||
/// Controls errors in trait implementations.
|
||||
(active, do_not_recommend, "1.67.0", Some(51992), None),
|
||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
||||
|
@ -699,6 +699,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
|
||||
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
|
||||
"#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
|
||||
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
|
||||
|
@ -95,6 +95,34 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par
|
||||
hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
|
||||
.note = parent implementation is in crate `{$cname}`
|
||||
|
||||
hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait
|
||||
.label = impl requires at least one non-auto trait
|
||||
.note = define and implement a new trait or type instead
|
||||
|
||||
hir_analysis_inherent_nominal = no nominal type found for inherent implementation
|
||||
.label = impl requires a nominal type
|
||||
.note = either implement a trait on it or create a newtype to wrap it instead
|
||||
hir_analysis_inherent_primitive_ty = cannot define inherent `impl` for primitive types
|
||||
.help = consider using an extension trait instead
|
||||
|
||||
hir_analysis_inherent_primitive_ty_note = you could also try moving the reference to uses of `{$subty}` (such as `self`) within the implementation
|
||||
|
||||
hir_analysis_inherent_ty_outside = cannot define inherent `impl` for a type outside of the crate where the type is defined
|
||||
.help = consider moving this inherent impl into the crate defining the type if possible
|
||||
.span_help = alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
|
||||
|
||||
hir_analysis_inherent_ty_outside_new = cannot define inherent `impl` for a type outside of the crate where the type is defined
|
||||
.label = impl for type defined outside of crate.
|
||||
.note = define and implement a trait or new type instead
|
||||
|
||||
hir_analysis_inherent_ty_outside_primitive = cannot define inherent `impl` for primitive types outside of `core`
|
||||
.help = consider moving this inherent impl into `core` if possible
|
||||
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
|
||||
|
||||
hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a type outside of the crate where the type is defined
|
||||
.help = consider moving this inherent impl into the crate defining the type if possible
|
||||
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
|
||||
|
||||
hir_analysis_invalid_union_field =
|
||||
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
||||
.note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
|
||||
@ -276,13 +304,13 @@ hir_analysis_transparent_enum_variant = transparent enum needs exactly one varia
|
||||
.many_label = too many variants in `{$path}`
|
||||
.multi_label = variant here
|
||||
|
||||
hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
|
||||
.label = needs at most one non-zero-sized field, but has {$field_count}
|
||||
.labels = this field is non-zero-sized
|
||||
hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count}
|
||||
.label = needs at most one field with non-trivial size or alignment, but has {$field_count}
|
||||
.labels = this field has non-zero size or requires alignment
|
||||
|
||||
hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
|
||||
.label = needs at most one non-zero-sized field, but has {$field_count}
|
||||
.labels = this field is non-zero-sized
|
||||
hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count}
|
||||
.label = needs at most one field with non-trivial size or alignment, but has {$field_count}
|
||||
.labels = this field has non-zero size or requires alignment
|
||||
|
||||
hir_analysis_typeof_reserved_keyword_used =
|
||||
`typeof` is a reserved keyword but unimplemented
|
||||
|
@ -1138,19 +1138,19 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
||||
return;
|
||||
}
|
||||
|
||||
// For each field, figure out if it's known to be a ZST and align(1), with "known"
|
||||
// respecting #[non_exhaustive] attributes.
|
||||
// For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
|
||||
// "known" respecting #[non_exhaustive] attributes.
|
||||
let field_infos = adt.all_fields().map(|field| {
|
||||
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
|
||||
let param_env = tcx.param_env(field.did);
|
||||
let layout = tcx.layout_of(param_env.and(ty));
|
||||
// We are currently checking the type this field came from, so it must be local
|
||||
let span = tcx.hir().span_if_local(field.did).unwrap();
|
||||
let zst = layout.is_ok_and(|layout| layout.is_zst());
|
||||
let align = layout.ok().map(|layout| layout.align.abi.bytes());
|
||||
if !zst {
|
||||
return (span, zst, align, None);
|
||||
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
|
||||
if !trivial {
|
||||
return (span, trivial, None);
|
||||
}
|
||||
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`.
|
||||
|
||||
fn check_non_exhaustive<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
@ -1184,58 +1184,52 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
||||
}
|
||||
}
|
||||
|
||||
(span, zst, align, check_non_exhaustive(tcx, ty).break_value())
|
||||
(span, trivial, check_non_exhaustive(tcx, ty).break_value())
|
||||
});
|
||||
|
||||
let non_zst_fields = field_infos
|
||||
let non_trivial_fields = field_infos
|
||||
.clone()
|
||||
.filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None });
|
||||
let non_zst_count = non_zst_fields.clone().count();
|
||||
if non_zst_count >= 2 {
|
||||
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
|
||||
.filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
|
||||
let non_trivial_count = non_trivial_fields.clone().count();
|
||||
if non_trivial_count >= 2 {
|
||||
bad_non_zero_sized_fields(
|
||||
tcx,
|
||||
adt,
|
||||
non_trivial_count,
|
||||
non_trivial_fields,
|
||||
tcx.def_span(adt.did()),
|
||||
);
|
||||
return;
|
||||
}
|
||||
let incompatible_zst_fields =
|
||||
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
|
||||
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
|
||||
for (span, zst, align, non_exhaustive) in field_infos {
|
||||
if zst && align != Some(1) {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0691,
|
||||
"zero-sized field in transparent {} has alignment larger than 1",
|
||||
adt.descr(),
|
||||
);
|
||||
|
||||
if let Some(align_bytes) = align {
|
||||
err.span_label(
|
||||
let mut prev_non_exhaustive_1zst = false;
|
||||
for (span, _trivial, non_exhaustive_1zst) in field_infos {
|
||||
if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst {
|
||||
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
|
||||
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
|
||||
if non_trivial_count > 0 || prev_non_exhaustive_1zst {
|
||||
tcx.struct_span_lint_hir(
|
||||
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
||||
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
|
||||
span,
|
||||
format!("has alignment of {align_bytes}, which is larger than 1"),
|
||||
);
|
||||
"zero-sized fields in `repr(transparent)` cannot \
|
||||
contain external non-exhaustive types",
|
||||
|lint| {
|
||||
let note = if non_exhaustive {
|
||||
"is marked with `#[non_exhaustive]`"
|
||||
} else {
|
||||
"contains private fields"
|
||||
};
|
||||
let field_ty = tcx.def_path_str_with_args(def_id, args);
|
||||
lint.note(format!(
|
||||
"this {descr} contains `{field_ty}`, which {note}, \
|
||||
and makes it not a breaking change to become \
|
||||
non-zero-sized in the future."
|
||||
))
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err.span_label(span, "may have alignment larger than 1");
|
||||
prev_non_exhaustive_1zst = true;
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
|
||||
tcx.struct_span_lint_hir(
|
||||
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
||||
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
|
||||
span,
|
||||
"zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
|
||||
|lint| {
|
||||
let note = if non_exhaustive {
|
||||
"is marked with `#[non_exhaustive]`"
|
||||
} else {
|
||||
"contains private fields"
|
||||
};
|
||||
let field_ty = tcx.def_path_str_with_args(def_id, args);
|
||||
lint
|
||||
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
|
||||
and makes it not a breaking change to become non-zero-sized in the future."))
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
//! `tcx.inherent_impls(def_id)`). That value, however,
|
||||
//! is computed by selecting an idea from this table.
|
||||
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
@ -15,6 +14,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
|
||||
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
/// On-demand query: yields a map containing all types mapped to their inherent impls.
|
||||
pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
|
||||
let mut collect = InherentCollect { tcx, impls_map: Default::default() };
|
||||
@ -45,14 +46,6 @@ struct InherentCollect<'tcx> {
|
||||
impls_map: CrateInherentImpls,
|
||||
}
|
||||
|
||||
const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
|
||||
const INTO_DEFINING_CRATE: &str =
|
||||
"consider moving this inherent impl into the crate defining the type if possible";
|
||||
const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
|
||||
and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
|
||||
const ADD_ATTR: &str =
|
||||
"alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
|
||||
|
||||
impl<'tcx> InherentCollect<'tcx> {
|
||||
fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
|
||||
if let Some(ty_def_id) = ty_def_id.as_local() {
|
||||
@ -69,30 +62,17 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
|
||||
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
impl_span,
|
||||
E0390,
|
||||
"cannot define inherent `impl` for a type outside of the crate where the type is defined",
|
||||
)
|
||||
.help(INTO_DEFINING_CRATE)
|
||||
.span_help(impl_span, ADD_ATTR_TO_TY)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span });
|
||||
return;
|
||||
}
|
||||
|
||||
for &impl_item in items {
|
||||
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
impl_span,
|
||||
E0390,
|
||||
"cannot define inherent `impl` for a type outside of the crate where the type is defined",
|
||||
)
|
||||
.help(INTO_DEFINING_CRATE)
|
||||
.span_help(self.tcx.def_span(impl_item), ADD_ATTR)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant {
|
||||
span: impl_span,
|
||||
help_span: self.tcx.def_span(impl_item),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
}
|
||||
} else {
|
||||
let impl_span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
impl_span,
|
||||
E0116,
|
||||
"cannot define inherent `impl` for a type outside of the crate \
|
||||
where the type is defined"
|
||||
)
|
||||
.span_label(impl_span, "impl for type defined outside of crate.")
|
||||
.note("define and implement a trait or new type instead")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span });
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
for &impl_item in items {
|
||||
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
||||
let span = self.tcx.def_span(impl_def_id);
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive {
|
||||
span,
|
||||
E0390,
|
||||
"cannot define inherent `impl` for primitive types outside of `core`",
|
||||
)
|
||||
.help(INTO_CORE)
|
||||
.span_help(self.tcx.def_span(impl_item), ADD_ATTR)
|
||||
.emit();
|
||||
help_span: self.tcx.def_span(impl_item),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let span = self.tcx.def_span(impl_def_id);
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0390,
|
||||
"cannot define inherent `impl` for primitive types",
|
||||
);
|
||||
err.help("consider using an extension trait instead");
|
||||
let mut note = None;
|
||||
if let ty::Ref(_, subty, _) = ty.kind() {
|
||||
err.note(format!(
|
||||
"you could also try moving the reference to \
|
||||
uses of `{subty}` (such as `self`) within the implementation"
|
||||
));
|
||||
note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
|
||||
}
|
||||
err.emit();
|
||||
self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note });
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
|
||||
}
|
||||
ty::Dynamic(..) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
item_span,
|
||||
E0785,
|
||||
"cannot define inherent `impl` for a dyn auto trait"
|
||||
)
|
||||
.span_label(item_span, "impl requires at least one non-auto trait")
|
||||
.note("define and implement a new trait or type instead")
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(errors::InherentDyn { span: item_span });
|
||||
}
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
@ -202,17 +151,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
| ty::FnPtr(_)
|
||||
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
|
||||
ty::Alias(..) | ty::Param(_) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
item_span,
|
||||
E0118,
|
||||
"no nominal type found for inherent implementation"
|
||||
);
|
||||
|
||||
err.span_label(item_span, "impl requires a nominal type")
|
||||
.note("either implement a trait on it or create a newtype to wrap it instead");
|
||||
|
||||
err.emit();
|
||||
self.tcx.sess.emit_err(errors::InherentNominal { span: item_span });
|
||||
}
|
||||
ty::FnDef(..)
|
||||
| ty::Closure(..)
|
||||
|
@ -943,3 +943,75 @@ pub struct AssocBoundOnConst {
|
||||
pub span: Span,
|
||||
pub descr: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
|
||||
#[help]
|
||||
pub struct InherentTyOutside {
|
||||
#[primary_span]
|
||||
#[help(hir_analysis_span_help)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")]
|
||||
#[help]
|
||||
pub struct InherentTyOutsideRelevant {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[help(hir_analysis_span_help)]
|
||||
pub help_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")]
|
||||
#[note]
|
||||
pub struct InherentTyOutsideNew {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")]
|
||||
#[help]
|
||||
pub struct InherentTyOutsidePrimitive {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[help(hir_analysis_span_help)]
|
||||
pub help_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")]
|
||||
#[help]
|
||||
pub struct InherentPrimitiveTy<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub note: Option<InherentPrimitiveTyNote<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(hir_analysis_inherent_primitive_ty_note)]
|
||||
pub struct InherentPrimitiveTyNote<'a> {
|
||||
pub subty: Ty<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_dyn, code = "E0785")]
|
||||
#[note]
|
||||
pub struct InherentDyn {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_inherent_nominal, code = "E0118")]
|
||||
#[note]
|
||||
pub struct InherentNominal {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ use rustc_hir::def::DefKind;
|
||||
fluent_messages! { "../messages.ftl" }
|
||||
|
||||
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
|
||||
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
|
||||
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`";
|
||||
const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
|
||||
const UNSTABLE_EXPLAIN: &str =
|
||||
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
|
||||
|
@ -16,6 +16,21 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`
|
||||
*[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
|
||||
}
|
||||
|
||||
hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
|
||||
.suggestion = compare with zero instead
|
||||
.help = compare with zero instead
|
||||
.label = unsupported cast
|
||||
|
||||
hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
|
||||
|
||||
hir_typeck_cast_unknown_pointer = cannot cast {$to ->
|
||||
[true] to
|
||||
*[false] from
|
||||
} a pointer of an unknown kind
|
||||
.label_to = needs more type information
|
||||
.note = the type information given here is insufficient to check whether the pointer cast is valid
|
||||
.label_from = the type information given here is insufficient to check whether the pointer cast is valid
|
||||
|
||||
hir_typeck_const_select_must_be_const = this argument must be a `const fn`
|
||||
.help = consult the documentation on `const_eval_select` for more information
|
||||
|
||||
@ -29,10 +44,16 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `
|
||||
|
||||
hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
|
||||
|
||||
hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty`
|
||||
|
||||
hir_typeck_expected_default_return_type = expected `()` because of default return type
|
||||
|
||||
hir_typeck_expected_return_type = expected `{$expected}` because of return type
|
||||
|
||||
hir_typeck_explicit_destructor = explicit use of destructor method
|
||||
.label = explicit destructor calls not allowed
|
||||
.suggestion = consider using `drop` function
|
||||
|
||||
hir_typeck_field_multiply_specified_in_initializer =
|
||||
field `{$ident}` specified more than once
|
||||
.label = used more than once
|
||||
@ -52,8 +73,17 @@ hir_typeck_functional_record_update_on_non_struct =
|
||||
|
||||
hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
|
||||
hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
|
||||
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
|
||||
|
||||
hir_typeck_int_to_fat = cannot cast `{$expr_ty}` to a pointer that {$known_wide ->
|
||||
[true] is
|
||||
*[false] may be
|
||||
} wide
|
||||
hir_typeck_int_to_fat_label = creating a `{$cast_ty}` requires both an address and {$metadata}
|
||||
hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
|
||||
|
||||
hir_typeck_invalid_callee = expected function, found {$ty}
|
||||
|
||||
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
|
||||
hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
|
||||
hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
|
||||
|
||||
@ -63,9 +93,22 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la
|
||||
hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
|
||||
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
|
||||
|
||||
hir_typeck_lossy_provenance_int2ptr =
|
||||
strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
|
||||
.suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
|
||||
.help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
|
||||
|
||||
hir_typeck_lossy_provenance_ptr2int =
|
||||
under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
|
||||
.suggestion = use `.addr()` to obtain the address of a pointer
|
||||
.help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
|
||||
|
||||
hir_typeck_method_call_on_unknown_raw_pointee =
|
||||
cannot call a method on a raw pointer with an unknown pointee type
|
||||
|
||||
hir_typeck_missing_fn_lang_items = failed to find an overloaded call trait for closure call
|
||||
.help = make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||
|
||||
hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
|
||||
|
||||
hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
|
||||
@ -92,6 +135,9 @@ hir_typeck_return_stmt_outside_of_fn_body =
|
||||
.encl_body_label = the {$statement_kind} is part of this body...
|
||||
.encl_fn_label = ...not the enclosing function body
|
||||
|
||||
hir_typeck_rustcall_incorrect_args =
|
||||
functions with the "rust-call" ABI must take a single non-self tuple argument
|
||||
|
||||
hir_typeck_struct_expr_non_exhaustive =
|
||||
cannot create non-exhaustive {$what} using struct expression
|
||||
|
||||
@ -101,8 +147,18 @@ hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `
|
||||
|
||||
hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead
|
||||
|
||||
hir_typeck_trivial_cast = trivial {$numeric ->
|
||||
[true] numeric cast
|
||||
*[false] cast
|
||||
}: `{$expr_ty}` as `{$cast_ty}`
|
||||
.help = cast can be replaced by coercion; this might require a temporary variable
|
||||
|
||||
hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
|
||||
|
||||
hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
|
||||
|
||||
hir_typeck_use_is_empty =
|
||||
consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything
|
||||
|
||||
hir_typeck_yield_expr_outside_of_generator =
|
||||
yield expression outside of generator literal
|
||||
|
@ -2,9 +2,9 @@ use super::method::probe::ProbeScope;
|
||||
use super::method::MethodCallee;
|
||||
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
||||
|
||||
use crate::type_error_struct;
|
||||
use crate::errors;
|
||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
|
||||
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -44,23 +44,15 @@ pub fn check_legal_trait_for_method_call(
|
||||
trait_id: DefId,
|
||||
) {
|
||||
if tcx.lang_items().drop_trait() == Some(trait_id) {
|
||||
let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
|
||||
err.span_label(span, "explicit destructor calls not allowed");
|
||||
|
||||
let (sp, suggestion) = receiver
|
||||
.and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok())
|
||||
.filter(|snippet| !snippet.is_empty())
|
||||
.map(|snippet| (expr_span, format!("drop({snippet})")))
|
||||
.unwrap_or_else(|| (span, "drop".to_string()));
|
||||
|
||||
err.span_suggestion(
|
||||
sp,
|
||||
"consider using `drop` function",
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
||||
err.emit();
|
||||
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
|
||||
errors::ExplicitDestructorCallSugg::Snippet {
|
||||
lo: expr_span.shrink_to_lo(),
|
||||
hi: receiver.shrink_to_hi().to(expr_span.shrink_to_hi()),
|
||||
}
|
||||
} else {
|
||||
errors::ExplicitDestructorCallSugg::Empty(span)
|
||||
};
|
||||
tcx.sess.emit_err(errors::ExplicitDestructorCall { span, sugg });
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,6 +379,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// Unit testing: function items annotated with
|
||||
// `#[rustc_evaluate_where_clauses]` trigger special output
|
||||
// to let us test the trait evaluation system.
|
||||
// Untranslatable diagnostics are okay for rustc internals
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
|
||||
let predicates = self.tcx.predicates_of(def_id);
|
||||
let predicates = predicates.instantiate(self.tcx, args);
|
||||
@ -478,10 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
);
|
||||
self.require_type_is_sized(ty, sp, traits::RustCall);
|
||||
} else {
|
||||
self.tcx.sess.span_err(
|
||||
sp,
|
||||
"functions with the \"rust-call\" ABI must take a single non-self tuple argument",
|
||||
);
|
||||
self.tcx.sess.emit_err(errors::RustCallIncorrectArgs { span: sp });
|
||||
}
|
||||
}
|
||||
|
||||
@ -610,17 +602,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
let callee_ty = self.resolve_vars_if_possible(callee_ty);
|
||||
let mut err = type_error_struct!(
|
||||
self.tcx.sess,
|
||||
callee_expr.span,
|
||||
callee_ty,
|
||||
E0618,
|
||||
"expected function, found {}",
|
||||
match &unit_variant {
|
||||
let mut err = self.tcx.sess.create_err(errors::InvalidCallee {
|
||||
span: callee_expr.span,
|
||||
ty: match &unit_variant {
|
||||
Some((_, kind, path)) => format!("{kind} `{path}`"),
|
||||
None => format!("`{callee_ty}`"),
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
if callee_ty.references_error() {
|
||||
err.downgrade_to_delayed_bug();
|
||||
}
|
||||
|
||||
self.identify_bad_closure_def_and_call(
|
||||
&mut err,
|
||||
@ -891,15 +882,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
|
||||
None => {
|
||||
// This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once`
|
||||
// lang items are not defined (issue #86238).
|
||||
let mut err = fcx.inh.tcx.sess.struct_span_err(
|
||||
self.call_expr.span,
|
||||
"failed to find an overloaded call trait for closure call",
|
||||
);
|
||||
err.help(
|
||||
"make sure the `fn`/`fn_mut`/`fn_once` lang items are defined \
|
||||
and have correctly defined `call`/`call_mut`/`call_once` methods",
|
||||
);
|
||||
err.emit();
|
||||
fcx.inh.tcx.sess.emit_err(errors::MissingFnLangItems { span: self.call_expr.span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,11 +30,10 @@
|
||||
|
||||
use super::FnCtxt;
|
||||
|
||||
use crate::errors;
|
||||
use crate::type_error_struct;
|
||||
use hir::ExprKind;
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
};
|
||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||
use rustc_middle::mir::Mutability;
|
||||
@ -321,33 +320,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
.emit();
|
||||
}
|
||||
CastError::CastToBool => {
|
||||
let mut err = struct_span_err!(
|
||||
fcx.tcx.sess,
|
||||
self.span,
|
||||
E0054,
|
||||
"cannot cast `{}` as `bool`",
|
||||
self.expr_ty
|
||||
);
|
||||
|
||||
if self.expr_ty.is_numeric() {
|
||||
match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
|
||||
Ok(snippet) => {
|
||||
err.span_suggestion(
|
||||
self.span,
|
||||
"compare with zero instead",
|
||||
format!("{snippet} != 0"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
Err(_) => {
|
||||
err.span_help(self.span, "compare with zero instead");
|
||||
}
|
||||
}
|
||||
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
||||
let help = if self.expr_ty.is_numeric() {
|
||||
errors::CannotCastToBoolHelp::Numeric(
|
||||
self.expr_span.shrink_to_hi().with_hi(self.span.hi()),
|
||||
)
|
||||
} else {
|
||||
err.span_label(self.span, "unsupported cast");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
errors::CannotCastToBoolHelp::Unsupported(self.span)
|
||||
};
|
||||
fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
|
||||
}
|
||||
CastError::CastToChar => {
|
||||
let mut err = type_error_struct!(
|
||||
@ -536,33 +517,20 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
.emit();
|
||||
}
|
||||
CastError::IntToFatCast(known_metadata) => {
|
||||
let mut err = struct_span_err!(
|
||||
fcx.tcx.sess,
|
||||
self.cast_span,
|
||||
E0606,
|
||||
"cannot cast `{}` to a pointer that {} wide",
|
||||
fcx.ty_to_string(self.expr_ty),
|
||||
if known_metadata.is_some() { "is" } else { "may be" }
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
self.cast_span,
|
||||
format!(
|
||||
"creating a `{}` requires both an address and {}",
|
||||
self.cast_ty,
|
||||
known_metadata.unwrap_or("type-specific metadata"),
|
||||
),
|
||||
);
|
||||
|
||||
if fcx.tcx.sess.is_nightly_build() {
|
||||
err.span_label(
|
||||
self.expr_span,
|
||||
"consider casting this expression to `*const ()`, \
|
||||
then using `core::ptr::from_raw_parts`",
|
||||
);
|
||||
}
|
||||
|
||||
err.emit();
|
||||
let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
|
||||
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
|
||||
let expr_ty = fcx.ty_to_string(self.expr_ty);
|
||||
let metadata = known_metadata.unwrap_or("type-specific metadata");
|
||||
let known_wide = known_metadata.is_some();
|
||||
let span = self.cast_span;
|
||||
fcx.tcx.sess.emit_err(errors::IntToWide {
|
||||
span,
|
||||
metadata,
|
||||
expr_ty,
|
||||
cast_ty,
|
||||
expr_if_nightly,
|
||||
known_wide,
|
||||
});
|
||||
}
|
||||
CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
|
||||
let unknown_cast_to = match e {
|
||||
@ -570,27 +538,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
CastError::UnknownExprPtrKind => false,
|
||||
_ => bug!(),
|
||||
};
|
||||
let mut err = struct_span_err!(
|
||||
fcx.tcx.sess,
|
||||
if unknown_cast_to { self.cast_span } else { self.span },
|
||||
E0641,
|
||||
"cannot cast {} a pointer of an unknown kind",
|
||||
if unknown_cast_to { "to" } else { "from" }
|
||||
);
|
||||
if unknown_cast_to {
|
||||
err.span_label(self.cast_span, "needs more type information");
|
||||
err.note(
|
||||
"the type information given here is insufficient to check whether \
|
||||
the pointer cast is valid",
|
||||
);
|
||||
let (span, sub) = if unknown_cast_to {
|
||||
(self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span))
|
||||
} else {
|
||||
err.span_label(
|
||||
self.span,
|
||||
"the type information given here is insufficient to check whether \
|
||||
the pointer cast is valid",
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
(self.cast_span, errors::CastUnknownPointerSub::From(self.span))
|
||||
};
|
||||
fcx.tcx.sess.emit_err(errors::CastUnknownPointer {
|
||||
span,
|
||||
to: unknown_cast_to,
|
||||
sub,
|
||||
});
|
||||
}
|
||||
CastError::ForeignNonExhaustiveAdt => {
|
||||
make_invalid_casting_error(
|
||||
@ -674,31 +631,18 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
}
|
||||
|
||||
fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
let t_cast = self.cast_ty;
|
||||
let t_expr = self.expr_ty;
|
||||
let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
|
||||
("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
|
||||
let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() {
|
||||
(true, lint::builtin::TRIVIAL_NUMERIC_CASTS)
|
||||
} else {
|
||||
("", lint::builtin::TRIVIAL_CASTS)
|
||||
(false, lint::builtin::TRIVIAL_CASTS)
|
||||
};
|
||||
fcx.tcx.struct_span_lint_hir(
|
||||
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
||||
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
|
||||
fcx.tcx.emit_spanned_lint(
|
||||
lint,
|
||||
self.expr.hir_id,
|
||||
self.span,
|
||||
DelayDm(|| {
|
||||
format!(
|
||||
"trivial {}cast: `{}` as `{}`",
|
||||
adjective,
|
||||
fcx.ty_to_string(t_expr),
|
||||
fcx.ty_to_string(t_cast)
|
||||
)
|
||||
}),
|
||||
|lint| {
|
||||
lint.help(
|
||||
"cast can be replaced by coercion; this might \
|
||||
require a temporary variable",
|
||||
)
|
||||
},
|
||||
errors::TrivialCast { numeric, expr_ty, cast_ty },
|
||||
);
|
||||
}
|
||||
|
||||
@ -991,93 +935,67 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
if let ty::Adt(d, _) = self.expr_ty.kind()
|
||||
&& d.has_dtor(fcx.tcx)
|
||||
{
|
||||
fcx.tcx.struct_span_lint_hir(
|
||||
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
||||
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
|
||||
|
||||
fcx.tcx.emit_spanned_lint(
|
||||
lint::builtin::CENUM_IMPL_DROP_CAST,
|
||||
self.expr.hir_id,
|
||||
self.span,
|
||||
DelayDm(|| format!(
|
||||
"cannot cast enum `{}` into integer `{}` because it implements `Drop`",
|
||||
self.expr_ty, self.cast_ty
|
||||
)),
|
||||
|lint| {
|
||||
lint
|
||||
},
|
||||
errors::CastEnumDrop {
|
||||
expr_ty,
|
||||
cast_ty,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
|
||||
fcx.tcx.struct_span_lint_hir(
|
||||
let expr_prec = self.expr.precedence().order();
|
||||
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
|
||||
|
||||
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
|
||||
let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
|
||||
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
||||
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
|
||||
let expr_span = self.expr_span.shrink_to_lo();
|
||||
let sugg = match (needs_parens, needs_cast) {
|
||||
(true, true) => errors::LossyProvenancePtr2IntSuggestion::NeedsParensCast {
|
||||
expr_span,
|
||||
cast_span,
|
||||
cast_ty,
|
||||
},
|
||||
(true, false) => {
|
||||
errors::LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span }
|
||||
}
|
||||
(false, true) => {
|
||||
errors::LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_ty }
|
||||
}
|
||||
(false, false) => errors::LossyProvenancePtr2IntSuggestion::Other { cast_span },
|
||||
};
|
||||
|
||||
let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg };
|
||||
fcx.tcx.emit_spanned_lint(
|
||||
lint::builtin::LOSSY_PROVENANCE_CASTS,
|
||||
self.expr.hir_id,
|
||||
self.span,
|
||||
DelayDm(|| format!(
|
||||
"under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
|
||||
self.expr_ty, self.cast_ty
|
||||
)),
|
||||
|lint| {
|
||||
let msg = "use `.addr()` to obtain the address of a pointer";
|
||||
|
||||
let expr_prec = self.expr.precedence().order();
|
||||
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
|
||||
|
||||
let scalar_cast = match t_c {
|
||||
ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
|
||||
_ => format!(" as {}", self.cast_ty),
|
||||
};
|
||||
|
||||
let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
|
||||
|
||||
if needs_parens {
|
||||
let suggestions = vec![
|
||||
(self.expr_span.shrink_to_lo(), String::from("(")),
|
||||
(cast_span, format!(").addr(){scalar_cast}")),
|
||||
];
|
||||
|
||||
lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
|
||||
} else {
|
||||
lint.span_suggestion(
|
||||
cast_span,
|
||||
msg,
|
||||
format!(".addr(){scalar_cast}"),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
lint.help(
|
||||
"if you can't comply with strict provenance and need to expose the pointer \
|
||||
provenance you can use `.expose_addr()` instead"
|
||||
);
|
||||
|
||||
lint
|
||||
},
|
||||
lint,
|
||||
);
|
||||
}
|
||||
|
||||
fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||
fcx.tcx.struct_span_lint_hir(
|
||||
let sugg = errors::LossyProvenanceInt2PtrSuggestion {
|
||||
lo: self.expr_span.shrink_to_lo(),
|
||||
hi: self.expr_span.shrink_to_hi().to(self.cast_span),
|
||||
};
|
||||
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
||||
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
|
||||
let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg };
|
||||
fcx.tcx.emit_spanned_lint(
|
||||
lint::builtin::FUZZY_PROVENANCE_CASTS,
|
||||
self.expr.hir_id,
|
||||
self.span,
|
||||
DelayDm(|| format!(
|
||||
"strict provenance disallows casting integer `{}` to pointer `{}`",
|
||||
self.expr_ty, self.cast_ty
|
||||
)),
|
||||
|lint| {
|
||||
let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
|
||||
let suggestions = vec![
|
||||
(self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
|
||||
(self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
|
||||
];
|
||||
|
||||
lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
|
||||
lint.help(
|
||||
"if you can't comply with strict provenance and don't have a pointer with \
|
||||
the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
|
||||
);
|
||||
|
||||
lint
|
||||
},
|
||||
lint,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1093,26 +1011,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
if let Some((deref_ty, _)) = derefed {
|
||||
// Give a note about what the expr derefs to.
|
||||
if deref_ty != self.expr_ty.peel_refs() {
|
||||
err.span_note(
|
||||
self.expr_span,
|
||||
format!(
|
||||
"this expression `Deref`s to `{}` which implements `is_empty`",
|
||||
fcx.ty_to_string(deref_ty)
|
||||
),
|
||||
);
|
||||
err.subdiagnostic(errors::DerefImplsIsEmpty {
|
||||
span: self.expr_span,
|
||||
deref_ty: fcx.ty_to_string(deref_ty),
|
||||
});
|
||||
}
|
||||
|
||||
// Create a multipart suggestion: add `!` and `.is_empty()` in
|
||||
// place of the cast.
|
||||
let suggestion = vec![
|
||||
(self.expr_span.shrink_to_lo(), "!".to_string()),
|
||||
(self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
|
||||
];
|
||||
|
||||
err.multipart_suggestion_verbose(format!(
|
||||
"consider using the `is_empty` method on `{}` to determine if it contains anything",
|
||||
fcx.ty_to_string(self.expr_ty),
|
||||
), suggestion, Applicability::MaybeIncorrect);
|
||||
err.subdiagnostic(errors::UseIsEmpty {
|
||||
lo: self.expr_span.shrink_to_lo(),
|
||||
hi: self.span.with_lo(self.expr_span.hi()),
|
||||
expr_ty: fcx.ty_to_string(self.expr_ty),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use rustc_errors::{
|
||||
AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
|
||||
SubdiagnosticMessage,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::{
|
||||
edition::{Edition, LATEST_STABLE_EDITION},
|
||||
@ -54,6 +54,13 @@ impl IntoDiagnosticArg for ReturnLikeStatementKind {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_rustcall_incorrect_args)]
|
||||
pub struct RustCallIncorrectArgs {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_yield_expr_outside_of_generator, code = "E0627")]
|
||||
pub struct YieldExprOutsideOfGenerator {
|
||||
@ -76,6 +83,14 @@ pub struct MethodCallOnUnknownRawPointee {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_missing_fn_lang_items)]
|
||||
#[help]
|
||||
pub struct MissingFnLangItems {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")]
|
||||
pub struct FunctionalRecordUpdateOnNonStruct {
|
||||
@ -129,6 +144,29 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_explicit_destructor, code = "E0040")]
|
||||
pub struct ExplicitDestructorCall {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: ExplicitDestructorCallSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ExplicitDestructorCallSugg {
|
||||
#[suggestion(hir_typeck_suggestion, code = "drop", applicability = "maybe-incorrect")]
|
||||
Empty(#[primary_span] Span),
|
||||
#[multipart_suggestion(hir_typeck_suggestion, style = "short")]
|
||||
Snippet {
|
||||
#[suggestion_part(code = "drop(")]
|
||||
lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
hi: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
|
||||
pub struct MissingParenthesesInRange {
|
||||
@ -231,6 +269,69 @@ pub struct LangStartIncorrectRetTy<'tcx> {
|
||||
pub found_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_typeck_lossy_provenance_int2ptr)]
|
||||
#[help]
|
||||
pub struct LossyProvenanceInt2Ptr<'tcx> {
|
||||
pub expr_ty: Ty<'tcx>,
|
||||
pub cast_ty: Ty<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub sugg: LossyProvenanceInt2PtrSuggestion,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")]
|
||||
pub struct LossyProvenanceInt2PtrSuggestion {
|
||||
#[suggestion_part(code = "(...).with_addr(")]
|
||||
pub lo: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub hi: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_typeck_lossy_provenance_ptr2int)]
|
||||
#[help]
|
||||
pub struct LossyProvenancePtr2Int<'tcx> {
|
||||
pub expr_ty: Ty<'tcx>,
|
||||
pub cast_ty: Ty<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub sugg: LossyProvenancePtr2IntSuggestion<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum LossyProvenancePtr2IntSuggestion<'tcx> {
|
||||
#[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
|
||||
NeedsParensCast {
|
||||
#[suggestion_part(code = "(")]
|
||||
expr_span: Span,
|
||||
#[suggestion_part(code = ").addr() as {cast_ty}")]
|
||||
cast_span: Span,
|
||||
cast_ty: Ty<'tcx>,
|
||||
},
|
||||
#[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
|
||||
NeedsParens {
|
||||
#[suggestion_part(code = "(")]
|
||||
expr_span: Span,
|
||||
#[suggestion_part(code = ").addr()")]
|
||||
cast_span: Span,
|
||||
},
|
||||
#[suggestion(
|
||||
hir_typeck_suggestion,
|
||||
code = ".addr() as {cast_ty}",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
NeedsCast {
|
||||
#[primary_span]
|
||||
cast_span: Span,
|
||||
cast_ty: Ty<'tcx>,
|
||||
},
|
||||
#[suggestion(hir_typeck_suggestion, code = ".addr()", applicability = "maybe-incorrect")]
|
||||
Other {
|
||||
#[primary_span]
|
||||
cast_span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum HelpUseLatestEdition {
|
||||
#[help(hir_typeck_help_set_edition_cargo)]
|
||||
@ -252,6 +353,28 @@ impl HelpUseLatestEdition {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_invalid_callee, code = "E0618")]
|
||||
pub struct InvalidCallee {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_int_to_fat, code = "E0606")]
|
||||
pub struct IntToWide<'tcx> {
|
||||
#[primary_span]
|
||||
#[label(hir_typeck_int_to_fat_label)]
|
||||
pub span: Span,
|
||||
pub metadata: &'tcx str,
|
||||
pub expr_ty: String,
|
||||
pub cast_ty: Ty<'tcx>,
|
||||
#[label(hir_typeck_int_to_fat_label_nightly)]
|
||||
pub expr_if_nightly: Option<Span>,
|
||||
pub known_wide: bool,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum OptionResultRefMismatch {
|
||||
#[suggestion(
|
||||
@ -350,6 +473,20 @@ pub struct UnionPatDotDot {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
hir_typeck_use_is_empty,
|
||||
applicability = "maybe-incorrect",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub struct UseIsEmpty {
|
||||
#[suggestion_part(code = "!")]
|
||||
pub lo: Span,
|
||||
#[suggestion_part(code = ".is_empty()")]
|
||||
pub hi: Span,
|
||||
pub expr_ty: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_arg_mismatch_indeterminate)]
|
||||
pub struct ArgMismatchIndeterminate {
|
||||
@ -396,6 +533,15 @@ pub struct SuggestPtrNullMut {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_typeck_trivial_cast)]
|
||||
#[help]
|
||||
pub struct TrivialCast<'tcx> {
|
||||
pub numeric: bool,
|
||||
pub expr_ty: Ty<'tcx>,
|
||||
pub cast_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_no_associated_item, code = "E0599")]
|
||||
pub struct NoAssociatedItem {
|
||||
@ -418,6 +564,74 @@ pub struct CandidateTraitNote {
|
||||
pub action_or_ty: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")]
|
||||
pub struct CannotCastToBool<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub expr_ty: Ty<'tcx>,
|
||||
#[subdiagnostic]
|
||||
pub help: CannotCastToBoolHelp,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_typeck_cast_enum_drop)]
|
||||
pub struct CastEnumDrop<'tcx> {
|
||||
pub expr_ty: Ty<'tcx>,
|
||||
pub cast_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")]
|
||||
pub struct CastUnknownPointer {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub to: bool,
|
||||
#[subdiagnostic]
|
||||
pub sub: CastUnknownPointerSub,
|
||||
}
|
||||
|
||||
pub enum CastUnknownPointerSub {
|
||||
To(Span),
|
||||
From(Span),
|
||||
}
|
||||
|
||||
impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub {
|
||||
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
|
||||
where
|
||||
F: Fn(
|
||||
&mut Diagnostic,
|
||||
rustc_errors::SubdiagnosticMessage,
|
||||
) -> rustc_errors::SubdiagnosticMessage,
|
||||
{
|
||||
match self {
|
||||
CastUnknownPointerSub::To(span) => {
|
||||
let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into());
|
||||
diag.span_label(span, msg);
|
||||
let msg = f(diag, crate::fluent_generated::hir_typeck_note.into());
|
||||
diag.note(msg);
|
||||
}
|
||||
CastUnknownPointerSub::From(span) => {
|
||||
let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into());
|
||||
diag.span_label(span, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum CannotCastToBoolHelp {
|
||||
#[suggestion(
|
||||
hir_typeck_suggestion,
|
||||
applicability = "machine-applicable",
|
||||
code = " != 0",
|
||||
style = "verbose"
|
||||
)]
|
||||
Numeric(#[primary_span] Span),
|
||||
#[label(hir_typeck_label)]
|
||||
Unsupported(#[primary_span] Span),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_ctor_is_private, code = "E0603")]
|
||||
pub struct CtorIsPrivate {
|
||||
@ -426,6 +640,14 @@ pub struct CtorIsPrivate {
|
||||
pub def: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(hir_typeck_deref_is_empty)]
|
||||
pub struct DerefImplsIsEmpty {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub deref_ty: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
hir_typeck_convert_using_method,
|
||||
|
@ -195,7 +195,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
|
||||
let mut delegate = InferBorrowKind {
|
||||
fcx: self,
|
||||
closure_def_id,
|
||||
capture_information: Default::default(),
|
||||
fake_reads: Default::default(),
|
||||
@ -1607,34 +1606,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Truncate the capture so that the place being borrowed is in accordance with RFC 1240,
|
||||
/// which states that it's unsafe to take a reference into a struct marked `repr(packed)`.
|
||||
fn restrict_repr_packed_field_ref_capture<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
mut place: Place<'tcx>,
|
||||
mut curr_borrow_kind: ty::UpvarCapture,
|
||||
) -> (Place<'tcx>, ty::UpvarCapture) {
|
||||
let pos = place.projections.iter().enumerate().position(|(i, p)| {
|
||||
let ty = place.ty_before_projection(i);
|
||||
|
||||
// Return true for fields of packed structs, unless those fields have alignment 1.
|
||||
// Return true for fields of packed structs.
|
||||
match p.kind {
|
||||
ProjectionKind::Field(..) => match ty.kind() {
|
||||
ty::Adt(def, _) if def.repr().packed() => {
|
||||
// We erase regions here because they cannot be hashed
|
||||
match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) {
|
||||
Ok(layout) if layout.align.abi.bytes() == 1 => {
|
||||
// if the alignment is 1, the type can't be further
|
||||
// disaligned.
|
||||
debug!(
|
||||
"restrict_repr_packed_field_ref_capture: ({:?}) - align = 1",
|
||||
place
|
||||
);
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
debug!("restrict_repr_packed_field_ref_capture: ({:?}) - true", place);
|
||||
true
|
||||
}
|
||||
}
|
||||
// We stop here regardless of field alignment. Field alignment can change as
|
||||
// types change, including the types of private fields in other crates, and that
|
||||
// shouldn't affect how we compute our captures.
|
||||
true
|
||||
}
|
||||
|
||||
_ => false,
|
||||
@ -1689,9 +1674,7 @@ fn drop_location_span(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> Span {
|
||||
tcx.sess.source_map().end_point(owner_span)
|
||||
}
|
||||
|
||||
struct InferBorrowKind<'a, 'tcx> {
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
|
||||
struct InferBorrowKind<'tcx> {
|
||||
// The def-id of the closure whose kind and upvar accesses are being inferred.
|
||||
closure_def_id: LocalDefId,
|
||||
|
||||
@ -1725,7 +1708,7 @@ struct InferBorrowKind<'a, 'tcx> {
|
||||
fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
|
||||
impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
|
||||
fn fake_read(
|
||||
&mut self,
|
||||
place: &PlaceWithHirId<'tcx>,
|
||||
@ -1740,12 +1723,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
|
||||
|
||||
let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind);
|
||||
|
||||
let (place, _) = restrict_repr_packed_field_ref_capture(
|
||||
self.fcx.tcx,
|
||||
self.fcx.param_env,
|
||||
place,
|
||||
dummy_capture_kind,
|
||||
);
|
||||
let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind);
|
||||
self.fake_reads.push((place, cause, diag_expr_id));
|
||||
}
|
||||
|
||||
@ -1780,12 +1758,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
|
||||
// We only want repr packed restriction to be applied to reading references into a packed
|
||||
// struct, and not when the data is being moved. Therefore we call this method here instead
|
||||
// of in `restrict_capture_precision`.
|
||||
let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(
|
||||
self.fcx.tcx,
|
||||
self.fcx.param_env,
|
||||
place_with_id.place.clone(),
|
||||
capture_kind,
|
||||
);
|
||||
let (place, mut capture_kind) =
|
||||
restrict_repr_packed_field_ref_capture(place_with_id.place.clone(), capture_kind);
|
||||
|
||||
// Raw pointers don't inherit mutability
|
||||
if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) {
|
||||
|
@ -385,7 +385,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
|
||||
|
||||
let highlight_trait_ref = |trait_ref| Highlighted {
|
||||
tcx: self.tcx(),
|
||||
highlight: RegionHighlightMode::new(self.tcx()),
|
||||
highlight: RegionHighlightMode::default(),
|
||||
value: trait_ref,
|
||||
};
|
||||
|
||||
|
@ -67,9 +67,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> HighlightBuilder<'tcx> {
|
||||
fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
|
||||
fn build(ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
|
||||
let mut builder =
|
||||
HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
|
||||
HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
|
||||
builder.visit_ty(ty);
|
||||
builder.highlight
|
||||
}
|
||||
@ -85,12 +85,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
|
||||
let expected_highlight = HighlightBuilder::build(expected);
|
||||
let expected = self
|
||||
.cx
|
||||
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
|
||||
.name;
|
||||
let found_highlight = HighlightBuilder::build(self.tcx(), found);
|
||||
let found_highlight = HighlightBuilder::build(found);
|
||||
let found =
|
||||
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
//! and use that to decide when one free region outlives another, and so forth.
|
||||
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||
use rustc_middle::ty::{Lift, Region, TyCtxt};
|
||||
use rustc_middle::ty::{Region, TyCtxt};
|
||||
|
||||
/// Combines a `FreeRegionMap` and a `TyCtxt`.
|
||||
///
|
||||
@ -101,10 +101,3 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
|
||||
type Lifted = FreeRegionMap<'tcx>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
|
||||
self.relation.maybe_map(|fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
|
||||
}
|
||||
}
|
||||
|
@ -1600,9 +1600,12 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
|
||||
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
|
||||
if let Err(e) = ct.error_reported() {
|
||||
return Err(ErrorHandled::Reported(e.into()));
|
||||
return Err(ErrorHandled::Reported(
|
||||
e.into(),
|
||||
span.unwrap_or(rustc_span::DUMMY_SP),
|
||||
));
|
||||
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
|
||||
return Err(ErrorHandled::TooGeneric);
|
||||
return Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP)));
|
||||
} else {
|
||||
args = replace_param_and_infer_args_with_placeholder(tcx, args);
|
||||
}
|
||||
|
@ -568,6 +568,13 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
|
||||
) {
|
||||
sess.emit_fatal(errors::MultipleOutputTypesToStdout);
|
||||
}
|
||||
|
||||
let crate_name = sess
|
||||
.opts
|
||||
.crate_name
|
||||
.clone()
|
||||
.or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()));
|
||||
|
||||
match sess.io.output_file {
|
||||
None => {
|
||||
// "-" as input file will cause the parser to read from stdin so we
|
||||
@ -576,15 +583,11 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
|
||||
let dirpath = sess.io.output_dir.clone().unwrap_or_default();
|
||||
|
||||
// If a crate name is present, we use it as the link name
|
||||
let stem = sess
|
||||
.opts
|
||||
.crate_name
|
||||
.clone()
|
||||
.or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()))
|
||||
.unwrap_or_else(|| sess.io.input.filestem().to_owned());
|
||||
let stem = crate_name.clone().unwrap_or_else(|| sess.io.input.filestem().to_owned());
|
||||
|
||||
OutputFilenames::new(
|
||||
dirpath,
|
||||
crate_name.unwrap_or_else(|| stem.replace('-', "_")),
|
||||
stem,
|
||||
None,
|
||||
sess.io.temps_dir.clone(),
|
||||
@ -609,9 +612,12 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
|
||||
sess.emit_warning(errors::IgnoringOutDir);
|
||||
}
|
||||
|
||||
let out_filestem =
|
||||
out_file.filestem().unwrap_or_default().to_str().unwrap().to_string();
|
||||
OutputFilenames::new(
|
||||
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
|
||||
out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(),
|
||||
crate_name.unwrap_or_else(|| out_filestem.replace('-', "_")),
|
||||
out_filestem,
|
||||
ofile,
|
||||
sess.io.temps_dir.clone(),
|
||||
sess.opts.cg.extra_filename.clone(),
|
||||
|
@ -453,6 +453,8 @@ lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking th
|
||||
.help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
|
||||
.label = expression has type `{$orig_ty}`
|
||||
|
||||
lint_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is never null, so checking it for null will always return false
|
||||
|
||||
lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false
|
||||
.label = expression has type `{$orig_ty}`
|
||||
|
||||
|
@ -635,6 +635,8 @@ pub enum PtrNullChecksDiag<'a> {
|
||||
#[label]
|
||||
label: Span,
|
||||
},
|
||||
#[diag(lint_ptr_null_checks_fn_ret)]
|
||||
FnRet { fn_name: Ident },
|
||||
}
|
||||
|
||||
// for_loops_over_fallibles.rs
|
||||
|
@ -31,12 +31,30 @@ declare_lint! {
|
||||
|
||||
declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
|
||||
|
||||
/// This function detects and returns the original expression from a series of consecutive casts,
|
||||
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
|
||||
fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
|
||||
/// This function checks if the expression is from a series of consecutive casts,
|
||||
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either
|
||||
/// a fn ptr, a reference, or a function call whose definition is
|
||||
/// annotated with `#![rustc_never_returns_null_ptr]`.
|
||||
/// If this situation is present, the function returns the appropriate diagnostic.
|
||||
fn incorrect_check<'a, 'tcx: 'a>(
|
||||
cx: &'a LateContext<'tcx>,
|
||||
mut e: &'a Expr<'a>,
|
||||
) -> Option<PtrNullChecksDiag<'tcx>> {
|
||||
let mut had_at_least_one_cast = false;
|
||||
loop {
|
||||
e = e.peel_blocks();
|
||||
if let ExprKind::MethodCall(_, _expr, [], _) = e.kind
|
||||
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
|
||||
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
|
||||
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
|
||||
return Some(PtrNullChecksDiag::FnRet { fn_name });
|
||||
} else if let ExprKind::Call(path, _args) = e.kind
|
||||
&& let ExprKind::Path(ref qpath) = path.kind
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
|
||||
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
|
||||
return Some(PtrNullChecksDiag::FnRet { fn_name });
|
||||
}
|
||||
e = if let ExprKind::Cast(expr, t) = e.kind
|
||||
&& let TyKind::Ptr(_) = t.kind {
|
||||
had_at_least_one_cast = true;
|
||||
@ -46,33 +64,21 @@ fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'
|
||||
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
|
||||
had_at_least_one_cast = true;
|
||||
expr
|
||||
} else if let ExprKind::Call(path, [arg]) = e.kind
|
||||
&& let ExprKind::Path(ref qpath) = path.kind
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::ptr_from_mut)) {
|
||||
had_at_least_one_cast = true;
|
||||
arg
|
||||
} else if had_at_least_one_cast {
|
||||
return Some(e);
|
||||
let orig_ty = cx.typeck_results().expr_ty(e);
|
||||
return if orig_ty.is_fn() {
|
||||
Some(PtrNullChecksDiag::FnPtr { orig_ty, label: e.span })
|
||||
} else if orig_ty.is_ref() {
|
||||
Some(PtrNullChecksDiag::Ref { orig_ty, label: e.span })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<PtrNullChecksDiag<'a>> {
|
||||
let expr = ptr_cast_chain(cx, expr)?;
|
||||
|
||||
let orig_ty = cx.typeck_results().expr_ty(expr);
|
||||
if orig_ty.is_fn() {
|
||||
Some(PtrNullChecksDiag::FnPtr { orig_ty, label: expr.span })
|
||||
} else if orig_ty.is_ref() {
|
||||
Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
match expr.kind {
|
||||
|
@ -3405,8 +3405,8 @@ declare_lint_pass! {
|
||||
UNFULFILLED_LINT_EXPECTATIONS,
|
||||
UNINHABITED_STATIC,
|
||||
UNKNOWN_CRATE_TYPES,
|
||||
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
||||
UNKNOWN_LINTS,
|
||||
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
UNNAMEABLE_TEST_ITEMS,
|
||||
UNNAMEABLE_TYPES,
|
||||
UNREACHABLE_CODE,
|
||||
@ -4420,7 +4420,8 @@ declare_lint! {
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `unknown_diagnostic_attributes` lint detects unrecognized diagnostic attributes.
|
||||
/// The `unknown_or_malformed_diagnostic_attributes` lint detects unrecognized or otherwise malformed
|
||||
/// diagnostic attributes.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
@ -4432,15 +4433,17 @@ declare_lint! {
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
|
||||
/// the spelling, and check the diagnostic attribute listing for the correct name. Also
|
||||
/// consider if you are using an old version of the compiler, and the attribute
|
||||
/// is only available in a newer version.
|
||||
pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
||||
pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||
Warn,
|
||||
"unrecognized diagnostic attribute"
|
||||
"unrecognized or malformed diagnostic attribute",
|
||||
@feature_gate = sym::diagnostic_namespace;
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
@ -239,16 +239,22 @@ enum class LLVMRustCodeGenOptLevel {
|
||||
Aggressive,
|
||||
};
|
||||
|
||||
static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) {
|
||||
#if LLVM_VERSION_GE(18, 0)
|
||||
using CodeGenOptLevelEnum = llvm::CodeGenOptLevel;
|
||||
#else
|
||||
using CodeGenOptLevelEnum = llvm::CodeGenOpt::Level;
|
||||
#endif
|
||||
|
||||
static CodeGenOptLevelEnum fromRust(LLVMRustCodeGenOptLevel Level) {
|
||||
switch (Level) {
|
||||
case LLVMRustCodeGenOptLevel::None:
|
||||
return CodeGenOpt::None;
|
||||
return CodeGenOptLevelEnum::None;
|
||||
case LLVMRustCodeGenOptLevel::Less:
|
||||
return CodeGenOpt::Less;
|
||||
return CodeGenOptLevelEnum::Less;
|
||||
case LLVMRustCodeGenOptLevel::Default:
|
||||
return CodeGenOpt::Default;
|
||||
return CodeGenOptLevelEnum::Default;
|
||||
case LLVMRustCodeGenOptLevel::Aggressive:
|
||||
return CodeGenOpt::Aggressive;
|
||||
return CodeGenOptLevelEnum::Aggressive;
|
||||
default:
|
||||
report_fatal_error("Bad CodeGenOptLevel.");
|
||||
}
|
||||
@ -554,9 +560,17 @@ enum class LLVMRustFileType {
|
||||
static CodeGenFileType fromRust(LLVMRustFileType Type) {
|
||||
switch (Type) {
|
||||
case LLVMRustFileType::AssemblyFile:
|
||||
#if LLVM_VERSION_GE(18, 0)
|
||||
return CodeGenFileType::AssemblyFile;
|
||||
#else
|
||||
return CGFT_AssemblyFile;
|
||||
#endif
|
||||
case LLVMRustFileType::ObjectFile:
|
||||
#if LLVM_VERSION_GE(18, 0)
|
||||
return CodeGenFileType::ObjectFile;
|
||||
#else
|
||||
return CGFT_ObjectFile;
|
||||
#endif
|
||||
default:
|
||||
report_fatal_error("Bad FileType.");
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ use crate::errors::{
|
||||
use crate::{encode_metadata, EncodedMetadata};
|
||||
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::config::{OutFileName, OutputType};
|
||||
use rustc_session::output::filename_for_metadata;
|
||||
@ -40,8 +39,7 @@ pub fn emit_wrapper_file(
|
||||
}
|
||||
|
||||
pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
|
||||
let crate_name = tcx.crate_name(LOCAL_CRATE);
|
||||
let out_filename = filename_for_metadata(tcx.sess, crate_name, tcx.output_filenames(()));
|
||||
let out_filename = filename_for_metadata(tcx.sess, tcx.output_filenames(()));
|
||||
// To avoid races with another rustc process scanning the output directory,
|
||||
// we need to write the file somewhere else and atomically move it to its
|
||||
// final destination, with an `fs::rename` call. In order for the rename to
|
||||
|
@ -52,6 +52,8 @@ middle_drop_check_overflow =
|
||||
overflow while adding drop-check rules for {$ty}
|
||||
.note = overflowed on {$overflow_ty}
|
||||
|
||||
middle_erroneous_constant = erroneous constant encountered
|
||||
|
||||
middle_layout_references_error =
|
||||
the type has an unknown layout
|
||||
|
||||
|
@ -144,5 +144,12 @@ pub struct UnsupportedFnAbi {
|
||||
pub abi: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_erroneous_constant)]
|
||||
pub struct ErroneousConstant {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// Used by `rustc_const_eval`
|
||||
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
|
||||
|
@ -34,7 +34,7 @@ use std::ops::Index;
|
||||
/// variables have been rewritten to "canonical vars". These are
|
||||
/// numbered starting from 0 in order of first appearance.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Canonical<'tcx, V> {
|
||||
pub value: V,
|
||||
pub max_universe: ty::UniverseIndex,
|
||||
@ -72,7 +72,7 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
|
||||
/// variables. You will need to supply it later to instantiate the
|
||||
/// canonicalized query response.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct CanonicalVarValues<'tcx> {
|
||||
pub var_values: ty::GenericArgsRef<'tcx>,
|
||||
}
|
||||
@ -311,7 +311,7 @@ pub enum CanonicalTyVarKind {
|
||||
/// After we execute a query with a canonicalized key, we get back a
|
||||
/// `Canonical<QueryResponse<..>>`. You can use
|
||||
/// `instantiate_query_result` to access the data in this result.
|
||||
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct QueryResponse<'tcx, R> {
|
||||
pub var_values: CanonicalVarValues<'tcx>,
|
||||
pub region_constraints: QueryRegionConstraints<'tcx>,
|
||||
@ -326,7 +326,7 @@ pub struct QueryResponse<'tcx, R> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct QueryRegionConstraints<'tcx> {
|
||||
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
|
||||
pub member_constraints: Vec<MemberConstraint<'tcx>>,
|
||||
@ -432,7 +432,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
|
||||
pub type QueryOutlivesConstraint<'tcx> =
|
||||
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
TrivialTypeTraversalImpls! {
|
||||
crate::infer::canonical::Certainty,
|
||||
crate::infer::canonical::CanonicalTyVarKind,
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use rustc_span::Span;
|
||||
/// R0 member of [O1..On]
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct MemberConstraint<'tcx> {
|
||||
/// The `DefId` and args of the opaque type causing this constraint.
|
||||
/// Used for error reporting.
|
||||
|
@ -42,7 +42,7 @@ macro_rules! span_bug {
|
||||
// the impls for you.
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! CloneLiftImpls {
|
||||
macro_rules! TrivialLiftImpls {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
|
||||
@ -96,6 +96,6 @@ macro_rules! TrivialTypeTraversalImpls {
|
||||
macro_rules! TrivialTypeTraversalAndLiftImpls {
|
||||
($($t:tt)*) => {
|
||||
TrivialTypeTraversalImpls! { $($t)* }
|
||||
CloneLiftImpls! { $($t)* }
|
||||
TrivialLiftImpls! { $($t)* }
|
||||
}
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { Cache }
|
||||
TrivialTypeTraversalImpls! { Cache }
|
||||
|
||||
impl<S: Encoder> Encodable<S> for Cache {
|
||||
#[inline]
|
||||
|
@ -1,8 +1,9 @@
|
||||
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
|
||||
|
||||
use crate::error;
|
||||
use crate::mir::interpret::ConstValue;
|
||||
use crate::query::TyCtxtAt;
|
||||
use crate::ty::{layout, tls, Ty, ValTree};
|
||||
use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
|
||||
|
||||
use rustc_data_structures::sync::Lock;
|
||||
use rustc_errors::{
|
||||
@ -11,7 +12,7 @@ use rustc_errors::{
|
||||
};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_session::CtfeBacktrace;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
|
||||
use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
|
||||
|
||||
use std::borrow::Cow;
|
||||
@ -21,16 +22,51 @@ use std::{any::Any, backtrace::Backtrace, fmt};
|
||||
pub enum ErrorHandled {
|
||||
/// Already reported an error for this evaluation, and the compilation is
|
||||
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
|
||||
Reported(ReportedErrorInfo),
|
||||
Reported(ReportedErrorInfo, Span),
|
||||
/// Don't emit an error, the evaluation failed because the MIR was generic
|
||||
/// and the args didn't fully monomorphize it.
|
||||
TooGeneric,
|
||||
TooGeneric(Span),
|
||||
}
|
||||
|
||||
impl From<ErrorGuaranteed> for ErrorHandled {
|
||||
#[inline]
|
||||
fn from(error: ErrorGuaranteed) -> ErrorHandled {
|
||||
ErrorHandled::Reported(error.into())
|
||||
ErrorHandled::Reported(error.into(), DUMMY_SP)
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorHandled {
|
||||
pub fn with_span(self, span: Span) -> Self {
|
||||
match self {
|
||||
ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
|
||||
ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_err(&self, tcx: TyCtxt<'_>) -> ErrorGuaranteed {
|
||||
match self {
|
||||
&ErrorHandled::Reported(err, span) => {
|
||||
if !err.is_tainted_by_errors && !span.is_dummy() {
|
||||
tcx.sess.emit_err(error::ErroneousConstant { span });
|
||||
}
|
||||
err.error
|
||||
}
|
||||
&ErrorHandled::TooGeneric(span) => tcx.sess.delay_span_bug(
|
||||
span,
|
||||
"encountered TooGeneric error when monomorphic data was expected",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_note(&self, tcx: TyCtxt<'_>) {
|
||||
match self {
|
||||
&ErrorHandled::Reported(err, span) => {
|
||||
if !err.is_tainted_by_errors && !span.is_dummy() {
|
||||
tcx.sess.emit_note(error::ErroneousConstant { span });
|
||||
}
|
||||
}
|
||||
&ErrorHandled::TooGeneric(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,12 +81,6 @@ impl ReportedErrorInfo {
|
||||
pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
|
||||
ReportedErrorInfo { is_tainted_by_errors: true, error }
|
||||
}
|
||||
|
||||
/// Returns true if evaluation failed because MIR was tainted by errors.
|
||||
#[inline]
|
||||
pub fn is_tainted_by_errors(self) -> bool {
|
||||
self.is_tainted_by_errors
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorGuaranteed> for ReportedErrorInfo {
|
||||
@ -67,7 +97,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
|
||||
TrivialTypeTraversalImpls! { ErrorHandled }
|
||||
|
||||
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
|
||||
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
||||
@ -162,6 +192,16 @@ impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorHandled> for InterpErrorInfo<'_> {
|
||||
fn from(err: ErrorHandled) -> Self {
|
||||
InterpError::InvalidProgram(match err {
|
||||
ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
|
||||
ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
|
||||
})
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
||||
fn from(kind: InterpError<'tcx>) -> Self {
|
||||
InterpErrorInfo(Box::new(InterpErrorInfoInner {
|
||||
|
@ -162,7 +162,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
|
||||
/// - A constant
|
||||
/// - A static
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct GlobalId<'tcx> {
|
||||
/// For a constant or static, the `Instance` of the item itself.
|
||||
/// For a promoted global, the `Instance` of the function they belong to.
|
||||
|
@ -61,8 +61,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
let cid = GlobalId { instance, promoted: ct.promoted };
|
||||
self.const_eval_global_id(param_env, cid, span)
|
||||
}
|
||||
Ok(None) => Err(ErrorHandled::TooGeneric),
|
||||
Err(err) => Err(ErrorHandled::Reported(err.into())),
|
||||
// For errors during resolution, we deliberately do not point at the usage site of the constant,
|
||||
// since for these errors the place the constant is used shouldn't matter.
|
||||
Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
|
||||
Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,8 +119,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
})
|
||||
}
|
||||
Ok(None) => Err(ErrorHandled::TooGeneric),
|
||||
Err(err) => Err(ErrorHandled::Reported(err.into())),
|
||||
// For errors during resolution, we deliberately do not point at the usage site of the constant,
|
||||
// since for these errors the place the constant is used shouldn't matter.
|
||||
Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
|
||||
Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,7 +147,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
// improve caching of queries.
|
||||
let inputs = self.erase_regions(param_env.and(cid));
|
||||
if let Some(span) = span {
|
||||
self.at(span).eval_to_const_value_raw(inputs)
|
||||
// The query doesn't know where it is being invoked, so we need to fix the span.
|
||||
self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
|
||||
} else {
|
||||
self.eval_to_const_value_raw(inputs)
|
||||
}
|
||||
@ -162,7 +167,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
let inputs = self.erase_regions(param_env.and(cid));
|
||||
debug!(?inputs);
|
||||
if let Some(span) = span {
|
||||
self.at(span).eval_to_valtree(inputs)
|
||||
// The query doesn't know where it is being invoked, so we need to fix the span.
|
||||
self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span))
|
||||
} else {
|
||||
self.eval_to_valtree(inputs)
|
||||
}
|
||||
|
@ -565,6 +565,34 @@ impl<'tcx> Body<'tcx> {
|
||||
pub fn is_custom_mir(&self) -> bool {
|
||||
self.injection_phase.is_some()
|
||||
}
|
||||
|
||||
/// *Must* be called once the full substitution for this body is known, to ensure that the body
|
||||
/// is indeed fit for code generation or consumption more generally.
|
||||
///
|
||||
/// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for
|
||||
/// constants specifically. (`Option<GenericArgsRef>` could be used for that, but the fact
|
||||
/// that `Instance::args_for_mir_body` is private and instead instance exposes normalization
|
||||
/// functions makes it seem like exposing the generic args is not the intended strategy.)
|
||||
///
|
||||
/// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic,
|
||||
/// so we cannot just immediately ICE on TooGeneric.
|
||||
///
|
||||
/// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported.
|
||||
pub fn post_mono_checks(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
|
||||
) -> Result<(), ErrorHandled> {
|
||||
// For now, the only thing we have to check is is to ensure that all the constants used in
|
||||
// the body successfully evaluate.
|
||||
for &const_ in &self.required_consts {
|
||||
let c = normalize_const(const_.literal)?;
|
||||
c.eval(tcx, param_env, Some(const_.span))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
@ -744,7 +772,7 @@ pub enum BindingForm<'tcx> {
|
||||
RefForGuard,
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
|
||||
TrivialTypeTraversalImpls! { BindingForm<'tcx> }
|
||||
|
||||
mod binding_form_impl {
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
@ -2295,7 +2323,7 @@ pub struct Constant<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
|
||||
#[derive(Lift, TypeFoldable, TypeVisitable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum ConstantKind<'tcx> {
|
||||
/// This constant came from the type system.
|
||||
///
|
||||
@ -2397,10 +2425,10 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||
match self.eval(tcx, param_env, None) {
|
||||
Ok(val) => Self::Val(val, self.ty()),
|
||||
Err(ErrorHandled::Reported(guar)) => {
|
||||
Err(ErrorHandled::Reported(guar, _span)) => {
|
||||
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric) => self,
|
||||
Err(ErrorHandled::TooGeneric(_span)) => self,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2615,7 +2643,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
}
|
||||
|
||||
/// An unevaluated (potentially generic) constant used in MIR.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct UnevaluatedConst<'tcx> {
|
||||
pub def: DefId,
|
||||
|
@ -334,7 +334,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
||||
///
|
||||
/// See also `rustc_const_eval::borrow_check::constraints`.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)]
|
||||
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
|
||||
pub enum ConstraintCategory<'tcx> {
|
||||
Return(ReturnConstraint),
|
||||
Yield,
|
||||
|
@ -5,7 +5,7 @@ use rustc_ast::InlineAsmTemplatePiece;
|
||||
use super::*;
|
||||
use crate::ty;
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
TrivialTypeTraversalImpls! {
|
||||
BlockTailInfo,
|
||||
MirPhase,
|
||||
SourceInfo,
|
||||
|
@ -1140,6 +1140,7 @@ rustc_queries! {
|
||||
query reachable_set(_: ()) -> &'tcx LocalDefIdSet {
|
||||
arena_cache
|
||||
desc { "reachability" }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
|
||||
|
@ -13,7 +13,7 @@ use crate::infer::canonical::Canonical;
|
||||
use crate::mir::ConstraintCategory;
|
||||
use crate::ty::abstract_const::NotConstEvaluatable;
|
||||
use crate::ty::GenericArgsRef;
|
||||
use crate::ty::{self, AdtKind, Ty, TyCtxt};
|
||||
use crate::ty::{self, AdtKind, Ty};
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, Diagnostic};
|
||||
@ -86,7 +86,7 @@ pub enum Reveal {
|
||||
///
|
||||
/// We do not want to intern this as there are a lot of obligation causes which
|
||||
/// only live for a short period of time.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeVisitable, TypeFoldable)]
|
||||
pub struct ObligationCause<'tcx> {
|
||||
pub span: Span,
|
||||
@ -194,7 +194,7 @@ impl<'tcx> ObligationCause<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeVisitable, TypeFoldable)]
|
||||
pub struct UnifyReceiverContext<'tcx> {
|
||||
pub assoc_item: ty::AssocItem,
|
||||
@ -202,7 +202,7 @@ pub struct UnifyReceiverContext<'tcx> {
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Lift, Default, HashStable)]
|
||||
#[derive(Clone, PartialEq, Eq, Default, HashStable)]
|
||||
#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
|
||||
pub struct InternedObligationCauseCode<'tcx> {
|
||||
/// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
|
||||
@ -238,7 +238,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeVisitable, TypeFoldable)]
|
||||
pub enum ObligationCauseCode<'tcx> {
|
||||
/// Not well classified or should be obvious from the span.
|
||||
@ -470,7 +470,7 @@ pub enum WellFormedLoc {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeVisitable, TypeFoldable)]
|
||||
pub struct ImplDerivedObligationCause<'tcx> {
|
||||
pub derived: DerivedObligationCause<'tcx>,
|
||||
@ -524,14 +524,7 @@ pub enum StatementAsExpression {
|
||||
NeedsBoxing,
|
||||
}
|
||||
|
||||
impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
|
||||
type Lifted = StatementAsExpression;
|
||||
fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeVisitable, TypeFoldable)]
|
||||
pub struct MatchExpressionArmCause<'tcx> {
|
||||
pub arm_block_id: Option<hir::HirId>,
|
||||
@ -547,7 +540,7 @@ pub struct MatchExpressionArmCause<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
|
||||
pub struct IfExpressionCause<'tcx> {
|
||||
pub then_id: hir::HirId,
|
||||
pub else_id: hir::HirId,
|
||||
@ -557,7 +550,7 @@ pub struct IfExpressionCause<'tcx> {
|
||||
pub opt_suggest_box_span: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeVisitable, TypeFoldable)]
|
||||
pub struct DerivedObligationCause<'tcx> {
|
||||
/// The trait predicate of the parent obligation that led to the
|
||||
@ -570,7 +563,7 @@ pub struct DerivedObligationCause<'tcx> {
|
||||
pub parent_code: InternedObligationCauseCode<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Debug, TypeVisitable)]
|
||||
pub enum SelectionError<'tcx> {
|
||||
/// The trait is not implemented.
|
||||
Unimplemented,
|
||||
@ -593,7 +586,7 @@ pub enum SelectionError<'tcx> {
|
||||
OpaqueTypeAutoTraitLeakageUnknown(DefId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Debug, TypeVisitable)]
|
||||
pub struct SelectionOutputTypeParameterMismatch<'tcx> {
|
||||
pub found_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
pub expected_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
@ -638,7 +631,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
|
||||
/// ### The type parameter `N`
|
||||
///
|
||||
/// See explanation on `ImplSourceUserDefinedData`.
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum ImplSource<'tcx, N> {
|
||||
/// ImplSource identifying a particular impl.
|
||||
@ -704,7 +697,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||
/// is `Obligation`, as one might expect. During codegen, however, this
|
||||
/// is `()`, because codegen only requires a shallow resolution of an
|
||||
/// impl, and nested obligations are satisfied later.
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceUserDefinedData<'tcx, N> {
|
||||
pub impl_def_id: DefId,
|
||||
@ -736,7 +729,7 @@ pub enum BuiltinImplSource {
|
||||
TupleUnsizing,
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
|
||||
TrivialTypeTraversalImpls! { BuiltinImplSource }
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
|
||||
pub enum ObjectSafetyViolation {
|
||||
|
@ -17,8 +17,7 @@ pub mod type_op {
|
||||
use crate::ty::{Predicate, Ty, TyCtxt, UserType};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct AscribeUserType<'tcx> {
|
||||
pub mir_ty: Ty<'tcx>,
|
||||
pub user_ty: UserType<'tcx>,
|
||||
@ -30,22 +29,19 @@ pub mod type_op {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Eq<'tcx> {
|
||||
pub a: Ty<'tcx>,
|
||||
pub b: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Subtype<'tcx> {
|
||||
pub sub: Ty<'tcx>,
|
||||
pub sup: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct ProvePredicate<'tcx> {
|
||||
pub predicate: Predicate<'tcx>,
|
||||
}
|
||||
@ -56,8 +52,7 @@ pub mod type_op {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Normalize<T> {
|
||||
pub value: T,
|
||||
}
|
||||
@ -101,7 +96,7 @@ impl<'tcx> From<TypeError<'tcx>> for NoSolution {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct DropckOutlivesResult<'tcx> {
|
||||
pub kinds: Vec<GenericArg<'tcx>>,
|
||||
pub overflows: Vec<Ty<'tcx>>,
|
||||
@ -194,7 +189,7 @@ pub struct MethodAutoderefBadTy<'tcx> {
|
||||
}
|
||||
|
||||
/// Result from the `normalize_projection_ty` query.
|
||||
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct NormalizationResult<'tcx> {
|
||||
/// Result of normalization.
|
||||
pub normalized_ty: Ty<'tcx>,
|
||||
@ -207,7 +202,7 @@ pub struct NormalizationResult<'tcx> {
|
||||
/// case they are called implied bounds). They are fed to the
|
||||
/// `OutlivesEnv` which in turn is supplied to the region checker and
|
||||
/// other parts of the inference system.
|
||||
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift, HashStable)]
|
||||
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
|
||||
pub enum OutlivesBound<'tcx> {
|
||||
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
|
||||
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
|
||||
|
@ -305,7 +305,7 @@ impl From<ErrorGuaranteed> for OverflowError {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { OverflowError }
|
||||
TrivialTypeTraversalImpls! { OverflowError }
|
||||
|
||||
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
|
||||
|
@ -14,10 +14,16 @@ pub enum CacheHit {
|
||||
Global,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum GoalEvaluationKind {
|
||||
Root,
|
||||
Nested { is_normalizes_to_hack: IsNormalizesToHack },
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub struct GoalEvaluation<'tcx> {
|
||||
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
pub is_normalizes_to_hack: IsNormalizesToHack,
|
||||
pub kind: GoalEvaluationKind,
|
||||
pub evaluation: CanonicalGoalEvaluation<'tcx>,
|
||||
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
}
|
||||
@ -25,12 +31,12 @@ pub struct GoalEvaluation<'tcx> {
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub struct CanonicalGoalEvaluation<'tcx> {
|
||||
pub goal: CanonicalInput<'tcx>,
|
||||
pub kind: GoalEvaluationKind<'tcx>,
|
||||
pub kind: CanonicalGoalEvaluationKind<'tcx>,
|
||||
pub result: QueryResult<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum GoalEvaluationKind<'tcx> {
|
||||
pub enum CanonicalGoalEvaluationKind<'tcx> {
|
||||
Overflow,
|
||||
CacheHit(CacheHit),
|
||||
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
|
||||
@ -52,22 +58,31 @@ pub struct GoalEvaluationStep<'tcx> {
|
||||
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
|
||||
|
||||
/// The actual evaluation of the goal, always `ProbeKind::Root`.
|
||||
pub evaluation: GoalCandidate<'tcx>,
|
||||
pub evaluation: Probe<'tcx>,
|
||||
}
|
||||
|
||||
/// A self-contained computation during trait solving. This either
|
||||
/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
|
||||
/// of a goal.
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub struct GoalCandidate<'tcx> {
|
||||
pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
|
||||
pub candidates: Vec<GoalCandidate<'tcx>>,
|
||||
pub struct Probe<'tcx> {
|
||||
pub steps: Vec<ProbeStep<'tcx>>,
|
||||
pub kind: ProbeKind<'tcx>,
|
||||
}
|
||||
|
||||
impl Debug for GoalCandidate<'_> {
|
||||
impl Debug for Probe<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
ProofTreeFormatter::new(f).format_candidate(self)
|
||||
ProofTreeFormatter::new(f).format_probe(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum ProbeStep<'tcx> {
|
||||
AddGoal(Goal<'tcx, ty::Predicate<'tcx>>),
|
||||
EvaluateGoals(AddedGoalsEvaluation<'tcx>),
|
||||
NestedProbe(Probe<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ProbeKind<'tcx> {
|
||||
/// The root inference context while proving a goal.
|
||||
|
@ -40,9 +40,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
||||
}
|
||||
|
||||
pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
|
||||
let goal_text = match eval.is_normalizes_to_hack {
|
||||
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
|
||||
IsNormalizesToHack::No => "GOAL",
|
||||
let goal_text = match eval.kind {
|
||||
GoalEvaluationKind::Root => "ROOT GOAL",
|
||||
GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack {
|
||||
IsNormalizesToHack::No => "GOAL",
|
||||
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
|
||||
},
|
||||
};
|
||||
writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
|
||||
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
|
||||
@ -68,16 +71,16 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
||||
writeln!(self.f, "GOAL: {:?}", eval.goal)?;
|
||||
|
||||
match &eval.kind {
|
||||
GoalEvaluationKind::Overflow => {
|
||||
CanonicalGoalEvaluationKind::Overflow => {
|
||||
writeln!(self.f, "OVERFLOW: {:?}", eval.result)
|
||||
}
|
||||
GoalEvaluationKind::CacheHit(CacheHit::Global) => {
|
||||
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => {
|
||||
writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
|
||||
}
|
||||
GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
|
||||
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
|
||||
writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
|
||||
}
|
||||
GoalEvaluationKind::Uncached { revisions } => {
|
||||
CanonicalGoalEvaluationKind::Uncached { revisions } => {
|
||||
for (n, step) in revisions.iter().enumerate() {
|
||||
writeln!(self.f, "REVISION {n}")?;
|
||||
self.nested(|this| this.format_evaluation_step(step))?;
|
||||
@ -92,11 +95,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
||||
evaluation_step: &GoalEvaluationStep<'_>,
|
||||
) -> std::fmt::Result {
|
||||
writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
|
||||
self.format_candidate(&evaluation_step.evaluation)
|
||||
self.format_probe(&evaluation_step.evaluation)
|
||||
}
|
||||
|
||||
pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
|
||||
match &candidate.kind {
|
||||
pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
|
||||
match &probe.kind {
|
||||
ProbeKind::Root { result } => {
|
||||
writeln!(self.f, "ROOT RESULT: {result:?}")
|
||||
}
|
||||
@ -118,11 +121,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
||||
}?;
|
||||
|
||||
self.nested(|this| {
|
||||
for candidate in &candidate.candidates {
|
||||
this.format_candidate(candidate)?;
|
||||
}
|
||||
for nested in &candidate.added_goals_evaluations {
|
||||
this.format_added_goals_evaluation(nested)?;
|
||||
for step in &probe.steps {
|
||||
match step {
|
||||
ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
|
||||
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
|
||||
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
@ -27,7 +27,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable }
|
||||
TrivialTypeTraversalImpls! { NotConstEvaluatable }
|
||||
|
||||
pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
|
||||
|
||||
|
@ -76,7 +76,7 @@ pub enum PointerCoercion {
|
||||
/// At some point, of course, `Box` should move out of the compiler, in which
|
||||
/// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
|
||||
/// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct Adjustment<'tcx> {
|
||||
pub kind: Adjust<'tcx>,
|
||||
pub target: Ty<'tcx>,
|
||||
@ -88,7 +88,7 @@ impl<'tcx> Adjustment<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum Adjust<'tcx> {
|
||||
/// Go from ! to any type.
|
||||
NeverToAny,
|
||||
@ -110,7 +110,7 @@ pub enum Adjust<'tcx> {
|
||||
/// The target type is `U` in both cases, with the region and mutability
|
||||
/// being those shared by both the receiver and the returned reference.
|
||||
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct OverloadedDeref<'tcx> {
|
||||
pub region: ty::Region<'tcx>,
|
||||
pub mutbl: hir::Mutability,
|
||||
@ -182,7 +182,7 @@ impl From<AutoBorrowMutability> for hir::Mutability {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum AutoBorrow<'tcx> {
|
||||
/// Converts from T to &T.
|
||||
Ref(ty::Region<'tcx>, AutoBorrowMutability),
|
||||
|
@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> {
|
||||
}
|
||||
Err(err) => {
|
||||
let msg = match err {
|
||||
ErrorHandled::Reported(_) => "enum discriminant evaluation failed",
|
||||
ErrorHandled::TooGeneric => "enum discriminant depends on generics",
|
||||
ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
|
||||
ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
|
||||
};
|
||||
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
|
||||
None
|
||||
|
@ -6,7 +6,7 @@ pub enum BindingMode {
|
||||
BindByValue(Mutability),
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { BindingMode }
|
||||
TrivialTypeTraversalImpls! { BindingMode }
|
||||
|
||||
impl BindingMode {
|
||||
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
|
||||
|
@ -300,7 +300,7 @@ impl<'tcx> Const<'tcx> {
|
||||
| ConstKind::Infer(_)
|
||||
| ConstKind::Bound(_, _)
|
||||
| ConstKind::Placeholder(_)
|
||||
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
|
||||
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,8 +309,8 @@ impl<'tcx> Const<'tcx> {
|
||||
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||
match self.eval(tcx, param_env, None) {
|
||||
Ok(val) => Self::new_value(tcx, val, self.ty()),
|
||||
Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
|
||||
Err(ErrorHandled::TooGeneric) => self,
|
||||
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
|
||||
Err(ErrorHandled::TooGeneric(_span)) => self,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::HashStable;
|
||||
|
||||
/// An unevaluated (potentially generic) constant used in the type-system.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
|
||||
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct UnevaluatedConst<'tcx> {
|
||||
pub def: DefId,
|
||||
|
@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::Definitions;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{Constness, HirId, Node, TraitCandidate};
|
||||
use rustc_hir::{HirId, Node, TraitCandidate};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
@ -82,6 +82,7 @@ use std::ops::{Bound, Deref};
|
||||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
type GenericArgsRef = ty::GenericArgsRef<'tcx>;
|
||||
type GenericArg = ty::GenericArg<'tcx>;
|
||||
type DefId = DefId;
|
||||
type Binder<T> = Binder<'tcx, T>;
|
||||
type Ty = Ty<'tcx>;
|
||||
@ -1214,6 +1215,25 @@ macro_rules! nop_lift {
|
||||
impl<'a, 'tcx> Lift<'tcx> for $ty {
|
||||
type Lifted = $lifted;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
// Assert that the set has the right type.
|
||||
// Given an argument that has an interned type, the return type has the type of
|
||||
// the corresponding interner set. This won't actually return anything, we're
|
||||
// just doing this to compute said type!
|
||||
fn _intern_set_ty_from_interned_ty<'tcx, Inner>(
|
||||
_x: Interned<'tcx, Inner>,
|
||||
) -> InternedSet<'tcx, Inner> {
|
||||
unreachable!()
|
||||
}
|
||||
fn _type_eq<T>(_x: &T, _y: &T) {}
|
||||
fn _test<'tcx>(x: $lifted, tcx: TyCtxt<'tcx>) {
|
||||
// If `x` is a newtype around an `Interned<T>`, then `interner` is an
|
||||
// interner of appropriate type. (Ideally we'd also check that `x` is a
|
||||
// newtype with just that one field. Not sure how to do that.)
|
||||
let interner = _intern_set_ty_from_interned_ty(x.0);
|
||||
// Now check that this is the same type as `interners.$set`.
|
||||
_type_eq(&interner, &tcx.interners.$set);
|
||||
}
|
||||
|
||||
tcx.interners
|
||||
.$set
|
||||
.contains_pointer_to(&InternedInSet(&*self.0.0))
|
||||
@ -1230,6 +1250,11 @@ macro_rules! nop_list_lift {
|
||||
impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
|
||||
type Lifted = &'tcx List<$lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
// Assert that the set has the right type.
|
||||
if false {
|
||||
let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set;
|
||||
}
|
||||
|
||||
if self.is_empty() {
|
||||
return Some(List::empty());
|
||||
}
|
||||
@ -1251,19 +1276,13 @@ nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
|
||||
|
||||
nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>}
|
||||
nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>}
|
||||
nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>}
|
||||
nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
|
||||
nop_list_lift! {projs; ProjectionKind => ProjectionKind}
|
||||
nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
|
||||
|
||||
// This is the impl for `&'a GenericArgs<'a>`.
|
||||
nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>}
|
||||
|
||||
CloneLiftImpls! {
|
||||
Constness,
|
||||
traits::WellFormedLoc,
|
||||
TrivialLiftImpls! {
|
||||
ImplPolarity,
|
||||
crate::mir::ReturnConstraint,
|
||||
}
|
||||
|
||||
macro_rules! sty_debug_print {
|
||||
|
@ -11,7 +11,7 @@ use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
|
||||
pub struct ExpectedFound<T> {
|
||||
pub expected: T,
|
||||
pub found: T,
|
||||
@ -28,7 +28,7 @@ impl<T> ExpectedFound<T> {
|
||||
}
|
||||
|
||||
// Data structures used in type unification
|
||||
#[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)]
|
||||
#[rustc_pass_by_value]
|
||||
pub enum TypeError<'tcx> {
|
||||
Mismatch,
|
||||
|
@ -1029,7 +1029,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
||||
/// Stores the user-given args to reach some fully qualified path
|
||||
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct UserArgs<'tcx> {
|
||||
/// The args for the item as given by the user.
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
@ -1056,7 +1056,7 @@ pub struct UserArgs<'tcx> {
|
||||
/// the self type, giving `Foo<?A>`. Finally, we unify that with
|
||||
/// the self type here, which contains `?A` to be `&'static u32`
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct UserSelfTy<'tcx> {
|
||||
pub impl_def_id: DefId,
|
||||
pub self_ty: Ty<'tcx>,
|
||||
|
@ -18,6 +18,9 @@ use std::fmt;
|
||||
/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
|
||||
/// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval
|
||||
/// will do all required substitution as they run.
|
||||
///
|
||||
/// Note: the `Lift` impl is currently not used by rustc, but is used by
|
||||
/// rustc_codegen_cranelift when the `jit` feature is enabled.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
||||
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
|
||||
pub struct Instance<'tcx> {
|
||||
|
@ -1510,7 +1510,7 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct OpaqueTypeKey<'tcx> {
|
||||
pub def_id: LocalDefId,
|
||||
@ -1793,7 +1793,7 @@ impl<'tcx> ParamEnv<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
|
||||
#[derive(HashStable, Lift)]
|
||||
#[derive(HashStable)]
|
||||
pub struct ParamEnvAnd<'tcx, T> {
|
||||
pub param_env: ParamEnv<'tcx>,
|
||||
pub value: T,
|
||||
@ -2408,6 +2408,22 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_attrs_by_path<'attr>(
|
||||
self,
|
||||
did: DefId,
|
||||
attr: &'attr [Symbol],
|
||||
) -> impl Iterator<Item = &'tcx ast::Attribute> + 'attr
|
||||
where
|
||||
'tcx: 'attr,
|
||||
{
|
||||
let filter_fn = move |a: &&ast::Attribute| a.path_matches(&attr);
|
||||
if let Some(did) = did.as_local() {
|
||||
self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
|
||||
} else {
|
||||
self.item_attrs(did).iter().filter(filter_fn)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> {
|
||||
if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
|
||||
let did: DefId = did.into();
|
||||
|
@ -136,10 +136,8 @@ define_helper!(
|
||||
///
|
||||
/// Regions not selected by the region highlight mode are presently
|
||||
/// unaffected.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct RegionHighlightMode<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
/// If enabled, when we see the selected region, use "`'N`"
|
||||
/// instead of the ordinary behavior.
|
||||
highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
|
||||
@ -155,14 +153,6 @@ pub struct RegionHighlightMode<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> RegionHighlightMode<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
highlight_regions: Default::default(),
|
||||
highlight_bound_region: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// If `region` and `number` are both `Some`, invokes
|
||||
/// `highlighting_region`.
|
||||
pub fn maybe_highlighting_region(
|
||||
@ -188,8 +178,13 @@ impl<'tcx> RegionHighlightMode<'tcx> {
|
||||
}
|
||||
|
||||
/// Convenience wrapper for `highlighting_region`.
|
||||
pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
|
||||
self.highlighting_region(ty::Region::new_var(self.tcx, vid), number)
|
||||
pub fn highlighting_region_vid(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
vid: ty::RegionVid,
|
||||
number: usize,
|
||||
) {
|
||||
self.highlighting_region(ty::Region::new_var(tcx, vid), number)
|
||||
}
|
||||
|
||||
/// Returns `Some(n)` with the number to use for the given region, if any.
|
||||
@ -1778,7 +1773,7 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
|
||||
printed_type_count: 0,
|
||||
type_length_limit,
|
||||
truncated: false,
|
||||
region_highlight_mode: RegionHighlightMode::new(tcx),
|
||||
region_highlight_mode: RegionHighlightMode::default(),
|
||||
ty_infer_name_resolver: None,
|
||||
const_infer_name_resolver: None,
|
||||
}))
|
||||
@ -2746,20 +2741,14 @@ forward_display_to_print! {
|
||||
|
||||
// HACK(eddyb) these are exhaustive instead of generic,
|
||||
// because `for<'tcx>` isn't possible yet.
|
||||
ty::PolyExistentialPredicate<'tcx>,
|
||||
ty::PolyExistentialProjection<'tcx>,
|
||||
ty::PolyExistentialTraitRef<'tcx>,
|
||||
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
||||
ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
|
||||
ty::Binder<'tcx, ty::FnSig<'tcx>>,
|
||||
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
||||
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
|
||||
ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
|
||||
ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
|
||||
ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
|
||||
ty::Binder<'tcx, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>,
|
||||
|
||||
ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
|
||||
ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
|
||||
}
|
||||
|
@ -9,15 +9,13 @@ use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
|
||||
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_target::abi::TyAndLayout;
|
||||
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||
|
||||
use std::fmt::{self, Debug};
|
||||
use std::ops::ControlFlow;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::print::PrettyPrinter;
|
||||
use super::{GenericArg, GenericArgKind, Region};
|
||||
|
||||
impl fmt::Debug for ty::TraitDef {
|
||||
@ -343,14 +341,27 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
|
||||
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||
f: &mut core::fmt::Formatter<'_>,
|
||||
) -> core::fmt::Result {
|
||||
// This reflects what `Const` looked liked before `Interned` was
|
||||
// introduced. We print it like this to avoid having to update expected
|
||||
// output in a lot of tests.
|
||||
// If this is a value, we spend some effort to make it look nice.
|
||||
if let ConstKind::Value(_) = this.data.kind() {
|
||||
return ty::tls::with(move |tcx| {
|
||||
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
|
||||
// entire constant.
|
||||
let lifted = tcx.lift(*this.data).unwrap();
|
||||
let ConstKind::Value(valtree) = lifted.kind() else {
|
||||
bug!("we checked that this is a valtree")
|
||||
};
|
||||
let cx = FmtPrinter::new(tcx, Namespace::ValueNS);
|
||||
let cx =
|
||||
cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?;
|
||||
f.write_str(&cx.into_buffer())
|
||||
});
|
||||
}
|
||||
// Fall back to something verbose.
|
||||
write!(
|
||||
f,
|
||||
"Const {{ ty: {:?}, kind: {:?} }}",
|
||||
&this.map(|data| data.ty()),
|
||||
&this.map(|data| data.kind())
|
||||
"{kind:?}: {ty:?}",
|
||||
ty = &this.map(|data| data.ty()),
|
||||
kind = &this.map(|data| data.kind())
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -442,22 +453,16 @@ impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty:
|
||||
|
||||
// For things for which the type library provides traversal implementations
|
||||
// for all Interners, we only need to provide a Lift implementation:
|
||||
CloneLiftImpls! {
|
||||
(),
|
||||
bool,
|
||||
usize,
|
||||
u16,
|
||||
u32,
|
||||
u64,
|
||||
String,
|
||||
rustc_type_ir::DebruijnIndex,
|
||||
TrivialLiftImpls! {
|
||||
(),
|
||||
bool,
|
||||
usize,
|
||||
}
|
||||
|
||||
// For things about which the type library does not know, or does not
|
||||
// provide any traversal implementations, we need to provide both a Lift
|
||||
// implementation and traversal implementations (the latter only for
|
||||
// TyCtxt<'_> interners).
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
// For some things about which the type library does not know, or does not
|
||||
// provide any traversal implementations, we need to provide a traversal
|
||||
// implementation (only for TyCtxt<'_> interners).
|
||||
TrivialTypeTraversalImpls! {
|
||||
::rustc_target::abi::FieldIdx,
|
||||
::rustc_target::abi::VariantIdx,
|
||||
crate::middle::region::Scope,
|
||||
@ -467,14 +472,10 @@ TrivialTypeTraversalAndLiftImpls! {
|
||||
::rustc_ast::NodeId,
|
||||
::rustc_span::symbol::Symbol,
|
||||
::rustc_hir::def::Res,
|
||||
::rustc_hir::def_id::DefId,
|
||||
::rustc_hir::def_id::LocalDefId,
|
||||
::rustc_hir::HirId,
|
||||
::rustc_hir::MatchSource,
|
||||
::rustc_hir::Mutability,
|
||||
::rustc_hir::Unsafety,
|
||||
::rustc_target::asm::InlineAsmRegOrRegClass,
|
||||
::rustc_target::spec::abi::Abi,
|
||||
crate::mir::coverage::CounterId,
|
||||
crate::mir::coverage::ExpressionId,
|
||||
crate::mir::coverage::MappedExpressionIndex,
|
||||
@ -492,16 +493,12 @@ TrivialTypeTraversalAndLiftImpls! {
|
||||
crate::ty::AssocItem,
|
||||
crate::ty::AssocKind,
|
||||
crate::ty::AliasKind,
|
||||
crate::ty::AliasRelationDirection,
|
||||
crate::ty::Placeholder<crate::ty::BoundRegion>,
|
||||
crate::ty::Placeholder<crate::ty::BoundTy>,
|
||||
crate::ty::Placeholder<ty::BoundVar>,
|
||||
crate::ty::ClosureKind,
|
||||
crate::ty::FreeRegion,
|
||||
crate::ty::InferTy,
|
||||
crate::ty::IntVarValue,
|
||||
crate::ty::ParamConst,
|
||||
crate::ty::ParamTy,
|
||||
crate::ty::adjustment::PointerCoercion,
|
||||
crate::ty::RegionVid,
|
||||
crate::ty::UniverseIndex,
|
||||
@ -509,33 +506,30 @@ TrivialTypeTraversalAndLiftImpls! {
|
||||
::rustc_span::Span,
|
||||
::rustc_span::symbol::Ident,
|
||||
::rustc_errors::ErrorGuaranteed,
|
||||
ty::BoundVar,
|
||||
ty::ValTree<'tcx>,
|
||||
}
|
||||
// For some things about which the type library does not know, or does not
|
||||
// provide any traversal implementations, we need to provide a traversal
|
||||
// implementation and a lift implementation (the former only for TyCtxt<'_>
|
||||
// interners).
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
::rustc_hir::def_id::DefId,
|
||||
::rustc_hir::Mutability,
|
||||
::rustc_hir::Unsafety,
|
||||
::rustc_target::spec::abi::Abi,
|
||||
crate::ty::AliasRelationDirection,
|
||||
crate::ty::ClosureKind,
|
||||
crate::ty::ParamConst,
|
||||
crate::ty::ParamTy,
|
||||
interpret::Scalar,
|
||||
interpret::AllocId,
|
||||
rustc_target::abi::Size,
|
||||
ty::BoundVar,
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
ty::ValTree<'tcx>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Lift implementations
|
||||
|
||||
impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
|
||||
type Lifted = (A::Lifted, B::Lifted);
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
Some((tcx.lift(self.0)?, tcx.lift(self.1)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) {
|
||||
type Lifted = (A::Lifted, B::Lifted, C::Lifted);
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
Some((tcx.lift(self.0)?, tcx.lift(self.1)?, tcx.lift(self.2)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
|
||||
type Lifted = Option<T::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
@ -546,50 +540,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
|
||||
type Lifted = Result<T::Lifted, E::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
match self {
|
||||
Ok(x) => tcx.lift(x).map(Ok),
|
||||
Err(e) => tcx.lift(e).map(Err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
|
||||
type Lifted = Box<T::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
Some(Box::new(tcx.lift(*self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc<T> {
|
||||
type Lifted = Rc<T::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
Some(Rc::new(tcx.lift(self.as_ref().clone())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> {
|
||||
type Lifted = Arc<T::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
Some(Arc::new(tcx.lift(self.as_ref().clone())?))
|
||||
}
|
||||
}
|
||||
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> {
|
||||
type Lifted = Vec<T::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
self.into_iter().map(|v| tcx.lift(v)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> {
|
||||
type Lifted = IndexVec<I, T::Lifted>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
self.into_iter().map(|e| tcx.lift(e)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
|
||||
type Lifted = ty::Term<'tcx>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
@ -602,13 +552,6 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
|
||||
type Lifted = ty::ParamEnv<'tcx>;
|
||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(self.caller_bounds())
|
||||
.map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Traversal implementations.
|
||||
|
@ -351,7 +351,7 @@ impl<'tcx> ClosureArgs<'tcx> {
|
||||
}
|
||||
|
||||
/// Similar to `ClosureArgs`; see the above documentation for more.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
|
||||
pub struct GeneratorArgs<'tcx> {
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
}
|
||||
@ -1305,7 +1305,7 @@ impl<'tcx> AliasTy<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
|
||||
pub struct GenSig<'tcx> {
|
||||
pub resume_ty: Ty<'tcx>,
|
||||
pub yield_ty: Ty<'tcx>,
|
||||
|
@ -165,7 +165,7 @@ pub struct TypeckResults<'tcx> {
|
||||
/// reading places that are mentioned in a closure (because of _ patterns). However,
|
||||
/// to ensure the places are initialized, we introduce fake reads.
|
||||
/// Consider these two examples:
|
||||
/// ``` (discriminant matching with only wildcard arm)
|
||||
/// ```ignore (discriminant matching with only wildcard arm)
|
||||
/// let x: u8;
|
||||
/// let c = || match x { _ => () };
|
||||
/// ```
|
||||
@ -173,7 +173,7 @@ pub struct TypeckResults<'tcx> {
|
||||
/// want to capture it. However, we do still want an error here, because `x` should have
|
||||
/// to be initialized at the point where c is created. Therefore, we add a "fake read"
|
||||
/// instead.
|
||||
/// ``` (destructured assignments)
|
||||
/// ```ignore (destructured assignments)
|
||||
/// let c = || {
|
||||
/// let (t1, t2) = t;
|
||||
/// }
|
||||
@ -654,7 +654,7 @@ rustc_index::newtype_index! {
|
||||
pub type CanonicalUserTypeAnnotations<'tcx> =
|
||||
IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
|
||||
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct CanonicalUserTypeAnnotation<'tcx> {
|
||||
pub user_ty: Box<CanonicalUserType<'tcx>>,
|
||||
pub span: Span,
|
||||
@ -714,7 +714,7 @@ impl<'tcx> CanonicalUserType<'tcx> {
|
||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||
/// so forth.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub enum UserType<'tcx> {
|
||||
Ty(Ty<'tcx>),
|
||||
|
||||
|
@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
pattern
|
||||
}
|
||||
}
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
// While `Reported | Linted` cases will have diagnostics emitted already
|
||||
// it is not true for TooGeneric case, so we need to give user more information.
|
||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
@ -640,14 +640,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
.kind
|
||||
} else {
|
||||
// If that fails, convert it to an opaque constant pattern.
|
||||
match tcx.const_eval_resolve(self.param_env, uneval, None) {
|
||||
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
|
||||
Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
|
||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
PatKind::Wild
|
||||
}
|
||||
Err(ErrorHandled::Reported(_)) => PatKind::Wild,
|
||||
Err(ErrorHandled::Reported(..)) => PatKind::Wild,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,25 +105,12 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
|
||||
|
||||
trace!("ConstProp starting for {:?}", def_id);
|
||||
|
||||
let dummy_body = &Body::new(
|
||||
body.source,
|
||||
(*body.basic_blocks).to_owned(),
|
||||
body.source_scopes.clone(),
|
||||
body.local_decls.clone(),
|
||||
Default::default(),
|
||||
body.arg_count,
|
||||
Default::default(),
|
||||
body.span,
|
||||
body.generator_kind(),
|
||||
body.tainted_by_errors,
|
||||
);
|
||||
|
||||
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
|
||||
// constants, instead of just checking for const-folding succeeding.
|
||||
// That would require a uniform one-def no-mutation analysis
|
||||
// and RPO (or recursing when needing the value of a local).
|
||||
let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
|
||||
optimization_finder.visit_body(body);
|
||||
let mut linter = ConstPropagator::new(body, tcx);
|
||||
linter.visit_body(body);
|
||||
|
||||
trace!("ConstProp done for {:?}", def_id);
|
||||
}
|
||||
@ -169,11 +156,7 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||
fn new(
|
||||
body: &Body<'tcx>,
|
||||
dummy_body: &'mir Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ConstPropagator<'mir, 'tcx> {
|
||||
fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
|
||||
let def_id = body.source.def_id();
|
||||
let args = &GenericArgs::identity_for_item(tcx, def_id);
|
||||
let param_env = tcx.param_env_reveal_all_normalized(def_id);
|
||||
@ -204,7 +187,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||
|
||||
ecx.push_stack_frame(
|
||||
Instance::new(def_id, args),
|
||||
dummy_body,
|
||||
body,
|
||||
&ret,
|
||||
StackPopCleanup::Root { cleanup: false },
|
||||
)
|
||||
|
@ -44,7 +44,7 @@
|
||||
//! points, which can be enabled via environment variable:
|
||||
//!
|
||||
//! ```shell
|
||||
//! RUSTC_LOG=rustc_mir_transform::transform::coverage=debug
|
||||
//! RUSTC_LOG=rustc_mir_transform::coverage=debug
|
||||
//! ```
|
||||
//!
|
||||
//! Other module paths with coverage-related debug logs may also be of interest, particularly for
|
||||
@ -52,7 +52,7 @@
|
||||
//! code generation pass). For example:
|
||||
//!
|
||||
//! ```shell
|
||||
//! RUSTC_LOG=rustc_mir_transform::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
|
||||
//! RUSTC_LOG=rustc_mir_transform::coverage,rustc_codegen_llvm::coverageinfo=debug
|
||||
//! ```
|
||||
//!
|
||||
//! Coverage Debug Options
|
||||
@ -108,24 +108,23 @@
|
||||
//! recursively, generating labels with nested operations, enclosed in parentheses
|
||||
//! (for example: `bcb2 + (bcb0 - bcb1)`).
|
||||
|
||||
use super::counters::{BcbCounter, CoverageCounters};
|
||||
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
|
||||
use super::spans::CoverageSpan;
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use itertools::Itertools;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_middle::mir::coverage::*;
|
||||
use rustc_middle::mir::create_dump_file;
|
||||
use rustc_middle::mir::generic_graphviz::GraphvizWriter;
|
||||
use rustc_middle::mir::spanview::{self, SpanViewable};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::mir::coverage::*;
|
||||
use rustc_middle::mir::{self, BasicBlock};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
use std::sync::OnceLock;
|
||||
use super::counters::{BcbCounter, CoverageCounters};
|
||||
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
|
||||
use super::spans::CoverageSpan;
|
||||
|
||||
pub const NESTED_INDENT: &str = " ";
|
||||
|
||||
@ -259,36 +258,42 @@ impl Default for ExpressionFormat {
|
||||
/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
|
||||
/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
|
||||
pub(super) struct DebugCounters {
|
||||
some_counters: Option<FxHashMap<Operand, DebugCounter>>,
|
||||
state: Option<DebugCountersState>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct DebugCountersState {
|
||||
counters: FxHashMap<Operand, DebugCounter>,
|
||||
}
|
||||
|
||||
impl DebugCounters {
|
||||
pub fn new() -> Self {
|
||||
Self { some_counters: None }
|
||||
Self { state: None }
|
||||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
debug_assert!(!self.is_enabled());
|
||||
self.some_counters.replace(FxHashMap::default());
|
||||
self.state = Some(DebugCountersState::default());
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.some_counters.is_some()
|
||||
self.state.is_some()
|
||||
}
|
||||
|
||||
pub fn add_counter(&mut self, counter_kind: &BcbCounter, some_block_label: Option<String>) {
|
||||
if let Some(counters) = &mut self.some_counters {
|
||||
let id = counter_kind.as_operand();
|
||||
counters
|
||||
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
|
||||
.expect("attempt to add the same counter_kind to DebugCounters more than once");
|
||||
}
|
||||
let Some(state) = &mut self.state else { return };
|
||||
|
||||
let id = counter_kind.as_operand();
|
||||
state
|
||||
.counters
|
||||
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
|
||||
.expect("attempt to add the same counter_kind to DebugCounters more than once");
|
||||
}
|
||||
|
||||
pub fn some_block_label(&self, operand: Operand) -> Option<&String> {
|
||||
self.some_counters.as_ref().and_then(|counters| {
|
||||
counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
|
||||
})
|
||||
let Some(state) = &self.state else { return None };
|
||||
|
||||
state.counters.get(&operand)?.some_block_label.as_ref()
|
||||
}
|
||||
|
||||
pub fn format_counter(&self, counter_kind: &BcbCounter) -> String {
|
||||
@ -308,7 +313,7 @@ impl DebugCounters {
|
||||
if counter_format.operation {
|
||||
return format!(
|
||||
"{}{} {} {}",
|
||||
if counter_format.id || self.some_counters.is_none() {
|
||||
if counter_format.id || !self.is_enabled() {
|
||||
format!("#{} = ", id.index())
|
||||
} else {
|
||||
String::new()
|
||||
@ -324,10 +329,9 @@ impl DebugCounters {
|
||||
}
|
||||
|
||||
let id = counter_kind.as_operand();
|
||||
if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
|
||||
let counters = self.some_counters.as_ref().unwrap();
|
||||
if let Some(state) = &self.state && (counter_format.block || !counter_format.id) {
|
||||
if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
|
||||
counters.get(&id)
|
||||
state.counters.get(&id)
|
||||
{
|
||||
return if counter_format.id {
|
||||
format!("{}#{:?}", block_label, id)
|
||||
@ -343,8 +347,10 @@ impl DebugCounters {
|
||||
if matches!(operand, Operand::Zero) {
|
||||
return String::from("0");
|
||||
}
|
||||
if let Some(counters) = &self.some_counters {
|
||||
if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) {
|
||||
if let Some(state) = &self.state {
|
||||
if let Some(DebugCounter { counter_kind, some_block_label }) =
|
||||
state.counters.get(&operand)
|
||||
{
|
||||
if let BcbCounter::Expression { .. } = counter_kind {
|
||||
if let Some(label) = some_block_label && debug_options().counter_format.block {
|
||||
return format!(
|
||||
@ -378,30 +384,29 @@ impl DebugCounter {
|
||||
/// If enabled, this data structure captures additional debugging information used when generating
|
||||
/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
|
||||
pub(super) struct GraphvizData {
|
||||
some_bcb_to_coverage_spans_with_counters:
|
||||
Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>>,
|
||||
some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>>,
|
||||
some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>>,
|
||||
state: Option<GraphvizDataState>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct GraphvizDataState {
|
||||
bcb_to_coverage_spans_with_counters:
|
||||
FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>,
|
||||
bcb_to_dependency_counters: FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>,
|
||||
edge_to_counter: FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>,
|
||||
}
|
||||
|
||||
impl GraphvizData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
some_bcb_to_coverage_spans_with_counters: None,
|
||||
some_bcb_to_dependency_counters: None,
|
||||
some_edge_to_counter: None,
|
||||
}
|
||||
Self { state: None }
|
||||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
debug_assert!(!self.is_enabled());
|
||||
self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default());
|
||||
self.some_bcb_to_dependency_counters = Some(FxHashMap::default());
|
||||
self.some_edge_to_counter = Some(FxHashMap::default());
|
||||
self.state = Some(GraphvizDataState::default());
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.some_bcb_to_coverage_spans_with_counters.is_some()
|
||||
self.state.is_some()
|
||||
}
|
||||
|
||||
pub fn add_bcb_coverage_span_with_counter(
|
||||
@ -410,27 +415,22 @@ impl GraphvizData {
|
||||
coverage_span: &CoverageSpan,
|
||||
counter_kind: &BcbCounter,
|
||||
) {
|
||||
if let Some(bcb_to_coverage_spans_with_counters) =
|
||||
self.some_bcb_to_coverage_spans_with_counters.as_mut()
|
||||
{
|
||||
bcb_to_coverage_spans_with_counters
|
||||
.entry(bcb)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((coverage_span.clone(), counter_kind.clone()));
|
||||
}
|
||||
let Some(state) = &mut self.state else { return };
|
||||
|
||||
state
|
||||
.bcb_to_coverage_spans_with_counters
|
||||
.entry(bcb)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((coverage_span.clone(), counter_kind.clone()));
|
||||
}
|
||||
|
||||
pub fn get_bcb_coverage_spans_with_counters(
|
||||
&self,
|
||||
bcb: BasicCoverageBlock,
|
||||
) -> Option<&[(CoverageSpan, BcbCounter)]> {
|
||||
if let Some(bcb_to_coverage_spans_with_counters) =
|
||||
self.some_bcb_to_coverage_spans_with_counters.as_ref()
|
||||
{
|
||||
bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let Some(state) = &self.state else { return None };
|
||||
|
||||
state.bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
|
||||
}
|
||||
|
||||
pub fn add_bcb_dependency_counter(
|
||||
@ -438,20 +438,19 @@ impl GraphvizData {
|
||||
bcb: BasicCoverageBlock,
|
||||
counter_kind: &BcbCounter,
|
||||
) {
|
||||
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
|
||||
bcb_to_dependency_counters
|
||||
.entry(bcb)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(counter_kind.clone());
|
||||
}
|
||||
let Some(state) = &mut self.state else { return };
|
||||
|
||||
state
|
||||
.bcb_to_dependency_counters
|
||||
.entry(bcb)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(counter_kind.clone());
|
||||
}
|
||||
|
||||
pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[BcbCounter]> {
|
||||
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() {
|
||||
bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let Some(state) = &self.state else { return None };
|
||||
|
||||
state.bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
|
||||
}
|
||||
|
||||
pub fn set_edge_counter(
|
||||
@ -460,11 +459,12 @@ impl GraphvizData {
|
||||
to_bb: BasicBlock,
|
||||
counter_kind: &BcbCounter,
|
||||
) {
|
||||
if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
|
||||
edge_to_counter
|
||||
.try_insert((from_bcb, to_bb), counter_kind.clone())
|
||||
.expect("invalid attempt to insert more than one edge counter for the same edge");
|
||||
}
|
||||
let Some(state) = &mut self.state else { return };
|
||||
|
||||
state
|
||||
.edge_to_counter
|
||||
.try_insert((from_bcb, to_bb), counter_kind.clone())
|
||||
.expect("invalid attempt to insert more than one edge counter for the same edge");
|
||||
}
|
||||
|
||||
pub fn get_edge_counter(
|
||||
@ -472,11 +472,9 @@ impl GraphvizData {
|
||||
from_bcb: BasicCoverageBlock,
|
||||
to_bb: BasicBlock,
|
||||
) -> Option<&BcbCounter> {
|
||||
if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() {
|
||||
edge_to_counter.get(&(from_bcb, to_bb))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let Some(state) = &self.state else { return None };
|
||||
|
||||
state.edge_to_counter.get(&(from_bcb, to_bb))
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,41 +483,42 @@ impl GraphvizData {
|
||||
/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
|
||||
/// and/or a `CoverageGraph` graphviz output).
|
||||
pub(super) struct UsedExpressions {
|
||||
some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
|
||||
some_unused_expressions:
|
||||
Option<Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
|
||||
state: Option<UsedExpressionsState>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct UsedExpressionsState {
|
||||
used_expression_operands: FxHashSet<Operand>,
|
||||
unused_expressions: Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>,
|
||||
}
|
||||
|
||||
impl UsedExpressions {
|
||||
pub fn new() -> Self {
|
||||
Self { some_used_expression_operands: None, some_unused_expressions: None }
|
||||
Self { state: None }
|
||||
}
|
||||
|
||||
pub fn enable(&mut self) {
|
||||
debug_assert!(!self.is_enabled());
|
||||
self.some_used_expression_operands = Some(FxHashMap::default());
|
||||
self.some_unused_expressions = Some(Vec::new());
|
||||
self.state = Some(UsedExpressionsState::default())
|
||||
}
|
||||
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.some_used_expression_operands.is_some()
|
||||
self.state.is_some()
|
||||
}
|
||||
|
||||
pub fn add_expression_operands(&mut self, expression: &BcbCounter) {
|
||||
if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
|
||||
if let BcbCounter::Expression { id, lhs, rhs, .. } = *expression {
|
||||
used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
|
||||
used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
|
||||
}
|
||||
let Some(state) = &mut self.state else { return };
|
||||
|
||||
if let BcbCounter::Expression { lhs, rhs, .. } = *expression {
|
||||
state.used_expression_operands.insert(lhs);
|
||||
state.used_expression_operands.insert(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expression_is_used(&self, expression: &BcbCounter) -> bool {
|
||||
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
|
||||
used_expression_operands.contains_key(&expression.as_operand())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
let Some(state) = &self.state else { return false };
|
||||
|
||||
state.used_expression_operands.contains(&expression.as_operand())
|
||||
}
|
||||
|
||||
pub fn add_unused_expression_if_not_found(
|
||||
@ -528,14 +527,10 @@ impl UsedExpressions {
|
||||
edge_from_bcb: Option<BasicCoverageBlock>,
|
||||
target_bcb: BasicCoverageBlock,
|
||||
) {
|
||||
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
|
||||
if !used_expression_operands.contains_key(&expression.as_operand()) {
|
||||
self.some_unused_expressions.as_mut().unwrap().push((
|
||||
expression.clone(),
|
||||
edge_from_bcb,
|
||||
target_bcb,
|
||||
));
|
||||
}
|
||||
let Some(state) = &mut self.state else { return };
|
||||
|
||||
if !state.used_expression_operands.contains(&expression.as_operand()) {
|
||||
state.unused_expressions.push((expression.clone(), edge_from_bcb, target_bcb));
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,11 +539,9 @@ impl UsedExpressions {
|
||||
pub fn get_unused_expressions(
|
||||
&self,
|
||||
) -> Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
|
||||
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
|
||||
unused_expressions.clone()
|
||||
} else {
|
||||
Vec::new()
|
||||
}
|
||||
let Some(state) = &self.state else { return Vec::new() };
|
||||
|
||||
state.unused_expressions.clone()
|
||||
}
|
||||
|
||||
/// If enabled, validate that every BCB or edge counter not directly associated with a coverage
|
||||
@ -562,51 +555,53 @@ impl UsedExpressions {
|
||||
BcbCounter,
|
||||
)],
|
||||
) {
|
||||
if self.is_enabled() {
|
||||
let mut not_validated = bcb_counters_without_direct_coverage_spans
|
||||
.iter()
|
||||
.map(|(_, _, counter_kind)| counter_kind)
|
||||
.collect::<Vec<_>>();
|
||||
let mut validating_count = 0;
|
||||
while not_validated.len() != validating_count {
|
||||
let to_validate = not_validated.split_off(0);
|
||||
validating_count = to_validate.len();
|
||||
for counter_kind in to_validate {
|
||||
if self.expression_is_used(counter_kind) {
|
||||
self.add_expression_operands(counter_kind);
|
||||
} else {
|
||||
not_validated.push(counter_kind);
|
||||
}
|
||||
if !self.is_enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut not_validated = bcb_counters_without_direct_coverage_spans
|
||||
.iter()
|
||||
.map(|(_, _, counter_kind)| counter_kind)
|
||||
.collect::<Vec<_>>();
|
||||
let mut validating_count = 0;
|
||||
while not_validated.len() != validating_count {
|
||||
let to_validate = not_validated.split_off(0);
|
||||
validating_count = to_validate.len();
|
||||
for counter_kind in to_validate {
|
||||
if self.expression_is_used(counter_kind) {
|
||||
self.add_expression_operands(counter_kind);
|
||||
} else {
|
||||
not_validated.push(counter_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) {
|
||||
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
|
||||
for (counter_kind, edge_from_bcb, target_bcb) in unused_expressions {
|
||||
let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
|
||||
format!(
|
||||
"non-coverage edge counter found without a dependent expression, in \
|
||||
{:?}->{:?}; counter={}",
|
||||
from_bcb,
|
||||
target_bcb,
|
||||
debug_counters.format_counter(&counter_kind),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"non-coverage counter found without a dependent expression, in {:?}; \
|
||||
counter={}",
|
||||
target_bcb,
|
||||
debug_counters.format_counter(&counter_kind),
|
||||
)
|
||||
};
|
||||
let Some(state) = &self.state else { return };
|
||||
|
||||
if debug_options().allow_unused_expressions {
|
||||
debug!("WARNING: {}", unused_counter_message);
|
||||
} else {
|
||||
bug!("{}", unused_counter_message);
|
||||
}
|
||||
for (counter_kind, edge_from_bcb, target_bcb) in &state.unused_expressions {
|
||||
let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
|
||||
format!(
|
||||
"non-coverage edge counter found without a dependent expression, in \
|
||||
{:?}->{:?}; counter={}",
|
||||
from_bcb,
|
||||
target_bcb,
|
||||
debug_counters.format_counter(&counter_kind),
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"non-coverage counter found without a dependent expression, in {:?}; \
|
||||
counter={}",
|
||||
target_bcb,
|
||||
debug_counters.format_counter(&counter_kind),
|
||||
)
|
||||
};
|
||||
|
||||
if debug_options().allow_unused_expressions {
|
||||
debug!("WARNING: {}", unused_counter_message);
|
||||
} else {
|
||||
bug!("{}", unused_counter_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,12 +199,8 @@ impl CoverageGraph {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn rank_partial_cmp(
|
||||
&self,
|
||||
a: BasicCoverageBlock,
|
||||
b: BasicCoverageBlock,
|
||||
) -> Option<Ordering> {
|
||||
self.dominators.as_ref().unwrap().rank_partial_cmp(a, b)
|
||||
pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering {
|
||||
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user