1
Fork 0

Auto merge of #88329 - LeSeulArtichaut:rollup-blg8hc0, r=LeSeulArtichaut

Rollup of 16 pull requests

Successful merges:

 - #87944 (add Cell::as_array_of_cells, similar to Cell::as_slice_of_cells)
 - #88156 (Adjust / fix documentation of `Arc::make_mut`)
 - #88157 (bootstrap.py: recognize riscv64 when auto-detect)
 - #88196 (Refactor `named_asm_labels` to a HIR lint)
 - #88218 (Remove `Session.trait_methods_not_found`)
 - #88223 (Remove the `TryV2` alias)
 - #88226 (Fix typo “a Rc” → “an Rc” (and a few more))
 - #88267 (2229: Update signature for truncate function)
 - #88273 (Fix references to `ControlFlow` in docs)
 - #88277 (Update books)
 - #88291 (Add SAFETY comments to core::slice::sort::partition_in_blocks)
 - #88293 (Fix grammar in alloc test)
 - #88298 (Errorkind reorder)
 - #88299 (Stabilise BufWriter::into_parts)
 - #88314 (Add type of a let tait test)
 - #88325 (Add mutable-noalias to the release notes for 1.54)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2021-08-25 16:22:57 +00:00
commit 7b0e554ee2
45 changed files with 686 additions and 323 deletions

View file

@ -2028,6 +2028,7 @@ pub enum InlineAsmOperand {
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct InlineAsm {
pub template: Vec<InlineAsmTemplatePiece>,
pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
pub operands: Vec<(InlineAsmOperand, Span)>,
pub clobber_abi: Option<(Symbol, Span)>,
pub options: InlineAsmOptions,

View file

@ -19,20 +19,20 @@ use crate::token;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AssocCtxt {
Trait,
Impl,
}
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum FnCtxt {
Free,
Foreign,
Assoc(AssocCtxt),
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> {
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),

View file

@ -392,8 +392,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let operands = self.arena.alloc_from_iter(operands);
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
let template_strs = self.arena.alloc_from_iter(asm.template_strs.iter().cloned());
let line_spans = self.arena.alloc_slice(&asm.line_spans[..]);
let hir_asm = hir::InlineAsm { template, operands, options: asm.options, line_spans };
let hir_asm =
hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans };
self.arena.alloc(hir_asm)
}
}

View file

@ -7,10 +7,10 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_expand::base::{self, *};
use rustc_parse::parser::Parser;
use rustc_parse_format as parse;
use rustc_session::lint::{self, BuiltinLintDiagnostics};
use rustc_session::lint;
use rustc_span::symbol::Ident;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{InnerSpan, MultiSpan, Span};
use rustc_span::{InnerSpan, Span};
use rustc_target::asm::InlineAsmArch;
use smallvec::smallvec;
@ -484,11 +484,7 @@ fn parse_reg<'a>(
Ok(result)
}
fn expand_preparsed_asm(
ecx: &mut ExtCtxt<'_>,
args: AsmArgs,
is_local_asm: bool,
) -> Option<ast::InlineAsm> {
fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::InlineAsm> {
let mut template = vec![];
// Register operands are implicitly used since they are not allowed to be
// referenced in the template string.
@ -501,6 +497,8 @@ fn expand_preparsed_asm(
let mut line_spans = Vec::with_capacity(args.templates.len());
let mut curarg = 0;
let mut template_strs = Vec::with_capacity(args.templates.len());
for template_expr in args.templates.into_iter() {
if !template.is_empty() {
template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
@ -524,8 +522,13 @@ fn expand_preparsed_asm(
ast::StrStyle::Raw(raw) => Some(raw as usize),
};
let template_str = &template_str.as_str();
let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
template_strs.push((
template_str,
template_snippet.as_ref().map(|s| Symbol::intern(s)),
template_sp,
));
let template_str = &template_str.as_str();
if let Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) = ecx.sess.asm_arch {
let find_span = |needle: &str| -> Span {
@ -560,72 +563,6 @@ fn expand_preparsed_asm(
}
}
// Lint against the use of named labels in inline `asm!` but not `global_asm!`
if is_local_asm {
let find_label_span = |needle: &str| -> Option<Span> {
if let Some(snippet) = &template_snippet {
if let Some(pos) = snippet.find(needle) {
let end = pos
+ &snippet[pos..]
.find(|c| c == ':')
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
return Some(template_sp.from_inner(inner));
}
}
None
};
let mut found_labels = Vec::new();
// A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
let statements = template_str.split(|c| matches!(c, '\n' | ';'));
for statement in statements {
// If there's a comment, trim it from the statement
let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
let mut start_idx = 0;
for (idx, _) in statement.match_indices(':') {
let possible_label = statement[start_idx..idx].trim();
let mut chars = possible_label.chars();
if let Some(c) = chars.next() {
// A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
if (c.is_alphabetic() || matches!(c, '.' | '_'))
&& chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
{
found_labels.push(possible_label);
} else {
// If we encounter a non-label, there cannot be any further labels, so stop checking
break;
}
} else {
// Empty string means a leading ':' in this section, which is not a label
break;
}
start_idx = idx + 1;
}
}
if found_labels.len() > 0 {
let spans =
found_labels.into_iter().filter_map(find_label_span).collect::<Vec<Span>>();
// If there were labels but we couldn't find a span, combine the warnings and use the template span
let target_spans: MultiSpan =
if spans.len() > 0 { spans.into() } else { template_sp.into() };
ecx.parse_sess().buffer_lint_with_diagnostic(
lint::builtin::NAMED_ASM_LABELS,
target_spans,
ecx.current_expansion.lint_node_id,
"avoid using named labels in inline assembly",
BuiltinLintDiagnostics::NamedAsmLabel(
"only local labels of the form `<number>:` should be used in inline asm"
.to_string(),
),
);
}
}
// Don't treat raw asm as a format string.
if args.options.contains(ast::InlineAsmOptions::RAW) {
template.push(ast::InlineAsmTemplatePiece::String(template_str.to_string()));
@ -819,6 +756,7 @@ fn expand_preparsed_asm(
Some(ast::InlineAsm {
template,
template_strs: template_strs.into_boxed_slice(),
operands: args.operands,
clobber_abi: args.clobber_abi,
options: args.options,
@ -833,7 +771,7 @@ pub fn expand_asm<'cx>(
) -> Box<dyn base::MacResult + 'cx> {
match parse_args(ecx, sp, tts, false) {
Ok(args) => {
let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args, true) {
let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
P(ast::Expr {
id: ast::DUMMY_NODE_ID,
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
@ -860,7 +798,7 @@ pub fn expand_global_asm<'cx>(
) -> Box<dyn base::MacResult + 'cx> {
match parse_args(ecx, sp, tts, true) {
Ok(args) => {
if let Some(inline_asm) = expand_preparsed_asm(ecx, args, false) {
if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
MacEager::items(smallvec![P(ast::Item {
ident: Ident::invalid(),
attrs: Vec::new(),

View file

@ -5,7 +5,7 @@
This crate provides the _owning reference_ types `OwningRef` and `OwningRefMut`
that enables it to bundle a reference together with the owner of the data it points to.
This allows moving and dropping of a `OwningRef` without needing to recreate the reference.
This allows moving and dropping of an `OwningRef` without needing to recreate the reference.
This can sometimes be useful because Rust borrowing rules normally prevent
moving a type that has been moved from. For example, this kind of code gets rejected:
@ -1146,7 +1146,7 @@ pub type VecRef<T, U = T> = OwningRef<Vec<T>, U>;
/// Typedef of an owning reference that uses a `String` as the owner.
pub type StringRef = OwningRef<String, str>;
/// Typedef of an owning reference that uses a `Rc` as the owner.
/// Typedef of an owning reference that uses an `Rc` as the owner.
pub type RcRef<T, U = T> = OwningRef<Rc<T>, U>;
/// Typedef of an owning reference that uses an `Arc` as the owner.
pub type ArcRef<T, U = T> = OwningRef<Arc<T>, U>;
@ -1157,9 +1157,9 @@ pub type RefRef<'a, T, U = T> = OwningRef<Ref<'a, T>, U>;
pub type RefMutRef<'a, T, U = T> = OwningRef<RefMut<'a, T>, U>;
/// Typedef of an owning reference that uses a `MutexGuard` as the owner.
pub type MutexGuardRef<'a, T, U = T> = OwningRef<MutexGuard<'a, T>, U>;
/// Typedef of an owning reference that uses a `RwLockReadGuard` as the owner.
/// Typedef of an owning reference that uses an `RwLockReadGuard` as the owner.
pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef<RwLockReadGuard<'a, T>, U>;
/// Typedef of an owning reference that uses a `RwLockWriteGuard` as the owner.
/// Typedef of an owning reference that uses an `RwLockWriteGuard` as the owner.
pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>;
/// Typedef of a mutable owning reference that uses a `Box` as the owner.
@ -1173,7 +1173,7 @@ pub type StringRefMut = OwningRefMut<String, str>;
pub type RefMutRefMut<'a, T, U = T> = OwningRefMut<RefMut<'a, T>, U>;
/// Typedef of a mutable owning reference that uses a `MutexGuard` as the owner.
pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut<MutexGuard<'a, T>, U>;
/// Typedef of a mutable owning reference that uses a `RwLockWriteGuard` as the owner.
/// Typedef of a mutable owning reference that uses an `RwLockWriteGuard` as the owner.
pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>;
unsafe impl<'a, T: 'a> IntoErased<'a> for Box<T> {

View file

@ -2386,6 +2386,7 @@ impl<'hir> InlineAsmOperand<'hir> {
#[derive(Debug, HashStable_Generic)]
pub struct InlineAsm<'hir> {
pub template: &'hir [InlineAsmTemplatePiece],
pub template_strs: &'hir [(Symbol, Option<Symbol>, Span)],
pub operands: &'hir [(InlineAsmOperand<'hir>, Span)],
pub options: InlineAsmOptions,
pub line_spans: &'hir [Span],

View file

@ -104,11 +104,5 @@ pub fn report_object_safety_error(
to be resolvable dynamically; for more information visit \
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
);
if tcx.sess.trait_methods_not_found.borrow().iter().any(|full_span| full_span.contains(span)) {
// Avoid emitting error caused by non-existing method (#58734)
err.cancel();
}
err
}

View file

@ -45,11 +45,11 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Span};
use rustc_span::{BytePos, InnerSpan, MultiSpan, Span};
use rustc_target::abi::{LayoutOf, VariantIdx};
use rustc_trait_selection::traits::misc::can_type_implement_copy;
@ -3140,3 +3140,123 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
}
}
}
declare_lint! {
/// The `named_asm_labels` lint detects the use of named labels in the
/// inline `asm!` macro.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![feature(asm)]
/// fn main() {
/// unsafe {
/// asm!("foo: bar");
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// LLVM is allowed to duplicate inline assembly blocks for any
/// reason, for example when it is in a function that gets inlined. Because
/// of this, GNU assembler [local labels] *must* be used instead of labels
/// with a name. Using named labels might cause assembler or linker errors.
///
/// See the [unstable book] for more details.
///
/// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
/// [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels
pub NAMED_ASM_LABELS,
Deny,
"named labels in inline assembly",
}
declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::Expr {
kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
..
} = expr
{
for (template_sym, template_snippet, template_span) in template_strs.iter() {
let template_str = &template_sym.as_str();
let find_label_span = |needle: &str| -> Option<Span> {
if let Some(template_snippet) = template_snippet {
let snippet = template_snippet.as_str();
if let Some(pos) = snippet.find(needle) {
let end = pos
+ &snippet[pos..]
.find(|c| c == ':')
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
return Some(template_span.from_inner(inner));
}
}
None
};
let mut found_labels = Vec::new();
// A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
let statements = template_str.split(|c| matches!(c, '\n' | ';'));
for statement in statements {
// If there's a comment, trim it from the statement
let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
let mut start_idx = 0;
for (idx, _) in statement.match_indices(':') {
let possible_label = statement[start_idx..idx].trim();
let mut chars = possible_label.chars();
if let Some(c) = chars.next() {
// A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
if (c.is_alphabetic() || matches!(c, '.' | '_'))
&& chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
{
found_labels.push(possible_label);
} else {
// If we encounter a non-label, there cannot be any further labels, so stop checking
break;
}
} else {
// Empty string means a leading ':' in this section, which is not a label
break;
}
start_idx = idx + 1;
}
}
debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
if found_labels.len() > 0 {
let spans = found_labels
.into_iter()
.filter_map(|label| find_label_span(label))
.collect::<Vec<Span>>();
// If there were labels but we couldn't find a span, combine the warnings and use the template span
let target_spans: MultiSpan =
if spans.len() > 0 { spans.into() } else { (*template_span).into() };
cx.lookup_with_diagnostics(
NAMED_ASM_LABELS,
Some(target_spans),
|diag| {
let mut err =
diag.build("avoid using named labels in inline assembly");
err.emit();
},
BuiltinLintDiagnostics::NamedAsmLabel(
"only local labels of the form `<number>:` should be used in inline asm"
.to_string(),
),
);
}
}
}
}
}

View file

@ -168,6 +168,7 @@ macro_rules! late_lint_passes {
NonPanicFmt: NonPanicFmt,
NoopMethodCall: NoopMethodCall,
InvalidAtomicOrdering: InvalidAtomicOrdering,
NamedAsmLabels: NamedAsmLabels,
]
);
};

View file

@ -2468,38 +2468,6 @@ declare_lint! {
"incorrect use of inline assembly",
}
declare_lint! {
/// The `named_asm_labels` lint detects the use of named labels in the
/// inline `asm!` macro.
///
/// ### Example
///
/// ```rust,compile_fail
/// fn main() {
/// unsafe {
/// asm!("foo: bar");
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// LLVM is allowed to duplicate inline assembly blocks for any
/// reason, for example when it is in a function that gets inlined. Because
/// of this, GNU assembler [local labels] *must* be used instead of labels
/// with a name. Using named labels might cause assembler or linker errors.
///
/// See the [unstable book] for more details.
///
/// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
/// [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels
pub NAMED_ASM_LABELS,
Deny,
"named labels in inline assembly",
}
declare_lint! {
/// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe
/// functions without an explicit unsafe block.
@ -3020,7 +2988,6 @@ declare_lint_pass! {
INLINE_NO_SANITIZE,
BAD_ASM_STYLE,
ASM_SUB_REGISTER,
NAMED_ASM_LABELS,
UNSAFE_OP_IN_UNSAFE_FN,
INCOMPLETE_INCLUDE,
CENUM_IMPL_DROP_CAST,

View file

@ -189,9 +189,6 @@ pub struct Session {
/// Cap lint level specified by a driver specifically.
pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
/// `Span`s of trait methods that weren't found to avoid emitting object safety errors
pub trait_methods_not_found: Lock<FxHashSet<Span>>,
/// Mapping from ident span to path span for paths that don't exist as written, but that
/// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
@ -1326,7 +1323,6 @@ pub fn build_session(
print_fuel,
jobserver: jobserver::client(),
driver_lint_caps,
trait_methods_not_found: Lock::new(Default::default()),
confused_type_with_std_module: Lock::new(Default::default()),
ctfe_backtrace,
miri_unleashed_features: Lock::new(Default::default()),

View file

@ -858,13 +858,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
path.segments,
);
}
QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
QPath::TypeRelative(ref qself, ref segment) => {
// Don't use `self.to_ty`, since this will register a WF obligation.
// If we're trying to call a non-existent method on a trait
// (e.g. `MyTrait::missing_method`), then resolution will
// give us a `QPath::TypeRelative` with a trait object as
// `qself`. In that case, we want to avoid registering a WF obligation
// for `dyn MyTrait`, since we don't actually need the trait
// to be object-safe.
// We manually call `register_wf_obligation` in the success path
// below.
(<dyn AstConv<'_>>::ast_ty_to_ty(self, qself), qself, segment)
}
QPath::LangItem(..) => {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
}
};
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
{
self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
// Return directly on cache hit. This is useful to avoid doubly reporting
// errors with default match binding modes. See #44614.
let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
@ -878,6 +890,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
_ => Err(ErrorReported),
};
// If we have a path like `MyTrait::missing_method`, then don't register
// a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
// register a WF obligation so that we can detect any additional
// errors in the self type.
if !(matches!(error, method::MethodError::NoMatch(_)) && ty.is_trait()) {
self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
}
if item_name.name != kw::Empty {
if let Some(mut e) = self.report_method_error(
span,
@ -895,6 +915,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if result.is_ok() {
self.maybe_lint_bare_trait(qpath, hir_id);
self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
}
// Write back the new resolution.

View file

@ -70,15 +70,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn report_method_error(
&self,
span: Span,
mut span: Span,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
error: MethodError<'tcx>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
) -> Option<DiagnosticBuilder<'_>> {
let orig_span = span;
let mut span = span;
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
return None;
@ -545,7 +543,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
}
self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
};
// If the method name is the name of a field with a function or closure type,

View file

@ -489,7 +489,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut root_var_min_capture_list =
typeck_results.closure_min_captures.remove(&closure_def_id).unwrap_or_default();
for (place, capture_info) in capture_information.into_iter() {
for (mut place, capture_info) in capture_information.into_iter() {
let var_hir_id = match place.base {
PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
base => bug!("Expected upvar, found={:?}", base),
@ -530,14 +530,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Truncate the descendant (already in min_captures) to be same as the ancestor to handle any
// possible change in capture mode.
let (_, descendant_capture_kind) = truncate_place_to_len(
possible_descendant.place,
possible_descendant.info.capture_kind,
truncate_place_to_len_and_update_capture_kind(
&mut possible_descendant.place,
&mut possible_descendant.info.capture_kind,
place.projections.len(),
);
possible_descendant.info.capture_kind = descendant_capture_kind;
updated_capture_info =
determine_capture_info(updated_capture_info, possible_descendant.info);
@ -561,14 +559,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Truncate the descendant (current place) to be same as the ancestor to handle any
// possible change in capture mode.
let (_, descendant_capture_kind) = truncate_place_to_len(
place.clone(),
updated_capture_info.capture_kind,
truncate_place_to_len_and_update_capture_kind(
&mut place,
&mut updated_capture_info.capture_kind,
possible_ancestor.place.projections.len(),
);
updated_capture_info.capture_kind = descendant_capture_kind;
possible_ancestor.info = determine_capture_info(
possible_ancestor.info,
updated_capture_info,
@ -1476,7 +1472,7 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
place: &Place<'tcx>,
curr_borrow_kind: ty::UpvarCapture<'tcx>,
mut curr_borrow_kind: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let pos = place.projections.iter().enumerate().position(|(i, p)| {
let ty = place.ty_before_projection(i);
@ -1508,13 +1504,13 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
}
});
let place = place.clone();
let mut place = place.clone();
if let Some(pos) = pos {
truncate_place_to_len(place, curr_borrow_kind, pos)
} else {
(place, curr_borrow_kind)
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos);
}
(place, curr_borrow_kind)
}
/// Returns a Ty that applies the specified capture kind on the provided capture Ty
@ -1841,31 +1837,28 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
/// them completely.
/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
fn restrict_precision_for_unsafe(
place: Place<'tcx>,
curr_mode: ty::UpvarCapture<'tcx>,
mut place: Place<'tcx>,
mut curr_mode: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
if place.projections.is_empty() {
// Nothing to do here
return (place, curr_mode);
}
if place.base_ty.is_unsafe_ptr() {
return truncate_place_to_len(place, curr_mode, 0);
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0);
}
if place.base_ty.is_union() {
return truncate_place_to_len(place, curr_mode, 0);
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0);
}
for (i, proj) in place.projections.iter().enumerate() {
if proj.ty.is_unsafe_ptr() {
// Don't apply any projections on top of an unsafe ptr.
return truncate_place_to_len(place, curr_mode, i + 1);
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i + 1);
break;
}
if proj.ty.is_union() {
// Don't capture preicse fields of a union.
return truncate_place_to_len(place, curr_mode, i + 1);
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i + 1);
break;
}
}
@ -1880,7 +1873,7 @@ fn restrict_capture_precision<'tcx>(
place: Place<'tcx>,
curr_mode: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let (place, curr_mode) = restrict_precision_for_unsafe(place, curr_mode);
let (mut place, mut curr_mode) = restrict_precision_for_unsafe(place, curr_mode);
if place.projections.is_empty() {
// Nothing to do here
@ -1891,7 +1884,8 @@ fn restrict_capture_precision<'tcx>(
match proj.kind {
ProjectionKind::Index => {
// Arrays are completely captured, so we drop Index projections
return truncate_place_to_len(place, curr_mode, i);
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i);
return (place, curr_mode);
}
ProjectionKind::Deref => {}
ProjectionKind::Field(..) => {} // ignore
@ -1906,8 +1900,8 @@ fn restrict_capture_precision<'tcx>(
/// (or if closure attempts to move data that it doesnt own).
/// Note: When taking ownership, only capture data found on the stack.
fn adjust_for_move_closure<'tcx>(
place: Place<'tcx>,
kind: ty::UpvarCapture<'tcx>,
mut place: Place<'tcx>,
mut kind: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let contains_deref_of_ref = place.deref_tys().any(|ty| ty.is_ref());
let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
@ -1917,52 +1911,38 @@ fn adjust_for_move_closure<'tcx>(
// If there's any Deref and the data needs to be moved into the closure body,
// or it's a Deref of a Box, truncate the path to the first deref
_ if first_deref.is_some() => {
let place = match first_deref {
Some(idx) => {
let (place, _) = truncate_place_to_len(place, kind, idx);
place
}
None => place,
};
_ => {
if let Some(idx) = first_deref {
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
}
// AMAN: I think we don't need the span inside the ByValue anymore
// we have more detailed span in CaptureInfo
(place, ty::UpvarCapture::ByValue(None))
}
_ => (place, ty::UpvarCapture::ByValue(None)),
}
}
/// Adjust closure capture just that if taking ownership of data, only move data
/// from enclosing stack frame.
fn adjust_for_non_move_closure<'tcx>(
place: Place<'tcx>,
mut place: Place<'tcx>,
mut kind: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let contains_deref =
place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
match kind {
ty::UpvarCapture::ByValue(..) if contains_deref.is_some() => {
let place = match contains_deref {
Some(idx) => {
let (place, new_kind) = truncate_place_to_len(place, kind, idx);
kind = new_kind;
place
}
// Because of the if guard on the match on `kind`, we should never get here.
None => unreachable!(),
};
(place, kind)
ty::UpvarCapture::ByValue(..) => {
if let Some(idx) = contains_deref {
truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
}
}
ty::UpvarCapture::ByValue(..) => (place, kind),
ty::UpvarCapture::ByRef(..) => (place, kind),
ty::UpvarCapture::ByRef(..) => {}
}
(place, kind)
}
fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
@ -2157,15 +2137,13 @@ fn determine_capture_info(
///
/// Note: Capture kind changes from `MutBorrow` to `UniqueImmBorrow` if the truncated part of the `place`
/// contained `Deref` of `&mut`.
fn truncate_place_to_len(
mut place: Place<'tcx>,
curr_mode: ty::UpvarCapture<'tcx>,
fn truncate_place_to_len_and_update_capture_kind(
place: &mut Place<'tcx>,
curr_mode: &mut ty::UpvarCapture<'tcx>,
len: usize,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
) {
let is_mut_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Mut));
let mut capture_kind = curr_mode;
// If the truncated part of the place contains `Deref` of a `&mut` then convert MutBorrow ->
// UniqueImmBorrow
// Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so
@ -2176,7 +2154,7 @@ fn truncate_place_to_len(
if place.projections[i].kind == ProjectionKind::Deref
&& is_mut_ref(place.ty_before_projection(i))
{
capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
*curr_mode = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
kind: ty::BorrowKind::UniqueImmBorrow,
region,
});
@ -2190,8 +2168,6 @@ fn truncate_place_to_len(
}
place.projections.truncate(len);
(place, capture_kind)
}
/// Determines the Ancestry relationship of Place A relative to Place B
@ -2256,8 +2232,8 @@ fn determine_place_ancestry_relation(
/// }
/// ```
fn truncate_capture_for_optimization<'tcx>(
place: Place<'tcx>,
curr_mode: ty::UpvarCapture<'tcx>,
mut place: Place<'tcx>,
mut curr_mode: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not));
@ -2269,10 +2245,12 @@ fn truncate_capture_for_optimization<'tcx>(
match idx {
// If that pointer is a shared reference, then we don't need those fields.
Some(idx) if is_shared_ref(place.ty_before_projection(idx)) => {
truncate_place_to_len(place, curr_mode, idx + 1)
truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, idx + 1)
}
None | Some(_) => (place, curr_mode),
None | Some(_) => {}
}
(place, curr_mode)
}
/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if