Merge from rustc

This commit is contained in:
The Miri Conjob Bot 2023-09-19 05:32:09 +00:00
commit 1e2813fa0f
561 changed files with 11894 additions and 7531 deletions

View File

@ -67,7 +67,7 @@ jobs:
- name: disable git crlf conversion
run: git config --global core.autocrlf false
- name: checkout the source code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: configure the PR in which the error message will be posted
@ -393,7 +393,7 @@ jobs:
- name: dist-x86_64-msvc
env:
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths
SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
DIST_REQUIRE_ALL_TOOLS: 1
os: windows-2019-8core-32gb
- name: dist-i686-msvc
@ -435,7 +435,7 @@ jobs:
- name: disable git crlf conversion
run: git config --global core.autocrlf false
- name: checkout the source code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: configure the PR in which the error message will be posted
@ -555,7 +555,7 @@ jobs:
- name: disable git crlf conversion
run: git config --global core.autocrlf false
- name: checkout the source code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: configure the PR in which the error message will be posted
@ -662,7 +662,7 @@ jobs:
if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
steps:
- name: checkout the source code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: publish toolstate

View File

@ -50,7 +50,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout the source code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
- name: install the bootstrap toolchain
@ -87,7 +87,7 @@ jobs:
pull-requests: write
steps:
- name: checkout the source code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: download Cargo.lock from update job
uses: actions/download-artifact@v3

1
.gitignore vendored
View File

@ -58,7 +58,6 @@ build/
\#*
\#*\#
.#*
rustc-ice-*.txt
## Tags
tags

View File

@ -328,7 +328,8 @@ Kyle J Strand <batmanaod@gmail.com> <BatmanAoD@users.noreply.github.com>
Kyle J Strand <batmanaod@gmail.com> <kyle.j.strand@gmail.com>
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.com>
Laurențiu Nicola <lnicola@dend.ro>
Laurențiu Nicola <lnicola@dend.ro> Laurentiu Nicola <lnicola@dend.ro>
Laurențiu Nicola <lnicola@dend.ro> <lnicola@users.noreply.github.com>
lcnr <rust@lcnr.de> <bastian_kauschke@hotmail.de>
Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
Lee Wondong <wdlee91@gmail.com>
@ -549,6 +550,8 @@ Timothy Maloney <tmaloney@pdx.edu>
Tomas Koutsky <tomas@stepnivlk.net>
Torsten Weber <TorstenWeber12@gmail.com>
Torsten Weber <TorstenWeber12@gmail.com> <torstenweber12@gmail.com>
Trevor Gross <tmgross@umich.edu> <t.gross35@gmail.com>
Trevor Gross <tmgross@umich.edu> <tgross@intrepidcs.com>
Trevor Spiteri <tspiteri@ieee.org> <trevor.spiteri@um.edu.mt>
Tshepang Mbambo <tshepang@gmail.com>
Ty Overby <ty@pre-alpha.com>

View File

@ -859,14 +859,38 @@ dependencies = [
"winapi",
]
[[package]]
name = "darling"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
dependencies = [
"darling_core 0.14.4",
"darling_macro 0.14.4",
]
[[package]]
name = "darling"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [
"darling_core",
"darling_macro",
"darling_core 0.20.3",
"darling_macro 0.20.3",
]
[[package]]
name = "darling_core"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 1.0.109",
]
[[package]]
@ -883,13 +907,24 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "darling_macro"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
dependencies = [
"darling_core 0.14.4",
"quote",
"syn 1.0.109",
]
[[package]]
name = "darling_macro"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"darling_core 0.20.3",
"quote",
"syn 2.0.29",
]
@ -920,6 +955,37 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "derive_builder"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
dependencies = [
"darling 0.14.4",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_builder_macro"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
dependencies = [
"derive_builder_core",
"syn 1.0.109",
]
[[package]]
name = "derive_more"
version = "0.99.17"
@ -939,7 +1005,7 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
dependencies = [
"darling",
"darling 0.20.3",
"proc-macro2",
"quote",
"syn 2.0.29",
@ -2594,6 +2660,8 @@ dependencies = [
"anyhow",
"build_helper",
"camino",
"clap",
"derive_builder",
"env_logger 0.10.0",
"fs_extra",
"glob",

View File

@ -99,6 +99,22 @@ impl Attribute {
}
}
pub fn path_matches(&self, name: &[Symbol]) -> bool {
match &self.kind {
AttrKind::Normal(normal) => {
normal.item.path.segments.len() == name.len()
&& normal
.item
.path
.segments
.iter()
.zip(name)
.all(|(s, n)| s.args.is_none() && s.ident.name == *n)
}
AttrKind::DocComment(..) => false,
}
}
pub fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, AttrArgs::Empty)

View File

@ -442,8 +442,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
span: Span,
counter: usize,
) -> RegionNameHighlight {
let mut highlight = RegionHighlightMode::new(self.infcx.tcx);
highlight.highlighting_region_vid(needle_fr, counter);
let mut highlight = RegionHighlightMode::default();
highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter);
let type_name =
self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
@ -804,8 +804,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
return None;
}
let mut highlight = RegionHighlightMode::new(tcx);
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
let mut highlight = RegionHighlightMode::default();
highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap());
let type_name =
self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;

View File

@ -137,6 +137,8 @@ builtin_macros_format_positional_after_named = positional arguments cannot follo
.label = positional arguments must be before named arguments
.named_args = named argument
builtin_macros_format_remove_raw_ident = remove the `r#`
builtin_macros_format_requires_string = requires at least a format string argument
builtin_macros_format_string_invalid = invalid format string: {$desc}
@ -165,6 +167,8 @@ builtin_macros_format_unused_arg = {$named ->
builtin_macros_format_unused_args = multiple unused formatting arguments
.label = multiple missing formatting specifiers
builtin_macros_format_use_positional = consider using a positional formatting argument instead
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
builtin_macros_invalid_crate_attribute = invalid crate attribute
@ -205,8 +209,6 @@ builtin_macros_requires_cfg_pattern =
builtin_macros_should_panic = functions using `#[should_panic]` must return `()`
builtin_macros_sugg = consider using a positional formatting argument instead
builtin_macros_test_arg_non_lifetime = functions used as tests can not have any non-lifetime generic parameters
builtin_macros_test_args = functions used as tests can not have any arguments

View File

@ -18,6 +18,20 @@ pub fn expand_deriving_eq(
is_const: bool,
) {
let span = cx.with_def_site_ctxt(span);
let structural_trait_def = TraitDef {
span,
path: path_std!(marker::StructuralEq),
skip_path_as_bound: true, // crucial!
needs_copy_as_bound_if_packed: false,
additional_bounds: Vec::new(),
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),
is_const: false,
};
structural_trait_def.expand(cx, mitem, item, push);
let trait_def = TraitDef {
span,
path: path_std!(cmp::Eq),
@ -44,9 +58,6 @@ pub fn expand_deriving_eq(
associated_types: Vec::new(),
is_const,
};
super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push);
trait_def.expand_ext(cx, mitem, item, push, true)
}

View File

@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq(
BlockOrExpr::new_expr(expr)
}
super::inject_impl_of_structural_trait(
cx,
let structural_trait_def = TraitDef {
span,
item,
path_std!(marker::StructuralPartialEq),
push,
);
path: path_std!(marker::StructuralPartialEq),
skip_path_as_bound: true, // crucial!
needs_copy_as_bound_if_packed: false,
additional_bounds: Vec::new(),
// We really don't support unions, but that's already checked by the impl generated below;
// a second check here would lead to redundant error messages.
supports_unions: true,
methods: Vec::new(),
associated_types: Vec::new(),
is_const: false,
};
structural_trait_def.expand(cx, mitem, item, push);
// No need to generate `ne`, the default suffices, and not generating it is
// faster.

View File

@ -88,7 +88,7 @@
//!
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
//!
//! ```{.text}
//! ```text
//! Struct(vec![FieldInfo {
//! span: <span of x>
//! name: Some(<ident of x>),
@ -99,7 +99,7 @@
//!
//! For the `B` impl, called with `B(a)` and `B(b)`,
//!
//! ```{.text}
//! ```text
//! Struct(vec![FieldInfo {
//! span: <span of `i32`>,
//! name: None,
@ -113,7 +113,7 @@
//! When generating the `expr` for a call with `self == C0(a)` and `other
//! == C0(b)`, the SubstructureFields is
//!
//! ```{.text}
//! ```text
//! EnumMatching(0, <ast::Variant for C0>,
//! vec![FieldInfo {
//! span: <span of i32>
@ -125,7 +125,7 @@
//!
//! For `C1 {x}` and `C1 {x}`,
//!
//! ```{.text}
//! ```text
//! EnumMatching(1, <ast::Variant for C1>,
//! vec![FieldInfo {
//! span: <span of x>
@ -137,7 +137,7 @@
//!
//! For the tags,
//!
//! ```{.text}
//! ```text
//! EnumTag(
//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
//! ```
@ -149,7 +149,7 @@
//!
//! A static method on the types above would result in,
//!
//! ```{.text}
//! ```text
//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
//!
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> {
.collect();
// Require the current trait.
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
if !self.skip_path_as_bound {
bounds.push(cx.trait_bound(trait_path.clone(), self.is_const));
}
// Add a `Copy` bound if required.
if is_packed && self.needs_copy_as_bound_if_packed {
@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> {
));
}
let predicate = ast::WhereBoundPredicate {
span: self.span,
bound_generic_params: field_ty_param.bound_generic_params,
bounded_ty: field_ty_param.ty,
bounds,
};
if !bounds.is_empty() {
let predicate = ast::WhereBoundPredicate {
span: self.span,
bound_generic_params: field_ty_param.bound_generic_params,
bounded_ty: field_ty_param.ty,
bounds,
};
let predicate = ast::WherePredicate::BoundPredicate(predicate);
where_clause.predicates.push(predicate);
let predicate = ast::WherePredicate::BoundPredicate(predicate);
where_clause.predicates.push(predicate);
}
}
}
}

View File

@ -2,9 +2,9 @@
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem};
use rustc_ast::{GenericArg, MetaItem};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use thin_vec::{thin_vec, ThinVec};
@ -116,100 +116,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
}))
}
// Injects `impl<...> Structural for ItemType<...> { }`. In particular,
// does *not* add `where T: Structural` for parameters `T` in `...`.
// (That's the main reason we cannot use TraitDef here.)
fn inject_impl_of_structural_trait(
cx: &mut ExtCtxt<'_>,
span: Span,
item: &Annotatable,
structural_path: generic::ty::Path,
push: &mut dyn FnMut(Annotatable),
) {
let Annotatable::Item(item) = item else {
unreachable!();
};
let generics = match &item.kind {
ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics,
// Do not inject `impl Structural for Union`. (`PartialEq` does not
// support unions, so we will see error downstream.)
ItemKind::Union(..) => return,
_ => unreachable!(),
};
// Create generics param list for where clauses and impl headers
let mut generics = generics.clone();
let ctxt = span.ctxt();
// Create the type of `self`.
//
// in addition, remove defaults from generic params (impls cannot have them).
let self_params: Vec<_> = generics
.params
.iter_mut()
.map(|param| match &mut param.kind {
ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime(
cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident),
),
ast::GenericParamKind::Type { default } => {
*default = None;
ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident))
}
ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
*default = None;
ast::GenericArg::Const(
cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident),
)
}
})
.collect();
let type_ident = item.ident;
let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics));
let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params));
// It would be nice to also encode constraint `where Self: Eq` (by adding it
// onto `generics` cloned above). Unfortunately, that strategy runs afoul of
// rust-lang/rust#48214. So we perform that additional check in the compiler
// itself, instead of encoding it here.
// Keep the lint and stability attributes of the original item, to control
// how the generated implementation is linted.
let mut attrs = ast::AttrVec::new();
attrs.extend(
item.attrs
.iter()
.filter(|a| {
[sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable]
.contains(&a.name_or_empty())
})
.cloned(),
);
// Mark as `automatically_derived` to avoid some silly lints.
attrs.push(cx.attr_word(sym::automatically_derived, span));
let newitem = cx.item(
span,
Ident::empty(),
attrs,
ItemKind::Impl(Box::new(Impl {
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
constness: ast::Const::No,
generics,
of_trait: Some(trait_ref),
self_ty: self_type,
items: ThinVec::new(),
})),
);
push(Annotatable::Item(newitem));
}
fn assert_ty_bounds(
cx: &mut ExtCtxt<'_>,
stmts: &mut ThinVec<ast::Stmt>,

View File

@ -539,18 +539,29 @@ pub(crate) struct InvalidFormatStringLabel {
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
builtin_macros_sugg,
style = "verbose",
applicability = "machine-applicable"
)]
pub(crate) struct InvalidFormatStringSuggestion {
#[suggestion_part(code = "{len}")]
pub(crate) captured: Span,
pub(crate) len: String,
#[suggestion_part(code = ", {arg}")]
pub(crate) span: Span,
pub(crate) arg: String,
pub(crate) enum InvalidFormatStringSuggestion {
#[multipart_suggestion(
builtin_macros_format_use_positional,
style = "verbose",
applicability = "machine-applicable"
)]
UsePositional {
#[suggestion_part(code = "{len}")]
captured: Span,
len: String,
#[suggestion_part(code = ", {arg}")]
span: Span,
arg: String,
},
#[suggestion(
builtin_macros_format_remove_raw_ident,
code = "",
applicability = "machine-applicable"
)]
RemoveRawIdent {
#[primary_span]
span: Span,
},
}
#[derive(Diagnostic)]

View File

@ -260,20 +260,29 @@ fn make_format_args(
if let Some((label, span)) = err.secondary_label && is_source_literal {
e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } );
}
if err.should_be_replaced_with_positional_argument {
let captured_arg_span =
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
let span = match args.unnamed_args().last() {
Some(arg) => arg.expr.span,
None => fmt_span,
};
e.sugg_ = Some(errors::InvalidFormatStringSuggestion {
captured: captured_arg_span,
len: args.unnamed_args().len().to_string(),
span: span.shrink_to_hi(),
arg,
});
match err.suggestion {
parse::Suggestion::None => {}
parse::Suggestion::UsePositional => {
let captured_arg_span =
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
let span = match args.unnamed_args().last() {
Some(arg) => arg.expr.span,
None => fmt_span,
};
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UsePositional {
captured: captured_arg_span,
len: args.unnamed_args().len().to_string(),
span: span.shrink_to_hi(),
arg,
});
}
}
parse::Suggestion::RemoveRawIdent(span) => {
if is_source_literal {
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span })
}
}
}
ecx.emit_err(e);

View File

@ -100,11 +100,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
}
_ => unreachable!("{:?}", self.layout.abi),
},
PassMode::Cast(ref cast, pad_i32) => {
PassMode::Cast { ref cast, pad_i32 } => {
assert!(!pad_i32, "padding support not yet implemented");
cast_target_to_abi_params(cast)
}
PassMode::Indirect { attrs, extra_attrs: None, on_stack } => {
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
if on_stack {
// Abi requires aligning struct size to pointer size
let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
@ -117,11 +117,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
}
}
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => {
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
assert!(!on_stack);
smallvec![
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs),
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
]
}
}
@ -148,14 +148,14 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
}
_ => unreachable!("{:?}", self.layout.abi),
},
PassMode::Cast(ref cast, _) => {
PassMode::Cast { ref cast, .. } => {
(None, cast_target_to_abi_params(cast).into_iter().collect())
}
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => {
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => {
assert!(!on_stack);
(Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value")
}
}
@ -229,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
let (a, b) = arg.load_scalar_pair(fx);
smallvec![a, b]
}
PassMode::Cast(ref cast, _) => to_casted_value(fx, arg, cast),
PassMode::Cast { ref cast, .. } => to_casted_value(fx, arg, cast),
PassMode::Indirect { .. } => {
if is_owned {
match arg.force_stack(fx) {
@ -287,14 +287,14 @@ pub(super) fn cvalue_for_param<'tcx>(
assert_eq!(block_params.len(), 2, "{:?}", block_params);
Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout))
}
PassMode::Cast(ref cast, _) => {
PassMode::Cast { ref cast, .. } => {
Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
}
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
assert_eq!(block_params.len(), 1, "{:?}", block_params);
Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout))
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
assert_eq!(block_params.len(), 2, "{:?}", block_params);
Some(CValue::by_ref_unsized(
Pointer::new(block_params[0]),

View File

@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>(
block_params_iter: &mut impl Iterator<Item = Value>,
) -> CPlace<'tcx> {
let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => {
PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => {
let is_ssa =
ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty);
(
@ -26,7 +26,7 @@ pub(super) fn codegen_return_param<'tcx>(
smallvec![],
)
}
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
let ret_param = block_params_iter.next().unwrap();
assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
(
@ -34,7 +34,7 @@ pub(super) fn codegen_return_param<'tcx>(
smallvec![ret_param],
)
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value")
}
};
@ -62,7 +62,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
) {
let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
PassMode::Ignore => (None, None),
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
if let Some(ret_ptr) = ret_place.try_to_ptr() {
// This is an optimization to prevent unnecessary copies of the return value when
// the return place is already a memory place as opposed to a register.
@ -73,10 +73,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
(Some(place), Some(place.to_ptr().get_addr(fx)))
}
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value")
}
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => (None, None),
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None),
};
let call_inst = f(fx, return_ptr);
@ -93,21 +93,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
ret_place
.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout));
}
PassMode::Cast(ref cast, _) => {
PassMode::Cast { ref cast, .. } => {
let results =
fx.bcx.inst_results(call_inst).iter().copied().collect::<SmallVec<[Value; 2]>>();
let result =
super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
ret_place.write_cvalue(fx, result);
}
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
if let Some(ret_temp_place) = ret_temp_place {
// If ret_temp_place is None, it is not necessary to copy the return value.
let ret_temp_value = ret_temp_place.to_cvalue(fx);
ret_place.write_cvalue(fx, ret_temp_value);
}
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value")
}
}
@ -116,10 +116,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
/// Codegen a return instruction with the right return value(s) if any.
pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
match fx.fn_abi.as_ref().unwrap().ret.mode {
PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
fx.bcx.ins().return_(&[]);
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value")
}
PassMode::Direct(_) => {
@ -132,7 +132,7 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) {
let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
}
PassMode::Cast(ref cast, _) => {
PassMode::Cast { ref cast, .. } => {
let place = fx.get_local_place(RETURN_PLACE);
let ret_val = place.to_cvalue(fx);
let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);

View File

@ -250,7 +250,10 @@ pub(crate) fn verify_func(
}
fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
if !crate::constant::check_constants(fx) {
if let Err(err) =
fx.mir.post_mono_checks(fx.tcx, ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
{
err.emit_err(fx.tcx);
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
// compilation should have been aborted

View File

@ -2,9 +2,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{
read_target_uint, AllocId, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
use rustc_middle::mir::interpret::{read_target_uint, AllocId, ConstValue, GlobalAlloc, Scalar};
use cranelift_module::*;
@ -33,16 +31,6 @@ impl ConstantCx {
}
}
pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
let mut all_constants_ok = true;
for constant in &fx.mir.required_consts {
if eval_mir_constant(fx, constant).is_none() {
all_constants_ok = false;
}
}
all_constants_ok
}
pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
let mut constants_cx = ConstantCx::new();
constants_cx.todo.push(TodoItem::Static(def_id));
@ -76,30 +64,20 @@ pub(crate) fn codegen_tls_ref<'tcx>(
pub(crate) fn eval_mir_constant<'tcx>(
fx: &FunctionCx<'_, '_, 'tcx>,
constant: &Constant<'tcx>,
) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> {
) -> (ConstValue<'tcx>, Ty<'tcx>) {
let cv = fx.monomorphize(constant.literal);
// This cannot fail because we checked all required_consts in advance.
let val = cv
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
.map_err(|err| match err {
ErrorHandled::Reported(_) => {
fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
}
ErrorHandled::TooGeneric => {
span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err);
}
})
.ok();
val.map(|val| (val, cv.ty()))
.expect("erroneous constant not captured by required_consts");
(val, cv.ty())
}
pub(crate) fn codegen_constant_operand<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
constant: &Constant<'tcx>,
) -> CValue<'tcx> {
let (const_val, ty) = eval_mir_constant(fx, constant).unwrap_or_else(|| {
span_bug!(constant.span, "erroneous constant not captured by required_consts")
});
let (const_val, ty) = eval_mir_constant(fx, constant);
codegen_const_value(fx, const_val, ty)
}
@ -459,7 +437,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
operand: &Operand<'tcx>,
) -> Option<ConstValue<'tcx>> {
match operand {
Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).unwrap().0),
Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).0),
// FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
// inside a temporary before being passed to the intrinsic requiring the const argument.
// This code tries to find a single constant defining definition of the referenced local.

View File

@ -242,8 +242,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
}
}
InlineAsmOperand::Const { ref value } => {
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value)
.unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved"));
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value);
let value = rustc_codegen_ssa::common::asm_const_to_str(
fx.tcx,
span,

View File

@ -113,7 +113,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
match self.ret.mode {
PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
PassMode::Cast(ref cast, _) => cast.gcc_type(cx),
PassMode::Cast { ref cast, .. } => cast.gcc_type(cx),
PassMode::Indirect { .. } => {
argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
cx.type_void()
@ -129,21 +129,21 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1));
continue;
}
PassMode::Indirect { extra_attrs: Some(_), .. } => {
PassMode::Indirect { meta_attrs: Some(_), .. } => {
unimplemented!();
}
PassMode::Cast(ref cast, pad_i32) => {
PassMode::Cast { ref cast, pad_i32 } => {
// add padding
if pad_i32 {
argument_tys.push(Reg::i32().gcc_type(cx));
}
cast.gcc_type(cx)
}
PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => {
PassMode::Indirect { meta_attrs: None, on_stack: true, .. } => {
on_stack_param_indices.insert(argument_tys.len());
arg.memory_ty(cx)
},
PassMode::Indirect { extra_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
PassMode::Indirect { meta_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
};
argument_tys.push(arg_ty);
}

View File

@ -144,7 +144,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = fn_args.type_at(0);
let mut ptr = args[0].immediate();
if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
}
let load = self.volatile_load(ptr.get_type(), ptr);
@ -353,7 +353,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
};
if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode {
let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
let ptr = self.pointercast(result.llval, ptr_llty);
self.store(llval, ptr, result.align);
@ -449,7 +449,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
}
else if let PassMode::Cast(ref cast, _) = self.mode {
else if let PassMode::Cast { ref cast, .. } = self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let can_store_through_cast_ptr = false;
@ -511,10 +511,10 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
PassMode::Pair(..) => {
OperandValue::Pair(next(), next()).store(bx, dst);
},
PassMode::Indirect { extra_attrs: Some(_), .. } => {
PassMode::Indirect { meta_attrs: Some(_), .. } => {
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
},
PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => {
PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } | PassMode::Cast { .. } => {
let next_arg = next();
self.store(bx, next_arg, dst);
},

View File

@ -211,7 +211,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
} else if self.is_unsized_indirect() {
bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
} else if let PassMode::Cast(cast, _) = &self.mode {
} else if let PassMode::Cast { cast, pad_i32: _ } = &self.mode {
// FIXME(eddyb): Figure out when the simpler Store is safe, clang
// uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
let can_store_through_cast_ptr = false;
@ -274,12 +274,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
PassMode::Pair(..) => {
OperandValue::Pair(next(), next()).store(bx, dst);
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
}
PassMode::Direct(_)
| PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }
| PassMode::Cast(..) => {
| PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }
| PassMode::Cast { .. } => {
let next_arg = next();
self.store(bx, next_arg, dst);
}
@ -332,7 +332,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
let llreturn_ty = match &self.ret.mode {
PassMode::Ignore => cx.type_void(),
PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx),
PassMode::Cast(cast, _) => cast.llvm_type(cx),
PassMode::Cast { cast, pad_i32: _ } => cast.llvm_type(cx),
PassMode::Indirect { .. } => {
llargument_tys.push(cx.type_ptr());
cx.type_void()
@ -351,6 +351,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
// guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for
// aggregates...
if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) {
assert!(
arg.layout.is_sized(),
"`PassMode::Direct` for unsized type: {}",
arg.layout.ty
);
// This really shouldn't happen, since `immediate_llvm_type` will use
// `layout.fields` to turn this Rust type into an LLVM type. This means all
// sorts of Rust type details leak into the ABI. However wasm sadly *does*
@ -378,8 +383,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
continue;
}
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
assert!(arg.layout.is_unsized());
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack } => {
// `Indirect` with metadata is only for unsized types, and doesn't work with
// on-stack passing.
assert!(arg.layout.is_unsized() && !on_stack);
// Construct the type of a (wide) pointer to `ty`, and pass its two fields.
// Any two ABI-compatible unsized types have the same metadata type and
// moreover the same metadata value leads to the same dynamic size and
@ -390,7 +397,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true));
continue;
}
PassMode::Cast(cast, pad_i32) => {
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
assert!(arg.layout.is_sized());
cx.type_ptr()
}
PassMode::Cast { cast, pad_i32 } => {
// `Cast` means "transmute to `CastType`"; that only makes sense for sized types.
assert!(arg.layout.is_sized());
// add padding
if *pad_i32 {
llargument_tys.push(Reg::i32().llvm_type(cx));
@ -399,7 +412,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
// We assume here that ABI-compatible Rust types have the same cast type.
cast.llvm_type(cx)
}
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(),
};
llargument_tys.push(llarg_ty);
}
@ -442,13 +454,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Direct(attrs) => {
attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
}
PassMode::Indirect { attrs, extra_attrs: _, on_stack } => {
PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
assert!(!on_stack);
let i = apply(attrs);
let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx));
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]);
}
PassMode::Cast(cast, _) => {
PassMode::Cast { cast, pad_i32: _ } => {
cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn);
}
_ => {}
@ -456,25 +468,25 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
for arg in self.args.iter() {
match &arg.mode {
PassMode::Ignore => {}
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
let i = apply(attrs);
let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx));
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]);
}
PassMode::Direct(attrs)
| PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => {
| PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
apply(attrs);
}
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => {
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
assert!(!on_stack);
apply(attrs);
apply(extra_attrs);
apply(meta_attrs);
}
PassMode::Pair(a, b) => {
apply(a);
apply(b);
}
PassMode::Cast(cast, pad_i32) => {
PassMode::Cast { cast, pad_i32 } => {
if *pad_i32 {
apply(&ArgAttributes::new());
}
@ -504,13 +516,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Direct(attrs) => {
attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite);
}
PassMode::Indirect { attrs, extra_attrs: _, on_stack } => {
PassMode::Indirect { attrs, meta_attrs: _, on_stack } => {
assert!(!on_stack);
let i = apply(bx.cx, attrs);
let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx));
attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]);
}
PassMode::Cast(cast, _) => {
PassMode::Cast { cast, pad_i32: _ } => {
cast.attrs.apply_attrs_to_callsite(
llvm::AttributePlace::ReturnValue,
&bx.cx,
@ -532,7 +544,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
for arg in self.args.iter() {
match &arg.mode {
PassMode::Ignore => {}
PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => {
PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => {
let i = apply(bx.cx, attrs);
let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx));
attributes::apply_to_callsite(
@ -542,18 +554,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
);
}
PassMode::Direct(attrs)
| PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => {
| PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
apply(bx.cx, attrs);
}
PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack: _ } => {
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack: _ } => {
apply(bx.cx, attrs);
apply(bx.cx, extra_attrs);
apply(bx.cx, meta_attrs);
}
PassMode::Pair(a, b) => {
apply(bx.cx, a);
apply(bx.cx, b);
}
PassMode::Cast(cast, pad_i32) => {
PassMode::Cast { cast, pad_i32 } => {
if *pad_i32 {
apply(bx.cx, &ArgAttributes::new());
}

View File

@ -165,7 +165,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => {
let tp_ty = fn_args.type_at(0);
let ptr = args[0].immediate();
let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode {
let llty = ty.llvm_type(self);
self.volatile_load(llty, ptr)
} else {
@ -386,7 +386,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
};
if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(_, _) = &fn_abi.ret.mode {
if let PassMode::Cast { .. } = &fn_abi.ret.mode {
self.store(llval, result.llval, result.align);
} else {
OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)

View File

@ -19,8 +19,6 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e
codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
codegen_ssa_erroneous_constant = erroneous constant encountered
codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error}
codegen_ssa_expected_coverage_symbol = expected `coverage(off)` or `coverage(on)`
@ -174,8 +172,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
.note = {$output}

View File

@ -595,20 +595,6 @@ pub struct InvalidWindowsSubsystem {
pub subsystem: Symbol,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_erroneous_constant)]
pub struct ErroneousConstant {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_polymorphic_constant_too_generic)]
pub struct PolymorphicConstantTooGeneric {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_shuffle_indices_evaluation)]
pub struct ShuffleIndicesEvaluation {

View File

@ -416,7 +416,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
PassMode::Cast(cast_ty, _) => {
PassMode::Cast { cast: cast_ty, pad_i32: _ } => {
let op = match self.locals[mir::RETURN_PLACE] {
LocalRef::Operand(op) => op,
LocalRef::PendingOperand => bug!("use of return before def"),
@ -1088,9 +1088,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
}
mir::InlineAsmOperand::Const { ref value } => {
let const_value = self
.eval_mir_constant(value)
.unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved"));
let const_value = self.eval_mir_constant(value);
let string = common::asm_const_to_str(
bx.tcx(),
span,
@ -1310,7 +1308,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) {
match arg.mode {
PassMode::Ignore => return,
PassMode::Cast(_, true) => {
PassMode::Cast { pad_i32: true, .. } => {
// Fill padding with undef value, where applicable.
llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32())));
}
@ -1322,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
_ => bug!("codegen_argument: {:?} invalid for pair argument", op),
},
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => match op.val {
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val {
Ref(a, Some(b), _) => {
llargs.push(a);
llargs.push(b);
@ -1347,7 +1345,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
op.val.store(bx, scratch);
(scratch.llval, scratch.align, true)
}
PassMode::Cast(..) => {
PassMode::Cast { .. } => {
let scratch = PlaceRef::alloca(bx, arg.layout);
op.val.store(bx, scratch);
(scratch.llval, scratch.align, true)
@ -1400,7 +1398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if by_ref && !arg.is_indirect() {
// Have to load the argument, maybe while casting it.
if let PassMode::Cast(ty, _) = &arg.mode {
if let PassMode::Cast { cast: ty, .. } = &arg.mode {
let llty = bx.cast_backend_type(ty);
llval = bx.load(llty, llval, align.min(arg.layout.align.abi));
} else {
@ -1744,7 +1742,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
DirectOperand(index) => {
// If there is a cast, we have to store and reload.
let op = if let PassMode::Cast(..) = ret_abi.mode {
let op = if let PassMode::Cast { .. } = ret_abi.mode {
let tmp = PlaceRef::alloca(bx, ret_abi.layout);
tmp.storage_live(bx);
bx.store_arg(&ret_abi, llval, tmp);

View File

@ -14,34 +14,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&self,
bx: &mut Bx,
constant: &mir::Constant<'tcx>,
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
let val = self.eval_mir_constant(constant)?;
) -> OperandRef<'tcx, Bx::Value> {
let val = self.eval_mir_constant(constant);
let ty = self.monomorphize(constant.ty());
Ok(OperandRef::from_const(bx, val, ty))
OperandRef::from_const(bx, val, ty)
}
pub fn eval_mir_constant(
&self,
constant: &mir::Constant<'tcx>,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> ConstValue<'tcx> {
self.monomorphize(constant.literal)
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
.map_err(|err| {
match err {
ErrorHandled::Reported(_) => {
self.cx
.tcx()
.sess
.emit_err(errors::ErroneousConstant { span: constant.span });
}
ErrorHandled::TooGeneric => {
self.cx.tcx().sess.diagnostic().emit_bug(
errors::PolymorphicConstantTooGeneric { span: constant.span },
);
}
}
err
})
.expect("erroneous constant not captured by required_consts")
}
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition

View File

@ -579,23 +579,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if let Some(dbg_var) = dbg_var {
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
self.set_debug_loc(bx, var.source_info);
let base = Self::spill_operand_to_stack(
operand,
Some(var.name.to_string()),
bx,
);
let operand = self.eval_mir_constant_to_operand(bx, &c);
self.set_debug_loc(bx, var.source_info);
let base =
Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
bx.dbg_var_addr(
dbg_var,
dbg_loc,
base.llval,
Size::ZERO,
&[],
fragment,
);
}
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
}
}
}

View File

@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
};
if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(..) = &fn_abi.ret.mode {
if let PassMode::Cast { .. } = &fn_abi.ret.mode {
bx.store(llval, result.llval, result.align);
} else {
OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout)

View File

@ -3,7 +3,6 @@ use crate::traits::*;
use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::traversal;
use rustc_middle::mir::UnwindTerminateReason;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
@ -212,23 +211,14 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
// Evaluate all required consts; codegen later assumes that CTFE will never fail.
let mut all_consts_ok = true;
for const_ in &mir.required_consts {
if let Err(err) = fx.eval_mir_constant(const_) {
all_consts_ok = false;
match err {
// errored or at least linted
ErrorHandled::Reported(_) => {}
ErrorHandled::TooGeneric => {
span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err)
}
}
}
}
if !all_consts_ok {
// We leave the IR in some half-built state here, and rely on this code not even being
// submitted to LLVM once an error was raised.
// Rust post-monomorphization checks; we later rely on them.
if let Err(err) =
mir.post_mono_checks(cx.tcx(), ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c)))
{
err.emit_err(cx.tcx());
// This IR shouldn't ever be emitted, but let's try to guard against any of this code
// ever running.
start_bx.abort();
return;
}
@ -327,7 +317,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
for i in 0..tupled_arg_tys.len() {
let arg = &fx.fn_abi.args[idx];
idx += 1;
if let PassMode::Cast(_, true) = arg.mode {
if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
llarg_idx += 1;
}
let pr_field = place.project_field(bx, i);
@ -351,7 +341,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let arg = &fx.fn_abi.args[idx];
idx += 1;
if let PassMode::Cast(_, true) = arg.mode {
if let PassMode::Cast { pad_i32: true, .. } = arg.mode {
llarg_idx += 1;
}

View File

@ -575,12 +575,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_consume(bx, place.as_ref())
}
mir::Operand::Constant(ref constant) => {
// This cannot fail because we checked all required_consts in advance.
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| {
span_bug!(constant.span, "erroneous constant not captured by required_consts")
})
}
mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
}
}
}

View File

@ -83,9 +83,6 @@ const_eval_dyn_call_vtable_mismatch =
const_eval_dyn_star_call_vtable_mismatch =
`dyn*` call on a pointer whose vtable does not match its type
const_eval_erroneous_constant =
erroneous constant used
const_eval_error = {$error_kind ->
[static] could not evaluate static initializer
[const] evaluation of constant value failed

View File

@ -4,7 +4,7 @@ use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDi
use rustc_middle::mir::AssertKind;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{layout::LayoutError, ConstInt};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
use super::InterpCx;
use crate::errors::{self, FrameNote, ReportErrorExt};
@ -134,11 +134,11 @@ where
// Don't emit a new diagnostic for these errors, they are already reported elsewhere or
// should remain silent.
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
ErrorHandled::TooGeneric
ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))
}
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar),
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)),
err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
ErrorHandled::Reported(guar.into())
ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP))
}
// Report remaining errors.
_ => {
@ -152,7 +152,7 @@ where
// Use *our* span to label the interp error
err.span_label(our_span, msg);
ErrorHandled::Reported(err.emit().into())
ErrorHandled::Reported(err.emit().into(), span)
}
}
}

View File

@ -212,7 +212,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_const_value_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
Err(ErrorHandled::TooGeneric(_)) => {}
// deduplicate calls
other => return other,
}
@ -259,7 +259,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_allocation_raw(key) {
// try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {}
Err(ErrorHandled::TooGeneric(_)) => {}
// deduplicate calls
other => return other,
}

View File

@ -239,13 +239,6 @@ pub struct LongRunningWarn {
pub item_span: Span,
}
#[derive(Diagnostic)]
#[diag(const_eval_erroneous_constant)]
pub(crate) struct ErroneousConstUsed {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[note(const_eval_non_const_impl)]
pub(crate) struct NonConstImplNote {

View File

@ -7,7 +7,7 @@ use hir::CRATE_HIR_ID;
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
@ -21,10 +21,10 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
use super::{
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
Projectable, Provenance, Scalar, StackPopJump,
};
use crate::errors::{self, ErroneousConstUsed};
use crate::errors;
use crate::util;
use crate::{fluent_generated as fluent, ReportErrorExt};
@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
>(
&self,
value: T,
) -> Result<T, InterpError<'tcx>> {
) -> Result<T, ErrorHandled> {
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
}
@ -566,7 +566,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&self,
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
value: T,
) -> Result<T, InterpError<'tcx>> {
) -> Result<T, ErrorHandled> {
frame
.instance
.try_subst_mir_and_normalize_erasing_regions(
@ -574,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.param_env,
ty::EarlyBinder::bind(value),
)
.map_err(|_| err_inval!(TooGeneric))
.map_err(|_| ErrorHandled::TooGeneric(self.cur_span()))
}
/// The `args` are assumed to already be in our interpreter "universe" (param_env).
@ -750,11 +750,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
if M::POST_MONO_CHECKS {
for ct in &body.required_consts {
let span = ct.span;
let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
self.eval_mir_constant(&ct, Some(span), None)?;
}
// `ctfe_query` does some error message decoration that we want to be in effect here.
self.ctfe_query(None, |tcx| {
body.post_mono_checks(*tcx, self.param_env, |c| {
self.subst_from_current_frame_and_normalize_erasing_regions(c)
})
})?;
}
// done
@ -1059,28 +1060,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&self,
span: Option<Span>,
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
) -> InterpResult<'tcx, T> {
) -> Result<T, ErrorHandled> {
// Use a precise span for better cycle errors.
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
match err {
ErrorHandled::Reported(err) => {
if !err.is_tainted_by_errors() && let Some(span) = span {
// To make it easier to figure out where this error comes from, also add a note at the current location.
self.tcx.sess.emit_note(ErroneousConstUsed { span });
}
err_inval!(AlreadyReported(err))
}
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
}
.into()
err.emit_note(*self.tcx);
err
})
}
pub fn eval_global(
&self,
gid: GlobalId<'tcx>,
span: Option<Span>,
instance: ty::Instance<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let gid = GlobalId { instance, promoted: None };
// For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
// and thus don't care about the parameter environment. While we could just use
// `self.param_env`, that would mean we invoke the query to evaluate the static
@ -1091,10 +1083,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else {
self.param_env
};
let val = self.ctfe_query(span, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
let val = self.ctfe_query(None, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
self.raw_const_to_mplace(val)
}
pub fn eval_mir_constant(
&self,
val: &mir::ConstantKind<'tcx>,
span: Option<Span>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
let const_val = self.ctfe_query(span, |tcx| val.eval(*tcx, self.param_env, span))?;
self.const_val_to_op(const_val, val.ty(), layout)
}
#[must_use]
pub fn dump_place(
&self,

View File

@ -8,15 +8,14 @@ use either::{Either, Left, Right};
use rustc_hir::def::Namespace;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
use rustc_middle::ty::{ConstInt, Ty, ValTree};
use rustc_middle::ty::{ConstInt, Ty};
use rustc_middle::{mir, ty};
use rustc_span::Span;
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
use super::{
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId,
InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer,
Projectable, Provenance, Scalar,
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, InterpCx,
InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, Projectable,
Provenance, Scalar,
};
/// An `Immediate` represents a single immediate self-contained Rust value.
@ -136,7 +135,11 @@ impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
impl<Prov: Provenance> std::fmt::Debug for ImmTy<'_, Prov> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ImmTy").field("imm", &self.imm).field("ty", &self.layout.ty).finish()
// Printing `layout` results in too much noise; just print a nice version of the type.
f.debug_struct("ImmTy")
.field("imm", &self.imm)
.field("ty", &format_args!("{}", self.layout.ty))
.finish()
}
}
@ -305,7 +308,11 @@ pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OpTy").field("op", &self.op).field("ty", &self.layout.ty).finish()
// Printing `layout` results in too much noise; just print a nice version of the type.
f.debug_struct("OpTy")
.field("op", &self.op)
.field("ty", &format_args!("{}", self.layout.ty))
.finish()
}
}
@ -693,54 +700,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(op)
}
fn eval_ty_constant(
&self,
val: ty::Const<'tcx>,
span: Option<Span>,
) -> InterpResult<'tcx, ValTree<'tcx>> {
Ok(match val.kind() {
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
throw_inval!(TooGeneric)
}
// FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated
ty::ConstKind::Expr(_) => throw_inval!(TooGeneric),
ty::ConstKind::Error(reported) => {
throw_inval!(AlreadyReported(reported.into()))
}
ty::ConstKind::Unevaluated(uv) => {
let instance = self.resolve(uv.def, uv.args)?;
let cid = GlobalId { instance, promoted: None };
self.ctfe_query(span, |tcx| tcx.eval_to_valtree(self.param_env.and(cid)))?
.unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"))
}
ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {val:?}")
}
ty::ConstKind::Value(valtree) => valtree,
})
}
pub fn eval_mir_constant(
&self,
val: &mir::ConstantKind<'tcx>,
span: Option<Span>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
match *val {
mir::ConstantKind::Ty(ct) => {
let ty = ct.ty();
let valtree = self.eval_ty_constant(ct, span)?;
let const_val = self.tcx.valtree_to_const_val((ty, valtree));
self.const_val_to_op(const_val, ty, layout)
}
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout),
mir::ConstantKind::Unevaluated(uv, _) => {
let instance = self.resolve(uv.def, uv.args)?;
Ok(self.eval_global(GlobalId { instance, promoted: uv.promoted }, span)?.into())
}
}
}
pub(crate) fn const_val_to_op(
&self,
val_val: ConstValue<'tcx>,

View File

@ -117,9 +117,10 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
impl<Prov: Provenance> std::fmt::Debug for MPlaceTy<'_, Prov> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Printing `layout` results in too much noise; just print a nice version of the type.
f.debug_struct("MPlaceTy")
.field("mplace", &self.mplace)
.field("ty", &self.layout.ty)
.field("ty", &format_args!("{}", self.layout.ty))
.finish()
}
}
@ -237,7 +238,11 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PlaceTy").field("place", &self.place).field("ty", &self.layout.ty).finish()
// Printing `layout` results in too much noise; just print a nice version of the type.
f.debug_struct("PlaceTy")
.field("place", &self.place)
.field("ty", &format_args!("{}", self.layout.ty))
.finish()
}
}

View File

@ -51,7 +51,7 @@ pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
// Traverse the graph, collecting a number of things:
//
// * Preorder mapping (to it, and back to the actual ordering)
// * Postorder mapping (used exclusively for rank_partial_cmp on the final product)
// * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product)
// * Parents for each vertex in the preorder tree
//
// These are all done here rather than through one of the 'standard'
@ -342,8 +342,8 @@ impl<Node: Idx> Dominators<Node> {
/// relationship, the dominator will always precede the dominated. (The relative ordering
/// of two unrelated nodes will also be consistent, but otherwise the order has no
/// meaning.) This method cannot be used to determine if either Node dominates the other.
pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs])
}
/// Returns true if `a` dominates `b`.

View File

@ -1,9 +1,11 @@
#### Note: this error code is no longer emitted by the compiler.
A struct, enum, or union with the `repr(transparent)` representation hint
contains a zero-sized field that requires non-trivial alignment.
Erroneous code example:
```compile_fail,E0691
```ignore (error is no longer emitted)
#![feature(repr_align)]
#[repr(align(32))]

View File

@ -401,6 +401,8 @@ declare_features! (
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
/// instrumentation of that function.
(active, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605), None),
/// Allows users to provide classes for fenced code block using `class:classname`.
(active, custom_code_classes_in_docs, "CURRENT_RUSTC_VERSION", Some(79483), None),
/// Allows non-builtin attributes in inner attribute position.
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
@ -414,7 +416,7 @@ declare_features! (
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
(active, deprecated_suggestion, "1.61.0", Some(94785), None),
/// Allows using the `#[diagnostic]` attribute tool namespace
(active, diagnostic_namespace, "1.73.0", Some(94785), None),
(active, diagnostic_namespace, "1.73.0", Some(111996), None),
/// Controls errors in trait implementations.
(active, do_not_recommend, "1.67.0", Some(51992), None),
/// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.

View File

@ -699,6 +699,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
),
rustc_attr!(
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
"#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
),
rustc_attr!(
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."

View File

@ -95,6 +95,34 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par
hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
.note = parent implementation is in crate `{$cname}`
hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait
.label = impl requires at least one non-auto trait
.note = define and implement a new trait or type instead
hir_analysis_inherent_nominal = no nominal type found for inherent implementation
.label = impl requires a nominal type
.note = either implement a trait on it or create a newtype to wrap it instead
hir_analysis_inherent_primitive_ty = cannot define inherent `impl` for primitive types
.help = consider using an extension trait instead
hir_analysis_inherent_primitive_ty_note = you could also try moving the reference to uses of `{$subty}` (such as `self`) within the implementation
hir_analysis_inherent_ty_outside = cannot define inherent `impl` for a type outside of the crate where the type is defined
.help = consider moving this inherent impl into the crate defining the type if possible
.span_help = alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items
hir_analysis_inherent_ty_outside_new = cannot define inherent `impl` for a type outside of the crate where the type is defined
.label = impl for type defined outside of crate.
.note = define and implement a trait or new type instead
hir_analysis_inherent_ty_outside_primitive = cannot define inherent `impl` for primitive types outside of `core`
.help = consider moving this inherent impl into `core` if possible
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a type outside of the crate where the type is defined
.help = consider moving this inherent impl into the crate defining the type if possible
.span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
hir_analysis_invalid_union_field =
field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
.note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
@ -276,13 +304,13 @@ hir_analysis_transparent_enum_variant = transparent enum needs exactly one varia
.many_label = too many variants in `{$path}`
.multi_label = variant here
hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
.label = needs at most one non-zero-sized field, but has {$field_count}
.labels = this field is non-zero-sized
hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count}
.label = needs at most one field with non-trivial size or alignment, but has {$field_count}
.labels = this field has non-zero size or requires alignment
hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
.label = needs at most one non-zero-sized field, but has {$field_count}
.labels = this field is non-zero-sized
hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count}
.label = needs at most one field with non-trivial size or alignment, but has {$field_count}
.labels = this field has non-zero size or requires alignment
hir_analysis_typeof_reserved_keyword_used =
`typeof` is a reserved keyword but unimplemented

View File

@ -1138,19 +1138,19 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
return;
}
// For each field, figure out if it's known to be a ZST and align(1), with "known"
// respecting #[non_exhaustive] attributes.
// For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with
// "known" respecting #[non_exhaustive] attributes.
let field_infos = adt.all_fields().map(|field| {
let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));
let param_env = tcx.param_env(field.did);
let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir().span_if_local(field.did).unwrap();
let zst = layout.is_ok_and(|layout| layout.is_zst());
let align = layout.ok().map(|layout| layout.align.abi.bytes());
if !zst {
return (span, zst, align, None);
let trivial = layout.is_ok_and(|layout| layout.is_1zst());
if !trivial {
return (span, trivial, None);
}
// Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`.
fn check_non_exhaustive<'tcx>(
tcx: TyCtxt<'tcx>,
@ -1184,58 +1184,52 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
}
}
(span, zst, align, check_non_exhaustive(tcx, ty).break_value())
(span, trivial, check_non_exhaustive(tcx, ty).break_value())
});
let non_zst_fields = field_infos
let non_trivial_fields = field_infos
.clone()
.filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None });
let non_zst_count = non_zst_fields.clone().count();
if non_zst_count >= 2 {
bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
.filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None });
let non_trivial_count = non_trivial_fields.clone().count();
if non_trivial_count >= 2 {
bad_non_zero_sized_fields(
tcx,
adt,
non_trivial_count,
non_trivial_fields,
tcx.def_span(adt.did()),
);
return;
}
let incompatible_zst_fields =
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
for (span, zst, align, non_exhaustive) in field_infos {
if zst && align != Some(1) {
let mut err = struct_span_err!(
tcx.sess,
span,
E0691,
"zero-sized field in transparent {} has alignment larger than 1",
adt.descr(),
);
if let Some(align_bytes) = align {
err.span_label(
let mut prev_non_exhaustive_1zst = false;
for (span, _trivial, non_exhaustive_1zst) in field_infos {
if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst {
// If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.
// Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.
if non_trivial_count > 0 || prev_non_exhaustive_1zst {
tcx.struct_span_lint_hir(
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span,
format!("has alignment of {align_bytes}, which is larger than 1"),
);
"zero-sized fields in `repr(transparent)` cannot \
contain external non-exhaustive types",
|lint| {
let note = if non_exhaustive {
"is marked with `#[non_exhaustive]`"
} else {
"contains private fields"
};
let field_ty = tcx.def_path_str_with_args(def_id, args);
lint.note(format!(
"this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become \
non-zero-sized in the future."
))
},
)
} else {
err.span_label(span, "may have alignment larger than 1");
prev_non_exhaustive_1zst = true;
}
err.emit();
}
if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive {
tcx.struct_span_lint_hir(
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
span,
"zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
|lint| {
let note = if non_exhaustive {
"is marked with `#[non_exhaustive]`"
} else {
"contains private fields"
};
let field_ty = tcx.def_path_str_with_args(def_id, args);
lint
.note(format!("this {descr} contains `{field_ty}`, which {note}, \
and makes it not a breaking change to become non-zero-sized in the future."))
},
)
}
}
}

View File

@ -7,7 +7,6 @@
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@ -15,6 +14,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
use rustc_span::symbol::sym;
use crate::errors;
/// On-demand query: yields a map containing all types mapped to their inherent impls.
pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
let mut collect = InherentCollect { tcx, impls_map: Default::default() };
@ -45,14 +46,6 @@ struct InherentCollect<'tcx> {
impls_map: CrateInherentImpls,
}
const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
const INTO_DEFINING_CRATE: &str =
"consider moving this inherent impl into the crate defining the type if possible";
const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
const ADD_ATTR: &str =
"alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
if let Some(ty_def_id) = ty_def_id.as_local() {
@ -69,30 +62,17 @@ impl<'tcx> InherentCollect<'tcx> {
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
let impl_span = self.tcx.def_span(impl_def_id);
struct_span_err!(
self.tcx.sess,
impl_span,
E0390,
"cannot define inherent `impl` for a type outside of the crate where the type is defined",
)
.help(INTO_DEFINING_CRATE)
.span_help(impl_span, ADD_ATTR_TO_TY)
.emit();
self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span });
return;
}
for &impl_item in items {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let impl_span = self.tcx.def_span(impl_def_id);
struct_span_err!(
self.tcx.sess,
impl_span,
E0390,
"cannot define inherent `impl` for a type outside of the crate where the type is defined",
)
.help(INTO_DEFINING_CRATE)
.span_help(self.tcx.def_span(impl_item), ADD_ATTR)
.emit();
self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant {
span: impl_span,
help_span: self.tcx.def_span(impl_item),
});
return;
}
}
@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
} else {
let impl_span = self.tcx.def_span(impl_def_id);
struct_span_err!(
self.tcx.sess,
impl_span,
E0116,
"cannot define inherent `impl` for a type outside of the crate \
where the type is defined"
)
.span_label(impl_span, "impl for type defined outside of crate.")
.note("define and implement a trait or new type instead")
.emit();
self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span });
}
}
@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> {
for &impl_item in items {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let span = self.tcx.def_span(impl_def_id);
struct_span_err!(
self.tcx.sess,
self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive {
span,
E0390,
"cannot define inherent `impl` for primitive types outside of `core`",
)
.help(INTO_CORE)
.span_help(self.tcx.def_span(impl_item), ADD_ATTR)
.emit();
help_span: self.tcx.def_span(impl_item),
});
return;
}
}
} else {
let span = self.tcx.def_span(impl_def_id);
let mut err = struct_span_err!(
self.tcx.sess,
span,
E0390,
"cannot define inherent `impl` for primitive types",
);
err.help("consider using an extension trait instead");
let mut note = None;
if let ty::Ref(_, subty, _) = ty.kind() {
err.note(format!(
"you could also try moving the reference to \
uses of `{subty}` (such as `self`) within the implementation"
));
note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
}
err.emit();
self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note });
return;
}
}
@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
}
ty::Dynamic(..) => {
struct_span_err!(
self.tcx.sess,
item_span,
E0785,
"cannot define inherent `impl` for a dyn auto trait"
)
.span_label(item_span, "impl requires at least one non-auto trait")
.note("define and implement a new trait or type instead")
.emit();
self.tcx.sess.emit_err(errors::InherentDyn { span: item_span });
}
ty::Bool
| ty::Char
@ -202,17 +151,7 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::FnPtr(_)
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
ty::Alias(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
item_span,
E0118,
"no nominal type found for inherent implementation"
);
err.span_label(item_span, "impl requires a nominal type")
.note("either implement a trait on it or create a newtype to wrap it instead");
err.emit();
self.tcx.sess.emit_err(errors::InherentNominal { span: item_span });
}
ty::FnDef(..)
| ty::Closure(..)

View File

@ -943,3 +943,75 @@ pub struct AssocBoundOnConst {
pub span: Span,
pub descr: &'static str,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside, code = "E0390")]
#[help]
pub struct InherentTyOutside {
#[primary_span]
#[help(hir_analysis_span_help)]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")]
#[help]
pub struct InherentTyOutsideRelevant {
#[primary_span]
pub span: Span,
#[help(hir_analysis_span_help)]
pub help_span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")]
#[note]
pub struct InherentTyOutsideNew {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")]
#[help]
pub struct InherentTyOutsidePrimitive {
#[primary_span]
pub span: Span,
#[help(hir_analysis_span_help)]
pub help_span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")]
#[help]
pub struct InherentPrimitiveTy<'a> {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub note: Option<InherentPrimitiveTyNote<'a>>,
}
#[derive(Subdiagnostic)]
#[note(hir_analysis_inherent_primitive_ty_note)]
pub struct InherentPrimitiveTyNote<'a> {
pub subty: Ty<'a>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_dyn, code = "E0785")]
#[note]
pub struct InherentDyn {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_nominal, code = "E0118")]
#[note]
pub struct InherentNominal {
#[primary_span]
#[label]
pub span: Span,
}

View File

@ -117,7 +117,7 @@ use rustc_hir::def::DefKind;
fluent_messages! { "../messages.ftl" }
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`";
const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
const UNSTABLE_EXPLAIN: &str =
"using calling conventions other than `C` or `cdecl` for varargs functions is unstable";

View File

@ -16,6 +16,21 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`
*[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
}
hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool`
.suggestion = compare with zero instead
.help = compare with zero instead
.label = unsupported cast
hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop`
hir_typeck_cast_unknown_pointer = cannot cast {$to ->
[true] to
*[false] from
} a pointer of an unknown kind
.label_to = needs more type information
.note = the type information given here is insufficient to check whether the pointer cast is valid
.label_from = the type information given here is insufficient to check whether the pointer cast is valid
hir_typeck_const_select_must_be_const = this argument must be a `const fn`
.help = consult the documentation on `const_eval_select` for more information
@ -29,10 +44,16 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `
hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty`
hir_typeck_expected_default_return_type = expected `()` because of default return type
hir_typeck_expected_return_type = expected `{$expected}` because of return type
hir_typeck_explicit_destructor = explicit use of destructor method
.label = explicit destructor calls not allowed
.suggestion = consider using `drop` function
hir_typeck_field_multiply_specified_in_initializer =
field `{$ident}` specified more than once
.label = used more than once
@ -52,8 +73,17 @@ hir_typeck_functional_record_update_on_non_struct =
hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
hir_typeck_int_to_fat = cannot cast `{$expr_ty}` to a pointer that {$known_wide ->
[true] is
*[false] may be
} wide
hir_typeck_int_to_fat_label = creating a `{$cast_ty}` requires both an address and {$metadata}
hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
hir_typeck_invalid_callee = expected function, found {$ty}
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
@ -63,9 +93,22 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la
hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
hir_typeck_lossy_provenance_int2ptr =
strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
.suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
.help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead
hir_typeck_lossy_provenance_ptr2int =
under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}`
.suggestion = use `.addr()` to obtain the address of a pointer
.help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
hir_typeck_method_call_on_unknown_raw_pointee =
cannot call a method on a raw pointer with an unknown pointee type
hir_typeck_missing_fn_lang_items = failed to find an overloaded call trait for closure call
.help = make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
@ -92,6 +135,9 @@ hir_typeck_return_stmt_outside_of_fn_body =
.encl_body_label = the {$statement_kind} is part of this body...
.encl_fn_label = ...not the enclosing function body
hir_typeck_rustcall_incorrect_args =
functions with the "rust-call" ABI must take a single non-self tuple argument
hir_typeck_struct_expr_non_exhaustive =
cannot create non-exhaustive {$what} using struct expression
@ -101,8 +147,18 @@ hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `
hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead
hir_typeck_trivial_cast = trivial {$numeric ->
[true] numeric cast
*[false] cast
}: `{$expr_ty}` as `{$cast_ty}`
.help = cast can be replaced by coercion; this might require a temporary variable
hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
hir_typeck_use_is_empty =
consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything
hir_typeck_yield_expr_outside_of_generator =
yield expression outside of generator literal

View File

@ -2,9 +2,9 @@ use super::method::probe::ProbeScope;
use super::method::MethodCallee;
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
use crate::type_error_struct;
use crate::errors;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey};
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res};
use rustc_hir::def_id::DefId;
@ -44,23 +44,15 @@ pub fn check_legal_trait_for_method_call(
trait_id: DefId,
) {
if tcx.lang_items().drop_trait() == Some(trait_id) {
let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
err.span_label(span, "explicit destructor calls not allowed");
let (sp, suggestion) = receiver
.and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok())
.filter(|snippet| !snippet.is_empty())
.map(|snippet| (expr_span, format!("drop({snippet})")))
.unwrap_or_else(|| (span, "drop".to_string()));
err.span_suggestion(
sp,
"consider using `drop` function",
suggestion,
Applicability::MaybeIncorrect,
);
err.emit();
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
errors::ExplicitDestructorCallSugg::Snippet {
lo: expr_span.shrink_to_lo(),
hi: receiver.shrink_to_hi().to(expr_span.shrink_to_hi()),
}
} else {
errors::ExplicitDestructorCallSugg::Empty(span)
};
tcx.sess.emit_err(errors::ExplicitDestructorCall { span, sugg });
}
}
@ -387,6 +379,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Unit testing: function items annotated with
// `#[rustc_evaluate_where_clauses]` trigger special output
// to let us test the trait evaluation system.
// Untranslatable diagnostics are okay for rustc internals
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) {
let predicates = self.tcx.predicates_of(def_id);
let predicates = predicates.instantiate(self.tcx, args);
@ -478,10 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
self.require_type_is_sized(ty, sp, traits::RustCall);
} else {
self.tcx.sess.span_err(
sp,
"functions with the \"rust-call\" ABI must take a single non-self tuple argument",
);
self.tcx.sess.emit_err(errors::RustCallIncorrectArgs { span: sp });
}
}
@ -610,17 +602,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let callee_ty = self.resolve_vars_if_possible(callee_ty);
let mut err = type_error_struct!(
self.tcx.sess,
callee_expr.span,
callee_ty,
E0618,
"expected function, found {}",
match &unit_variant {
let mut err = self.tcx.sess.create_err(errors::InvalidCallee {
span: callee_expr.span,
ty: match &unit_variant {
Some((_, kind, path)) => format!("{kind} `{path}`"),
None => format!("`{callee_ty}`"),
}
);
},
});
if callee_ty.references_error() {
err.downgrade_to_delayed_bug();
}
self.identify_bad_closure_def_and_call(
&mut err,
@ -891,15 +882,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
None => {
// This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once`
// lang items are not defined (issue #86238).
let mut err = fcx.inh.tcx.sess.struct_span_err(
self.call_expr.span,
"failed to find an overloaded call trait for closure call",
);
err.help(
"make sure the `fn`/`fn_mut`/`fn_once` lang items are defined \
and have correctly defined `call`/`call_mut`/`call_once` methods",
);
err.emit();
fcx.inh.tcx.sess.emit_err(errors::MissingFnLangItems { span: self.call_expr.span });
}
}
}

View File

@ -30,11 +30,10 @@
use super::FnCtxt;
use crate::errors;
use crate::type_error_struct;
use hir::ExprKind;
use rustc_errors::{
struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
};
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::mir::Mutability;
@ -321,33 +320,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
.emit();
}
CastError::CastToBool => {
let mut err = struct_span_err!(
fcx.tcx.sess,
self.span,
E0054,
"cannot cast `{}` as `bool`",
self.expr_ty
);
if self.expr_ty.is_numeric() {
match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
Ok(snippet) => {
err.span_suggestion(
self.span,
"compare with zero instead",
format!("{snippet} != 0"),
Applicability::MachineApplicable,
);
}
Err(_) => {
err.span_help(self.span, "compare with zero instead");
}
}
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let help = if self.expr_ty.is_numeric() {
errors::CannotCastToBoolHelp::Numeric(
self.expr_span.shrink_to_hi().with_hi(self.span.hi()),
)
} else {
err.span_label(self.span, "unsupported cast");
}
err.emit();
errors::CannotCastToBoolHelp::Unsupported(self.span)
};
fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
}
CastError::CastToChar => {
let mut err = type_error_struct!(
@ -536,33 +517,20 @@ impl<'a, 'tcx> CastCheck<'tcx> {
.emit();
}
CastError::IntToFatCast(known_metadata) => {
let mut err = struct_span_err!(
fcx.tcx.sess,
self.cast_span,
E0606,
"cannot cast `{}` to a pointer that {} wide",
fcx.ty_to_string(self.expr_ty),
if known_metadata.is_some() { "is" } else { "may be" }
);
err.span_label(
self.cast_span,
format!(
"creating a `{}` requires both an address and {}",
self.cast_ty,
known_metadata.unwrap_or("type-specific metadata"),
),
);
if fcx.tcx.sess.is_nightly_build() {
err.span_label(
self.expr_span,
"consider casting this expression to `*const ()`, \
then using `core::ptr::from_raw_parts`",
);
}
err.emit();
let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span);
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
let expr_ty = fcx.ty_to_string(self.expr_ty);
let metadata = known_metadata.unwrap_or("type-specific metadata");
let known_wide = known_metadata.is_some();
let span = self.cast_span;
fcx.tcx.sess.emit_err(errors::IntToWide {
span,
metadata,
expr_ty,
cast_ty,
expr_if_nightly,
known_wide,
});
}
CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
let unknown_cast_to = match e {
@ -570,27 +538,16 @@ impl<'a, 'tcx> CastCheck<'tcx> {
CastError::UnknownExprPtrKind => false,
_ => bug!(),
};
let mut err = struct_span_err!(
fcx.tcx.sess,
if unknown_cast_to { self.cast_span } else { self.span },
E0641,
"cannot cast {} a pointer of an unknown kind",
if unknown_cast_to { "to" } else { "from" }
);
if unknown_cast_to {
err.span_label(self.cast_span, "needs more type information");
err.note(
"the type information given here is insufficient to check whether \
the pointer cast is valid",
);
let (span, sub) = if unknown_cast_to {
(self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span))
} else {
err.span_label(
self.span,
"the type information given here is insufficient to check whether \
the pointer cast is valid",
);
}
err.emit();
(self.cast_span, errors::CastUnknownPointerSub::From(self.span))
};
fcx.tcx.sess.emit_err(errors::CastUnknownPointer {
span,
to: unknown_cast_to,
sub,
});
}
CastError::ForeignNonExhaustiveAdt => {
make_invalid_casting_error(
@ -674,31 +631,18 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
let t_cast = self.cast_ty;
let t_expr = self.expr_ty;
let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() {
("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS)
let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() {
(true, lint::builtin::TRIVIAL_NUMERIC_CASTS)
} else {
("", lint::builtin::TRIVIAL_CASTS)
(false, lint::builtin::TRIVIAL_CASTS)
};
fcx.tcx.struct_span_lint_hir(
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
fcx.tcx.emit_spanned_lint(
lint,
self.expr.hir_id,
self.span,
DelayDm(|| {
format!(
"trivial {}cast: `{}` as `{}`",
adjective,
fcx.ty_to_string(t_expr),
fcx.ty_to_string(t_cast)
)
}),
|lint| {
lint.help(
"cast can be replaced by coercion; this might \
require a temporary variable",
)
},
errors::TrivialCast { numeric, expr_ty, cast_ty },
);
}
@ -991,93 +935,67 @@ impl<'a, 'tcx> CastCheck<'tcx> {
if let ty::Adt(d, _) = self.expr_ty.kind()
&& d.has_dtor(fcx.tcx)
{
fcx.tcx.struct_span_lint_hir(
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
fcx.tcx.emit_spanned_lint(
lint::builtin::CENUM_IMPL_DROP_CAST,
self.expr.hir_id,
self.span,
DelayDm(|| format!(
"cannot cast enum `{}` into integer `{}` because it implements `Drop`",
self.expr_ty, self.cast_ty
)),
|lint| {
lint
},
errors::CastEnumDrop {
expr_ty,
cast_ty,
}
);
}
}
fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) {
fcx.tcx.struct_span_lint_hir(
let expr_prec = self.expr.precedence().order();
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize));
let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
let expr_span = self.expr_span.shrink_to_lo();
let sugg = match (needs_parens, needs_cast) {
(true, true) => errors::LossyProvenancePtr2IntSuggestion::NeedsParensCast {
expr_span,
cast_span,
cast_ty,
},
(true, false) => {
errors::LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span }
}
(false, true) => {
errors::LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_ty }
}
(false, false) => errors::LossyProvenancePtr2IntSuggestion::Other { cast_span },
};
let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg };
fcx.tcx.emit_spanned_lint(
lint::builtin::LOSSY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
DelayDm(|| format!(
"under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
self.expr_ty, self.cast_ty
)),
|lint| {
let msg = "use `.addr()` to obtain the address of a pointer";
let expr_prec = self.expr.precedence().order();
let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX;
let scalar_cast = match t_c {
ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
_ => format!(" as {}", self.cast_ty),
};
let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span);
if needs_parens {
let suggestions = vec![
(self.expr_span.shrink_to_lo(), String::from("(")),
(cast_span, format!(").addr(){scalar_cast}")),
];
lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
} else {
lint.span_suggestion(
cast_span,
msg,
format!(".addr(){scalar_cast}"),
Applicability::MaybeIncorrect,
);
}
lint.help(
"if you can't comply with strict provenance and need to expose the pointer \
provenance you can use `.expose_addr()` instead"
);
lint
},
lint,
);
}
fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
fcx.tcx.struct_span_lint_hir(
let sugg = errors::LossyProvenanceInt2PtrSuggestion {
lo: self.expr_span.shrink_to_lo(),
hi: self.expr_span.shrink_to_hi().to(self.cast_span),
};
let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty);
let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg };
fcx.tcx.emit_spanned_lint(
lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
DelayDm(|| format!(
"strict provenance disallows casting integer `{}` to pointer `{}`",
self.expr_ty, self.cast_ty
)),
|lint| {
let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
let suggestions = vec![
(self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
(self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
];
lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
lint.help(
"if you can't comply with strict provenance and don't have a pointer with \
the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
);
lint
},
lint,
);
}
@ -1093,26 +1011,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
if let Some((deref_ty, _)) = derefed {
// Give a note about what the expr derefs to.
if deref_ty != self.expr_ty.peel_refs() {
err.span_note(
self.expr_span,
format!(
"this expression `Deref`s to `{}` which implements `is_empty`",
fcx.ty_to_string(deref_ty)
),
);
err.subdiagnostic(errors::DerefImplsIsEmpty {
span: self.expr_span,
deref_ty: fcx.ty_to_string(deref_ty),
});
}
// Create a multipart suggestion: add `!` and `.is_empty()` in
// place of the cast.
let suggestion = vec![
(self.expr_span.shrink_to_lo(), "!".to_string()),
(self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()),
];
err.multipart_suggestion_verbose(format!(
"consider using the `is_empty` method on `{}` to determine if it contains anything",
fcx.ty_to_string(self.expr_ty),
), suggestion, Applicability::MaybeIncorrect);
err.subdiagnostic(errors::UseIsEmpty {
lo: self.expr_span.shrink_to_lo(),
hi: self.span.with_lo(self.expr_span.hi()),
expr_ty: fcx.ty_to_string(self.expr_ty),
});
}
}
}

View File

@ -6,7 +6,7 @@ use rustc_errors::{
AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
SubdiagnosticMessage,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{
edition::{Edition, LATEST_STABLE_EDITION},
@ -54,6 +54,13 @@ impl IntoDiagnosticArg for ReturnLikeStatementKind {
}
}
#[derive(Diagnostic)]
#[diag(hir_typeck_rustcall_incorrect_args)]
pub struct RustCallIncorrectArgs {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_yield_expr_outside_of_generator, code = "E0627")]
pub struct YieldExprOutsideOfGenerator {
@ -76,6 +83,14 @@ pub struct MethodCallOnUnknownRawPointee {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_missing_fn_lang_items)]
#[help]
pub struct MissingFnLangItems {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")]
pub struct FunctionalRecordUpdateOnNonStruct {
@ -129,6 +144,29 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
},
}
#[derive(Diagnostic)]
#[diag(hir_typeck_explicit_destructor, code = "E0040")]
pub struct ExplicitDestructorCall {
#[primary_span]
#[label]
pub span: Span,
#[subdiagnostic]
pub sugg: ExplicitDestructorCallSugg,
}
#[derive(Subdiagnostic)]
pub enum ExplicitDestructorCallSugg {
#[suggestion(hir_typeck_suggestion, code = "drop", applicability = "maybe-incorrect")]
Empty(#[primary_span] Span),
#[multipart_suggestion(hir_typeck_suggestion, style = "short")]
Snippet {
#[suggestion_part(code = "drop(")]
lo: Span,
#[suggestion_part(code = ")")]
hi: Span,
},
}
#[derive(Diagnostic)]
#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
pub struct MissingParenthesesInRange {
@ -231,6 +269,69 @@ pub struct LangStartIncorrectRetTy<'tcx> {
pub found_ty: Ty<'tcx>,
}
#[derive(LintDiagnostic)]
#[diag(hir_typeck_lossy_provenance_int2ptr)]
#[help]
pub struct LossyProvenanceInt2Ptr<'tcx> {
pub expr_ty: Ty<'tcx>,
pub cast_ty: Ty<'tcx>,
#[subdiagnostic]
pub sugg: LossyProvenanceInt2PtrSuggestion,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")]
pub struct LossyProvenanceInt2PtrSuggestion {
#[suggestion_part(code = "(...).with_addr(")]
pub lo: Span,
#[suggestion_part(code = ")")]
pub hi: Span,
}
#[derive(LintDiagnostic)]
#[diag(hir_typeck_lossy_provenance_ptr2int)]
#[help]
pub struct LossyProvenancePtr2Int<'tcx> {
pub expr_ty: Ty<'tcx>,
pub cast_ty: Ty<'tcx>,
#[subdiagnostic]
pub sugg: LossyProvenancePtr2IntSuggestion<'tcx>,
}
#[derive(Subdiagnostic)]
pub enum LossyProvenancePtr2IntSuggestion<'tcx> {
#[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
NeedsParensCast {
#[suggestion_part(code = "(")]
expr_span: Span,
#[suggestion_part(code = ").addr() as {cast_ty}")]
cast_span: Span,
cast_ty: Ty<'tcx>,
},
#[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")]
NeedsParens {
#[suggestion_part(code = "(")]
expr_span: Span,
#[suggestion_part(code = ").addr()")]
cast_span: Span,
},
#[suggestion(
hir_typeck_suggestion,
code = ".addr() as {cast_ty}",
applicability = "maybe-incorrect"
)]
NeedsCast {
#[primary_span]
cast_span: Span,
cast_ty: Ty<'tcx>,
},
#[suggestion(hir_typeck_suggestion, code = ".addr()", applicability = "maybe-incorrect")]
Other {
#[primary_span]
cast_span: Span,
},
}
#[derive(Subdiagnostic)]
pub enum HelpUseLatestEdition {
#[help(hir_typeck_help_set_edition_cargo)]
@ -252,6 +353,28 @@ impl HelpUseLatestEdition {
}
}
#[derive(Diagnostic)]
#[diag(hir_typeck_invalid_callee, code = "E0618")]
pub struct InvalidCallee {
#[primary_span]
pub span: Span,
pub ty: String,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_int_to_fat, code = "E0606")]
pub struct IntToWide<'tcx> {
#[primary_span]
#[label(hir_typeck_int_to_fat_label)]
pub span: Span,
pub metadata: &'tcx str,
pub expr_ty: String,
pub cast_ty: Ty<'tcx>,
#[label(hir_typeck_int_to_fat_label_nightly)]
pub expr_if_nightly: Option<Span>,
pub known_wide: bool,
}
#[derive(Subdiagnostic)]
pub enum OptionResultRefMismatch {
#[suggestion(
@ -350,6 +473,20 @@ pub struct UnionPatDotDot {
pub span: Span,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
hir_typeck_use_is_empty,
applicability = "maybe-incorrect",
style = "verbose"
)]
pub struct UseIsEmpty {
#[suggestion_part(code = "!")]
pub lo: Span,
#[suggestion_part(code = ".is_empty()")]
pub hi: Span,
pub expr_ty: String,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_arg_mismatch_indeterminate)]
pub struct ArgMismatchIndeterminate {
@ -396,6 +533,15 @@ pub struct SuggestPtrNullMut {
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(hir_typeck_trivial_cast)]
#[help]
pub struct TrivialCast<'tcx> {
pub numeric: bool,
pub expr_ty: Ty<'tcx>,
pub cast_ty: Ty<'tcx>,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_no_associated_item, code = "E0599")]
pub struct NoAssociatedItem {
@ -418,6 +564,74 @@ pub struct CandidateTraitNote {
pub action_or_ty: String,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")]
pub struct CannotCastToBool<'tcx> {
#[primary_span]
pub span: Span,
pub expr_ty: Ty<'tcx>,
#[subdiagnostic]
pub help: CannotCastToBoolHelp,
}
#[derive(LintDiagnostic)]
#[diag(hir_typeck_cast_enum_drop)]
pub struct CastEnumDrop<'tcx> {
pub expr_ty: Ty<'tcx>,
pub cast_ty: Ty<'tcx>,
}
#[derive(Diagnostic)]
#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")]
pub struct CastUnknownPointer {
#[primary_span]
pub span: Span,
pub to: bool,
#[subdiagnostic]
pub sub: CastUnknownPointerSub,
}
pub enum CastUnknownPointerSub {
To(Span),
From(Span),
}
impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub {
fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, f: F)
where
F: Fn(
&mut Diagnostic,
rustc_errors::SubdiagnosticMessage,
) -> rustc_errors::SubdiagnosticMessage,
{
match self {
CastUnknownPointerSub::To(span) => {
let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into());
diag.span_label(span, msg);
let msg = f(diag, crate::fluent_generated::hir_typeck_note.into());
diag.note(msg);
}
CastUnknownPointerSub::From(span) => {
let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into());
diag.span_label(span, msg);
}
}
}
}
#[derive(Subdiagnostic)]
pub enum CannotCastToBoolHelp {
#[suggestion(
hir_typeck_suggestion,
applicability = "machine-applicable",
code = " != 0",
style = "verbose"
)]
Numeric(#[primary_span] Span),
#[label(hir_typeck_label)]
Unsupported(#[primary_span] Span),
}
#[derive(Diagnostic)]
#[diag(hir_typeck_ctor_is_private, code = "E0603")]
pub struct CtorIsPrivate {
@ -426,6 +640,14 @@ pub struct CtorIsPrivate {
pub def: String,
}
#[derive(Subdiagnostic)]
#[note(hir_typeck_deref_is_empty)]
pub struct DerefImplsIsEmpty {
#[primary_span]
pub span: Span,
pub deref_ty: String,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
hir_typeck_convert_using_method,

View File

@ -195,7 +195,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id);
let mut delegate = InferBorrowKind {
fcx: self,
closure_def_id,
capture_information: Default::default(),
fake_reads: Default::default(),
@ -1607,34 +1606,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Truncate the capture so that the place being borrowed is in accordance with RFC 1240,
/// which states that it's unsafe to take a reference into a struct marked `repr(packed)`.
fn restrict_repr_packed_field_ref_capture<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
mut place: Place<'tcx>,
mut curr_borrow_kind: ty::UpvarCapture,
) -> (Place<'tcx>, ty::UpvarCapture) {
let pos = place.projections.iter().enumerate().position(|(i, p)| {
let ty = place.ty_before_projection(i);
// Return true for fields of packed structs, unless those fields have alignment 1.
// Return true for fields of packed structs.
match p.kind {
ProjectionKind::Field(..) => match ty.kind() {
ty::Adt(def, _) if def.repr().packed() => {
// We erase regions here because they cannot be hashed
match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) {
Ok(layout) if layout.align.abi.bytes() == 1 => {
// if the alignment is 1, the type can't be further
// disaligned.
debug!(
"restrict_repr_packed_field_ref_capture: ({:?}) - align = 1",
place
);
false
}
_ => {
debug!("restrict_repr_packed_field_ref_capture: ({:?}) - true", place);
true
}
}
// We stop here regardless of field alignment. Field alignment can change as
// types change, including the types of private fields in other crates, and that
// shouldn't affect how we compute our captures.
true
}
_ => false,
@ -1689,9 +1674,7 @@ fn drop_location_span(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> Span {
tcx.sess.source_map().end_point(owner_span)
}
struct InferBorrowKind<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
struct InferBorrowKind<'tcx> {
// The def-id of the closure whose kind and upvar accesses are being inferred.
closure_def_id: LocalDefId,
@ -1725,7 +1708,7 @@ struct InferBorrowKind<'a, 'tcx> {
fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
}
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> {
fn fake_read(
&mut self,
place: &PlaceWithHirId<'tcx>,
@ -1740,12 +1723,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind);
let (place, _) = restrict_repr_packed_field_ref_capture(
self.fcx.tcx,
self.fcx.param_env,
place,
dummy_capture_kind,
);
let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind);
self.fake_reads.push((place, cause, diag_expr_id));
}
@ -1780,12 +1758,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
// We only want repr packed restriction to be applied to reading references into a packed
// struct, and not when the data is being moved. Therefore we call this method here instead
// of in `restrict_capture_precision`.
let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(
self.fcx.tcx,
self.fcx.param_env,
place_with_id.place.clone(),
capture_kind,
);
let (place, mut capture_kind) =
restrict_repr_packed_field_ref_capture(place_with_id.place.clone(), capture_kind);
// Raw pointers don't inherit mutability
if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) {

View File

@ -385,7 +385,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
let highlight_trait_ref = |trait_ref| Highlighted {
tcx: self.tcx(),
highlight: RegionHighlightMode::new(self.tcx()),
highlight: RegionHighlightMode::default(),
value: trait_ref,
};

View File

@ -67,9 +67,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
impl<'tcx> HighlightBuilder<'tcx> {
fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
fn build(ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
let mut builder =
HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
builder.visit_ty(ty);
builder.highlight
}
@ -85,12 +85,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
}
let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
let expected_highlight = HighlightBuilder::build(expected);
let expected = self
.cx
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
.name;
let found_highlight = HighlightBuilder::build(self.tcx(), found);
let found_highlight = HighlightBuilder::build(found);
let found =
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;

View File

@ -4,7 +4,7 @@
//! and use that to decide when one free region outlives another, and so forth.
use rustc_data_structures::transitive_relation::TransitiveRelation;
use rustc_middle::ty::{Lift, Region, TyCtxt};
use rustc_middle::ty::{Region, TyCtxt};
/// Combines a `FreeRegionMap` and a `TyCtxt`.
///
@ -101,10 +101,3 @@ impl<'tcx> FreeRegionMap<'tcx> {
result
}
}
impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> {
type Lifted = FreeRegionMap<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<FreeRegionMap<'tcx>> {
self.relation.maybe_map(|fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation })
}
}

View File

@ -1600,9 +1600,12 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
if let Err(e) = ct.error_reported() {
return Err(ErrorHandled::Reported(e.into()));
return Err(ErrorHandled::Reported(
e.into(),
span.unwrap_or(rustc_span::DUMMY_SP),
));
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
return Err(ErrorHandled::TooGeneric);
return Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP)));
} else {
args = replace_param_and_infer_args_with_placeholder(tcx, args);
}

View File

@ -568,6 +568,13 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
) {
sess.emit_fatal(errors::MultipleOutputTypesToStdout);
}
let crate_name = sess
.opts
.crate_name
.clone()
.or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()));
match sess.io.output_file {
None => {
// "-" as input file will cause the parser to read from stdin so we
@ -576,15 +583,11 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
let dirpath = sess.io.output_dir.clone().unwrap_or_default();
// If a crate name is present, we use it as the link name
let stem = sess
.opts
.crate_name
.clone()
.or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()))
.unwrap_or_else(|| sess.io.input.filestem().to_owned());
let stem = crate_name.clone().unwrap_or_else(|| sess.io.input.filestem().to_owned());
OutputFilenames::new(
dirpath,
crate_name.unwrap_or_else(|| stem.replace('-', "_")),
stem,
None,
sess.io.temps_dir.clone(),
@ -609,9 +612,12 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
sess.emit_warning(errors::IgnoringOutDir);
}
let out_filestem =
out_file.filestem().unwrap_or_default().to_str().unwrap().to_string();
OutputFilenames::new(
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(),
crate_name.unwrap_or_else(|| out_filestem.replace('-', "_")),
out_filestem,
ofile,
sess.io.temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),

View File

@ -453,6 +453,8 @@ lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking th
.help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
.label = expression has type `{$orig_ty}`
lint_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is never null, so checking it for null will always return false
lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false
.label = expression has type `{$orig_ty}`

View File

@ -635,6 +635,8 @@ pub enum PtrNullChecksDiag<'a> {
#[label]
label: Span,
},
#[diag(lint_ptr_null_checks_fn_ret)]
FnRet { fn_name: Ident },
}
// for_loops_over_fallibles.rs

View File

@ -31,12 +31,30 @@ declare_lint! {
declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]);
/// This function detects and returns the original expression from a series of consecutive casts,
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`.
fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
/// This function checks if the expression is from a series of consecutive casts,
/// ie. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either
/// a fn ptr, a reference, or a function call whose definition is
/// annotated with `#![rustc_never_returns_null_ptr]`.
/// If this situation is present, the function returns the appropriate diagnostic.
fn incorrect_check<'a, 'tcx: 'a>(
cx: &'a LateContext<'tcx>,
mut e: &'a Expr<'a>,
) -> Option<PtrNullChecksDiag<'tcx>> {
let mut had_at_least_one_cast = false;
loop {
e = e.peel_blocks();
if let ExprKind::MethodCall(_, _expr, [], _) = e.kind
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
return Some(PtrNullChecksDiag::FnRet { fn_name });
} else if let ExprKind::Call(path, _args) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
return Some(PtrNullChecksDiag::FnRet { fn_name });
}
e = if let ExprKind::Cast(expr, t) = e.kind
&& let TyKind::Ptr(_) = t.kind {
had_at_least_one_cast = true;
@ -46,33 +64,21 @@ fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
had_at_least_one_cast = true;
expr
} else if let ExprKind::Call(path, [arg]) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_from_ref | sym::ptr_from_mut)) {
had_at_least_one_cast = true;
arg
} else if had_at_least_one_cast {
return Some(e);
let orig_ty = cx.typeck_results().expr_ty(e);
return if orig_ty.is_fn() {
Some(PtrNullChecksDiag::FnPtr { orig_ty, label: e.span })
} else if orig_ty.is_ref() {
Some(PtrNullChecksDiag::Ref { orig_ty, label: e.span })
} else {
None
};
} else {
return None;
};
}
}
fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option<PtrNullChecksDiag<'a>> {
let expr = ptr_cast_chain(cx, expr)?;
let orig_ty = cx.typeck_results().expr_ty(expr);
if orig_ty.is_fn() {
Some(PtrNullChecksDiag::FnPtr { orig_ty, label: expr.span })
} else if orig_ty.is_ref() {
Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span })
} else {
None
}
}
impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
match expr.kind {

View File

@ -3405,8 +3405,8 @@ declare_lint_pass! {
UNFULFILLED_LINT_EXPECTATIONS,
UNINHABITED_STATIC,
UNKNOWN_CRATE_TYPES,
UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
UNKNOWN_LINTS,
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
UNNAMEABLE_TEST_ITEMS,
UNNAMEABLE_TYPES,
UNREACHABLE_CODE,
@ -4420,7 +4420,8 @@ declare_lint! {
}
declare_lint! {
/// The `unknown_diagnostic_attributes` lint detects unrecognized diagnostic attributes.
/// The `unknown_or_malformed_diagnostic_attributes` lint detects unrecognized or otherwise malformed
/// diagnostic attributes.
///
/// ### Example
///
@ -4432,15 +4433,17 @@ declare_lint! {
///
/// {{produces}}
///
///
/// ### Explanation
///
/// It is usually a mistake to specify a diagnostic attribute that does not exist. Check
/// the spelling, and check the diagnostic attribute listing for the correct name. Also
/// consider if you are using an old version of the compiler, and the attribute
/// is only available in a newer version.
pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES,
pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
Warn,
"unrecognized diagnostic attribute"
"unrecognized or malformed diagnostic attribute",
@feature_gate = sym::diagnostic_namespace;
}
declare_lint! {

View File

@ -239,16 +239,22 @@ enum class LLVMRustCodeGenOptLevel {
Aggressive,
};
static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) {
#if LLVM_VERSION_GE(18, 0)
using CodeGenOptLevelEnum = llvm::CodeGenOptLevel;
#else
using CodeGenOptLevelEnum = llvm::CodeGenOpt::Level;
#endif
static CodeGenOptLevelEnum fromRust(LLVMRustCodeGenOptLevel Level) {
switch (Level) {
case LLVMRustCodeGenOptLevel::None:
return CodeGenOpt::None;
return CodeGenOptLevelEnum::None;
case LLVMRustCodeGenOptLevel::Less:
return CodeGenOpt::Less;
return CodeGenOptLevelEnum::Less;
case LLVMRustCodeGenOptLevel::Default:
return CodeGenOpt::Default;
return CodeGenOptLevelEnum::Default;
case LLVMRustCodeGenOptLevel::Aggressive:
return CodeGenOpt::Aggressive;
return CodeGenOptLevelEnum::Aggressive;
default:
report_fatal_error("Bad CodeGenOptLevel.");
}
@ -554,9 +560,17 @@ enum class LLVMRustFileType {
static CodeGenFileType fromRust(LLVMRustFileType Type) {
switch (Type) {
case LLVMRustFileType::AssemblyFile:
#if LLVM_VERSION_GE(18, 0)
return CodeGenFileType::AssemblyFile;
#else
return CGFT_AssemblyFile;
#endif
case LLVMRustFileType::ObjectFile:
#if LLVM_VERSION_GE(18, 0)
return CodeGenFileType::ObjectFile;
#else
return CGFT_ObjectFile;
#endif
default:
report_fatal_error("Bad FileType.");
}

View File

@ -5,7 +5,6 @@ use crate::errors::{
use crate::{encode_metadata, EncodedMetadata};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OutFileName, OutputType};
use rustc_session::output::filename_for_metadata;
@ -40,8 +39,7 @@ pub fn emit_wrapper_file(
}
pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
let crate_name = tcx.crate_name(LOCAL_CRATE);
let out_filename = filename_for_metadata(tcx.sess, crate_name, tcx.output_filenames(()));
let out_filename = filename_for_metadata(tcx.sess, tcx.output_filenames(()));
// To avoid races with another rustc process scanning the output directory,
// we need to write the file somewhere else and atomically move it to its
// final destination, with an `fs::rename` call. In order for the rename to

View File

@ -52,6 +52,8 @@ middle_drop_check_overflow =
overflow while adding drop-check rules for {$ty}
.note = overflowed on {$overflow_ty}
middle_erroneous_constant = erroneous constant encountered
middle_layout_references_error =
the type has an unknown layout

View File

@ -144,5 +144,12 @@ pub struct UnsupportedFnAbi {
pub abi: &'static str,
}
#[derive(Diagnostic)]
#[diag(middle_erroneous_constant)]
pub struct ErroneousConstant {
#[primary_span]
pub span: Span,
}
/// Used by `rustc_const_eval`
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;

View File

@ -34,7 +34,7 @@ use std::ops::Index;
/// variables have been rewritten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct Canonical<'tcx, V> {
pub value: V,
pub max_universe: ty::UniverseIndex,
@ -72,7 +72,7 @@ impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: ty::GenericArgsRef<'tcx>,
}
@ -311,7 +311,7 @@ pub enum CanonicalTyVarKind {
/// After we execute a query with a canonicalized key, we get back a
/// `Canonical<QueryResponse<..>>`. You can use
/// `instantiate_query_result` to access the data in this result.
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
@ -326,7 +326,7 @@ pub struct QueryResponse<'tcx, R> {
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct QueryRegionConstraints<'tcx> {
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
pub member_constraints: Vec<MemberConstraint<'tcx>>,
@ -432,7 +432,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
pub type QueryOutlivesConstraint<'tcx> =
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
TrivialTypeTraversalAndLiftImpls! {
TrivialTypeTraversalImpls! {
crate::infer::canonical::Certainty,
crate::infer::canonical::CanonicalTyVarKind,
}

View File

@ -13,7 +13,7 @@ use rustc_span::Span;
/// R0 member of [O1..On]
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct MemberConstraint<'tcx> {
/// The `DefId` and args of the opaque type causing this constraint.
/// Used for error reporting.

View File

@ -42,7 +42,7 @@ macro_rules! span_bug {
// the impls for you.
#[macro_export]
macro_rules! CloneLiftImpls {
macro_rules! TrivialLiftImpls {
($($ty:ty),+ $(,)?) => {
$(
impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
@ -96,6 +96,6 @@ macro_rules! TrivialTypeTraversalImpls {
macro_rules! TrivialTypeTraversalAndLiftImpls {
($($t:tt)*) => {
TrivialTypeTraversalImpls! { $($t)* }
CloneLiftImpls! { $($t)* }
TrivialLiftImpls! { $($t)* }
}
}

View File

@ -178,7 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
}
}
TrivialTypeTraversalAndLiftImpls! { Cache }
TrivialTypeTraversalImpls! { Cache }
impl<S: Encoder> Encodable<S> for Cache {
#[inline]

View File

@ -1,8 +1,9 @@
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
use crate::error;
use crate::mir::interpret::ConstValue;
use crate::query::TyCtxtAt;
use crate::ty::{layout, tls, Ty, ValTree};
use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
use rustc_data_structures::sync::Lock;
use rustc_errors::{
@ -11,7 +12,7 @@ use rustc_errors::{
};
use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace;
use rustc_span::def_id::DefId;
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
use std::borrow::Cow;
@ -21,16 +22,51 @@ use std::{any::Any, backtrace::Backtrace, fmt};
pub enum ErrorHandled {
/// Already reported an error for this evaluation, and the compilation is
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
Reported(ReportedErrorInfo),
Reported(ReportedErrorInfo, Span),
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the args didn't fully monomorphize it.
TooGeneric,
TooGeneric(Span),
}
impl From<ErrorGuaranteed> for ErrorHandled {
#[inline]
fn from(error: ErrorGuaranteed) -> ErrorHandled {
ErrorHandled::Reported(error.into())
ErrorHandled::Reported(error.into(), DUMMY_SP)
}
}
impl ErrorHandled {
pub fn with_span(self, span: Span) -> Self {
match self {
ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
}
}
pub fn emit_err(&self, tcx: TyCtxt<'_>) -> ErrorGuaranteed {
match self {
&ErrorHandled::Reported(err, span) => {
if !err.is_tainted_by_errors && !span.is_dummy() {
tcx.sess.emit_err(error::ErroneousConstant { span });
}
err.error
}
&ErrorHandled::TooGeneric(span) => tcx.sess.delay_span_bug(
span,
"encountered TooGeneric error when monomorphic data was expected",
),
}
}
pub fn emit_note(&self, tcx: TyCtxt<'_>) {
match self {
&ErrorHandled::Reported(err, span) => {
if !err.is_tainted_by_errors && !span.is_dummy() {
tcx.sess.emit_note(error::ErroneousConstant { span });
}
}
&ErrorHandled::TooGeneric(_) => {}
}
}
}
@ -45,12 +81,6 @@ impl ReportedErrorInfo {
pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
ReportedErrorInfo { is_tainted_by_errors: true, error }
}
/// Returns true if evaluation failed because MIR was tainted by errors.
#[inline]
pub fn is_tainted_by_errors(self) -> bool {
self.is_tainted_by_errors
}
}
impl From<ErrorGuaranteed> for ReportedErrorInfo {
@ -67,7 +97,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
}
}
TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
TrivialTypeTraversalImpls! { ErrorHandled }
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
@ -162,6 +192,16 @@ impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
}
}
impl From<ErrorHandled> for InterpErrorInfo<'_> {
fn from(err: ErrorHandled) -> Self {
InterpError::InvalidProgram(match err {
ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
})
.into()
}
}
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self {
InterpErrorInfo(Box::new(InterpErrorInfoInner {

View File

@ -162,7 +162,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
/// - A constant
/// - A static
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct GlobalId<'tcx> {
/// For a constant or static, the `Instance` of the item itself.
/// For a promoted global, the `Instance` of the function they belong to.

View File

@ -61,8 +61,10 @@ impl<'tcx> TyCtxt<'tcx> {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
}
Ok(None) => Err(ErrorHandled::TooGeneric),
Err(err) => Err(ErrorHandled::Reported(err.into())),
// For errors during resolution, we deliberately do not point at the usage site of the constant,
// since for these errors the place the constant is used shouldn't matter.
Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
}
}
@ -117,8 +119,10 @@ impl<'tcx> TyCtxt<'tcx> {
}
})
}
Ok(None) => Err(ErrorHandled::TooGeneric),
Err(err) => Err(ErrorHandled::Reported(err.into())),
// For errors during resolution, we deliberately do not point at the usage site of the constant,
// since for these errors the place the constant is used shouldn't matter.
Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
}
}
@ -143,7 +147,8 @@ impl<'tcx> TyCtxt<'tcx> {
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
if let Some(span) = span {
self.at(span).eval_to_const_value_raw(inputs)
// The query doesn't know where it is being invoked, so we need to fix the span.
self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_const_value_raw(inputs)
}
@ -162,7 +167,8 @@ impl<'tcx> TyCtxt<'tcx> {
let inputs = self.erase_regions(param_env.and(cid));
debug!(?inputs);
if let Some(span) = span {
self.at(span).eval_to_valtree(inputs)
// The query doesn't know where it is being invoked, so we need to fix the span.
self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_valtree(inputs)
}

View File

@ -565,6 +565,34 @@ impl<'tcx> Body<'tcx> {
pub fn is_custom_mir(&self) -> bool {
self.injection_phase.is_some()
}
/// *Must* be called once the full substitution for this body is known, to ensure that the body
/// is indeed fit for code generation or consumption more generally.
///
/// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for
/// constants specifically. (`Option<GenericArgsRef>` could be used for that, but the fact
/// that `Instance::args_for_mir_body` is private and instead instance exposes normalization
/// functions makes it seem like exposing the generic args is not the intended strategy.)
///
/// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic,
/// so we cannot just immediately ICE on TooGeneric.
///
/// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported.
pub fn post_mono_checks(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
) -> Result<(), ErrorHandled> {
// For now, the only thing we have to check is is to ensure that all the constants used in
// the body successfully evaluate.
for &const_ in &self.required_consts {
let c = normalize_const(const_.literal)?;
c.eval(tcx, param_env, Some(const_.span))?;
}
Ok(())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@ -744,7 +772,7 @@ pub enum BindingForm<'tcx> {
RefForGuard,
}
TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
TrivialTypeTraversalImpls! { BindingForm<'tcx> }
mod binding_form_impl {
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@ -2295,7 +2323,7 @@ pub struct Constant<'tcx> {
}
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
#[derive(Lift, TypeFoldable, TypeVisitable)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum ConstantKind<'tcx> {
/// This constant came from the type system.
///
@ -2397,10 +2425,10 @@ impl<'tcx> ConstantKind<'tcx> {
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, None) {
Ok(val) => Self::Val(val, self.ty()),
Err(ErrorHandled::Reported(guar)) => {
Err(ErrorHandled::Reported(guar, _span)) => {
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
}
Err(ErrorHandled::TooGeneric) => self,
Err(ErrorHandled::TooGeneric(_span)) => self,
}
}
@ -2615,7 +2643,7 @@ impl<'tcx> ConstantKind<'tcx> {
}
/// An unevaluated (potentially generic) constant used in MIR.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct UnevaluatedConst<'tcx> {
pub def: DefId,

View File

@ -334,7 +334,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
///
/// See also `rustc_const_eval::borrow_check::constraints`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
pub enum ConstraintCategory<'tcx> {
Return(ReturnConstraint),
Yield,

View File

@ -5,7 +5,7 @@ use rustc_ast::InlineAsmTemplatePiece;
use super::*;
use crate::ty;
TrivialTypeTraversalAndLiftImpls! {
TrivialTypeTraversalImpls! {
BlockTailInfo,
MirPhase,
SourceInfo,

View File

@ -1140,6 +1140,7 @@ rustc_queries! {
query reachable_set(_: ()) -> &'tcx LocalDefIdSet {
arena_cache
desc { "reachability" }
cache_on_disk_if { true }
}
/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;

View File

@ -13,7 +13,7 @@ use crate::infer::canonical::Canonical;
use crate::mir::ConstraintCategory;
use crate::ty::abstract_const::NotConstEvaluatable;
use crate::ty::GenericArgsRef;
use crate::ty::{self, AdtKind, Ty, TyCtxt};
use crate::ty::{self, AdtKind, Ty};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, Diagnostic};
@ -86,7 +86,7 @@ pub enum Reveal {
///
/// We do not want to intern this as there are a lot of obligation causes which
/// only live for a short period of time.
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ObligationCause<'tcx> {
pub span: Span,
@ -194,7 +194,7 @@ impl<'tcx> ObligationCause<'tcx> {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct UnifyReceiverContext<'tcx> {
pub assoc_item: ty::AssocItem,
@ -202,7 +202,7 @@ pub struct UnifyReceiverContext<'tcx> {
pub args: GenericArgsRef<'tcx>,
}
#[derive(Clone, PartialEq, Eq, Lift, Default, HashStable)]
#[derive(Clone, PartialEq, Eq, Default, HashStable)]
#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
pub struct InternedObligationCauseCode<'tcx> {
/// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
@ -238,7 +238,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
}
}
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from the span.
@ -470,7 +470,7 @@ pub enum WellFormedLoc {
},
}
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedObligationCause<'tcx> {
pub derived: DerivedObligationCause<'tcx>,
@ -524,14 +524,7 @@ pub enum StatementAsExpression {
NeedsBoxing,
}
impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
type Lifted = StatementAsExpression;
fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option<StatementAsExpression> {
Some(self)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_block_id: Option<hir::HirId>,
@ -547,7 +540,7 @@ pub struct MatchExpressionArmCause<'tcx> {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
pub struct IfExpressionCause<'tcx> {
pub then_id: hir::HirId,
pub else_id: hir::HirId,
@ -557,7 +550,7 @@ pub struct IfExpressionCause<'tcx> {
pub opt_suggest_box_span: Option<Span>,
}
#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct DerivedObligationCause<'tcx> {
/// The trait predicate of the parent obligation that led to the
@ -570,7 +563,7 @@ pub struct DerivedObligationCause<'tcx> {
pub parent_code: InternedObligationCauseCode<'tcx>,
}
#[derive(Clone, Debug, TypeVisitable, Lift)]
#[derive(Clone, Debug, TypeVisitable)]
pub enum SelectionError<'tcx> {
/// The trait is not implemented.
Unimplemented,
@ -593,7 +586,7 @@ pub enum SelectionError<'tcx> {
OpaqueTypeAutoTraitLeakageUnknown(DefId),
}
#[derive(Clone, Debug, TypeVisitable, Lift)]
#[derive(Clone, Debug, TypeVisitable)]
pub struct SelectionOutputTypeParameterMismatch<'tcx> {
pub found_trait_ref: ty::PolyTraitRef<'tcx>,
pub expected_trait_ref: ty::PolyTraitRef<'tcx>,
@ -638,7 +631,7 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
/// ### The type parameter `N`
///
/// See explanation on `ImplSourceUserDefinedData`.
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum ImplSource<'tcx, N> {
/// ImplSource identifying a particular impl.
@ -704,7 +697,7 @@ impl<'tcx, N> ImplSource<'tcx, N> {
/// is `Obligation`, as one might expect. During codegen, however, this
/// is `()`, because codegen only requires a shallow resolution of an
/// impl, and nested obligations are satisfied later.
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceUserDefinedData<'tcx, N> {
pub impl_def_id: DefId,
@ -736,7 +729,7 @@ pub enum BuiltinImplSource {
TupleUnsizing,
}
TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
TrivialTypeTraversalImpls! { BuiltinImplSource }
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
pub enum ObjectSafetyViolation {

View File

@ -17,8 +17,7 @@ pub mod type_op {
use crate::ty::{Predicate, Ty, TyCtxt, UserType};
use std::fmt;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'tcx>,
pub user_ty: UserType<'tcx>,
@ -30,22 +29,19 @@ pub mod type_op {
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct Eq<'tcx> {
pub a: Ty<'tcx>,
pub b: Ty<'tcx>,
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct Subtype<'tcx> {
pub sub: Ty<'tcx>,
pub sup: Ty<'tcx>,
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct ProvePredicate<'tcx> {
pub predicate: Predicate<'tcx>,
}
@ -56,8 +52,7 @@ pub mod type_op {
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)]
pub struct Normalize<T> {
pub value: T,
}
@ -101,7 +96,7 @@ impl<'tcx> From<TypeError<'tcx>> for NoSolution {
}
}
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)]
pub struct DropckOutlivesResult<'tcx> {
pub kinds: Vec<GenericArg<'tcx>>,
pub overflows: Vec<Ty<'tcx>>,
@ -194,7 +189,7 @@ pub struct MethodAutoderefBadTy<'tcx> {
}
/// Result from the `normalize_projection_ty` query.
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct NormalizationResult<'tcx> {
/// Result of normalization.
pub normalized_ty: Ty<'tcx>,
@ -207,7 +202,7 @@ pub struct NormalizationResult<'tcx> {
/// case they are called implied bounds). They are fed to the
/// `OutlivesEnv` which in turn is supplied to the region checker and
/// other parts of the inference system.
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift, HashStable)]
#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)]
pub enum OutlivesBound<'tcx> {
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),

View File

@ -305,7 +305,7 @@ impl From<ErrorGuaranteed> for OverflowError {
}
}
TrivialTypeTraversalAndLiftImpls! { OverflowError }
TrivialTypeTraversalImpls! { OverflowError }
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {

View File

@ -14,10 +14,16 @@ pub enum CacheHit {
Global,
}
#[derive(Eq, PartialEq)]
pub enum GoalEvaluationKind {
Root,
Nested { is_normalizes_to_hack: IsNormalizesToHack },
}
#[derive(Eq, PartialEq)]
pub struct GoalEvaluation<'tcx> {
pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
pub is_normalizes_to_hack: IsNormalizesToHack,
pub kind: GoalEvaluationKind,
pub evaluation: CanonicalGoalEvaluation<'tcx>,
pub returned_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
}
@ -25,12 +31,12 @@ pub struct GoalEvaluation<'tcx> {
#[derive(Eq, PartialEq)]
pub struct CanonicalGoalEvaluation<'tcx> {
pub goal: CanonicalInput<'tcx>,
pub kind: GoalEvaluationKind<'tcx>,
pub kind: CanonicalGoalEvaluationKind<'tcx>,
pub result: QueryResult<'tcx>,
}
#[derive(Eq, PartialEq)]
pub enum GoalEvaluationKind<'tcx> {
pub enum CanonicalGoalEvaluationKind<'tcx> {
Overflow,
CacheHit(CacheHit),
Uncached { revisions: Vec<GoalEvaluationStep<'tcx>> },
@ -52,22 +58,31 @@ pub struct GoalEvaluationStep<'tcx> {
pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
/// The actual evaluation of the goal, always `ProbeKind::Root`.
pub evaluation: GoalCandidate<'tcx>,
pub evaluation: Probe<'tcx>,
}
/// A self-contained computation during trait solving. This either
/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
/// of a goal.
#[derive(Eq, PartialEq)]
pub struct GoalCandidate<'tcx> {
pub added_goals_evaluations: Vec<AddedGoalsEvaluation<'tcx>>,
pub candidates: Vec<GoalCandidate<'tcx>>,
pub struct Probe<'tcx> {
pub steps: Vec<ProbeStep<'tcx>>,
pub kind: ProbeKind<'tcx>,
}
impl Debug for GoalCandidate<'_> {
impl Debug for Probe<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
ProofTreeFormatter::new(f).format_candidate(self)
ProofTreeFormatter::new(f).format_probe(self)
}
}
#[derive(Eq, PartialEq)]
pub enum ProbeStep<'tcx> {
AddGoal(Goal<'tcx, ty::Predicate<'tcx>>),
EvaluateGoals(AddedGoalsEvaluation<'tcx>),
NestedProbe(Probe<'tcx>),
}
#[derive(Debug, PartialEq, Eq)]
pub enum ProbeKind<'tcx> {
/// The root inference context while proving a goal.

View File

@ -40,9 +40,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
}
pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
let goal_text = match eval.is_normalizes_to_hack {
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
IsNormalizesToHack::No => "GOAL",
let goal_text = match eval.kind {
GoalEvaluationKind::Root => "ROOT GOAL",
GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack {
IsNormalizesToHack::No => "GOAL",
IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL",
},
};
writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?;
self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?;
@ -68,16 +71,16 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
writeln!(self.f, "GOAL: {:?}", eval.goal)?;
match &eval.kind {
GoalEvaluationKind::Overflow => {
CanonicalGoalEvaluationKind::Overflow => {
writeln!(self.f, "OVERFLOW: {:?}", eval.result)
}
GoalEvaluationKind::CacheHit(CacheHit::Global) => {
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => {
writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result)
}
GoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => {
writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result)
}
GoalEvaluationKind::Uncached { revisions } => {
CanonicalGoalEvaluationKind::Uncached { revisions } => {
for (n, step) in revisions.iter().enumerate() {
writeln!(self.f, "REVISION {n}")?;
self.nested(|this| this.format_evaluation_step(step))?;
@ -92,11 +95,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
evaluation_step: &GoalEvaluationStep<'_>,
) -> std::fmt::Result {
writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
self.format_candidate(&evaluation_step.evaluation)
self.format_probe(&evaluation_step.evaluation)
}
pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result {
match &candidate.kind {
pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
match &probe.kind {
ProbeKind::Root { result } => {
writeln!(self.f, "ROOT RESULT: {result:?}")
}
@ -118,11 +121,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
}?;
self.nested(|this| {
for candidate in &candidate.candidates {
this.format_candidate(candidate)?;
}
for nested in &candidate.added_goals_evaluations {
this.format_added_goals_evaluation(nested)?;
for step in &probe.steps {
match step {
ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?,
ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?,
ProbeStep::NestedProbe(probe) => this.format_probe(probe)?,
}
}
Ok(())
})

View File

@ -27,7 +27,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
}
}
TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable }
TrivialTypeTraversalImpls! { NotConstEvaluatable }
pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;

View File

@ -76,7 +76,7 @@ pub enum PointerCoercion {
/// At some point, of course, `Box` should move out of the compiler, in which
/// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
/// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct Adjustment<'tcx> {
pub kind: Adjust<'tcx>,
pub target: Ty<'tcx>,
@ -88,7 +88,7 @@ impl<'tcx> Adjustment<'tcx> {
}
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub enum Adjust<'tcx> {
/// Go from ! to any type.
NeverToAny,
@ -110,7 +110,7 @@ pub enum Adjust<'tcx> {
/// The target type is `U` in both cases, with the region and mutability
/// being those shared by both the receiver and the returned reference.
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct OverloadedDeref<'tcx> {
pub region: ty::Region<'tcx>,
pub mutbl: hir::Mutability,
@ -182,7 +182,7 @@ impl From<AutoBorrowMutability> for hir::Mutability {
}
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum AutoBorrow<'tcx> {
/// Converts from T to &T.
Ref(ty::Region<'tcx>, AutoBorrowMutability),

View File

@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> {
}
Err(err) => {
let msg = match err {
ErrorHandled::Reported(_) => "enum discriminant evaluation failed",
ErrorHandled::TooGeneric => "enum discriminant depends on generics",
ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
};
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
None

View File

@ -6,7 +6,7 @@ pub enum BindingMode {
BindByValue(Mutability),
}
TrivialTypeTraversalAndLiftImpls! { BindingMode }
TrivialTypeTraversalImpls! { BindingMode }
impl BindingMode {
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {

View File

@ -300,7 +300,7 @@ impl<'tcx> Const<'tcx> {
| ConstKind::Infer(_)
| ConstKind::Bound(_, _)
| ConstKind::Placeholder(_)
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
}
}
@ -309,8 +309,8 @@ impl<'tcx> Const<'tcx> {
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, None) {
Ok(val) => Self::new_value(tcx, val, self.ty()),
Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
Err(ErrorHandled::TooGeneric) => self,
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
Err(ErrorHandled::TooGeneric(_span)) => self,
}
}

View File

@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
/// An unevaluated (potentially generic) constant used in the type-system.
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct UnevaluatedConst<'tcx> {
pub def: DefId,

View File

@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{Constness, HirId, Node, TraitCandidate};
use rustc_hir::{HirId, Node, TraitCandidate};
use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::dep_graph::DepNodeIndex;
@ -82,6 +82,7 @@ use std::ops::{Bound, Deref};
impl<'tcx> Interner for TyCtxt<'tcx> {
type AdtDef = ty::AdtDef<'tcx>;
type GenericArgsRef = ty::GenericArgsRef<'tcx>;
type GenericArg = ty::GenericArg<'tcx>;
type DefId = DefId;
type Binder<T> = Binder<'tcx, T>;
type Ty = Ty<'tcx>;
@ -1214,6 +1215,25 @@ macro_rules! nop_lift {
impl<'a, 'tcx> Lift<'tcx> for $ty {
type Lifted = $lifted;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
// Assert that the set has the right type.
// Given an argument that has an interned type, the return type has the type of
// the corresponding interner set. This won't actually return anything, we're
// just doing this to compute said type!
fn _intern_set_ty_from_interned_ty<'tcx, Inner>(
_x: Interned<'tcx, Inner>,
) -> InternedSet<'tcx, Inner> {
unreachable!()
}
fn _type_eq<T>(_x: &T, _y: &T) {}
fn _test<'tcx>(x: $lifted, tcx: TyCtxt<'tcx>) {
// If `x` is a newtype around an `Interned<T>`, then `interner` is an
// interner of appropriate type. (Ideally we'd also check that `x` is a
// newtype with just that one field. Not sure how to do that.)
let interner = _intern_set_ty_from_interned_ty(x.0);
// Now check that this is the same type as `interners.$set`.
_type_eq(&interner, &tcx.interners.$set);
}
tcx.interners
.$set
.contains_pointer_to(&InternedInSet(&*self.0.0))
@ -1230,6 +1250,11 @@ macro_rules! nop_list_lift {
impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
type Lifted = &'tcx List<$lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
// Assert that the set has the right type.
if false {
let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set;
}
if self.is_empty() {
return Some(List::empty());
}
@ -1251,19 +1276,13 @@ nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>}
nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>}
nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>}
nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
nop_list_lift! {projs; ProjectionKind => ProjectionKind}
nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
// This is the impl for `&'a GenericArgs<'a>`.
nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>}
CloneLiftImpls! {
Constness,
traits::WellFormedLoc,
TrivialLiftImpls! {
ImplPolarity,
crate::mir::ReturnConstraint,
}
macro_rules! sty_debug_print {

View File

@ -11,7 +11,7 @@ use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::path::PathBuf;
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
pub struct ExpectedFound<T> {
pub expected: T,
pub found: T,
@ -28,7 +28,7 @@ impl<T> ExpectedFound<T> {
}
// Data structures used in type unification
#[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)]
#[rustc_pass_by_value]
pub enum TypeError<'tcx> {
Mismatch,

View File

@ -1029,7 +1029,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> {
/// Stores the user-given args to reach some fully qualified path
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct UserArgs<'tcx> {
/// The args for the item as given by the user.
pub args: GenericArgsRef<'tcx>,
@ -1056,7 +1056,7 @@ pub struct UserArgs<'tcx> {
/// the self type, giving `Foo<?A>`. Finally, we unify that with
/// the self type here, which contains `?A` to be `&'static u32`
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct UserSelfTy<'tcx> {
pub impl_def_id: DefId,
pub self_ty: Ty<'tcx>,

View File

@ -18,6 +18,9 @@ use std::fmt;
/// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type
/// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval
/// will do all required substitution as they run.
///
/// Note: the `Lift` impl is currently not used by rustc, but is used by
/// rustc_codegen_cranelift when the `jit` feature is enabled.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
pub struct Instance<'tcx> {

View File

@ -1510,7 +1510,7 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct OpaqueTypeKey<'tcx> {
pub def_id: LocalDefId,
@ -1793,7 +1793,7 @@ impl<'tcx> ParamEnv<'tcx> {
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
#[derive(HashStable, Lift)]
#[derive(HashStable)]
pub struct ParamEnvAnd<'tcx, T> {
pub param_env: ParamEnv<'tcx>,
pub value: T,
@ -2408,6 +2408,22 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
pub fn get_attrs_by_path<'attr>(
self,
did: DefId,
attr: &'attr [Symbol],
) -> impl Iterator<Item = &'tcx ast::Attribute> + 'attr
where
'tcx: 'attr,
{
let filter_fn = move |a: &&ast::Attribute| a.path_matches(&attr);
if let Some(did) = did.as_local() {
self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else {
self.item_attrs(did).iter().filter(filter_fn)
}
}
pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> {
if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
let did: DefId = did.into();

View File

@ -136,10 +136,8 @@ define_helper!(
///
/// Regions not selected by the region highlight mode are presently
/// unaffected.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Default)]
pub struct RegionHighlightMode<'tcx> {
tcx: TyCtxt<'tcx>,
/// If enabled, when we see the selected region, use "`'N`"
/// instead of the ordinary behavior.
highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
@ -155,14 +153,6 @@ pub struct RegionHighlightMode<'tcx> {
}
impl<'tcx> RegionHighlightMode<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
Self {
tcx,
highlight_regions: Default::default(),
highlight_bound_region: Default::default(),
}
}
/// If `region` and `number` are both `Some`, invokes
/// `highlighting_region`.
pub fn maybe_highlighting_region(
@ -188,8 +178,13 @@ impl<'tcx> RegionHighlightMode<'tcx> {
}
/// Convenience wrapper for `highlighting_region`.
pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
self.highlighting_region(ty::Region::new_var(self.tcx, vid), number)
pub fn highlighting_region_vid(
&mut self,
tcx: TyCtxt<'tcx>,
vid: ty::RegionVid,
number: usize,
) {
self.highlighting_region(ty::Region::new_var(tcx, vid), number)
}
/// Returns `Some(n)` with the number to use for the given region, if any.
@ -1778,7 +1773,7 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
printed_type_count: 0,
type_length_limit,
truncated: false,
region_highlight_mode: RegionHighlightMode::new(tcx),
region_highlight_mode: RegionHighlightMode::default(),
ty_infer_name_resolver: None,
const_infer_name_resolver: None,
}))
@ -2746,20 +2741,14 @@ forward_display_to_print! {
// HACK(eddyb) these are exhaustive instead of generic,
// because `for<'tcx>` isn't possible yet.
ty::PolyExistentialPredicate<'tcx>,
ty::PolyExistentialProjection<'tcx>,
ty::PolyExistentialTraitRef<'tcx>,
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
ty::Binder<'tcx, ty::FnSig<'tcx>>,
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
ty::Binder<'tcx, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>,
ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
}

View File

@ -9,15 +9,13 @@ use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_hir::def::Namespace;
use rustc_index::{Idx, IndexVec};
use rustc_target::abi::TyAndLayout;
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx};
use std::fmt::{self, Debug};
use std::ops::ControlFlow;
use std::rc::Rc;
use std::sync::Arc;
use super::print::PrettyPrinter;
use super::{GenericArg, GenericArgKind, Region};
impl fmt::Debug for ty::TraitDef {
@ -343,14 +341,27 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
// This reflects what `Const` looked liked before `Interned` was
// introduced. We print it like this to avoid having to update expected
// output in a lot of tests.
// If this is a value, we spend some effort to make it look nice.
if let ConstKind::Value(_) = this.data.kind() {
return ty::tls::with(move |tcx| {
// Somehow trying to lift the valtree results in lifetime errors, so we lift the
// entire constant.
let lifted = tcx.lift(*this.data).unwrap();
let ConstKind::Value(valtree) = lifted.kind() else {
bug!("we checked that this is a valtree")
};
let cx = FmtPrinter::new(tcx, Namespace::ValueNS);
let cx =
cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?;
f.write_str(&cx.into_buffer())
});
}
// Fall back to something verbose.
write!(
f,
"Const {{ ty: {:?}, kind: {:?} }}",
&this.map(|data| data.ty()),
&this.map(|data| data.kind())
"{kind:?}: {ty:?}",
ty = &this.map(|data| data.ty()),
kind = &this.map(|data| data.kind())
)
}
}
@ -442,22 +453,16 @@ impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty:
// For things for which the type library provides traversal implementations
// for all Interners, we only need to provide a Lift implementation:
CloneLiftImpls! {
(),
bool,
usize,
u16,
u32,
u64,
String,
rustc_type_ir::DebruijnIndex,
TrivialLiftImpls! {
(),
bool,
usize,
}
// For things about which the type library does not know, or does not
// provide any traversal implementations, we need to provide both a Lift
// implementation and traversal implementations (the latter only for
// TyCtxt<'_> interners).
TrivialTypeTraversalAndLiftImpls! {
// For some things about which the type library does not know, or does not
// provide any traversal implementations, we need to provide a traversal
// implementation (only for TyCtxt<'_> interners).
TrivialTypeTraversalImpls! {
::rustc_target::abi::FieldIdx,
::rustc_target::abi::VariantIdx,
crate::middle::region::Scope,
@ -467,14 +472,10 @@ TrivialTypeTraversalAndLiftImpls! {
::rustc_ast::NodeId,
::rustc_span::symbol::Symbol,
::rustc_hir::def::Res,
::rustc_hir::def_id::DefId,
::rustc_hir::def_id::LocalDefId,
::rustc_hir::HirId,
::rustc_hir::MatchSource,
::rustc_hir::Mutability,
::rustc_hir::Unsafety,
::rustc_target::asm::InlineAsmRegOrRegClass,
::rustc_target::spec::abi::Abi,
crate::mir::coverage::CounterId,
crate::mir::coverage::ExpressionId,
crate::mir::coverage::MappedExpressionIndex,
@ -492,16 +493,12 @@ TrivialTypeTraversalAndLiftImpls! {
crate::ty::AssocItem,
crate::ty::AssocKind,
crate::ty::AliasKind,
crate::ty::AliasRelationDirection,
crate::ty::Placeholder<crate::ty::BoundRegion>,
crate::ty::Placeholder<crate::ty::BoundTy>,
crate::ty::Placeholder<ty::BoundVar>,
crate::ty::ClosureKind,
crate::ty::FreeRegion,
crate::ty::InferTy,
crate::ty::IntVarValue,
crate::ty::ParamConst,
crate::ty::ParamTy,
crate::ty::adjustment::PointerCoercion,
crate::ty::RegionVid,
crate::ty::UniverseIndex,
@ -509,33 +506,30 @@ TrivialTypeTraversalAndLiftImpls! {
::rustc_span::Span,
::rustc_span::symbol::Ident,
::rustc_errors::ErrorGuaranteed,
ty::BoundVar,
ty::ValTree<'tcx>,
}
// For some things about which the type library does not know, or does not
// provide any traversal implementations, we need to provide a traversal
// implementation and a lift implementation (the former only for TyCtxt<'_>
// interners).
TrivialTypeTraversalAndLiftImpls! {
::rustc_hir::def_id::DefId,
::rustc_hir::Mutability,
::rustc_hir::Unsafety,
::rustc_target::spec::abi::Abi,
crate::ty::AliasRelationDirection,
crate::ty::ClosureKind,
crate::ty::ParamConst,
crate::ty::ParamTy,
interpret::Scalar,
interpret::AllocId,
rustc_target::abi::Size,
ty::BoundVar,
}
TrivialTypeTraversalAndLiftImpls! {
ty::ValTree<'tcx>,
}
///////////////////////////////////////////////////////////////////////////
// Lift implementations
impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
type Lifted = (A::Lifted, B::Lifted);
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some((tcx.lift(self.0)?, tcx.lift(self.1)?))
}
}
impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) {
type Lifted = (A::Lifted, B::Lifted, C::Lifted);
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some((tcx.lift(self.0)?, tcx.lift(self.1)?, tcx.lift(self.2)?))
}
}
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
type Lifted = Option<T::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@ -546,50 +540,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
}
}
impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
type Lifted = Result<T::Lifted, E::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match self {
Ok(x) => tcx.lift(x).map(Ok),
Err(e) => tcx.lift(e).map(Err),
}
}
}
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
type Lifted = Box<T::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some(Box::new(tcx.lift(*self)?))
}
}
impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc<T> {
type Lifted = Rc<T::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some(Rc::new(tcx.lift(self.as_ref().clone())?))
}
}
impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc<T> {
type Lifted = Arc<T::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some(Arc::new(tcx.lift(self.as_ref().clone())?))
}
}
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec<T> {
type Lifted = Vec<T::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
self.into_iter().map(|v| tcx.lift(v)).collect()
}
}
impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec<I, T> {
type Lifted = IndexVec<I, T::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
self.into_iter().map(|e| tcx.lift(e)).collect()
}
}
impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
type Lifted = ty::Term<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@ -602,13 +552,6 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
)
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
type Lifted = ty::ParamEnv<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(self.caller_bounds())
.map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal()))
}
}
///////////////////////////////////////////////////////////////////////////
// Traversal implementations.

View File

@ -351,7 +351,7 @@ impl<'tcx> ClosureArgs<'tcx> {
}
/// Similar to `ClosureArgs`; see the above documentation for more.
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)]
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
pub struct GeneratorArgs<'tcx> {
pub args: GenericArgsRef<'tcx>,
}
@ -1305,7 +1305,7 @@ impl<'tcx> AliasTy<'tcx> {
}
}
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
pub struct GenSig<'tcx> {
pub resume_ty: Ty<'tcx>,
pub yield_ty: Ty<'tcx>,

View File

@ -165,7 +165,7 @@ pub struct TypeckResults<'tcx> {
/// reading places that are mentioned in a closure (because of _ patterns). However,
/// to ensure the places are initialized, we introduce fake reads.
/// Consider these two examples:
/// ``` (discriminant matching with only wildcard arm)
/// ```ignore (discriminant matching with only wildcard arm)
/// let x: u8;
/// let c = || match x { _ => () };
/// ```
@ -173,7 +173,7 @@ pub struct TypeckResults<'tcx> {
/// want to capture it. However, we do still want an error here, because `x` should have
/// to be initialized at the point where c is created. Therefore, we add a "fake read"
/// instead.
/// ``` (destructured assignments)
/// ```ignore (destructured assignments)
/// let c = || {
/// let (t1, t2) = t;
/// }
@ -654,7 +654,7 @@ rustc_index::newtype_index! {
pub type CanonicalUserTypeAnnotations<'tcx> =
IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct CanonicalUserTypeAnnotation<'tcx> {
pub user_ty: Box<CanonicalUserType<'tcx>>,
pub span: Span,
@ -714,7 +714,7 @@ impl<'tcx> CanonicalUserType<'tcx> {
/// from constants that are named via paths, like `Foo::<A>::new` and
/// so forth.
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)]
#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub enum UserType<'tcx> {
Ty(Ty<'tcx>),

View File

@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
pattern
}
}
Err(ErrorHandled::TooGeneric) => {
Err(ErrorHandled::TooGeneric(_)) => {
// While `Reported | Linted` cases will have diagnostics emitted already
// it is not true for TooGeneric case, so we need to give user more information.
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
@ -640,14 +640,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.kind
} else {
// If that fails, convert it to an opaque constant pattern.
match tcx.const_eval_resolve(self.param_env, uneval, None) {
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
Err(ErrorHandled::TooGeneric) => {
Err(ErrorHandled::TooGeneric(_)) => {
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
PatKind::Wild
}
Err(ErrorHandled::Reported(_)) => PatKind::Wild,
Err(ErrorHandled::Reported(..)) => PatKind::Wild,
}
}
}

View File

@ -105,25 +105,12 @@ impl<'tcx> MirLint<'tcx> for ConstProp {
trace!("ConstProp starting for {:?}", def_id);
let dummy_body = &Body::new(
body.source,
(*body.basic_blocks).to_owned(),
body.source_scopes.clone(),
body.local_decls.clone(),
Default::default(),
body.arg_count,
Default::default(),
body.span,
body.generator_kind(),
body.tainted_by_errors,
);
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
// constants, instead of just checking for const-folding succeeding.
// That would require a uniform one-def no-mutation analysis
// and RPO (or recursing when needing the value of a local).
let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
optimization_finder.visit_body(body);
let mut linter = ConstPropagator::new(body, tcx);
linter.visit_body(body);
trace!("ConstProp done for {:?}", def_id);
}
@ -169,11 +156,7 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
}
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn new(
body: &Body<'tcx>,
dummy_body: &'mir Body<'tcx>,
tcx: TyCtxt<'tcx>,
) -> ConstPropagator<'mir, 'tcx> {
fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
let def_id = body.source.def_id();
let args = &GenericArgs::identity_for_item(tcx, def_id);
let param_env = tcx.param_env_reveal_all_normalized(def_id);
@ -204,7 +187,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
ecx.push_stack_frame(
Instance::new(def_id, args),
dummy_body,
body,
&ret,
StackPopCleanup::Root { cleanup: false },
)

View File

@ -44,7 +44,7 @@
//! points, which can be enabled via environment variable:
//!
//! ```shell
//! RUSTC_LOG=rustc_mir_transform::transform::coverage=debug
//! RUSTC_LOG=rustc_mir_transform::coverage=debug
//! ```
//!
//! Other module paths with coverage-related debug logs may also be of interest, particularly for
@ -52,7 +52,7 @@
//! code generation pass). For example:
//!
//! ```shell
//! RUSTC_LOG=rustc_mir_transform::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
//! RUSTC_LOG=rustc_mir_transform::coverage,rustc_codegen_llvm::coverageinfo=debug
//! ```
//!
//! Coverage Debug Options
@ -108,24 +108,23 @@
//! recursively, generating labels with nested operations, enclosed in parentheses
//! (for example: `bcb2 + (bcb0 - bcb1)`).
use super::counters::{BcbCounter, CoverageCounters};
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use super::spans::CoverageSpan;
use std::iter;
use std::ops::Deref;
use std::sync::OnceLock;
use itertools::Itertools;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::create_dump_file;
use rustc_middle::mir::generic_graphviz::GraphvizWriter;
use rustc_middle::mir::spanview::{self, SpanViewable};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{self, BasicBlock};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
use std::iter;
use std::ops::Deref;
use std::sync::OnceLock;
use super::counters::{BcbCounter, CoverageCounters};
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
use super::spans::CoverageSpan;
pub const NESTED_INDENT: &str = " ";
@ -259,36 +258,42 @@ impl Default for ExpressionFormat {
/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
pub(super) struct DebugCounters {
some_counters: Option<FxHashMap<Operand, DebugCounter>>,
state: Option<DebugCountersState>,
}
#[derive(Default)]
struct DebugCountersState {
counters: FxHashMap<Operand, DebugCounter>,
}
impl DebugCounters {
pub fn new() -> Self {
Self { some_counters: None }
Self { state: None }
}
pub fn enable(&mut self) {
debug_assert!(!self.is_enabled());
self.some_counters.replace(FxHashMap::default());
self.state = Some(DebugCountersState::default());
}
pub fn is_enabled(&self) -> bool {
self.some_counters.is_some()
self.state.is_some()
}
pub fn add_counter(&mut self, counter_kind: &BcbCounter, some_block_label: Option<String>) {
if let Some(counters) = &mut self.some_counters {
let id = counter_kind.as_operand();
counters
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
.expect("attempt to add the same counter_kind to DebugCounters more than once");
}
let Some(state) = &mut self.state else { return };
let id = counter_kind.as_operand();
state
.counters
.try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
.expect("attempt to add the same counter_kind to DebugCounters more than once");
}
pub fn some_block_label(&self, operand: Operand) -> Option<&String> {
self.some_counters.as_ref().and_then(|counters| {
counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
})
let Some(state) = &self.state else { return None };
state.counters.get(&operand)?.some_block_label.as_ref()
}
pub fn format_counter(&self, counter_kind: &BcbCounter) -> String {
@ -308,7 +313,7 @@ impl DebugCounters {
if counter_format.operation {
return format!(
"{}{} {} {}",
if counter_format.id || self.some_counters.is_none() {
if counter_format.id || !self.is_enabled() {
format!("#{} = ", id.index())
} else {
String::new()
@ -324,10 +329,9 @@ impl DebugCounters {
}
let id = counter_kind.as_operand();
if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
let counters = self.some_counters.as_ref().unwrap();
if let Some(state) = &self.state && (counter_format.block || !counter_format.id) {
if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
counters.get(&id)
state.counters.get(&id)
{
return if counter_format.id {
format!("{}#{:?}", block_label, id)
@ -343,8 +347,10 @@ impl DebugCounters {
if matches!(operand, Operand::Zero) {
return String::from("0");
}
if let Some(counters) = &self.some_counters {
if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) {
if let Some(state) = &self.state {
if let Some(DebugCounter { counter_kind, some_block_label }) =
state.counters.get(&operand)
{
if let BcbCounter::Expression { .. } = counter_kind {
if let Some(label) = some_block_label && debug_options().counter_format.block {
return format!(
@ -378,30 +384,29 @@ impl DebugCounter {
/// If enabled, this data structure captures additional debugging information used when generating
/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
pub(super) struct GraphvizData {
some_bcb_to_coverage_spans_with_counters:
Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>>,
some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>>,
some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>>,
state: Option<GraphvizDataState>,
}
#[derive(Default)]
struct GraphvizDataState {
bcb_to_coverage_spans_with_counters:
FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, BcbCounter)>>,
bcb_to_dependency_counters: FxHashMap<BasicCoverageBlock, Vec<BcbCounter>>,
edge_to_counter: FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>,
}
impl GraphvizData {
pub fn new() -> Self {
Self {
some_bcb_to_coverage_spans_with_counters: None,
some_bcb_to_dependency_counters: None,
some_edge_to_counter: None,
}
Self { state: None }
}
pub fn enable(&mut self) {
debug_assert!(!self.is_enabled());
self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default());
self.some_bcb_to_dependency_counters = Some(FxHashMap::default());
self.some_edge_to_counter = Some(FxHashMap::default());
self.state = Some(GraphvizDataState::default());
}
pub fn is_enabled(&self) -> bool {
self.some_bcb_to_coverage_spans_with_counters.is_some()
self.state.is_some()
}
pub fn add_bcb_coverage_span_with_counter(
@ -410,27 +415,22 @@ impl GraphvizData {
coverage_span: &CoverageSpan,
counter_kind: &BcbCounter,
) {
if let Some(bcb_to_coverage_spans_with_counters) =
self.some_bcb_to_coverage_spans_with_counters.as_mut()
{
bcb_to_coverage_spans_with_counters
.entry(bcb)
.or_insert_with(Vec::new)
.push((coverage_span.clone(), counter_kind.clone()));
}
let Some(state) = &mut self.state else { return };
state
.bcb_to_coverage_spans_with_counters
.entry(bcb)
.or_insert_with(Vec::new)
.push((coverage_span.clone(), counter_kind.clone()));
}
pub fn get_bcb_coverage_spans_with_counters(
&self,
bcb: BasicCoverageBlock,
) -> Option<&[(CoverageSpan, BcbCounter)]> {
if let Some(bcb_to_coverage_spans_with_counters) =
self.some_bcb_to_coverage_spans_with_counters.as_ref()
{
bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
} else {
None
}
let Some(state) = &self.state else { return None };
state.bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref)
}
pub fn add_bcb_dependency_counter(
@ -438,20 +438,19 @@ impl GraphvizData {
bcb: BasicCoverageBlock,
counter_kind: &BcbCounter,
) {
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
bcb_to_dependency_counters
.entry(bcb)
.or_insert_with(Vec::new)
.push(counter_kind.clone());
}
let Some(state) = &mut self.state else { return };
state
.bcb_to_dependency_counters
.entry(bcb)
.or_insert_with(Vec::new)
.push(counter_kind.clone());
}
pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[BcbCounter]> {
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() {
bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
} else {
None
}
let Some(state) = &self.state else { return None };
state.bcb_to_dependency_counters.get(&bcb).map(Deref::deref)
}
pub fn set_edge_counter(
@ -460,11 +459,12 @@ impl GraphvizData {
to_bb: BasicBlock,
counter_kind: &BcbCounter,
) {
if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
edge_to_counter
.try_insert((from_bcb, to_bb), counter_kind.clone())
.expect("invalid attempt to insert more than one edge counter for the same edge");
}
let Some(state) = &mut self.state else { return };
state
.edge_to_counter
.try_insert((from_bcb, to_bb), counter_kind.clone())
.expect("invalid attempt to insert more than one edge counter for the same edge");
}
pub fn get_edge_counter(
@ -472,11 +472,9 @@ impl GraphvizData {
from_bcb: BasicCoverageBlock,
to_bb: BasicBlock,
) -> Option<&BcbCounter> {
if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() {
edge_to_counter.get(&(from_bcb, to_bb))
} else {
None
}
let Some(state) = &self.state else { return None };
state.edge_to_counter.get(&(from_bcb, to_bb))
}
}
@ -485,41 +483,42 @@ impl GraphvizData {
/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
/// and/or a `CoverageGraph` graphviz output).
pub(super) struct UsedExpressions {
some_used_expression_operands: Option<FxHashMap<Operand, Vec<ExpressionId>>>,
some_unused_expressions:
Option<Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
state: Option<UsedExpressionsState>,
}
#[derive(Default)]
struct UsedExpressionsState {
used_expression_operands: FxHashSet<Operand>,
unused_expressions: Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)>,
}
impl UsedExpressions {
pub fn new() -> Self {
Self { some_used_expression_operands: None, some_unused_expressions: None }
Self { state: None }
}
pub fn enable(&mut self) {
debug_assert!(!self.is_enabled());
self.some_used_expression_operands = Some(FxHashMap::default());
self.some_unused_expressions = Some(Vec::new());
self.state = Some(UsedExpressionsState::default())
}
pub fn is_enabled(&self) -> bool {
self.some_used_expression_operands.is_some()
self.state.is_some()
}
pub fn add_expression_operands(&mut self, expression: &BcbCounter) {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
if let BcbCounter::Expression { id, lhs, rhs, .. } = *expression {
used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
}
let Some(state) = &mut self.state else { return };
if let BcbCounter::Expression { lhs, rhs, .. } = *expression {
state.used_expression_operands.insert(lhs);
state.used_expression_operands.insert(rhs);
}
}
pub fn expression_is_used(&self, expression: &BcbCounter) -> bool {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
used_expression_operands.contains_key(&expression.as_operand())
} else {
false
}
let Some(state) = &self.state else { return false };
state.used_expression_operands.contains(&expression.as_operand())
}
pub fn add_unused_expression_if_not_found(
@ -528,14 +527,10 @@ impl UsedExpressions {
edge_from_bcb: Option<BasicCoverageBlock>,
target_bcb: BasicCoverageBlock,
) {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
if !used_expression_operands.contains_key(&expression.as_operand()) {
self.some_unused_expressions.as_mut().unwrap().push((
expression.clone(),
edge_from_bcb,
target_bcb,
));
}
let Some(state) = &mut self.state else { return };
if !state.used_expression_operands.contains(&expression.as_operand()) {
state.unused_expressions.push((expression.clone(), edge_from_bcb, target_bcb));
}
}
@ -544,11 +539,9 @@ impl UsedExpressions {
pub fn get_unused_expressions(
&self,
) -> Vec<(BcbCounter, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
unused_expressions.clone()
} else {
Vec::new()
}
let Some(state) = &self.state else { return Vec::new() };
state.unused_expressions.clone()
}
/// If enabled, validate that every BCB or edge counter not directly associated with a coverage
@ -562,51 +555,53 @@ impl UsedExpressions {
BcbCounter,
)],
) {
if self.is_enabled() {
let mut not_validated = bcb_counters_without_direct_coverage_spans
.iter()
.map(|(_, _, counter_kind)| counter_kind)
.collect::<Vec<_>>();
let mut validating_count = 0;
while not_validated.len() != validating_count {
let to_validate = not_validated.split_off(0);
validating_count = to_validate.len();
for counter_kind in to_validate {
if self.expression_is_used(counter_kind) {
self.add_expression_operands(counter_kind);
} else {
not_validated.push(counter_kind);
}
if !self.is_enabled() {
return;
}
let mut not_validated = bcb_counters_without_direct_coverage_spans
.iter()
.map(|(_, _, counter_kind)| counter_kind)
.collect::<Vec<_>>();
let mut validating_count = 0;
while not_validated.len() != validating_count {
let to_validate = not_validated.split_off(0);
validating_count = to_validate.len();
for counter_kind in to_validate {
if self.expression_is_used(counter_kind) {
self.add_expression_operands(counter_kind);
} else {
not_validated.push(counter_kind);
}
}
}
}
pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) {
if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
for (counter_kind, edge_from_bcb, target_bcb) in unused_expressions {
let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
format!(
"non-coverage edge counter found without a dependent expression, in \
{:?}->{:?}; counter={}",
from_bcb,
target_bcb,
debug_counters.format_counter(&counter_kind),
)
} else {
format!(
"non-coverage counter found without a dependent expression, in {:?}; \
counter={}",
target_bcb,
debug_counters.format_counter(&counter_kind),
)
};
let Some(state) = &self.state else { return };
if debug_options().allow_unused_expressions {
debug!("WARNING: {}", unused_counter_message);
} else {
bug!("{}", unused_counter_message);
}
for (counter_kind, edge_from_bcb, target_bcb) in &state.unused_expressions {
let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
format!(
"non-coverage edge counter found without a dependent expression, in \
{:?}->{:?}; counter={}",
from_bcb,
target_bcb,
debug_counters.format_counter(&counter_kind),
)
} else {
format!(
"non-coverage counter found without a dependent expression, in {:?}; \
counter={}",
target_bcb,
debug_counters.format_counter(&counter_kind),
)
};
if debug_options().allow_unused_expressions {
debug!("WARNING: {}", unused_counter_message);
} else {
bug!("{}", unused_counter_message);
}
}
}

View File

@ -199,12 +199,8 @@ impl CoverageGraph {
}
#[inline(always)]
pub fn rank_partial_cmp(
&self,
a: BasicCoverageBlock,
b: BasicCoverageBlock,
) -> Option<Ordering> {
self.dominators.as_ref().unwrap().rank_partial_cmp(a, b)
pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering {
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
}
}

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