mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
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:
commit
21ee03e062
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
688
compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Normal file
688
compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Normal 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 };
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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 }
|
||||
})
|
||||
}
|
||||
|
@ -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)`
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>;
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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() })
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
||||
|
9
src/test/ui/async-await/track-caller/async-block.rs
Normal file
9
src/test/ui/async-await/track-caller/async-block.rs
Normal 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]
|
||||
};
|
||||
}
|
12
src/test/ui/async-await/track-caller/async-block.stderr
Normal file
12
src/test/ui/async-await/track-caller/async-block.stderr
Normal 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`.
|
10
src/test/ui/async-await/track-caller/async-closure-gate.rs
Normal file
10
src/test/ui/async-await/track-caller/async-closure-gate.rs
Normal 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]
|
||||
};
|
||||
}
|
@ -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`.
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
12
src/test/ui/borrowck/borrowck-issue-2657-2.fixed
Normal file
12
src/test/ui/borrowck/borrowck-issue-2657-2.fixed
Normal 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
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// run-rustfix
|
||||
fn main() {
|
||||
|
||||
let x: Option<Box<_>> = Some(Box::new(1));
|
||||
|
@ -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
|
||||
|
||||
|
56
src/test/ui/borrowck/borrowck-move-error-with-note.fixed
Normal file
56
src/test/ui/borrowck/borrowck-move-error-with-note.fixed
Normal 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() {}
|
@ -1,3 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(unused)]
|
||||
enum Foo {
|
||||
Foo1(Box<u32>, Box<u32>),
|
||||
Foo2(Box<u32>),
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
@ -1,3 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(unused)]
|
||||
struct S {f:String}
|
||||
impl Drop for S {
|
||||
fn drop(&mut self) { println!("{}", self.f); }
|
||||
|
@ -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
|
||||
|
||||
|
@ -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() {}
|
@ -1,3 +1,5 @@
|
||||
// run-rustfix
|
||||
#![allow(unused)]
|
||||
struct S(String);
|
||||
impl Drop for S {
|
||||
fn drop(&mut self) { }
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
12
src/test/ui/borrowck/issue-51415.fixed
Normal file
12
src/test/ui/borrowck/issue-51415.fixed
Normal 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);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// run-rustfix
|
||||
// Regression test for #51415: match default bindings were failing to
|
||||
// see the "move out" implied by `&s` below.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user