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
|
- name: disable git crlf conversion
|
||||||
run: git config --global core.autocrlf false
|
run: git config --global core.autocrlf false
|
||||||
- name: checkout the source code
|
- name: checkout the source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
- name: configure the PR in which the error message will be posted
|
- name: configure the PR in which the error message will be posted
|
||||||
@ -393,7 +393,7 @@ jobs:
|
|||||||
- name: dist-x86_64-msvc
|
- name: dist-x86_64-msvc
|
||||||
env:
|
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"
|
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
|
DIST_REQUIRE_ALL_TOOLS: 1
|
||||||
os: windows-2019-8core-32gb
|
os: windows-2019-8core-32gb
|
||||||
- name: dist-i686-msvc
|
- name: dist-i686-msvc
|
||||||
@ -435,7 +435,7 @@ jobs:
|
|||||||
- name: disable git crlf conversion
|
- name: disable git crlf conversion
|
||||||
run: git config --global core.autocrlf false
|
run: git config --global core.autocrlf false
|
||||||
- name: checkout the source code
|
- name: checkout the source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
- name: configure the PR in which the error message will be posted
|
- name: configure the PR in which the error message will be posted
|
||||||
@ -555,7 +555,7 @@ jobs:
|
|||||||
- name: disable git crlf conversion
|
- name: disable git crlf conversion
|
||||||
run: git config --global core.autocrlf false
|
run: git config --global core.autocrlf false
|
||||||
- name: checkout the source code
|
- name: checkout the source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
- name: configure the PR in which the error message will be posted
|
- 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'"
|
if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
|
||||||
steps:
|
steps:
|
||||||
- name: checkout the source code
|
- name: checkout the source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
- name: publish toolstate
|
- name: publish toolstate
|
||||||
|
4
.github/workflows/dependencies.yml
vendored
4
.github/workflows/dependencies.yml
vendored
@ -50,7 +50,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout the source code
|
- name: checkout the source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: install the bootstrap toolchain
|
- name: install the bootstrap toolchain
|
||||||
@ -87,7 +87,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: checkout the source code
|
- name: checkout the source code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: download Cargo.lock from update job
|
- name: download Cargo.lock from update job
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -58,7 +58,6 @@ build/
|
|||||||
\#*
|
\#*
|
||||||
\#*\#
|
\#*\#
|
||||||
.#*
|
.#*
|
||||||
rustc-ice-*.txt
|
|
||||||
|
|
||||||
## Tags
|
## Tags
|
||||||
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.j.strand@gmail.com>
|
||||||
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
|
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
|
||||||
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.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>
|
lcnr <rust@lcnr.de> <bastian_kauschke@hotmail.de>
|
||||||
Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
|
Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
|
||||||
Lee Wondong <wdlee91@gmail.com>
|
Lee Wondong <wdlee91@gmail.com>
|
||||||
@ -549,6 +550,8 @@ Timothy Maloney <tmaloney@pdx.edu>
|
|||||||
Tomas Koutsky <tomas@stepnivlk.net>
|
Tomas Koutsky <tomas@stepnivlk.net>
|
||||||
Torsten Weber <TorstenWeber12@gmail.com>
|
Torsten Weber <TorstenWeber12@gmail.com>
|
||||||
Torsten Weber <TorstenWeber12@gmail.com> <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>
|
Trevor Spiteri <tspiteri@ieee.org> <trevor.spiteri@um.edu.mt>
|
||||||
Tshepang Mbambo <tshepang@gmail.com>
|
Tshepang Mbambo <tshepang@gmail.com>
|
||||||
Ty Overby <ty@pre-alpha.com>
|
Ty Overby <ty@pre-alpha.com>
|
||||||
|
76
Cargo.lock
76
Cargo.lock
@ -859,14 +859,38 @@ dependencies = [
|
|||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.20.3"
|
version = "0.20.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core 0.20.3",
|
||||||
"darling_macro",
|
"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]]
|
[[package]]
|
||||||
@ -883,13 +907,24 @@ dependencies = [
|
|||||||
"syn 2.0.29",
|
"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]]
|
[[package]]
|
||||||
name = "darling_macro"
|
name = "darling_macro"
|
||||||
version = "0.20.3"
|
version = "0.20.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core 0.20.3",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.29",
|
"syn 2.0.29",
|
||||||
]
|
]
|
||||||
@ -920,6 +955,37 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"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]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "0.99.17"
|
version = "0.99.17"
|
||||||
@ -939,7 +1005,7 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
|
checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling 0.20.3",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.29",
|
"syn 2.0.29",
|
||||||
@ -2594,6 +2660,8 @@ dependencies = [
|
|||||||
"anyhow",
|
"anyhow",
|
||||||
"build_helper",
|
"build_helper",
|
||||||
"camino",
|
"camino",
|
||||||
|
"clap",
|
||||||
|
"derive_builder",
|
||||||
"env_logger 0.10.0",
|
"env_logger 0.10.0",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
"glob",
|
"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 {
|
pub fn is_word(&self) -> bool {
|
||||||
if let AttrKind::Normal(normal) = &self.kind {
|
if let AttrKind::Normal(normal) = &self.kind {
|
||||||
matches!(normal.item.args, AttrArgs::Empty)
|
matches!(normal.item.args, AttrArgs::Empty)
|
||||||
|
@ -442,8 +442,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
counter: usize,
|
counter: usize,
|
||||||
) -> RegionNameHighlight {
|
) -> RegionNameHighlight {
|
||||||
let mut highlight = RegionHighlightMode::new(self.infcx.tcx);
|
let mut highlight = RegionHighlightMode::default();
|
||||||
highlight.highlighting_region_vid(needle_fr, counter);
|
highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter);
|
||||||
let type_name =
|
let type_name =
|
||||||
self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
|
self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
|
||||||
|
|
||||||
@ -804,8 +804,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut highlight = RegionHighlightMode::new(tcx);
|
let mut highlight = RegionHighlightMode::default();
|
||||||
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap());
|
||||||
let type_name =
|
let type_name =
|
||||||
self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).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
|
.label = positional arguments must be before named arguments
|
||||||
.named_args = named argument
|
.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_requires_string = requires at least a format string argument
|
||||||
|
|
||||||
builtin_macros_format_string_invalid = invalid format string: {$desc}
|
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
|
builtin_macros_format_unused_args = multiple unused formatting arguments
|
||||||
.label = multiple missing formatting specifiers
|
.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_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
|
||||||
|
|
||||||
builtin_macros_invalid_crate_attribute = invalid crate attribute
|
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_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_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
|
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,
|
is_const: bool,
|
||||||
) {
|
) {
|
||||||
let span = cx.with_def_site_ctxt(span);
|
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 {
|
let trait_def = TraitDef {
|
||||||
span,
|
span,
|
||||||
path: path_std!(cmp::Eq),
|
path: path_std!(cmp::Eq),
|
||||||
@ -44,9 +58,6 @@ pub fn expand_deriving_eq(
|
|||||||
associated_types: Vec::new(),
|
associated_types: Vec::new(),
|
||||||
is_const,
|
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)
|
trait_def.expand_ext(cx, mitem, item, push, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq(
|
|||||||
BlockOrExpr::new_expr(expr)
|
BlockOrExpr::new_expr(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
super::inject_impl_of_structural_trait(
|
let structural_trait_def = TraitDef {
|
||||||
cx,
|
|
||||||
span,
|
span,
|
||||||
item,
|
path: path_std!(marker::StructuralPartialEq),
|
||||||
path_std!(marker::StructuralPartialEq),
|
skip_path_as_bound: true, // crucial!
|
||||||
push,
|
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
|
// No need to generate `ne`, the default suffices, and not generating it is
|
||||||
// faster.
|
// faster.
|
||||||
|
@ -88,7 +88,7 @@
|
|||||||
//!
|
//!
|
||||||
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
|
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
|
||||||
//!
|
//!
|
||||||
//! ```{.text}
|
//! ```text
|
||||||
//! Struct(vec![FieldInfo {
|
//! Struct(vec![FieldInfo {
|
||||||
//! span: <span of x>
|
//! span: <span of x>
|
||||||
//! name: Some(<ident of x>),
|
//! name: Some(<ident of x>),
|
||||||
@ -99,7 +99,7 @@
|
|||||||
//!
|
//!
|
||||||
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
||||||
//!
|
//!
|
||||||
//! ```{.text}
|
//! ```text
|
||||||
//! Struct(vec![FieldInfo {
|
//! Struct(vec![FieldInfo {
|
||||||
//! span: <span of `i32`>,
|
//! span: <span of `i32`>,
|
||||||
//! name: None,
|
//! name: None,
|
||||||
@ -113,7 +113,7 @@
|
|||||||
//! When generating the `expr` for a call with `self == C0(a)` and `other
|
//! When generating the `expr` for a call with `self == C0(a)` and `other
|
||||||
//! == C0(b)`, the SubstructureFields is
|
//! == C0(b)`, the SubstructureFields is
|
||||||
//!
|
//!
|
||||||
//! ```{.text}
|
//! ```text
|
||||||
//! EnumMatching(0, <ast::Variant for C0>,
|
//! EnumMatching(0, <ast::Variant for C0>,
|
||||||
//! vec![FieldInfo {
|
//! vec![FieldInfo {
|
||||||
//! span: <span of i32>
|
//! span: <span of i32>
|
||||||
@ -125,7 +125,7 @@
|
|||||||
//!
|
//!
|
||||||
//! For `C1 {x}` and `C1 {x}`,
|
//! For `C1 {x}` and `C1 {x}`,
|
||||||
//!
|
//!
|
||||||
//! ```{.text}
|
//! ```text
|
||||||
//! EnumMatching(1, <ast::Variant for C1>,
|
//! EnumMatching(1, <ast::Variant for C1>,
|
||||||
//! vec![FieldInfo {
|
//! vec![FieldInfo {
|
||||||
//! span: <span of x>
|
//! span: <span of x>
|
||||||
@ -137,7 +137,7 @@
|
|||||||
//!
|
//!
|
||||||
//! For the tags,
|
//! For the tags,
|
||||||
//!
|
//!
|
||||||
//! ```{.text}
|
//! ```text
|
||||||
//! EnumTag(
|
//! EnumTag(
|
||||||
//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
|
//! &[<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,
|
//! 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 A>, Named(vec![(<ident of x>, <span of x>)]))
|
||||||
//!
|
//!
|
||||||
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
|
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
|
||||||
@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Require the current trait.
|
// 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.
|
// Add a `Copy` bound if required.
|
||||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||||
@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let predicate = ast::WhereBoundPredicate {
|
if !bounds.is_empty() {
|
||||||
span: self.span,
|
let predicate = ast::WhereBoundPredicate {
|
||||||
bound_generic_params: field_ty_param.bound_generic_params,
|
span: self.span,
|
||||||
bounded_ty: field_ty_param.ty,
|
bound_generic_params: field_ty_param.bound_generic_params,
|
||||||
bounds,
|
bounded_ty: field_ty_param.ty,
|
||||||
};
|
bounds,
|
||||||
|
};
|
||||||
|
|
||||||
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
let predicate = ast::WherePredicate::BoundPredicate(predicate);
|
||||||
where_clause.predicates.push(predicate);
|
where_clause.predicates.push(predicate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_ast::ptr::P;
|
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_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
|
||||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use thin_vec::{thin_vec, ThinVec};
|
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(
|
fn assert_ty_bounds(
|
||||||
cx: &mut ExtCtxt<'_>,
|
cx: &mut ExtCtxt<'_>,
|
||||||
stmts: &mut ThinVec<ast::Stmt>,
|
stmts: &mut ThinVec<ast::Stmt>,
|
||||||
|
@ -539,18 +539,29 @@ pub(crate) struct InvalidFormatStringLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
pub(crate) enum InvalidFormatStringSuggestion {
|
||||||
builtin_macros_sugg,
|
#[multipart_suggestion(
|
||||||
style = "verbose",
|
builtin_macros_format_use_positional,
|
||||||
applicability = "machine-applicable"
|
style = "verbose",
|
||||||
)]
|
applicability = "machine-applicable"
|
||||||
pub(crate) struct InvalidFormatStringSuggestion {
|
)]
|
||||||
#[suggestion_part(code = "{len}")]
|
UsePositional {
|
||||||
pub(crate) captured: Span,
|
#[suggestion_part(code = "{len}")]
|
||||||
pub(crate) len: String,
|
captured: Span,
|
||||||
#[suggestion_part(code = ", {arg}")]
|
len: String,
|
||||||
pub(crate) span: Span,
|
#[suggestion_part(code = ", {arg}")]
|
||||||
pub(crate) arg: String,
|
span: Span,
|
||||||
|
arg: String,
|
||||||
|
},
|
||||||
|
#[suggestion(
|
||||||
|
builtin_macros_format_remove_raw_ident,
|
||||||
|
code = "",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
|
RemoveRawIdent {
|
||||||
|
#[primary_span]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
@ -260,20 +260,29 @@ fn make_format_args(
|
|||||||
if let Some((label, span)) = err.secondary_label && is_source_literal {
|
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 } );
|
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 {
|
match err.suggestion {
|
||||||
let captured_arg_span =
|
parse::Suggestion::None => {}
|
||||||
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
|
parse::Suggestion::UsePositional => {
|
||||||
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
|
let captured_arg_span =
|
||||||
let span = match args.unnamed_args().last() {
|
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
|
||||||
Some(arg) => arg.expr.span,
|
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
|
||||||
None => fmt_span,
|
let span = match args.unnamed_args().last() {
|
||||||
};
|
Some(arg) => arg.expr.span,
|
||||||
e.sugg_ = Some(errors::InvalidFormatStringSuggestion {
|
None => fmt_span,
|
||||||
captured: captured_arg_span,
|
};
|
||||||
len: args.unnamed_args().len().to_string(),
|
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UsePositional {
|
||||||
span: span.shrink_to_hi(),
|
captured: captured_arg_span,
|
||||||
arg,
|
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);
|
ecx.emit_err(e);
|
||||||
|
@ -100,11 +100,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||||||
}
|
}
|
||||||
_ => unreachable!("{:?}", self.layout.abi),
|
_ => unreachable!("{:?}", self.layout.abi),
|
||||||
},
|
},
|
||||||
PassMode::Cast(ref cast, pad_i32) => {
|
PassMode::Cast { ref cast, pad_i32 } => {
|
||||||
assert!(!pad_i32, "padding support not yet implemented");
|
assert!(!pad_i32, "padding support not yet implemented");
|
||||||
cast_target_to_abi_params(cast)
|
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 {
|
if on_stack {
|
||||||
// Abi requires aligning struct size to pointer size
|
// Abi requires aligning struct size to pointer size
|
||||||
let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
|
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)]
|
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);
|
assert!(!on_stack);
|
||||||
smallvec![
|
smallvec![
|
||||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
|
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),
|
_ => unreachable!("{:?}", self.layout.abi),
|
||||||
},
|
},
|
||||||
PassMode::Cast(ref cast, _) => {
|
PassMode::Cast { ref cast, .. } => {
|
||||||
(None, cast_target_to_abi_params(cast).into_iter().collect())
|
(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);
|
assert!(!on_stack);
|
||||||
(Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
|
(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")
|
unreachable!("unsized return value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
|
|||||||
let (a, b) = arg.load_scalar_pair(fx);
|
let (a, b) = arg.load_scalar_pair(fx);
|
||||||
smallvec![a, b]
|
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 { .. } => {
|
PassMode::Indirect { .. } => {
|
||||||
if is_owned {
|
if is_owned {
|
||||||
match arg.force_stack(fx) {
|
match arg.force_stack(fx) {
|
||||||
@ -287,14 +287,14 @@ pub(super) fn cvalue_for_param<'tcx>(
|
|||||||
assert_eq!(block_params.len(), 2, "{:?}", block_params);
|
assert_eq!(block_params.len(), 2, "{:?}", block_params);
|
||||||
Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout))
|
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))
|
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);
|
assert_eq!(block_params.len(), 1, "{:?}", block_params);
|
||||||
Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout))
|
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);
|
assert_eq!(block_params.len(), 2, "{:?}", block_params);
|
||||||
Some(CValue::by_ref_unsized(
|
Some(CValue::by_ref_unsized(
|
||||||
Pointer::new(block_params[0]),
|
Pointer::new(block_params[0]),
|
||||||
|
@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>(
|
|||||||
block_params_iter: &mut impl Iterator<Item = Value>,
|
block_params_iter: &mut impl Iterator<Item = Value>,
|
||||||
) -> CPlace<'tcx> {
|
) -> CPlace<'tcx> {
|
||||||
let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
|
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 =
|
let is_ssa =
|
||||||
ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty);
|
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![],
|
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();
|
let ret_param = block_params_iter.next().unwrap();
|
||||||
assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
|
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],
|
smallvec![ret_param],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||||
unreachable!("unsized return value")
|
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 {
|
let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
|
||||||
PassMode::Ignore => (None, None),
|
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() {
|
if let Some(ret_ptr) = ret_place.try_to_ptr() {
|
||||||
// This is an optimization to prevent unnecessary copies of the return value when
|
// 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.
|
// 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)))
|
(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")
|
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);
|
let call_inst = f(fx, return_ptr);
|
||||||
@ -93,21 +93,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
|
|||||||
ret_place
|
ret_place
|
||||||
.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
|
.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 =
|
let results =
|
||||||
fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
|
fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
|
||||||
let result =
|
let result =
|
||||||
super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
|
super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
|
||||||
ret_place.write_cvalue(fx, result);
|
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 let Some(ret_temp_place) = ret_temp_place {
|
||||||
// If ret_temp_place is None, it is not necessary to copy the return value.
|
// 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);
|
let ret_temp_value = ret_temp_place.to_cvalue(fx);
|
||||||
ret_place.write_cvalue(fx, ret_temp_value);
|
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")
|
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.
|
/// Codegen a return instruction with the right return value(s) if any.
|
||||||
pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
|
pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
|
||||||
match fx.fn_abi.as_ref().unwrap().ret.mode {
|
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_(&[]);
|
fx.bcx.ins().return_(&[]);
|
||||||
}
|
}
|
||||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||||
unreachable!("unsized return value")
|
unreachable!("unsized return value")
|
||||||
}
|
}
|
||||||
PassMode::Direct(_) => {
|
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);
|
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]);
|
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 place = fx.get_local_place(RETURN_PLACE);
|
||||||
let ret_val = place.to_cvalue(fx);
|
let ret_val = place.to_cvalue(fx);
|
||||||
let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
|
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) {
|
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.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
|
||||||
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
|
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
|
||||||
// compilation should have been aborted
|
// compilation should have been aborted
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use rustc_middle::mir::interpret::{
|
use rustc_middle::mir::interpret::{read_target_uint, AllocId, ConstValue, GlobalAlloc, Scalar};
|
||||||
read_target_uint, AllocId, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
|
|
||||||
};
|
|
||||||
|
|
||||||
use cranelift_module::*;
|
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) {
|
pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
|
||||||
let mut constants_cx = ConstantCx::new();
|
let mut constants_cx = ConstantCx::new();
|
||||||
constants_cx.todo.push(TodoItem::Static(def_id));
|
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>(
|
pub(crate) fn eval_mir_constant<'tcx>(
|
||||||
fx: &FunctionCx<'_, '_, 'tcx>,
|
fx: &FunctionCx<'_, '_, 'tcx>,
|
||||||
constant: &Constant<'tcx>,
|
constant: &Constant<'tcx>,
|
||||||
) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
|
) -> (ConstValue<'tcx>, Ty<'tcx>) {
|
||||||
let cv = fx.monomorphize(constant.literal);
|
let cv = fx.monomorphize(constant.literal);
|
||||||
|
// This cannot fail because we checked all required_consts in advance.
|
||||||
let val = cv
|
let val = cv
|
||||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
|
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||||
.map_err(|err| match err {
|
.expect("erroneous constant not captured by required_consts");
|
||||||
ErrorHandled::Reported(_) => {
|
(val, cv.ty())
|
||||||
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()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn codegen_constant_operand<'tcx>(
|
pub(crate) fn codegen_constant_operand<'tcx>(
|
||||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||||
constant: &Constant<'tcx>,
|
constant: &Constant<'tcx>,
|
||||||
) -> CValue<'tcx> {
|
) -> CValue<'tcx> {
|
||||||
let (const_val, ty) = eval_mir_constant(fx, constant).unwrap_or_else(|| {
|
let (const_val, ty) = eval_mir_constant(fx, constant);
|
||||||
span_bug!(constant.span, "erroneous constant not captured by required_consts")
|
|
||||||
});
|
|
||||||
|
|
||||||
codegen_const_value(fx, const_val, ty)
|
codegen_const_value(fx, const_val, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,7 +437,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
|||||||
operand: &Operand<'tcx>,
|
operand: &Operand<'tcx>,
|
||||||
) -> Option<ConstValue<'tcx>> {
|
) -> Option<ConstValue<'tcx>> {
|
||||||
match operand {
|
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
|
// 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.
|
// 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.
|
// 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 } => {
|
InlineAsmOperand::Const { ref value } => {
|
||||||
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value)
|
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value);
|
||||||
.unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved"));
|
|
||||||
let value = rustc_codegen_ssa::common::asm_const_to_str(
|
let value = rustc_codegen_ssa::common::asm_const_to_str(
|
||||||
fx.tcx,
|
fx.tcx,
|
||||||
span,
|
span,
|
||||||
|
@ -113,7 +113,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
match self.ret.mode {
|
match self.ret.mode {
|
||||||
PassMode::Ignore => cx.type_void(),
|
PassMode::Ignore => cx.type_void(),
|
||||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
|
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 { .. } => {
|
PassMode::Indirect { .. } => {
|
||||||
argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
|
argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
|
||||||
cx.type_void()
|
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));
|
argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PassMode::Indirect { extra_attrs: Some(_), .. } => {
|
PassMode::Indirect { meta_attrs: Some(_), .. } => {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
PassMode::Cast(ref cast, pad_i32) => {
|
PassMode::Cast { ref cast, pad_i32 } => {
|
||||||
// add padding
|
// add padding
|
||||||
if pad_i32 {
|
if pad_i32 {
|
||||||
argument_tys.push(Reg::i32().gcc_type(cx));
|
argument_tys.push(Reg::i32().gcc_type(cx));
|
||||||
}
|
}
|
||||||
cast.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());
|
on_stack_param_indices.insert(argument_tys.len());
|
||||||
arg.memory_ty(cx)
|
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);
|
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 => {
|
sym::volatile_load | sym::unaligned_volatile_load => {
|
||||||
let tp_ty = fn_args.type_at(0);
|
let tp_ty = fn_args.type_at(0);
|
||||||
let mut ptr = args[0].immediate();
|
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)));
|
ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
|
||||||
}
|
}
|
||||||
let load = self.volatile_load(ptr.get_type(), ptr);
|
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 !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_llty = self.type_ptr_to(ty.gcc_type(self));
|
||||||
let ptr = self.pointercast(result.llval, ptr_llty);
|
let ptr = self.pointercast(result.llval, ptr_llty);
|
||||||
self.store(llval, ptr, result.align);
|
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() {
|
else if self.is_unsized_indirect() {
|
||||||
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
|
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
|
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
|
||||||
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
|
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
|
||||||
let can_store_through_cast_ptr = false;
|
let can_store_through_cast_ptr = false;
|
||||||
@ -511,10 +511,10 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||||||
PassMode::Pair(..) => {
|
PassMode::Pair(..) => {
|
||||||
OperandValue::Pair(next(), next()).store(bx, dst);
|
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);
|
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();
|
let next_arg = next();
|
||||||
self.store(bx, next_arg, dst);
|
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)
|
OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
|
||||||
} else if self.is_unsized_indirect() {
|
} else if self.is_unsized_indirect() {
|
||||||
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
|
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
|
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
|
||||||
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
|
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
|
||||||
let can_store_through_cast_ptr = false;
|
let can_store_through_cast_ptr = false;
|
||||||
@ -274,12 +274,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||||||
PassMode::Pair(..) => {
|
PassMode::Pair(..) => {
|
||||||
OperandValue::Pair(next(), next()).store(bx, dst);
|
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);
|
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
|
||||||
}
|
}
|
||||||
PassMode::Direct(_)
|
PassMode::Direct(_)
|
||||||
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
|
| PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }
|
||||||
| PassMode::Cast(..) => {
|
| PassMode::Cast { .. } => {
|
||||||
let next_arg = next();
|
let next_arg = next();
|
||||||
self.store(bx, next_arg, dst);
|
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 {
|
let llreturn_ty = match &self.ret.mode {
|
||||||
PassMode::Ignore => cx.type_void(),
|
PassMode::Ignore => cx.type_void(),
|
||||||
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
|
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 { .. } => {
|
PassMode::Indirect { .. } => {
|
||||||
llargument_tys.push(cx.type_ptr());
|
llargument_tys.push(cx.type_ptr());
|
||||||
cx.type_void()
|
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
|
// guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
|
||||||
// aggregates...
|
// aggregates...
|
||||||
if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
|
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
|
// 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
|
// `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*
|
// 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));
|
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
|
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack } => {
|
||||||
assert!(arg.layout.is_unsized());
|
// `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.
|
// 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
|
// Any two ABI-compatible unsized types have the same metadata type and
|
||||||
// moreover the same metadata value leads to the same dynamic size 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));
|
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
|
||||||
continue;
|
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
|
// add padding
|
||||||
if *pad_i32 {
|
if *pad_i32 {
|
||||||
llargument_tys.push(Reg::i32().llvm_type(cx));
|
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.
|
// We assume here that ABI-compatible Rust types have the same cast type.
|
||||||
cast.llvm_type(cx)
|
cast.llvm_type(cx)
|
||||||
}
|
}
|
||||||
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(),
|
|
||||||
};
|
};
|
||||||
llargument_tys.push(llarg_ty);
|
llargument_tys.push(llarg_ty);
|
||||||
}
|
}
|
||||||
@ -442,13 +454,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
PassMode::Direct(attrs) => {
|
PassMode::Direct(attrs) => {
|
||||||
attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
|
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);
|
assert!(!on_stack);
|
||||||
let i = apply(attrs);
|
let i = apply(attrs);
|
||||||
let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
|
let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
|
||||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
|
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);
|
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() {
|
for arg in self.args.iter() {
|
||||||
match &arg.mode {
|
match &arg.mode {
|
||||||
PassMode::Ignore => {}
|
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 i = apply(attrs);
|
||||||
let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx));
|
let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx));
|
||||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
|
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
|
||||||
}
|
}
|
||||||
PassMode::Direct(attrs)
|
PassMode::Direct(attrs)
|
||||||
| PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => {
|
| PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
|
||||||
apply(attrs);
|
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);
|
assert!(!on_stack);
|
||||||
apply(attrs);
|
apply(attrs);
|
||||||
apply(extra_attrs);
|
apply(meta_attrs);
|
||||||
}
|
}
|
||||||
PassMode::Pair(a, b) => {
|
PassMode::Pair(a, b) => {
|
||||||
apply(a);
|
apply(a);
|
||||||
apply(b);
|
apply(b);
|
||||||
}
|
}
|
||||||
PassMode::Cast(cast, pad_i32) => {
|
PassMode::Cast { cast, pad_i32 } => {
|
||||||
if *pad_i32 {
|
if *pad_i32 {
|
||||||
apply(&ArgAttributes::new());
|
apply(&ArgAttributes::new());
|
||||||
}
|
}
|
||||||
@ -504,13 +516,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
PassMode::Direct(attrs) => {
|
PassMode::Direct(attrs) => {
|
||||||
attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite);
|
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);
|
assert!(!on_stack);
|
||||||
let i = apply(bx.cx, attrs);
|
let i = apply(bx.cx, attrs);
|
||||||
let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
|
let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
|
||||||
attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
|
attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
|
||||||
}
|
}
|
||||||
PassMode::Cast(cast, _) => {
|
PassMode::Cast { cast, pad_i32: _ } => {
|
||||||
cast.attrs.apply_attrs_to_callsite(
|
cast.attrs.apply_attrs_to_callsite(
|
||||||
llvm::AttributePlace::ReturnValue,
|
llvm::AttributePlace::ReturnValue,
|
||||||
&bx.cx,
|
&bx.cx,
|
||||||
@ -532,7 +544,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
for arg in self.args.iter() {
|
for arg in self.args.iter() {
|
||||||
match &arg.mode {
|
match &arg.mode {
|
||||||
PassMode::Ignore => {}
|
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 i = apply(bx.cx, attrs);
|
||||||
let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx));
|
let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx));
|
||||||
attributes::apply_to_callsite(
|
attributes::apply_to_callsite(
|
||||||
@ -542,18 +554,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
PassMode::Direct(attrs)
|
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);
|
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, attrs);
|
||||||
apply(bx.cx, extra_attrs);
|
apply(bx.cx, meta_attrs);
|
||||||
}
|
}
|
||||||
PassMode::Pair(a, b) => {
|
PassMode::Pair(a, b) => {
|
||||||
apply(bx.cx, a);
|
apply(bx.cx, a);
|
||||||
apply(bx.cx, b);
|
apply(bx.cx, b);
|
||||||
}
|
}
|
||||||
PassMode::Cast(cast, pad_i32) => {
|
PassMode::Cast { cast, pad_i32 } => {
|
||||||
if *pad_i32 {
|
if *pad_i32 {
|
||||||
apply(bx.cx, &ArgAttributes::new());
|
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 => {
|
sym::volatile_load | sym::unaligned_volatile_load => {
|
||||||
let tp_ty = fn_args.type_at(0);
|
let tp_ty = fn_args.type_at(0);
|
||||||
let ptr = args[0].immediate();
|
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);
|
let llty = ty.llvm_type(self);
|
||||||
self.volatile_load(llty, ptr)
|
self.volatile_load(llty, ptr)
|
||||||
} else {
|
} else {
|
||||||
@ -386,7 +386,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !fn_abi.ret.is_ignore() {
|
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);
|
self.store(llval, result.llval, result.align);
|
||||||
} else {
|
} else {
|
||||||
OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
|
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_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_error_creating_remark_dir = failed to create remark directory: {$error}
|
||||||
|
|
||||||
codegen_ssa_expected_coverage_symbol = expected `coverage(off)` or `coverage(on)`
|
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_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}
|
codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
|
||||||
.note = {$output}
|
.note = {$output}
|
||||||
|
|
||||||
|
@ -595,20 +595,6 @@ pub struct InvalidWindowsSubsystem {
|
|||||||
pub subsystem: Symbol,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(codegen_ssa_shuffle_indices_evaluation)]
|
#[diag(codegen_ssa_shuffle_indices_evaluation)]
|
||||||
pub struct ShuffleIndicesEvaluation {
|
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] {
|
let op = match self.locals[mir::RETURN_PLACE] {
|
||||||
LocalRef::Operand(op) => op,
|
LocalRef::Operand(op) => op,
|
||||||
LocalRef::PendingOperand => bug!("use of return before def"),
|
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 }
|
InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
|
||||||
}
|
}
|
||||||
mir::InlineAsmOperand::Const { ref value } => {
|
mir::InlineAsmOperand::Const { ref value } => {
|
||||||
let const_value = self
|
let const_value = self.eval_mir_constant(value);
|
||||||
.eval_mir_constant(value)
|
|
||||||
.unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved"));
|
|
||||||
let string = common::asm_const_to_str(
|
let string = common::asm_const_to_str(
|
||||||
bx.tcx(),
|
bx.tcx(),
|
||||||
span,
|
span,
|
||||||
@ -1310,7 +1308,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
) {
|
) {
|
||||||
match arg.mode {
|
match arg.mode {
|
||||||
PassMode::Ignore => return,
|
PassMode::Ignore => return,
|
||||||
PassMode::Cast(_, true) => {
|
PassMode::Cast { pad_i32: true, .. } => {
|
||||||
// Fill padding with undef value, where applicable.
|
// Fill padding with undef value, where applicable.
|
||||||
llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32())));
|
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),
|
_ => 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), _) => {
|
Ref(a, Some(b), _) => {
|
||||||
llargs.push(a);
|
llargs.push(a);
|
||||||
llargs.push(b);
|
llargs.push(b);
|
||||||
@ -1347,7 +1345,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
op.val.store(bx, scratch);
|
op.val.store(bx, scratch);
|
||||||
(scratch.llval, scratch.align, true)
|
(scratch.llval, scratch.align, true)
|
||||||
}
|
}
|
||||||
PassMode::Cast(..) => {
|
PassMode::Cast { .. } => {
|
||||||
let scratch = PlaceRef::alloca(bx, arg.layout);
|
let scratch = PlaceRef::alloca(bx, arg.layout);
|
||||||
op.val.store(bx, scratch);
|
op.val.store(bx, scratch);
|
||||||
(scratch.llval, scratch.align, true)
|
(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() {
|
if by_ref && !arg.is_indirect() {
|
||||||
// Have to load the argument, maybe while casting it.
|
// 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);
|
let llty = bx.cast_backend_type(ty);
|
||||||
llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
|
llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
|
||||||
} else {
|
} else {
|
||||||
@ -1744,7 +1742,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
}
|
}
|
||||||
DirectOperand(index) => {
|
DirectOperand(index) => {
|
||||||
// If there is a cast, we have to store and reload.
|
// 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);
|
let tmp = PlaceRef::alloca(bx, ret_abi.layout);
|
||||||
tmp.storage_live(bx);
|
tmp.storage_live(bx);
|
||||||
bx.store_arg(&ret_abi, llval, tmp);
|
bx.store_arg(&ret_abi, llval, tmp);
|
||||||
|
@ -14,34 +14,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
&self,
|
&self,
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
constant: &mir::Constant<'tcx>,
|
constant: &mir::Constant<'tcx>,
|
||||||
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
|
) -> OperandRef<'tcx, Bx::Value> {
|
||||||
let val = self.eval_mir_constant(constant)?;
|
let val = self.eval_mir_constant(constant);
|
||||||
let ty = self.monomorphize(constant.ty());
|
let ty = self.monomorphize(constant.ty());
|
||||||
Ok(OperandRef::from_const(bx, val, ty))
|
OperandRef::from_const(bx, val, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_mir_constant(
|
pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> ConstValue<'tcx> {
|
||||||
&self,
|
|
||||||
constant: &mir::Constant<'tcx>,
|
|
||||||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
|
||||||
self.monomorphize(constant.literal)
|
self.monomorphize(constant.literal)
|
||||||
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||||
.map_err(|err| {
|
.expect("erroneous constant not captured by required_consts")
|
||||||
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
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
|
/// 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 {
|
if let Some(dbg_var) = dbg_var {
|
||||||
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
|
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
|
||||||
|
|
||||||
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
|
let operand = self.eval_mir_constant_to_operand(bx, &c);
|
||||||
self.set_debug_loc(bx, var.source_info);
|
self.set_debug_loc(bx, var.source_info);
|
||||||
let base = Self::spill_operand_to_stack(
|
let base =
|
||||||
operand,
|
Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
|
||||||
Some(var.name.to_string()),
|
|
||||||
bx,
|
|
||||||
);
|
|
||||||
|
|
||||||
bx.dbg_var_addr(
|
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
|
||||||
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 !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);
|
bx.store(llval, result.llval, result.align);
|
||||||
} else {
|
} else {
|
||||||
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)
|
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::bit_set::BitSet;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::ErrorHandled;
|
|
||||||
use rustc_middle::mir::traversal;
|
use rustc_middle::mir::traversal;
|
||||||
use rustc_middle::mir::UnwindTerminateReason;
|
use rustc_middle::mir::UnwindTerminateReason;
|
||||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
|
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);
|
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.
|
// Rust post-monomorphization checks; we later rely on them.
|
||||||
let mut all_consts_ok = true;
|
if let Err(err) =
|
||||||
for const_ in &mir.required_consts {
|
mir.post_mono_checks(cx.tcx(), ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
|
||||||
if let Err(err) = fx.eval_mir_constant(const_) {
|
{
|
||||||
all_consts_ok = false;
|
err.emit_err(cx.tcx());
|
||||||
match err {
|
// This IR shouldn't ever be emitted, but let's try to guard against any of this code
|
||||||
// errored or at least linted
|
// ever running.
|
||||||
ErrorHandled::Reported(_) => {}
|
start_bx.abort();
|
||||||
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.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,7 +317,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
for i in 0..tupled_arg_tys.len() {
|
for i in 0..tupled_arg_tys.len() {
|
||||||
let arg = &fx.fn_abi.args[idx];
|
let arg = &fx.fn_abi.args[idx];
|
||||||
idx += 1;
|
idx += 1;
|
||||||
if let PassMode::Cast(_, true) = arg.mode {
|
if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
|
||||||
llarg_idx += 1;
|
llarg_idx += 1;
|
||||||
}
|
}
|
||||||
let pr_field = place.project_field(bx, i);
|
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];
|
let arg = &fx.fn_abi.args[idx];
|
||||||
idx += 1;
|
idx += 1;
|
||||||
if let PassMode::Cast(_, true) = arg.mode {
|
if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
|
||||||
llarg_idx += 1;
|
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())
|
self.codegen_consume(bx, place.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::Operand::Constant(ref constant) => {
|
mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, 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")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,9 +83,6 @@ const_eval_dyn_call_vtable_mismatch =
|
|||||||
const_eval_dyn_star_call_vtable_mismatch =
|
const_eval_dyn_star_call_vtable_mismatch =
|
||||||
`dyn*` call on a pointer whose vtable does not match its type
|
`dyn*` call on a pointer whose vtable does not match its type
|
||||||
|
|
||||||
const_eval_erroneous_constant =
|
|
||||||
erroneous constant used
|
|
||||||
|
|
||||||
const_eval_error = {$error_kind ->
|
const_eval_error = {$error_kind ->
|
||||||
[static] could not evaluate static initializer
|
[static] could not evaluate static initializer
|
||||||
[const] evaluation of constant value failed
|
[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::mir::AssertKind;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_middle::ty::{layout::LayoutError, ConstInt};
|
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 super::InterpCx;
|
||||||
use crate::errors::{self, FrameNote, ReportErrorExt};
|
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
|
// Don't emit a new diagnostic for these errors, they are already reported elsewhere or
|
||||||
// should remain silent.
|
// should remain silent.
|
||||||
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
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))) => {
|
err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
|
||||||
ErrorHandled::Reported(guar.into())
|
ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP))
|
||||||
}
|
}
|
||||||
// Report remaining errors.
|
// Report remaining errors.
|
||||||
_ => {
|
_ => {
|
||||||
@ -152,7 +152,7 @@ where
|
|||||||
|
|
||||||
// Use *our* span to label the interp error
|
// Use *our* span to label the interp error
|
||||||
err.span_label(our_span, msg);
|
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();
|
key.param_env = key.param_env.with_user_facing();
|
||||||
match tcx.eval_to_const_value_raw(key) {
|
match tcx.eval_to_const_value_raw(key) {
|
||||||
// try again with reveal all as requested
|
// try again with reveal all as requested
|
||||||
Err(ErrorHandled::TooGeneric) => {}
|
Err(ErrorHandled::TooGeneric(_)) => {}
|
||||||
// deduplicate calls
|
// deduplicate calls
|
||||||
other => return other,
|
other => return other,
|
||||||
}
|
}
|
||||||
@ -259,7 +259,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||||||
key.param_env = key.param_env.with_user_facing();
|
key.param_env = key.param_env.with_user_facing();
|
||||||
match tcx.eval_to_allocation_raw(key) {
|
match tcx.eval_to_allocation_raw(key) {
|
||||||
// try again with reveal all as requested
|
// try again with reveal all as requested
|
||||||
Err(ErrorHandled::TooGeneric) => {}
|
Err(ErrorHandled::TooGeneric(_)) => {}
|
||||||
// deduplicate calls
|
// deduplicate calls
|
||||||
other => return other,
|
other => return other,
|
||||||
}
|
}
|
||||||
|
@ -239,13 +239,6 @@ pub struct LongRunningWarn {
|
|||||||
pub item_span: Span,
|
pub item_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(const_eval_erroneous_constant)]
|
|
||||||
pub(crate) struct ErroneousConstUsed {
|
|
||||||
#[primary_span]
|
|
||||||
pub span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[note(const_eval_non_const_impl)]
|
#[note(const_eval_non_const_impl)]
|
||||||
pub(crate) struct NonConstImplNote {
|
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_hir::{self as hir, def_id::DefId, definitions::DefPathData};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir;
|
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::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::layout::{
|
use rustc_middle::ty::layout::{
|
||||||
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
|
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
|
||||||
@ -21,10 +21,10 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
|
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,
|
Projectable, Provenance, Scalar, StackPopJump,
|
||||||
};
|
};
|
||||||
use crate::errors::{self, ErroneousConstUsed};
|
use crate::errors;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
use crate::{fluent_generated as fluent, ReportErrorExt};
|
use crate::{fluent_generated as fluent, ReportErrorExt};
|
||||||
|
|
||||||
@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
value: T,
|
value: T,
|
||||||
) -> Result<T, InterpError<'tcx>> {
|
) -> Result<T, ErrorHandled> {
|
||||||
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
|
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,
|
&self,
|
||||||
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
|
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
|
||||||
value: T,
|
value: T,
|
||||||
) -> Result<T, InterpError<'tcx>> {
|
) -> Result<T, ErrorHandled> {
|
||||||
frame
|
frame
|
||||||
.instance
|
.instance
|
||||||
.try_subst_mir_and_normalize_erasing_regions(
|
.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,
|
self.param_env,
|
||||||
ty::EarlyBinder::bind(value),
|
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).
|
/// 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).
|
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
|
||||||
if M::POST_MONO_CHECKS {
|
if M::POST_MONO_CHECKS {
|
||||||
for ct in &body.required_consts {
|
// `ctfe_query` does some error message decoration that we want to be in effect here.
|
||||||
let span = ct.span;
|
self.ctfe_query(None, |tcx| {
|
||||||
let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
|
body.post_mono_checks(*tcx, self.param_env, |c| {
|
||||||
self.eval_mir_constant(&ct, Some(span), None)?;
|
self.subst_from_current_frame_and_normalize_erasing_regions(c)
|
||||||
}
|
})
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// done
|
// done
|
||||||
@ -1059,28 +1060,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
&self,
|
&self,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
|
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
|
||||||
) -> InterpResult<'tcx, T> {
|
) -> Result<T, ErrorHandled> {
|
||||||
// Use a precise span for better cycle errors.
|
// Use a precise span for better cycle errors.
|
||||||
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
|
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
|
||||||
match err {
|
err.emit_note(*self.tcx);
|
||||||
ErrorHandled::Reported(err) => {
|
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()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_global(
|
pub fn eval_global(
|
||||||
&self,
|
&self,
|
||||||
gid: GlobalId<'tcx>,
|
instance: ty::Instance<'tcx>,
|
||||||
span: Option<Span>,
|
|
||||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
|
) -> 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
|
// 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
|
// 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
|
// `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 {
|
} else {
|
||||||
self.param_env
|
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)
|
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]
|
#[must_use]
|
||||||
pub fn dump_place(
|
pub fn dump_place(
|
||||||
&self,
|
&self,
|
||||||
|
@ -8,15 +8,14 @@ use either::{Either, Left, Right};
|
|||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
|
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_middle::{mir, ty};
|
||||||
use rustc_span::Span;
|
|
||||||
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
|
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId,
|
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, InterpCx,
|
||||||
InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer,
|
InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, Projectable,
|
||||||
Projectable, Provenance, Scalar,
|
Provenance, Scalar,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An `Immediate` represents a single immediate self-contained Rust value.
|
/// 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> {
|
impl<Prov: Provenance> std::fmt::Debug for ImmTy<'_, Prov> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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> {
|
impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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)
|
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(
|
pub(crate) fn const_val_to_op(
|
||||||
&self,
|
&self,
|
||||||
val_val: ConstValue<'tcx>,
|
val_val: ConstValue<'tcx>,
|
||||||
|
@ -117,9 +117,10 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
|
|||||||
|
|
||||||
impl<Prov: Provenance> std::fmt::Debug for MPlaceTy<'_, Prov> {
|
impl<Prov: Provenance> std::fmt::Debug for MPlaceTy<'_, Prov> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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")
|
f.debug_struct("MPlaceTy")
|
||||||
.field("mplace", &self.mplace)
|
.field("mplace", &self.mplace)
|
||||||
.field("ty", &self.layout.ty)
|
.field("ty", &format_args!("{}", self.layout.ty))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +238,11 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
|
|||||||
|
|
||||||
impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> {
|
impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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:
|
// Traverse the graph, collecting a number of things:
|
||||||
//
|
//
|
||||||
// * Preorder mapping (to it, and back to the actual ordering)
|
// * 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
|
// * Parents for each vertex in the preorder tree
|
||||||
//
|
//
|
||||||
// These are all done here rather than through one of the 'standard'
|
// 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
|
/// 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
|
/// 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.
|
/// 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> {
|
pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
|
||||||
self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
|
self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if `a` dominates `b`.
|
/// 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
|
A struct, enum, or union with the `repr(transparent)` representation hint
|
||||||
contains a zero-sized field that requires non-trivial alignment.
|
contains a zero-sized field that requires non-trivial alignment.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0691
|
```ignore (error is no longer emitted)
|
||||||
#![feature(repr_align)]
|
#![feature(repr_align)]
|
||||||
|
|
||||||
#[repr(align(32))]
|
#[repr(align(32))]
|
||||||
|
@ -401,6 +401,8 @@ declare_features! (
|
|||||||
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
|
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
|
||||||
/// instrumentation of that function.
|
/// instrumentation of that function.
|
||||||
(active, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605), None),
|
(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.
|
/// Allows non-builtin attributes in inner attribute position.
|
||||||
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
|
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
|
||||||
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
|
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
|
||||||
@ -414,7 +416,7 @@ declare_features! (
|
|||||||
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
|
||||||
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
|
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
|
||||||
/// Allows using the `#[diagnostic]` attribute tool namespace
|
/// 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.
|
/// Controls errors in trait implementations.
|
||||||
(active, do_not_recommend, "1.67.0", Some(51992), None),
|
(active, do_not_recommend, "1.67.0", Some(51992), None),
|
||||||
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
|
/// 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, Normal, template!(Word), ErrorFollowing,
|
||||||
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
|
"#[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_attr!(
|
||||||
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
|
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`."
|
"#![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`
|
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}`
|
.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 =
|
hir_analysis_invalid_union_field =
|
||||||
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
|
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<...>`
|
.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}`
|
.many_label = too many variants in `{$path}`
|
||||||
.multi_label = variant here
|
.multi_label = variant here
|
||||||
|
|
||||||
hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
|
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 non-zero-sized field, but has {$field_count}
|
.label = needs at most one field with non-trivial size or alignment, but has {$field_count}
|
||||||
.labels = this field is non-zero-sized
|
.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}
|
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 non-zero-sized field, but has {$field_count}
|
.label = needs at most one field with non-trivial size or alignment, but has {$field_count}
|
||||||
.labels = this field is non-zero-sized
|
.labels = this field has non-zero size or requires alignment
|
||||||
|
|
||||||
hir_analysis_typeof_reserved_keyword_used =
|
hir_analysis_typeof_reserved_keyword_used =
|
||||||
`typeof` is a reserved keyword but unimplemented
|
`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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each field, figure out if it's known to be a ZST and align(1), with "known"
|
// For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
|
||||||
// respecting #[non_exhaustive] attributes.
|
// "known" respecting #[non_exhaustive] attributes.
|
||||||
let field_infos = adt.all_fields().map(|field| {
|
let field_infos = adt.all_fields().map(|field| {
|
||||||
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
|
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
|
||||||
let param_env = tcx.param_env(field.did);
|
let param_env = tcx.param_env(field.did);
|
||||||
let layout = tcx.layout_of(param_env.and(ty));
|
let layout = tcx.layout_of(param_env.and(ty));
|
||||||
// We are currently checking the type this field came from, so it must be local
|
// 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 span = tcx.hir().span_if_local(field.did).unwrap();
|
||||||
let zst = layout.is_ok_and(|layout| layout.is_zst());
|
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
|
||||||
let align = layout.ok().map(|layout| layout.align.abi.bytes());
|
if !trivial {
|
||||||
if !zst {
|
return (span, trivial, None);
|
||||||
return (span, zst, align, None);
|
|
||||||
}
|
}
|
||||||
|
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`.
|
||||||
|
|
||||||
fn check_non_exhaustive<'tcx>(
|
fn check_non_exhaustive<'tcx>(
|
||||||
tcx: TyCtxt<'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()
|
.clone()
|
||||||
.filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None });
|
.filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
|
||||||
let non_zst_count = non_zst_fields.clone().count();
|
let non_trivial_count = non_trivial_fields.clone().count();
|
||||||
if non_zst_count >= 2 {
|
if non_trivial_count >= 2 {
|
||||||
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
|
bad_non_zero_sized_fields(
|
||||||
|
tcx,
|
||||||
|
adt,
|
||||||
|
non_trivial_count,
|
||||||
|
non_trivial_fields,
|
||||||
|
tcx.def_span(adt.did()),
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
let incompatible_zst_fields =
|
let mut prev_non_exhaustive_1zst = false;
|
||||||
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
|
for (span, _trivial, non_exhaustive_1zst) in field_infos {
|
||||||
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
|
if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst {
|
||||||
for (span, zst, align, non_exhaustive) in field_infos {
|
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
|
||||||
if zst && align != Some(1) {
|
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
|
||||||
let mut err = struct_span_err!(
|
if non_trivial_count > 0 || prev_non_exhaustive_1zst {
|
||||||
tcx.sess,
|
tcx.struct_span_lint_hir(
|
||||||
span,
|
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
||||||
E0691,
|
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
|
||||||
"zero-sized field in transparent {} has alignment larger than 1",
|
|
||||||
adt.descr(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(align_bytes) = align {
|
|
||||||
err.span_label(
|
|
||||||
span,
|
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 {
|
} 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,
|
//! `tcx.inherent_impls(def_id)`). That value, however,
|
||||||
//! is computed by selecting an idea from this table.
|
//! is computed by selecting an idea from this table.
|
||||||
|
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
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_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
/// On-demand query: yields a map containing all types mapped to their inherent impls.
|
/// On-demand query: yields a map containing all types mapped to their inherent impls.
|
||||||
pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
|
pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
|
||||||
let mut collect = InherentCollect { tcx, impls_map: Default::default() };
|
let mut collect = InherentCollect { tcx, impls_map: Default::default() };
|
||||||
@ -45,14 +46,6 @@ struct InherentCollect<'tcx> {
|
|||||||
impls_map: CrateInherentImpls,
|
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> {
|
impl<'tcx> InherentCollect<'tcx> {
|
||||||
fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
|
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() {
|
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) {
|
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
|
||||||
let impl_span = self.tcx.def_span(impl_def_id);
|
let impl_span = self.tcx.def_span(impl_def_id);
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span });
|
||||||
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();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for &impl_item in items {
|
for &impl_item in items {
|
||||||
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
||||||
let impl_span = self.tcx.def_span(impl_def_id);
|
let impl_span = self.tcx.def_span(impl_def_id);
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant {
|
||||||
self.tcx.sess,
|
span: impl_span,
|
||||||
impl_span,
|
help_span: self.tcx.def_span(impl_item),
|
||||||
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();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let impl_span = self.tcx.def_span(impl_def_id);
|
let impl_span = self.tcx.def_span(impl_def_id);
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span });
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||||||
for &impl_item in items {
|
for &impl_item in items {
|
||||||
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
|
||||||
let span = self.tcx.def_span(impl_def_id);
|
let span = self.tcx.def_span(impl_def_id);
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive {
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
span,
|
||||||
E0390,
|
help_span: self.tcx.def_span(impl_item),
|
||||||
"cannot define inherent `impl` for primitive types outside of `core`",
|
});
|
||||||
)
|
|
||||||
.help(INTO_CORE)
|
|
||||||
.span_help(self.tcx.def_span(impl_item), ADD_ATTR)
|
|
||||||
.emit();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let span = self.tcx.def_span(impl_def_id);
|
let span = self.tcx.def_span(impl_def_id);
|
||||||
let mut err = struct_span_err!(
|
let mut note = None;
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0390,
|
|
||||||
"cannot define inherent `impl` for primitive types",
|
|
||||||
);
|
|
||||||
err.help("consider using an extension trait instead");
|
|
||||||
if let ty::Ref(_, subty, _) = ty.kind() {
|
if let ty::Ref(_, subty, _) = ty.kind() {
|
||||||
err.note(format!(
|
note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
|
||||||
"you could also try moving the reference to \
|
|
||||||
uses of `{subty}` (such as `self`) within the implementation"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
err.emit();
|
self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||||||
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
|
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
|
||||||
}
|
}
|
||||||
ty::Dynamic(..) => {
|
ty::Dynamic(..) => {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(errors::InherentDyn { span: item_span });
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
ty::Bool
|
ty::Bool
|
||||||
| ty::Char
|
| ty::Char
|
||||||
@ -202,17 +151,7 @@ impl<'tcx> InherentCollect<'tcx> {
|
|||||||
| ty::FnPtr(_)
|
| ty::FnPtr(_)
|
||||||
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
|
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
|
||||||
ty::Alias(..) | ty::Param(_) => {
|
ty::Alias(..) | ty::Param(_) => {
|
||||||
let mut err = struct_span_err!(
|
self.tcx.sess.emit_err(errors::InherentNominal { span: item_span });
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
ty::FnDef(..)
|
ty::FnDef(..)
|
||||||
| ty::Closure(..)
|
| ty::Closure(..)
|
||||||
|
@ -943,3 +943,75 @@ pub struct AssocBoundOnConst {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub descr: &'static str,
|
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" }
|
fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
|
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 CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
|
||||||
const UNSTABLE_EXPLAIN: &str =
|
const UNSTABLE_EXPLAIN: &str =
|
||||||
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
|
"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
|
*[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`
|
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
|
.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_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_default_return_type = expected `()` because of default return type
|
||||||
|
|
||||||
hir_typeck_expected_return_type = expected `{$expected}` because of 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 =
|
hir_typeck_field_multiply_specified_in_initializer =
|
||||||
field `{$ident}` specified more than once
|
field `{$ident}` specified more than once
|
||||||
.label = used 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_cargo = set `edition = "{$edition}"` in `Cargo.toml`
|
||||||
hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
|
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 = 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}
|
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
|
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}`
|
.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 =
|
hir_typeck_method_call_on_unknown_raw_pointee =
|
||||||
cannot call a method on a raw pointer with an unknown pointee type
|
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_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 ->
|
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_body_label = the {$statement_kind} is part of this body...
|
||||||
.encl_fn_label = ...not the enclosing function 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 =
|
hir_typeck_struct_expr_non_exhaustive =
|
||||||
cannot create non-exhaustive {$what} using struct expression
|
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_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_dotdot = `..` cannot be used in union patterns
|
||||||
|
|
||||||
hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
|
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 =
|
hir_typeck_yield_expr_outside_of_generator =
|
||||||
yield expression outside of generator literal
|
yield expression outside of generator literal
|
||||||
|
@ -2,9 +2,9 @@ use super::method::probe::ProbeScope;
|
|||||||
use super::method::MethodCallee;
|
use super::method::MethodCallee;
|
||||||
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
|
||||||
|
|
||||||
use crate::type_error_struct;
|
use crate::errors;
|
||||||
use rustc_ast::util::parser::PREC_POSTFIX;
|
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 as hir;
|
||||||
use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
|
use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
@ -44,23 +44,15 @@ pub fn check_legal_trait_for_method_call(
|
|||||||
trait_id: DefId,
|
trait_id: DefId,
|
||||||
) {
|
) {
|
||||||
if tcx.lang_items().drop_trait() == Some(trait_id) {
|
if tcx.lang_items().drop_trait() == Some(trait_id) {
|
||||||
let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
|
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
|
||||||
err.span_label(span, "explicit destructor calls not allowed");
|
errors::ExplicitDestructorCallSugg::Snippet {
|
||||||
|
lo: expr_span.shrink_to_lo(),
|
||||||
let (sp, suggestion) = receiver
|
hi: receiver.shrink_to_hi().to(expr_span.shrink_to_hi()),
|
||||||
.and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok())
|
}
|
||||||
.filter(|snippet| !snippet.is_empty())
|
} else {
|
||||||
.map(|snippet| (expr_span, format!("drop({snippet})")))
|
errors::ExplicitDestructorCallSugg::Empty(span)
|
||||||
.unwrap_or_else(|| (span, "drop".to_string()));
|
};
|
||||||
|
tcx.sess.emit_err(errors::ExplicitDestructorCall { span, sugg });
|
||||||
err.span_suggestion(
|
|
||||||
sp,
|
|
||||||
"consider using `drop` function",
|
|
||||||
suggestion,
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
|
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,6 +379,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// Unit testing: function items annotated with
|
// Unit testing: function items annotated with
|
||||||
// `#[rustc_evaluate_where_clauses]` trigger special output
|
// `#[rustc_evaluate_where_clauses]` trigger special output
|
||||||
// to let us test the trait evaluation system.
|
// 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) {
|
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
|
||||||
let predicates = self.tcx.predicates_of(def_id);
|
let predicates = self.tcx.predicates_of(def_id);
|
||||||
let predicates = predicates.instantiate(self.tcx, args);
|
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);
|
self.require_type_is_sized(ty, sp, traits::RustCall);
|
||||||
} else {
|
} else {
|
||||||
self.tcx.sess.span_err(
|
self.tcx.sess.emit_err(errors::RustCallIncorrectArgs { span: sp });
|
||||||
sp,
|
|
||||||
"functions with the \"rust-call\" ABI must take a single non-self tuple argument",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,17 +602,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let callee_ty = self.resolve_vars_if_possible(callee_ty);
|
let callee_ty = self.resolve_vars_if_possible(callee_ty);
|
||||||
let mut err = type_error_struct!(
|
let mut err = self.tcx.sess.create_err(errors::InvalidCallee {
|
||||||
self.tcx.sess,
|
span: callee_expr.span,
|
||||||
callee_expr.span,
|
ty: match &unit_variant {
|
||||||
callee_ty,
|
|
||||||
E0618,
|
|
||||||
"expected function, found {}",
|
|
||||||
match &unit_variant {
|
|
||||||
Some((_, kind, path)) => format!("{kind} `{path}`"),
|
Some((_, kind, path)) => format!("{kind} `{path}`"),
|
||||||
None => format!("`{callee_ty}`"),
|
None => format!("`{callee_ty}`"),
|
||||||
}
|
},
|
||||||
);
|
});
|
||||||
|
if callee_ty.references_error() {
|
||||||
|
err.downgrade_to_delayed_bug();
|
||||||
|
}
|
||||||
|
|
||||||
self.identify_bad_closure_def_and_call(
|
self.identify_bad_closure_def_and_call(
|
||||||
&mut err,
|
&mut err,
|
||||||
@ -891,15 +882,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
|
|||||||
None => {
|
None => {
|
||||||
// This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once`
|
// This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once`
|
||||||
// lang items are not defined (issue #86238).
|
// lang items are not defined (issue #86238).
|
||||||
let mut err = fcx.inh.tcx.sess.struct_span_err(
|
fcx.inh.tcx.sess.emit_err(errors::MissingFnLangItems { span: self.call_expr.span });
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,10 @@
|
|||||||
|
|
||||||
use super::FnCtxt;
|
use super::FnCtxt;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
use crate::type_error_struct;
|
use crate::type_error_struct;
|
||||||
use hir::ExprKind;
|
use hir::ExprKind;
|
||||||
use rustc_errors::{
|
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
||||||
struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
|
||||||
};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_macros::{TypeFoldable, TypeVisitable};
|
use rustc_macros::{TypeFoldable, TypeVisitable};
|
||||||
use rustc_middle::mir::Mutability;
|
use rustc_middle::mir::Mutability;
|
||||||
@ -321,33 +320,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
CastError::CastToBool => {
|
CastError::CastToBool => {
|
||||||
let mut err = struct_span_err!(
|
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
|
||||||
fcx.tcx.sess,
|
let help = if self.expr_ty.is_numeric() {
|
||||||
self.span,
|
errors::CannotCastToBoolHelp::Numeric(
|
||||||
E0054,
|
self.expr_span.shrink_to_hi().with_hi(self.span.hi()),
|
||||||
"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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
err.span_label(self.span, "unsupported cast");
|
errors::CannotCastToBoolHelp::Unsupported(self.span)
|
||||||
}
|
};
|
||||||
|
fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
|
||||||
err.emit();
|
|
||||||
}
|
}
|
||||||
CastError::CastToChar => {
|
CastError::CastToChar => {
|
||||||
let mut err = type_error_struct!(
|
let mut err = type_error_struct!(
|
||||||
@ -536,33 +517,20 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
CastError::IntToFatCast(known_metadata) => {
|
CastError::IntToFatCast(known_metadata) => {
|
||||||
let mut err = struct_span_err!(
|
let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
|
||||||
fcx.tcx.sess,
|
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
|
||||||
self.cast_span,
|
let expr_ty = fcx.ty_to_string(self.expr_ty);
|
||||||
E0606,
|
let metadata = known_metadata.unwrap_or("type-specific metadata");
|
||||||
"cannot cast `{}` to a pointer that {} wide",
|
let known_wide = known_metadata.is_some();
|
||||||
fcx.ty_to_string(self.expr_ty),
|
let span = self.cast_span;
|
||||||
if known_metadata.is_some() { "is" } else { "may be" }
|
fcx.tcx.sess.emit_err(errors::IntToWide {
|
||||||
);
|
span,
|
||||||
|
metadata,
|
||||||
err.span_label(
|
expr_ty,
|
||||||
self.cast_span,
|
cast_ty,
|
||||||
format!(
|
expr_if_nightly,
|
||||||
"creating a `{}` requires both an address and {}",
|
known_wide,
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
|
CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
|
||||||
let unknown_cast_to = match e {
|
let unknown_cast_to = match e {
|
||||||
@ -570,27 +538,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
CastError::UnknownExprPtrKind => false,
|
CastError::UnknownExprPtrKind => false,
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
let mut err = struct_span_err!(
|
let (span, sub) = if unknown_cast_to {
|
||||||
fcx.tcx.sess,
|
(self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span))
|
||||||
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",
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
err.span_label(
|
(self.cast_span, errors::CastUnknownPointerSub::From(self.span))
|
||||||
self.span,
|
};
|
||||||
"the type information given here is insufficient to check whether \
|
fcx.tcx.sess.emit_err(errors::CastUnknownPointer {
|
||||||
the pointer cast is valid",
|
span,
|
||||||
);
|
to: unknown_cast_to,
|
||||||
}
|
sub,
|
||||||
err.emit();
|
});
|
||||||
}
|
}
|
||||||
CastError::ForeignNonExhaustiveAdt => {
|
CastError::ForeignNonExhaustiveAdt => {
|
||||||
make_invalid_casting_error(
|
make_invalid_casting_error(
|
||||||
@ -674,31 +631,18 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
||||||
let t_cast = self.cast_ty;
|
let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() {
|
||||||
let t_expr = self.expr_ty;
|
(true, lint::builtin::TRIVIAL_NUMERIC_CASTS)
|
||||||
let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
|
|
||||||
("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
|
|
||||||
} else {
|
} 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,
|
lint,
|
||||||
self.expr.hir_id,
|
self.expr.hir_id,
|
||||||
self.span,
|
self.span,
|
||||||
DelayDm(|| {
|
errors::TrivialCast { numeric, expr_ty, cast_ty },
|
||||||
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",
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -991,93 +935,67 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
if let ty::Adt(d, _) = self.expr_ty.kind()
|
if let ty::Adt(d, _) = self.expr_ty.kind()
|
||||||
&& d.has_dtor(fcx.tcx)
|
&& 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,
|
lint::builtin::CENUM_IMPL_DROP_CAST,
|
||||||
self.expr.hir_id,
|
self.expr.hir_id,
|
||||||
self.span,
|
self.span,
|
||||||
DelayDm(|| format!(
|
errors::CastEnumDrop {
|
||||||
"cannot cast enum `{}` into integer `{}` because it implements `Drop`",
|
expr_ty,
|
||||||
self.expr_ty, self.cast_ty
|
cast_ty,
|
||||||
)),
|
}
|
||||||
|lint| {
|
|
||||||
lint
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
|
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,
|
lint::builtin::LOSSY_PROVENANCE_CASTS,
|
||||||
self.expr.hir_id,
|
self.expr.hir_id,
|
||||||
self.span,
|
self.span,
|
||||||
DelayDm(|| format!(
|
lint,
|
||||||
"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
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
|
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,
|
lint::builtin::FUZZY_PROVENANCE_CASTS,
|
||||||
self.expr.hir_id,
|
self.expr.hir_id,
|
||||||
self.span,
|
self.span,
|
||||||
DelayDm(|| format!(
|
lint,
|
||||||
"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
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1093,26 +1011,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||||||
if let Some((deref_ty, _)) = derefed {
|
if let Some((deref_ty, _)) = derefed {
|
||||||
// Give a note about what the expr derefs to.
|
// Give a note about what the expr derefs to.
|
||||||
if deref_ty != self.expr_ty.peel_refs() {
|
if deref_ty != self.expr_ty.peel_refs() {
|
||||||
err.span_note(
|
err.subdiagnostic(errors::DerefImplsIsEmpty {
|
||||||
self.expr_span,
|
span: self.expr_span,
|
||||||
format!(
|
deref_ty: fcx.ty_to_string(deref_ty),
|
||||||
"this expression `Deref`s to `{}` which implements `is_empty`",
|
});
|
||||||
fcx.ty_to_string(deref_ty)
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a multipart suggestion: add `!` and `.is_empty()` in
|
// Create a multipart suggestion: add `!` and `.is_empty()` in
|
||||||
// place of the cast.
|
// place of the cast.
|
||||||
let suggestion = vec![
|
err.subdiagnostic(errors::UseIsEmpty {
|
||||||
(self.expr_span.shrink_to_lo(), "!".to_string()),
|
lo: self.expr_span.shrink_to_lo(),
|
||||||
(self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
|
hi: self.span.with_lo(self.expr_span.hi()),
|
||||||
];
|
expr_ty: fcx.ty_to_string(self.expr_ty),
|
||||||
|
});
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use rustc_errors::{
|
|||||||
AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
|
AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
|
||||||
SubdiagnosticMessage,
|
SubdiagnosticMessage,
|
||||||
};
|
};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||||
use rustc_middle::ty::Ty;
|
use rustc_middle::ty::Ty;
|
||||||
use rustc_span::{
|
use rustc_span::{
|
||||||
edition::{Edition, LATEST_STABLE_EDITION},
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_typeck_yield_expr_outside_of_generator, code = "E0627")]
|
#[diag(hir_typeck_yield_expr_outside_of_generator, code = "E0627")]
|
||||||
pub struct YieldExprOutsideOfGenerator {
|
pub struct YieldExprOutsideOfGenerator {
|
||||||
@ -76,6 +83,14 @@ pub struct MethodCallOnUnknownRawPointee {
|
|||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(hir_typeck_missing_fn_lang_items)]
|
||||||
|
#[help]
|
||||||
|
pub struct MissingFnLangItems {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")]
|
#[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")]
|
||||||
pub struct FunctionalRecordUpdateOnNonStruct {
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
|
#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
|
||||||
pub struct MissingParenthesesInRange {
|
pub struct MissingParenthesesInRange {
|
||||||
@ -231,6 +269,69 @@ pub struct LangStartIncorrectRetTy<'tcx> {
|
|||||||
pub found_ty: Ty<'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)]
|
#[derive(Subdiagnostic)]
|
||||||
pub enum HelpUseLatestEdition {
|
pub enum HelpUseLatestEdition {
|
||||||
#[help(hir_typeck_help_set_edition_cargo)]
|
#[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)]
|
#[derive(Subdiagnostic)]
|
||||||
pub enum OptionResultRefMismatch {
|
pub enum OptionResultRefMismatch {
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
@ -350,6 +473,20 @@ pub struct UnionPatDotDot {
|
|||||||
pub span: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_typeck_arg_mismatch_indeterminate)]
|
#[diag(hir_typeck_arg_mismatch_indeterminate)]
|
||||||
pub struct ArgMismatchIndeterminate {
|
pub struct ArgMismatchIndeterminate {
|
||||||
@ -396,6 +533,15 @@ pub struct SuggestPtrNullMut {
|
|||||||
pub span: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_typeck_no_associated_item, code = "E0599")]
|
#[diag(hir_typeck_no_associated_item, code = "E0599")]
|
||||||
pub struct NoAssociatedItem {
|
pub struct NoAssociatedItem {
|
||||||
@ -418,6 +564,74 @@ pub struct CandidateTraitNote {
|
|||||||
pub action_or_ty: String,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_typeck_ctor_is_private, code = "E0603")]
|
#[diag(hir_typeck_ctor_is_private, code = "E0603")]
|
||||||
pub struct CtorIsPrivate {
|
pub struct CtorIsPrivate {
|
||||||
@ -426,6 +640,14 @@ pub struct CtorIsPrivate {
|
|||||||
pub def: String,
|
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)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(
|
#[multipart_suggestion(
|
||||||
hir_typeck_convert_using_method,
|
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);
|
assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
|
||||||
let mut delegate = InferBorrowKind {
|
let mut delegate = InferBorrowKind {
|
||||||
fcx: self,
|
|
||||||
closure_def_id,
|
closure_def_id,
|
||||||
capture_information: Default::default(),
|
capture_information: Default::default(),
|
||||||
fake_reads: 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,
|
/// 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)`.
|
/// which states that it's unsafe to take a reference into a struct marked `repr(packed)`.
|
||||||
fn restrict_repr_packed_field_ref_capture<'tcx>(
|
fn restrict_repr_packed_field_ref_capture<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
mut place: Place<'tcx>,
|
mut place: Place<'tcx>,
|
||||||
mut curr_borrow_kind: ty::UpvarCapture,
|
mut curr_borrow_kind: ty::UpvarCapture,
|
||||||
) -> (Place<'tcx>, ty::UpvarCapture) {
|
) -> (Place<'tcx>, ty::UpvarCapture) {
|
||||||
let pos = place.projections.iter().enumerate().position(|(i, p)| {
|
let pos = place.projections.iter().enumerate().position(|(i, p)| {
|
||||||
let ty = place.ty_before_projection(i);
|
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 {
|
match p.kind {
|
||||||
ProjectionKind::Field(..) => match ty.kind() {
|
ProjectionKind::Field(..) => match ty.kind() {
|
||||||
ty::Adt(def, _) if def.repr().packed() => {
|
ty::Adt(def, _) if def.repr().packed() => {
|
||||||
// We erase regions here because they cannot be hashed
|
// We stop here regardless of field alignment. Field alignment can change as
|
||||||
match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) {
|
// types change, including the types of private fields in other crates, and that
|
||||||
Ok(layout) if layout.align.abi.bytes() == 1 => {
|
// shouldn't affect how we compute our captures.
|
||||||
// if the alignment is 1, the type can't be further
|
true
|
||||||
// disaligned.
|
|
||||||
debug!(
|
|
||||||
"restrict_repr_packed_field_ref_capture: ({:?}) - align = 1",
|
|
||||||
place
|
|
||||||
);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
debug!("restrict_repr_packed_field_ref_capture: ({:?}) - true", place);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1689,9 +1674,7 @@ fn drop_location_span(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> Span {
|
|||||||
tcx.sess.source_map().end_point(owner_span)
|
tcx.sess.source_map().end_point(owner_span)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InferBorrowKind<'a, 'tcx> {
|
struct InferBorrowKind<'tcx> {
|
||||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
|
||||||
|
|
||||||
// The def-id of the closure whose kind and upvar accesses are being inferred.
|
// The def-id of the closure whose kind and upvar accesses are being inferred.
|
||||||
closure_def_id: LocalDefId,
|
closure_def_id: LocalDefId,
|
||||||
|
|
||||||
@ -1725,7 +1708,7 @@ struct InferBorrowKind<'a, 'tcx> {
|
|||||||
fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
|
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(
|
fn fake_read(
|
||||||
&mut self,
|
&mut self,
|
||||||
place: &PlaceWithHirId<'tcx>,
|
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_capture_precision(place.place.clone(), dummy_capture_kind);
|
||||||
|
|
||||||
let (place, _) = restrict_repr_packed_field_ref_capture(
|
let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind);
|
||||||
self.fcx.tcx,
|
|
||||||
self.fcx.param_env,
|
|
||||||
place,
|
|
||||||
dummy_capture_kind,
|
|
||||||
);
|
|
||||||
self.fake_reads.push((place, cause, diag_expr_id));
|
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
|
// 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
|
// struct, and not when the data is being moved. Therefore we call this method here instead
|
||||||
// of in `restrict_capture_precision`.
|
// of in `restrict_capture_precision`.
|
||||||
let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(
|
let (place, mut capture_kind) =
|
||||||
self.fcx.tcx,
|
restrict_repr_packed_field_ref_capture(place_with_id.place.clone(), capture_kind);
|
||||||
self.fcx.param_env,
|
|
||||||
place_with_id.place.clone(),
|
|
||||||
capture_kind,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Raw pointers don't inherit mutability
|
// Raw pointers don't inherit mutability
|
||||||
if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) {
|
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 {
|
let highlight_trait_ref = |trait_ref| Highlighted {
|
||||||
tcx: self.tcx(),
|
tcx: self.tcx(),
|
||||||
highlight: RegionHighlightMode::new(self.tcx()),
|
highlight: RegionHighlightMode::default(),
|
||||||
value: trait_ref,
|
value: trait_ref,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,9 +67,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> HighlightBuilder<'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 =
|
let mut builder =
|
||||||
HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
|
HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
|
||||||
builder.visit_ty(ty);
|
builder.visit_ty(ty);
|
||||||
builder.highlight
|
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
|
let expected = self
|
||||||
.cx
|
.cx
|
||||||
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
|
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
|
||||||
.name;
|
.name;
|
||||||
let found_highlight = HighlightBuilder::build(self.tcx(), found);
|
let found_highlight = HighlightBuilder::build(found);
|
||||||
let found =
|
let found =
|
||||||
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
|
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.
|
//! and use that to decide when one free region outlives another, and so forth.
|
||||||
|
|
||||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
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`.
|
/// Combines a `FreeRegionMap` and a `TyCtxt`.
|
||||||
///
|
///
|
||||||
@ -101,10 +101,3 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
|||||||
result
|
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)? {
|
if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
|
||||||
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
|
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
|
||||||
if let Err(e) = ct.error_reported() {
|
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() {
|
} 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 {
|
} else {
|
||||||
args = replace_param_and_infer_args_with_placeholder(tcx, args);
|
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);
|
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 {
|
match sess.io.output_file {
|
||||||
None => {
|
None => {
|
||||||
// "-" as input file will cause the parser to read from stdin so we
|
// "-" 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();
|
let dirpath = sess.io.output_dir.clone().unwrap_or_default();
|
||||||
|
|
||||||
// If a crate name is present, we use it as the link name
|
// If a crate name is present, we use it as the link name
|
||||||
let stem = sess
|
let stem = crate_name.clone().unwrap_or_else(|| sess.io.input.filestem().to_owned());
|
||||||
.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());
|
|
||||||
|
|
||||||
OutputFilenames::new(
|
OutputFilenames::new(
|
||||||
dirpath,
|
dirpath,
|
||||||
|
crate_name.unwrap_or_else(|| stem.replace('-', "_")),
|
||||||
stem,
|
stem,
|
||||||
None,
|
None,
|
||||||
sess.io.temps_dir.clone(),
|
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);
|
sess.emit_warning(errors::IgnoringOutDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let out_filestem =
|
||||||
|
out_file.filestem().unwrap_or_default().to_str().unwrap().to_string();
|
||||||
OutputFilenames::new(
|
OutputFilenames::new(
|
||||||
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
|
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,
|
ofile,
|
||||||
sess.io.temps_dir.clone(),
|
sess.io.temps_dir.clone(),
|
||||||
sess.opts.cg.extra_filename.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
|
.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}`
|
.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
|
lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false
|
||||||
.label = expression has type `{$orig_ty}`
|
.label = expression has type `{$orig_ty}`
|
||||||
|
|
||||||
|
@ -635,6 +635,8 @@ pub enum PtrNullChecksDiag<'a> {
|
|||||||
#[label]
|
#[label]
|
||||||
label: Span,
|
label: Span,
|
||||||
},
|
},
|
||||||
|
#[diag(lint_ptr_null_checks_fn_ret)]
|
||||||
|
FnRet { fn_name: Ident },
|
||||||
}
|
}
|
||||||
|
|
||||||
// for_loops_over_fallibles.rs
|
// for_loops_over_fallibles.rs
|
||||||
|
@ -31,12 +31,30 @@ declare_lint! {
|
|||||||
|
|
||||||
declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
|
declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
|
||||||
|
|
||||||
/// This function detects and returns the original expression from a series of consecutive casts,
|
/// This function checks if the expression is from a series of consecutive casts,
|
||||||
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
|
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either
|
||||||
fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
|
/// 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;
|
let mut had_at_least_one_cast = false;
|
||||||
loop {
|
loop {
|
||||||
e = e.peel_blocks();
|
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
|
e = if let ExprKind::Cast(expr, t) = e.kind
|
||||||
&& let TyKind::Ptr(_) = t.kind {
|
&& let TyKind::Ptr(_) = t.kind {
|
||||||
had_at_least_one_cast = true;
|
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)) {
|
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
|
||||||
had_at_least_one_cast = true;
|
had_at_least_one_cast = true;
|
||||||
expr
|
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 {
|
} 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 {
|
} else {
|
||||||
return None;
|
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 {
|
impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
|
@ -3405,8 +3405,8 @@ declare_lint_pass! {
|
|||||||
UNFULFILLED_LINT_EXPECTATIONS,
|
UNFULFILLED_LINT_EXPECTATIONS,
|
||||||
UNINHABITED_STATIC,
|
UNINHABITED_STATIC,
|
||||||
UNKNOWN_CRATE_TYPES,
|
UNKNOWN_CRATE_TYPES,
|
||||||
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
|
||||||
UNKNOWN_LINTS,
|
UNKNOWN_LINTS,
|
||||||
|
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||||
UNNAMEABLE_TEST_ITEMS,
|
UNNAMEABLE_TEST_ITEMS,
|
||||||
UNNAMEABLE_TYPES,
|
UNNAMEABLE_TYPES,
|
||||||
UNREACHABLE_CODE,
|
UNREACHABLE_CODE,
|
||||||
@ -4420,7 +4420,8 @@ declare_lint! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
/// ### Example
|
||||||
///
|
///
|
||||||
@ -4432,15 +4433,17 @@ declare_lint! {
|
|||||||
///
|
///
|
||||||
/// {{produces}}
|
/// {{produces}}
|
||||||
///
|
///
|
||||||
|
///
|
||||||
/// ### Explanation
|
/// ### Explanation
|
||||||
///
|
///
|
||||||
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
|
/// 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
|
/// 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
|
/// consider if you are using an old version of the compiler, and the attribute
|
||||||
/// is only available in a newer version.
|
/// is only available in a newer version.
|
||||||
pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
|
pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
|
||||||
Warn,
|
Warn,
|
||||||
"unrecognized diagnostic attribute"
|
"unrecognized or malformed diagnostic attribute",
|
||||||
|
@feature_gate = sym::diagnostic_namespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
@ -239,16 +239,22 @@ enum class LLVMRustCodeGenOptLevel {
|
|||||||
Aggressive,
|
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) {
|
switch (Level) {
|
||||||
case LLVMRustCodeGenOptLevel::None:
|
case LLVMRustCodeGenOptLevel::None:
|
||||||
return CodeGenOpt::None;
|
return CodeGenOptLevelEnum::None;
|
||||||
case LLVMRustCodeGenOptLevel::Less:
|
case LLVMRustCodeGenOptLevel::Less:
|
||||||
return CodeGenOpt::Less;
|
return CodeGenOptLevelEnum::Less;
|
||||||
case LLVMRustCodeGenOptLevel::Default:
|
case LLVMRustCodeGenOptLevel::Default:
|
||||||
return CodeGenOpt::Default;
|
return CodeGenOptLevelEnum::Default;
|
||||||
case LLVMRustCodeGenOptLevel::Aggressive:
|
case LLVMRustCodeGenOptLevel::Aggressive:
|
||||||
return CodeGenOpt::Aggressive;
|
return CodeGenOptLevelEnum::Aggressive;
|
||||||
default:
|
default:
|
||||||
report_fatal_error("Bad CodeGenOptLevel.");
|
report_fatal_error("Bad CodeGenOptLevel.");
|
||||||
}
|
}
|
||||||
@ -554,9 +560,17 @@ enum class LLVMRustFileType {
|
|||||||
static CodeGenFileType fromRust(LLVMRustFileType Type) {
|
static CodeGenFileType fromRust(LLVMRustFileType Type) {
|
||||||
switch (Type) {
|
switch (Type) {
|
||||||
case LLVMRustFileType::AssemblyFile:
|
case LLVMRustFileType::AssemblyFile:
|
||||||
|
#if LLVM_VERSION_GE(18, 0)
|
||||||
|
return CodeGenFileType::AssemblyFile;
|
||||||
|
#else
|
||||||
return CGFT_AssemblyFile;
|
return CGFT_AssemblyFile;
|
||||||
|
#endif
|
||||||
case LLVMRustFileType::ObjectFile:
|
case LLVMRustFileType::ObjectFile:
|
||||||
|
#if LLVM_VERSION_GE(18, 0)
|
||||||
|
return CodeGenFileType::ObjectFile;
|
||||||
|
#else
|
||||||
return CGFT_ObjectFile;
|
return CGFT_ObjectFile;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
report_fatal_error("Bad FileType.");
|
report_fatal_error("Bad FileType.");
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ use crate::errors::{
|
|||||||
use crate::{encode_metadata, EncodedMetadata};
|
use crate::{encode_metadata, EncodedMetadata};
|
||||||
|
|
||||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||||
use rustc_hir::def_id::LOCAL_CRATE;
|
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::{OutFileName, OutputType};
|
use rustc_session::config::{OutFileName, OutputType};
|
||||||
use rustc_session::output::filename_for_metadata;
|
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) {
|
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, tcx.output_filenames(()));
|
||||||
let out_filename = filename_for_metadata(tcx.sess, crate_name, tcx.output_filenames(()));
|
|
||||||
// To avoid races with another rustc process scanning the output directory,
|
// 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
|
// 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
|
// 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}
|
overflow while adding drop-check rules for {$ty}
|
||||||
.note = overflowed on {$overflow_ty}
|
.note = overflowed on {$overflow_ty}
|
||||||
|
|
||||||
|
middle_erroneous_constant = erroneous constant encountered
|
||||||
|
|
||||||
middle_layout_references_error =
|
middle_layout_references_error =
|
||||||
the type has an unknown layout
|
the type has an unknown layout
|
||||||
|
|
||||||
|
@ -144,5 +144,12 @@ pub struct UnsupportedFnAbi {
|
|||||||
pub abi: &'static str,
|
pub abi: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(middle_erroneous_constant)]
|
||||||
|
pub struct ErroneousConstant {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
/// Used by `rustc_const_eval`
|
/// Used by `rustc_const_eval`
|
||||||
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
|
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
|
/// variables have been rewritten to "canonical vars". These are
|
||||||
/// numbered starting from 0 in order of first appearance.
|
/// numbered starting from 0 in order of first appearance.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct Canonical<'tcx, V> {
|
pub struct Canonical<'tcx, V> {
|
||||||
pub value: V,
|
pub value: V,
|
||||||
pub max_universe: ty::UniverseIndex,
|
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
|
/// variables. You will need to supply it later to instantiate the
|
||||||
/// canonicalized query response.
|
/// canonicalized query response.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct CanonicalVarValues<'tcx> {
|
pub struct CanonicalVarValues<'tcx> {
|
||||||
pub var_values: ty::GenericArgsRef<'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
|
/// After we execute a query with a canonicalized key, we get back a
|
||||||
/// `Canonical<QueryResponse<..>>`. You can use
|
/// `Canonical<QueryResponse<..>>`. You can use
|
||||||
/// `instantiate_query_result` to access the data in this result.
|
/// `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 struct QueryResponse<'tcx, R> {
|
||||||
pub var_values: CanonicalVarValues<'tcx>,
|
pub var_values: CanonicalVarValues<'tcx>,
|
||||||
pub region_constraints: QueryRegionConstraints<'tcx>,
|
pub region_constraints: QueryRegionConstraints<'tcx>,
|
||||||
@ -326,7 +326,7 @@ pub struct QueryResponse<'tcx, R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct QueryRegionConstraints<'tcx> {
|
pub struct QueryRegionConstraints<'tcx> {
|
||||||
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
|
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
|
||||||
pub member_constraints: Vec<MemberConstraint<'tcx>>,
|
pub member_constraints: Vec<MemberConstraint<'tcx>>,
|
||||||
@ -432,7 +432,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
|
|||||||
pub type QueryOutlivesConstraint<'tcx> =
|
pub type QueryOutlivesConstraint<'tcx> =
|
||||||
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
|
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
|
||||||
|
|
||||||
TrivialTypeTraversalAndLiftImpls! {
|
TrivialTypeTraversalImpls! {
|
||||||
crate::infer::canonical::Certainty,
|
crate::infer::canonical::Certainty,
|
||||||
crate::infer::canonical::CanonicalTyVarKind,
|
crate::infer::canonical::CanonicalTyVarKind,
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ use rustc_span::Span;
|
|||||||
/// R0 member of [O1..On]
|
/// R0 member of [O1..On]
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct MemberConstraint<'tcx> {
|
pub struct MemberConstraint<'tcx> {
|
||||||
/// The `DefId` and args of the opaque type causing this constraint.
|
/// The `DefId` and args of the opaque type causing this constraint.
|
||||||
/// Used for error reporting.
|
/// Used for error reporting.
|
||||||
|
@ -42,7 +42,7 @@ macro_rules! span_bug {
|
|||||||
// the impls for you.
|
// the impls for you.
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! CloneLiftImpls {
|
macro_rules! TrivialLiftImpls {
|
||||||
($($ty:ty),+ $(,)?) => {
|
($($ty:ty),+ $(,)?) => {
|
||||||
$(
|
$(
|
||||||
impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
|
impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
|
||||||
@ -96,6 +96,6 @@ macro_rules! TrivialTypeTraversalImpls {
|
|||||||
macro_rules! TrivialTypeTraversalAndLiftImpls {
|
macro_rules! TrivialTypeTraversalAndLiftImpls {
|
||||||
($($t:tt)*) => {
|
($($t:tt)*) => {
|
||||||
TrivialTypeTraversalImpls! { $($t)* }
|
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 {
|
impl<S: Encoder> Encodable<S> for Cache {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
|
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
|
||||||
|
|
||||||
|
use crate::error;
|
||||||
use crate::mir::interpret::ConstValue;
|
use crate::mir::interpret::ConstValue;
|
||||||
use crate::query::TyCtxtAt;
|
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_data_structures::sync::Lock;
|
||||||
use rustc_errors::{
|
use rustc_errors::{
|
||||||
@ -11,7 +12,7 @@ use rustc_errors::{
|
|||||||
};
|
};
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_session::CtfeBacktrace;
|
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 rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
@ -21,16 +22,51 @@ use std::{any::Any, backtrace::Backtrace, fmt};
|
|||||||
pub enum ErrorHandled {
|
pub enum ErrorHandled {
|
||||||
/// Already reported an error for this evaluation, and the compilation is
|
/// Already reported an error for this evaluation, and the compilation is
|
||||||
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
|
/// *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
|
/// Don't emit an error, the evaluation failed because the MIR was generic
|
||||||
/// and the args didn't fully monomorphize it.
|
/// and the args didn't fully monomorphize it.
|
||||||
TooGeneric,
|
TooGeneric(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ErrorGuaranteed> for ErrorHandled {
|
impl From<ErrorGuaranteed> for ErrorHandled {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(error: ErrorGuaranteed) -> ErrorHandled {
|
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 {
|
pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
|
||||||
ReportedErrorInfo { is_tainted_by_errors: true, error }
|
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 {
|
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 EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
|
||||||
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'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> {
|
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
||||||
fn from(kind: InterpError<'tcx>) -> Self {
|
fn from(kind: InterpError<'tcx>) -> Self {
|
||||||
InterpErrorInfo(Box::new(InterpErrorInfoInner {
|
InterpErrorInfo(Box::new(InterpErrorInfoInner {
|
||||||
|
@ -162,7 +162,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
|
|||||||
/// - A constant
|
/// - A constant
|
||||||
/// - A static
|
/// - A static
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
|
||||||
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct GlobalId<'tcx> {
|
pub struct GlobalId<'tcx> {
|
||||||
/// For a constant or static, the `Instance` of the item itself.
|
/// For a constant or static, the `Instance` of the item itself.
|
||||||
/// For a promoted global, the `Instance` of the function they belong to.
|
/// 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 };
|
let cid = GlobalId { instance, promoted: ct.promoted };
|
||||||
self.const_eval_global_id(param_env, cid, span)
|
self.const_eval_global_id(param_env, cid, span)
|
||||||
}
|
}
|
||||||
Ok(None) => Err(ErrorHandled::TooGeneric),
|
// For errors during resolution, we deliberately do not point at the usage site of the constant,
|
||||||
Err(err) => Err(ErrorHandled::Reported(err.into())),
|
// 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),
|
// For errors during resolution, we deliberately do not point at the usage site of the constant,
|
||||||
Err(err) => Err(ErrorHandled::Reported(err.into())),
|
// 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.
|
// improve caching of queries.
|
||||||
let inputs = self.erase_regions(param_env.and(cid));
|
let inputs = self.erase_regions(param_env.and(cid));
|
||||||
if let Some(span) = span {
|
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 {
|
} else {
|
||||||
self.eval_to_const_value_raw(inputs)
|
self.eval_to_const_value_raw(inputs)
|
||||||
}
|
}
|
||||||
@ -162,7 +167,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
let inputs = self.erase_regions(param_env.and(cid));
|
let inputs = self.erase_regions(param_env.and(cid));
|
||||||
debug!(?inputs);
|
debug!(?inputs);
|
||||||
if let Some(span) = span {
|
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 {
|
} else {
|
||||||
self.eval_to_valtree(inputs)
|
self.eval_to_valtree(inputs)
|
||||||
}
|
}
|
||||||
|
@ -565,6 +565,34 @@ impl<'tcx> Body<'tcx> {
|
|||||||
pub fn is_custom_mir(&self) -> bool {
|
pub fn is_custom_mir(&self) -> bool {
|
||||||
self.injection_phase.is_some()
|
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)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
@ -744,7 +772,7 @@ pub enum BindingForm<'tcx> {
|
|||||||
RefForGuard,
|
RefForGuard,
|
||||||
}
|
}
|
||||||
|
|
||||||
TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
|
TrivialTypeTraversalImpls! { BindingForm<'tcx> }
|
||||||
|
|
||||||
mod binding_form_impl {
|
mod binding_form_impl {
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
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(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
|
||||||
#[derive(Lift, TypeFoldable, TypeVisitable)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub enum ConstantKind<'tcx> {
|
pub enum ConstantKind<'tcx> {
|
||||||
/// This constant came from the type system.
|
/// 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 {
|
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
||||||
match self.eval(tcx, param_env, None) {
|
match self.eval(tcx, param_env, None) {
|
||||||
Ok(val) => Self::Val(val, self.ty()),
|
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()))
|
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.
|
/// 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)]
|
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct UnevaluatedConst<'tcx> {
|
pub struct UnevaluatedConst<'tcx> {
|
||||||
pub def: DefId,
|
pub def: DefId,
|
||||||
|
@ -334,7 +334,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
|||||||
///
|
///
|
||||||
/// See also `rustc_const_eval::borrow_check::constraints`.
|
/// See also `rustc_const_eval::borrow_check::constraints`.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
#[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> {
|
pub enum ConstraintCategory<'tcx> {
|
||||||
Return(ReturnConstraint),
|
Return(ReturnConstraint),
|
||||||
Yield,
|
Yield,
|
||||||
|
@ -5,7 +5,7 @@ use rustc_ast::InlineAsmTemplatePiece;
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::ty;
|
use crate::ty;
|
||||||
|
|
||||||
TrivialTypeTraversalAndLiftImpls! {
|
TrivialTypeTraversalImpls! {
|
||||||
BlockTailInfo,
|
BlockTailInfo,
|
||||||
MirPhase,
|
MirPhase,
|
||||||
SourceInfo,
|
SourceInfo,
|
||||||
|
@ -1140,6 +1140,7 @@ rustc_queries! {
|
|||||||
query reachable_set(_: ()) -> &'tcx LocalDefIdSet {
|
query reachable_set(_: ()) -> &'tcx LocalDefIdSet {
|
||||||
arena_cache
|
arena_cache
|
||||||
desc { "reachability" }
|
desc { "reachability" }
|
||||||
|
cache_on_disk_if { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
|
/// 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::mir::ConstraintCategory;
|
||||||
use crate::ty::abstract_const::NotConstEvaluatable;
|
use crate::ty::abstract_const::NotConstEvaluatable;
|
||||||
use crate::ty::GenericArgsRef;
|
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_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{Applicability, Diagnostic};
|
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
|
/// We do not want to intern this as there are a lot of obligation causes which
|
||||||
/// only live for a short period of time.
|
/// 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)]
|
#[derive(TypeVisitable, TypeFoldable)]
|
||||||
pub struct ObligationCause<'tcx> {
|
pub struct ObligationCause<'tcx> {
|
||||||
pub span: Span,
|
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)]
|
#[derive(TypeVisitable, TypeFoldable)]
|
||||||
pub struct UnifyReceiverContext<'tcx> {
|
pub struct UnifyReceiverContext<'tcx> {
|
||||||
pub assoc_item: ty::AssocItem,
|
pub assoc_item: ty::AssocItem,
|
||||||
@ -202,7 +202,7 @@ pub struct UnifyReceiverContext<'tcx> {
|
|||||||
pub args: GenericArgsRef<'tcx>,
|
pub args: GenericArgsRef<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Lift, Default, HashStable)]
|
#[derive(Clone, PartialEq, Eq, Default, HashStable)]
|
||||||
#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
|
#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
|
||||||
pub struct InternedObligationCauseCode<'tcx> {
|
pub struct InternedObligationCauseCode<'tcx> {
|
||||||
/// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
|
/// `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)]
|
#[derive(TypeVisitable, TypeFoldable)]
|
||||||
pub enum ObligationCauseCode<'tcx> {
|
pub enum ObligationCauseCode<'tcx> {
|
||||||
/// Not well classified or should be obvious from the span.
|
/// 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)]
|
#[derive(TypeVisitable, TypeFoldable)]
|
||||||
pub struct ImplDerivedObligationCause<'tcx> {
|
pub struct ImplDerivedObligationCause<'tcx> {
|
||||||
pub derived: DerivedObligationCause<'tcx>,
|
pub derived: DerivedObligationCause<'tcx>,
|
||||||
@ -524,14 +524,7 @@ pub enum StatementAsExpression {
|
|||||||
NeedsBoxing,
|
NeedsBoxing,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
|
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
||||||
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(TypeVisitable, TypeFoldable)]
|
#[derive(TypeVisitable, TypeFoldable)]
|
||||||
pub struct MatchExpressionArmCause<'tcx> {
|
pub struct MatchExpressionArmCause<'tcx> {
|
||||||
pub arm_block_id: Option<hir::HirId>,
|
pub arm_block_id: Option<hir::HirId>,
|
||||||
@ -547,7 +540,7 @@ pub struct MatchExpressionArmCause<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
|
#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
|
||||||
pub struct IfExpressionCause<'tcx> {
|
pub struct IfExpressionCause<'tcx> {
|
||||||
pub then_id: hir::HirId,
|
pub then_id: hir::HirId,
|
||||||
pub else_id: hir::HirId,
|
pub else_id: hir::HirId,
|
||||||
@ -557,7 +550,7 @@ pub struct IfExpressionCause<'tcx> {
|
|||||||
pub opt_suggest_box_span: Option<Span>,
|
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)]
|
#[derive(TypeVisitable, TypeFoldable)]
|
||||||
pub struct DerivedObligationCause<'tcx> {
|
pub struct DerivedObligationCause<'tcx> {
|
||||||
/// The trait predicate of the parent obligation that led to the
|
/// The trait predicate of the parent obligation that led to the
|
||||||
@ -570,7 +563,7 @@ pub struct DerivedObligationCause<'tcx> {
|
|||||||
pub parent_code: InternedObligationCauseCode<'tcx>,
|
pub parent_code: InternedObligationCauseCode<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, TypeVisitable, Lift)]
|
#[derive(Clone, Debug, TypeVisitable)]
|
||||||
pub enum SelectionError<'tcx> {
|
pub enum SelectionError<'tcx> {
|
||||||
/// The trait is not implemented.
|
/// The trait is not implemented.
|
||||||
Unimplemented,
|
Unimplemented,
|
||||||
@ -593,7 +586,7 @@ pub enum SelectionError<'tcx> {
|
|||||||
OpaqueTypeAutoTraitLeakageUnknown(DefId),
|
OpaqueTypeAutoTraitLeakageUnknown(DefId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, TypeVisitable, Lift)]
|
#[derive(Clone, Debug, TypeVisitable)]
|
||||||
pub struct SelectionOutputTypeParameterMismatch<'tcx> {
|
pub struct SelectionOutputTypeParameterMismatch<'tcx> {
|
||||||
pub found_trait_ref: ty::PolyTraitRef<'tcx>,
|
pub found_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
pub expected_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`
|
/// ### The type parameter `N`
|
||||||
///
|
///
|
||||||
/// See explanation on `ImplSourceUserDefinedData`.
|
/// See explanation on `ImplSourceUserDefinedData`.
|
||||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub enum ImplSource<'tcx, N> {
|
pub enum ImplSource<'tcx, N> {
|
||||||
/// ImplSource identifying a particular impl.
|
/// 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 `Obligation`, as one might expect. During codegen, however, this
|
||||||
/// is `()`, because codegen only requires a shallow resolution of an
|
/// is `()`, because codegen only requires a shallow resolution of an
|
||||||
/// impl, and nested obligations are satisfied later.
|
/// 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)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub struct ImplSourceUserDefinedData<'tcx, N> {
|
pub struct ImplSourceUserDefinedData<'tcx, N> {
|
||||||
pub impl_def_id: DefId,
|
pub impl_def_id: DefId,
|
||||||
@ -736,7 +729,7 @@ pub enum BuiltinImplSource {
|
|||||||
TupleUnsizing,
|
TupleUnsizing,
|
||||||
}
|
}
|
||||||
|
|
||||||
TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
|
TrivialTypeTraversalImpls! { BuiltinImplSource }
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
|
||||||
pub enum ObjectSafetyViolation {
|
pub enum ObjectSafetyViolation {
|
||||||
|
@ -17,8 +17,7 @@ pub mod type_op {
|
|||||||
use crate::ty::{Predicate, Ty, TyCtxt, UserType};
|
use crate::ty::{Predicate, Ty, TyCtxt, UserType};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
|
||||||
pub struct AscribeUserType<'tcx> {
|
pub struct AscribeUserType<'tcx> {
|
||||||
pub mir_ty: Ty<'tcx>,
|
pub mir_ty: Ty<'tcx>,
|
||||||
pub user_ty: UserType<'tcx>,
|
pub user_ty: UserType<'tcx>,
|
||||||
@ -30,22 +29,19 @@ pub mod type_op {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
|
||||||
pub struct Eq<'tcx> {
|
pub struct Eq<'tcx> {
|
||||||
pub a: Ty<'tcx>,
|
pub a: Ty<'tcx>,
|
||||||
pub b: Ty<'tcx>,
|
pub b: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
|
||||||
pub struct Subtype<'tcx> {
|
pub struct Subtype<'tcx> {
|
||||||
pub sub: Ty<'tcx>,
|
pub sub: Ty<'tcx>,
|
||||||
pub sup: Ty<'tcx>,
|
pub sup: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
|
||||||
pub struct ProvePredicate<'tcx> {
|
pub struct ProvePredicate<'tcx> {
|
||||||
pub predicate: Predicate<'tcx>,
|
pub predicate: Predicate<'tcx>,
|
||||||
}
|
}
|
||||||
@ -56,8 +52,7 @@ pub mod type_op {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
|
||||||
pub struct Normalize<T> {
|
pub struct Normalize<T> {
|
||||||
pub value: 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 struct DropckOutlivesResult<'tcx> {
|
||||||
pub kinds: Vec<GenericArg<'tcx>>,
|
pub kinds: Vec<GenericArg<'tcx>>,
|
||||||
pub overflows: Vec<Ty<'tcx>>,
|
pub overflows: Vec<Ty<'tcx>>,
|
||||||
@ -194,7 +189,7 @@ pub struct MethodAutoderefBadTy<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Result from the `normalize_projection_ty` query.
|
/// Result from the `normalize_projection_ty` query.
|
||||||
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct NormalizationResult<'tcx> {
|
pub struct NormalizationResult<'tcx> {
|
||||||
/// Result of normalization.
|
/// Result of normalization.
|
||||||
pub normalized_ty: Ty<'tcx>,
|
pub normalized_ty: Ty<'tcx>,
|
||||||
@ -207,7 +202,7 @@ pub struct NormalizationResult<'tcx> {
|
|||||||
/// case they are called implied bounds). They are fed to the
|
/// case they are called implied bounds). They are fed to the
|
||||||
/// `OutlivesEnv` which in turn is supplied to the region checker and
|
/// `OutlivesEnv` which in turn is supplied to the region checker and
|
||||||
/// other parts of the inference system.
|
/// other parts of the inference system.
|
||||||
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift, HashStable)]
|
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
|
||||||
pub enum OutlivesBound<'tcx> {
|
pub enum OutlivesBound<'tcx> {
|
||||||
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
|
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
|
||||||
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
|
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> {
|
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||||
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
|
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
|
||||||
|
@ -14,10 +14,16 @@ pub enum CacheHit {
|
|||||||
Global,
|
Global,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub enum GoalEvaluationKind {
|
||||||
|
Root,
|
||||||
|
Nested { is_normalizes_to_hack: IsNormalizesToHack },
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
pub struct GoalEvaluation<'tcx> {
|
pub struct GoalEvaluation<'tcx> {
|
||||||
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||||
pub is_normalizes_to_hack: IsNormalizesToHack,
|
pub kind: GoalEvaluationKind,
|
||||||
pub evaluation: CanonicalGoalEvaluation<'tcx>,
|
pub evaluation: CanonicalGoalEvaluation<'tcx>,
|
||||||
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||||
}
|
}
|
||||||
@ -25,12 +31,12 @@ pub struct GoalEvaluation<'tcx> {
|
|||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
pub struct CanonicalGoalEvaluation<'tcx> {
|
pub struct CanonicalGoalEvaluation<'tcx> {
|
||||||
pub goal: CanonicalInput<'tcx>,
|
pub goal: CanonicalInput<'tcx>,
|
||||||
pub kind: GoalEvaluationKind<'tcx>,
|
pub kind: CanonicalGoalEvaluationKind<'tcx>,
|
||||||
pub result: QueryResult<'tcx>,
|
pub result: QueryResult<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
pub enum GoalEvaluationKind<'tcx> {
|
pub enum CanonicalGoalEvaluationKind<'tcx> {
|
||||||
Overflow,
|
Overflow,
|
||||||
CacheHit(CacheHit),
|
CacheHit(CacheHit),
|
||||||
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
|
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
|
||||||
@ -52,22 +58,31 @@ pub struct GoalEvaluationStep<'tcx> {
|
|||||||
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
|
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
|
||||||
|
|
||||||
/// The actual evaluation of the goal, always `ProbeKind::Root`.
|
/// 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)]
|
#[derive(Eq, PartialEq)]
|
||||||
pub struct GoalCandidate<'tcx> {
|
pub struct Probe<'tcx> {
|
||||||
pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
|
pub steps: Vec<ProbeStep<'tcx>>,
|
||||||
pub candidates: Vec<GoalCandidate<'tcx>>,
|
|
||||||
pub kind: ProbeKind<'tcx>,
|
pub kind: ProbeKind<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for GoalCandidate<'_> {
|
impl Debug for Probe<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum ProbeKind<'tcx> {
|
pub enum ProbeKind<'tcx> {
|
||||||
/// The root inference context while proving a goal.
|
/// 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 {
|
pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
|
||||||
let goal_text = match eval.is_normalizes_to_hack {
|
let goal_text = match eval.kind {
|
||||||
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
|
GoalEvaluationKind::Root => "ROOT GOAL",
|
||||||
IsNormalizesToHack::No => "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)?;
|
writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
|
||||||
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
|
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)?;
|
writeln!(self.f, "GOAL: {:?}", eval.goal)?;
|
||||||
|
|
||||||
match &eval.kind {
|
match &eval.kind {
|
||||||
GoalEvaluationKind::Overflow => {
|
CanonicalGoalEvaluationKind::Overflow => {
|
||||||
writeln!(self.f, "OVERFLOW: {:?}", eval.result)
|
writeln!(self.f, "OVERFLOW: {:?}", eval.result)
|
||||||
}
|
}
|
||||||
GoalEvaluationKind::CacheHit(CacheHit::Global) => {
|
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => {
|
||||||
writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
|
writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
|
||||||
}
|
}
|
||||||
GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
|
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
|
||||||
writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
|
writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
|
||||||
}
|
}
|
||||||
GoalEvaluationKind::Uncached { revisions } => {
|
CanonicalGoalEvaluationKind::Uncached { revisions } => {
|
||||||
for (n, step) in revisions.iter().enumerate() {
|
for (n, step) in revisions.iter().enumerate() {
|
||||||
writeln!(self.f, "REVISION {n}")?;
|
writeln!(self.f, "REVISION {n}")?;
|
||||||
self.nested(|this| this.format_evaluation_step(step))?;
|
self.nested(|this| this.format_evaluation_step(step))?;
|
||||||
@ -92,11 +95,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
|||||||
evaluation_step: &GoalEvaluationStep<'_>,
|
evaluation_step: &GoalEvaluationStep<'_>,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
|
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 {
|
pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
|
||||||
match &candidate.kind {
|
match &probe.kind {
|
||||||
ProbeKind::Root { result } => {
|
ProbeKind::Root { result } => {
|
||||||
writeln!(self.f, "ROOT RESULT: {result:?}")
|
writeln!(self.f, "ROOT RESULT: {result:?}")
|
||||||
}
|
}
|
||||||
@ -118,11 +121,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
|
|||||||
}?;
|
}?;
|
||||||
|
|
||||||
self.nested(|this| {
|
self.nested(|this| {
|
||||||
for candidate in &candidate.candidates {
|
for step in &probe.steps {
|
||||||
this.format_candidate(candidate)?;
|
match step {
|
||||||
}
|
ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
|
||||||
for nested in &candidate.added_goals_evaluations {
|
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
|
||||||
this.format_added_goals_evaluation(nested)?;
|
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
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>;
|
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
|
/// 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]>` ->
|
/// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
|
||||||
/// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
|
/// `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 struct Adjustment<'tcx> {
|
||||||
pub kind: Adjust<'tcx>,
|
pub kind: Adjust<'tcx>,
|
||||||
pub target: Ty<'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> {
|
pub enum Adjust<'tcx> {
|
||||||
/// Go from ! to any type.
|
/// Go from ! to any type.
|
||||||
NeverToAny,
|
NeverToAny,
|
||||||
@ -110,7 +110,7 @@ pub enum Adjust<'tcx> {
|
|||||||
/// The target type is `U` in both cases, with the region and mutability
|
/// The target type is `U` in both cases, with the region and mutability
|
||||||
/// being those shared by both the receiver and the returned reference.
|
/// being those shared by both the receiver and the returned reference.
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable, Lift)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub struct OverloadedDeref<'tcx> {
|
pub struct OverloadedDeref<'tcx> {
|
||||||
pub region: ty::Region<'tcx>,
|
pub region: ty::Region<'tcx>,
|
||||||
pub mutbl: hir::Mutability,
|
pub mutbl: hir::Mutability,
|
||||||
@ -182,7 +182,7 @@ impl From<AutoBorrowMutability> for hir::Mutability {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||||
#[derive(TypeFoldable, TypeVisitable, Lift)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub enum AutoBorrow<'tcx> {
|
pub enum AutoBorrow<'tcx> {
|
||||||
/// Converts from T to &T.
|
/// Converts from T to &T.
|
||||||
Ref(ty::Region<'tcx>, AutoBorrowMutability),
|
Ref(ty::Region<'tcx>, AutoBorrowMutability),
|
||||||
|
@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> {
|
|||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = match err {
|
let msg = match err {
|
||||||
ErrorHandled::Reported(_) => "enum discriminant evaluation failed",
|
ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
|
||||||
ErrorHandled::TooGeneric => "enum discriminant depends on generics",
|
ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
|
||||||
};
|
};
|
||||||
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
|
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
|
||||||
None
|
None
|
||||||
|
@ -6,7 +6,7 @@ pub enum BindingMode {
|
|||||||
BindByValue(Mutability),
|
BindByValue(Mutability),
|
||||||
}
|
}
|
||||||
|
|
||||||
TrivialTypeTraversalAndLiftImpls! { BindingMode }
|
TrivialTypeTraversalImpls! { BindingMode }
|
||||||
|
|
||||||
impl BindingMode {
|
impl BindingMode {
|
||||||
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
|
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
|
||||||
|
@ -300,7 +300,7 @@ impl<'tcx> Const<'tcx> {
|
|||||||
| ConstKind::Infer(_)
|
| ConstKind::Infer(_)
|
||||||
| ConstKind::Bound(_, _)
|
| ConstKind::Bound(_, _)
|
||||||
| ConstKind::Placeholder(_)
|
| 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 {
|
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
|
||||||
match self.eval(tcx, param_env, None) {
|
match self.eval(tcx, param_env, None) {
|
||||||
Ok(val) => Self::new_value(tcx, val, self.ty()),
|
Ok(val) => Self::new_value(tcx, val, self.ty()),
|
||||||
Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
|
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
|
||||||
Err(ErrorHandled::TooGeneric) => self,
|
Err(ErrorHandled::TooGeneric(_span)) => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
|
|||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
|
||||||
/// An unevaluated (potentially generic) constant used in the type-system.
|
/// 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)]
|
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct UnevaluatedConst<'tcx> {
|
pub struct UnevaluatedConst<'tcx> {
|
||||||
pub def: DefId,
|
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::definitions::Definitions;
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::lang_items::LangItem;
|
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_index::IndexVec;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
use rustc_query_system::dep_graph::DepNodeIndex;
|
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||||
@ -82,6 +82,7 @@ use std::ops::{Bound, Deref};
|
|||||||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||||
type AdtDef = ty::AdtDef<'tcx>;
|
type AdtDef = ty::AdtDef<'tcx>;
|
||||||
type GenericArgsRef = ty::GenericArgsRef<'tcx>;
|
type GenericArgsRef = ty::GenericArgsRef<'tcx>;
|
||||||
|
type GenericArg = ty::GenericArg<'tcx>;
|
||||||
type DefId = DefId;
|
type DefId = DefId;
|
||||||
type Binder<T> = Binder<'tcx, T>;
|
type Binder<T> = Binder<'tcx, T>;
|
||||||
type Ty = Ty<'tcx>;
|
type Ty = Ty<'tcx>;
|
||||||
@ -1214,6 +1215,25 @@ macro_rules! nop_lift {
|
|||||||
impl<'a, 'tcx> Lift<'tcx> for $ty {
|
impl<'a, 'tcx> Lift<'tcx> for $ty {
|
||||||
type Lifted = $lifted;
|
type Lifted = $lifted;
|
||||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::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
|
tcx.interners
|
||||||
.$set
|
.$set
|
||||||
.contains_pointer_to(&InternedInSet(&*self.0.0))
|
.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> {
|
impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
|
||||||
type Lifted = &'tcx List<$lifted>;
|
type Lifted = &'tcx List<$lifted>;
|
||||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::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() {
|
if self.is_empty() {
|
||||||
return Some(List::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! {type_lists; Ty<'a> => Ty<'tcx>}
|
||||||
nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'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}
|
nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
|
||||||
|
|
||||||
// This is the impl for `&'a GenericArgs<'a>`.
|
// This is the impl for `&'a GenericArgs<'a>`.
|
||||||
nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>}
|
nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>}
|
||||||
|
|
||||||
CloneLiftImpls! {
|
TrivialLiftImpls! {
|
||||||
Constness,
|
|
||||||
traits::WellFormedLoc,
|
|
||||||
ImplPolarity,
|
ImplPolarity,
|
||||||
crate::mir::ReturnConstraint,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! sty_debug_print {
|
macro_rules! sty_debug_print {
|
||||||
|
@ -11,7 +11,7 @@ use std::collections::hash_map::DefaultHasher;
|
|||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::PathBuf;
|
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 struct ExpectedFound<T> {
|
||||||
pub expected: T,
|
pub expected: T,
|
||||||
pub found: T,
|
pub found: T,
|
||||||
@ -28,7 +28,7 @@ impl<T> ExpectedFound<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Data structures used in type unification
|
// 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]
|
#[rustc_pass_by_value]
|
||||||
pub enum TypeError<'tcx> {
|
pub enum TypeError<'tcx> {
|
||||||
Mismatch,
|
Mismatch,
|
||||||
|
@ -1029,7 +1029,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
|
|||||||
/// Stores the user-given args to reach some fully qualified path
|
/// Stores the user-given args to reach some fully qualified path
|
||||||
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
|
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct UserArgs<'tcx> {
|
pub struct UserArgs<'tcx> {
|
||||||
/// The args for the item as given by the user.
|
/// The args for the item as given by the user.
|
||||||
pub args: GenericArgsRef<'tcx>,
|
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, giving `Foo<?A>`. Finally, we unify that with
|
||||||
/// the self type here, which contains `?A` to be `&'static u32`
|
/// the self type here, which contains `?A` to be `&'static u32`
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
|
||||||
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct UserSelfTy<'tcx> {
|
pub struct UserSelfTy<'tcx> {
|
||||||
pub impl_def_id: DefId,
|
pub impl_def_id: DefId,
|
||||||
pub self_ty: Ty<'tcx>,
|
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
|
/// 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
|
/// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval
|
||||||
/// will do all required substitution as they run.
|
/// 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(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
|
||||||
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
|
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
|
||||||
pub struct Instance<'tcx> {
|
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)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub struct OpaqueTypeKey<'tcx> {
|
pub struct OpaqueTypeKey<'tcx> {
|
||||||
pub def_id: LocalDefId,
|
pub def_id: LocalDefId,
|
||||||
@ -1793,7 +1793,7 @@ impl<'tcx> ParamEnv<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
|
||||||
#[derive(HashStable, Lift)]
|
#[derive(HashStable)]
|
||||||
pub struct ParamEnvAnd<'tcx, T> {
|
pub struct ParamEnvAnd<'tcx, T> {
|
||||||
pub param_env: ParamEnv<'tcx>,
|
pub param_env: ParamEnv<'tcx>,
|
||||||
pub value: T,
|
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> {
|
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) {
|
if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
|
||||||
let did: DefId = did.into();
|
let did: DefId = did.into();
|
||||||
|
@ -136,10 +136,8 @@ define_helper!(
|
|||||||
///
|
///
|
||||||
/// Regions not selected by the region highlight mode are presently
|
/// Regions not selected by the region highlight mode are presently
|
||||||
/// unaffected.
|
/// unaffected.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub struct RegionHighlightMode<'tcx> {
|
pub struct RegionHighlightMode<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
|
|
||||||
/// If enabled, when we see the selected region, use "`'N`"
|
/// If enabled, when we see the selected region, use "`'N`"
|
||||||
/// instead of the ordinary behavior.
|
/// instead of the ordinary behavior.
|
||||||
highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
|
highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
|
||||||
@ -155,14 +153,6 @@ pub struct RegionHighlightMode<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> 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
|
/// If `region` and `number` are both `Some`, invokes
|
||||||
/// `highlighting_region`.
|
/// `highlighting_region`.
|
||||||
pub fn maybe_highlighting_region(
|
pub fn maybe_highlighting_region(
|
||||||
@ -188,8 +178,13 @@ impl<'tcx> RegionHighlightMode<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience wrapper for `highlighting_region`.
|
/// Convenience wrapper for `highlighting_region`.
|
||||||
pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
|
pub fn highlighting_region_vid(
|
||||||
self.highlighting_region(ty::Region::new_var(self.tcx, vid), number)
|
&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.
|
/// 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,
|
printed_type_count: 0,
|
||||||
type_length_limit,
|
type_length_limit,
|
||||||
truncated: false,
|
truncated: false,
|
||||||
region_highlight_mode: RegionHighlightMode::new(tcx),
|
region_highlight_mode: RegionHighlightMode::default(),
|
||||||
ty_infer_name_resolver: None,
|
ty_infer_name_resolver: None,
|
||||||
const_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,
|
// HACK(eddyb) these are exhaustive instead of generic,
|
||||||
// because `for<'tcx>` isn't possible yet.
|
// because `for<'tcx>` isn't possible yet.
|
||||||
ty::PolyExistentialPredicate<'tcx>,
|
|
||||||
ty::PolyExistentialProjection<'tcx>,
|
ty::PolyExistentialProjection<'tcx>,
|
||||||
ty::PolyExistentialTraitRef<'tcx>,
|
ty::PolyExistentialTraitRef<'tcx>,
|
||||||
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||||
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
|
||||||
ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
|
|
||||||
ty::Binder<'tcx, ty::FnSig<'tcx>>,
|
ty::Binder<'tcx, ty::FnSig<'tcx>>,
|
||||||
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
|
||||||
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
|
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
|
||||||
ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
|
|
||||||
ty::Binder<'tcx, ty::ProjectionPredicate<'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<'tcx>, ty::Region<'tcx>>,
|
||||||
ty::OutlivesPredicate<ty::Region<'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::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||||
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
|
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_index::{Idx, IndexVec};
|
|
||||||
use rustc_target::abi::TyAndLayout;
|
use rustc_target::abi::TyAndLayout;
|
||||||
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
|
||||||
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
|
use super::print::PrettyPrinter;
|
||||||
use super::{GenericArg, GenericArgKind, Region};
|
use super::{GenericArg, GenericArgKind, Region};
|
||||||
|
|
||||||
impl fmt::Debug for ty::TraitDef {
|
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>,
|
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
|
||||||
f: &mut core::fmt::Formatter<'_>,
|
f: &mut core::fmt::Formatter<'_>,
|
||||||
) -> core::fmt::Result {
|
) -> core::fmt::Result {
|
||||||
// This reflects what `Const` looked liked before `Interned` was
|
// If this is a value, we spend some effort to make it look nice.
|
||||||
// introduced. We print it like this to avoid having to update expected
|
if let ConstKind::Value(_) = this.data.kind() {
|
||||||
// output in a lot of tests.
|
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!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Const {{ ty: {:?}, kind: {:?} }}",
|
"{kind:?}: {ty:?}",
|
||||||
&this.map(|data| data.ty()),
|
ty = &this.map(|data| data.ty()),
|
||||||
&this.map(|data| data.kind())
|
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 things for which the type library provides traversal implementations
|
||||||
// for all Interners, we only need to provide a Lift implementation:
|
// for all Interners, we only need to provide a Lift implementation:
|
||||||
CloneLiftImpls! {
|
TrivialLiftImpls! {
|
||||||
(),
|
(),
|
||||||
bool,
|
bool,
|
||||||
usize,
|
usize,
|
||||||
u16,
|
|
||||||
u32,
|
|
||||||
u64,
|
|
||||||
String,
|
|
||||||
rustc_type_ir::DebruijnIndex,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For things about which the type library does not know, or does not
|
// For some things about which the type library does not know, or does not
|
||||||
// provide any traversal implementations, we need to provide both a Lift
|
// provide any traversal implementations, we need to provide a traversal
|
||||||
// implementation and traversal implementations (the latter only for
|
// implementation (only for TyCtxt<'_> interners).
|
||||||
// TyCtxt<'_> interners).
|
TrivialTypeTraversalImpls! {
|
||||||
TrivialTypeTraversalAndLiftImpls! {
|
|
||||||
::rustc_target::abi::FieldIdx,
|
::rustc_target::abi::FieldIdx,
|
||||||
::rustc_target::abi::VariantIdx,
|
::rustc_target::abi::VariantIdx,
|
||||||
crate::middle::region::Scope,
|
crate::middle::region::Scope,
|
||||||
@ -467,14 +472,10 @@ TrivialTypeTraversalAndLiftImpls! {
|
|||||||
::rustc_ast::NodeId,
|
::rustc_ast::NodeId,
|
||||||
::rustc_span::symbol::Symbol,
|
::rustc_span::symbol::Symbol,
|
||||||
::rustc_hir::def::Res,
|
::rustc_hir::def::Res,
|
||||||
::rustc_hir::def_id::DefId,
|
|
||||||
::rustc_hir::def_id::LocalDefId,
|
::rustc_hir::def_id::LocalDefId,
|
||||||
::rustc_hir::HirId,
|
::rustc_hir::HirId,
|
||||||
::rustc_hir::MatchSource,
|
::rustc_hir::MatchSource,
|
||||||
::rustc_hir::Mutability,
|
|
||||||
::rustc_hir::Unsafety,
|
|
||||||
::rustc_target::asm::InlineAsmRegOrRegClass,
|
::rustc_target::asm::InlineAsmRegOrRegClass,
|
||||||
::rustc_target::spec::abi::Abi,
|
|
||||||
crate::mir::coverage::CounterId,
|
crate::mir::coverage::CounterId,
|
||||||
crate::mir::coverage::ExpressionId,
|
crate::mir::coverage::ExpressionId,
|
||||||
crate::mir::coverage::MappedExpressionIndex,
|
crate::mir::coverage::MappedExpressionIndex,
|
||||||
@ -492,16 +493,12 @@ TrivialTypeTraversalAndLiftImpls! {
|
|||||||
crate::ty::AssocItem,
|
crate::ty::AssocItem,
|
||||||
crate::ty::AssocKind,
|
crate::ty::AssocKind,
|
||||||
crate::ty::AliasKind,
|
crate::ty::AliasKind,
|
||||||
crate::ty::AliasRelationDirection,
|
|
||||||
crate::ty::Placeholder<crate::ty::BoundRegion>,
|
crate::ty::Placeholder<crate::ty::BoundRegion>,
|
||||||
crate::ty::Placeholder<crate::ty::BoundTy>,
|
crate::ty::Placeholder<crate::ty::BoundTy>,
|
||||||
crate::ty::Placeholder<ty::BoundVar>,
|
crate::ty::Placeholder<ty::BoundVar>,
|
||||||
crate::ty::ClosureKind,
|
|
||||||
crate::ty::FreeRegion,
|
crate::ty::FreeRegion,
|
||||||
crate::ty::InferTy,
|
crate::ty::InferTy,
|
||||||
crate::ty::IntVarValue,
|
crate::ty::IntVarValue,
|
||||||
crate::ty::ParamConst,
|
|
||||||
crate::ty::ParamTy,
|
|
||||||
crate::ty::adjustment::PointerCoercion,
|
crate::ty::adjustment::PointerCoercion,
|
||||||
crate::ty::RegionVid,
|
crate::ty::RegionVid,
|
||||||
crate::ty::UniverseIndex,
|
crate::ty::UniverseIndex,
|
||||||
@ -509,33 +506,30 @@ TrivialTypeTraversalAndLiftImpls! {
|
|||||||
::rustc_span::Span,
|
::rustc_span::Span,
|
||||||
::rustc_span::symbol::Ident,
|
::rustc_span::symbol::Ident,
|
||||||
::rustc_errors::ErrorGuaranteed,
|
::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::Scalar,
|
||||||
interpret::AllocId,
|
interpret::AllocId,
|
||||||
rustc_target::abi::Size,
|
rustc_target::abi::Size,
|
||||||
ty::BoundVar,
|
|
||||||
}
|
|
||||||
|
|
||||||
TrivialTypeTraversalAndLiftImpls! {
|
|
||||||
ty::ValTree<'tcx>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Lift implementations
|
// 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> {
|
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
|
||||||
type Lifted = Option<T::Lifted>;
|
type Lifted = Option<T::Lifted>;
|
||||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::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> {
|
impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
|
||||||
type Lifted = ty::Term<'tcx>;
|
type Lifted = ty::Term<'tcx>;
|
||||||
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
|
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.
|
// Traversal implementations.
|
||||||
|
@ -351,7 +351,7 @@ impl<'tcx> ClosureArgs<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to `ClosureArgs`; see the above documentation for more.
|
/// 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 struct GeneratorArgs<'tcx> {
|
||||||
pub args: GenericArgsRef<'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 struct GenSig<'tcx> {
|
||||||
pub resume_ty: Ty<'tcx>,
|
pub resume_ty: Ty<'tcx>,
|
||||||
pub yield_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,
|
/// reading places that are mentioned in a closure (because of _ patterns). However,
|
||||||
/// to ensure the places are initialized, we introduce fake reads.
|
/// to ensure the places are initialized, we introduce fake reads.
|
||||||
/// Consider these two examples:
|
/// Consider these two examples:
|
||||||
/// ``` (discriminant matching with only wildcard arm)
|
/// ```ignore (discriminant matching with only wildcard arm)
|
||||||
/// let x: u8;
|
/// let x: u8;
|
||||||
/// let c = || match x { _ => () };
|
/// 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
|
/// 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"
|
/// to be initialized at the point where c is created. Therefore, we add a "fake read"
|
||||||
/// instead.
|
/// instead.
|
||||||
/// ``` (destructured assignments)
|
/// ```ignore (destructured assignments)
|
||||||
/// let c = || {
|
/// let c = || {
|
||||||
/// let (t1, t2) = t;
|
/// let (t1, t2) = t;
|
||||||
/// }
|
/// }
|
||||||
@ -654,7 +654,7 @@ rustc_index::newtype_index! {
|
|||||||
pub type CanonicalUserTypeAnnotations<'tcx> =
|
pub type CanonicalUserTypeAnnotations<'tcx> =
|
||||||
IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'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 struct CanonicalUserTypeAnnotation<'tcx> {
|
||||||
pub user_ty: Box<CanonicalUserType<'tcx>>,
|
pub user_ty: Box<CanonicalUserType<'tcx>>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
@ -714,7 +714,7 @@ impl<'tcx> CanonicalUserType<'tcx> {
|
|||||||
/// from constants that are named via paths, like `Foo::<A>::new` and
|
/// from constants that are named via paths, like `Foo::<A>::new` and
|
||||||
/// so forth.
|
/// so forth.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
|
||||||
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
|
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub enum UserType<'tcx> {
|
pub enum UserType<'tcx> {
|
||||||
Ty(Ty<'tcx>),
|
Ty(Ty<'tcx>),
|
||||||
|
|
||||||
|
@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
pattern
|
pattern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ErrorHandled::TooGeneric) => {
|
Err(ErrorHandled::TooGeneric(_)) => {
|
||||||
// While `Reported | Linted` cases will have diagnostics emitted already
|
// While `Reported | Linted` cases will have diagnostics emitted already
|
||||||
// it is not true for TooGeneric case, so we need to give user more information.
|
// it is not true for TooGeneric case, so we need to give user more information.
|
||||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||||
@ -640,14 +640,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
.kind
|
.kind
|
||||||
} else {
|
} else {
|
||||||
// If that fails, convert it to an opaque constant pattern.
|
// 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,
|
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`.
|
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
|
||||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||||
PatKind::Wild
|
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);
|
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
|
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
|
||||||
// constants, instead of just checking for const-folding succeeding.
|
// constants, instead of just checking for const-folding succeeding.
|
||||||
// That would require a uniform one-def no-mutation analysis
|
// That would require a uniform one-def no-mutation analysis
|
||||||
// and RPO (or recursing when needing the value of a local).
|
// and RPO (or recursing when needing the value of a local).
|
||||||
let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
|
let mut linter = ConstPropagator::new(body, tcx);
|
||||||
optimization_finder.visit_body(body);
|
linter.visit_body(body);
|
||||||
|
|
||||||
trace!("ConstProp done for {:?}", def_id);
|
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> {
|
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
fn new(
|
fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
|
||||||
body: &Body<'tcx>,
|
|
||||||
dummy_body: &'mir Body<'tcx>,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
) -> ConstPropagator<'mir, 'tcx> {
|
|
||||||
let def_id = body.source.def_id();
|
let def_id = body.source.def_id();
|
||||||
let args = &GenericArgs::identity_for_item(tcx, def_id);
|
let args = &GenericArgs::identity_for_item(tcx, def_id);
|
||||||
let param_env = tcx.param_env_reveal_all_normalized(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(
|
ecx.push_stack_frame(
|
||||||
Instance::new(def_id, args),
|
Instance::new(def_id, args),
|
||||||
dummy_body,
|
body,
|
||||||
&ret,
|
&ret,
|
||||||
StackPopCleanup::Root { cleanup: false },
|
StackPopCleanup::Root { cleanup: false },
|
||||||
)
|
)
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
//! points, which can be enabled via environment variable:
|
//! points, which can be enabled via environment variable:
|
||||||
//!
|
//!
|
||||||
//! ```shell
|
//! ```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
|
//! Other module paths with coverage-related debug logs may also be of interest, particularly for
|
||||||
@ -52,7 +52,7 @@
|
|||||||
//! code generation pass). For example:
|
//! code generation pass). For example:
|
||||||
//!
|
//!
|
||||||
//! ```shell
|
//! ```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
|
//! Coverage Debug Options
|
||||||
@ -108,24 +108,23 @@
|
|||||||
//! recursively, generating labels with nested operations, enclosed in parentheses
|
//! recursively, generating labels with nested operations, enclosed in parentheses
|
||||||
//! (for example: `bcb2 + (bcb0 - bcb1)`).
|
//! (for example: `bcb2 + (bcb0 - bcb1)`).
|
||||||
|
|
||||||
use super::counters::{BcbCounter, CoverageCounters};
|
use std::iter;
|
||||||
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
|
use std::ops::Deref;
|
||||||
use super::spans::CoverageSpan;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use itertools::Itertools;
|
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::create_dump_file;
|
||||||
use rustc_middle::mir::generic_graphviz::GraphvizWriter;
|
use rustc_middle::mir::generic_graphviz::GraphvizWriter;
|
||||||
use rustc_middle::mir::spanview::{self, SpanViewable};
|
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::mir::{self, BasicBlock};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use std::iter;
|
use super::counters::{BcbCounter, CoverageCounters};
|
||||||
use std::ops::Deref;
|
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
|
||||||
use std::sync::OnceLock;
|
use super::spans::CoverageSpan;
|
||||||
|
|
||||||
pub const NESTED_INDENT: &str = " ";
|
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
|
/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
|
||||||
/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
|
/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
|
||||||
pub(super) struct DebugCounters {
|
pub(super) struct DebugCounters {
|
||||||
some_counters: Option<FxHashMap<Operand, DebugCounter>>,
|
state: Option<DebugCountersState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct DebugCountersState {
|
||||||
|
counters: FxHashMap<Operand, DebugCounter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugCounters {
|
impl DebugCounters {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { some_counters: None }
|
Self { state: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
debug_assert!(!self.is_enabled());
|
debug_assert!(!self.is_enabled());
|
||||||
self.some_counters.replace(FxHashMap::default());
|
self.state = Some(DebugCountersState::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_enabled(&self) -> bool {
|
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>) {
|
pub fn add_counter(&mut self, counter_kind: &BcbCounter, some_block_label: Option<String>) {
|
||||||
if let Some(counters) = &mut self.some_counters {
|
let Some(state) = &mut self.state else { return };
|
||||||
let id = counter_kind.as_operand();
|
|
||||||
counters
|
let id = counter_kind.as_operand();
|
||||||
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
|
state
|
||||||
.expect("attempt to add the same counter_kind to DebugCounters more than once");
|
.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> {
|
pub fn some_block_label(&self, operand: Operand) -> Option<&String> {
|
||||||
self.some_counters.as_ref().and_then(|counters| {
|
let Some(state) = &self.state else { return None };
|
||||||
counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
|
|
||||||
})
|
state.counters.get(&operand)?.some_block_label.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_counter(&self, counter_kind: &BcbCounter) -> String {
|
pub fn format_counter(&self, counter_kind: &BcbCounter) -> String {
|
||||||
@ -308,7 +313,7 @@ impl DebugCounters {
|
|||||||
if counter_format.operation {
|
if counter_format.operation {
|
||||||
return format!(
|
return format!(
|
||||||
"{}{} {} {}",
|
"{}{} {} {}",
|
||||||
if counter_format.id || self.some_counters.is_none() {
|
if counter_format.id || !self.is_enabled() {
|
||||||
format!("#{} = ", id.index())
|
format!("#{} = ", id.index())
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
@ -324,10 +329,9 @@ impl DebugCounters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let id = counter_kind.as_operand();
|
let id = counter_kind.as_operand();
|
||||||
if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
|
if let Some(state) = &self.state && (counter_format.block || !counter_format.id) {
|
||||||
let counters = self.some_counters.as_ref().unwrap();
|
|
||||||
if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
|
if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
|
||||||
counters.get(&id)
|
state.counters.get(&id)
|
||||||
{
|
{
|
||||||
return if counter_format.id {
|
return if counter_format.id {
|
||||||
format!("{}#{:?}", block_label, id)
|
format!("{}#{:?}", block_label, id)
|
||||||
@ -343,8 +347,10 @@ impl DebugCounters {
|
|||||||
if matches!(operand, Operand::Zero) {
|
if matches!(operand, Operand::Zero) {
|
||||||
return String::from("0");
|
return String::from("0");
|
||||||
}
|
}
|
||||||
if let Some(counters) = &self.some_counters {
|
if let Some(state) = &self.state {
|
||||||
if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) {
|
if let Some(DebugCounter { counter_kind, some_block_label }) =
|
||||||
|
state.counters.get(&operand)
|
||||||
|
{
|
||||||
if let BcbCounter::Expression { .. } = counter_kind {
|
if let BcbCounter::Expression { .. } = counter_kind {
|
||||||
if let Some(label) = some_block_label && debug_options().counter_format.block {
|
if let Some(label) = some_block_label && debug_options().counter_format.block {
|
||||||
return format!(
|
return format!(
|
||||||
@ -378,30 +384,29 @@ impl DebugCounter {
|
|||||||
/// If enabled, this data structure captures additional debugging information used when generating
|
/// If enabled, this data structure captures additional debugging information used when generating
|
||||||
/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
|
/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
|
||||||
pub(super) struct GraphvizData {
|
pub(super) struct GraphvizData {
|
||||||
some_bcb_to_coverage_spans_with_counters:
|
state: Option<GraphvizDataState>,
|
||||||
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>>,
|
#[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 {
|
impl GraphvizData {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self { state: None }
|
||||||
some_bcb_to_coverage_spans_with_counters: None,
|
|
||||||
some_bcb_to_dependency_counters: None,
|
|
||||||
some_edge_to_counter: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
debug_assert!(!self.is_enabled());
|
debug_assert!(!self.is_enabled());
|
||||||
self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default());
|
self.state = Some(GraphvizDataState::default());
|
||||||
self.some_bcb_to_dependency_counters = Some(FxHashMap::default());
|
|
||||||
self.some_edge_to_counter = Some(FxHashMap::default());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_enabled(&self) -> bool {
|
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(
|
pub fn add_bcb_coverage_span_with_counter(
|
||||||
@ -410,27 +415,22 @@ impl GraphvizData {
|
|||||||
coverage_span: &CoverageSpan,
|
coverage_span: &CoverageSpan,
|
||||||
counter_kind: &BcbCounter,
|
counter_kind: &BcbCounter,
|
||||||
) {
|
) {
|
||||||
if let Some(bcb_to_coverage_spans_with_counters) =
|
let Some(state) = &mut self.state else { return };
|
||||||
self.some_bcb_to_coverage_spans_with_counters.as_mut()
|
|
||||||
{
|
state
|
||||||
bcb_to_coverage_spans_with_counters
|
.bcb_to_coverage_spans_with_counters
|
||||||
.entry(bcb)
|
.entry(bcb)
|
||||||
.or_insert_with(Vec::new)
|
.or_insert_with(Vec::new)
|
||||||
.push((coverage_span.clone(), counter_kind.clone()));
|
.push((coverage_span.clone(), counter_kind.clone()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bcb_coverage_spans_with_counters(
|
pub fn get_bcb_coverage_spans_with_counters(
|
||||||
&self,
|
&self,
|
||||||
bcb: BasicCoverageBlock,
|
bcb: BasicCoverageBlock,
|
||||||
) -> Option<&[(CoverageSpan, BcbCounter)]> {
|
) -> Option<&[(CoverageSpan, BcbCounter)]> {
|
||||||
if let Some(bcb_to_coverage_spans_with_counters) =
|
let Some(state) = &self.state else { return None };
|
||||||
self.some_bcb_to_coverage_spans_with_counters.as_ref()
|
|
||||||
{
|
state.bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
|
||||||
bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_bcb_dependency_counter(
|
pub fn add_bcb_dependency_counter(
|
||||||
@ -438,20 +438,19 @@ impl GraphvizData {
|
|||||||
bcb: BasicCoverageBlock,
|
bcb: BasicCoverageBlock,
|
||||||
counter_kind: &BcbCounter,
|
counter_kind: &BcbCounter,
|
||||||
) {
|
) {
|
||||||
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
|
let Some(state) = &mut self.state else { return };
|
||||||
bcb_to_dependency_counters
|
|
||||||
.entry(bcb)
|
state
|
||||||
.or_insert_with(Vec::new)
|
.bcb_to_dependency_counters
|
||||||
.push(counter_kind.clone());
|
.entry(bcb)
|
||||||
}
|
.or_insert_with(Vec::new)
|
||||||
|
.push(counter_kind.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[BcbCounter]> {
|
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() {
|
let Some(state) = &self.state else { return None };
|
||||||
bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
|
|
||||||
} else {
|
state.bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_edge_counter(
|
pub fn set_edge_counter(
|
||||||
@ -460,11 +459,12 @@ impl GraphvizData {
|
|||||||
to_bb: BasicBlock,
|
to_bb: BasicBlock,
|
||||||
counter_kind: &BcbCounter,
|
counter_kind: &BcbCounter,
|
||||||
) {
|
) {
|
||||||
if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
|
let Some(state) = &mut self.state else { return };
|
||||||
edge_to_counter
|
|
||||||
.try_insert((from_bcb, to_bb), counter_kind.clone())
|
state
|
||||||
.expect("invalid attempt to insert more than one edge counter for the same edge");
|
.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(
|
pub fn get_edge_counter(
|
||||||
@ -472,11 +472,9 @@ impl GraphvizData {
|
|||||||
from_bcb: BasicCoverageBlock,
|
from_bcb: BasicCoverageBlock,
|
||||||
to_bb: BasicBlock,
|
to_bb: BasicBlock,
|
||||||
) -> Option<&BcbCounter> {
|
) -> Option<&BcbCounter> {
|
||||||
if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() {
|
let Some(state) = &self.state else { return None };
|
||||||
edge_to_counter.get(&(from_bcb, to_bb))
|
|
||||||
} else {
|
state.edge_to_counter.get(&(from_bcb, to_bb))
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,41 +483,42 @@ impl GraphvizData {
|
|||||||
/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
|
/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
|
||||||
/// and/or a `CoverageGraph` graphviz output).
|
/// and/or a `CoverageGraph` graphviz output).
|
||||||
pub(super) struct UsedExpressions {
|
pub(super) struct UsedExpressions {
|
||||||
some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
|
state: Option<UsedExpressionsState>,
|
||||||
some_unused_expressions:
|
}
|
||||||
Option<Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct UsedExpressionsState {
|
||||||
|
used_expression_operands: FxHashSet<Operand>,
|
||||||
|
unused_expressions: Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsedExpressions {
|
impl UsedExpressions {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { some_used_expression_operands: None, some_unused_expressions: None }
|
Self { state: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable(&mut self) {
|
pub fn enable(&mut self) {
|
||||||
debug_assert!(!self.is_enabled());
|
debug_assert!(!self.is_enabled());
|
||||||
self.some_used_expression_operands = Some(FxHashMap::default());
|
self.state = Some(UsedExpressionsState::default())
|
||||||
self.some_unused_expressions = Some(Vec::new());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_enabled(&self) -> bool {
|
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) {
|
pub fn add_expression_operands(&mut self, expression: &BcbCounter) {
|
||||||
if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
|
let Some(state) = &mut self.state else { return };
|
||||||
if let BcbCounter::Expression { id, lhs, rhs, .. } = *expression {
|
|
||||||
used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
|
if let BcbCounter::Expression { lhs, rhs, .. } = *expression {
|
||||||
used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
|
state.used_expression_operands.insert(lhs);
|
||||||
}
|
state.used_expression_operands.insert(rhs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expression_is_used(&self, expression: &BcbCounter) -> bool {
|
pub fn expression_is_used(&self, expression: &BcbCounter) -> bool {
|
||||||
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
|
let Some(state) = &self.state else { return false };
|
||||||
used_expression_operands.contains_key(&expression.as_operand())
|
|
||||||
} else {
|
state.used_expression_operands.contains(&expression.as_operand())
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_unused_expression_if_not_found(
|
pub fn add_unused_expression_if_not_found(
|
||||||
@ -528,14 +527,10 @@ impl UsedExpressions {
|
|||||||
edge_from_bcb: Option<BasicCoverageBlock>,
|
edge_from_bcb: Option<BasicCoverageBlock>,
|
||||||
target_bcb: BasicCoverageBlock,
|
target_bcb: BasicCoverageBlock,
|
||||||
) {
|
) {
|
||||||
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
|
let Some(state) = &mut self.state else { return };
|
||||||
if !used_expression_operands.contains_key(&expression.as_operand()) {
|
|
||||||
self.some_unused_expressions.as_mut().unwrap().push((
|
if !state.used_expression_operands.contains(&expression.as_operand()) {
|
||||||
expression.clone(),
|
state.unused_expressions.push((expression.clone(), edge_from_bcb, target_bcb));
|
||||||
edge_from_bcb,
|
|
||||||
target_bcb,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,11 +539,9 @@ impl UsedExpressions {
|
|||||||
pub fn get_unused_expressions(
|
pub fn get_unused_expressions(
|
||||||
&self,
|
&self,
|
||||||
) -> Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
|
) -> Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
|
||||||
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
|
let Some(state) = &self.state else { return Vec::new() };
|
||||||
unused_expressions.clone()
|
|
||||||
} else {
|
state.unused_expressions.clone()
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If enabled, validate that every BCB or edge counter not directly associated with a coverage
|
/// If enabled, validate that every BCB or edge counter not directly associated with a coverage
|
||||||
@ -562,51 +555,53 @@ impl UsedExpressions {
|
|||||||
BcbCounter,
|
BcbCounter,
|
||||||
)],
|
)],
|
||||||
) {
|
) {
|
||||||
if self.is_enabled() {
|
if !self.is_enabled() {
|
||||||
let mut not_validated = bcb_counters_without_direct_coverage_spans
|
return;
|
||||||
.iter()
|
}
|
||||||
.map(|(_, _, counter_kind)| counter_kind)
|
|
||||||
.collect::<Vec<_>>();
|
let mut not_validated = bcb_counters_without_direct_coverage_spans
|
||||||
let mut validating_count = 0;
|
.iter()
|
||||||
while not_validated.len() != validating_count {
|
.map(|(_, _, counter_kind)| counter_kind)
|
||||||
let to_validate = not_validated.split_off(0);
|
.collect::<Vec<_>>();
|
||||||
validating_count = to_validate.len();
|
let mut validating_count = 0;
|
||||||
for counter_kind in to_validate {
|
while not_validated.len() != validating_count {
|
||||||
if self.expression_is_used(counter_kind) {
|
let to_validate = not_validated.split_off(0);
|
||||||
self.add_expression_operands(counter_kind);
|
validating_count = to_validate.len();
|
||||||
} else {
|
for counter_kind in to_validate {
|
||||||
not_validated.push(counter_kind);
|
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) {
|
pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) {
|
||||||
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
|
let Some(state) = &self.state else { return };
|
||||||
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),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
if debug_options().allow_unused_expressions {
|
for (counter_kind, edge_from_bcb, target_bcb) in &state.unused_expressions {
|
||||||
debug!("WARNING: {}", unused_counter_message);
|
let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
|
||||||
} else {
|
format!(
|
||||||
bug!("{}", unused_counter_message);
|
"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)]
|
#[inline(always)]
|
||||||
pub fn rank_partial_cmp(
|
pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering {
|
||||||
&self,
|
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
|
||||||
a: BasicCoverageBlock,
|
|
||||||
b: BasicCoverageBlock,
|
|
||||||
) -> Option<Ordering> {
|
|
||||||
self.dominators.as_ref().unwrap().rank_partial_cmp(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