Auto merge of #105667 - matthiaskrgr:rollup-fexlc0b, r=matthiaskrgr

Rollup of 7 pull requests

Successful merges:

 - #105147 (Allow unsafe through inline const)
 - #105438 (Move some codegen-y methods from `rustc_hir_analysis::collect` -> `rustc_codegen_ssa`)
 - #105464 (Support #[track_caller] on async closures)
 - #105476 (Change pattern borrowing suggestions to be verbose and remove invalid suggestion)
 - #105500 (Make some diagnostics not depend on the source of what they reference being available)
 - #105628 (Small doc fixes)
 - #105659 (Don't require owned data in `MaybeStorageLive`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-12-13 22:05:28 +00:00
commit 21ee03e062
354 changed files with 3398 additions and 3397 deletions

View File

@ -31,6 +31,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
ensure_sufficient_stack(|| {
match &e.kind {
// Paranthesis expression does not have a HirId and is handled specially.
ExprKind::Paren(ex) => {
let mut ex = self.lower_expr_mut(ex);
// Include parens in span, but only if it is a super-span.
if e.span.contains(ex.span) {
ex.span = self.lower_span(e.span);
}
// Merge attributes into the inner expression.
if !e.attrs.is_empty() {
let old_attrs =
self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
self.attrs.insert(
ex.hir_id.local_id,
&*self.arena.alloc_from_iter(
e.attrs
.iter()
.map(|a| self.lower_attr(a))
.chain(old_attrs.iter().cloned()),
),
);
}
return ex;
}
// Desugar `ExprForLoop`
// from: `[opt_ident]: for <pat> in <head> <body>`
//
// This also needs special handling because the HirId of the returned `hir::Expr` will not
// correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
ExprKind::ForLoop(pat, head, body, opt_label) => {
return self.lower_expr_for(e, pat, head, body, *opt_label);
}
_ => (),
}
let hir_id = self.lower_node_id(e.id);
self.lower_attrs(hir_id, &e.attrs);
let kind = match &e.kind {
ExprKind::Box(inner) => hir::ExprKind::Box(self.lower_expr(inner)),
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
@ -48,7 +86,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) {
if let [inner] = &args[..] && e.attrs.len() == 1 {
let kind = hir::ExprKind::Box(self.lower_expr(&inner));
let hir_id = self.lower_node_id(e.id);
return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
} else {
self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span });
@ -147,7 +184,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
),
ExprKind::Async(capture_clause, closure_node_id, block) => self.make_async_expr(
*capture_clause,
None,
hir_id,
*closure_node_id,
None,
e.span,
@ -184,6 +221,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder,
*capture_clause,
e.id,
hir_id,
*closure_id,
fn_decl,
body,
@ -279,39 +317,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
ExprKind::Err => hir::ExprKind::Err,
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
ExprKind::Paren(ex) => {
let mut ex = self.lower_expr_mut(ex);
// Include parens in span, but only if it is a super-span.
if e.span.contains(ex.span) {
ex.span = self.lower_span(e.span);
}
// Merge attributes into the inner expression.
if !e.attrs.is_empty() {
let old_attrs =
self.attrs.get(&ex.hir_id.local_id).map(|la| *la).unwrap_or(&[]);
self.attrs.insert(
ex.hir_id.local_id,
&*self.arena.alloc_from_iter(
e.attrs
.iter()
.map(|a| self.lower_attr(a))
.chain(old_attrs.iter().cloned()),
),
);
}
return ex;
}
// Desugar `ExprForLoop`
// from: `[opt_ident]: for <pat> in <head> <body>`
ExprKind::ForLoop(pat, head, body, opt_label) => {
return self.lower_expr_for(e, pat, head, body, *opt_label);
}
ExprKind::Paren(_) | ExprKind::ForLoop(..) => unreachable!("already handled"),
ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
};
let hir_id = self.lower_node_id(e.id);
self.lower_attrs(hir_id, &e.attrs);
hir::Expr { hir_id, kind, span: self.lower_span(e.span) }
})
}
@ -576,7 +587,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn make_async_expr(
&mut self,
capture_clause: CaptureBy,
outer_hir_id: Option<hir::HirId>,
outer_hir_id: hir::HirId,
closure_node_id: NodeId,
ret_ty: Option<hir::FnRetTy<'hir>>,
span: Span,
@ -669,8 +680,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::Closure(c)
};
let track_caller = outer_hir_id
.and_then(|id| self.attrs.get(&id.local_id))
let track_caller = self
.attrs
.get(&outer_hir_id.local_id)
.map_or(false, |attrs| attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)));
let hir_id = self.lower_node_id(closure_node_id);
@ -985,6 +997,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
binder: &ClosureBinder,
capture_clause: CaptureBy,
closure_id: NodeId,
closure_hir_id: hir::HirId,
inner_closure_id: NodeId,
decl: &FnDecl,
body: &Expr,
@ -1018,9 +1031,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let async_body = this.make_async_expr(
capture_clause,
// FIXME(nbdd0121): This should also use a proper HIR id so `#[track_caller]`
// can be applied on async closures as well.
None,
closure_hir_id,
inner_closure_id,
async_ret_ty,
body.span,

View File

@ -1139,7 +1139,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let async_expr = this.make_async_expr(
CaptureBy::Value,
Some(fn_id),
fn_id,
closure_id,
None,
body.span,

View File

@ -1059,17 +1059,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
if self.fn_self_span_reported.insert(fn_span) {
err.span_note(
// Check whether the source is accessible
if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) {
self_arg.span
} else {
fn_call_span
},
self_arg.span,
"calling this operator moves the left-hand side",
);
}
}
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
CallKind::Normal { self_arg, desugaring, method_did } => {
let self_arg = self_arg.unwrap();
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
@ -1139,14 +1134,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
),
);
}
let tcx = self.infcx.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) {
let func = tcx.def_path_str(method_did);
err.span_note(
self_arg.span,
&format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
&format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
);
}
let parent_did = tcx.parent(method_did);
let parent_self_ty = (tcx.def_kind(parent_did)
== rustc_hir::def::DefKind::Impl)
.then_some(parent_did)
.and_then(|did| match tcx.type_of(did).kind() {
ty::Adt(def, ..) => Some(def.did()),
_ => None,
});
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
if is_option_or_result && maybe_reinitialized_locations_is_empty {
err.span_label(
var_span,

View File

@ -4,7 +4,7 @@ use rustc_middle::ty;
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
use rustc_span::Span;
use rustc_span::{BytePos, Span};
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
@ -148,7 +148,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match_span: Span,
statement_span: Span,
) {
debug!("append_binding_error(match_place={:?}, match_span={:?})", match_place, match_span);
debug!(?match_place, ?match_span, "append_binding_error");
let from_simple_let = match_place.is_none();
let match_place = match_place.unwrap_or(move_from);
@ -160,7 +160,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if let GroupedMoveError::MovesFromPlace { span, binds_to, .. } = ge
&& match_span == *span
{
debug!("appending local({:?}) to list", bind_to);
debug!("appending local({bind_to:?}) to list");
if !binds_to.is_empty() {
binds_to.push(bind_to);
}
@ -198,7 +198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} = ge
{
if match_span == *span && mpi == *other_mpi {
debug!("appending local({:?}) to list", bind_to);
debug!("appending local({bind_to:?}) to list");
binds_to.push(bind_to);
return;
}
@ -410,15 +410,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diagnostic, span: Span) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
err.span_suggestion(
span,
"consider borrowing here",
format!("&{snippet}"),
Applicability::Unspecified,
);
}
self.add_borrow_suggestions(err, span);
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(move_from.as_ref()) {
@ -461,39 +453,75 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
fn add_borrow_suggestions(&self, err: &mut Diagnostic, span: Span) {
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
Ok(snippet) if snippet.starts_with('*') => {
err.span_suggestion_verbose(
span.with_hi(span.lo() + BytePos(1)),
"consider removing the dereference here",
String::new(),
Applicability::MaybeIncorrect,
);
}
_ => {
err.span_suggestion_verbose(
span.shrink_to_lo(),
"consider borrowing here",
"&".to_string(),
Applicability::MaybeIncorrect,
);
}
}
}
fn add_move_error_suggestions(&self, err: &mut Diagnostic, binds_to: &[Local]) {
let mut suggestions: Vec<(Span, &str, String)> = Vec::new();
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
for local in binds_to {
let bind_to = &self.body.local_decls[*local];
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm { pat_span, .. },
)))) = bind_to.local_info
{
if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span)
let Ok(pat_snippet) =
self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
let Some(stripped) = pat_snippet.strip_prefix('&') else {
suggestions.push((
bind_to.source_info.span.shrink_to_lo(),
"consider borrowing the pattern binding".to_string(),
"ref ".to_string(),
));
continue;
};
let inner_pat_snippet = stripped.trim_start();
let (pat_span, suggestion, to_remove) = if inner_pat_snippet.starts_with("mut")
&& inner_pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
{
if let Some(stripped) = pat_snippet.strip_prefix('&') {
let pat_snippet = stripped.trim_start();
let (suggestion, to_remove) = if pat_snippet.starts_with("mut")
&& pat_snippet["mut".len()..].starts_with(rustc_lexer::is_whitespace)
{
(pat_snippet["mut".len()..].trim_start(), "&mut")
} else {
(pat_snippet, "&")
};
suggestions.push((pat_span, to_remove, suggestion.to_owned()));
}
}
let inner_pat_snippet = inner_pat_snippet["mut".len()..].trim_start();
let pat_span = pat_span.with_hi(
pat_span.lo()
+ BytePos((pat_snippet.len() - inner_pat_snippet.len()) as u32),
);
(pat_span, String::new(), "mutable borrow")
} else {
let pat_span = pat_span.with_hi(
pat_span.lo()
+ BytePos(
(pat_snippet.len() - inner_pat_snippet.trim_start().len()) as u32,
),
);
(pat_span, String::new(), "borrow")
};
suggestions.push((
pat_span,
format!("consider removing the {to_remove}"),
suggestion.to_string(),
));
}
}
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
suggestions.dedup_by_key(|&mut (span, _, _)| span);
for (span, to_remove, suggestion) in suggestions {
err.span_suggestion(
span,
&format!("consider removing the `{to_remove}`"),
suggestion,
Applicability::MachineApplicable,
);
for (span, msg, suggestion) in suggestions {
err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable);
}
}
@ -521,8 +549,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
if binds_to.len() > 1 {
err.note(
"move occurs because these variables have types that \
don't implement the `Copy` trait",
"move occurs because these variables have types that don't implement the `Copy` \
trait",
);
}
}

View File

@ -0,0 +1,688 @@
use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self as ty, DefIdTree, TyCtxt};
use rustc_session::{lint, parse::feature_err};
use rustc_span::{sym, Span};
use rustc_target::spec::{abi, SanitizerSet};
use crate::target_features::from_target_feature;
use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
use rustc_middle::mir::mono::Linkage::*;
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
// applicable to variable declarations and may not really make sense for
// Rust code in the first place but allow them anyway and trust that the
// user knows what they're doing. Who knows, unanticipated use cases may pop
// up in the future.
//
// ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
// and don't have to be, LLVM treats them as no-ops.
match name {
"appending" => Appending,
"available_externally" => AvailableExternally,
"common" => Common,
"extern_weak" => ExternalWeak,
"external" => External,
"internal" => Internal,
"linkonce" => LinkOnceAny,
"linkonce_odr" => LinkOnceODR,
"private" => Private,
"weak" => WeakAny,
"weak_odr" => WeakODR,
_ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
}
}
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
if cfg!(debug_assertions) {
let def_kind = tcx.def_kind(did);
assert!(
def_kind.has_codegen_attrs(),
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
);
}
let did = did.expect_local();
let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
let mut codegen_fn_attrs = CodegenFnAttrs::new();
if tcx.should_inherit_track_caller(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
let mut inline_span = None;
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;
for attr in attrs.iter() {
if attr.has_name(sym::cold) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
} else if attr.has_name(sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
} else if attr.has_name(sym::ffi_returns_twice) {
if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else {
// `#[ffi_returns_twice]` is only allowed `extern fn`s.
struct_span_err!(
tcx.sess,
attr.span,
E0724,
"`#[ffi_returns_twice]` may only be used on foreign functions"
)
.emit();
}
} else if attr.has_name(sym::ffi_pure) {
if tcx.is_foreign_item(did) {
if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]`
struct_span_err!(
tcx.sess,
attr.span,
E0757,
"`#[ffi_const]` function cannot be `#[ffi_pure]`"
)
.emit();
} else {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
}
} else {
// `#[ffi_pure]` is only allowed on foreign functions
struct_span_err!(
tcx.sess,
attr.span,
E0755,
"`#[ffi_pure]` may only be used on foreign functions"
)
.emit();
}
} else if attr.has_name(sym::ffi_const) {
if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else {
// `#[ffi_const]` is only allowed on foreign functions
struct_span_err!(
tcx.sess,
attr.span,
E0756,
"`#[ffi_const]` may only be used on foreign functions"
)
.emit();
}
} else if attr.has_name(sym::rustc_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
} else if attr.has_name(sym::rustc_reallocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
} else if attr.has_name(sym::rustc_deallocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
} else if attr.has_name(sym::rustc_allocator_zeroed) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
} else if attr.has_name(sym::naked) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
} else if attr.has_name(sym::no_mangle) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
} else if attr.has_name(sym::no_coverage) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
} else if attr.has_name(sym::rustc_std_internal_symbol) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
} else if attr.has_name(sym::used) {
let inner = attr.meta_item_list();
match inner.as_deref() {
Some([item]) if item.has_name(sym::linker) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
sym::used_with_arg,
attr.span,
"`#[used(linker)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
}
Some([item]) if item.has_name(sym::compiler) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
sym::used_with_arg,
attr.span,
"`#[used(compiler)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
}
Some(_) => {
tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
}
None => {
// Unfortunately, unconditionally using `llvm.used` causes
// issues in handling `.init_array` with the gold linker,
// but using `llvm.compiler.used` caused a nontrival amount
// of unintentional ecosystem breakage -- particularly on
// Mach-O targets.
//
// As a result, we emit `llvm.compiler.used` only on ELF
// targets. This is somewhat ad-hoc, but actually follows
// our pre-LLVM 13 behavior (prior to the ecosystem
// breakage), and seems to match `clang`'s behavior as well
// (both before and after LLVM 13), possibly because they
// have similar compatibility concerns to us. See
// https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
// and following comments for some discussion of this, as
// well as the comments in `rustc_codegen_llvm` where these
// flags are handled.
//
// Anyway, to be clear: this is still up in the air
// somewhat, and is subject to change in the future (which
// is a good thing, because this would ideally be a bit
// more firmed up).
let is_like_elf = !(tcx.sess.target.is_like_osx
|| tcx.sess.target.is_like_windows
|| tcx.sess.target.is_like_wasm);
codegen_fn_attrs.flags |= if is_like_elf {
CodegenFnAttrFlags::USED
} else {
CodegenFnAttrFlags::USED_LINKER
};
}
}
} else if attr.has_name(sym::cmse_nonsecure_entry) {
if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
struct_span_err!(
tcx.sess,
attr.span,
E0776,
"`#[cmse_nonsecure_entry]` requires C ABI"
)
.emit();
}
if !tcx.sess.target.llvm_target.contains("thumbv8m") {
struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
} else if attr.has_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if attr.has_name(sym::track_caller) {
if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
feature_err(
&tcx.sess.parse_sess,
sym::closure_track_caller,
attr.span,
"`#[track_caller]` on closures is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
} else if attr.has_name(sym::export_name) {
if let Some(s) = attr.value_str() {
if s.as_str().contains('\0') {
// `#[export_name = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
struct_span_err!(
tcx.sess,
attr.span,
E0648,
"`export_name` may not contain null characters"
)
.emit();
}
codegen_fn_attrs.export_name = Some(s);
}
} else if attr.has_name(sym::target_feature) {
if !tcx.is_closure(did.to_def_id())
&& tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
{
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
// The `#[target_feature]` attribute is allowed on
// WebAssembly targets on all functions, including safe
// ones. Other targets require that `#[target_feature]` is
// only applied to unsafe functions (pending the
// `target_feature_11` feature) because on most targets
// execution of instructions that are not supported is
// considered undefined behavior. For WebAssembly which is a
// 100% safe target at execution time it's not possible to
// execute undefined instructions, and even if a future
// feature was added in some form for this it would be a
// deterministic trap. There is no undefined behavior when
// executing WebAssembly so `#[target_feature]` is allowed
// on safe functions (but again, only for WebAssembly)
//
// Note that this is also allowed if `actually_rustdoc` so
// if a target is documenting some wasm-specific code then
// it's not spuriously denied.
} else if !tcx.features().target_feature_11 {
let mut err = feature_err(
&tcx.sess.parse_sess,
sym::target_feature_11,
attr.span,
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
);
err.span_label(tcx.def_span(did), "not an `unsafe` function");
err.emit();
} else {
check_target_feature_trait_unsafe(tcx, did, attr.span);
}
}
from_target_feature(
tcx,
attr,
supported_target_features,
&mut codegen_fn_attrs.target_features,
);
} else if attr.has_name(sym::linkage) {
if let Some(val) = attr.value_str() {
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
if tcx.is_foreign_item(did) {
codegen_fn_attrs.import_linkage = linkage;
} else {
codegen_fn_attrs.linkage = linkage;
}
}
} else if attr.has_name(sym::link_section) {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!(
"illegal null byte in link_section \
value: `{}`",
&val
);
tcx.sess.span_err(attr.span, &msg);
} else {
codegen_fn_attrs.link_section = Some(val);
}
}
} else if attr.has_name(sym::link_name) {
codegen_fn_attrs.link_name = attr.value_str();
} else if attr.has_name(sym::link_ordinal) {
link_ordinal_span = Some(attr.span);
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
codegen_fn_attrs.link_ordinal = ordinal;
}
} else if attr.has_name(sym::no_sanitize) {
no_sanitize_span = Some(attr.span);
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
if item.has_name(sym::address) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
} else if item.has_name(sym::cfi) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
} else if item.has_name(sym::kcfi) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
} else if item.has_name(sym::memory) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
} else if item.has_name(sym::memtag) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
} else if item.has_name(sym::shadow_call_stack) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
} else if item.has_name(sym::thread) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
} else if item.has_name(sym::hwaddress) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
} else {
tcx.sess
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
.note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
.emit();
}
}
}
} else if attr.has_name(sym::instruction_set) {
codegen_fn_attrs.instruction_set = match attr.meta_kind() {
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
[NestedMetaItem::MetaItem(set)] => {
let segments =
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
match segments.as_slice() {
[sym::arm, sym::a32] | [sym::arm, sym::t32] => {
if !tcx.sess.target.has_thumb_interworking {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"target does not support `#[instruction_set]`"
)
.emit();
None
} else if segments[1] == sym::a32 {
Some(InstructionSetAttr::ArmA32)
} else if segments[1] == sym::t32 {
Some(InstructionSetAttr::ArmT32)
} else {
unreachable!()
}
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"invalid instruction set specified",
)
.emit();
None
}
}
}
[] => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"`#[instruction_set]` requires an argument"
)
.emit();
None
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"cannot specify more than one instruction set"
)
.emit();
None
}
},
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"must specify an instruction set"
)
.emit();
None
}
};
} else if attr.has_name(sym::repr) {
codegen_fn_attrs.alignment = match attr.meta_item_list() {
Some(items) => match items.as_slice() {
[item] => match item.name_value_literal() {
Some((sym::align, literal)) => {
let alignment = rustc_attr::parse_alignment(&literal.kind);
match alignment {
Ok(align) => Some(align),
Err(msg) => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0589,
"invalid `repr(align)` attribute: {}",
msg
)
.emit();
None
}
}
}
_ => None,
},
[] => None,
_ => None,
},
None => None,
};
}
}
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
if !attr.has_name(sym::inline) {
return ia;
}
match attr.meta_kind() {
Some(MetaItemKind::Word) => InlineAttr::Hint,
Some(MetaItemKind::List(ref items)) => {
inline_span = Some(attr.span);
if items.len() != 1 {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0534,
"expected one argument"
)
.emit();
InlineAttr::None
} else if list_contains_name(&items, sym::always) {
InlineAttr::Always
} else if list_contains_name(&items, sym::never) {
InlineAttr::Never
} else {
struct_span_err!(
tcx.sess.diagnostic(),
items[0].span(),
E0535,
"invalid argument"
)
.help("valid inline arguments are `always` and `never`")
.emit();
InlineAttr::None
}
}
Some(MetaItemKind::NameValue(_)) => ia,
None => ia,
}
});
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
if !attr.has_name(sym::optimize) {
return ia;
}
let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
match attr.meta_kind() {
Some(MetaItemKind::Word) => {
err(attr.span, "expected one argument");
ia
}
Some(MetaItemKind::List(ref items)) => {
inline_span = Some(attr.span);
if items.len() != 1 {
err(attr.span, "expected one argument");
OptimizeAttr::None
} else if list_contains_name(&items, sym::size) {
OptimizeAttr::Size
} else if list_contains_name(&items, sym::speed) {
OptimizeAttr::Speed
} else {
err(items[0].span(), "invalid argument");
OptimizeAttr::None
}
}
Some(MetaItemKind::NameValue(_)) => ia,
None => ia,
}
});
// #73631: closures inherit `#[target_feature]` annotations
if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
let owner_id = tcx.parent(did.to_def_id());
if tcx.def_kind(owner_id).has_codegen_attrs() {
codegen_fn_attrs
.target_features
.extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
}
}
// If a function uses #[target_feature] it can't be inlined into general
// purpose functions as they wouldn't have the right target features
// enabled. For that reason we also forbid #[inline(always)] as it can't be
// respected.
if !codegen_fn_attrs.target_features.is_empty() {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let Some(span) = inline_span {
tcx.sess.span_err(
span,
"cannot use `#[inline(always)]` with \
`#[target_feature]`",
);
}
}
}
if !codegen_fn_attrs.no_sanitize.is_empty() {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
tcx.struct_span_lint_hir(
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
no_sanitize_span,
"`no_sanitize` will have no effect after inlining",
|lint| lint.span_note(inline_span, "inlining requested here"),
)
}
}
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
codegen_fn_attrs.inline = InlineAttr::Never;
}
// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only
// strippable by the linker.
//
// Additionally weak lang items have predetermined symbol names.
if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
if let Some((name, _)) = lang_items::extract(attrs)
&& let Some(lang_item) = LangItem::from_name(name)
&& let Some(link_name) = lang_item.link_name()
{
codegen_fn_attrs.export_name = Some(link_name);
codegen_fn_attrs.link_name = Some(link_name);
}
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
// Internal symbols to the standard library all have no_mangle semantics in
// that they have defined symbol names present in the function name. This
// also applies to weak symbols where they all have known symbol names.
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
}
// Any linkage to LLVM intrinsics for now forcibly marks them all as never
// unwinds since LLVM sometimes can't handle codegen which `invoke`s
// intrinsic functions.
if let Some(name) = &codegen_fn_attrs.link_name {
if name.as_str().starts_with("llvm.") {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
}
}
codegen_fn_attrs
}
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(impl_item) = tcx.opt_associated_item(def_id)
&& let ty::AssocItemContainer::ImplContainer = impl_item.container
&& let Some(trait_item) = impl_item.trait_item_def_id
{
return tcx
.codegen_fn_attrs(trait_item)
.flags
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
}
false
}
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
feature_err(
&tcx.sess.parse_sess,
sym::raw_dylib,
attr.span,
"`#[link_ordinal]` is unstable on x86",
)
.emit();
}
let meta_item_list = attr.meta_item_list();
let meta_item_list = meta_item_list.as_deref();
let sole_meta_list = match meta_item_list {
Some([item]) => item.lit(),
Some(_) => {
tcx.sess
.struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
.note("the attribute requires exactly one argument")
.emit();
return None;
}
_ => None,
};
if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
sole_meta_list
{
// According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
// the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
// to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
//
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
// both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
// a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
// for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
// library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
// if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
// about LINK.EXE failing.)
if *ordinal <= u16::MAX as u128 {
Some(*ordinal as u16)
} else {
let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
tcx.sess
.struct_span_err(attr.span, &msg)
.note("the value may not exceed `u16::MAX`")
.emit();
None
}
} else {
tcx.sess
.struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
.note("an unsuffixed integer value, e.g., `1`, is expected")
.emit();
None
}
}
fn check_link_name_xor_ordinal(
tcx: TyCtxt<'_>,
codegen_fn_attrs: &CodegenFnAttrs,
inline_span: Option<Span>,
) {
if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
return;
}
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
if let Some(span) = inline_span {
tcx.sess.span_err(span, msg);
} else {
tcx.sess.err(msg);
}
}
pub fn provide(providers: &mut Providers) {
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
}

View File

@ -548,3 +548,10 @@ pub struct ArchiveBuildFailure {
pub struct UnknownArchiveKind<'a> {
pub kind: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_expected_used_symbol)]
pub struct ExpectedUsedSymbol {
#[primary_span]
pub span: Span,
}

View File

@ -42,6 +42,7 @@ use std::path::{Path, PathBuf};
pub mod back;
pub mod base;
pub mod codegen_attrs;
pub mod common;
pub mod coverageinfo;
pub mod debuginfo;
@ -180,6 +181,7 @@ pub fn provide(providers: &mut Providers) {
crate::back::symbol_export::provide(providers);
crate::base::provide(providers);
crate::target_features::provide(providers);
crate::codegen_attrs::provide(providers);
}
pub fn provide_extern(providers: &mut ExternProviders) {

View File

@ -1,8 +1,19 @@
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
/// Features that control behaviour of rustc, rather than the codegen.
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
@ -322,15 +333,148 @@ pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]
}
}
pub(crate) fn provide(providers: &mut Providers) {
providers.supported_target_features = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
if tcx.sess.opts.actually_rustdoc {
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
} else {
supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
}
pub fn from_target_feature(
tcx: TyCtxt<'_>,
attr: &ast::Attribute,
supported_target_features: &FxHashMap<String, Option<Symbol>>,
target_features: &mut Vec<Symbol>,
) {
let Some(list) = attr.meta_item_list() else { return };
let bad_item = |span| {
let msg = "malformed `target_feature` attribute input";
let code = "enable = \"..\"";
tcx.sess
.struct_span_err(span, msg)
.span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
.emit();
};
let rust_features = tcx.features();
for item in list {
// Only `enable = ...` is accepted in the meta-item list.
if !item.has_name(sym::enable) {
bad_item(item.span());
continue;
}
// Must be of the form `enable = "..."` (a string).
let Some(value) = item.value_str() else {
bad_item(item.span());
continue;
};
// We allow comma separation to enable multiple features.
target_features.extend(value.as_str().split(',').filter_map(|feature| {
let Some(feature_gate) = supported_target_features.get(feature) else {
let msg =
format!("the feature named `{}` is not valid for this target", feature);
let mut err = tcx.sess.struct_span_err(item.span(), &msg);
err.span_label(
item.span(),
format!("`{}` is not valid for this target", feature),
);
if let Some(stripped) = feature.strip_prefix('+') {
let valid = supported_target_features.contains_key(stripped);
if valid {
err.help("consider removing the leading `+` in the feature name");
}
}
err.emit();
return None;
};
// Only allow features whose feature gates have been enabled.
let allowed = match feature_gate.as_ref().copied() {
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
if !allowed {
feature_err(
&tcx.sess.parse_sess,
feature_gate.unwrap(),
item.span(),
&format!("the target feature `{}` is currently unstable", feature),
)
.emit();
}
Some(Symbol::intern(feature))
}));
}
}
/// Computes the set of target features used in a function for the purposes of
/// inline assembly.
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
let mut target_features = tcx.sess.unstable_target_features.clone();
if tcx.def_kind(did).has_codegen_attrs() {
let attrs = tcx.codegen_fn_attrs(did);
target_features.extend(&attrs.target_features);
match attrs.instruction_set {
None => {}
Some(InstructionSetAttr::ArmA32) => {
target_features.remove(&sym::thumb_mode);
}
Some(InstructionSetAttr::ArmT32) => {
target_features.insert(sym::thumb_mode);
}
}
}
tcx.arena.alloc(target_features)
}
/// Checks the function annotated with `#[target_feature]` is not a safe
/// trait method implementation, reporting an error if it is.
pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
let node = tcx.hir().get(hir_id);
if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
let parent_id = tcx.hir().get_parent_item(hir_id);
let parent_item = tcx.hir().expect_item(parent_id.def_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
.struct_span_err(
attr_span,
"`#[target_feature(..)]` cannot be applied to safe trait method",
)
.span_label(attr_span, "cannot be applied to safe trait method")
.span_label(tcx.def_span(id), "not an `unsafe` function")
.emit();
}
}
}
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
supported_target_features: |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
if tcx.sess.opts.actually_rustdoc {
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
} else {
supported_target_features(tcx.sess)
.iter()
.map(|&(a, b)| (a.to_string(), b))
.collect()
}
},
asm_target_features,
..*providers
}
}

View File

@ -52,7 +52,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
};
let always_live_locals = always_storage_live_locals(body);
let storage_liveness = MaybeStorageLive::new(always_live_locals)
let storage_liveness = MaybeStorageLive::new(std::borrow::Cow::Owned(always_live_locals))
.into_engine(tcx, body)
.iterate_to_fixpoint()
.into_results_cursor(body);
@ -79,7 +79,7 @@ struct TypeChecker<'a, 'tcx> {
param_env: ParamEnv<'tcx>,
mir_phase: MirPhase,
reachable_blocks: BitSet<BasicBlock>,
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>,
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
place_cache: Vec<PlaceRef<'tcx>>,
value_cache: Vec<u128>,
}

View File

@ -5,7 +5,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::{lang_items, LangItem};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt};
use rustc_span::symbol::Ident;
use rustc_span::{sym, DesugaringKind, Span};
@ -39,9 +39,7 @@ pub enum CallKind<'tcx> {
Normal {
self_arg: Option<Ident>,
desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
/// Whether the self type of the method call has an `.as_ref()` method.
/// Used for better diagnostics.
is_option_or_result: bool,
method_did: DefId,
},
/// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
@ -133,16 +131,6 @@ pub fn call_kind<'tcx>(
} else {
None
};
let parent_did = tcx.parent(method_did);
let parent_self_ty = (tcx.def_kind(parent_did) == rustc_hir::def::DefKind::Impl)
.then_some(parent_did)
.and_then(|did| match tcx.type_of(did).kind() {
ty::Adt(def, ..) => Some(def.did()),
_ => None,
});
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
CallKind::Normal { self_arg, desugaring, is_option_or_result }
CallKind::Normal { self_arg, desugaring, method_did }
})
}

View File

@ -192,3 +192,5 @@ codegen_ssa_archive_build_failure =
codegen_ssa_unknown_archive_kind =
Don't know how to build archive of type: {$kind}
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`

View File

@ -101,8 +101,6 @@ hir_analysis_extern_crate_not_idiomatic =
`extern crate` is not idiomatic in the new edition
.suggestion = convert it to a `{$msg_code}`
hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
hir_analysis_const_impl_for_non_const_trait =
const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
.suggestion = mark `{$trait_name}` as const

View File

@ -1408,49 +1408,58 @@ impl EmitterWriter {
if !sm.ensure_source_file_source_present(annotated_file.file.clone()) {
if !self.short_message {
// We'll just print an unannotated message.
for (annotation_id, line) in annotated_file.lines.into_iter().enumerate() {
for (annotation_id, line) in annotated_file.lines.iter().enumerate() {
let mut annotations = line.annotations.clone();
annotations.sort_by_key(|a| Reverse(a.start_col));
let mut line_idx = buffer.num_lines();
buffer.append(
line_idx,
&format!(
"{}:{}:{}",
sm.filename_for_diagnostics(&annotated_file.file.name),
sm.doctest_offset_line(&annotated_file.file.name, line.line_index),
annotations[0].start_col + 1,
),
Style::LineAndColumn,
);
if annotation_id == 0 {
buffer.prepend(line_idx, "--> ", Style::LineNumber);
let labels: Vec<_> = annotations
.iter()
.filter_map(|a| Some((a.label.as_ref()?, a.is_primary)))
.filter(|(l, _)| !l.is_empty())
.collect();
if annotation_id == 0 || !labels.is_empty() {
buffer.append(
line_idx,
&format!(
"{}:{}:{}",
sm.filename_for_diagnostics(&annotated_file.file.name),
sm.doctest_offset_line(
&annotated_file.file.name,
line.line_index
),
annotations[0].start_col + 1,
),
Style::LineAndColumn,
);
if annotation_id == 0 {
buffer.prepend(line_idx, "--> ", Style::LineNumber);
} else {
buffer.prepend(line_idx, "::: ", Style::LineNumber);
}
for _ in 0..max_line_num_len {
buffer.prepend(line_idx, " ", Style::NoStyle);
}
line_idx += 1;
};
for (i, annotation) in annotations.into_iter().enumerate() {
if let Some(label) = &annotation.label {
let style = if annotation.is_primary {
Style::LabelPrimary
} else {
Style::LabelSecondary
};
if annotation_id == 0 {
buffer.prepend(line_idx, " |", Style::LineNumber);
for _ in 0..max_line_num_len {
buffer.prepend(line_idx, " ", Style::NoStyle);
}
line_idx += 1;
buffer.append(line_idx + i, " = note: ", style);
for _ in 0..max_line_num_len {
buffer.prepend(line_idx, " ", Style::NoStyle);
}
} else {
buffer.append(line_idx + i, ": ", style);
}
buffer.append(line_idx + i, label, style);
}
for (label, is_primary) in labels.into_iter() {
let style = if is_primary {
Style::LabelPrimary
} else {
Style::LabelSecondary
};
buffer.prepend(line_idx, " |", Style::LineNumber);
for _ in 0..max_line_num_len {
buffer.prepend(line_idx, " ", Style::NoStyle);
}
line_idx += 1;
buffer.append(line_idx, " = note: ", style);
for _ in 0..max_line_num_len {
buffer.prepend(line_idx, " ", Style::NoStyle);
}
buffer.append(line_idx, label, style);
line_idx += 1;
}
}
}

View File

@ -17,28 +17,20 @@
use crate::astconv::AstConv;
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
use rustc_ast as ast;
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
use rustc_hir::{lang_items, GenericParamKind, LangItem, Node};
use rustc_hir::{GenericParamKind, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_session::lint;
use rustc_session::parse::feature_err;
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::{abi, SanitizerSet};
use rustc_target::spec::abi;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use std::iter;
@ -78,10 +70,7 @@ pub fn provide(providers: &mut Providers) {
impl_polarity,
is_foreign_item,
generator_kind,
codegen_fn_attrs,
asm_target_features,
collect_mod_item_types,
should_inherit_track_caller,
..*providers
};
}
@ -1455,797 +1444,3 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind>
_ => bug!("generator_kind applied to non-local def-id {:?}", def_id),
}
}
fn from_target_feature(
tcx: TyCtxt<'_>,
attr: &ast::Attribute,
supported_target_features: &FxHashMap<String, Option<Symbol>>,
target_features: &mut Vec<Symbol>,
) {
let Some(list) = attr.meta_item_list() else { return };
let bad_item = |span| {
let msg = "malformed `target_feature` attribute input";
let code = "enable = \"..\"";
tcx.sess
.struct_span_err(span, msg)
.span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
.emit();
};
let rust_features = tcx.features();
for item in list {
// Only `enable = ...` is accepted in the meta-item list.
if !item.has_name(sym::enable) {
bad_item(item.span());
continue;
}
// Must be of the form `enable = "..."` (a string).
let Some(value) = item.value_str() else {
bad_item(item.span());
continue;
};
// We allow comma separation to enable multiple features.
target_features.extend(value.as_str().split(',').filter_map(|feature| {
let Some(feature_gate) = supported_target_features.get(feature) else {
let msg =
format!("the feature named `{}` is not valid for this target", feature);
let mut err = tcx.sess.struct_span_err(item.span(), &msg);
err.span_label(
item.span(),
format!("`{}` is not valid for this target", feature),
);
if let Some(stripped) = feature.strip_prefix('+') {
let valid = supported_target_features.contains_key(stripped);
if valid {
err.help("consider removing the leading `+` in the feature name");
}
}
err.emit();
return None;
};
// Only allow features whose feature gates have been enabled.
let allowed = match feature_gate.as_ref().copied() {
Some(sym::arm_target_feature) => rust_features.arm_target_feature,
Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
Some(sym::mips_target_feature) => rust_features.mips_target_feature,
Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
Some(name) => bug!("unknown target feature gate {}", name),
None => true,
};
if !allowed {
feature_err(
&tcx.sess.parse_sess,
feature_gate.unwrap(),
item.span(),
&format!("the target feature `{}` is currently unstable", feature),
)
.emit();
}
Some(Symbol::intern(feature))
}));
}
}
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
use rustc_middle::mir::mono::Linkage::*;
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
// applicable to variable declarations and may not really make sense for
// Rust code in the first place but allow them anyway and trust that the
// user knows what they're doing. Who knows, unanticipated use cases may pop
// up in the future.
//
// ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
// and don't have to be, LLVM treats them as no-ops.
match name {
"appending" => Appending,
"available_externally" => AvailableExternally,
"common" => Common,
"extern_weak" => ExternalWeak,
"external" => External,
"internal" => Internal,
"linkonce" => LinkOnceAny,
"linkonce_odr" => LinkOnceODR,
"private" => Private,
"weak" => WeakAny,
"weak_odr" => WeakODR,
_ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
}
}
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
if cfg!(debug_assertions) {
let def_kind = tcx.def_kind(did);
assert!(
def_kind.has_codegen_attrs(),
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
);
}
let did = did.expect_local();
let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
let mut codegen_fn_attrs = CodegenFnAttrs::new();
if tcx.should_inherit_track_caller(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
}
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
let mut inline_span = None;
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;
for attr in attrs.iter() {
if attr.has_name(sym::cold) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
} else if attr.has_name(sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
} else if attr.has_name(sym::ffi_returns_twice) {
if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else {
// `#[ffi_returns_twice]` is only allowed `extern fn`s.
struct_span_err!(
tcx.sess,
attr.span,
E0724,
"`#[ffi_returns_twice]` may only be used on foreign functions"
)
.emit();
}
} else if attr.has_name(sym::ffi_pure) {
if tcx.is_foreign_item(did) {
if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]`
struct_span_err!(
tcx.sess,
attr.span,
E0757,
"`#[ffi_const]` function cannot be `#[ffi_pure]`"
)
.emit();
} else {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_PURE;
}
} else {
// `#[ffi_pure]` is only allowed on foreign functions
struct_span_err!(
tcx.sess,
attr.span,
E0755,
"`#[ffi_pure]` may only be used on foreign functions"
)
.emit();
}
} else if attr.has_name(sym::ffi_const) {
if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else {
// `#[ffi_const]` is only allowed on foreign functions
struct_span_err!(
tcx.sess,
attr.span,
E0756,
"`#[ffi_const]` may only be used on foreign functions"
)
.emit();
}
} else if attr.has_name(sym::rustc_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
} else if attr.has_name(sym::rustc_reallocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;
} else if attr.has_name(sym::rustc_deallocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::DEALLOCATOR;
} else if attr.has_name(sym::rustc_allocator_zeroed) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED;
} else if attr.has_name(sym::naked) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
} else if attr.has_name(sym::no_mangle) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
} else if attr.has_name(sym::no_coverage) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
} else if attr.has_name(sym::rustc_std_internal_symbol) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
} else if attr.has_name(sym::used) {
let inner = attr.meta_item_list();
match inner.as_deref() {
Some([item]) if item.has_name(sym::linker) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
sym::used_with_arg,
attr.span,
"`#[used(linker)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
}
Some([item]) if item.has_name(sym::compiler) => {
if !tcx.features().used_with_arg {
feature_err(
&tcx.sess.parse_sess,
sym::used_with_arg,
attr.span,
"`#[used(compiler)]` is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
}
Some(_) => {
tcx.sess.emit_err(errors::ExpectedUsedSymbol { span: attr.span });
}
None => {
// Unfortunately, unconditionally using `llvm.used` causes
// issues in handling `.init_array` with the gold linker,
// but using `llvm.compiler.used` caused a nontrival amount
// of unintentional ecosystem breakage -- particularly on
// Mach-O targets.
//
// As a result, we emit `llvm.compiler.used` only on ELF
// targets. This is somewhat ad-hoc, but actually follows
// our pre-LLVM 13 behavior (prior to the ecosystem
// breakage), and seems to match `clang`'s behavior as well
// (both before and after LLVM 13), possibly because they
// have similar compatibility concerns to us. See
// https://github.com/rust-lang/rust/issues/47384#issuecomment-1019080146
// and following comments for some discussion of this, as
// well as the comments in `rustc_codegen_llvm` where these
// flags are handled.
//
// Anyway, to be clear: this is still up in the air
// somewhat, and is subject to change in the future (which
// is a good thing, because this would ideally be a bit
// more firmed up).
let is_like_elf = !(tcx.sess.target.is_like_osx
|| tcx.sess.target.is_like_windows
|| tcx.sess.target.is_like_wasm);
codegen_fn_attrs.flags |= if is_like_elf {
CodegenFnAttrFlags::USED
} else {
CodegenFnAttrFlags::USED_LINKER
};
}
}
} else if attr.has_name(sym::cmse_nonsecure_entry) {
if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
struct_span_err!(
tcx.sess,
attr.span,
E0776,
"`#[cmse_nonsecure_entry]` requires C ABI"
)
.emit();
}
if !tcx.sess.target.llvm_target.contains("thumbv8m") {
struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
} else if attr.has_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if attr.has_name(sym::track_caller) {
if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
feature_err(
&tcx.sess.parse_sess,
sym::closure_track_caller,
attr.span,
"`#[track_caller]` on closures is currently unstable",
)
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
} else if attr.has_name(sym::export_name) {
if let Some(s) = attr.value_str() {
if s.as_str().contains('\0') {
// `#[export_name = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
struct_span_err!(
tcx.sess,
attr.span,
E0648,
"`export_name` may not contain null characters"
)
.emit();
}
codegen_fn_attrs.export_name = Some(s);
}
} else if attr.has_name(sym::target_feature) {
if !tcx.is_closure(did.to_def_id())
&& tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
{
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
// The `#[target_feature]` attribute is allowed on
// WebAssembly targets on all functions, including safe
// ones. Other targets require that `#[target_feature]` is
// only applied to unsafe functions (pending the
// `target_feature_11` feature) because on most targets
// execution of instructions that are not supported is
// considered undefined behavior. For WebAssembly which is a
// 100% safe target at execution time it's not possible to
// execute undefined instructions, and even if a future
// feature was added in some form for this it would be a
// deterministic trap. There is no undefined behavior when
// executing WebAssembly so `#[target_feature]` is allowed
// on safe functions (but again, only for WebAssembly)
//
// Note that this is also allowed if `actually_rustdoc` so
// if a target is documenting some wasm-specific code then
// it's not spuriously denied.
} else if !tcx.features().target_feature_11 {
let mut err = feature_err(
&tcx.sess.parse_sess,
sym::target_feature_11,
attr.span,
"`#[target_feature(..)]` can only be applied to `unsafe` functions",
);
err.span_label(tcx.def_span(did), "not an `unsafe` function");
err.emit();
} else {
check_target_feature_trait_unsafe(tcx, did, attr.span);
}
}
from_target_feature(
tcx,
attr,
supported_target_features,
&mut codegen_fn_attrs.target_features,
);
} else if attr.has_name(sym::linkage) {
if let Some(val) = attr.value_str() {
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
if tcx.is_foreign_item(did) {
codegen_fn_attrs.import_linkage = linkage;
} else {
codegen_fn_attrs.linkage = linkage;
}
}
} else if attr.has_name(sym::link_section) {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!(
"illegal null byte in link_section \
value: `{}`",
&val
);
tcx.sess.span_err(attr.span, &msg);
} else {
codegen_fn_attrs.link_section = Some(val);
}
}
} else if attr.has_name(sym::link_name) {
codegen_fn_attrs.link_name = attr.value_str();
} else if attr.has_name(sym::link_ordinal) {
link_ordinal_span = Some(attr.span);
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
codegen_fn_attrs.link_ordinal = ordinal;
}
} else if attr.has_name(sym::no_sanitize) {
no_sanitize_span = Some(attr.span);
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
if item.has_name(sym::address) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
} else if item.has_name(sym::cfi) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
} else if item.has_name(sym::kcfi) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI;
} else if item.has_name(sym::memory) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
} else if item.has_name(sym::memtag) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG;
} else if item.has_name(sym::shadow_call_stack) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK;
} else if item.has_name(sym::thread) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
} else if item.has_name(sym::hwaddress) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
} else {
tcx.sess
.struct_span_err(item.span(), "invalid argument for `no_sanitize`")
.note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
.emit();
}
}
}
} else if attr.has_name(sym::instruction_set) {
codegen_fn_attrs.instruction_set = match attr.meta_kind() {
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
[NestedMetaItem::MetaItem(set)] => {
let segments =
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
match segments.as_slice() {
[sym::arm, sym::a32] | [sym::arm, sym::t32] => {
if !tcx.sess.target.has_thumb_interworking {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"target does not support `#[instruction_set]`"
)
.emit();
None
} else if segments[1] == sym::a32 {
Some(InstructionSetAttr::ArmA32)
} else if segments[1] == sym::t32 {
Some(InstructionSetAttr::ArmT32)
} else {
unreachable!()
}
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"invalid instruction set specified",
)
.emit();
None
}
}
}
[] => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"`#[instruction_set]` requires an argument"
)
.emit();
None
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"cannot specify more than one instruction set"
)
.emit();
None
}
},
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"must specify an instruction set"
)
.emit();
None
}
};
} else if attr.has_name(sym::repr) {
codegen_fn_attrs.alignment = match attr.meta_item_list() {
Some(items) => match items.as_slice() {
[item] => match item.name_value_literal() {
Some((sym::align, literal)) => {
let alignment = rustc_attr::parse_alignment(&literal.kind);
match alignment {
Ok(align) => Some(align),
Err(msg) => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0589,
"invalid `repr(align)` attribute: {}",
msg
)
.emit();
None
}
}
}
_ => None,
},
[] => None,
_ => None,
},
None => None,
};
}
}
codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
if !attr.has_name(sym::inline) {
return ia;
}
match attr.meta_kind() {
Some(MetaItemKind::Word) => InlineAttr::Hint,
Some(MetaItemKind::List(ref items)) => {
inline_span = Some(attr.span);
if items.len() != 1 {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0534,
"expected one argument"
)
.emit();
InlineAttr::None
} else if list_contains_name(&items, sym::always) {
InlineAttr::Always
} else if list_contains_name(&items, sym::never) {
InlineAttr::Never
} else {
struct_span_err!(
tcx.sess.diagnostic(),
items[0].span(),
E0535,
"invalid argument"
)
.help("valid inline arguments are `always` and `never`")
.emit();
InlineAttr::None
}
}
Some(MetaItemKind::NameValue(_)) => ia,
None => ia,
}
});
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
if !attr.has_name(sym::optimize) {
return ia;
}
let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit();
match attr.meta_kind() {
Some(MetaItemKind::Word) => {
err(attr.span, "expected one argument");
ia
}
Some(MetaItemKind::List(ref items)) => {
inline_span = Some(attr.span);
if items.len() != 1 {
err(attr.span, "expected one argument");
OptimizeAttr::None
} else if list_contains_name(&items, sym::size) {
OptimizeAttr::Size
} else if list_contains_name(&items, sym::speed) {
OptimizeAttr::Speed
} else {
err(items[0].span(), "invalid argument");
OptimizeAttr::None
}
}
Some(MetaItemKind::NameValue(_)) => ia,
None => ia,
}
});
// #73631: closures inherit `#[target_feature]` annotations
if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
let owner_id = tcx.parent(did.to_def_id());
if tcx.def_kind(owner_id).has_codegen_attrs() {
codegen_fn_attrs
.target_features
.extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied());
}
}
// If a function uses #[target_feature] it can't be inlined into general
// purpose functions as they wouldn't have the right target features
// enabled. For that reason we also forbid #[inline(always)] as it can't be
// respected.
if !codegen_fn_attrs.target_features.is_empty() {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let Some(span) = inline_span {
tcx.sess.span_err(
span,
"cannot use `#[inline(always)]` with \
`#[target_feature]`",
);
}
}
}
if !codegen_fn_attrs.no_sanitize.is_empty() {
if codegen_fn_attrs.inline == InlineAttr::Always {
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
tcx.struct_span_lint_hir(
lint::builtin::INLINE_NO_SANITIZE,
hir_id,
no_sanitize_span,
"`no_sanitize` will have no effect after inlining",
|lint| lint.span_note(inline_span, "inlining requested here"),
)
}
}
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
codegen_fn_attrs.inline = InlineAttr::Never;
}
// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only
// strippable by the linker.
//
// Additionally weak lang items have predetermined symbol names.
if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
if let Some((name, _)) = lang_items::extract(attrs)
&& let Some(lang_item) = LangItem::from_name(name)
&& let Some(link_name) = lang_item.link_name()
{
codegen_fn_attrs.export_name = Some(link_name);
codegen_fn_attrs.link_name = Some(link_name);
}
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
// Internal symbols to the standard library all have no_mangle semantics in
// that they have defined symbol names present in the function name. This
// also applies to weak symbols where they all have known symbol names.
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
}
// Any linkage to LLVM intrinsics for now forcibly marks them all as never
// unwinds since LLVM sometimes can't handle codegen which `invoke`s
// intrinsic functions.
if let Some(name) = &codegen_fn_attrs.link_name {
if name.as_str().starts_with("llvm.") {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
}
}
codegen_fn_attrs
}
/// Computes the set of target features used in a function for the purposes of
/// inline assembly.
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
let mut target_features = tcx.sess.unstable_target_features.clone();
if tcx.def_kind(did).has_codegen_attrs() {
let attrs = tcx.codegen_fn_attrs(did);
target_features.extend(&attrs.target_features);
match attrs.instruction_set {
None => {}
Some(InstructionSetAttr::ArmA32) => {
target_features.remove(&sym::thumb_mode);
}
Some(InstructionSetAttr::ArmT32) => {
target_features.insert(sym::thumb_mode);
}
}
}
tcx.arena.alloc(target_features)
}
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
/// applied to the method prototype.
fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
if let Some(impl_item) = tcx.opt_associated_item(def_id)
&& let ty::AssocItemContainer::ImplContainer = impl_item.container
&& let Some(trait_item) = impl_item.trait_item_def_id
{
return tcx
.codegen_fn_attrs(trait_item)
.flags
.intersects(CodegenFnAttrFlags::TRACK_CALLER);
}
false
}
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
feature_err(
&tcx.sess.parse_sess,
sym::raw_dylib,
attr.span,
"`#[link_ordinal]` is unstable on x86",
)
.emit();
}
let meta_item_list = attr.meta_item_list();
let meta_item_list = meta_item_list.as_deref();
let sole_meta_list = match meta_item_list {
Some([item]) => item.lit(),
Some(_) => {
tcx.sess
.struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
.note("the attribute requires exactly one argument")
.emit();
return None;
}
_ => None,
};
if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
sole_meta_list
{
// According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header,
// the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information
// to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
//
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for this:
// both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that specifies
// a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import library
// for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an import
// library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet
// if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment
// about LINK.EXE failing.)
if *ordinal <= u16::MAX as u128 {
Some(*ordinal as u16)
} else {
let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
tcx.sess
.struct_span_err(attr.span, &msg)
.note("the value may not exceed `u16::MAX`")
.emit();
None
}
} else {
tcx.sess
.struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
.note("an unsuffixed integer value, e.g., `1`, is expected")
.emit();
None
}
}
fn check_link_name_xor_ordinal(
tcx: TyCtxt<'_>,
codegen_fn_attrs: &CodegenFnAttrs,
inline_span: Option<Span>,
) {
if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
return;
}
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
if let Some(span) = inline_span {
tcx.sess.span_err(span, msg);
} else {
tcx.sess.err(msg);
}
}
/// Checks the function annotated with `#[target_feature]` is not a safe
/// trait method implementation, reporting an error if it is.
fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
let hir_id = tcx.hir().local_def_id_to_hir_id(id);
let node = tcx.hir().get(hir_id);
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
let parent_id = tcx.hir().get_parent_item(hir_id);
let parent_item = tcx.hir().expect_item(parent_id.def_id);
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
.struct_span_err(
attr_span,
"`#[target_feature(..)]` cannot be applied to safe trait method",
)
.span_label(attr_span, "cannot be applied to safe trait method")
.span_label(tcx.def_span(id), "not an `unsafe` function")
.emit();
}
}
}

View File

@ -75,7 +75,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty();
// We use an `IndexSet` to preserves order of insertion.
// We use an `IndexSet` to preserve order of insertion.
// Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
@ -97,11 +97,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => *generics,
ItemKind::Trait(_, _, ref generics, ..) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
*generics
}
ItemKind::TraitAlias(ref generics, _) => {
ItemKind::Trait(_, _, ref generics, ..) | ItemKind::TraitAlias(ref generics, _) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id));
*generics
}
@ -406,9 +402,10 @@ pub(super) fn explicit_predicates_of<'tcx>(
// For a predicate from a where clause to become a bound on an
// associated type:
// * It must use the identity substs of the item.
// * Since any generic parameters on the item are not in scope,
// this means that the item is not a GAT, and its identity
// substs are the same as the trait's.
// * We're in the scope of the trait, so we can't name any
// parameters of the GAT. That means that all we need to
// check are that the substs of the projection are the
// identity substs of the trait.
// * It must be an associated type for this trait (*not* a
// supertrait).
if let ty::Projection(projection) = ty.kind() {

View File

@ -253,13 +253,6 @@ pub struct ExternCrateNotIdiomatic {
pub suggestion_code: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_expected_used_symbol)]
pub struct ExpectedUsedSymbol {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_const_impl_for_non_const_trait)]
pub struct ConstImplForNonConstTrait {

View File

@ -1853,7 +1853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)],
) {
let mut derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::<Span>::new();
let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates {
let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() else { continue };
let adt = match trait_pred.self_ty().ty_adt_def() {
@ -1892,10 +1892,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
derives.push((self_name, self_span, diagnostic_name));
} else {
traits.push(self.tcx.def_span(trait_pred.def_id()));
traits.push(trait_pred.def_id());
}
} else {
traits.push(self.tcx.def_span(trait_pred.def_id()));
traits.push(trait_pred.def_id());
}
}
traits.sort();
@ -1918,10 +1918,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let len = traits.len();
if len > 0 {
let span: MultiSpan = traits.into();
let span =
MultiSpan::from_spans(traits.iter().map(|&did| self.tcx.def_span(did)).collect());
let mut names = format!("`{}`", self.tcx.def_path_str(traits[0]));
for (i, &did) in traits.iter().enumerate().skip(1) {
if len > 2 {
names.push_str(", ");
}
if i == len - 1 {
names.push_str(" and ");
}
names.push('`');
names.push_str(&self.tcx.def_path_str(did));
names.push('`');
}
err.span_note(
span,
&format!("the following trait{} must be implemented", pluralize!(len),),
&format!("the trait{} {} must be implemented", pluralize!(len), names),
);
}

View File

@ -1527,13 +1527,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base
{
if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
if let rustc_span::FileName::Real(ref mut old_name) = name {
if let rustc_span::RealFileName::LocalPath(local) = old_name {
if let Ok(rest) = local.strip_prefix(real_dir) {
*old_name = rustc_span::RealFileName::Remapped {
local_path: None,
virtual_name: virtual_dir.join(rest),
};
for subdir in ["library", "compiler"] {
if let rustc_span::FileName::Real(ref mut old_name) = name {
if let rustc_span::RealFileName::LocalPath(local) = old_name {
if let Ok(rest) = local.strip_prefix(real_dir.join(subdir)) {
*old_name = rustc_span::RealFileName::Remapped {
local_path: None,
virtual_name: virtual_dir.join(subdir).join(rest),
};
}
}
}
}

View File

@ -252,7 +252,7 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for GenericArg<'tcx> {
}
}
/// A substitution mapping generic parameters to new values.
/// List of generic arguments that are gonna be used to substitute generic parameters.
pub type InternalSubsts<'tcx> = List<GenericArg<'tcx>>;
pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>;

View File

@ -231,7 +231,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
remainder_span,
pattern,
None,
Some((None, initializer_span)),
Some((Some(&destination), initializer_span)),
);
this.visit_primary_bindings(
pattern,

View File

@ -20,6 +20,7 @@
use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
use rustc_index::vec::IndexVec;
use rustc_middle::{
mir::*,
@ -33,6 +34,7 @@ mod parse;
pub(super) fn build_custom_mir<'tcx>(
tcx: TyCtxt<'tcx>,
did: DefId,
hir_id: HirId,
thir: &Thir<'tcx>,
expr: ExprId,
params: &IndexVec<ParamId, Param<'tcx>>,
@ -67,7 +69,10 @@ pub(super) fn build_custom_mir<'tcx>(
parent_scope: None,
inlined: None,
inlined_parent_scope: None,
local_data: ClearCrossCrate::Clear,
local_data: ClearCrossCrate::Set(SourceScopeLocalData {
lint_root: hir_id,
safety: Safety::Safe,
}),
});
body.injection_phase = Some(parse_attribute(attr));

View File

@ -487,6 +487,7 @@ fn construct_fn<'tcx>(
return custom::build_custom_mir(
tcx,
fn_def.did.to_def_id(),
fn_id,
thir,
expr,
arguments,

View File

@ -132,6 +132,18 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
fn unsafe_op_in_unsafe_fn_allowed(&self) -> bool {
self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, self.hir_context).0 == Level::Allow
}
/// Handle closures/generators/inline-consts, which is unsafecked with their parent body.
fn visit_inner_body(&mut self, def: ty::WithOptConstParam<LocalDefId>) {
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
let inner_thir = &inner_thir.borrow();
let hir_context = self.tcx.hir().local_def_id_to_hir_id(def.did);
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
inner_visitor.visit_expr(&inner_thir[expr]);
// Unsafe blocks can be used in the inner body, make sure to take it into account
self.safety_context = inner_visitor.safety_context;
}
}
}
// Searches for accesses to layout constrained fields.
@ -408,16 +420,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
} else {
ty::WithOptConstParam::unknown(closure_id)
};
let (closure_thir, expr) = self.tcx.thir_body(closure_def).unwrap_or_else(|_| {
(self.tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0))
});
let closure_thir = &closure_thir.borrow();
let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
let mut closure_visitor =
UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
closure_visitor.visit_expr(&closure_thir[expr]);
// Unsafe blocks can be used in closures, make sure to take it into account
self.safety_context = closure_visitor.safety_context;
self.visit_inner_body(closure_def);
}
ExprKind::ConstBlock { did, substs: _ } => {
let def_id = did.expect_local();
self.visit_inner_body(ty::WithOptConstParam::unknown(def_id));
}
ExprKind::Field { lhs, .. } => {
let lhs = &self.thir[lhs];
@ -612,11 +619,8 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
return;
}
// Closures are handled by their owner, if it has a body
if tcx.is_closure(def.did.to_def_id()) {
let hir = tcx.hir();
let owner = hir.enclosing_body_owner(hir.local_def_id_to_hir_id(def.did));
tcx.ensure().thir_check_unsafety(owner);
// Closures and inline consts are handled by their owner, if it has a body
if tcx.is_typeck_child(def.did.to_def_id()) {
return;
}

View File

@ -3,20 +3,21 @@ pub use super::*;
use crate::{CallReturnPlaces, GenKill, Results, ResultsRefCursor};
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use std::borrow::Cow;
use std::cell::RefCell;
#[derive(Clone)]
pub struct MaybeStorageLive {
always_live_locals: BitSet<Local>,
pub struct MaybeStorageLive<'a> {
always_live_locals: Cow<'a, BitSet<Local>>,
}
impl MaybeStorageLive {
pub fn new(always_live_locals: BitSet<Local>) -> Self {
impl<'a> MaybeStorageLive<'a> {
pub fn new(always_live_locals: Cow<'a, BitSet<Local>>) -> Self {
MaybeStorageLive { always_live_locals }
}
}
impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive {
impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> {
type Domain = BitSet<Local>;
const NAME: &'static str = "maybe_storage_live";
@ -38,7 +39,7 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageLive {
}
}
impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageLive {
impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
type Idx = Local;
fn statement_effect(

View File

@ -1,6 +1,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::HirId;
use rustc_hir::intravisit;
@ -134,6 +135,28 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
self.super_rvalue(rvalue, location);
}
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
if let Operand::Constant(constant) = op {
let maybe_uneval = match constant.literal {
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
ConstantKind::Unevaluated(uv, _) => Some(uv),
};
if let Some(uv) = maybe_uneval {
if uv.promoted.is_none() {
let def_id = uv.def.def_id_for_type_of();
if self.tcx.def_kind(def_id) == DefKind::InlineConst {
let local_def_id = def_id.expect_local();
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
self.tcx.unsafety_check_result(local_def_id);
self.register_violations(violations, used_unsafe_blocks.iter().copied());
}
}
}
}
self.super_operand(op, location);
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
// On types with `scalar_valid_range`, prevent
// * `&mut x.field`
@ -410,6 +433,12 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
intravisit::walk_block(self, block);
}
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
if matches!(self.tcx.def_kind(c.def_id), DefKind::InlineConst) {
self.visit_body(self.tcx.hir().body(c.body))
}
}
fn visit_fn(
&mut self,
fk: intravisit::FnKind<'tcx>,
@ -484,7 +513,7 @@ fn unsafety_check_result<'tcx>(
let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
checker.visit_body(&body);
let unused_unsafes = (!tcx.is_closure(def.did.to_def_id()))
let unused_unsafes = (!tcx.is_typeck_child(def.did.to_def_id()))
.then(|| check_unused_unsafe(tcx, def.did, &checker.used_unsafe_blocks));
tcx.arena.alloc(UnsafetyCheckResult {
@ -516,8 +545,8 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
debug!("check_unsafety({:?})", def_id);
// closures are handled by their parent fn.
if tcx.is_closure(def_id.to_def_id()) {
// closures and inline consts are handled by their parent fn.
if tcx.is_typeck_child(def_id.to_def_id()) {
return;
}

View File

@ -490,7 +490,7 @@ fn locals_live_across_suspend_points<'tcx>(
// Calculate when MIR locals have live storage. This gives us an upper bound of their
// lifetimes.
let mut storage_live = MaybeStorageLive::new(always_live_locals.clone())
let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
.into_engine(tcx, body_ref)
.iterate_to_fixpoint()
.into_results_cursor(body_ref);

View File

@ -1308,15 +1308,15 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
let is_local_static =
if let DefKind::Static(_) = kind { def_id.is_local() } else { false };
if !self.item_is_accessible(def_id) && !is_local_static {
let sess = self.tcx.sess;
let sm = sess.source_map();
let name = match qpath {
hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => {
sm.span_to_snippet(qpath.span()).ok()
let name = match *qpath {
hir::QPath::LangItem(it, ..) => {
self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
}
hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
};
let kind = kind.descr(def_id);
let sess = self.tcx.sess;
let _ = match name {
Some(name) => {
sess.emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })

View File

@ -2186,15 +2186,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
};
let mut explain_yield = |interior_span: Span,
yield_span: Span,
scope_span: Option<Span>| {
let mut span = MultiSpan::from_span(yield_span);
if let Ok(snippet) = source_map.span_to_snippet(interior_span) {
// #70935: If snippet contains newlines, display "the value" instead
// so that we do not emit complex diagnostics.
let snippet = &format!("`{}`", snippet);
let snippet = if snippet.contains('\n') { "the value" } else { snippet };
let mut explain_yield =
|interior_span: Span, yield_span: Span, scope_span: Option<Span>| {
let mut span = MultiSpan::from_span(yield_span);
let snippet = match source_map.span_to_snippet(interior_span) {
// #70935: If snippet contains newlines, display "the value" instead
// so that we do not emit complex diagnostics.
Ok(snippet) if !snippet.contains('\n') => format!("`{}`", snippet),
_ => "the value".to_string(),
};
// note: future is not `Send` as this value is used across an await
// --> $DIR/issue-70935-complex-spans.rs:13:9
// |
@ -2219,17 +2219,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
interior_span,
format!("has type `{}` which {}", target_ty, trait_explanation),
);
// If available, use the scope span to annotate the drop location.
let mut scope_note = None;
if let Some(scope_span) = scope_span {
let scope_span = source_map.end_point(scope_span);
let msg = format!("{} is later dropped here", snippet);
if source_map.is_multiline(yield_span.between(scope_span)) {
span.push_span_label(scope_span, msg);
} else {
scope_note = Some((scope_span, msg));
}
span.push_span_label(scope_span, msg);
}
err.span_note(
span,
@ -2238,11 +2232,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
future_or_generator, trait_explanation, an_await_or_yield
),
);
if let Some((span, msg)) = scope_note {
err.span_note(span, &msg);
}
}
};
};
match interior_or_upvar_span {
GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => {
if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info {

View File

@ -187,9 +187,9 @@ pub fn change_continue_label() {
}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, typeck")]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, typeck, optimized_mir")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_continue_label() {
let mut _x = 0;

View File

@ -158,9 +158,9 @@ pub fn change_break_label() {
}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn change_break_label() {
let mut _x = 0;
@ -210,9 +210,9 @@ pub fn change_continue_label() {
}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn change_continue_label() {
let mut _x = 0;

View File

@ -158,9 +158,9 @@ pub fn change_break_label() {
}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_break_label() {
let mut _x = 0;
@ -212,9 +212,9 @@ pub fn change_continue_label() {
}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")]
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_continue_label() {
let mut _x = 0;

View File

@ -660,10 +660,7 @@ LL | #[derive(Diagnostic)]
= help: normalized in stderr
note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
--> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
|
LL | arg: impl IntoDiagnosticArg,
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 83 previous errors

View File

@ -17,9 +17,6 @@ LL | | }
= note: struct `core::alloc::Layout` and struct `Layout` have similar names, but are actually distinct types
note: struct `core::alloc::Layout` is defined in crate `core`
--> $SRC_DIR/core/src/alloc/layout.rs:LL:COL
|
LL | pub struct Layout {
| ^^^^^^^^^^^^^^^^^
note: struct `Layout` is defined in the current crate
--> $DIR/alloc-error-handler-bad-signature-2.rs:7:1
|

View File

@ -15,9 +15,6 @@ LL | fn get_iter(vec: &[i32]) -> impl Iterator<Item = {}> + '_ {
|
note: associated type defined here
--> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
|
LL | type Item;
| ^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -7,9 +7,6 @@ LL | type Ty = Vec<[u8]>;
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Vec`
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
|
LL | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
| ^ required by this bound in `Vec`
error: aborting due to previous error

View File

@ -6,9 +6,6 @@ LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self>
|
note: required by a bound in `Add`
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Add<Rhs = Self> {
| ^^^^^^^^^^ required by this bound in `Add`
help: consider further restricting `Self`
|
LL | trait ArithmeticOps: Add<Output=Self> + Sub<Output=Self> + Mul<Output=Self> + Div<Output=Self> + Sized {}

View File

@ -68,14 +68,10 @@ note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:33:28
|
LL | (Rc::new(()), bar().await);
| ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
| |
| ----------- ^^^^^^ - `Rc::new(())` is later dropped here
| | |
| | await occurs here, with `Rc::new(())` maybe used later
| has type `Rc<()>` which is not `Send`
note: `Rc::new(())` is later dropped here
--> $DIR/async-await-let-else.rs:33:35
|
LL | (Rc::new(()), bar().await);
| ^
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|

View File

@ -53,14 +53,10 @@ note: future is not `Send` as this value is used across an await
--> $DIR/async-await-let-else.rs:33:28
|
LL | (Rc::new(()), bar().await);
| ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
| |
| ----------- ^^^^^^ - `Rc::new(())` is later dropped here
| | |
| | await occurs here, with `Rc::new(())` maybe used later
| has type `Rc<()>` which is not `Send`
note: `Rc::new(())` is later dropped here
--> $DIR/async-await-let-else.rs:33:35
|
LL | (Rc::new(()), bar().await);
| ^
note: required by a bound in `is_send`
--> $DIR/async-await-let-else.rs:19:15
|

View File

@ -12,9 +12,6 @@ LL | fun(async {}, async {});
found `async` block `[async block@$DIR/generator-desc.rs:10:19: 10:27]`
note: function defined here
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
| ^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/generator-desc.rs:12:16

View File

@ -12,14 +12,10 @@ LL | baz(|| async{
| _____________-
LL | | foo(tx.clone());
LL | | }).await;
| | - ^^^^^^ await occurs here, with the value maybe used later
| |_________|
| | - ^^^^^^- the value is later dropped here
| | | |
| |_________| await occurs here, with the value maybe used later
| has type `[closure@$DIR/issue-70935-complex-spans.rs:17:13: 17:15]` which is not `Send`
note: the value is later dropped here
--> $DIR/issue-70935-complex-spans.rs:19:17
|
LL | }).await;
| ^
error: aborting due to previous error

View File

@ -8,9 +8,6 @@ LL | let mut f = File::open(path.to_str())?;
|
note: required by a bound in `File::open`
--> $SRC_DIR/std/src/fs.rs:LL:COL
|
LL | pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
| ^^^^^^^^^^^ required by this bound in `File::open`
error: aborting due to previous error

View File

@ -6,11 +6,6 @@ LL | async fn copy() -> Result<()>
| |
| expected 2 generic arguments
|
note: enum defined here, with 2 generic parameters: `T`, `E`
--> $SRC_DIR/core/src/result.rs:LL:COL
|
LL | pub enum Result<T, E> {
| ^^^^^^ - -
help: add missing generic argument
|
LL | async fn copy() -> Result<(), E>

View File

@ -13,14 +13,10 @@ note: future is not `Send` as this value is used across an await
--> $DIR/issue-65436-raw-ptr-not-send.rs:18:35
|
LL | bar(Foo(std::ptr::null())).await;
| ---------------- ^^^^^^ await occurs here, with `std::ptr::null()` maybe used later
| |
| ---------------- ^^^^^^- `std::ptr::null()` is later dropped here
| | |
| | await occurs here, with `std::ptr::null()` maybe used later
| has type `*const u8` which is not `Send`
note: `std::ptr::null()` is later dropped here
--> $DIR/issue-65436-raw-ptr-not-send.rs:18:41
|
LL | bar(Foo(std::ptr::null())).await;
| ^
help: consider moving this into a `let` binding to create a shorter lived borrow
--> $DIR/issue-65436-raw-ptr-not-send.rs:18:13
|

View File

@ -9,14 +9,10 @@ note: future is not `Send` as this value is used across an await
--> $DIR/auxiliary/issue_67893.rs:9:26
|
LL | f(*x.lock().unwrap()).await;
| ----------------- ^^^^^^ await occurs here, with `x.lock().unwrap()` maybe used later
| |
| ----------------- ^^^^^^- `x.lock().unwrap()` is later dropped here
| | |
| | await occurs here, with `x.lock().unwrap()` maybe used later
| has type `MutexGuard<'_, ()>` which is not `Send`
note: `x.lock().unwrap()` is later dropped here
--> $DIR/auxiliary/issue_67893.rs:9:32
|
LL | f(*x.lock().unwrap()).await;
| ^
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|

View File

@ -14,9 +14,6 @@ LL | struct Sleep(std::marker::PhantomPinned);
| ^^^^^
note: required by a bound in `Pin::<P>::new`
--> $SRC_DIR/core/src/pin.rs:LL:COL
|
LL | impl<P: Deref<Target: Unpin>> Pin<P> {
| ^^^^^ required by this bound in `Pin::<P>::new`
error: aborting due to previous error

View File

@ -6,11 +6,9 @@ LL | struct Sleep;
...
LL | self.sleep.poll(cx)
| ^^^^ method not found in `Sleep`
--> $SRC_DIR/core/src/future/future.rs:LL:COL
|
::: $SRC_DIR/core/src/future/future.rs:LL:COL
|
LL | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
| ---- the method is available for `Pin<&mut Sleep>` here
= note: the method is available for `Pin<&mut Sleep>` here
|
help: consider wrapping the receiver expression with the appropriate type
|

View File

@ -0,0 +1,9 @@
// edition:2021
#![feature(closure_track_caller, stmt_expr_attributes)]
fn main() {
let _ = #[track_caller] async {
//~^ ERROR attribute should be applied to a function definition [E0739]
};
}

View File

@ -0,0 +1,12 @@
error[E0739]: attribute should be applied to a function definition
--> $DIR/async-block.rs:6:13
|
LL | let _ = #[track_caller] async {
| _____________^^^^^^^^^^^^^^^_-
LL | |
LL | | };
| |_____- not a function definition
error: aborting due to previous error
For more information about this error, try `rustc --explain E0739`.

View File

@ -0,0 +1,10 @@
// edition:2021
#![feature(async_closure, stmt_expr_attributes)]
fn main() {
let _ = #[track_caller] async || {
//~^ ERROR `#[track_caller]` on closures is currently unstable [E0658]
//~| ERROR `#[track_caller]` on closures is currently unstable [E0658]
};
}

View File

@ -0,0 +1,25 @@
error[E0658]: `#[track_caller]` on closures is currently unstable
--> $DIR/async-closure-gate.rs:6:13
|
LL | let _ = #[track_caller] async || {
| ^^^^^^^^^^^^^^^
|
= note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
= help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
error[E0658]: `#[track_caller]` on closures is currently unstable
--> $DIR/async-closure-gate.rs:6:38
|
LL | let _ = #[track_caller] async || {
| ______________________________________^
LL | |
LL | |
LL | | };
| |_____^
|
= note: see issue #87417 <https://github.com/rust-lang/rust/issues/87417> for more information
= help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -1,7 +1,7 @@
// run-pass
// edition:2021
// needs-unwind
#![feature(closure_track_caller)]
#![feature(closure_track_caller, async_closure, stmt_expr_attributes)]
use std::future::Future;
use std::panic;
@ -67,6 +67,13 @@ async fn foo_assoc() {
Foo::bar_assoc().await
}
async fn foo_closure() {
let c = #[track_caller] async || {
panic!();
};
c().await
}
fn panicked_at(f: impl FnOnce() + panic::UnwindSafe) -> u32 {
let loc = Arc::new(Mutex::new(None));
@ -87,4 +94,5 @@ fn main() {
assert_eq!(panicked_at(|| block_on(foo())), 41);
assert_eq!(panicked_at(|| block_on(foo_track_caller())), 54);
assert_eq!(panicked_at(|| block_on(foo_assoc())), 67);
assert_eq!(panicked_at(|| block_on(foo_closure())), 74);
}

View File

@ -10,9 +10,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | fn add(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn add<A: Add<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -46,9 +43,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | fn sub(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn sub<A: Sub<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -82,9 +76,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | fn mul(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn mul<A: Mul<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -118,9 +109,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | fn div(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn div<A: Div<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -154,9 +142,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | fn rem(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn rem<A: Rem<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -190,9 +175,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | fn bitand(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn bitand<A: BitAnd<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -226,9 +208,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | fn bitor(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn bitor<A: BitOr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -262,9 +241,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | fn bitxor(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn bitxor<A: BitXor<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -298,9 +274,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | fn shl(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn shl<A: Shl<B, Output=()> + Copy, B>(lhs: A, rhs: B) {
@ -334,9 +307,6 @@ LL | drop(lhs);
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | fn shr(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn shr<A: Shr<B, Output=()> + Copy, B>(lhs: A, rhs: B) {

View File

@ -13,9 +13,6 @@ LL | | x;
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | fn add(self, rhs: Rhs) -> Self::Output;
| ^^^^
help: consider further restricting this bound
|
LL | fn double_move<T: Add<Output=()> + Copy>(x: T) {
@ -78,9 +75,6 @@ LL | | *n;
|
note: calling this operator moves the left-hand side
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | fn add(self, rhs: Rhs) -> Self::Output;
| ^^^^
error[E0507]: cannot move out of `*n` which is behind a shared reference
--> $DIR/binop-move-semantics.rs:32:5

View File

@ -11,11 +11,8 @@ note: an implementation of `Add<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `Add<_>`
note: the following trait must be implemented
note: the trait `Add` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Add<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot subtract `A` from `A`
--> $DIR/issue-28837.rs:8:7
@ -30,11 +27,8 @@ note: an implementation of `Sub<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `Sub<_>`
note: the following trait must be implemented
note: the trait `Sub` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Sub<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot multiply `A` by `A`
--> $DIR/issue-28837.rs:10:7
@ -49,11 +43,8 @@ note: an implementation of `Mul<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `Mul<_>`
note: the following trait must be implemented
note: the trait `Mul` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Mul<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot divide `A` by `A`
--> $DIR/issue-28837.rs:12:7
@ -68,11 +59,8 @@ note: an implementation of `Div<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `Div<_>`
note: the following trait must be implemented
note: the trait `Div` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Div<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: cannot mod `A` by `A`
--> $DIR/issue-28837.rs:14:7
@ -87,11 +75,8 @@ note: an implementation of `Rem<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `Rem<_>`
note: the following trait must be implemented
note: the trait `Rem` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Rem<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A & A`
--> $DIR/issue-28837.rs:16:7
@ -106,11 +91,8 @@ note: an implementation of `BitAnd<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `BitAnd<_>`
note: the following trait must be implemented
note: the trait `BitAnd` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | pub trait BitAnd<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A | A`
--> $DIR/issue-28837.rs:18:7
@ -125,11 +107,8 @@ note: an implementation of `BitOr<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `BitOr<_>`
note: the following trait must be implemented
note: the trait `BitOr` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | pub trait BitOr<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A << A`
--> $DIR/issue-28837.rs:20:7
@ -144,11 +123,8 @@ note: an implementation of `Shl<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `Shl<_>`
note: the following trait must be implemented
note: the trait `Shl` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | pub trait Shl<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: no implementation for `A >> A`
--> $DIR/issue-28837.rs:22:7
@ -163,11 +139,8 @@ note: an implementation of `Shr<_>` might be missing for `A`
|
LL | struct A;
| ^^^^^^^^ must implement `Shr<_>`
note: the following trait must be implemented
note: the trait `Shr` must be implemented
--> $SRC_DIR/core/src/ops/bit.rs:LL:COL
|
LL | pub trait Shr<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0369]: binary operation `==` cannot be applied to type `A`
--> $DIR/issue-28837.rs:24:7

View File

@ -11,11 +11,8 @@ note: an implementation of `Mul<_>` might be missing for `Thing`
|
LL | struct Thing {
| ^^^^^^^^^^^^ must implement `Mul<_>`
note: the following trait must be implemented
note: the trait `Mul` must be implemented
--> $SRC_DIR/core/src/ops/arith.rs:LL:COL
|
LL | pub trait Mul<Rhs = Self> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -3,10 +3,15 @@ error[E0507]: cannot move out of `s` which is behind a shared reference
|
LL | match *s { S(v) => v }
| ^^ -
| | |
| | data moved here
| | move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*s`
| |
| data moved here
| move occurs because `v` has type `Vec<isize>`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - match *s { S(v) => v }
LL + match s { S(v) => v }
|
error: aborting due to previous error

View File

@ -2,31 +2,46 @@ error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:12:15
|
LL | for &a in x.iter() {
| -- ^^^^^^^^
| ||
| |data moved here
| |move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
| help: consider removing the `&`: `a`
| - ^^^^^^^^
| |
| data moved here
| move occurs because `a` has type `&mut i32`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - for &a in x.iter() {
LL + for a in x.iter() {
|
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:18:15
|
LL | for &a in &f.a {
| -- ^^^^
| ||
| |data moved here
| |move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait
| help: consider removing the `&`: `a`
| - ^^^^
| |
| data moved here
| move occurs because `a` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - for &a in &f.a {
LL + for a in &f.a {
|
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-for-loop-correct-cmt-for-pattern.rs:22:15
|
LL | for &a in x.iter() {
| -- ^^^^^^^^
| ||
| |data moved here
| |move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait
| help: consider removing the `&`: `a`
| - ^^^^^^^^
| |
| data moved here
| move occurs because `a` has type `Box<i32>`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - for &a in x.iter() {
LL + for a in x.iter() {
|
error: aborting due to 3 previous errors

View File

@ -0,0 +1,12 @@
// run-rustfix
fn main() {
let x: Option<Box<_>> = Some(Box::new(1));
match x {
Some(ref y) => {
let _b = y; //~ ERROR cannot move out
}
_ => {}
}
}

View File

@ -1,3 +1,4 @@
// run-rustfix
fn main() {
let x: Option<Box<_>> = Some(Box::new(1));

View File

@ -1,11 +1,14 @@
error[E0507]: cannot move out of `*y` which is behind a shared reference
--> $DIR/borrowck-issue-2657-2.rs:7:18
--> $DIR/borrowck-issue-2657-2.rs:8:18
|
LL | let _b = *y;
| ^^
| |
| move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*y`
| ^^ move occurs because `*y` has type `Box<i32>`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let _b = *y;
LL + let _b = y;
|
error: aborting due to previous error

View File

@ -0,0 +1,56 @@
// run-rustfix
#![allow(unused)]
enum Foo {
Foo1(Box<u32>, Box<u32>),
Foo2(Box<u32>),
Foo3,
}
fn blah() {
let f = &Foo::Foo1(Box::new(1), Box::new(2));
match f { //~ ERROR cannot move out of
Foo::Foo1(num1,
num2) => (),
Foo::Foo2(num) => (),
Foo::Foo3 => ()
}
}
struct S {
f: String,
g: String
}
impl Drop for S {
fn drop(&mut self) { println!("{}", self.f); }
}
fn move_in_match() {
match (S {f: "foo".to_string(), g: "bar".to_string()}) {
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
S {
f: ref _s,
g: ref _t
} => {}
}
}
// from issue-8064
struct A {
a: Box<isize>,
}
fn free<T>(_: T) {}
fn blah2() {
let a = &A { a: Box::new(1) };
match &a.a { //~ ERROR cannot move out of
n => {
free(n)
}
}
free(a)
}
fn main() {}

View File

@ -1,3 +1,5 @@
// run-rustfix
#![allow(unused)]
enum Foo {
Foo1(Box<u32>, Box<u32>),
Foo2(Box<u32>),

View File

@ -1,8 +1,8 @@
error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
--> $DIR/borrowck-move-error-with-note.rs:11:11
--> $DIR/borrowck-move-error-with-note.rs:13:11
|
LL | match *f {
| ^^ help: consider borrowing here: `&*f`
| ^^
LL | Foo::Foo1(num1,
| ---- data moved here
LL | num2) => (),
@ -11,9 +11,14 @@ LL | Foo::Foo2(num) => (),
| --- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
help: consider removing the dereference here
|
LL - match *f {
LL + match f {
|
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-move-error-with-note.rs:28:11
--> $DIR/borrowck-move-error-with-note.rs:30:11
|
LL | match (S {f: "foo".to_string(), g: "bar".to_string()}) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
@ -24,17 +29,30 @@ LL | g: _t
| -- ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
help: consider borrowing the pattern binding
|
LL | f: ref _s,
| +++
help: consider borrowing the pattern binding
|
LL | g: ref _t
| +++
error[E0507]: cannot move out of `a.a` which is behind a shared reference
--> $DIR/borrowck-move-error-with-note.rs:46:11
--> $DIR/borrowck-move-error-with-note.rs:48:11
|
LL | match a.a {
| ^^^ help: consider borrowing here: `&a.a`
| ^^^
LL | n => {
| -
| |
| data moved here
| move occurs because `n` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | match &a.a {
| +
error: aborting due to 3 previous errors

View File

@ -2,10 +2,13 @@ error[E0507]: cannot move out of `*x` which is behind a raw pointer
--> $DIR/borrowck-move-from-unsafe-ptr.rs:2:13
|
LL | let y = *x;
| ^^
| |
| move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*x`
| ^^ move occurs because `*x` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let y = *x;
LL + let y = x;
|
error: aborting due to previous error

View File

@ -3,30 +3,45 @@ error[E0507]: cannot move out of a shared reference
|
LL | fn arg_item(&_x: &String) {}
| ^--
| ||
| |data moved here
| |move occurs because `_x` has type `String`, which does not implement the `Copy` trait
| help: consider removing the `&`: `_x`
| |
| data moved here
| move occurs because `_x` has type `String`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - fn arg_item(&_x: &String) {}
LL + fn arg_item(_x: &String) {}
|
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-move-in-irrefut-pat.rs:7:11
|
LL | with(|&_x| ())
| ^--
| ||
| |data moved here
| |move occurs because `_x` has type `String`, which does not implement the `Copy` trait
| help: consider removing the `&`: `_x`
| |
| data moved here
| move occurs because `_x` has type `String`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - with(|&_x| ())
LL + with(|_x| ())
|
error[E0507]: cannot move out of a shared reference
--> $DIR/borrowck-move-in-irrefut-pat.rs:12:15
|
LL | let &_x = &"hi".to_string();
| --- ^^^^^^^^^^^^^^^^^
| ||
| |data moved here
| |move occurs because `_x` has type `String`, which does not implement the `Copy` trait
| help: consider removing the `&`: `_x`
| -- ^^^^^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `_x` has type `String`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - let &_x = &"hi".to_string();
LL + let _x = &"hi".to_string();
|
error: aborting due to 3 previous errors

View File

@ -7,11 +7,8 @@ LL | let _x = Rc::new(vec![1, 2]).into_iter();
| | value moved due to this method call
| move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves value
note: `into_iter` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to previous error

View File

@ -2,10 +2,13 @@ error[E0507]: cannot move out of an `Rc`
--> $DIR/borrowck-move-out-of-overloaded-deref.rs:4:14
|
LL | let _x = *Rc::new("hi".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| move occurs because value has type `String`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*Rc::new("hi".to_string())`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let _x = *Rc::new("hi".to_string());
LL + let _x = Rc::new("hi".to_string());
|
error: aborting due to previous error

View File

@ -0,0 +1,24 @@
// run-rustfix
#![allow(unused)]
struct S {f:String}
impl Drop for S {
fn drop(&mut self) { println!("{}", self.f); }
}
fn move_in_match() {
match (S {f:"foo".to_string()}) {
//~^ ERROR [E0509]
S {f:ref _s} => {}
}
}
fn move_in_let() {
let S {f:ref _s} = S {f:"foo".to_string()};
//~^ ERROR [E0509]
}
fn move_in_fn_arg(S {f:ref _s}: S) {
//~^ ERROR [E0509]
}
fn main() {}

View File

@ -1,3 +1,5 @@
// run-rustfix
#![allow(unused)]
struct S {f:String}
impl Drop for S {
fn drop(&mut self) { println!("{}", self.f); }

View File

@ -1,5 +1,5 @@
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:7:11
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:9:11
|
LL | match (S {f:"foo".to_string()}) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
@ -9,18 +9,28 @@ LL | S {f:_s} => {}
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | S {f:ref _s} => {}
| +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:14:20
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:16:20
|
LL | let S {f:_s} = S {f:"foo".to_string()};
| -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | let S {f:ref _s} = S {f:"foo".to_string()};
| +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:19
--> $DIR/borrowck-move-out-of-struct-with-dtor.rs:20:19
|
LL | fn move_in_fn_arg(S {f:_s}: S) {
| ^^^^^--^
@ -28,6 +38,11 @@ LL | fn move_in_fn_arg(S {f:_s}: S) {
| | data moved here
| | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
| cannot move out of here
|
help: consider borrowing the pattern binding
|
LL | fn move_in_fn_arg(S {f:ref _s}: S) {
| +++
error: aborting due to 3 previous errors

View File

@ -0,0 +1,24 @@
// run-rustfix
#![allow(unused)]
struct S(String);
impl Drop for S {
fn drop(&mut self) { }
}
fn move_in_match() {
match S("foo".to_string()) {
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
S(ref _s) => {}
}
}
fn move_in_let() {
let S(ref _s) = S("foo".to_string());
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
}
fn move_in_fn_arg(S(ref _s): S) {
//~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
}
fn main() {}

View File

@ -1,3 +1,5 @@
// run-rustfix
#![allow(unused)]
struct S(String);
impl Drop for S {
fn drop(&mut self) { }

View File

@ -1,5 +1,5 @@
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:7:11
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:9:11
|
LL | match S("foo".to_string()) {
| ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
@ -9,18 +9,28 @@ LL | S(_s) => {}
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | S(ref _s) => {}
| +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:17
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:16:17
|
LL | let S(_s) = S("foo".to_string());
| -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here
| |
| data moved here
| move occurs because `_s` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | let S(ref _s) = S("foo".to_string());
| +++
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:19
--> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:20:19
|
LL | fn move_in_fn_arg(S(_s): S) {
| ^^--^
@ -28,6 +38,11 @@ LL | fn move_in_fn_arg(S(_s): S) {
| | data moved here
| | move occurs because `_s` has type `String`, which does not implement the `Copy` trait
| cannot move out of here
|
help: consider borrowing the pattern binding
|
LL | fn move_in_fn_arg(S(ref _s): S) {
| +++
error: aborting due to 3 previous errors

View File

@ -10,10 +10,10 @@ LL | Foo { string: b }] => {
| - ...and here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
help: consider removing the `&`
help: consider removing the borrow
|
LL ~ [Foo { string: a },
LL ~ Foo { string: b }] => {
LL - &[Foo { string: a },
LL + [Foo { string: a },
|
error: aborting due to previous error

View File

@ -2,10 +2,12 @@ error[E0507]: cannot move out of index of `MyVec<Box<i32>>`
--> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15
|
LL | let bad = v[0];
| ^^^^
| |
| move occurs because value has type `Box<i32>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&v[0]`
| ^^^^ move occurs because value has type `Box<i32>`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | let bad = &v[0];
| +
error: aborting due to previous error

View File

@ -37,7 +37,7 @@ fn c() {
&mut [_a,
//~^ NOTE data moved here
//~| NOTE move occurs because `_a` has type
//~| HELP consider removing the `&mut`
//~| HELP consider removing the mutable borrow
..
] => {
}
@ -56,7 +56,7 @@ fn d() {
//~^ ERROR cannot move out
//~| NOTE cannot move out
&mut [
//~^ HELP consider removing the `&mut`
//~^ HELP consider removing the mutable borrow
_b] => {}
//~^ NOTE data moved here
//~| NOTE move occurs because `_b` has type
@ -79,7 +79,7 @@ fn e() {
//~^ NOTE data moved here
//~| NOTE and here
//~| NOTE and here
//~| HELP consider removing the `&mut`
//~| HELP consider removing the mutable borrow
_ => {}
}
let a = vec[0]; //~ ERROR cannot move out

View File

@ -34,14 +34,10 @@ LL | &mut [_a,
| data moved here
| move occurs because `_a` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider removing the `&mut`
help: consider removing the mutable borrow
|
LL ~ [_a,
LL +
LL +
LL +
LL + ..
LL ~ ] => {
LL - &mut [_a,
LL + [_a,
|
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
@ -52,7 +48,11 @@ LL | let a = vec[0];
| |
| cannot move out of here
| move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&vec[0]`
|
help: consider borrowing here
|
LL | let a = &vec[0];
| +
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:55:11
@ -66,11 +66,10 @@ LL | _b] => {}
| data moved here
| move occurs because `_b` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider removing the `&mut`
help: consider removing the mutable borrow
|
LL ~ [
LL +
LL ~ _b] => {}
LL - &mut [
LL + [
|
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
@ -81,7 +80,11 @@ LL | let a = vec[0];
| |
| cannot move out of here
| move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&vec[0]`
|
help: consider borrowing here
|
LL | let a = &vec[0];
| +
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:74:11
@ -90,14 +93,17 @@ LL | match vec {
| ^^^ cannot move out of here
...
LL | &mut [_a, _b, _c] => {}
| -----------------
| | | | |
| | | | ...and here
| | | ...and here
| | data moved here
| help: consider removing the `&mut`: `[_a, _b, _c]`
| -- -- -- ...and here
| | |
| | ...and here
| data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
help: consider removing the mutable borrow
|
LL - &mut [_a, _b, _c] => {}
LL + [_a, _b, _c] => {}
|
error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
--> $DIR/borrowck-vec-pattern-nesting.rs:85:13
@ -107,7 +113,11 @@ LL | let a = vec[0];
| |
| cannot move out of here
| move occurs because `vec[_]` has type `Box<isize>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&vec[0]`
|
help: consider borrowing here
|
LL | let a = &vec[0];
| +
error: aborting due to 8 previous errors

View File

@ -2,10 +2,12 @@ error[E0507]: cannot move out of static item `FOO`
--> $DIR/issue-17718-static-move.rs:6:14
|
LL | let _a = FOO;
| ^^^
| |
| move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
| help: consider borrowing here: `&FOO`
| ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | let _a = &FOO;
| +
error: aborting due to previous error

View File

@ -2,37 +2,49 @@ error[E0507]: cannot move out of a mutable reference
--> $DIR/issue-20801.rs:26:22
|
LL | let a = unsafe { *mut_ref() };
| ^^^^^^^^^^
| |
| move occurs because value has type `T`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*mut_ref()`
| ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let a = unsafe { *mut_ref() };
LL + let a = unsafe { mut_ref() };
|
error[E0507]: cannot move out of a shared reference
--> $DIR/issue-20801.rs:29:22
|
LL | let b = unsafe { *imm_ref() };
| ^^^^^^^^^^
| |
| move occurs because value has type `T`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*imm_ref()`
| ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let b = unsafe { *imm_ref() };
LL + let b = unsafe { imm_ref() };
|
error[E0507]: cannot move out of a raw pointer
--> $DIR/issue-20801.rs:32:22
|
LL | let c = unsafe { *mut_ptr() };
| ^^^^^^^^^^
| |
| move occurs because value has type `T`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*mut_ptr()`
| ^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let c = unsafe { *mut_ptr() };
LL + let c = unsafe { mut_ptr() };
|
error[E0507]: cannot move out of a raw pointer
--> $DIR/issue-20801.rs:35:22
|
LL | let d = unsafe { *const_ptr() };
| ^^^^^^^^^^^^
| |
| move occurs because value has type `T`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*const_ptr()`
| ^^^^^^^^^^^^ move occurs because value has type `T`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - let d = unsafe { *const_ptr() };
LL + let d = unsafe { const_ptr() };
|
error: aborting due to 4 previous errors

View File

@ -2,10 +2,12 @@ error[E0507]: cannot move out of static item `X`
--> $DIR/issue-47215-ice-from-drop-elab.rs:17:21
|
LL | let mut x = X;
| ^
| |
| move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait
| help: consider borrowing here: `&X`
| ^ move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | let mut x = &X;
| +
error: aborting due to previous error

View File

@ -6,6 +6,11 @@ LL | .find(|(&event_type, _)| event == event_type)
| |
| data moved here
| move occurs because `event_type` has type `EventType`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | .find(|(&ref event_type, _)| event == event_type)
| +++
error: aborting due to previous error

View File

@ -0,0 +1,12 @@
// run-rustfix
// Regression test for #51415: match default bindings were failing to
// see the "move out" implied by `&s` below.
fn main() {
let a = vec![String::from("a")];
let opt = a.iter().enumerate().find(|(_, &ref s)| {
//~^ ERROR cannot move out
*s == String::from("d")
}).map(|(i, _)| i);
println!("{:?}", opt);
}

View File

@ -1,3 +1,4 @@
// run-rustfix
// Regression test for #51415: match default bindings were failing to
// see the "move out" implied by `&s` below.

View File

@ -1,11 +1,16 @@
error[E0507]: cannot move out of a shared reference
--> $DIR/issue-51415.rs:6:42
--> $DIR/issue-51415.rs:7:42
|
LL | let opt = a.iter().enumerate().find(|(_, &s)| {
| ^^^^^-^
| |
| data moved here
| move occurs because `s` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | let opt = a.iter().enumerate().find(|(_, &ref s)| {
| +++
error: aborting due to previous error

View File

@ -2,10 +2,13 @@ error[E0507]: cannot move out of `*array` which is behind a shared reference
--> $DIR/issue-54597-reject-move-out-of-borrow-via-pat.rs:14:13
|
LL | *array
| ^^^^^^
| |
| move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&*array`
| ^^^^^^ move occurs because `*array` has type `Vec<Value>`, which does not implement the `Copy` trait
|
help: consider removing the dereference here
|
LL - *array
LL + array
|
error: aborting due to previous error

View File

@ -27,11 +27,8 @@ LL | foo = Some(Struct);
LL | let _y = foo;
| ^^^ value used here after move
|
note: this function takes ownership of the receiver `self`, which moves `foo`
note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | pub const fn unwrap(self) -> T {
| ^^^^
error[E0382]: use of moved value: `foo`
--> $DIR/issue-83760.rs:37:14
@ -55,11 +52,8 @@ LL | foo = Some(Struct);
LL | } else if true {
LL | foo = Some(Struct);
| ^^^^^^^^^^^^^^^^^^
note: this function takes ownership of the receiver `self`, which moves `foo`
note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | pub const fn unwrap(self) -> T {
| ^^^^
error: aborting due to 3 previous errors

View File

@ -8,10 +8,12 @@ LL | take_mut(|| {
| -- captured by this `FnMut` closure
LL |
LL | let _foo: String = val;
| ^^^
| |
| move occurs because `val` has type `String`, which does not implement the `Copy` trait
| help: consider borrowing here: `&val`
| ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | let _foo: String = &val;
| +
error: aborting due to previous error

View File

@ -2,10 +2,7 @@ error[E0507]: cannot move out of static item `D`
--> $DIR/move-error-snippets-ext.rs:5:17
|
LL | let a = $c;
| ^^
| |
| move occurs because `D` has type `A`, which does not implement the `Copy` trait
| help: consider borrowing here: `&$c`
| ^^ move occurs because `D` has type `A`, which does not implement the `Copy` trait
|
::: $DIR/move-error-snippets.rs:21:1
|
@ -13,6 +10,10 @@ LL | sss!();
| ------ in this macro invocation
|
= note: this error originates in the macro `aaa` which comes from the expansion of the macro `sss` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider borrowing here
|
LL | let a = &$c;
| +
error: aborting due to previous error

View File

@ -9,11 +9,8 @@ LL |
LL | fill_segment(state);
| ^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `state`
note: `into_iter` takes ownership of the receiver `self`, which moves `state`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
help: consider creating a fresh reborrow of `state` here
|
LL | for _ in &mut *state {}

View File

@ -8,11 +8,8 @@ LL | cb.map(|cb| cb());
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because `*cb` has type `Option<&mut dyn FnMut()>`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves `*cb`
note: `Option::<T>::map` takes ownership of the receiver `self`, which moves `*cb`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | pub const fn map<U, F>(self, f: F) -> Option<U>
| ^^^^
error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference
--> $DIR/suggest-as-ref-on-mut-closure.rs:12:26

View File

@ -10,11 +10,8 @@ LL | y.into_iter();
| |
| move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves `y`
note: `into_iter` takes ownership of the receiver `self`, which moves `y`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | fn into_iter(self) -> Self::IntoIter;
| ^^^^
error: aborting due to previous error

View File

@ -9,9 +9,6 @@ LL | let _ = Box::into_boxed_slice(boxed_slice);
= help: the trait `Sized` is not implemented for `[u8]`
note: required by a bound in `Box::<T, A>::into_boxed_slice`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
LL | impl<T, A: Allocator> Box<T, A> {
| ^ required by this bound in `Box::<T, A>::into_boxed_slice`
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/into-boxed-slice-fail.rs:7:13
@ -33,9 +30,6 @@ LL | let _ = Box::into_boxed_slice(boxed_trait);
= help: the trait `Sized` is not implemented for `dyn Debug`
note: required by a bound in `Box::<T, A>::into_boxed_slice`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
|
LL | impl<T, A: Allocator> Box<T, A> {
| ^ required by this bound in `Box::<T, A>::into_boxed_slice`
error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time
--> $DIR/into-boxed-slice-fail.rs:11:13

View File

@ -19,4 +19,11 @@ fn main() {
&E::Foo => {}
&E::Bar(ref identifier) => println!("{}", *identifier)
};
if let &E::Bar(identifier) = &s.x { //~ ERROR cannot move
f(identifier.clone());
};
let &E::Bar(identifier) = &s.x else { //~ ERROR cannot move
return;
};
f(identifier.clone());
}

View File

@ -5,12 +5,47 @@ LL | match &s.x {
| ^^^^
LL | &E::Foo => {}
LL | &E::Bar(identifier) => f(identifier.clone())
| -------------------
| | |
| | data moved here
| | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
| help: consider removing the `&`: `E::Bar(identifier)`
| ----------
| |
| data moved here
| move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - &E::Bar(identifier) => f(identifier.clone())
LL + E::Bar(identifier) => f(identifier.clone())
|
error: aborting due to previous error
error[E0507]: cannot move out of a shared reference
--> $DIR/by-move-pattern-binding.rs:22:34
|
LL | if let &E::Bar(identifier) = &s.x {
| ---------- ^^^^
| |
| data moved here
| move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - if let &E::Bar(identifier) = &s.x {
LL + if let E::Bar(identifier) = &s.x {
|
error[E0507]: cannot move out of a shared reference
--> $DIR/by-move-pattern-binding.rs:25:31
|
LL | let &E::Bar(identifier) = &s.x else {
| ---------- ^^^^
| |
| data moved here
| move occurs because `identifier` has type `String`, which does not implement the `Copy` trait
|
help: consider removing the borrow
|
LL - let &E::Bar(identifier) = &s.x else {
LL + let E::Bar(identifier) = &s.x else {
|
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0507`.

View File

@ -63,11 +63,9 @@ error[E0412]: cannot find type `F` in this scope
|
LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) {
| ^
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
| -------------------------------------- similarly named trait `Fn` defined here
= note: similarly named trait `Fn` defined here
|
help: a trait with a similar name exists
|

View File

@ -14,9 +14,6 @@ LL | | }
= note: [async fn body@$DIR/async.rs:7:29: 9:2] must be a future or must implement `IntoFuture` to be awaited
note: required by a bound in `identity_future`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
| ^^^^^^^^^^^^^^^^^^ required by this bound in `identity_future`
error[E0277]: the size for values of type `<[async fn body@$DIR/async.rs:7:29: 9:2] as Future>::Output` cannot be known at compilation time
--> $DIR/async.rs:7:29
@ -30,9 +27,6 @@ LL | | }
= help: the trait `Sized` is not implemented for `<[async fn body@$DIR/async.rs:7:29: 9:2] as Future>::Output`
note: required by a bound in `identity_future`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
| ^ required by this bound in `identity_future`
error[E0277]: `[async fn body@$DIR/async.rs:7:29: 9:2]` is not a future
--> $DIR/async.rs:7:25

View File

@ -58,10 +58,12 @@ error[E0507]: cannot move out of static item `x`
--> $DIR/check-static-values-constraints.rs:110:45
|
LL | let y = { static x: Box<isize> = box 3; x };
| ^
| |
| move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
| help: consider borrowing here: `&x`
| ^ move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | let y = { static x: Box<isize> = box 3; &x };
| +
error[E0010]: allocations are not allowed in statics
--> $DIR/check-static-values-constraints.rs:110:38

View File

@ -10,9 +10,6 @@ LL | let y = x.or_else(4);
= note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
note: required by a bound in `Option::<T>::or_else`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | F: ~const FnOnce() -> Option<T>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::or_else`
error: aborting due to previous error

View File

@ -19,9 +19,6 @@ LL | let t = thread::spawn(|| {
| ^^
note: required by a bound in `spawn`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
|
LL | F: Send + 'static,
| ^^^^ required by this bound in `spawn`
error[E0277]: `Sender<()>` cannot be shared between threads safely
--> $DIR/closure-move-sync.rs:18:19
@ -40,9 +37,6 @@ LL | thread::spawn(|| tx.send(()).unwrap());
| ^^
note: required by a bound in `spawn`
--> $SRC_DIR/std/src/thread/mod.rs:LL:COL
|
LL | F: Send + 'static,
| ^^^^ required by this bound in `spawn`
error: aborting due to 2 previous errors

View File

@ -10,9 +10,6 @@ LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | F: ~const FnOnce(T) -> U,
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Option::<T>::map`
error: aborting due to previous error

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