Auto merge of #2955 - rust-lang:rustup2023-07-03, r=oli-obk

Automatic sync from rustc
This commit is contained in:
bors 2023-07-03 08:16:58 +00:00
commit a8b6ec1667
1365 changed files with 28729 additions and 9003 deletions

View File

@ -31,7 +31,7 @@ defaults:
run:
shell: bash
concurrency:
group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
group: "${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.sha) || github.ref }}"
cancel-in-progress: true
jobs:
pr:

1141
Cargo.lock

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ members = [
"src/tools/cargotest",
"src/tools/clippy",
"src/tools/clippy/clippy_dev",
"src/tools/clippy/clippy_test_deps",
"src/tools/compiletest",
"src/tools/error_index_generator",
"src/tools/linkchecker",

View File

@ -1539,9 +1539,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
debug!(?opaque_ty_def_id);
// Contains the new lifetime definitions created for the TAIT (if any).
let mut collected_lifetimes = Vec::new();
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
// exactly which ones those are.
@ -1558,20 +1555,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
debug!(?lifetimes_to_remap);
let mut new_remapping = FxHashMap::default();
// Contains the new lifetime definitions created for the TAIT (if any).
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
// bounds), then create the new lifetime parameters required and create a mapping from the
// old `'a` (on the function) to the new `'a` (on the opaque type).
let collected_lifetimes =
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
debug!(?collected_lifetimes);
debug!(?new_remapping);
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
.iter()
.map(|(node_id, lifetime)| {
let id = self.next_node_id();
let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
let def_id = self.local_def_id(*node_id);
(lifetime, def_id)
})
.collect();
debug!(?collected_lifetime_mapping);
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
let mut new_remapping = FxHashMap::default();
// If this opaque type is only capturing a subset of the lifetimes (those that appear
// in bounds), then create the new lifetime parameters required and create a mapping
// from the old `'a` (on the function) to the new `'a` (on the opaque type).
collected_lifetimes = lctx.create_lifetime_defs(
opaque_ty_def_id,
&lifetimes_to_remap,
&mut new_remapping,
);
debug!(?collected_lifetimes);
debug!(?new_remapping);
// Install the remapping from old to new (if any):
lctx.with_remapping(new_remapping, |lctx| {
// This creates HIR lifetime definitions as `hir::GenericParam`, in the given
@ -1610,6 +1618,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
debug!(?hir_bounds);
let lifetime_mapping = if in_trait {
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
)
} else {
&mut []
};
let opaque_ty_item = hir::OpaqueTy {
generics: self.arena.alloc(hir::Generics {
params: lifetime_defs,
@ -1620,6 +1638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}),
bounds: hir_bounds,
origin,
lifetime_mapping,
in_trait,
};
debug!(?opaque_ty_item);
@ -1628,20 +1647,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
});
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
let lifetimes =
self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
let id = self.next_node_id();
let l = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
hir::GenericArg::Lifetime(l)
}));
debug!(?lifetimes);
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
hir::TyKind::OpaqueDef(
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
lifetimes,
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
),
in_trait,
)
}
@ -1655,7 +1668,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
opaque_ty_span: Span,
) -> hir::OwnerNode<'hir> {
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
// Generate an `type Foo = impl Trait;` declaration.
trace!("registering opaque type with id {:#?}", opaque_ty_id);
let opaque_ty_item = hir::Item {
@ -1983,7 +1996,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetime = Lifetime { id: outer_node_id, ident };
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
}
debug!(?collected_lifetimes);
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
@ -1993,22 +2005,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
debug!(?lifetimes_to_remap);
self.with_hir_id_owner(opaque_ty_node_id, |this| {
// If this opaque type is only capturing a subset of the lifetimes (those that appear
// in bounds), then create the new lifetime parameters required and create a mapping
// from the old `'a` (on the function) to the new `'a` (on the opaque type).
collected_lifetimes.extend(
this.create_lifetime_defs(
opaque_ty_def_id,
&lifetimes_to_remap,
&mut new_remapping,
)
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
// bounds), then create the new lifetime parameters required and create a mapping from the
// old `'a` (on the function) to the new `'a` (on the opaque type).
collected_lifetimes.extend(
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
.into_iter()
.map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
);
debug!(?collected_lifetimes);
debug!(?new_remapping);
);
debug!(?collected_lifetimes);
debug!(?new_remapping);
// This creates pairs of HIR lifetimes and def_ids. In the given example `type
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
// new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
// `TestReturn`.
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
.iter()
.map(|(node_id, lifetime, res)| {
let id = self.next_node_id();
let res = res.unwrap_or(
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
);
let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
let def_id = self.local_def_id(*node_id);
(lifetime, def_id)
})
.collect();
debug!(?collected_lifetime_mapping);
self.with_hir_id_owner(opaque_ty_node_id, |this| {
// Install the remapping from old to new (if any):
this.with_remapping(new_remapping, |this| {
// We have to be careful to get elision right here. The
@ -2063,6 +2089,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
));
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
let lifetime_mapping = if in_trait {
self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
)
} else {
&mut []
};
let opaque_ty_item = hir::OpaqueTy {
generics: this.arena.alloc(hir::Generics {
params: generic_params,
@ -2073,6 +2109,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}),
bounds: arena_vec![this; future_bound],
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
lifetime_mapping,
in_trait,
};
@ -2096,15 +2133,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
//
// For the "output" lifetime parameters, we just want to
// generate `'_`.
let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
|(_, lifetime, res)| {
let id = self.next_node_id();
let res = res.unwrap_or(
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
);
hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, lifetime.ident, res))
},
));
let generic_args = self.arena.alloc_from_iter(
collected_lifetime_mapping
.iter()
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
);
// Create the `Foo<...>` reference itself. Note that the `type
// Foo = impl Trait` is, internally, created as a child of the

View File

@ -1,6 +1,5 @@
use std::iter;
use either::Either;
use hir::PatField;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{
@ -28,6 +27,7 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
@ -982,7 +982,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&msg_borrow,
None,
);
self.suggest_split_at_mut_if_applicable(
self.suggest_slice_method_if_applicable(
&mut err,
place,
issued_borrow.borrowed_place,
@ -992,6 +992,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
issued_borrow.borrowed_place,
&issued_spans,
);
self.explain_iterator_advancement_in_for_loop_if_applicable(
&mut err,
span,
&issued_spans,
);
err
}
@ -1262,7 +1267,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
fn suggest_split_at_mut_if_applicable(
fn suggest_slice_method_if_applicable(
&self,
err: &mut Diagnostic,
place: Place<'tcx>,
@ -1274,7 +1279,75 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.help(
"consider using `.split_at_mut(position)` or similar method to obtain \
two mutable non-overlapping sub-slices",
);
)
.help("consider using `.swap(index_1, index_2)` to swap elements at the specified indices");
}
}
/// Suggest using `while let` for call `next` on an iterator in a for loop.
///
/// For example:
/// ```ignore (illustrative)
///
/// for x in iter {
/// ...
/// iter.next()
/// }
/// ```
pub(crate) fn explain_iterator_advancement_in_for_loop_if_applicable(
&self,
err: &mut Diagnostic,
span: Span,
issued_spans: &UseSpans<'tcx>,
) {
let issue_span = issued_spans.args_or_use();
let tcx = self.infcx.tcx;
let hir = tcx.hir();
let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return };
let typeck_results = tcx.typeck(self.mir_def_id());
struct ExprFinder<'hir> {
issue_span: Span,
expr_span: Span,
body_expr: Option<&'hir hir::Expr<'hir>>,
loop_bind: Option<Symbol>,
}
impl<'hir> Visitor<'hir> for ExprFinder<'hir> {
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
if let hir::ExprKind::Loop(hir::Block{ stmts: [stmt, ..], ..}, _, hir::LoopSource::ForLoop, _) = ex.kind &&
let hir::StmtKind::Expr(hir::Expr{ kind: hir::ExprKind::Match(call, [_, bind, ..], _), ..}) = stmt.kind &&
let hir::ExprKind::Call(path, _args) = call.kind &&
let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _, )) = path.kind &&
let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind &&
let hir::QPath::LangItem(LangItem::OptionSome, _, _) = path &&
let PatField { pat: hir::Pat{ kind: hir::PatKind::Binding(_, _, ident, ..), .. }, ..} = field &&
self.issue_span.source_equal(call.span) {
self.loop_bind = Some(ident.name);
}
if let hir::ExprKind::MethodCall(body_call, _recv, ..) = ex.kind &&
body_call.ident.name == sym::next && ex.span.source_equal(self.expr_span) {
self.body_expr = Some(ex);
}
hir::intravisit::walk_expr(self, ex);
}
}
let mut finder =
ExprFinder { expr_span: span, issue_span, loop_bind: None, body_expr: None };
finder.visit_expr(hir.body(body_id).value);
if let Some(loop_bind) = finder.loop_bind &&
let Some(body_expr) = finder.body_expr &&
let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) &&
let Some(trait_did) = tcx.trait_of_item(def_id) &&
tcx.is_diagnostic_item(sym::Iterator, trait_did) {
err.note(format!(
"a for loop advances the iterator for you, the result is stored in `{}`.",
loop_bind
));
err.help("if you want to call `next` on a iterator within the loop, consider using `while let`.");
}
}
@ -1730,18 +1803,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(
Some(name),
BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
) => self.report_escaping_closure_capture(
borrow_spans,
borrow_span,
&RegionName {
name: self.synthesize_region_name(),
source: RegionNameSource::Static,
},
ConstraintCategory::CallArgument(None),
var_or_use_span,
&format!("`{}`", name),
"block",
),
) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,
&RegionName {
name: self.synthesize_region_name(),
source: RegionNameSource::Static,
},
ConstraintCategory::CallArgument(None),
var_or_use_span,
&format!("`{}`", name),
"block",
),
(
Some(name),
BorrowExplanation::MustBeValidFor {
@ -1754,7 +1828,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
span,
..
},
) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
) if borrow_spans.for_generator() || borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,

View File

@ -1146,6 +1146,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
self.explain_iterator_advancement_in_for_loop_if_applicable(
err,
span,
&move_spans,
);
let func = tcx.def_path_str(method_did);
err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
func,

View File

@ -222,7 +222,7 @@ fn do_mir_borrowck<'tcx>(
let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) =
match MoveData::gather_moves(&body, tcx, param_env) {
Ok((_, move_data)) => (move_data, Vec::new()),
Ok(move_data) => (move_data, Vec::new()),
Err((move_data, move_errors)) => (move_data, move_errors),
};
let promoted_errors = promoted

View File

@ -1,4 +1,5 @@
builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
builtin_macros_alloc_must_statics = allocators must be statics
builtin_macros_asm_clobber_abi = clobber_abi
builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs
@ -56,6 +57,9 @@ builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `e
.label = not applicable here
.label2 = not a `struct`, `enum` or `union`
builtin_macros_bench_sig = functions used as benches must have signature `fn(&mut Bencher) -> impl Termination`
builtin_macros_cannot_derive_union = this trait cannot be derived for unions
builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments
@ -84,6 +88,7 @@ builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
builtin_macros_concat_bytes_oob = numeric literal is out of bounds
builtin_macros_concat_bytestr = cannot concatenate a byte string literal
builtin_macros_concat_c_str_lit = cannot concatenate a C string literal
builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
@ -111,6 +116,10 @@ builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
builtin_macros_expected_register_class_or_explicit_register = expected register class or explicit register
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
.label1 = previously here
.label2 = duplicate argument
@ -158,6 +167,8 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
builtin_macros_invalid_crate_attribute = invalid crate attribute
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
.note = only one `#[default]` attribute is needed
.label = `#[default]` used here
@ -177,6 +188,8 @@ builtin_macros_no_default_variant = no default declared
.help = make a unit variant default by placing `#[default]` above it
.suggestion = make `{$ident}` default
builtin_macros_non_abi = at least one abi must be provided as an argument to `clobber_abi`
builtin_macros_non_exhaustive_default = default variant must be exhaustive
.label = declared `#[non_exhaustive]` here
.help = consider a manual implementation of `Default`
@ -184,12 +197,20 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
.help = consider a manual implementation of `Default`
builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]`
builtin_macros_requires_cfg_pattern =
macro requires a cfg-pattern as an argument
.label = cfg-pattern required
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
builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
.label = `{$kind}` because of this
@ -198,6 +219,10 @@ builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on
builtin_macros_test_runner_invalid = `test_runner` argument must be a path
builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument
builtin_macros_tests_not_support = building tests with panic=abort is not supported without `-Zpanic_abort_tests`
builtin_macros_trace_macros = trace_macros! accepts only `true` or `false`
builtin_macros_unexpected_lit = expected path to a trait, found literal
.label = not a trait
.str_lit = try using `#[derive({$sym})]`

View File

@ -371,11 +371,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
let err = p.sess.span_diagnostic.struct_span_err(
p.token.span,
"at least one abi must be provided as an argument to `clobber_abi`",
);
return Err(err);
return Err(p.sess.span_diagnostic.create_err(errors::NonABI { span: p.token.span }));
}
let mut new_abis = Vec::new();
@ -428,9 +424,9 @@ fn parse_reg<'a>(
ast::InlineAsmRegOrRegClass::Reg(symbol)
}
_ => {
return Err(
p.struct_span_err(p.token.span, "expected register class or explicit register")
);
return Err(p.sess.create_err(errors::ExpectedRegisterClassOrExplicitRegister {
span: p.token.span,
}));
}
};
p.bump();

View File

@ -1,5 +1,6 @@
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
use crate::errors;
use rustc_ast::attr::mk_attr;
use rustc_ast::token;
use rustc_ast::{self as ast, AttrItem, AttrStyle};
@ -24,7 +25,9 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String])
};
let end_span = parser.token.span;
if parser.token != token::Eof {
parse_sess.span_diagnostic.span_err(start_span.to(end_span), "invalid crate attribute");
parse_sess
.span_diagnostic
.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
continue;
}

View File

@ -33,7 +33,7 @@ pub fn expand_concat(
accumulator.push_str(&b.to_string());
}
Ok(ast::LitKind::CStr(..)) => {
cx.span_err(e.span, "cannot concatenate a C string literal");
cx.emit_err(errors::ConcatCStrLit{ span: e.span});
has_errors = true;
}
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {

View File

@ -21,7 +21,7 @@ fn invalid_type_err(
Ok(ast::LitKind::CStr(_, _)) => {
// FIXME(c_str_literals): should concatenation of C string literals
// include the null bytes in the end?
cx.span_err(span, "cannot concatenate C string literals");
cx.emit_err(errors::ConcatCStrLit { span: span });
}
Ok(ast::LitKind::Char(_)) => {
let sugg =

View File

@ -87,6 +87,83 @@ pub(crate) struct ConcatBytestr {
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_concat_c_str_lit)]
pub(crate) struct ConcatCStrLit {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_export_macro_rules)]
pub(crate) struct ExportMacroRules {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_proc_macro)]
pub(crate) struct ProcMacro {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_invalid_crate_attribute)]
pub(crate) struct InvalidCrateAttr {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_non_abi)]
pub(crate) struct NonABI {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_trace_macros)]
pub(crate) struct TraceMacros {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_bench_sig)]
pub(crate) struct BenchSig {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_test_arg_non_lifetime)]
pub(crate) struct TestArgNonLifetime {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_should_panic)]
pub(crate) struct ShouldPanic {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_test_args)]
pub(crate) struct TestArgs {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_alloc_must_statics)]
pub(crate) struct AllocMustStatics {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_concat_bytes_invalid)]
pub(crate) struct ConcatBytesInvalid {
@ -201,6 +278,10 @@ pub(crate) struct BadDeriveTarget {
pub(crate) item: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_tests_not_support)]
pub(crate) struct TestsNotSupport {}
#[derive(Diagnostic)]
#[diag(builtin_macros_unexpected_lit, code = "E0777")]
pub(crate) struct BadDeriveLit {
@ -732,3 +813,10 @@ pub(crate) struct TestRunnerNargs {
#[primary_span]
pub(crate) span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_expected_register_class_or_explicit_register)]
pub(crate) struct ExpectedRegisterClassOrExplicitRegister {
#[primary_span]
pub(crate) span: Span,
}

View File

@ -1,5 +1,6 @@
use crate::util::check_builtin_macro_attribute;
use crate::errors;
use rustc_ast::expand::allocator::{
global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
};
@ -34,7 +35,7 @@ pub fn expand(
{
(item, true, ecx.with_def_site_ctxt(ty.span))
} else {
ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocMustStatics{span: item.span()});
return vec![orig_item];
};

View File

@ -1,3 +1,4 @@
use crate::errors;
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{self as ast, attr, NodeId};
@ -83,12 +84,7 @@ pub fn inject(
impl<'a> CollectProcMacros<'a> {
fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() {
self.handler.span_err(
sp,
"`proc-macro` crate types currently cannot export any items other \
than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, \
or `#[proc_macro_attribute]`",
);
self.handler.emit_err(errors::ProcMacro { span: sp });
}
}
@ -157,9 +153,9 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
fn visit_item(&mut self, item: &'a ast::Item) {
if let ast::ItemKind::MacroDef(..) = item.kind {
if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
let msg =
"cannot export macro_rules! macros from a `proc-macro` crate type currently";
self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
self.handler.emit_err(errors::ExportMacroRules {
span: self.source_map.guess_head_span(item.span),
});
}
}

View File

@ -576,12 +576,7 @@ fn check_bench_signature(
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
if f.sig.decl.inputs.len() != 1 {
return Err(cx.sess.parse_sess.span_diagnostic.span_err(
i.span,
"functions used as benches must have \
signature `fn(&mut Bencher) -> impl Termination`",
));
return Err(cx.sess.parse_sess.span_diagnostic.emit_err(errors::BenchSig { span: i.span }));
}
Ok(())
}

View File

@ -63,10 +63,7 @@ pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn Resolve
// Silently allow compiling with panic=abort on these platforms,
// but with old behavior (abort if a test fails).
} else {
span_diagnostic.err(
"building tests with panic=abort is not supported \
without `-Zpanic_abort_tests`",
);
span_diagnostic.emit_err(errors::TestsNotSupport {});
}
PanicStrategy::Unwind
}

View File

@ -1,3 +1,4 @@
use crate::errors;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_expand::base::{self, ExtCtxt};
use rustc_span::symbol::kw;
@ -20,7 +21,7 @@ pub fn expand_trace_macros(
};
err |= cursor.next().is_some();
if err {
cx.span_err(sp, "trace_macros! accepts only `true` or `false`")
cx.emit_err(errors::TraceMacros { span: sp });
} else {
cx.set_trace_macros(value);
}

View File

@ -81,7 +81,7 @@ impl DebugContext {
match tcx.sess.source_map().lookup_line(span.lo()) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.line_begin_pos(span.lo());
let line_pos = file.lines(|lines| lines[line]);
(
file,

View File

@ -1,7 +1,6 @@
//! Set and unset common attributes on LLVM values.
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::small_str::SmallStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::{self, TyCtxt};
@ -481,8 +480,8 @@ pub fn from_fn_attrs<'ll, 'tcx>(
let global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
let function_features = function_features.iter().map(|s| s.as_str());
let target_features =
global_features.chain(function_features).intersperse(",").collect::<SmallStr<1024>>();
let target_features: String =
global_features.chain(function_features).intersperse(",").collect();
if !target_features.is_empty() {
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
}

View File

@ -1,4 +1,4 @@
use crate::back::write::{self, save_temp_bitcode, DiagnosticHandlers};
use crate::back::write::{self, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers};
use crate::errors::{
DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib,
};
@ -302,7 +302,13 @@ fn fat_lto(
// The linking steps below may produce errors and diagnostics within LLVM
// which we'd like to handle and print, so set up our diagnostic handlers
// (which get unregistered when they go out of scope below).
let _handler = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
let _handler = DiagnosticHandlers::new(
cgcx,
diag_handler,
llcx,
&module,
CodegenDiagnosticsStage::LTO,
);
// For all other modules we codegened we'll need to link them into our own
// bitcode. All modules were codegened in their own LLVM context, however,

View File

@ -268,6 +268,16 @@ pub(crate) fn save_temp_bitcode(
}
}
/// In what context is a dignostic handler being attached to a codegen unit?
pub enum CodegenDiagnosticsStage {
/// Prelink optimization stage.
Opt,
/// LTO/ThinLTO postlink optimization stage.
LTO,
/// Code generation.
Codegen,
}
pub struct DiagnosticHandlers<'a> {
data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler),
llcx: &'a llvm::Context,
@ -279,6 +289,8 @@ impl<'a> DiagnosticHandlers<'a> {
cgcx: &'a CodegenContext<LlvmCodegenBackend>,
handler: &'a Handler,
llcx: &'a llvm::Context,
module: &ModuleCodegen<ModuleLlvm>,
stage: CodegenDiagnosticsStage,
) -> Self {
let remark_passes_all: bool;
let remark_passes: Vec<CString>;
@ -295,6 +307,20 @@ impl<'a> DiagnosticHandlers<'a> {
};
let remark_passes: Vec<*const c_char> =
remark_passes.iter().map(|name: &CString| name.as_ptr()).collect();
let remark_file = cgcx
.remark_dir
.as_ref()
// Use the .opt.yaml file suffix, which is supported by LLVM's opt-viewer.
.map(|dir| {
let stage_suffix = match stage {
CodegenDiagnosticsStage::Codegen => "codegen",
CodegenDiagnosticsStage::Opt => "opt",
CodegenDiagnosticsStage::LTO => "lto",
};
dir.join(format!("{}.{stage_suffix}.opt.yaml", module.name))
})
.and_then(|dir| dir.to_str().and_then(|p| CString::new(p).ok()));
let data = Box::into_raw(Box::new((cgcx, handler)));
unsafe {
let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
@ -305,6 +331,9 @@ impl<'a> DiagnosticHandlers<'a> {
remark_passes_all,
remark_passes.as_ptr(),
remark_passes.len(),
// The `as_ref()` is important here, otherwise the `CString` will be dropped
// too soon!
remark_file.as_ref().map(|dir| dir.as_ptr()).unwrap_or(std::ptr::null()),
);
DiagnosticHandlers { data, llcx, old_handler }
}
@ -523,7 +552,8 @@ pub(crate) unsafe fn optimize(
let llmod = module.module_llvm.llmod();
let llcx = &*module.module_llvm.llcx;
let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
let _handlers =
DiagnosticHandlers::new(cgcx, diag_handler, llcx, module, CodegenDiagnosticsStage::Opt);
let module_name = module.name.clone();
let module_name = Some(&module_name[..]);
@ -582,7 +612,13 @@ pub(crate) unsafe fn codegen(
let tm = &*module.module_llvm.tm;
let module_name = module.name.clone();
let module_name = Some(&module_name[..]);
let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
let _handlers = DiagnosticHandlers::new(
cgcx,
diag_handler,
llcx,
&module,
CodegenDiagnosticsStage::Codegen,
);
if cgcx.msvc_imps_needed {
create_msvc_imps(cgcx, llcx, llmod);
@ -775,7 +811,6 @@ pub(crate) unsafe fn codegen(
}
record_llvm_cgu_instructions_stats(&cgcx.prof, llmod);
drop(handlers);
}
// `.dwo` files are only emitted if:
@ -875,14 +910,19 @@ unsafe fn embed_bitcode(
// passed though then these sections will show up in the final output.
// Additionally the flag that we need to set here is `SHF_EXCLUDE`.
//
// * XCOFF - AIX linker ignores content in .ipa and .info if no auxiliary
// symbol associated with these sections.
//
// Unfortunately, LLVM provides no way to set custom section flags. For ELF
// and COFF we emit the sections using module level inline assembly for that
// reason (see issue #90326 for historical background).
let is_aix = cgcx.opts.target_triple.triple().contains("-aix");
let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
|| cgcx.opts.target_triple.triple().contains("-darwin")
|| cgcx.opts.target_triple.triple().contains("-tvos")
|| cgcx.opts.target_triple.triple().contains("-watchos");
if is_apple
|| is_aix
|| cgcx.opts.target_triple.triple().starts_with("wasm")
|| cgcx.opts.target_triple.triple().starts_with("asmjs")
{
@ -895,7 +935,13 @@ unsafe fn embed_bitcode(
);
llvm::LLVMSetInitializer(llglobal, llconst);
let section = if is_apple { c"__LLVM,__bitcode" } else { c".llvmbc" };
let section = if is_apple {
c"__LLVM,__bitcode"
} else if is_aix {
c".ipa"
} else {
c".llvmbc"
};
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
@ -907,7 +953,13 @@ unsafe fn embed_bitcode(
c"rustc.embedded.cmdline".as_ptr().cast(),
);
llvm::LLVMSetInitializer(llglobal, llconst);
let section = if is_apple { c"__LLVM,__cmdline" } else { c".llvmcmd" };
let section = if is_apple {
c"__LLVM,__cmdline"
} else if is_aix {
c".info"
} else {
c".llvmcmd"
};
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
} else {

View File

@ -23,6 +23,7 @@ use rustc_span::Span;
use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
use smallvec::SmallVec;
use std::borrow::Cow;
use std::iter;
use std::ops::Deref;
@ -225,7 +226,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let args = self.check_call("invoke", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
let mut bundles = vec![funclet_bundle];
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
// Emit CFI pointer type membership test
self.cfi_type_test(fn_attrs, fn_abi, llfn);
@ -233,9 +237,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
// Emit KCFI operand bundle
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
bundles.push(kcfi_bundle);
if let Some(kcfi_bundle) = kcfi_bundle {
bundles.push(kcfi_bundle);
}
bundles.retain(|bundle| bundle.is_some());
let invoke = unsafe {
llvm::LLVMRustBuildInvoke(
self.llbuilder,
@ -1181,7 +1186,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let args = self.check_call("call", llty, llfn, args);
let funclet_bundle = funclet.map(|funclet| funclet.bundle());
let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
let mut bundles = vec![funclet_bundle];
let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
if let Some(funclet_bundle) = funclet_bundle {
bundles.push(funclet_bundle);
}
// Emit CFI pointer type membership test
self.cfi_type_test(fn_attrs, fn_abi, llfn);
@ -1189,9 +1197,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
// Emit KCFI operand bundle
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
bundles.push(kcfi_bundle);
if let Some(kcfi_bundle) = kcfi_bundle {
bundles.push(kcfi_bundle);
}
bundles.retain(|bundle| bundle.is_some());
let call = unsafe {
llvm::LLVMRustBuildCall(
self.llbuilder,

View File

@ -8,7 +8,7 @@ use crate::llvm_util;
use crate::type_::Type;
use crate::value::Value;
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n;
use rustc_data_structures::fx::FxHashMap;
@ -532,19 +532,28 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
if let Some(llpersonality) = self.eh_personality.get() {
return llpersonality;
}
let name = if wants_msvc_seh(self.sess()) {
Some("__CxxFrameHandler3")
} else if wants_wasm_eh(self.sess()) {
// LLVM specifically tests for the name of the personality function
// There is no need for this function to exist anywhere, it will
// not be called. However, its name has to be "__gxx_wasm_personality_v0"
// for native wasm exceptions.
Some("__gxx_wasm_personality_v0")
} else {
None
};
let tcx = self.tcx;
let llfn = match tcx.lang_items().eh_personality() {
Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr(
Some(def_id) if name.is_none() => self.get_fn_addr(
ty::Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, ty::List::empty())
.unwrap()
.unwrap(),
),
_ => {
let name = if wants_msvc_seh(self.sess()) {
"__CxxFrameHandler3"
} else {
"rust_eh_personality"
};
let name = name.unwrap_or("rust_eh_personality");
if let Some(llfn) = self.get_declared_value(name) {
llfn
} else {
@ -662,6 +671,10 @@ impl<'ll> CodegenCx<'ll, '_> {
let t_f32 = self.type_f32();
let t_f64 = self.type_f64();
let t_metadata = self.type_metadata();
let t_token = self.type_token();
ifn!("llvm.wasm.get.exception", fn(t_token) -> i8p);
ifn!("llvm.wasm.get.ehselector", fn(t_token) -> t_i32);
ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);

View File

@ -65,10 +65,10 @@ fn make_mir_scope<'ll, 'tcx>(
debug_context.scopes[parent]
} else {
// The root is the function itself.
let loc = cx.lookup_debug_loc(mir.span.lo());
let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
debug_context.scopes[scope] = DebugScope {
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
file_start_pos: file.start_pos,
file_end_pos: file.end_pos,
..debug_context.scopes[scope]
};
instantiated.insert(scope);

View File

@ -262,7 +262,7 @@ impl CodegenCx<'_, '_> {
pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.line_begin_pos(pos);
let line_pos = file.lines(|lines| lines[line]);
// Use 1-based indexing.
let line = (line + 1) as u32;
@ -331,7 +331,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
};
let mut name = String::new();
let mut name = String::with_capacity(64);
type_names::push_item_name(tcx, def_id, false, &mut name);
// Find the enclosing function, in case this is a closure.

View File

@ -28,7 +28,7 @@ pub fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DISco
.map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent }));
let namespace_name_string = {
let mut output = String::new();
let mut output = String::with_capacity(64);
type_names::push_item_name(cx.tcx, def_id, false, &mut output);
output
};

View File

@ -7,7 +7,7 @@ use crate::type_of::LayoutLlvmExt;
use crate::va_arg::emit_va_arg;
use crate::value::Value;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
use rustc_codegen_ssa::mir::operand::OperandRef;
@ -452,6 +452,8 @@ fn try_intrinsic<'ll>(
bx.store(bx.const_i32(0), dest, ret_align);
} else if wants_msvc_seh(bx.sess()) {
codegen_msvc_try(bx, try_func, data, catch_func, dest);
} else if wants_wasm_eh(bx.sess()) {
codegen_wasm_try(bx, try_func, data, catch_func, dest);
} else if bx.sess().target.os == "emscripten" {
codegen_emcc_try(bx, try_func, data, catch_func, dest);
} else {
@ -610,6 +612,80 @@ fn codegen_msvc_try<'ll>(
bx.store(ret, dest, i32_align);
}
// WASM's definition of the `rust_try` function.
fn codegen_wasm_try<'ll>(
bx: &mut Builder<'_, 'll, '_>,
try_func: &'ll Value,
data: &'ll Value,
catch_func: &'ll Value,
dest: &'ll Value,
) {
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
bx.set_personality_fn(bx.eh_personality());
let normal = bx.append_sibling_block("normal");
let catchswitch = bx.append_sibling_block("catchswitch");
let catchpad = bx.append_sibling_block("catchpad");
let caught = bx.append_sibling_block("caught");
let try_func = llvm::get_param(bx.llfn(), 0);
let data = llvm::get_param(bx.llfn(), 1);
let catch_func = llvm::get_param(bx.llfn(), 2);
// We're generating an IR snippet that looks like:
//
// declare i32 @rust_try(%try_func, %data, %catch_func) {
// %slot = alloca i8*
// invoke %try_func(%data) to label %normal unwind label %catchswitch
//
// normal:
// ret i32 0
//
// catchswitch:
// %cs = catchswitch within none [%catchpad] unwind to caller
//
// catchpad:
// %tok = catchpad within %cs [null]
// %ptr = call @llvm.wasm.get.exception(token %tok)
// %sel = call @llvm.wasm.get.ehselector(token %tok)
// call %catch_func(%data, %ptr)
// catchret from %tok to label %caught
//
// caught:
// ret i32 1
// }
//
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None);
bx.switch_to_block(normal);
bx.ret(bx.const_i32(0));
bx.switch_to_block(catchswitch);
let cs = bx.catch_switch(None, None, &[catchpad]);
bx.switch_to_block(catchpad);
let null = bx.const_null(bx.type_i8p());
let funclet = bx.catch_pad(cs, &[null]);
let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[funclet.cleanuppad()]);
let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[funclet.cleanuppad()]);
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet));
bx.catch_ret(&funclet, caught);
bx.switch_to_block(caught);
bx.ret(bx.const_i32(1));
});
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
// Definition of the standard `try` function for Rust using the GNU-like model
// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
// instructions).

View File

@ -1071,6 +1071,7 @@ extern "C" {
// Operations on other types
pub fn LLVMVoidTypeInContext(C: &Context) -> &Type;
pub fn LLVMTokenTypeInContext(C: &Context) -> &Type;
pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
// Operations on all values
@ -1301,7 +1302,7 @@ extern "C" {
NumArgs: c_uint,
Then: &'a BasicBlock,
Catch: &'a BasicBlock,
OpBundles: *const Option<&OperandBundleDef<'a>>,
OpBundles: *const &OperandBundleDef<'a>,
NumOpBundles: c_uint,
Name: *const c_char,
) -> &'a Value;
@ -1673,7 +1674,7 @@ extern "C" {
Fn: &'a Value,
Args: *const &'a Value,
NumArgs: c_uint,
OpBundles: *const Option<&OperandBundleDef<'a>>,
OpBundles: *const &OperandBundleDef<'a>,
NumOpBundles: c_uint,
) -> &'a Value;
pub fn LLVMRustBuildMemCpy<'a>(
@ -2512,6 +2513,7 @@ extern "C" {
remark_all_passes: bool,
remark_passes: *const *const c_char,
remark_passes_len: usize,
remark_file: *const c_char,
);
#[allow(improper_ctypes)]

View File

@ -52,6 +52,10 @@ impl<'ll> CodegenCx<'ll, '_> {
unsafe { llvm::LLVMVoidTypeInContext(self.llcx) }
}
pub(crate) fn type_token(&self) -> &'ll Type {
unsafe { llvm::LLVMTokenTypeInContext(self.llcx) }
}
pub(crate) fn type_metadata(&self) -> &'ll Type {
unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) }
}

View File

@ -21,6 +21,8 @@ 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_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified

View File

@ -12,7 +12,7 @@ use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, Strip};
use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
use rustc_session::cstore::DllImport;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
@ -1688,7 +1688,7 @@ fn detect_self_contained_mingw(sess: &Session) -> bool {
/// instead of being found somewhere on the host system.
/// We only provide such support for a very limited number of targets.
fn self_contained(sess: &Session, crate_type: CrateType) -> bool {
if let Some(self_contained) = sess.opts.cg.link_self_contained {
if let Some(self_contained) = sess.opts.cg.link_self_contained.explicitly_set {
if sess.target.link_self_contained == LinkSelfContainedDefault::False {
sess.emit_err(errors::UnsupportedLinkSelfContained);
}
@ -2246,7 +2246,8 @@ fn add_order_independent_options(
out_filename: &Path,
tmpdir: &Path,
) {
add_gcc_ld_path(cmd, sess, flavor);
// Take care of the flavors and CLI options requesting the `lld` linker.
add_lld_args(cmd, sess, flavor);
add_apple_sdk(cmd, sess, flavor);
@ -2948,55 +2949,66 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootErro
}
}
fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
if let Some(ld_impl) = sess.opts.unstable_opts.gcc_ld {
if let LinkerFlavor::Gnu(Cc::Yes, _)
| LinkerFlavor::Darwin(Cc::Yes, _)
| LinkerFlavor::WasmLld(Cc::Yes) = flavor
{
match ld_impl {
LdImpl::Lld => {
// Implement the "self-contained" part of -Zgcc-ld
// by adding rustc distribution directories to the tool search path.
for path in sess.get_tools_search_paths(false) {
cmd.arg({
let mut arg = OsString::from("-B");
arg.push(path.join("gcc-ld"));
arg
});
}
// Implement the "linker flavor" part of -Zgcc-ld
// by asking cc to use some kind of lld.
cmd.arg("-fuse-ld=lld");
/// When using the linker flavors opting in to `lld`, or the unstable `-Zgcc-ld=lld` flag, add the
/// necessary paths and arguments to invoke it:
/// - when the self-contained linker flag is active: the build of `lld` distributed with rustc,
/// - or any `lld` available to `cc`.
fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
let unstable_use_lld = sess.opts.unstable_opts.gcc_ld.is_some();
debug!("add_lld_args requested, flavor: '{flavor:?}', `-Zgcc-ld=lld`: {unstable_use_lld}");
if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
//
// Note that we don't want to do that by default on macOS: e.g. passing a
// 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
// shown in issue #101653 and the discussion in PR #101792.
//
// It could be required in some cases of cross-compiling with
// `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
// which specific versions of clang, macOS SDK, host and target OS
// combinations impact us here.
//
// So we do a simple first-approximation until we know more of what the
// Apple targets require (and which would be handled prior to hitting this
// `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
// this should be manually passed if needed. We specify the target when
// targeting a different linker flavor on macOS, and that's also always
// the case when targeting WASM.
if sess.target.linker_flavor != sess.host.linker_flavor {
cmd.arg(format!("--target={}", sess.target.llvm_target));
}
}
}
}
} else {
sess.emit_fatal(errors::OptionGccOnly);
// Sanity check: using the old unstable `-Zgcc-ld=lld` option requires a `cc`-using flavor.
let flavor_uses_cc = flavor.uses_cc();
if unstable_use_lld && !flavor_uses_cc {
sess.emit_fatal(errors::OptionGccOnly);
}
// If the flavor doesn't use a C/C++ compiler to invoke the linker, or doesn't opt in to `lld`,
// we don't need to do anything.
let use_lld = flavor.uses_lld() || unstable_use_lld;
if !flavor_uses_cc || !use_lld {
return;
}
// 1. Implement the "self-contained" part of this feature by adding rustc distribution
// directories to the tool's search path.
let self_contained_linker = sess.opts.cg.link_self_contained.linker() || unstable_use_lld;
if self_contained_linker {
for path in sess.get_tools_search_paths(false) {
cmd.arg({
let mut arg = OsString::from("-B");
arg.push(path.join("gcc-ld"));
arg
});
}
}
// 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of
// `lld` as the linker.
cmd.arg("-fuse-ld=lld");
if !flavor.is_gnu() {
// Tell clang to use a non-default LLD flavor.
// Gcc doesn't understand the target option, but we currently assume
// that gcc is not used for Apple and Wasm targets (#97402).
//
// Note that we don't want to do that by default on macOS: e.g. passing a
// 10.7 target to LLVM works, but not to recent versions of clang/macOS, as
// shown in issue #101653 and the discussion in PR #101792.
//
// It could be required in some cases of cross-compiling with
// `-Zgcc-ld=lld`, but this is generally unspecified, and we don't know
// which specific versions of clang, macOS SDK, host and target OS
// combinations impact us here.
//
// So we do a simple first-approximation until we know more of what the
// Apple targets require (and which would be handled prior to hitting this
// `-Zgcc-ld=lld` codepath anyway), but the expectation is that until then
// this should be manually passed if needed. We specify the target when
// targeting a different linker flavor on macOS, and that's also always
// the case when targeting WASM.
if sess.target.linker_flavor != sess.host.linker_flavor {
cmd.arg(format!("--target={}", sess.target.llvm_target));
}
}
}

View File

@ -20,7 +20,7 @@ use rustc_metadata::EncodedMetadata;
use rustc_session::cstore::MetadataLoader;
use rustc_session::Session;
use rustc_target::abi::Endian;
use rustc_target::spec::{RelocModel, Target};
use rustc_target::spec::{ef_avr_arch, RelocModel, Target};
/// The default metadata loader. This is used by cg_llvm and cg_clif.
///
@ -284,8 +284,24 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
e_flags
}
Architecture::LoongArch64 => {
// Source: https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_e_flags_identifies_abi_type_and_version
elf::EF_LARCH_OBJABI_V1 | elf::EF_LARCH_ABI_DOUBLE_FLOAT
// Source: https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc#e_flags-identifies-abi-type-and-version
let mut e_flags: u32 = elf::EF_LARCH_OBJABI_V1;
let features = &sess.target.options.features;
// Select the appropriate floating-point ABI
if features.contains("+d") {
e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT;
} else if features.contains("+f") {
e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT;
} else {
e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT;
}
e_flags
}
Architecture::Avr => {
// Resolve the ISA revision and set
// the appropriate EF_AVR_ARCH flag.
ef_avr_arch(&sess.target.options.cpu)
}
_ => 0,
};

View File

@ -35,6 +35,7 @@ use rustc_span::symbol::sym;
use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
use rustc_target::spec::{MergeFunctions, SanitizerSet};
use crate::errors::ErrorCreatingRemarkDir;
use std::any::Any;
use std::borrow::Cow;
use std::fs;
@ -345,6 +346,9 @@ pub struct CodegenContext<B: WriteBackendMethods> {
pub diag_emitter: SharedEmitter,
/// LLVM optimizations for which we want to print remarks.
pub remark: Passes,
/// Directory into which should the LLVM optimization remarks be written.
/// If `None`, they will be written to stderr.
pub remark_dir: Option<PathBuf>,
/// Worker thread number
pub worker: usize,
/// The incremental compilation session directory, or None if we are not
@ -698,28 +702,49 @@ impl<B: WriteBackendMethods> WorkItem<B> {
/// Generate a short description of this work item suitable for use as a thread name.
fn short_description(&self) -> String {
// `pthread_setname()` on *nix is limited to 15 characters and longer names are ignored.
// Use very short descriptions in this case to maximize the space available for the module name.
// Windows does not have that limitation so use slightly more descriptive names there.
// `pthread_setname()` on *nix ignores anything beyond the first 15
// bytes. Use short descriptions to maximize the space available for
// the module name.
#[cfg(not(windows))]
fn desc(short: &str, _long: &str, name: &str) -> String {
// The short label is three bytes, and is followed by a space. That
// leaves 11 bytes for the CGU name. How we obtain those 11 bytes
// depends on the the CGU name form.
//
// - Non-incremental, e.g. `regex.f10ba03eb5ec7975-cgu.0`: the part
// before the `-cgu.0` is the same for every CGU, so use the
// `cgu.0` part. The number suffix will be different for each
// CGU.
//
// - Incremental (normal), e.g. `2i52vvl2hco29us0`: use the whole
// name because each CGU will have a unique ASCII hash, and the
// first 11 bytes will be enough to identify it.
//
// - Incremental (with `-Zhuman-readable-cgu-names`), e.g.
// `regex.f10ba03eb5ec7975-re_builder.volatile`: use the whole
// name. The first 11 bytes won't be enough to uniquely identify
// it, but no obvious substring will, and this is a rarely used
// option so it doesn't matter much.
//
assert_eq!(short.len(), 3);
let name = if let Some(index) = name.find("-cgu.") {
&name[index + 1..] // +1 skips the leading '-'.
} else {
name
};
format!("{short} {name}")
}
// Windows has no thread name length limit, so use more descriptive names.
#[cfg(windows)]
fn desc(_short: &str, long: &str, name: &str) -> String {
format!("{long} {name}")
}
match self {
WorkItem::Optimize(m) => {
#[cfg(windows)]
return format!("optimize module {}", m.name);
#[cfg(not(windows))]
return format!("opt {}", m.name);
}
WorkItem::CopyPostLtoArtifacts(m) => {
#[cfg(windows)]
return format!("copy LTO artifacts for {}", m.name);
#[cfg(not(windows))]
return format!("copy {}", m.name);
}
WorkItem::LTO(m) => {
#[cfg(windows)]
return format!("LTO module {}", m.name());
#[cfg(not(windows))]
return format!("LTO {}", m.name());
}
WorkItem::Optimize(m) => desc("opt", "optimize module {}", &m.name),
WorkItem::CopyPostLtoArtifacts(m) => desc("cpy", "copy LTO artifacts for {}", &m.name),
WorkItem::LTO(m) => desc("lto", "LTO module {}", m.name()),
}
}
}
@ -1041,6 +1066,17 @@ fn start_executing_work<B: ExtraBackendMethods>(
tcx.backend_optimization_level(())
};
let backend_features = tcx.global_backend_features(());
let remark_dir = if let Some(ref dir) = sess.opts.unstable_opts.remark_dir {
let result = fs::create_dir_all(dir).and_then(|_| dir.canonicalize());
match result {
Ok(dir) => Some(dir),
Err(error) => sess.emit_fatal(ErrorCreatingRemarkDir { error }),
}
} else {
None
};
let cgcx = CodegenContext::<B> {
crate_types: sess.crate_types().to_vec(),
each_linked_rlib_for_lto,
@ -1052,6 +1088,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
prof: sess.prof.clone(),
exported_symbols,
remark: sess.opts.cg.remark.clone(),
remark_dir,
worker: 0,
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),

View File

@ -357,6 +357,13 @@ pub fn cast_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
}
}
// Returns `true` if this session's target will use native wasm
// exceptions. This means that the VM does the unwinding for
// us
pub fn wants_wasm_eh(sess: &Session) -> bool {
sess.target.is_like_wasm && sess.target.os != "emscripten"
}
/// Returns `true` if this session's target will use SEH-based unwinding.
///
/// This is only true for MSVC targets, and even then the 64-bit MSVC target
@ -366,6 +373,13 @@ pub fn wants_msvc_seh(sess: &Session) -> bool {
sess.target.is_like_msvc
}
/// Returns `true` if this session's target requires the new exception
/// handling LLVM IR instructions (catchpad / cleanuppad / ... instead
/// of landingpad)
pub fn wants_new_eh_instructions(sess: &Session) -> bool {
wants_wasm_eh(sess) || wants_msvc_seh(sess)
}
pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
dst: Bx::Value,

View File

@ -1023,3 +1023,9 @@ pub struct TargetFeatureSafeTrait {
#[label(codegen_ssa_label_def)]
pub def: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_error_creating_remark_dir)]
pub struct ErrorCreatingRemarkDir {
pub error: std::io::Error,
}

View File

@ -79,8 +79,8 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
lltarget = fx.landing_pad_for(target);
}
if is_cleanupret {
// MSVC cross-funclet jump - need a trampoline
debug_assert!(base::wants_msvc_seh(fx.cx.tcx().sess));
// Cross-funclet jump - need a trampoline
debug_assert!(base::wants_new_eh_instructions(fx.cx.tcx().sess));
debug!("llbb_with_cleanup: creating cleanup trampoline for {:?}", target);
let name = &format!("{:?}_cleanup_trampoline_{:?}", self.bb, target);
let trampoline_llbb = Bx::append_block(fx.cx, fx.llfn, name);
@ -177,9 +177,16 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
mir::UnwindAction::Continue => None,
mir::UnwindAction::Unreachable => None,
mir::UnwindAction::Terminate => {
if fx.mir[self.bb].is_cleanup && base::wants_msvc_seh(fx.cx.tcx().sess) {
// SEH will abort automatically if an exception tries to
if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) {
// MSVC SEH will abort automatically if an exception tries to
// propagate out from cleanup.
// FIXME(@mirkootter): For wasm, we currently do not support terminate during
// cleanup, because this requires a few more changes: The current code
// caches the `terminate_block` for each function; funclet based code - however -
// requires a different terminate_block for each funclet
// Until this is implemented, we just do not unwind inside cleanup blocks
None
} else {
Some(fx.terminate_block())
@ -863,13 +870,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// promotes any complex rvalues to constants.
if i == 2 && intrinsic.as_str().starts_with("simd_shuffle") {
if let mir::Operand::Constant(constant) = arg {
let c = self.eval_mir_constant(constant);
let (llval, ty) = self.simd_shuffle_indices(
&bx,
constant.span,
self.monomorphize(constant.ty()),
c,
);
let (llval, ty) = self.simd_shuffle_indices(&bx, constant);
return OperandRef {
val: Immediate(llval),
layout: bx.layout_of(ty),
@ -1528,7 +1529,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// FIXME(eddyb) rename this to `eh_pad_for_uncached`.
fn landing_pad_for_uncached(&mut self, bb: mir::BasicBlock) -> Bx::BasicBlock {
let llbb = self.llbb(bb);
if base::wants_msvc_seh(self.cx.sess()) {
if base::wants_new_eh_instructions(self.cx.sess()) {
let cleanup_bb = Bx::append_block(self.cx, self.llfn, &format!("funclet_{:?}", bb));
let mut cleanup_bx = Bx::build(self.cx, cleanup_bb);
let funclet = cleanup_bx.cleanup_pad(None, &[]);
@ -1587,6 +1588,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// } catch (...) {
// bar();
// }
//
// which creates an IR snippet like
//
// cs_terminate:
// %cs = catchswitch within none [%cp_terminate] unwind to caller
// cp_terminate:
// %cp = catchpad within %cs [null, i32 64, null]
// ...
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");

View File

@ -5,7 +5,6 @@ use rustc_middle::mir;
use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_target::abi::Abi;
use super::FunctionCx;
@ -59,22 +58,40 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
})
}
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
/// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
pub fn eval_unevaluated_mir_constant_to_valtree(
&self,
constant: &mir::Constant<'tcx>,
) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
let uv = match constant.literal {
mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(),
other => span_bug!(constant.span, "{other:#?}"),
};
let uv = self.monomorphize(uv);
self.cx.tcx().const_eval_resolve_for_typeck(
ty::ParamEnv::reveal_all(),
uv,
Some(constant.span),
)
}
/// process constant containing SIMD shuffle indices
pub fn simd_shuffle_indices(
&mut self,
bx: &Bx,
span: Span,
ty: Ty<'tcx>,
constant: Result<ConstValue<'tcx>, ErrorHandled>,
constant: &mir::Constant<'tcx>,
) -> (Bx::Value, Ty<'tcx>) {
constant
let ty = self.monomorphize(constant.ty());
let val = self
.eval_unevaluated_mir_constant_to_valtree(constant)
.ok()
.flatten()
.map(|val| {
let field_ty = ty.builtin_index().unwrap();
let c = mir::ConstantKind::from_value(val, ty);
let values: Vec<_> = bx
.tcx()
.destructure_mir_constant(ty::ParamEnv::reveal_all(), c)
.fields
let values: Vec<_> = val
.unwrap_branch()
.iter()
.map(|field| {
if let Some(prim) = field.try_to_scalar() {
@ -88,15 +105,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
})
.collect();
let llval = bx.const_struct(&values, false);
(llval, c.ty())
bx.const_struct(&values, false)
})
.unwrap_or_else(|_| {
bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span });
.unwrap_or_else(|| {
bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });
// We've errored, so we don't have to produce working code.
let ty = self.monomorphize(ty);
let llty = bx.backend_type(bx.layout_of(ty));
(bx.const_undef(llty), ty)
})
bx.const_undef(llty)
});
(val, ty)
}
}

View File

@ -179,7 +179,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
start_bx.set_personality_fn(cx.eh_personality());
}
let cleanup_kinds = base::wants_msvc_seh(cx.tcx().sess).then(|| analyze::cleanup_kinds(&mir));
let cleanup_kinds =
base::wants_new_eh_instructions(cx.tcx().sess).then(|| analyze::cleanup_kinds(&mir));
let cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>> =
mir.basic_blocks

View File

@ -284,6 +284,7 @@ const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// tidy-alphabetical-start
("atomics", Some(sym::wasm_target_feature)),
("bulk-memory", Some(sym::wasm_target_feature)),
("exception-handling", Some(sym::wasm_target_feature)),
("multivalue", Some(sym::wasm_target_feature)),
("mutable-globals", Some(sym::wasm_target_feature)),
("nontrapping-fptoint", Some(sym::wasm_target_feature)),

View File

@ -92,7 +92,6 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
param_env: ty::ParamEnv<'tcx>,
val: mir::ConstantKind<'tcx>,
) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
trace!("destructure_mir_constant: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
let op = ecx.eval_mir_constant(&val, None, None)?;

View File

@ -72,7 +72,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
}
sym::pref_align_of => {
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(*e)))?;
ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx)
}
sym::type_id => {

View File

@ -344,15 +344,18 @@ where
};
// Check the qualifs of the value of `const` items.
// FIXME(valtrees): check whether const qualifs should behave the same
// way for type and mir constants.
let uneval = match constant.literal {
ConstantKind::Ty(ct)
if matches!(ct.kind(), ty::ConstKind::Param(_) | ty::ConstKind::Error(_)) =>
if matches!(
ct.kind(),
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
) =>
{
None
}
ConstantKind::Ty(c) => bug!("expected ConstKind::Param here, found {:?}", c),
ConstantKind::Ty(c) => {
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
}
ConstantKind::Unevaluated(uv, _) => Some(uv),
ConstantKind::Val(..) => None,
};

View File

@ -21,7 +21,7 @@ pub fn check_validity_requirement<'tcx>(
tcx: TyCtxt<'tcx>,
kind: ValidityRequirement,
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Result<bool, LayoutError<'tcx>> {
) -> Result<bool, &'tcx LayoutError<'tcx>> {
let layout = tcx.layout_of(param_env_and_ty)?;
// There is nothing strict or lax about inhabitedness.
@ -43,7 +43,7 @@ fn might_permit_raw_init_strict<'tcx>(
ty: TyAndLayout<'tcx>,
tcx: TyCtxt<'tcx>,
kind: ValidityRequirement,
) -> Result<bool, LayoutError<'tcx>> {
) -> Result<bool, &'tcx LayoutError<'tcx>> {
let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error);
let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
@ -75,7 +75,7 @@ fn might_permit_raw_init_lax<'tcx>(
this: TyAndLayout<'tcx>,
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
init_kind: ValidityRequirement,
) -> Result<bool, LayoutError<'tcx>> {
) -> Result<bool, &'tcx LayoutError<'tcx>> {
let scalar_allows_raw_init = move |s: Scalar| -> bool {
match init_kind {
ValidityRequirement::Inhabited => {

View File

@ -68,7 +68,6 @@ pub mod macros;
pub mod obligation_forest;
pub mod sip128;
pub mod small_c_str;
pub mod small_str;
pub mod snapshot_map;
pub mod svh;
pub use ena::snapshot_vec;

View File

@ -1,68 +0,0 @@
use smallvec::SmallVec;
#[cfg(test)]
mod tests;
/// Like SmallVec but for strings.
#[derive(Default)]
pub struct SmallStr<const N: usize>(SmallVec<[u8; N]>);
impl<const N: usize> SmallStr<N> {
#[inline]
pub fn new() -> Self {
SmallStr(SmallVec::default())
}
#[inline]
pub fn push_str(&mut self, s: &str) {
self.0.extend_from_slice(s.as_bytes());
}
#[inline]
pub fn empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn spilled(&self) -> bool {
self.0.spilled()
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.0.as_slice()) }
}
}
impl<const N: usize> std::ops::Deref for SmallStr<N> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.as_str()
}
}
impl<const N: usize, A: AsRef<str>> FromIterator<A> for SmallStr<N> {
#[inline]
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = A>,
{
let mut s = SmallStr::default();
s.extend(iter);
s
}
}
impl<const N: usize, A: AsRef<str>> Extend<A> for SmallStr<N> {
#[inline]
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A>,
{
for a in iter.into_iter() {
self.push_str(a.as_ref());
}
}
}

View File

@ -1,20 +0,0 @@
use super::*;
#[test]
fn empty() {
let s = SmallStr::<1>::new();
assert!(s.empty());
assert_eq!("", s.as_str());
assert!(!s.spilled());
}
#[test]
fn from_iter() {
let s = ["aa", "bb", "cc"].iter().collect::<SmallStr<6>>();
assert_eq!("aabbcc", s.as_str());
assert!(!s.spilled());
let s = ["aa", "bb", "cc", "dd"].iter().collect::<SmallStr<6>>();
assert_eq!("aabbccdd", s.as_str());
assert!(s.spilled());
}

View File

@ -8,3 +8,6 @@ crate-type = ["dylib"]
[dependencies]
rustc_driver_impl = { path = "../rustc_driver_impl" }
# FIXME(Nilstrieb): 0.37.12 adds eventfd support for FreeBSD,
# but FreeBSD 12 does not support it: https://github.com/bytecodealliance/rustix/issues/716
rustix = "=0.37.11"

View File

@ -543,6 +543,8 @@ declare_features! (
/// Allows creation of instances of a struct by moving fields that have
/// not changed from prior instances of the same struct (RFC #2528)
(active, type_changing_struct_update, "1.58.0", Some(86555), None),
/// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`).
(active, type_privacy_lints, "CURRENT_RUSTC_VERSION", Some(48054), None),
/// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
(active, unix_sigpipe, "1.65.0", Some(97889), None),
/// Allows unsized fn parameters.

View File

@ -2664,6 +2664,10 @@ pub struct OpaqueTy<'hir> {
pub generics: &'hir Generics<'hir>,
pub bounds: GenericBounds<'hir>,
pub origin: OpaqueTyOrigin,
// Opaques have duplicated lifetimes, this mapping connects the original lifetime with the copy
// so we can later generate bidirectional outlives predicates to enforce that these lifetimes
// stay in sync.
pub lifetime_mapping: &'hir [(Lifetime, LocalDefId)],
pub in_trait: bool,
}
@ -3315,7 +3319,7 @@ pub enum ItemKind<'hir> {
/// A type alias, e.g., `type Foo = Bar<u8>`.
TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
/// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
OpaqueTy(OpaqueTy<'hir>),
OpaqueTy(&'hir OpaqueTy<'hir>),
/// An enum definition, e.g., `enum Foo<A, B> {C<A>, D<B>}`.
Enum(EnumDef<'hir>, &'hir Generics<'hir>),
/// A struct definition, e.g., `struct Foo<A> {x: A}`.

View File

@ -502,7 +502,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
visitor.visit_ty(ty);
visitor.visit_generics(generics)
}
ItemKind::OpaqueTy(OpaqueTy { ref generics, bounds, .. }) => {
ItemKind::OpaqueTy(&OpaqueTy { generics, bounds, .. }) => {
visitor.visit_id(item.hir_id());
walk_generics(visitor, generics);
walk_list!(visitor, visit_param_bound, bounds);

View File

@ -99,6 +99,15 @@ hir_analysis_invalid_union_field =
hir_analysis_invalid_union_field_sugg =
wrap the field type in `ManuallyDrop<...>`
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
.label = const parameter declared here
hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetimes from an fn or impl
.label = lifetime declared here
hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl
.label = type parameter declared here
hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait

View File

@ -1984,7 +1984,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.copied()
.filter(|&(impl_, _)| {
infcx.probe(|_| {
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligations(obligations.clone());
let impl_substs = infcx.fresh_substs_for_item(span, impl_);
@ -2809,7 +2809,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let opaque_ty = tcx.hir().item(item_id);
match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
hir::ItemKind::OpaqueTy(&hir::OpaqueTy { origin, .. }) => {
let local_def_id = item_id.owner_id.def_id;
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
// generate the def_id of an associated type for the trait and return as

View File

@ -161,7 +161,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
&self,
ty: Ty<'tcx>,
) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(self.infcx);
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.infcx);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let normalized_ty = match self

View File

@ -299,7 +299,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
}
}
if let ItemKind::OpaqueTy(hir::OpaqueTy {
if let ItemKind::OpaqueTy(&hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
in_trait,
..

View File

@ -19,7 +19,7 @@ use rustc_middle::ty::{
self, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
};
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{
@ -651,11 +651,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let impl_sig = ocx.normalize(
&norm_cause,
param_env,
infcx.instantiate_binder_with_fresh_vars(
return_span,
infer::HigherRankedType,
tcx.fn_sig(impl_m.def_id).subst_identity(),
),
tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(impl_m.def_id).subst_identity()),
);
impl_sig.error_reported()?;
let impl_return_ty = impl_sig.output();
@ -665,9 +661,10 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// them with inference variables.
// We will use these inference variables to collect the hidden types of RPITITs.
let mut collector = ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_def_id);
let unnormalized_trait_sig = tcx
.liberate_late_bound_regions(
impl_m.def_id,
let unnormalized_trait_sig = infcx
.instantiate_binder_with_fresh_vars(
return_span,
infer::HigherRankedType,
tcx.fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs),
)
.fold_with(&mut collector);
@ -760,15 +757,17 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
let mut collected_tys = FxHashMap::default();
for (def_id, (ty, substs)) in collected_types {
match infcx.fully_resolve(ty) {
Ok(ty) => {
match infcx.fully_resolve((ty, substs)) {
Ok((ty, substs)) => {
// `ty` contains free regions that we created earlier while liberating the
// trait fn signature. However, projection normalization expects `ty` to
// contains `def_id`'s early-bound regions.
let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
debug!(?id_substs, ?substs);
let map: FxHashMap<ty::GenericArg<'tcx>, ty::GenericArg<'tcx>> =
std::iter::zip(substs, id_substs).collect();
let map: FxHashMap<_, _> = std::iter::zip(substs, id_substs)
.skip(tcx.generics_of(trait_m.def_id).count())
.filter_map(|(a, b)| Some((a.as_region()?, b.as_region()?)))
.collect();
debug!(?map);
// NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound
@ -793,25 +792,19 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// same generics.
let num_trait_substs = trait_to_impl_substs.len();
let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
let ty = tcx.fold_regions(ty, |region, _| {
match region.kind() {
// Remap all free regions, which correspond to late-bound regions in the function.
ty::ReFree(_) => {}
// Remap early-bound regions as long as they don't come from the `impl` itself.
ty::ReEarlyBound(ebr) if tcx.parent(ebr.def_id) != impl_m.container_id(tcx) => {}
_ => return region,
}
let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
else {
return ty::Region::new_error_with_message(tcx, return_span, "expected ReFree to map to ReEarlyBound")
};
ty::Region::new_early_bound(tcx, ty::EarlyBoundRegion {
def_id: e.def_id,
name: e.name,
index: (e.index as usize - num_trait_substs + num_impl_substs) as u32,
})
});
debug!(%ty);
let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions {
tcx,
map,
num_trait_substs,
num_impl_substs,
def_id,
impl_def_id: impl_m.container_id(tcx),
ty,
return_span,
}) {
Ok(ty) => ty,
Err(guar) => tcx.ty_error(guar),
};
collected_tys.insert(def_id, ty::EarlyBinder::bind(ty));
}
Err(err) => {
@ -895,6 +888,97 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
}
}
struct RemapHiddenTyRegions<'tcx> {
tcx: TyCtxt<'tcx>,
map: FxHashMap<ty::Region<'tcx>, ty::Region<'tcx>>,
num_trait_substs: usize,
num_impl_substs: usize,
def_id: DefId,
impl_def_id: DefId,
ty: Ty<'tcx>,
return_span: Span,
}
impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
type Error = ErrorGuaranteed;
fn interner(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if let ty::Alias(ty::Opaque, ty::AliasTy { substs, def_id, .. }) = *t.kind() {
let mut mapped_substs = Vec::with_capacity(substs.len());
for (arg, v) in std::iter::zip(substs, self.tcx.variances_of(def_id)) {
mapped_substs.push(match (arg.unpack(), v) {
// Skip uncaptured opaque substs
(ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg,
_ => arg.try_fold_with(self)?,
});
}
Ok(self.tcx.mk_opaque(def_id, self.tcx.mk_substs(&mapped_substs)))
} else {
t.try_super_fold_with(self)
}
}
fn try_fold_region(
&mut self,
region: ty::Region<'tcx>,
) -> Result<ty::Region<'tcx>, Self::Error> {
match region.kind() {
// Remap all free regions, which correspond to late-bound regions in the function.
ty::ReFree(_) => {}
// Remap early-bound regions as long as they don't come from the `impl` itself,
// in which case we don't really need to renumber them.
ty::ReEarlyBound(ebr) if self.tcx.parent(ebr.def_id) != self.impl_def_id => {}
_ => return Ok(region),
}
let e = if let Some(region) = self.map.get(&region) {
if let ty::ReEarlyBound(e) = region.kind() { e } else { bug!() }
} else {
let guar = match region.kind() {
ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. })
| ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
..
}) => {
let return_span = if let ty::Alias(ty::Opaque, opaque_ty) = self.ty.kind() {
self.tcx.def_span(opaque_ty.def_id)
} else {
self.return_span
};
self.tcx
.sess
.struct_span_err(
return_span,
"return type captures more lifetimes than trait definition",
)
.span_label(self.tcx.def_span(def_id), "this lifetime was captured")
.span_note(
self.tcx.def_span(self.def_id),
"hidden type must only reference lifetimes captured by this impl trait",
)
.note(format!("hidden type inferred to be `{}`", self.ty))
.emit()
}
_ => self.tcx.sess.delay_span_bug(DUMMY_SP, "should've been able to remap region"),
};
return Err(guar);
};
Ok(ty::Region::new_early_bound(
self.tcx,
ty::EarlyBoundRegion {
def_id: e.def_id,
name: e.name,
index: (e.index as usize - self.num_trait_substs + self.num_impl_substs) as u32,
},
))
}
}
fn report_trait_method_mismatch<'tcx>(
infcx: &InferCtxt<'tcx>,
mut cause: ObligationCause<'tcx>,

View File

@ -1328,7 +1328,7 @@ fn suggest_impl_trait<'tcx>(
{
continue;
}
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
let ocx = ObligationCtxt::new(&infcx);
let item_ty = ocx.normalize(
&ObligationCause::misc(span, def_id),
param_env,

View File

@ -144,7 +144,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
}
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy {
ItemKind::OpaqueTy(&hir::OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
in_trait,

View File

@ -2,7 +2,7 @@ use crate::astconv::{AstConv, OnlySelfBounds, PredicateFilter};
use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
use hir::{HirId, Node};
use hir::{HirId, Lifetime, Node};
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@ -10,9 +10,9 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{GenericPredicates, ToPredicate};
use rustc_middle::ty::{GenericPredicates, Generics, ImplTraitInTraitData, ToPredicate};
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
use rustc_span::{Span, Symbol, DUMMY_SP};
/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
@ -62,6 +62,54 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic
fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::GenericPredicates<'_> {
use rustc_hir::*;
match tcx.opt_rpitit_info(def_id.to_def_id()) {
Some(ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
let opaque_ty_node = tcx.hir().get(opaque_ty_id);
let Node::Item(&Item { kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }), .. }) = opaque_ty_node else {
bug!("unexpected {opaque_ty_node:?}")
};
let mut predicates = Vec::new();
compute_bidirectional_outlives_predicates(
tcx,
def_id,
lifetime_mapping.iter().map(|(lifetime, def_id)| {
(*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
}),
tcx.generics_of(def_id.to_def_id()),
&mut predicates,
);
return ty::GenericPredicates {
parent: Some(tcx.parent(def_id.to_def_id())),
predicates: tcx.arena.alloc_from_iter(predicates),
};
}
Some(ImplTraitInTraitData::Impl { fn_def_id }) => {
let assoc_item = tcx.associated_item(def_id);
let trait_assoc_predicates = tcx.predicates_of(assoc_item.trait_item_def_id.unwrap());
let impl_assoc_identity_substs = InternalSubsts::identity_for_item(tcx, def_id);
let impl_def_id = tcx.parent(fn_def_id);
let impl_trait_ref_substs =
tcx.impl_trait_ref(impl_def_id).unwrap().skip_binder().substs;
let impl_assoc_substs =
impl_assoc_identity_substs.rebase_onto(tcx, impl_def_id, impl_trait_ref_substs);
let impl_predicates = trait_assoc_predicates.instantiate_own(tcx, impl_assoc_substs);
return ty::GenericPredicates {
parent: Some(impl_def_id),
predicates: tcx.arena.alloc_from_iter(impl_predicates),
};
}
None => {}
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let node = tcx.hir().get(hir_id);
@ -289,38 +337,22 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
bug!("unexpected {opaque_ty_node:?}")
};
debug!(?lifetimes);
for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
let orig_region = icx.astconv().ast_region_to_region(&arg, None);
if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
// Only early-bound regions can point to the original generic parameter.
continue;
}
let hir::GenericParamKind::Lifetime { .. } = duplicate.kind else { continue };
let dup_def = duplicate.def_id.to_def_id();
let lifetime_mapping = std::iter::zip(lifetimes, ast_generics.params)
.map(|(arg, dup)| {
let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
(**arg, dup)
})
.filter(|(_, dup)| matches!(dup.kind, hir::GenericParamKind::Lifetime { .. }))
.map(|(lifetime, dup)| (lifetime, (dup.def_id, dup.name.ident().name, dup.span)));
let Some(dup_index) = generics.param_def_id_to_index(tcx, dup_def) else { bug!() };
let dup_region = ty::Region::new_early_bound(
tcx,
ty::EarlyBoundRegion {
def_id: dup_def,
index: dup_index,
name: duplicate.name.ident().name,
},
);
predicates.push((
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region))
.to_predicate(icx.tcx),
duplicate.span,
));
predicates.push((
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region))
.to_predicate(icx.tcx),
duplicate.span,
));
}
compute_bidirectional_outlives_predicates(
tcx,
def_id,
lifetime_mapping,
generics,
&mut predicates,
);
debug!(?predicates);
}
@ -330,6 +362,46 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
}
/// Opaques have duplicated lifetimes and we need to compute bidirectional outlives predicates to
/// enforce that these lifetimes stay in sync.
fn compute_bidirectional_outlives_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
item_def_id: LocalDefId,
lifetime_mapping: impl Iterator<Item = (Lifetime, (LocalDefId, Symbol, Span))>,
generics: &Generics,
predicates: &mut Vec<(ty::Clause<'tcx>, Span)>,
) {
let icx = ItemCtxt::new(tcx, item_def_id);
for (arg, (dup_def, name, span)) in lifetime_mapping {
let orig_region = icx.astconv().ast_region_to_region(&arg, None);
if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
// There is no late-bound lifetime to actually match up here, since the lifetime doesn't
// show up in the opaque's parent's substs.
continue;
}
let Some(dup_index) = generics.param_def_id_to_index(icx.tcx, dup_def.to_def_id()) else { bug!() };
let dup_region = ty::Region::new_early_bound(
tcx,
ty::EarlyBoundRegion { def_id: dup_def.to_def_id(), index: dup_index, name },
);
predicates.push((
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region))
.to_predicate(tcx),
span,
));
predicates.push((
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region))
.to_predicate(tcx),
span,
));
}
}
fn const_evaluatable_predicates_of(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
@ -668,7 +740,7 @@ pub(super) fn type_param_predicates(
ItemKind::Fn(.., generics, _)
| ItemKind::Impl(&hir::Impl { generics, .. })
| ItemKind::TyAlias(_, generics)
| ItemKind::OpaqueTy(OpaqueTy {
| ItemKind::OpaqueTy(&OpaqueTy {
generics,
origin: hir::OpaqueTyOrigin::TyAlias { .. },
..

View File

@ -556,7 +556,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
});
}
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
hir::ItemKind::OpaqueTy(&hir::OpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent),
generics,
..
@ -1344,12 +1344,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
Scope::Binder {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let mut err = self.tcx.sess.struct_span_err(
lifetime_ref.ident.span,
"`impl Trait` can only mention lifetimes bound at the fn or impl level",
);
err.span_note(self.tcx.def_span(region_def_id), "lifetime declared here");
err.emit();
self.tcx.sess.emit_err(errors::LateBoundInApit::Lifetime {
span: lifetime_ref.ident.span,
param_span: self.tcx.def_span(region_def_id),
});
return;
}
Scope::Root { .. } => break,
@ -1379,6 +1377,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
let mut late_depth = 0;
let mut scope = self.scope;
let mut crossed_anon_const = false;
let result = loop {
match *scope {
Scope::Body { s, .. } => {
@ -1446,6 +1445,50 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
return;
}
// We may fail to resolve higher-ranked ty/const vars that are mentioned by APIT.
// AST-based resolution does not care for impl-trait desugaring, which are the
// responsibility of lowering. This may create a mismatch between the resolution
// AST found (`param_def_id`) which points to HRTB, and what HIR allows.
// ```
// fn foo(x: impl for<T> Trait<Assoc = impl Trait2<T>>) {}
// ```
//
// In such case, walk back the binders to diagnose it properly.
let mut scope = self.scope;
loop {
match *scope {
Scope::Binder {
where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
} => {
let guar = self.tcx.sess.emit_err(match self.tcx.def_kind(param_def_id) {
DefKind::TyParam => errors::LateBoundInApit::Type {
span: self.tcx.hir().span(hir_id),
param_span: self.tcx.def_span(param_def_id),
},
DefKind::ConstParam => errors::LateBoundInApit::Const {
span: self.tcx.hir().span(hir_id),
param_span: self.tcx.def_span(param_def_id),
},
kind => {
bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id()))
}
});
self.map.defs.insert(hir_id, ResolvedArg::Error(guar));
return;
}
Scope::Root { .. } => break,
Scope::Binder { s, .. }
| Scope::Body { s, .. }
| Scope::Elision { s, .. }
| Scope::ObjectLifetimeDefault { s, .. }
| Scope::Supertrait { s, .. }
| Scope::TraitRefBoundary { s, .. }
| Scope::AnonConstBoundary { s } => {
scope = s;
}
}
}
self.tcx.sess.delay_span_bug(
self.tcx.hir().span(hir_id),
format!("could not resolve {param_def_id:?}"),

View File

@ -435,7 +435,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(OpaqueTy {
ItemKind::OpaqueTy(&OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
in_trait,

View File

@ -875,3 +875,28 @@ pub(crate) enum ReturnTypeNotationIllegalParam {
param_span: Span,
},
}
#[derive(Diagnostic)]
pub(crate) enum LateBoundInApit {
#[diag(hir_analysis_late_bound_type_in_apit)]
Type {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
#[diag(hir_analysis_late_bound_const_in_apit)]
Const {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
#[diag(hir_analysis_late_bound_lifetime_in_apit)]
Lifetime {
#[primary_span]
span: Span,
#[label]
param_span: Span,
},
}

View File

@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
use rustc_middle::ty::{self, CrateVariancesMap, ImplTraitInTraitData, SubstsRef, Ty, TyCtxt};
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
use std::ops::ControlFlow;
@ -51,20 +51,26 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
| DefKind::Struct
| DefKind::Union
| DefKind::Variant
| DefKind::Ctor(..) => {}
| DefKind::Ctor(..) => {
// These are inferred.
let crate_map = tcx.crate_variances(());
return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
}
DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder => {
return variance_of_opaque(tcx, item_def_id);
}
_ => {
// Variance not relevant.
span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item")
DefKind::AssocTy => {
if let Some(ImplTraitInTraitData::Trait { .. }) =
tcx.opt_rpitit_info(item_def_id.to_def_id())
{
return variance_of_opaque(tcx, item_def_id);
}
}
_ => {}
}
// Everything else must be inferred.
let crate_map = tcx.crate_variances(());
crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[])
// Variance not relevant.
span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item");
}
#[instrument(level = "trace", skip(tcx), ret)]

View File

@ -1033,7 +1033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Ok(ok) = coerce.coerce(source, target) else {
return false;
};
let ocx = ObligationCtxt::new_in_snapshot(self);
let ocx = ObligationCtxt::new(self);
ocx.register_obligations(ok.obligations);
ocx.select_where_possible().is_empty()
})

View File

@ -2962,7 +2962,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
self.commit_if_ok(|_| {
let ocx = ObligationCtxt::new_in_snapshot(self);
let ocx = ObligationCtxt::new(self);
let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id);
let impl_trait_ref =
self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs);

View File

@ -2,7 +2,7 @@ use crate::callee::{self, DeferredCallResolution};
use crate::errors::CtorIsPrivate;
use crate::method::{self, MethodCallee, SelfSource};
use crate::rvalue_scopes;
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, RawTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey};
@ -135,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("{:p}", self)
}
pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
pub fn local_ty(&self, span: Span, nid: hir::HirId) -> Ty<'tcx> {
self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
})
@ -746,7 +746,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let expect_args = self
.fudge_inference_if_ok(|| {
let ocx = ObligationCtxt::new_in_snapshot(self);
let ocx = ObligationCtxt::new(self);
// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
@ -1152,7 +1152,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if let Res::Local(hid) = res {
let ty = self.local_ty(span, hid).decl_ty;
let ty = self.local_ty(span, hid);
let ty = self.normalize(span, ty);
self.write_ty(hir_id, ty);
return (ty, res);

View File

@ -6,8 +6,7 @@ use crate::method::MethodCallee;
use crate::TupleArgumentsFlag::*;
use crate::{errors, Expectation::*};
use crate::{
struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy,
TupleArgumentsFlag,
struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, Needs, RawTy, TupleArgumentsFlag,
};
use rustc_ast as ast;
use rustc_data_structures::fx::FxIndexSet;
@ -1423,7 +1422,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// See #44848.
let ref_bindings = pat.contains_explicit_ref_binding();
let local_ty = self.local_ty(init.span, hir_id).revealed_ty;
let local_ty = self.local_ty(init.span, hir_id);
if let Some(m) = ref_bindings {
// Somewhat subtle: if we have a `ref` binding in the pattern,
// we want to avoid introducing coercions for the RHS. This is
@ -1453,7 +1452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) {
// Determine and write the type which we'll check the pattern against.
let decl_ty = self.local_ty(decl.span, decl.hir_id).decl_ty;
let decl_ty = self.local_ty(decl.span, decl.hir_id);
self.write_ty(decl.hir_id, decl_ty);
// Type check the initializer.
@ -1799,9 +1798,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let err = self.tcx.ty_error(guar);
self.write_ty(hir_id, err);
self.write_ty(pat.hir_id, err);
let local_ty = LocalTy { decl_ty: err, revealed_ty: err };
self.locals.borrow_mut().insert(hir_id, local_ty);
self.locals.borrow_mut().insert(pat.hir_id, local_ty);
self.locals.borrow_mut().insert(hir_id, err);
self.locals.borrow_mut().insert(pat.hir_id, err);
}
}

View File

@ -163,7 +163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return fn_sig;
}
self.probe(|_| {
let ocx = ObligationCtxt::new_in_snapshot(self);
let ocx = ObligationCtxt::new(self);
let normalized_fn_sig =
ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
if ocx.select_all_or_error().is_empty() {

View File

@ -1,4 +1,4 @@
use crate::{FnCtxt, LocalTy};
use crate::FnCtxt;
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::PatKind;
@ -48,7 +48,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
Self { fcx, outermost_fn_param_pat: None }
}
fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<LocalTy<'tcx>>) -> Ty<'tcx> {
fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
match ty_opt {
None => {
// Infer the variable's type.
@ -56,23 +56,20 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
kind: TypeVariableOriginKind::TypeInference,
span,
});
self.fcx
.locals
.borrow_mut()
.insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty });
self.fcx.locals.borrow_mut().insert(nid, var_ty);
var_ty
}
Some(typ) => {
// Take type that the user specified.
self.fcx.locals.borrow_mut().insert(nid, typ);
typ.revealed_ty
typ
}
}
}
/// Allocates a [LocalTy] for a declaration, which may have a type annotation. If it does have
/// a type annotation, then the LocalTy stored will be the resolved type. This may be found
/// again during type checking by querying [FnCtxt::local_ty] for the same hir_id.
/// Allocates a type for a declaration, which may have a type annotation. If it does have
/// a type annotation, then the [`Ty`] stored will be the resolved type. This may be found
/// again during type checking by querying [`FnCtxt::local_ty`] for the same hir_id.
fn declare(&mut self, decl: Declaration<'tcx>) {
let local_ty = match decl.ty {
Some(ref ty) => {
@ -87,7 +84,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
.user_provided_types_mut()
.insert(ty.hir_id, c_ty);
Some(LocalTy { decl_ty: o_ty.normalized, revealed_ty: o_ty.normalized })
Some(o_ty.normalized)
}
None => None,
};
@ -96,7 +93,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
debug!(
"local variable {:?} is assigned type {}",
decl.pat,
self.fcx.ty_to_string(self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
self.fcx.ty_to_string(*self.fcx.locals.borrow().get(&decl.hir_id).unwrap())
);
}
}
@ -151,7 +148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
debug!(
"pattern binding {} is assigned to {} with type {:?}",
ident,
self.fcx.ty_to_string(self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
self.fcx.ty_to_string(*self.fcx.locals.borrow().get(&p.hir_id).unwrap()),
var_ty
);
}

View File

@ -30,7 +30,7 @@ pub struct Inherited<'tcx> {
pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
pub(super) locals: RefCell<HirIdMap<super::LocalTy<'tcx>>>,
pub(super) locals: RefCell<HirIdMap<Ty<'tcx>>>,
pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>,

View File

@ -81,7 +81,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
// Try to display a sensible error with as much information as possible.
let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk {
Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
Ok(SizeSkeleton::Known(size)) => {
if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
Err(LayoutError::Unknown(bad)) => {
if bad == ty {
if *bad == ty {
"this type does not have a fixed size".to_owned()
} else {
format!("size can vary because of {bad}")

View File

@ -89,13 +89,6 @@ macro_rules! type_error_struct {
})
}
/// The type of a local binding, including the revealed type for anon types.
#[derive(Copy, Clone, Debug)]
pub struct LocalTy<'tcx> {
decl_ty: Ty<'tcx>,
revealed_ty: Ty<'tcx>,
}
/// If this `DefId` is a "primary tables entry", returns
/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
///

View File

@ -594,7 +594,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
let local_ty = self.local_ty(pat.span, pat.hir_id).decl_ty;
let local_ty = self.local_ty(pat.span, pat.hir_id);
let eq_ty = match bm {
ty::BindByReference(mutbl) => {
// If the binding is like `ref x | ref mut x`,
@ -635,7 +635,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
ti: TopInfo<'tcx>,
) {
let var_ty = self.local_ty(span, var_id).decl_ty;
let var_ty = self.local_ty(span, var_id);
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
let hir = self.tcx.hir();
let var_ty = self.resolve_vars_with_obligations(var_ty);

View File

@ -348,7 +348,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
intravisit::walk_local(self, l);
let var_ty = self.fcx.local_ty(l.span, l.hir_id).decl_ty;
let var_ty = self.fcx.local_ty(l.span, l.hir_id);
let var_ty = self.resolve(var_ty, &l.span);
self.write_ty_to_typeck_results(l.hir_id, var_ty);
}

View File

@ -79,7 +79,6 @@ impl<'tcx> InferCtxt<'tcx> {
reported_closure_mismatch: self.reported_closure_mismatch.clone(),
tainted_by_errors: self.tainted_by_errors.clone(),
err_count_on_creation: self.err_count_on_creation,
in_snapshot: self.in_snapshot.clone(),
universe: self.universe.clone(),
intercrate: self.intercrate,
next_trait_solver: self.next_trait_solver,

View File

@ -6,6 +6,7 @@ pub use self::RegionVariableOrigin::*;
pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*;
pub use combine::ObligationEmittingRelation;
use rustc_data_structures::undo_log::UndoLogs;
use self::opaque_types::OpaqueTypeStorage;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
@ -297,9 +298,6 @@ pub struct InferCtxt<'tcx> {
// FIXME(matthewjasper) Merge into `tainted_by_errors`
err_count_on_creation: usize,
/// This flag is true while there is an active snapshot.
in_snapshot: Cell<bool>,
/// What is the innermost universe we have created? Starts out as
/// `UniverseIndex::root()` but grows from there as we enter
/// universal quantifiers.
@ -643,7 +641,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
reported_closure_mismatch: Default::default(),
tainted_by_errors: Cell::new(None),
err_count_on_creation: tcx.sess.err_count(),
in_snapshot: Cell::new(false),
universe: Cell::new(ty::UniverseIndex::ROOT),
intercrate,
next_trait_solver,
@ -679,7 +676,6 @@ pub struct CombinedSnapshot<'tcx> {
undo_snapshot: Snapshot<'tcx>,
region_constraints_snapshot: RegionSnapshot,
universe: ty::UniverseIndex,
was_in_snapshot: bool,
}
impl<'tcx> InferCtxt<'tcx> {
@ -702,10 +698,6 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
pub fn is_in_snapshot(&self) -> bool {
self.in_snapshot.get()
}
pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
t.fold_with(&mut self.freshener())
}
@ -766,31 +758,30 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
pub fn in_snapshot(&self) -> bool {
UndoLogs::<UndoLog<'tcx>>::in_snapshot(&self.inner.borrow_mut().undo_log)
}
pub fn num_open_snapshots(&self) -> usize {
UndoLogs::<UndoLog<'tcx>>::num_open_snapshots(&self.inner.borrow_mut().undo_log)
}
fn start_snapshot(&self) -> CombinedSnapshot<'tcx> {
debug!("start_snapshot()");
let in_snapshot = self.in_snapshot.replace(true);
let mut inner = self.inner.borrow_mut();
CombinedSnapshot {
undo_snapshot: inner.undo_log.start_snapshot(),
region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(),
universe: self.universe(),
was_in_snapshot: in_snapshot,
}
}
#[instrument(skip(self, snapshot), level = "debug")]
fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot,
universe,
was_in_snapshot,
} = snapshot;
let CombinedSnapshot { undo_snapshot, region_constraints_snapshot, universe } = snapshot;
self.in_snapshot.set(was_in_snapshot);
self.universe.set(universe);
let mut inner = self.inner.borrow_mut();
@ -800,14 +791,8 @@ impl<'tcx> InferCtxt<'tcx> {
#[instrument(skip(self, snapshot), level = "debug")]
fn commit_from(&self, snapshot: CombinedSnapshot<'tcx>) {
let CombinedSnapshot {
undo_snapshot,
region_constraints_snapshot: _,
universe: _,
was_in_snapshot,
} = snapshot;
self.in_snapshot.set(was_in_snapshot);
let CombinedSnapshot { undo_snapshot, region_constraints_snapshot: _, universe: _ } =
snapshot;
self.inner.borrow_mut().commit(undo_snapshot);
}

View File

@ -125,10 +125,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// right before lexical region resolution.
#[instrument(level = "debug", skip(self, outlives_env))]
pub fn process_registered_region_obligations(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
assert!(
!self.in_snapshot.get(),
"cannot process registered region obligations in a snapshot"
);
assert!(!self.in_snapshot(), "cannot process registered region obligations in a snapshot");
let my_region_obligations = self.take_registered_region_obligations();

View File

@ -80,14 +80,14 @@ pub struct Elaborator<'tcx, O> {
pub trait Elaboratable<'tcx> {
fn predicate(&self) -> ty::Predicate<'tcx>;
// Makes a new `Self` but with a different predicate.
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self;
// Makes a new `Self` but with a different clause that comes from elaboration.
fn child(&self, clause: ty::Clause<'tcx>) -> Self;
// Makes a new `Self` but with a different predicate and a different cause
// code (if `Self` has one).
// Makes a new `Self` but with a different clause and a different cause
// code (if `Self` has one, such as [`PredicateObligation`]).
fn child_with_derived_cause(
&self,
predicate: ty::Predicate<'tcx>,
clause: ty::Clause<'tcx>,
span: Span,
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
index: usize,
@ -99,18 +99,18 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
self.predicate
}
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
recursion_depth: 0,
predicate,
predicate: clause.as_predicate(),
}
}
fn child_with_derived_cause(
&self,
predicate: ty::Predicate<'tcx>,
clause: ty::Clause<'tcx>,
span: Span,
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
index: usize,
@ -123,7 +123,12 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> {
span,
}))
});
Obligation { cause, param_env: self.param_env, recursion_depth: 0, predicate }
Obligation {
cause,
param_env: self.param_env,
recursion_depth: 0,
predicate: clause.as_predicate(),
}
}
}
@ -132,18 +137,18 @@ impl<'tcx> Elaboratable<'tcx> for ty::Predicate<'tcx> {
*self
}
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
predicate
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
clause.as_predicate()
}
fn child_with_derived_cause(
&self,
predicate: ty::Predicate<'tcx>,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
predicate
clause.as_predicate()
}
}
@ -152,18 +157,18 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Predicate<'tcx>, Span) {
self.0
}
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
(predicate, self.1)
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
(clause.as_predicate(), self.1)
}
fn child_with_derived_cause(
&self,
predicate: ty::Predicate<'tcx>,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
(predicate, self.1)
(clause.as_predicate(), self.1)
}
}
@ -172,18 +177,18 @@ impl<'tcx> Elaboratable<'tcx> for (ty::Clause<'tcx>, Span) {
self.0.as_predicate()
}
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
(predicate.expect_clause(), self.1)
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
(clause, self.1)
}
fn child_with_derived_cause(
&self,
predicate: ty::Predicate<'tcx>,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
(predicate.expect_clause(), self.1)
(clause, self.1)
}
}
@ -192,18 +197,18 @@ impl<'tcx> Elaboratable<'tcx> for ty::Clause<'tcx> {
self.as_predicate()
}
fn child(&self, predicate: ty::Predicate<'tcx>) -> Self {
predicate.expect_clause()
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
clause
}
fn child_with_derived_cause(
&self,
predicate: ty::Predicate<'tcx>,
clause: ty::Clause<'tcx>,
_span: Span,
_parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
_index: usize,
) -> Self {
predicate.expect_clause()
clause
}
}
@ -252,14 +257,13 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
};
let obligations =
predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
predicates.predicates.iter().enumerate().map(|(index, &(mut clause, span))| {
// when parent predicate is non-const, elaborate it to non-const predicates.
if data.constness == ty::BoundConstness::NotConst {
pred = pred.without_const(tcx);
clause = clause.without_const(tcx);
}
elaboratable.child_with_derived_cause(
pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref))
.as_predicate(),
clause.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
span,
bound_predicate.rebind(data),
index,
@ -333,17 +337,15 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
if r.is_late_bound() {
None
} else {
Some(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
ty::OutlivesPredicate(r, r_min),
Some(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
r, r_min,
)))
}
}
Component::Param(p) => {
let ty = tcx.mk_ty_param(p.index, p.name);
Some(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
ty::OutlivesPredicate(ty, r_min),
)))
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, r_min)))
}
Component::UnresolvedInferenceVariable(_) => None,
@ -351,8 +353,9 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
Component::Alias(alias_ty) => {
// We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
// With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
Some(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
ty::OutlivesPredicate(alias_ty.to_ty(tcx), r_min),
Some(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
alias_ty.to_ty(tcx),
r_min,
)))
}
@ -362,10 +365,9 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
None
}
})
.map(|predicate_kind| {
bound_predicate.rebind(predicate_kind).to_predicate(tcx)
})
.map(|predicate| elaboratable.child(predicate)),
.map(|clause| {
elaboratable.child(bound_predicate.rebind(clause).to_predicate(tcx))
}),
);
}
ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {

View File

@ -8,6 +8,7 @@ use rustc_session::config::rustc_optgroups;
use rustc_session::config::DebugInfo;
use rustc_session::config::Input;
use rustc_session::config::InstrumentXRay;
use rustc_session::config::LinkSelfContained;
use rustc_session::config::TraitSolver;
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
use rustc_session::config::{
@ -579,7 +580,7 @@ fn test_codegen_options_tracking_hash() {
untracked!(incremental, Some(String::from("abc")));
// `link_arg` is omitted because it just forwards to `link_args`.
untracked!(link_args, vec![String::from("abc"), String::from("def")]);
untracked!(link_self_contained, Some(true));
untracked!(link_self_contained, LinkSelfContained::on());
untracked!(linker, Some(PathBuf::from("linker")));
untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc));
untracked!(no_stack_check, true);

View File

@ -665,9 +665,7 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])
impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
&& cx.tcx.local_visibility(item.owner_id.def_id).is_public())
{
if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}
let (def, ty) = match item.kind {
@ -786,9 +784,7 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
&& cx.tcx.local_visibility(item.owner_id.def_id).is_public())
{
if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}

View File

@ -194,7 +194,7 @@ fn is_single_call_in_arm<'tcx>(
arg: &'tcx Expr<'_>,
drop_expr: &'tcx Expr<'_>,
) -> bool {
if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) {
if arg.can_have_side_effects() {
let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id);
if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
return body.hir_id == drop_expr.hir_id;

View File

@ -4264,6 +4264,7 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(type_privacy_lints)]
/// # #![allow(unused)]
/// # #![allow(private_in_public)]
/// #![deny(private_interfaces)]
@ -4288,6 +4289,7 @@ declare_lint! {
pub PRIVATE_INTERFACES,
Allow,
"private type in primary interface of an item",
@feature_gate = sym::type_privacy_lints;
}
declare_lint! {
@ -4298,6 +4300,7 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(type_privacy_lints)]
/// # #![allow(private_in_public)]
/// # #![allow(unused)]
/// #![deny(private_bounds)]
@ -4317,7 +4320,8 @@ declare_lint! {
/// the item actually provides.
pub PRIVATE_BOUNDS,
Allow,
"private type in secondary interface of an item"
"private type in secondary interface of an item",
@feature_gate = sym::type_privacy_lints;
}
declare_lint! {
@ -4327,6 +4331,7 @@ declare_lint! {
/// ### Example
///
/// ```rust,compile_fail
/// # #![feature(type_privacy_lints)]
/// # #![allow(unused)]
/// #![deny(unnameable_types)]
/// mod m {
@ -4345,5 +4350,6 @@ declare_lint! {
/// you can name the type `T` as well, this lint attempts to enforce this rule.
pub UNNAMEABLE_TYPES,
Allow,
"effective visibility of a type is larger than the area in which it can be named"
"effective visibility of a type is larger than the area in which it can be named",
@feature_gate = sym::type_privacy_lints;
}

View File

@ -7,7 +7,12 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/Mangler.h"
#include "llvm/Remarks/RemarkStreamer.h"
#include "llvm/Remarks/RemarkSerializer.h"
#include "llvm/Remarks/RemarkFormat.h"
#include "llvm/Support/ToolOutputFile.h"
#if LLVM_VERSION_GE(16, 0)
#include "llvm/Support/ModRef.h"
#endif
@ -1855,23 +1860,44 @@ using LLVMDiagnosticHandlerTy = DiagnosticHandler::DiagnosticHandlerTy;
// When RemarkAllPasses is true, remarks are enabled for all passes. Otherwise
// the RemarkPasses array specifies individual passes for which remarks will be
// enabled.
//
// If RemarkFilePath is not NULL, optimization remarks will be streamed directly into this file,
// bypassing the diagnostics handler.
extern "C" void LLVMRustContextConfigureDiagnosticHandler(
LLVMContextRef C, LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
void *DiagnosticHandlerContext, bool RemarkAllPasses,
const char * const * RemarkPasses, size_t RemarkPassesLen) {
const char * const * RemarkPasses, size_t RemarkPassesLen,
const char * RemarkFilePath
) {
class RustDiagnosticHandler final : public DiagnosticHandler {
public:
RustDiagnosticHandler(LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
void *DiagnosticHandlerContext,
bool RemarkAllPasses,
std::vector<std::string> RemarkPasses)
RustDiagnosticHandler(
LLVMDiagnosticHandlerTy DiagnosticHandlerCallback,
void *DiagnosticHandlerContext,
bool RemarkAllPasses,
std::vector<std::string> RemarkPasses,
std::unique_ptr<ToolOutputFile> RemarksFile,
std::unique_ptr<llvm::remarks::RemarkStreamer> RemarkStreamer,
std::unique_ptr<LLVMRemarkStreamer> LlvmRemarkStreamer
)
: DiagnosticHandlerCallback(DiagnosticHandlerCallback),
DiagnosticHandlerContext(DiagnosticHandlerContext),
RemarkAllPasses(RemarkAllPasses),
RemarkPasses(RemarkPasses) {}
RemarkPasses(std::move(RemarkPasses)),
RemarksFile(std::move(RemarksFile)),
RemarkStreamer(std::move(RemarkStreamer)),
LlvmRemarkStreamer(std::move(LlvmRemarkStreamer)) {}
virtual bool handleDiagnostics(const DiagnosticInfo &DI) override {
if (this->LlvmRemarkStreamer) {
if (auto *OptDiagBase = dyn_cast<DiagnosticInfoOptimizationBase>(&DI)) {
if (OptDiagBase->isEnabled()) {
this->LlvmRemarkStreamer->emit(*OptDiagBase);
return true;
}
}
}
if (DiagnosticHandlerCallback) {
DiagnosticHandlerCallback(DI, DiagnosticHandlerContext);
return true;
@ -1912,14 +1938,64 @@ extern "C" void LLVMRustContextConfigureDiagnosticHandler(
bool RemarkAllPasses = false;
std::vector<std::string> RemarkPasses;
// Since LlvmRemarkStreamer contains a pointer to RemarkStreamer, the ordering of the three
// members below is important.
std::unique_ptr<ToolOutputFile> RemarksFile;
std::unique_ptr<llvm::remarks::RemarkStreamer> RemarkStreamer;
std::unique_ptr<LLVMRemarkStreamer> LlvmRemarkStreamer;
};
std::vector<std::string> Passes;
for (size_t I = 0; I != RemarkPassesLen; ++I)
{
Passes.push_back(RemarkPasses[I]);
}
// We need to hold onto both the streamers and the opened file
std::unique_ptr<ToolOutputFile> RemarkFile;
std::unique_ptr<llvm::remarks::RemarkStreamer> RemarkStreamer;
std::unique_ptr<LLVMRemarkStreamer> LlvmRemarkStreamer;
if (RemarkFilePath != nullptr) {
std::error_code EC;
RemarkFile = std::make_unique<ToolOutputFile>(
RemarkFilePath,
EC,
llvm::sys::fs::OF_TextWithCRLF
);
if (EC) {
std::string Error = std::string("Cannot create remark file: ") +
toString(errorCodeToError(EC));
report_fatal_error(Twine(Error));
}
// Do not delete the file after we gather remarks
RemarkFile->keep();
auto RemarkSerializer = remarks::createRemarkSerializer(
llvm::remarks::Format::YAML,
remarks::SerializerMode::Separate,
RemarkFile->os()
);
if (Error E = RemarkSerializer.takeError())
{
std::string Error = std::string("Cannot create remark serializer: ") + toString(std::move(E));
report_fatal_error(Twine(Error));
}
RemarkStreamer = std::make_unique<llvm::remarks::RemarkStreamer>(std::move(*RemarkSerializer));
LlvmRemarkStreamer = std::make_unique<LLVMRemarkStreamer>(*RemarkStreamer);
}
unwrap(C)->setDiagnosticHandler(std::make_unique<RustDiagnosticHandler>(
DiagnosticHandlerCallback, DiagnosticHandlerContext, RemarkAllPasses, Passes));
DiagnosticHandlerCallback,
DiagnosticHandlerContext,
RemarkAllPasses,
Passes,
std::move(RemarkFile),
std::move(RemarkStreamer),
std::move(LlvmRemarkStreamer)
));
}
extern "C" void LLVMRustGetMangledName(LLVMValueRef V, RustStringRef Str) {

View File

@ -7,7 +7,7 @@ edition = "2021"
tracing = "0.1.28"
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
tracing-tree = "0.2.0"
tracing-core = "0.1.28"
tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635
[dev-dependencies]
rustc_span = { path = "../rustc_span" }

View File

@ -8,6 +8,7 @@ proc-macro = true
[dependencies]
synstructure = "0.13.0"
syn = { version = "2", features = ["full"] }
# FIXME(Nilstrieb): Updating this causes changes in the diagnostics output.
syn = { version = "=2.0.8", features = ["full"] }
proc-macro2 = "1"
quote = "1"

View File

@ -25,6 +25,9 @@ metadata_conflicting_alloc_error_handler =
metadata_conflicting_global_alloc =
the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
metadata_consider_adding_std =
consider adding the standard library to the sysroot with `x build library --target {$locator_triple}`
metadata_consider_building_std =
consider building the standard library from source with `cargo build -Zbuild-std`

View File

@ -646,12 +646,18 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
} else {
diag.note(fluent::metadata_target_no_std_support);
}
// NOTE: this suggests using rustup, even though the user may not have it installed.
// That's because they could choose to install it; or this may give them a hint which
// target they need to install from their distro.
if self.missing_core {
diag.help(fluent::metadata_consider_downloading_target);
if env!("CFG_RELEASE_CHANNEL") == "dev" {
diag.help(fluent::metadata_consider_adding_std);
} else {
// NOTE: this suggests using rustup, even though the user may not have it installed.
// That's because they could choose to install it; or this may give them a hint which
// target they need to install from their distro.
diag.help(fluent::metadata_consider_downloading_target);
}
}
// Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway.
// NOTE: this is a dummy span if `extern crate std` was injected by the compiler.
// If it's not a dummy, that means someone added `extern crate std` explicitly and

View File

@ -1447,6 +1447,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
.is_type_alias_impl_trait
.set(def_id.index, self.tcx.is_type_alias_impl_trait(def_id));
}
if let DefKind::ImplTraitPlaceholder = def_kind {
self.encode_explicit_item_bounds(def_id);
}
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
{

View File

@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
bitflags = "1.2.1"
chalk-ir = "0.87.0"
chalk-ir = "0.92.0"
derive_more = "0.99.17"
either = "1.5.0"
gsgdt = "0.1.2"

View File

@ -4,6 +4,7 @@
use crate::ty::{TyCtxt, Visibility};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def::DefKind;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
use rustc_span::def_id::{LocalDefId, CRATE_DEF_ID};
@ -148,13 +149,12 @@ impl EffectiveVisibilities {
};
}
pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
pub fn check_invariants(&self, tcx: TyCtxt<'_>) {
if !cfg!(debug_assertions) {
return;
}
for (&def_id, ev) in &self.map {
// More direct visibility levels can never go farther than less direct ones,
// neither of effective visibilities can go farther than nominal visibility,
// and all effective visibilities are larger or equal than private visibility.
let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id));
let span = tcx.def_span(def_id.to_def_id());
@ -175,17 +175,20 @@ impl EffectiveVisibilities {
ev.reachable_through_impl_trait
);
}
let nominal_vis = tcx.visibility(def_id);
// FIXME: `rustc_privacy` is not yet updated for the new logic and can set
// effective visibilities that are larger than the nominal one.
if !nominal_vis.is_at_least(ev.reachable_through_impl_trait, tcx) && early {
span_bug!(
span,
"{:?}: reachable_through_impl_trait {:?} > nominal {:?}",
def_id,
ev.reachable_through_impl_trait,
nominal_vis
);
// All effective visibilities except `reachable_through_impl_trait` are limited to
// nominal visibility. For some items nominal visibility doesn't make sense so we
// don't check this condition for them.
if !matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) {
let nominal_vis = tcx.visibility(def_id);
if !nominal_vis.is_at_least(ev.reachable, tcx) {
span_bug!(
span,
"{:?}: reachable {:?} > nominal {:?}",
def_id,
ev.reachable,
nominal_vis
);
}
}
}
}
@ -212,7 +215,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
pub fn update(
&mut self,
id: Id,
nominal_vis: Option<Visibility>,
max_vis: Option<Visibility>,
lazy_private_vis: impl FnOnce() -> Visibility,
inherited_effective_vis: EffectiveVisibility,
level: Level,
@ -236,8 +239,8 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
&& level != l)
{
calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
nominal_vis
calculated_effective_vis = if let Some(max_vis) = max_vis && !max_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
max_vis
} else {
inherited_effective_vis_at_level
}

View File

@ -95,11 +95,15 @@ impl<'tcx> TyCtxt<'tcx> {
// used generic parameters is a bug of evaluation, so checking for it
// here does feel somewhat sensible.
if !self.features().generic_const_exprs && ct.substs.has_non_region_param() {
assert!(matches!(
self.def_kind(ct.def),
DefKind::InlineConst | DefKind::AnonConst
));
let mir_body = self.mir_for_ctfe(ct.def);
let def_kind = self.def_kind(instance.def_id());
assert!(
matches!(
def_kind,
DefKind::InlineConst | DefKind::AnonConst | DefKind::AssocConst
),
"{cid:?} is {def_kind:?}",
);
let mir_body = self.mir_for_ctfe(instance.def_id());
if mir_body.is_polymorphic {
let Some(local_def_id) = ct.def.as_local() else { return };
self.struct_span_lint_hir(
@ -239,15 +243,3 @@ impl<'tcx> TyCtxtEnsure<'tcx> {
self.eval_to_allocation_raw(param_env.and(gid))
}
}
impl<'tcx> TyCtxt<'tcx> {
/// Destructure a mir constant ADT or array into its variant index and its field values.
/// Panics if the destructuring fails, use `try_destructure_mir_constant` for fallible version.
pub fn destructure_mir_constant(
self,
param_env: ty::ParamEnv<'tcx>,
constant: mir::ConstantKind<'tcx>,
) -> mir::DestructuredConstant<'tcx> {
self.try_destructure_mir_constant(param_env.and(constant)).unwrap()
}
}

View File

@ -2581,10 +2581,9 @@ pub struct UnevaluatedConst<'tcx> {
}
impl<'tcx> UnevaluatedConst<'tcx> {
// FIXME: probably should get rid of this method. It's also wrong to
// shrink and then later expand a promoted.
#[inline]
pub fn shrink(self) -> ty::UnevaluatedConst<'tcx> {
assert_eq!(self.promoted, None);
ty::UnevaluatedConst { def: self.def, substs: self.substs }
}
}

View File

@ -71,8 +71,8 @@ impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> {
type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()];
}
impl<T> EraseType for Result<&'_ T, ty::layout::FnAbiError<'_>> {
type Result = [u8; size_of::<Result<&'static (), ty::layout::FnAbiError<'static>>>()];
impl<T> EraseType for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> {
type Result = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()];
}
impl<T> EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> {
@ -96,15 +96,17 @@ impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
type Result = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()];
}
impl EraseType for Result<bool, ty::layout::LayoutError<'_>> {
type Result = [u8; size_of::<Result<bool, ty::layout::LayoutError<'static>>>()];
impl EraseType for Result<bool, &ty::layout::LayoutError<'_>> {
type Result = [u8; size_of::<Result<bool, &'static ty::layout::LayoutError<'static>>>()];
}
impl EraseType for Result<rustc_target::abi::TyAndLayout<'_, Ty<'_>>, ty::layout::LayoutError<'_>> {
impl EraseType
for Result<rustc_target::abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>>
{
type Result = [u8; size_of::<
Result<
rustc_target::abi::TyAndLayout<'static, Ty<'static>>,
ty::layout::LayoutError<'static>,
&'static ty::layout::LayoutError<'static>,
>,
>()];
}

View File

@ -1383,7 +1383,7 @@ rustc_queries! {
/// executes in "reveal all" mode, and will normalize the input type.
query layout_of(
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
depth_limit
desc { "computing layout of `{}`", key.value }
}
@ -1394,7 +1394,7 @@ rustc_queries! {
/// instead, where the instance is an `InstanceDef::Virtual`.
query fn_abi_of_fn_ptr(
key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}` function pointers", key.value.0 }
}
@ -1405,7 +1405,7 @@ rustc_queries! {
/// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
query fn_abi_of_instance(
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}`", key.value.0 }
}
@ -2164,7 +2164,7 @@ rustc_queries! {
separate_provide_extern
}
query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> {
query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> {
desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
}

View File

@ -310,7 +310,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
ty: Ty<'tcx>,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> {
debug_assert!(!ty.has_non_region_infer());
// First try computing a static layout.
@ -353,13 +353,13 @@ impl<'tcx> SizeSkeleton<'tcx> {
let size = s
.bytes()
.checked_mul(c)
.ok_or_else(|| LayoutError::SizeOverflow(ty))?;
.ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
return Ok(SizeSkeleton::Known(Size::from_bytes(size)));
}
let len = tcx.expand_abstract_consts(len);
let prev = ty::Const::from_target_usize(tcx, s.bytes());
let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else {
return Err(LayoutError::SizeOverflow(ty));
return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
};
Ok(SizeSkeleton::Generic(gen_size))
}
@ -367,7 +367,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
SizeSkeleton::Generic(g) => {
let len = tcx.expand_abstract_consts(len);
let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else {
return Err(LayoutError::SizeOverflow(ty));
return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
};
Ok(SizeSkeleton::Generic(gen_size))
}
@ -672,7 +672,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
MaybeResult::from(
tcx.layout_of(self.param_env().and(ty))
.map_err(|err| self.handle_layout_err(err, span, ty)),
.map_err(|err| self.handle_layout_err(*err, span, ty)),
)
}
}
@ -680,16 +680,21 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
err
fn handle_layout_err(
&self,
err: LayoutError<'tcx>,
_: Span,
_: Ty<'tcx>,
) -> &'tcx LayoutError<'tcx> {
self.tcx.arena.alloc(err)
}
}
impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
#[inline]
fn layout_tcx_at_span(&self) -> Span {
@ -697,8 +702,13 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
}
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
err
fn handle_layout_err(
&self,
err: LayoutError<'tcx>,
_: Span,
_: Ty<'tcx>,
) -> &'tcx LayoutError<'tcx> {
self.tcx.arena.alloc(err)
}
}
@ -1250,18 +1260,6 @@ pub enum FnAbiError<'tcx> {
AdjustForForeignAbi(call::AdjustForForeignAbiError),
}
impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
fn from(err: LayoutError<'tcx>) -> Self {
Self::Layout(err)
}
}
impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
fn from(err: call::AdjustForForeignAbiError) -> Self {
Self::AdjustForForeignAbi(err)
}
}
impl<'a, 'b> IntoDiagnostic<'a, !> for FnAbiError<'b> {
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
match self {
@ -1321,7 +1319,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
let tcx = self.tcx().at(span);
MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
|err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
|err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
))
}
@ -1348,7 +1346,11 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
// However, we don't do this early in order to avoid calling
// `def_span` unconditionally (which may have a perf penalty).
let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
self.handle_fn_abi_err(
*err,
span,
FnAbiRequest::OfInstance { instance, extra_args },
)
}),
)
}

View File

@ -106,9 +106,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::F
}
}
impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, ty::layout::LayoutError<'_>> {
impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
Err(ty::layout::LayoutError::Cycle)
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
// tcx.arena.alloc is pretty much equal to leaking).
Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle)))
}
}

View File

@ -43,7 +43,6 @@ pub mod impls;
pub mod move_paths;
pub mod rustc_peek;
pub mod storage;
pub mod un_derefer;
pub mod value_analysis;
fluent_messages! { "../messages.ftl" }

View File

@ -1,11 +1,10 @@
use crate::move_paths::FxHashMap;
use crate::un_derefer::UnDerefer;
use rustc_index::IndexVec;
use rustc_middle::mir::tcx::RvalueInitializationState;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
use smallvec::{smallvec, SmallVec};
use std::iter;
use std::mem;
use super::abs_domain::Lift;
@ -21,7 +20,6 @@ struct MoveDataBuilder<'a, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
data: MoveData<'tcx>,
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
un_derefer: UnDerefer<'tcx>,
}
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@ -35,25 +33,29 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
tcx,
param_env,
errors: Vec::new(),
un_derefer: UnDerefer { tcx: tcx, derefer_sidetable: Default::default() },
data: MoveData {
moves: IndexVec::new(),
loc_map: LocationMap::new(body),
rev_lookup: MovePathLookup {
locals: body
.local_decls
.indices()
.map(|i| {
Self::new_move_path(
&mut move_paths,
&mut path_map,
&mut init_path_map,
None,
Place::from(i),
.iter_enumerated()
.filter(|(_, l)| !l.is_deref_temp())
.map(|(i, _)| {
(
i,
Self::new_move_path(
&mut move_paths,
&mut path_map,
&mut init_path_map,
None,
Place::from(i),
),
)
})
.collect(),
projections: Default::default(),
derefer_sidetable: Default::default(),
},
move_paths,
path_map,
@ -98,13 +100,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
///
/// Maybe we should have separate "borrowck" and "moveck" modes.
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body)
{
return self.move_path_for(new_place);
}
let deref_chain = self.builder.data.rev_lookup.deref_chain(place.as_ref());
debug!("lookup({:?})", place);
let mut base = self.builder.data.rev_lookup.locals[place.local];
let mut base =
self.builder.data.rev_lookup.find_local(deref_chain.first().unwrap_or(&place).local);
// The move path index of the first union that we find. Once this is
// some we stop creating child move paths, since moves from unions
@ -113,51 +113,55 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
// from `*(u.f: &_)` isn't allowed.
let mut union_path = None;
for (place_ref, elem) in place.as_ref().iter_projections() {
let body = self.builder.body;
let tcx = self.builder.tcx;
let place_ty = place_ref.ty(body, tcx).ty;
match place_ty.kind() {
ty::Ref(..) | ty::RawPtr(..) => {
return Err(MoveError::cannot_move_out_of(
self.loc,
BorrowedContent { target_place: place_ref.project_deeper(&[elem], tcx) },
));
}
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
return Err(MoveError::cannot_move_out_of(
self.loc,
InteriorOfTypeWithDestructor { container_ty: place_ty },
));
}
ty::Adt(adt, _) if adt.is_union() => {
union_path.get_or_insert(base);
}
ty::Slice(_) => {
return Err(MoveError::cannot_move_out_of(
self.loc,
InteriorOfSliceOrArray {
ty: place_ty,
is_index: matches!(elem, ProjectionElem::Index(..)),
},
));
}
ty::Array(..) => {
if let ProjectionElem::Index(..) = elem {
for place in deref_chain.into_iter().chain(iter::once(place)) {
for (place_ref, elem) in place.as_ref().iter_projections() {
let body = self.builder.body;
let tcx = self.builder.tcx;
let place_ty = place_ref.ty(body, tcx).ty;
match place_ty.kind() {
ty::Ref(..) | ty::RawPtr(..) => {
return Err(MoveError::cannot_move_out_of(
self.loc,
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
BorrowedContent {
target_place: place_ref.project_deeper(&[elem], tcx),
},
));
}
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
return Err(MoveError::cannot_move_out_of(
self.loc,
InteriorOfTypeWithDestructor { container_ty: place_ty },
));
}
ty::Adt(adt, _) if adt.is_union() => {
union_path.get_or_insert(base);
}
ty::Slice(_) => {
return Err(MoveError::cannot_move_out_of(
self.loc,
InteriorOfSliceOrArray {
ty: place_ty,
is_index: matches!(elem, ProjectionElem::Index(..)),
},
));
}
ty::Array(..) => {
if let ProjectionElem::Index(..) = elem {
return Err(MoveError::cannot_move_out_of(
self.loc,
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
));
}
}
_ => {}
};
if union_path.is_none() {
base = self
.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
}
_ => {}
};
if union_path.is_none() {
base = self.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
}
}
@ -198,10 +202,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
}
}
pub type MoveDat<'tcx> = Result<
(FxHashMap<Local, Place<'tcx>>, MoveData<'tcx>),
(MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>),
>;
pub type MoveDat<'tcx> =
Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)>;
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
fn finalize(self) -> MoveDat<'tcx> {
@ -217,11 +219,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
"done dumping moves"
});
if self.errors.is_empty() {
Ok((self.un_derefer.derefer_sidetable, self.data))
} else {
Err((self.data, self.errors))
}
if self.errors.is_empty() { Ok(self.data) } else { Err((self.data, self.errors)) }
}
}
@ -250,7 +248,7 @@ pub(super) fn gather_moves<'tcx>(
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
fn gather_args(&mut self) {
for arg in self.body.args_iter() {
let path = self.data.rev_lookup.locals[arg];
let path = self.data.rev_lookup.find_local(arg);
let init = self.data.inits.push(Init {
path,
@ -286,7 +284,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
assert!(place.projection.is_empty());
if self.builder.body.local_decls[place.local].is_deref_temp() {
self.builder.un_derefer.derefer_sidetable.insert(place.local, *reffed);
self.builder.data.rev_lookup.derefer_sidetable.insert(place.local, *reffed);
}
}
StatementKind::Assign(box (place, rval)) => {
@ -308,7 +306,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
StatementKind::StorageLive(_) => {}
StatementKind::StorageDead(local) => {
// DerefTemp locals (results of CopyForDeref) don't actually move anything.
if !self.builder.un_derefer.derefer_sidetable.contains_key(&local) {
if !self.builder.data.rev_lookup.derefer_sidetable.contains_key(&local) {
self.gather_move(Place::from(*local));
}
}
@ -450,12 +448,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
fn gather_move(&mut self, place: Place<'tcx>) {
debug!("gather_move({:?}, {:?})", self.loc, place);
if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref(), self.builder.body)
{
self.gather_move(new_place);
return;
}
if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] =
**place.projection
{
@ -512,11 +504,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) {
debug!("gather_init({:?}, {:?})", self.loc, place);
if let Some(new_place) = self.builder.un_derefer.derefer(place, self.builder.body) {
self.gather_init(new_place.as_ref(), kind);
return;
}
let mut place = place;
// Check if we are assigning into a field of a union, if so, lookup the place

View File

@ -1,5 +1,5 @@
use crate::move_paths::builder::MoveDat;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::*;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
@ -175,7 +175,7 @@ pub struct MoveData<'tcx> {
/// particular path being moved.)
pub loc_map: LocationMap<SmallVec<[MoveOutIndex; 4]>>,
pub path_map: IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
pub rev_lookup: MovePathLookup,
pub rev_lookup: MovePathLookup<'tcx>,
pub inits: IndexVec<InitIndex, Init>,
/// Each Location `l` is mapped to the Inits that are effects
/// of executing the code at `l`.
@ -289,8 +289,8 @@ impl Init {
/// Tables mapping from a place to its MovePathIndex.
#[derive(Debug)]
pub struct MovePathLookup {
locals: IndexVec<Local, MovePathIndex>,
pub struct MovePathLookup<'tcx> {
locals: FxIndexMap<Local, MovePathIndex>,
/// projections are made from a base-place and a projection
/// elem. The base-place will have a unique MovePathIndex; we use
@ -299,6 +299,9 @@ pub struct MovePathLookup {
/// base-place). For the remaining lookup, we map the projection
/// elem to the associated MovePathIndex.
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
/// Maps `DerefTemp` locals to the `Place`s assigned to them.
derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
}
mod builder;
@ -309,27 +312,59 @@ pub enum LookupResult {
Parent(Option<MovePathIndex>),
}
impl MovePathLookup {
impl<'tcx> MovePathLookup<'tcx> {
// Unlike the builder `fn move_path_for` below, this lookup
// alternative will *not* create a MovePath on the fly for an
// unknown place, but will rather return the nearest available
// parent.
pub fn find(&self, place: PlaceRef<'_>) -> LookupResult {
let mut result = self.locals[place.local];
let deref_chain = self.deref_chain(place);
for elem in place.projection.iter() {
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
result = subpath;
} else {
let local = match deref_chain.first() {
Some(place) => place.local,
None => place.local,
};
let mut result = *self.locals.get(&local).unwrap_or_else(|| {
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
});
// this needs to be a closure because `place` has a different lifetime than `prefix`'s places
let mut subpaths_for_place = |place: PlaceRef<'_>| {
for elem in place.projection.iter() {
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
result = subpath;
} else {
return Some(result);
}
}
None
};
for place in deref_chain {
if let Some(result) = subpaths_for_place(place.as_ref()) {
return LookupResult::Parent(Some(result));
}
}
if let Some(result) = subpaths_for_place(place) {
return LookupResult::Parent(Some(result));
}
LookupResult::Exact(result)
}
pub fn find_local(&self, local: Local) -> MovePathIndex {
self.locals[local]
let deref_chain = self.deref_chain(Place::from(local).as_ref());
let local = match deref_chain.last() {
Some(place) => place.local,
None => local,
};
*self.locals.get(&local).unwrap_or_else(|| {
bug!("base local ({local:?}) of deref_chain should not be a deref temp")
})
}
/// An enumerated iterator of `local`s and their associated
@ -337,7 +372,22 @@ impl MovePathLookup {
pub fn iter_locals_enumerated(
&self,
) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> + ExactSizeIterator + '_ {
self.locals.iter_enumerated().map(|(l, &idx)| (l, idx))
self.locals.iter().map(|(&l, &idx)| (l, idx))
}
/// Returns the chain of places behind `DerefTemp` locals in `place`
pub fn deref_chain(&self, place: PlaceRef<'_>) -> Vec<Place<'tcx>> {
let mut prefix = Vec::new();
let mut local = place.local;
while let Some(&reffed) = self.derefer_sidetable.get(&local) {
prefix.insert(0, reffed);
local = reffed.local;
}
debug!("deref_chain({place:?}) = {prefix:?}");
prefix
}
}

View File

@ -34,7 +34,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
}
let param_env = tcx.param_env(def_id);
let (_, move_data) = MoveData::gather_moves(body, tcx, param_env).unwrap();
let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
let mdpe = MoveDataParamEnv { move_data, param_env };
if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {

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