Merge from rustc
This commit is contained in:
commit
9fe4539fa7
135 changed files with 1183 additions and 1175 deletions
|
|
@ -4978,15 +4978,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.15"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
|
||||
checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"winapi",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -69,14 +69,14 @@ pub enum FnKind<'a> {
|
|||
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, &'a Generics, Option<&'a Block>),
|
||||
|
||||
/// E.g., `|x, y| body`.
|
||||
Closure(&'a ClosureBinder, &'a FnDecl, &'a Expr),
|
||||
Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
|
||||
}
|
||||
|
||||
impl<'a> FnKind<'a> {
|
||||
pub fn header(&self) -> Option<&'a FnHeader> {
|
||||
match *self {
|
||||
FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
|
||||
FnKind::Closure(_, _, _) => None,
|
||||
FnKind::Closure(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ impl<'a> FnKind<'a> {
|
|||
pub fn decl(&self) -> &'a FnDecl {
|
||||
match self {
|
||||
FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
|
||||
FnKind::Closure(_, decl, _) => decl,
|
||||
FnKind::Closure(_, _, decl, _) => decl,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -839,7 +839,7 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu
|
|||
try_visit!(walk_fn_decl(visitor, decl));
|
||||
visit_opt!(visitor, visit_block, body);
|
||||
}
|
||||
FnKind::Closure(binder, decl, body) => {
|
||||
FnKind::Closure(binder, _coroutine_kind, decl, body) => {
|
||||
try_visit!(visitor.visit_closure_binder(binder));
|
||||
try_visit!(walk_fn_decl(visitor, decl));
|
||||
try_visit!(visitor.visit_expr(body));
|
||||
|
|
@ -1107,7 +1107,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
ExprKind::Closure(box Closure {
|
||||
binder,
|
||||
capture_clause,
|
||||
coroutine_kind: _,
|
||||
coroutine_kind,
|
||||
constness: _,
|
||||
movability: _,
|
||||
fn_decl,
|
||||
|
|
@ -1116,7 +1116,11 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V
|
|||
fn_arg_span: _,
|
||||
}) => {
|
||||
try_visit!(visitor.visit_capture_by(capture_clause));
|
||||
try_visit!(visitor.visit_fn(FnKind::Closure(binder, fn_decl, body), *span, *id))
|
||||
try_visit!(visitor.visit_fn(
|
||||
FnKind::Closure(binder, coroutine_kind, fn_decl, body),
|
||||
*span,
|
||||
*id
|
||||
))
|
||||
}
|
||||
ExprKind::Block(block, opt_label) => {
|
||||
visit_opt!(visitor, visit_label, opt_label);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ use std::collections::hash_map::Entry;
|
|||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
|
|
@ -837,7 +836,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided(kind))
|
||||
}
|
||||
LifetimeRes::Static | LifetimeRes::Error => return None,
|
||||
LifetimeRes::Static { .. } | LifetimeRes::Error => return None,
|
||||
res => panic!(
|
||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||
res, ident, ident.span
|
||||
|
|
@ -1399,24 +1398,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnApit { span });
|
||||
}
|
||||
|
||||
let span = t.span;
|
||||
|
||||
// HACK: pprust breaks strings with newlines when the type
|
||||
// gets too long. We don't want these to show up in compiler
|
||||
// output or built artifacts, so replace them here...
|
||||
// Perhaps we should instead format APITs more robustly.
|
||||
let ident = Ident::from_str_and_span(
|
||||
&pprust::ty_to_string(t).replace('\n', " "),
|
||||
span,
|
||||
);
|
||||
|
||||
self.create_def(
|
||||
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
|
||||
*def_node_id,
|
||||
ident.name,
|
||||
DefKind::TyParam,
|
||||
span,
|
||||
);
|
||||
let def_id = self.local_def_id(*def_node_id);
|
||||
let name = self.tcx.item_name(def_id.to_def_id());
|
||||
let ident = Ident::new(name, span);
|
||||
let (param, bounds, path) = self.lower_universal_param_and_bounds(
|
||||
*def_node_id,
|
||||
span,
|
||||
|
|
@ -1618,13 +1602,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
opaque_ty_span: Span,
|
||||
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
|
||||
) -> hir::TyKind<'hir> {
|
||||
let opaque_ty_def_id = self.create_def(
|
||||
self.current_hir_id_owner.def_id, // FIXME: should this use self.current_def_id_parent?
|
||||
opaque_ty_node_id,
|
||||
kw::Empty,
|
||||
DefKind::OpaqueTy,
|
||||
opaque_ty_span,
|
||||
);
|
||||
let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
|
||||
debug!(?opaque_ty_def_id);
|
||||
|
||||
// Map from captured (old) lifetime to synthetic (new) lifetime.
|
||||
|
|
@ -1656,7 +1634,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
// Opaques do not capture `'static`
|
||||
LifetimeRes::Static | LifetimeRes::Error => {
|
||||
LifetimeRes::Static { .. } | LifetimeRes::Error => {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -2069,7 +2047,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::LifetimeName::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => hir::LifetimeName::Infer,
|
||||
LifetimeRes::Static => hir::LifetimeName::Static,
|
||||
LifetimeRes::Static { .. } => hir::LifetimeName::Static,
|
||||
LifetimeRes::Error => hir::LifetimeName::Error,
|
||||
res => panic!(
|
||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl<'ast> LifetimeCollectVisitor<'ast> {
|
|||
self.collected_lifetimes.insert(lifetime);
|
||||
}
|
||||
}
|
||||
LifetimeRes::Static | LifetimeRes::Error => {
|
||||
LifetimeRes::Static { .. } | LifetimeRes::Error => {
|
||||
self.collected_lifetimes.insert(lifetime);
|
||||
}
|
||||
LifetimeRes::Infer => {}
|
||||
|
|
|
|||
|
|
@ -1485,7 +1485,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
|
||||
let disallowed = (!tilde_const_allowed).then(|| match fk {
|
||||
FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
|
||||
FnKind::Closure(_, _, _) => TildeConstReason::Closure,
|
||||
FnKind::Closure(..) => TildeConstReason::Closure,
|
||||
});
|
||||
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
|
||||
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{struct_span_code_err, DiagMessage, SubdiagMessage};
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -9,7 +8,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
|
|||
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
|
||||
use rustc_hir::{lang_items, LangItem};
|
||||
use rustc_middle::middle::codegen_fn_attrs::{
|
||||
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, TargetFeature,
|
||||
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
|
||||
};
|
||||
use rustc_middle::mir::mono::Linkage;
|
||||
use rustc_middle::query::Providers;
|
||||
|
|
@ -18,7 +17,6 @@ use rustc_session::lint;
|
|||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Span};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_target::spec::{abi, SanitizerSet};
|
||||
|
||||
use crate::errors;
|
||||
|
|
@ -80,13 +78,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
let mut link_ordinal_span = None;
|
||||
let mut no_sanitize_span = None;
|
||||
|
||||
let fn_sig_outer = || {
|
||||
use DefKind::*;
|
||||
|
||||
let def_kind = tcx.def_kind(did);
|
||||
if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { None }
|
||||
};
|
||||
|
||||
for attr in attrs.iter() {
|
||||
// In some cases, attribute are only valid on functions, but it's the `check_attr`
|
||||
// pass that check that they aren't used anywhere else, rather this module.
|
||||
|
|
@ -94,12 +85,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
|
||||
// report a delayed bug, just in case `check_attr` isn't doing its job.
|
||||
let fn_sig = || {
|
||||
let sig = fn_sig_outer();
|
||||
if sig.is_none() {
|
||||
use DefKind::*;
|
||||
|
||||
let def_kind = tcx.def_kind(did);
|
||||
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
|
||||
Some(tcx.fn_sig(did))
|
||||
} else {
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(attr.span, "this attribute can only be applied to functions");
|
||||
None
|
||||
}
|
||||
sig
|
||||
};
|
||||
|
||||
let Some(Ident { name, .. }) = attr.ident() else {
|
||||
|
|
@ -618,93 +613,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(sig) = fn_sig_outer() {
|
||||
// Collect target features from types reachable from arguments.
|
||||
// We define a type as "reachable" if:
|
||||
// - it is a function argument
|
||||
// - it is a field of a reachable struct
|
||||
// - there is a reachable reference to it
|
||||
// FIXME(struct_target_features): we may want to cache the result of this computation.
|
||||
let mut visited_types = FxHashSet::default();
|
||||
let mut reachable_types: Vec<_> = sig.skip_binder().inputs().skip_binder().to_owned();
|
||||
let mut additional_tf = vec![];
|
||||
|
||||
while let Some(ty) = reachable_types.pop() {
|
||||
if visited_types.contains(&ty) {
|
||||
continue;
|
||||
}
|
||||
visited_types.insert(ty);
|
||||
match ty.kind() {
|
||||
ty::Alias(..) => {
|
||||
if let Ok(t) =
|
||||
tcx.try_normalize_erasing_regions(tcx.param_env(did.to_def_id()), ty)
|
||||
{
|
||||
reachable_types.push(t)
|
||||
}
|
||||
}
|
||||
|
||||
ty::Ref(_, inner, _) => reachable_types.push(*inner),
|
||||
ty::Tuple(tys) => reachable_types.extend(tys.iter()),
|
||||
ty::Adt(adt_def, args) => {
|
||||
additional_tf.extend_from_slice(tcx.struct_target_features(adt_def.did()));
|
||||
// This only recurses into structs as i.e. an Option<TargetFeature> is an ADT
|
||||
// that doesn't actually always contain a TargetFeature.
|
||||
if adt_def.is_struct() {
|
||||
reachable_types.extend(
|
||||
adt_def
|
||||
.variant(VariantIdx::from_usize(0))
|
||||
.fields
|
||||
.iter()
|
||||
.map(|field| field.ty(tcx, args)),
|
||||
);
|
||||
}
|
||||
}
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
| ty::Uint(..)
|
||||
| ty::Float(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Str
|
||||
| ty::Array(..)
|
||||
| ty::Pat(..)
|
||||
| ty::Slice(..)
|
||||
| ty::RawPtr(..)
|
||||
| ty::FnDef(..)
|
||||
| ty::FnPtr(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(..)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Param(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(..)
|
||||
| ty::Error(..) => (),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(struct_target_features): is this really necessary?
|
||||
if !additional_tf.is_empty() && sig.skip_binder().abi() != abi::Abi::Rust {
|
||||
tcx.dcx().span_err(
|
||||
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
|
||||
"cannot use a struct with target features in a function with non-Rust ABI",
|
||||
);
|
||||
}
|
||||
if !additional_tf.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
|
||||
tcx.dcx().span_err(
|
||||
tcx.hir().span(tcx.local_def_id_to_hir_id(did)),
|
||||
"cannot use a struct with target features in a #[inline(always)] function",
|
||||
);
|
||||
}
|
||||
codegen_fn_attrs
|
||||
.target_features
|
||||
.extend(additional_tf.iter().map(|tf| TargetFeature { implied: true, ..*tf }));
|
||||
}
|
||||
|
||||
// If a function uses non-default target_features it can't be inlined into general
|
||||
// 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.
|
||||
|
|
@ -849,20 +758,6 @@ fn check_link_name_xor_ordinal(
|
|||
}
|
||||
}
|
||||
|
||||
fn struct_target_features(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[TargetFeature] {
|
||||
let mut features = vec![];
|
||||
let supported_features = tcx.supported_target_features(LOCAL_CRATE);
|
||||
for attr in tcx.get_attrs(def_id, sym::target_feature) {
|
||||
from_target_feature(tcx, attr, supported_features, &mut features);
|
||||
}
|
||||
tcx.arena.alloc_slice(&features)
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
codegen_fn_attrs,
|
||||
should_inherit_track_caller,
|
||||
struct_target_features,
|
||||
..*providers
|
||||
};
|
||||
*providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ rustc_index = { path = "../rustc_index", package = "rustc_index" }
|
|||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] }
|
||||
stacker = "0.1.15"
|
||||
stacker = "0.1.17"
|
||||
tempfile = "3.2"
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_lint_defs::{Applicability, LintExpectationId};
|
|||
use rustc_macros::{Decodable, Encodable};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::{AttrId, Span, DUMMY_SP};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::snippet::Style;
|
||||
|
|
@ -356,24 +356,19 @@ impl DiagInner {
|
|||
|
||||
pub(crate) fn update_unstable_expectation_id(
|
||||
&mut self,
|
||||
unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
|
||||
unstable_to_stable: &FxIndexMap<AttrId, LintExpectationId>,
|
||||
) {
|
||||
if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) =
|
||||
&mut self.level
|
||||
&& let LintExpectationId::Unstable { attr_id, lint_index } = *expectation_id
|
||||
{
|
||||
if expectation_id.is_stable() {
|
||||
return;
|
||||
}
|
||||
|
||||
// The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
|
||||
// The lint index inside the attribute is manually transferred here.
|
||||
let lint_index = expectation_id.get_lint_index();
|
||||
expectation_id.set_lint_index(None);
|
||||
let mut stable_id = unstable_to_stable
|
||||
.get(expectation_id)
|
||||
.expect("each unstable `LintExpectationId` must have a matching stable id")
|
||||
.normalize();
|
||||
let Some(stable_id) = unstable_to_stable.get(&attr_id) else {
|
||||
panic!("{expectation_id:?} must have a matching stable id")
|
||||
};
|
||||
|
||||
let mut stable_id = *stable_id;
|
||||
stable_id.set_lint_index(lint_index);
|
||||
*expectation_id = stable_id;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ use rustc_macros::{Decodable, Encodable};
|
|||
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
pub use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::{Loc, Span, DUMMY_SP};
|
||||
use rustc_span::{AttrId, Loc, Span, DUMMY_SP};
|
||||
pub use snippet::Style;
|
||||
// Used by external projects such as `rust-gpu`.
|
||||
// See https://github.com/rust-lang/rust/pull/115393.
|
||||
|
|
@ -1096,7 +1096,7 @@ impl<'a> DiagCtxtHandle<'a> {
|
|||
|
||||
pub fn update_unstable_expectation_id(
|
||||
&self,
|
||||
unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
|
||||
unstable_to_stable: FxIndexMap<AttrId, LintExpectationId>,
|
||||
) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
let diags = std::mem::take(&mut inner.unstable_expect_diagnostics);
|
||||
|
|
@ -1105,7 +1105,7 @@ impl<'a> DiagCtxtHandle<'a> {
|
|||
if !diags.is_empty() {
|
||||
inner.suppressed_expected_diag = true;
|
||||
for mut diag in diags.into_iter() {
|
||||
diag.update_unstable_expectation_id(unstable_to_stable);
|
||||
diag.update_unstable_expectation_id(&unstable_to_stable);
|
||||
|
||||
// Here the diagnostic is given back to `emit_diagnostic` where it was first
|
||||
// intercepted. Now it should be processed as usual, since the unstable expectation
|
||||
|
|
@ -1117,11 +1117,11 @@ impl<'a> DiagCtxtHandle<'a> {
|
|||
inner
|
||||
.stashed_diagnostics
|
||||
.values_mut()
|
||||
.for_each(|(diag, _guar)| diag.update_unstable_expectation_id(unstable_to_stable));
|
||||
.for_each(|(diag, _guar)| diag.update_unstable_expectation_id(&unstable_to_stable));
|
||||
inner
|
||||
.future_breakage_diagnostics
|
||||
.iter_mut()
|
||||
.for_each(|diag| diag.update_unstable_expectation_id(unstable_to_stable));
|
||||
.for_each(|diag| diag.update_unstable_expectation_id(&unstable_to_stable));
|
||||
}
|
||||
|
||||
/// This methods steals all [`LintExpectationId`]s that are stored inside
|
||||
|
|
@ -1567,7 +1567,7 @@ impl DiagCtxtInner {
|
|||
if let LintExpectationId::Unstable { .. } = expect_id {
|
||||
unreachable!(); // this case was handled at the top of this function
|
||||
}
|
||||
self.fulfilled_expectations.insert(expect_id.normalize());
|
||||
self.fulfilled_expectations.insert(expect_id);
|
||||
if let Expect(_) = diagnostic.level {
|
||||
// Nothing emitted here for expected lints.
|
||||
TRACK_DIAGNOSTIC(diagnostic, &mut |_| None);
|
||||
|
|
|
|||
|
|
@ -597,8 +597,6 @@ declare_features! (
|
|||
(unstable, strict_provenance, "1.61.0", Some(95228)),
|
||||
/// Allows string patterns to dereference values to match them.
|
||||
(unstable, string_deref_patterns, "1.67.0", Some(87121)),
|
||||
/// Allows structs to carry target_feature information.
|
||||
(incomplete, struct_target_features, "CURRENT_RUSTC_VERSION", Some(129107)),
|
||||
/// Allows the use of `#[target_feature]` on safe functions.
|
||||
(unstable, target_feature_11, "1.45.0", Some(69098)),
|
||||
/// Allows using `#[thread_local]` on `static` items.
|
||||
|
|
|
|||
|
|
@ -326,41 +326,6 @@ impl DefKind {
|
|||
| DefKind::ExternCrate => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether `query struct_target_features` should be used with this definition.
|
||||
pub fn has_struct_target_features(self) -> bool {
|
||||
match self {
|
||||
DefKind::Struct | DefKind::Union | DefKind::Enum => true,
|
||||
DefKind::Fn
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Ctor(..)
|
||||
| DefKind::Closure
|
||||
| DefKind::Static { .. }
|
||||
| DefKind::Mod
|
||||
| DefKind::Variant
|
||||
| DefKind::Trait
|
||||
| DefKind::TyAlias
|
||||
| DefKind::ForeignTy
|
||||
| DefKind::TraitAlias
|
||||
| DefKind::AssocTy
|
||||
| DefKind::Const
|
||||
| DefKind::AssocConst
|
||||
| DefKind::Macro(..)
|
||||
| DefKind::Use
|
||||
| DefKind::ForeignMod
|
||||
| DefKind::OpaqueTy
|
||||
| DefKind::Impl { .. }
|
||||
| DefKind::Field
|
||||
| DefKind::TyParam
|
||||
| DefKind::ConstParam
|
||||
| DefKind::LifetimeParam
|
||||
| DefKind::AnonConst
|
||||
| DefKind::InlineConst
|
||||
| DefKind::SyntheticCoroutineBody
|
||||
| DefKind::GlobalAsm
|
||||
| DefKind::ExternCrate => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The resolution of a path or export.
|
||||
|
|
@ -863,8 +828,13 @@ pub enum LifetimeRes {
|
|||
/// This variant is used for anonymous lifetimes that we did not resolve during
|
||||
/// late resolution. Those lifetimes will be inferred by typechecking.
|
||||
Infer,
|
||||
/// Explicit `'static` lifetime.
|
||||
Static,
|
||||
/// `'static` lifetime.
|
||||
Static {
|
||||
/// We do not want to emit `elided_named_lifetimes`
|
||||
/// when we are inside of a const item or a static,
|
||||
/// because it would get too annoying.
|
||||
suppress_elision_warning: bool,
|
||||
},
|
||||
/// Resolution failure.
|
||||
Error,
|
||||
/// HACK: This is used to recover the NodeId of an elided lifetime.
|
||||
|
|
|
|||
|
|
@ -851,8 +851,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
}
|
||||
|
||||
// Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
|
||||
// FIXME(struct_target_features): should this be true also for functions that inherit
|
||||
// target features from structs?
|
||||
|
||||
if b_hdr.safety == hir::Safety::Safe
|
||||
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
|
|
|
|||
|
|
@ -252,6 +252,10 @@ lint_duplicate_macro_attribute =
|
|||
|
||||
lint_duplicate_matcher_binding = duplicate matcher binding
|
||||
|
||||
lint_elided_named_lifetime = elided lifetime has a name
|
||||
.label_elided = this elided lifetime gets resolved as `{$name}`
|
||||
.label_named = lifetime `{$name}` declared here
|
||||
|
||||
lint_enum_intrinsics_mem_discriminant =
|
||||
the return value of `mem::discriminant` is unspecified when called with a non-enum type
|
||||
.note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use rustc_errors::{
|
|||
use rustc_middle::middle::stability;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::BytePos;
|
||||
use tracing::debug;
|
||||
|
||||
|
|
@ -441,5 +442,17 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
|
|||
BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
|
||||
lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
|
||||
}
|
||||
BuiltinLintDiag::ElidedIsStatic { elided } => {
|
||||
lints::ElidedNamedLifetime { elided, name: kw::StaticLifetime, named_declaration: None }
|
||||
.decorate_lint(diag)
|
||||
}
|
||||
BuiltinLintDiag::ElidedIsParam { elided, param: (param_name, param_span) } => {
|
||||
lints::ElidedNamedLifetime {
|
||||
elided,
|
||||
name: param_name,
|
||||
named_declaration: Some(param_span),
|
||||
}
|
||||
.decorate_lint(diag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,66 @@
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir::{HirId, CRATE_OWNER_ID};
|
||||
use rustc_middle::lint::LintExpectation;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
|
||||
use rustc_session::lint::LintExpectationId;
|
||||
use rustc_session::lint::{Level, LintExpectationId};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
use crate::lints::{Expectation, ExpectationNote};
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { check_expectations, ..*providers };
|
||||
*providers = Providers { lint_expectations, check_expectations, ..*providers };
|
||||
}
|
||||
|
||||
fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> {
|
||||
let krate = tcx.hir_crate_items(());
|
||||
|
||||
let mut expectations = Vec::new();
|
||||
let mut unstable_to_stable_ids = FxIndexMap::default();
|
||||
|
||||
let mut record_stable = |attr_id, hir_id, attr_index| {
|
||||
let expect_id = LintExpectationId::Stable { hir_id, attr_index, lint_index: None };
|
||||
unstable_to_stable_ids.entry(attr_id).or_insert(expect_id);
|
||||
};
|
||||
let mut push_expectations = |owner| {
|
||||
let lints = tcx.shallow_lint_levels_on(owner);
|
||||
if lints.expectations.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
expectations.extend_from_slice(&lints.expectations);
|
||||
|
||||
let attrs = tcx.hir_attrs(owner);
|
||||
for &(local_id, attrs) in attrs.map.iter() {
|
||||
// Some attributes appear multiple times in HIR, to ensure they are correctly taken
|
||||
// into account where they matter. This means we cannot just associate the AttrId to
|
||||
// the first HirId where we see it, but need to check it actually appears in a lint
|
||||
// level.
|
||||
// FIXME(cjgillot): Can this cause an attribute to appear in multiple expectation ids?
|
||||
if !lints.specs.contains_key(&local_id) {
|
||||
continue;
|
||||
}
|
||||
for (attr_index, attr) in attrs.iter().enumerate() {
|
||||
let Some(Level::Expect(_)) = Level::from_attr(attr) else { continue };
|
||||
record_stable(attr.id, HirId { owner, local_id }, attr_index.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
push_expectations(CRATE_OWNER_ID);
|
||||
for owner in krate.owners() {
|
||||
push_expectations(owner);
|
||||
}
|
||||
|
||||
tcx.dcx().update_unstable_expectation_id(unstable_to_stable_ids);
|
||||
expectations
|
||||
}
|
||||
|
||||
fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
|
||||
let lint_expectations = tcx.lint_expectations(());
|
||||
let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids();
|
||||
|
||||
tracing::debug!(?lint_expectations, ?fulfilled_expectations);
|
||||
|
||||
for (id, expectation) in lint_expectations {
|
||||
// This check will always be true, since `lint_expectations` only
|
||||
// holds stable ids
|
||||
|
|
|
|||
|
|
@ -115,34 +115,6 @@ impl LintLevelSets {
|
|||
}
|
||||
}
|
||||
|
||||
fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> {
|
||||
let store = unerased_lint_store(tcx.sess);
|
||||
|
||||
let mut builder = LintLevelsBuilder {
|
||||
sess: tcx.sess,
|
||||
features: tcx.features(),
|
||||
provider: QueryMapExpectationsWrapper {
|
||||
tcx,
|
||||
cur: hir::CRATE_HIR_ID,
|
||||
specs: ShallowLintLevelMap::default(),
|
||||
expectations: Vec::new(),
|
||||
unstable_to_stable_ids: FxIndexMap::default(),
|
||||
empty: FxIndexMap::default(),
|
||||
},
|
||||
lint_added_lints: false,
|
||||
store,
|
||||
registered_tools: tcx.registered_tools(()),
|
||||
};
|
||||
|
||||
builder.add_command_line();
|
||||
builder.add_id(hir::CRATE_HIR_ID);
|
||||
tcx.hir().walk_toplevel_module(&mut builder);
|
||||
|
||||
tcx.dcx().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
|
||||
|
||||
builder.provider.expectations
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(tcx), ret)]
|
||||
fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
|
||||
let store = unerased_lint_store(tcx.sess);
|
||||
|
|
@ -207,7 +179,7 @@ pub trait LintLevelsProvider {
|
|||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource>;
|
||||
fn insert(&mut self, id: LintId, lvl: LevelAndSource);
|
||||
fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource;
|
||||
fn push_expectation(&mut self, _id: LintExpectationId, _expectation: LintExpectation) {}
|
||||
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation);
|
||||
}
|
||||
|
||||
impl LintLevelsProvider for TopDown {
|
||||
|
|
@ -222,6 +194,8 @@ impl LintLevelsProvider for TopDown {
|
|||
fn get_lint_level(&self, lint: &'static Lint, sess: &Session) -> LevelAndSource {
|
||||
self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), sess)
|
||||
}
|
||||
|
||||
fn push_expectation(&mut self, _: LintExpectationId, _: LintExpectation) {}
|
||||
}
|
||||
|
||||
struct LintLevelQueryMap<'tcx> {
|
||||
|
|
@ -243,47 +217,8 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> {
|
|||
fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
|
||||
self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
|
||||
}
|
||||
}
|
||||
|
||||
struct QueryMapExpectationsWrapper<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
/// HirId of the currently investigated element.
|
||||
cur: HirId,
|
||||
/// Level map for `cur`.
|
||||
specs: ShallowLintLevelMap,
|
||||
expectations: Vec<(LintExpectationId, LintExpectation)>,
|
||||
unstable_to_stable_ids: FxIndexMap<LintExpectationId, LintExpectationId>,
|
||||
/// Empty hash map to simplify code.
|
||||
empty: FxIndexMap<LintId, LevelAndSource>,
|
||||
}
|
||||
|
||||
impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> {
|
||||
fn current_specs(&self) -> &FxIndexMap<LintId, LevelAndSource> {
|
||||
self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
|
||||
}
|
||||
fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
|
||||
self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl);
|
||||
}
|
||||
fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
|
||||
// We cannot use `tcx.lint_level_at_node` because we want to know in which order the
|
||||
// attributes have been inserted, in particular whether an `expect` follows a `forbid`.
|
||||
self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
|
||||
}
|
||||
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
|
||||
let LintExpectationId::Stable { attr_id: Some(attr_id), hir_id, attr_index, .. } = id
|
||||
else {
|
||||
bug!("unstable expectation id should already be mapped")
|
||||
};
|
||||
let key = LintExpectationId::Unstable { attr_id, lint_index: None };
|
||||
|
||||
self.unstable_to_stable_ids.entry(key).or_insert(LintExpectationId::Stable {
|
||||
hir_id,
|
||||
attr_index,
|
||||
lint_index: None,
|
||||
attr_id: None,
|
||||
});
|
||||
|
||||
self.expectations.push((id.normalize(), expectation));
|
||||
self.specs.expectations.push((id, expectation))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,80 +303,6 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
|
||||
fn add_id(&mut self, hir_id: HirId) {
|
||||
// Change both the `HirId` and the associated specs.
|
||||
self.provider.cur = hir_id;
|
||||
self.provider.specs.specs.clear();
|
||||
self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
|
||||
type NestedFilter = nested_filter::All;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.provider.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
|
||||
self.add_id(param.hir_id);
|
||||
intravisit::walk_param(self, param);
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
|
||||
self.add_id(it.hir_id());
|
||||
intravisit::walk_item(self, it);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
|
||||
self.add_id(it.hir_id());
|
||||
intravisit::walk_foreign_item(self, it);
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) {
|
||||
// We will call `add_id` when we walk
|
||||
// the `StmtKind`. The outer statement itself doesn't
|
||||
// define the lint levels.
|
||||
intravisit::walk_stmt(self, e);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
|
||||
self.add_id(e.hir_id);
|
||||
intravisit::walk_expr(self, e);
|
||||
}
|
||||
|
||||
fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
|
||||
self.add_id(s.hir_id);
|
||||
intravisit::walk_field_def(self, s);
|
||||
}
|
||||
|
||||
fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
|
||||
self.add_id(v.hir_id);
|
||||
intravisit::walk_variant(self, v);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
|
||||
self.add_id(l.hir_id);
|
||||
intravisit::walk_local(self, l);
|
||||
}
|
||||
|
||||
fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
|
||||
self.add_id(a.hir_id);
|
||||
intravisit::walk_arm(self, a);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
|
||||
self.add_id(trait_item.hir_id());
|
||||
intravisit::walk_trait_item(self, trait_item);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
||||
self.add_id(impl_item.hir_id());
|
||||
intravisit::walk_impl_item(self, impl_item);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LintLevelsBuilder<'s, P> {
|
||||
sess: &'s Session,
|
||||
features: &'s Features,
|
||||
|
|
@ -625,13 +486,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
/// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
|
||||
/// (e.g. if a forbid was already inserted on the same scope), then emits a
|
||||
/// diagnostic with no change to `specs`.
|
||||
fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) {
|
||||
fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
|
||||
let (old_level, old_src) = self.provider.get_lint_level(id.lint, self.sess);
|
||||
if let Level::Expect(id) = &mut level
|
||||
&& let LintExpectationId::Stable { .. } = id
|
||||
{
|
||||
*id = id.normalize();
|
||||
}
|
||||
|
||||
// Setting to a non-forbid level is an error if the lint previously had
|
||||
// a forbid level. Note that this is not necessarily true even with a
|
||||
// `#[forbid(..)]` attribute present, as that is overridden by `--cap-lints`.
|
||||
|
|
@ -743,17 +600,15 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
// This is the only lint level with a `LintExpectationId` that can be created from
|
||||
// an attribute.
|
||||
Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => {
|
||||
let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id else {
|
||||
let LintExpectationId::Unstable { lint_index: None, attr_id: _ } = unstable_id
|
||||
else {
|
||||
bug!("stable id Level::from_attr")
|
||||
};
|
||||
|
||||
let stable_id = LintExpectationId::Stable {
|
||||
hir_id,
|
||||
attr_index: attr_index.try_into().unwrap(),
|
||||
lint_index,
|
||||
// We pass the previous unstable attr_id such that we can trace the ast id
|
||||
// when building a map to go from unstable to stable id.
|
||||
attr_id: Some(attr_id),
|
||||
lint_index: None,
|
||||
};
|
||||
|
||||
Level::Expect(stable_id)
|
||||
|
|
@ -840,59 +695,20 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
let name = pprust::path_to_string(&meta_item.path);
|
||||
let lint_result =
|
||||
self.store.check_lint_name(&name, tool_name, self.registered_tools);
|
||||
match &lint_result {
|
||||
|
||||
let (ids, name) = match lint_result {
|
||||
CheckLintNameResult::Ok(ids) => {
|
||||
// This checks for instances where the user writes
|
||||
// `#[expect(unfulfilled_lint_expectations)]` in that case we want to avoid
|
||||
// overriding the lint level but instead add an expectation that can't be
|
||||
// fulfilled. The lint message will include an explanation, that the
|
||||
// `unfulfilled_lint_expectations` lint can't be expected.
|
||||
if let Level::Expect(expect_id) = level {
|
||||
// The `unfulfilled_lint_expectations` lint is not part of any lint
|
||||
// groups. Therefore. we only need to check the slice if it contains a
|
||||
// single lint.
|
||||
let is_unfulfilled_lint_expectations = match ids {
|
||||
[lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
|
||||
_ => false,
|
||||
};
|
||||
self.provider.push_expectation(
|
||||
expect_id,
|
||||
LintExpectation::new(
|
||||
reason,
|
||||
sp,
|
||||
is_unfulfilled_lint_expectations,
|
||||
tool_name,
|
||||
),
|
||||
);
|
||||
}
|
||||
let src = LintLevelSource::Node {
|
||||
name: meta_item
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
.expect("empty lint name")
|
||||
.ident
|
||||
.name,
|
||||
span: sp,
|
||||
reason,
|
||||
};
|
||||
for &id in *ids {
|
||||
if self.check_gated_lint(id, attr.span, false) {
|
||||
self.insert_spec(id, (level, src));
|
||||
}
|
||||
}
|
||||
let name =
|
||||
meta_item.path.segments.last().expect("empty lint name").ident.name;
|
||||
(ids, name)
|
||||
}
|
||||
|
||||
CheckLintNameResult::Tool(ids, new_lint_name) => {
|
||||
let src = match new_lint_name {
|
||||
let name = match new_lint_name {
|
||||
None => {
|
||||
let complete_name =
|
||||
&format!("{}::{}", tool_ident.unwrap().name, name);
|
||||
LintLevelSource::Node {
|
||||
name: Symbol::intern(complete_name),
|
||||
span: sp,
|
||||
reason,
|
||||
}
|
||||
Symbol::intern(complete_name)
|
||||
}
|
||||
Some(new_lint_name) => {
|
||||
self.emit_span_lint(
|
||||
|
|
@ -901,27 +717,13 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
DeprecatedLintName {
|
||||
name,
|
||||
suggestion: sp,
|
||||
replace: new_lint_name,
|
||||
replace: &new_lint_name,
|
||||
},
|
||||
);
|
||||
LintLevelSource::Node {
|
||||
name: Symbol::intern(new_lint_name),
|
||||
span: sp,
|
||||
reason,
|
||||
}
|
||||
Symbol::intern(&new_lint_name)
|
||||
}
|
||||
};
|
||||
for &id in *ids {
|
||||
if self.check_gated_lint(id, attr.span, false) {
|
||||
self.insert_spec(id, (level, src));
|
||||
}
|
||||
}
|
||||
if let Level::Expect(expect_id) = level {
|
||||
self.provider.push_expectation(
|
||||
expect_id,
|
||||
LintExpectation::new(reason, sp, false, tool_name),
|
||||
);
|
||||
}
|
||||
(ids, name)
|
||||
}
|
||||
|
||||
CheckLintNameResult::MissingTool => {
|
||||
|
|
@ -929,9 +731,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
// exist in the tool or the code was not compiled with the tool and
|
||||
// therefore the lint was never added to the `LintStore`. To detect
|
||||
// this is the responsibility of the lint tool.
|
||||
continue;
|
||||
}
|
||||
|
||||
&CheckLintNameResult::NoTool => {
|
||||
CheckLintNameResult::NoTool => {
|
||||
sess.dcx().emit_err(UnknownToolInScopedLint {
|
||||
span: tool_ident.map(|ident| ident.span),
|
||||
tool_name: tool_name.unwrap(),
|
||||
|
|
@ -941,57 +744,87 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
continue;
|
||||
}
|
||||
|
||||
_ if !self.lint_added_lints => {}
|
||||
|
||||
CheckLintNameResult::Renamed(ref replace) => {
|
||||
let suggestion =
|
||||
RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
|
||||
let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
let lint = RenamedLint { name: name.as_str(), suggestion };
|
||||
self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
|
||||
if self.lint_added_lints {
|
||||
let suggestion =
|
||||
RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
|
||||
let name =
|
||||
tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
let lint = RenamedLint { name: name.as_str(), suggestion };
|
||||
self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
|
||||
}
|
||||
|
||||
// If this lint was renamed, apply the new lint instead of ignoring the
|
||||
// attribute. Ignore any errors or warnings that happen because the new
|
||||
// name is inaccurate.
|
||||
// NOTE: `new_name` already includes the tool name, so we don't
|
||||
// have to add it again.
|
||||
let CheckLintNameResult::Ok(ids) =
|
||||
self.store.check_lint_name(replace, None, self.registered_tools)
|
||||
else {
|
||||
panic!("renamed lint does not exist: {replace}");
|
||||
};
|
||||
|
||||
(ids, Symbol::intern(&replace))
|
||||
}
|
||||
|
||||
CheckLintNameResult::Removed(ref reason) => {
|
||||
let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
let lint = RemovedLint { name: name.as_str(), reason };
|
||||
self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
|
||||
if self.lint_added_lints {
|
||||
let name =
|
||||
tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
let lint = RemovedLint { name: name.as_str(), reason };
|
||||
self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
CheckLintNameResult::NoLint(suggestion) => {
|
||||
let name = tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
let suggestion = suggestion.map(|(replace, from_rustc)| {
|
||||
UnknownLintSuggestion::WithSpan { suggestion: sp, replace, from_rustc }
|
||||
});
|
||||
let lint = UnknownLint { name, suggestion };
|
||||
self.emit_span_lint(UNKNOWN_LINTS, sp.into(), lint);
|
||||
if self.lint_added_lints {
|
||||
let name =
|
||||
tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
|
||||
let suggestion = suggestion.map(|(replace, from_rustc)| {
|
||||
UnknownLintSuggestion::WithSpan {
|
||||
suggestion: sp,
|
||||
replace,
|
||||
from_rustc,
|
||||
}
|
||||
});
|
||||
let lint = UnknownLint { name, suggestion };
|
||||
self.emit_span_lint(UNKNOWN_LINTS, sp.into(), lint);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let src = LintLevelSource::Node { name, span: sp, reason };
|
||||
for &id in ids {
|
||||
if self.check_gated_lint(id, attr.span, false) {
|
||||
self.insert_spec(id, (level, src));
|
||||
}
|
||||
}
|
||||
// If this lint was renamed, apply the new lint instead of ignoring the attribute.
|
||||
// This happens outside of the match because the new lint should be applied even if
|
||||
// we don't warn about the name change.
|
||||
if let CheckLintNameResult::Renamed(new_name) = lint_result {
|
||||
// Ignore any errors or warnings that happen because the new name is inaccurate
|
||||
// NOTE: `new_name` already includes the tool name, so we don't have to add it
|
||||
// again.
|
||||
let CheckLintNameResult::Ok(ids) =
|
||||
self.store.check_lint_name(&new_name, None, self.registered_tools)
|
||||
else {
|
||||
panic!("renamed lint does not exist: {new_name}");
|
||||
};
|
||||
|
||||
let src =
|
||||
LintLevelSource::Node { name: Symbol::intern(&new_name), span: sp, reason };
|
||||
for &id in ids {
|
||||
if self.check_gated_lint(id, attr.span, false) {
|
||||
self.insert_spec(id, (level, src));
|
||||
}
|
||||
}
|
||||
if let Level::Expect(expect_id) = level {
|
||||
self.provider.push_expectation(
|
||||
expect_id,
|
||||
LintExpectation::new(reason, sp, false, tool_name),
|
||||
);
|
||||
}
|
||||
// This checks for instances where the user writes
|
||||
// `#[expect(unfulfilled_lint_expectations)]` in that case we want to avoid
|
||||
// overriding the lint level but instead add an expectation that can't be
|
||||
// fulfilled. The lint message will include an explanation, that the
|
||||
// `unfulfilled_lint_expectations` lint can't be expected.
|
||||
if let Level::Expect(expect_id) = level {
|
||||
// The `unfulfilled_lint_expectations` lint is not part of any lint
|
||||
// groups. Therefore. we only need to check the slice if it contains a
|
||||
// single lint.
|
||||
let is_unfulfilled_lint_expectations = match ids {
|
||||
[lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
|
||||
_ => false,
|
||||
};
|
||||
self.provider.push_expectation(
|
||||
expect_id,
|
||||
LintExpectation::new(
|
||||
reason,
|
||||
sp,
|
||||
is_unfulfilled_lint_expectations,
|
||||
tool_name,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1100,7 +933,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
|||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { shallow_lint_levels_on, lint_expectations, ..*providers };
|
||||
*providers = Providers { shallow_lint_levels_on, ..*providers };
|
||||
}
|
||||
|
||||
pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
|
||||
|
|
|
|||
|
|
@ -2611,6 +2611,16 @@ pub(crate) struct ElidedLifetimesInPaths {
|
|||
pub subdiag: ElidedLifetimeInPathSubdiag,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_elided_named_lifetime)]
|
||||
pub(crate) struct ElidedNamedLifetime {
|
||||
#[label(lint_label_elided)]
|
||||
pub elided: Span,
|
||||
pub name: Symbol,
|
||||
#[label(lint_label_named)]
|
||||
pub named_declaration: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_invalid_crate_type_value)]
|
||||
pub(crate) struct UnknownCrateTypes {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ declare_lint_pass! {
|
|||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
ELIDED_NAMED_LIFETIMES,
|
||||
EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
|
||||
EXPORTED_PRIVATE_DEPENDENCIES,
|
||||
FFI_UNWIND_CALLS,
|
||||
|
|
@ -1862,6 +1863,38 @@ declare_lint! {
|
|||
"hidden lifetime parameters in types are deprecated"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `elided_named_lifetimes` lint detects when an elided
|
||||
/// lifetime ends up being a named lifetime, such as `'static`
|
||||
/// or some lifetime parameter `'a`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(elided_named_lifetimes)]
|
||||
/// struct Foo;
|
||||
/// impl Foo {
|
||||
/// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
|
||||
/// unsafe { &mut *(x as *mut _) }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Lifetime elision is quite useful, because it frees you from having
|
||||
/// to give each lifetime its own name, but sometimes it can produce
|
||||
/// somewhat surprising resolutions. In safe code, it is mostly okay,
|
||||
/// because the borrow checker prevents any unsoundness, so the worst
|
||||
/// case scenario is you get a confusing error message in some other place.
|
||||
/// But with `unsafe` code, such unexpected resolutions may lead to unsound code.
|
||||
pub ELIDED_NAMED_LIFETIMES,
|
||||
Warn,
|
||||
"detects when an elided lifetime gets resolved to be `'static` or some named parameter"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
|
||||
/// objects.
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ pub enum LintExpectationId {
|
|||
/// stable and can be cached. The additional index ensures that nodes with
|
||||
/// several expectations can correctly match diagnostics to the individual
|
||||
/// expectation.
|
||||
Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16>, attr_id: Option<AttrId> },
|
||||
Stable { hir_id: HirId, attr_index: u16, lint_index: Option<u16> },
|
||||
}
|
||||
|
||||
impl LintExpectationId {
|
||||
|
|
@ -122,31 +122,13 @@ impl LintExpectationId {
|
|||
|
||||
*lint_index = new_lint_index
|
||||
}
|
||||
|
||||
/// Prepares the id for hashing. Removes references to the ast.
|
||||
/// Should only be called when the id is stable.
|
||||
pub fn normalize(self) -> Self {
|
||||
match self {
|
||||
Self::Stable { hir_id, attr_index, lint_index, .. } => {
|
||||
Self::Stable { hir_id, attr_index, lint_index, attr_id: None }
|
||||
}
|
||||
Self::Unstable { .. } => {
|
||||
unreachable!("`normalize` called when `ExpectationId` is unstable")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCX: rustc_hir::HashStableContext> HashStable<HCX> for LintExpectationId {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
match self {
|
||||
LintExpectationId::Stable {
|
||||
hir_id,
|
||||
attr_index,
|
||||
lint_index: Some(lint_index),
|
||||
attr_id: _,
|
||||
} => {
|
||||
LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
|
||||
hir_id.hash_stable(hcx, hasher);
|
||||
attr_index.hash_stable(hcx, hasher);
|
||||
lint_index.hash_stable(hcx, hasher);
|
||||
|
|
@ -166,12 +148,9 @@ impl<HCX: rustc_hir::HashStableContext> ToStableHashKey<HCX> for LintExpectation
|
|||
#[inline]
|
||||
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
|
||||
match self {
|
||||
LintExpectationId::Stable {
|
||||
hir_id,
|
||||
attr_index,
|
||||
lint_index: Some(lint_index),
|
||||
attr_id: _,
|
||||
} => (*hir_id, *attr_index, *lint_index),
|
||||
LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
|
||||
(*hir_id, *attr_index, *lint_index)
|
||||
}
|
||||
_ => {
|
||||
unreachable!("HashStable should only be called for a filled `LintExpectationId`")
|
||||
}
|
||||
|
|
@ -589,6 +568,13 @@ pub enum BuiltinLintDiag {
|
|||
},
|
||||
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
|
||||
ElidedLifetimesInPaths(usize, Span, bool, Span),
|
||||
ElidedIsStatic {
|
||||
elided: Span,
|
||||
},
|
||||
ElidedIsParam {
|
||||
elided: Span,
|
||||
param: (Symbol, Span),
|
||||
},
|
||||
UnknownCrateTypes {
|
||||
span: Span,
|
||||
candidate: Option<Symbol>,
|
||||
|
|
|
|||
|
|
@ -254,7 +254,6 @@ provide! { tcx, def_id, other, cdata,
|
|||
variances_of => { table }
|
||||
fn_sig => { table }
|
||||
codegen_fn_attrs => { table }
|
||||
struct_target_features => { table }
|
||||
impl_trait_header => { table }
|
||||
const_param_default => { table }
|
||||
object_lifetime_default => { table }
|
||||
|
|
|
|||
|
|
@ -1392,9 +1392,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
if def_kind.has_codegen_attrs() {
|
||||
record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
|
||||
}
|
||||
if def_kind.has_struct_target_features() {
|
||||
record_array!(self.tables.struct_target_features[def_id] <- self.tcx.struct_target_features(def_id));
|
||||
}
|
||||
if should_encode_visibility(def_kind) {
|
||||
let vis =
|
||||
self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use rustc_macros::{
|
|||
Decodable, Encodable, MetadataDecodable, MetadataEncodable, TyDecodable, TyEncodable,
|
||||
};
|
||||
use rustc_middle::metadata::ModChild;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||
use rustc_middle::middle::lib_features::FeatureStability;
|
||||
|
|
@ -427,7 +427,6 @@ define_tables! {
|
|||
variances_of: Table<DefIndex, LazyArray<ty::Variance>>,
|
||||
fn_sig: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, ty::PolyFnSig<'static>>>>,
|
||||
codegen_fn_attrs: Table<DefIndex, LazyValue<CodegenFnAttrs>>,
|
||||
struct_target_features: Table<DefIndex, LazyArray<TargetFeature>>,
|
||||
impl_trait_header: Table<DefIndex, LazyValue<ty::ImplTraitHeader<'static>>>,
|
||||
const_param_default: Table<DefIndex, LazyValue<ty::EarlyBinder<'static, rustc_middle::ty::Const<'static>>>>,
|
||||
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_errors::{Diag, MultiSpan};
|
|||
use rustc_hir::{HirId, ItemLocalId};
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS};
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintId};
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::{symbol, DesugaringKind, Span, Symbol, DUMMY_SP};
|
||||
|
|
@ -61,6 +61,7 @@ pub type LevelAndSource = (Level, LintLevelSource);
|
|||
/// by the attributes for *a single HirId*.
|
||||
#[derive(Default, Debug, HashStable)]
|
||||
pub struct ShallowLintLevelMap {
|
||||
pub expectations: Vec<(LintExpectationId, LintExpectation)>,
|
||||
pub specs: SortedMap<ItemLocalId, FxIndexMap<LintId, LevelAndSource>>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ pub struct CodegenFnAttrs {
|
|||
/// be set when `link_name` is set. This is for foreign items with the
|
||||
/// "raw-dylib" kind.
|
||||
pub link_ordinal: Option<u16>,
|
||||
/// All the target features that are enabled for this function. Some features might be enabled
|
||||
/// implicitly.
|
||||
/// The `#[target_feature(enable = "...")]` attribute and the enabled
|
||||
/// features (only enabled features are supported right now).
|
||||
pub target_features: Vec<TargetFeature>,
|
||||
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
|
||||
pub linkage: Option<Linkage>,
|
||||
|
|
@ -55,8 +55,8 @@ pub struct CodegenFnAttrs {
|
|||
pub struct TargetFeature {
|
||||
/// The name of the target feature (e.g. "avx")
|
||||
pub name: Symbol,
|
||||
/// The feature is implied by another feature or by an argument, rather than explicitly
|
||||
/// added by the `#[target_feature]` attribute
|
||||
/// The feature is implied by another feature, rather than explicitly added by the
|
||||
/// `#[target_feature]` attribute
|
||||
pub implied: bool,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
|
|||
use crate::infer::canonical::{self, Canonical};
|
||||
use crate::lint::LintExpectation;
|
||||
use crate::metadata::ModChild;
|
||||
use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature};
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||
use crate::middle::lib_features::LibFeatures;
|
||||
|
|
@ -1249,11 +1249,6 @@ rustc_queries! {
|
|||
feedable
|
||||
}
|
||||
|
||||
query struct_target_features(def_id: DefId) -> &'tcx [TargetFeature] {
|
||||
separate_provide_extern
|
||||
desc { |tcx| "computing target features for struct `{}`", tcx.def_path_str(def_id) }
|
||||
}
|
||||
|
||||
query asm_target_features(def_id: DefId) -> &'tcx FxIndexSet<Symbol> {
|
||||
desc { |tcx| "computing target features for inline asm of `{}`", tcx.def_path_str(def_id) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ trivially_parameterized_over_tcx! {
|
|||
std::string::String,
|
||||
crate::metadata::ModChild,
|
||||
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
|
||||
crate::middle::codegen_fn_attrs::TargetFeature,
|
||||
crate::middle::debugger_visualizer::DebuggerVisualizerFile,
|
||||
crate::middle::exported_symbols::SymbolExportInfo,
|
||||
crate::middle::lib_features::FeatureStability,
|
||||
|
|
|
|||
|
|
@ -125,17 +125,6 @@ mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed
|
|||
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
|
||||
.label = initializing type with `rustc_layout_scalar_valid_range` attr
|
||||
|
||||
mir_build_initializing_type_with_target_feature_requires_unsafe =
|
||||
initializing type with `target_feature` attr is unsafe and requires unsafe block
|
||||
.note = this struct can only be constructed if the corresponding `target_feature`s are available
|
||||
.label = initializing type with `target_feature` attr
|
||||
|
||||
mir_build_initializing_type_with_target_feature_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
initializing type with `target_feature` attr is unsafe and requires unsafe function or block
|
||||
.note = this struct can only be constructed if the corresponding `target_feature`s are available
|
||||
.label = initializing type with `target_feature` attr
|
||||
|
||||
|
||||
mir_build_inline_assembly_requires_unsafe =
|
||||
use of inline assembly is unsafe and requires unsafe block
|
||||
.note = inline assembly is entirely unchecked and can cause undefined behavior
|
||||
|
|
@ -398,11 +387,6 @@ mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
|
|||
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
|
||||
.label = initializing type with `rustc_layout_scalar_valid_range` attr
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_target_feature_requires_unsafe =
|
||||
initializing type with `target_feature` attr is unsafe and requires unsafe block
|
||||
.note = this struct can only be constructed if the corresponding `target_feature`s are available
|
||||
.label = initializing type with `target_feature` attr
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
|
||||
use of inline assembly is unsafe and requires unsafe block
|
||||
.note = inline assembly is entirely unchecked and can cause undefined behavior
|
||||
|
|
|
|||
|
|
@ -461,18 +461,14 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
};
|
||||
self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
|
||||
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
|
||||
// If the called function has explicit target features the calling function hasn't,
|
||||
// If the called function has target features the calling function hasn't,
|
||||
// the call requires `unsafe`. Don't check this on wasm
|
||||
// targets, though. For more information on wasm see the
|
||||
// is_like_wasm check in hir_analysis/src/collect.rs
|
||||
// Implicit target features are OK because they are either a consequence of some
|
||||
// explicit target feature (which is checked to be present in the caller) or
|
||||
// come from a witness argument.
|
||||
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
|
||||
if !self.tcx.sess.target.options.is_like_wasm
|
||||
&& !callee_features.iter().all(|feature| {
|
||||
feature.implied
|
||||
|| self.body_target_features.iter().any(|f| f.name == feature.name)
|
||||
self.body_target_features.iter().any(|f| f.name == feature.name)
|
||||
})
|
||||
{
|
||||
let missing: Vec<_> = callee_features
|
||||
|
|
@ -546,16 +542,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
|||
user_ty: _,
|
||||
fields: _,
|
||||
base: _,
|
||||
}) => {
|
||||
match self.tcx.layout_scalar_valid_range(adt_def.did()) {
|
||||
(Bound::Unbounded, Bound::Unbounded) => {}
|
||||
_ => self.requires_unsafe(expr.span, InitializingTypeWith),
|
||||
}
|
||||
if !self.tcx.struct_target_features(adt_def.did()).is_empty() {
|
||||
self.requires_unsafe(expr.span, ConstructingTargetFeaturesType)
|
||||
}
|
||||
}
|
||||
|
||||
}) => match self.tcx.layout_scalar_valid_range(adt_def.did()) {
|
||||
(Bound::Unbounded, Bound::Unbounded) => {}
|
||||
_ => self.requires_unsafe(expr.span, InitializingTypeWith),
|
||||
},
|
||||
ExprKind::Closure(box ClosureExpr {
|
||||
closure_id,
|
||||
args: _,
|
||||
|
|
@ -657,7 +647,6 @@ enum UnsafeOpKind {
|
|||
CallToUnsafeFunction(Option<DefId>),
|
||||
UseOfInlineAssembly,
|
||||
InitializingTypeWith,
|
||||
ConstructingTargetFeaturesType,
|
||||
UseOfMutableStatic,
|
||||
UseOfExternStatic,
|
||||
DerefOfRawPointer,
|
||||
|
|
@ -739,15 +728,6 @@ impl UnsafeOpKind {
|
|||
unsafe_not_inherited_note,
|
||||
},
|
||||
),
|
||||
ConstructingTargetFeaturesType => tcx.emit_node_span_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnInitializingTypeWithTargetFeatureRequiresUnsafe {
|
||||
span,
|
||||
unsafe_not_inherited_note,
|
||||
},
|
||||
),
|
||||
UseOfMutableStatic => tcx.emit_node_span_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
|
|
@ -905,20 +885,6 @@ impl UnsafeOpKind {
|
|||
unsafe_not_inherited_note,
|
||||
});
|
||||
}
|
||||
ConstructingTargetFeaturesType if unsafe_op_in_unsafe_fn_allowed => {
|
||||
dcx.emit_err(
|
||||
InitializingTypeWithTargetFeatureRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
span,
|
||||
unsafe_not_inherited_note,
|
||||
},
|
||||
);
|
||||
}
|
||||
ConstructingTargetFeaturesType => {
|
||||
dcx.emit_err(InitializingTypeWithTargetFeatureRequiresUnsafe {
|
||||
span,
|
||||
unsafe_not_inherited_note,
|
||||
});
|
||||
}
|
||||
UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
|
||||
dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -86,16 +86,6 @@ pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
|
|||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_target_feature_requires_unsafe, code = E0133)]
|
||||
#[note]
|
||||
pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithTargetFeatureRequiresUnsafe {
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe, code = E0133)]
|
||||
#[note]
|
||||
|
|
@ -260,17 +250,6 @@ pub(crate) struct InitializingTypeWithRequiresUnsafe {
|
|||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_initializing_type_with_target_feature_requires_unsafe, code = E0133)]
|
||||
#[note]
|
||||
pub(crate) struct InitializingTypeWithTargetFeatureRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
|
||||
|
|
@ -285,20 +264,6 @@ pub(crate) struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
|||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
mir_build_initializing_type_with_target_feature_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
|
||||
code = E0133
|
||||
)]
|
||||
#[note]
|
||||
pub(crate) struct InitializingTypeWithTargetFeatureRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub(crate) span: Span,
|
||||
#[subdiagnostic]
|
||||
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_mutable_static_requires_unsafe, code = E0133)]
|
||||
#[note]
|
||||
|
|
|
|||
|
|
@ -672,10 +672,6 @@ passes_should_be_applied_to_fn =
|
|||
*[false] not a function definition
|
||||
}
|
||||
|
||||
passes_should_be_applied_to_fn_or_unit_struct =
|
||||
attribute should be applied to a function definition or unit struct
|
||||
.label = not a function definition or a unit struct
|
||||
|
||||
passes_should_be_applied_to_static =
|
||||
attribute should be applied to a static
|
||||
.label = not a static
|
||||
|
|
|
|||
|
|
@ -747,35 +747,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Target::Field | Target::Arm | Target::MacroDef => {
|
||||
self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
|
||||
}
|
||||
Target::Struct if self.tcx.features().struct_target_features => {
|
||||
let ty = self.tcx.hir_node(hir_id).expect_item();
|
||||
match ty.kind {
|
||||
ItemKind::Struct(data, _) => {
|
||||
if data.fields().len() != 0 {
|
||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToFnOrUnitStruct {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("Target::Struct for a non-struct");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if self.tcx.features().struct_target_features {
|
||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToFnOrUnitStruct {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
} else {
|
||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
on_crate: hir_id == CRATE_HIR_ID,
|
||||
});
|
||||
}
|
||||
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
on_crate: hir_id == CRATE_HIR_ID,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,15 +82,6 @@ pub(crate) struct AttrShouldBeAppliedToFn {
|
|||
pub on_crate: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_should_be_applied_to_fn_or_unit_struct)]
|
||||
pub(crate) struct AttrShouldBeAppliedToFnOrUnitStruct {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_should_be_applied_to_fn, code = E0739)]
|
||||
pub(crate) struct TrackedCallerWrongLocation {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::mem;
|
|||
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
|
|
@ -120,8 +121,6 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
|
|||
|
||||
impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||
fn visit_item(&mut self, i: &'a Item) {
|
||||
debug!("visit_item: {:?}", i);
|
||||
|
||||
// Pick the def data. This need not be unique, but the more
|
||||
// information we encapsulate into, the better
|
||||
let mut opt_macro_data = None;
|
||||
|
|
@ -183,38 +182,51 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
|
||||
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
|
||||
match sig.header.coroutine_kind {
|
||||
Some(coroutine_kind) => {
|
||||
self.visit_generics(generics);
|
||||
match fn_kind {
|
||||
FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body)
|
||||
if let Some(coroutine_kind) = header.coroutine_kind =>
|
||||
{
|
||||
self.visit_fn_header(header);
|
||||
self.visit_generics(generics);
|
||||
|
||||
// For async functions, we need to create their inner defs inside of a
|
||||
// closure to match their desugared representation. Besides that,
|
||||
// we must mirror everything that `visit::walk_fn` below does.
|
||||
self.visit_fn_header(&sig.header);
|
||||
for param in &sig.decl.inputs {
|
||||
self.visit_param(param);
|
||||
}
|
||||
self.visit_fn_ret_ty(&sig.decl.output);
|
||||
// If this async fn has no body (i.e. it's an async fn signature in a trait)
|
||||
// then the closure_def will never be used, and we should avoid generating a
|
||||
// def-id for it.
|
||||
if let Some(body) = body {
|
||||
let closure_def = self.create_def(
|
||||
coroutine_kind.closure_id(),
|
||||
kw::Empty,
|
||||
DefKind::Closure,
|
||||
span,
|
||||
);
|
||||
self.with_parent(closure_def, |this| this.visit_block(body));
|
||||
}
|
||||
return;
|
||||
// For async functions, we need to create their inner defs inside of a
|
||||
// closure to match their desugared representation. Besides that,
|
||||
// we must mirror everything that `visit::walk_fn` below does.
|
||||
let FnDecl { inputs, output } = &**decl;
|
||||
for param in inputs {
|
||||
self.visit_param(param);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
visit::walk_fn(self, fn_kind);
|
||||
let (return_id, return_span) = coroutine_kind.return_id();
|
||||
let return_def =
|
||||
self.create_def(return_id, kw::Empty, DefKind::OpaqueTy, return_span);
|
||||
self.with_parent(return_def, |this| this.visit_fn_ret_ty(output));
|
||||
|
||||
// If this async fn has no body (i.e. it's an async fn signature in a trait)
|
||||
// then the closure_def will never be used, and we should avoid generating a
|
||||
// def-id for it.
|
||||
if let Some(body) = body {
|
||||
let closure_def = self.create_def(
|
||||
coroutine_kind.closure_id(),
|
||||
kw::Empty,
|
||||
DefKind::Closure,
|
||||
span,
|
||||
);
|
||||
self.with_parent(closure_def, |this| this.visit_block(body));
|
||||
}
|
||||
}
|
||||
FnKind::Closure(binder, Some(coroutine_kind), decl, body) => {
|
||||
self.visit_closure_binder(binder);
|
||||
visit::walk_fn_decl(self, decl);
|
||||
|
||||
// Async closures desugar to closures inside of closures, so
|
||||
// we must create two defs.
|
||||
let coroutine_def =
|
||||
self.create_def(coroutine_kind.closure_id(), kw::Empty, DefKind::Closure, span);
|
||||
self.with_parent(coroutine_def, |this| visit::walk_expr(this, body));
|
||||
}
|
||||
_ => visit::walk_fn(self, fn_kind),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
|
||||
|
|
@ -334,27 +346,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
|||
fn visit_expr(&mut self, expr: &'a Expr) {
|
||||
let parent_def = match expr.kind {
|
||||
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
|
||||
ExprKind::Closure(ref closure) => {
|
||||
// Async closures desugar to closures inside of closures, so
|
||||
// we must create two defs.
|
||||
let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
|
||||
match closure.coroutine_kind {
|
||||
Some(coroutine_kind) => {
|
||||
self.with_parent(closure_def, |this| {
|
||||
let coroutine_def = this.create_def(
|
||||
coroutine_kind.closure_id(),
|
||||
kw::Empty,
|
||||
DefKind::Closure,
|
||||
expr.span,
|
||||
);
|
||||
this.with_parent(coroutine_def, |this| visit::walk_expr(this, expr));
|
||||
});
|
||||
return;
|
||||
}
|
||||
None => closure_def,
|
||||
}
|
||||
}
|
||||
ExprKind::Gen(_, _, _, _) => {
|
||||
ExprKind::Closure(..) | ExprKind::Gen(..) => {
|
||||
self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span)
|
||||
}
|
||||
ExprKind::ConstBlock(ref constant) => {
|
||||
|
|
@ -381,6 +373,26 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
|||
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
|
||||
// Anonymous structs or unions are visited later after defined.
|
||||
TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
|
||||
TyKind::ImplTrait(id, _) => {
|
||||
// HACK: pprust breaks strings with newlines when the type
|
||||
// gets too long. We don't want these to show up in compiler
|
||||
// output or built artifacts, so replace them here...
|
||||
// Perhaps we should instead format APITs more robustly.
|
||||
let name = Symbol::intern(&pprust::ty_to_string(ty).replace('\n', " "));
|
||||
let kind = match self.impl_trait_context {
|
||||
ImplTraitContext::Universal => DefKind::TyParam,
|
||||
ImplTraitContext::Existential => DefKind::OpaqueTy,
|
||||
};
|
||||
let id = self.create_def(*id, name, kind, ty.span);
|
||||
match self.impl_trait_context {
|
||||
// Do not nest APIT, as we desugar them as `impl_trait: bounds`,
|
||||
// so the `impl_trait` node is not a parent to `bounds`.
|
||||
ImplTraitContext::Universal => visit::walk_ty(self, ty),
|
||||
ImplTraitContext::Existential => {
|
||||
self.with_parent(id, |this| visit::walk_ty(this, ty))
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => visit::walk_ty(self, ty),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1010,7 +1010,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
|
|||
this.in_func_body = previous_state;
|
||||
}
|
||||
}
|
||||
FnKind::Closure(binder, declaration, body) => {
|
||||
FnKind::Closure(binder, _, declaration, body) => {
|
||||
this.visit_closure_binder(binder);
|
||||
|
||||
this.with_lifetime_rib(
|
||||
|
|
@ -1557,14 +1557,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
if ident.name == kw::StaticLifetime {
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Static,
|
||||
LifetimeRes::Static { suppress_elision_warning: false },
|
||||
LifetimeElisionCandidate::Named,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ident.name == kw::UnderscoreLifetime {
|
||||
return self.resolve_anonymous_lifetime(lifetime, false);
|
||||
return self.resolve_anonymous_lifetime(lifetime, lifetime.id, false);
|
||||
}
|
||||
|
||||
let mut lifetime_rib_iter = self.lifetime_ribs.iter().rev();
|
||||
|
|
@ -1667,13 +1667,23 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) {
|
||||
fn resolve_anonymous_lifetime(
|
||||
&mut self,
|
||||
lifetime: &Lifetime,
|
||||
id_for_lint: NodeId,
|
||||
elided: bool,
|
||||
) {
|
||||
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
|
||||
|
||||
let kind =
|
||||
if elided { MissingLifetimeKind::Ampersand } else { MissingLifetimeKind::Underscore };
|
||||
let missing_lifetime =
|
||||
MissingLifetime { id: lifetime.id, span: lifetime.ident.span, kind, count: 1 };
|
||||
let missing_lifetime = MissingLifetime {
|
||||
id: lifetime.id,
|
||||
span: lifetime.ident.span,
|
||||
kind,
|
||||
count: 1,
|
||||
id_for_lint,
|
||||
};
|
||||
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
|
||||
for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
|
||||
debug!(?rib.kind);
|
||||
|
|
@ -1697,7 +1707,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
if lifetimes_in_scope.is_empty() {
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Static,
|
||||
// We are inside a const item, so do not warn.
|
||||
LifetimeRes::Static { suppress_elision_warning: true },
|
||||
elision_candidate,
|
||||
);
|
||||
return;
|
||||
|
|
@ -1800,7 +1811,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
|
||||
LifetimeElisionCandidate::Ignore,
|
||||
);
|
||||
self.resolve_anonymous_lifetime(<, true);
|
||||
self.resolve_anonymous_lifetime(<, anchor_id, true);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -1916,6 +1927,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
};
|
||||
let missing_lifetime = MissingLifetime {
|
||||
id: node_ids.start,
|
||||
id_for_lint: segment_id,
|
||||
span: elided_lifetime_span,
|
||||
kind,
|
||||
count: expected_lifetimes,
|
||||
|
|
@ -2039,8 +2051,44 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) {
|
||||
panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)")
|
||||
}
|
||||
|
||||
match candidate {
|
||||
LifetimeElisionCandidate::Missing(missing @ MissingLifetime { .. }) => {
|
||||
debug_assert_eq!(id, missing.id);
|
||||
match res {
|
||||
LifetimeRes::Static { suppress_elision_warning } => {
|
||||
if !suppress_elision_warning {
|
||||
self.r.lint_buffer.buffer_lint(
|
||||
lint::builtin::ELIDED_NAMED_LIFETIMES,
|
||||
missing.id_for_lint,
|
||||
missing.span,
|
||||
BuiltinLintDiag::ElidedIsStatic { elided: missing.span },
|
||||
);
|
||||
}
|
||||
}
|
||||
LifetimeRes::Param { param, binder: _ } => {
|
||||
let tcx = self.r.tcx();
|
||||
self.r.lint_buffer.buffer_lint(
|
||||
lint::builtin::ELIDED_NAMED_LIFETIMES,
|
||||
missing.id_for_lint,
|
||||
missing.span,
|
||||
BuiltinLintDiag::ElidedIsParam {
|
||||
elided: missing.span,
|
||||
param: (tcx.item_name(param.into()), tcx.source_span(param)),
|
||||
},
|
||||
);
|
||||
}
|
||||
LifetimeRes::Fresh { .. }
|
||||
| LifetimeRes::Infer
|
||||
| LifetimeRes::Error
|
||||
| LifetimeRes::ElidedAnchor { .. } => {}
|
||||
}
|
||||
}
|
||||
LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {}
|
||||
}
|
||||
|
||||
match res {
|
||||
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
|
||||
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static { .. } => {
|
||||
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
|
||||
candidates.push((res, candidate));
|
||||
}
|
||||
|
|
@ -2558,9 +2606,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
|
||||
ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
|
||||
self.with_static_rib(def_kind, |this| {
|
||||
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
|
||||
this.visit_ty(ty);
|
||||
});
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::Elided(LifetimeRes::Static {
|
||||
suppress_elision_warning: true,
|
||||
}),
|
||||
|this| {
|
||||
this.visit_ty(ty);
|
||||
},
|
||||
);
|
||||
if let Some(expr) = expr {
|
||||
// We already forbid generic params because of the above item rib,
|
||||
// so it doesn't matter whether this is a trivial constant.
|
||||
|
|
@ -2589,7 +2642,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
this.visit_generics(generics);
|
||||
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::Elided(LifetimeRes::Static),
|
||||
LifetimeRibKind::Elided(LifetimeRes::Static {
|
||||
suppress_elision_warning: true,
|
||||
}),
|
||||
|this| this.visit_ty(ty),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,13 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
|
|||
pub(super) struct MissingLifetime {
|
||||
/// Used to overwrite the resolution with the suggestion, to avoid cascading errors.
|
||||
pub id: NodeId,
|
||||
/// As we cannot yet emit lints in this crate and have to buffer them instead,
|
||||
/// we need to associate each lint with some `NodeId`,
|
||||
/// however for some `MissingLifetime`s their `NodeId`s are "fake",
|
||||
/// in a sense that they are temporary and not get preserved down the line,
|
||||
/// which means that the lints for those nodes will not get emitted.
|
||||
/// To combat this, we can try to use some other `NodeId`s as a fallback option.
|
||||
pub id_for_lint: NodeId,
|
||||
/// Where to suggest adding the lifetime.
|
||||
pub span: Span,
|
||||
/// How the lifetime was introduced, to have the correct space and comma.
|
||||
|
|
@ -3028,7 +3035,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
maybe_static = true;
|
||||
in_scope_lifetimes = vec![(
|
||||
Ident::with_dummy_span(kw::StaticLifetime),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
|
||||
)];
|
||||
}
|
||||
} else if elided_len == 0 {
|
||||
|
|
@ -3040,7 +3047,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
maybe_static = true;
|
||||
in_scope_lifetimes = vec![(
|
||||
Ident::with_dummy_span(kw::StaticLifetime),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
|
||||
)];
|
||||
}
|
||||
} else if num_params == 1 {
|
||||
|
|
|
|||
|
|
@ -1858,7 +1858,6 @@ symbols! {
|
|||
stringify,
|
||||
struct_field_attributes,
|
||||
struct_inherit,
|
||||
struct_target_features,
|
||||
struct_variant,
|
||||
structural_match,
|
||||
structural_peq,
|
||||
|
|
|
|||
|
|
@ -1837,6 +1837,7 @@ supported_targets! {
|
|||
|
||||
("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
|
||||
|
||||
("aarch64-unknown-nto-qnx700", aarch64_unknown_nto_qnx700),
|
||||
("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx710),
|
||||
("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710),
|
||||
("i586-pc-nto-qnx700", i586_pc_nto_qnx700),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
use crate::spec::{base, Cc, LinkerFlavor, Lld, Target, TargetOptions};
|
||||
|
||||
pub fn target() -> Target {
|
||||
// In QNX, libc does not provide a compatible ABI between versions.
|
||||
// To distinguish between QNX versions, we needed a stable conditional compilation switch,
|
||||
// which is why we needed to implement different targets in the compiler.
|
||||
Target {
|
||||
llvm_target: "aarch64-unknown-unknown".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("ARM64 QNX Neutrino 7.0 RTOS".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
// from: https://llvm.org/docs/LangRef.html#data-layout
|
||||
// e = little endian
|
||||
// m:e = ELF mangling: Private symbols get a .L prefix
|
||||
// i8:8:32 = 8-bit-integer, minimum_alignment=8, preferred_alignment=32
|
||||
// i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32
|
||||
// i64:64 = 64-bit-integer, minimum_alignment=64, preferred_alignment=64
|
||||
// i128:128 = 128-bit-integer, minimum_alignment=128, preferred_alignment=128
|
||||
// n32:64 = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently.
|
||||
// S128 = 128 bits are the natural alignment of the stack in bits.
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
features: "+v8a".into(),
|
||||
max_atomic_width: Some(128),
|
||||
pre_link_args: TargetOptions::link_args(
|
||||
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
&["-Vgcc_ntoaarch64le_cxx"],
|
||||
),
|
||||
env: "nto70".into(),
|
||||
..base::nto_qnx::opts()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,8 @@
|
|||
use crate::spec::{base, Cc, LinkerFlavor, Lld, Target, TargetOptions};
|
||||
use crate::spec::Target;
|
||||
|
||||
pub fn target() -> Target {
|
||||
Target {
|
||||
llvm_target: "aarch64-unknown-unknown".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("ARM64 QNX Neutrino 7.1 RTOS".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
// from: https://llvm.org/docs/LangRef.html#data-layout
|
||||
// e = little endian
|
||||
// m:e = ELF mangling: Private symbols get a .L prefix
|
||||
// i8:8:32 = 8-bit-integer, minimum_alignment=8, preferred_alignment=32
|
||||
// i16:16:32 = 16-bit-integer, minimum_alignment=16, preferred_alignment=32
|
||||
// i64:64 = 64-bit-integer, minimum_alignment=64, preferred_alignment=64
|
||||
// i128:128 = 128-bit-integer, minimum_alignment=128, preferred_alignment=128
|
||||
// n32:64 = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently.
|
||||
// S128 = 128 bits are the natural alignment of the stack in bits.
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: "aarch64".into(),
|
||||
options: TargetOptions {
|
||||
features: "+v8a".into(),
|
||||
max_atomic_width: Some(128),
|
||||
pre_link_args: TargetOptions::link_args(
|
||||
LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||
&["-Vgcc_ntoaarch64le_cxx"],
|
||||
),
|
||||
env: "nto71".into(),
|
||||
..base::nto_qnx::opts()
|
||||
},
|
||||
}
|
||||
let mut base = super::aarch64_unknown_nto_qnx700::target();
|
||||
base.metadata.description = Some("ARM64 QNX Neutrino 7.1 RTOS".into());
|
||||
base.options.env = "nto71".into();
|
||||
base
|
||||
}
|
||||
|
|
|
|||
|
|
@ -439,8 +439,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
|
||||
*leaf_trait_ref.skip_binder().self_ty().kind()
|
||||
{
|
||||
// FIXME(struct_target_features): should a function that inherits
|
||||
// target_features through arguments implement Fn traits?
|
||||
!self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -546,8 +546,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
|
||||
ty::FnDef(def_id, args) => {
|
||||
let tcx = self.tcx();
|
||||
// FIXME(struct_target_features): should a function that inherits target_features
|
||||
// through an argument implement Fn traits?
|
||||
if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
|
||||
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ codegen-units = 10000
|
|||
# helps to improve link times a little bit.
|
||||
[profile.release.package]
|
||||
addr2line.debug = 0
|
||||
addr2line.opt-level = "s"
|
||||
adler.debug = 0
|
||||
gimli.debug = 0
|
||||
gimli.opt-level = "s"
|
||||
miniz_oxide.debug = 0
|
||||
object.debug = 0
|
||||
rustc-demangle.debug = 0
|
||||
|
|
|
|||
|
|
@ -372,6 +372,7 @@ extern "Rust" {
|
|||
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
|
||||
#[cfg(all(not(no_global_oom_handling), not(test)))]
|
||||
#[cold]
|
||||
#[optimize(size)]
|
||||
pub const fn handle_alloc_error(layout: Layout) -> ! {
|
||||
const fn ct_error(_: Layout) -> ! {
|
||||
panic!("allocation failed");
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@
|
|||
#![feature(multiple_supertrait_upcastable)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
#![feature(optimize_attribute)]
|
||||
#![feature(rustc_allow_const_fn_unstable)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(slice_internals)]
|
||||
|
|
|
|||
|
|
@ -782,6 +782,7 @@ where
|
|||
// Central function for reserve error handling.
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[cold]
|
||||
#[optimize(size)]
|
||||
fn handle_error(e: TryReserveError) -> ! {
|
||||
match e.kind() {
|
||||
CapacityOverflow => capacity_overflow(),
|
||||
|
|
|
|||
|
|
@ -2313,7 +2313,7 @@ impl<'b> Pattern for &'b String {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&str>
|
||||
fn strip_suffix_of<'a>(self, haystack: &'a str) -> Option<&'a str>
|
||||
where
|
||||
Self::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1519,6 +1519,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[cold]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[track_caller]
|
||||
#[optimize(size)]
|
||||
fn assert_failed(index: usize, len: usize) -> ! {
|
||||
panic!("swap_remove index (is {index}) should be < len (is {len})");
|
||||
}
|
||||
|
|
@ -1567,6 +1568,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[cold]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[track_caller]
|
||||
#[optimize(size)]
|
||||
fn assert_failed(index: usize, len: usize) -> ! {
|
||||
panic!("insertion index (is {index}) should be <= len (is {len})");
|
||||
}
|
||||
|
|
@ -1629,6 +1631,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[cold]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[track_caller]
|
||||
#[optimize(size)]
|
||||
fn assert_failed(index: usize, len: usize) -> ! {
|
||||
panic!("removal index (is {index}) should be < len (is {len})");
|
||||
}
|
||||
|
|
@ -2317,6 +2320,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
#[cold]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||
#[track_caller]
|
||||
#[optimize(size)]
|
||||
fn assert_failed(at: usize, len: usize) -> ! {
|
||||
panic!("`at` split index (is {at}) should be <= len (is {len})");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ pub const fn from_u32(i: u32) -> Option<char> {
|
|||
self::convert::from_u32(i)
|
||||
}
|
||||
|
||||
/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`].
|
||||
/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]
|
||||
/// instead.
|
||||
#[stable(feature = "char_from_unchecked", since = "1.5.0")]
|
||||
#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "1.81.0")]
|
||||
|
|
|
|||
|
|
@ -110,43 +110,43 @@ impl<'a> Argument<'a> {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, Display::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_debug<'b, T: Debug>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, Debug::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_debug_noop<'b, T: Debug>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, |_, _| Ok(()))
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_octal<'b, T: Octal>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, Octal::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_lower_hex<'b, T: LowerHex>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, LowerHex::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_upper_hex<'b, T: UpperHex>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, UpperHex::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_pointer<'b, T: Pointer>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, Pointer::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_binary<'b, T: Binary>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, Binary::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_lower_exp<'b, T: LowerExp>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, LowerExp::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'_> {
|
||||
pub fn new_upper_exp<'b, T: UpperExp>(x: &'b T) -> Argument<'b> {
|
||||
Self::new(x, UpperExp::fmt)
|
||||
}
|
||||
#[inline(always)]
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@
|
|||
#![feature(never_type)]
|
||||
#![feature(no_core)]
|
||||
#![feature(no_sanitize)]
|
||||
#![feature(optimize_attribute)]
|
||||
#![feature(prelude_import)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(rustc_allow_const_fn_unstable)]
|
||||
|
|
|
|||
|
|
@ -112,18 +112,18 @@ impl<'a> Parser<'a> {
|
|||
max_digits: Option<usize>,
|
||||
allow_zero_prefix: bool,
|
||||
) -> Option<T> {
|
||||
// If max_digits.is_some(), then we are parsing a `u8` or `u16` and
|
||||
// don't need to use checked arithmetic since it fits within a `u32`.
|
||||
if let Some(max_digits) = max_digits {
|
||||
// u32::MAX = 4_294_967_295u32, which is 10 digits long.
|
||||
// `max_digits` must be less than 10 to not overflow a `u32`.
|
||||
debug_assert!(max_digits < 10);
|
||||
self.read_atomically(move |p| {
|
||||
let mut digit_count = 0;
|
||||
let has_leading_zero = p.peek_char() == Some('0');
|
||||
|
||||
// If max_digits.is_some(), then we are parsing a `u8` or `u16` and
|
||||
// don't need to use checked arithmetic since it fits within a `u32`.
|
||||
let result = if let Some(max_digits) = max_digits {
|
||||
// u32::MAX = 4_294_967_295u32, which is 10 digits long.
|
||||
// `max_digits` must be less than 10 to not overflow a `u32`.
|
||||
debug_assert!(max_digits < 10);
|
||||
|
||||
self.read_atomically(move |p| {
|
||||
let mut result = 0_u32;
|
||||
let mut digit_count = 0;
|
||||
let has_leading_zero = p.peek_char() == Some('0');
|
||||
|
||||
while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
|
||||
result *= radix;
|
||||
result += digit;
|
||||
|
|
@ -134,19 +134,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if digit_count == 0 {
|
||||
None
|
||||
} else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
|
||||
None
|
||||
} else {
|
||||
result.try_into().ok()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.read_atomically(move |p| {
|
||||
result.try_into().ok()
|
||||
} else {
|
||||
let mut result = T::ZERO;
|
||||
let mut digit_count = 0;
|
||||
let has_leading_zero = p.peek_char() == Some('0');
|
||||
|
||||
while let Some(digit) = p.read_atomically(|p| p.read_char()?.to_digit(radix)) {
|
||||
result = result.checked_mul(radix)?;
|
||||
|
|
@ -154,15 +144,17 @@ impl<'a> Parser<'a> {
|
|||
digit_count += 1;
|
||||
}
|
||||
|
||||
if digit_count == 0 {
|
||||
None
|
||||
} else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
|
||||
None
|
||||
} else {
|
||||
Some(result)
|
||||
}
|
||||
})
|
||||
}
|
||||
Some(result)
|
||||
};
|
||||
|
||||
if digit_count == 0 {
|
||||
None
|
||||
} else if !allow_zero_prefix && has_leading_zero && digit_count > 1 {
|
||||
None
|
||||
} else {
|
||||
result
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Reads an IPv4 address.
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
|
|||
panic_fmt(format_args!("{}", *x));
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
|
||||
|
|
@ -276,7 +276,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
|
|||
panic!("index out of bounds: the len is {len} but the index is {index}")
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref
|
||||
|
|
@ -301,7 +301,7 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
|
|||
///
|
||||
/// This function is called directly by the codegen backend, and must not have
|
||||
/// any extra arguments (including those synthesized by track_caller).
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[lang = "panic_cannot_unwind"] // needed by codegen for panic in nounwind function
|
||||
#[rustc_nounwind]
|
||||
|
|
@ -317,7 +317,7 @@ fn panic_cannot_unwind() -> ! {
|
|||
///
|
||||
/// This function is called directly by the codegen backend, and must not have
|
||||
/// any extra arguments (including those synthesized by track_caller).
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function
|
||||
#[rustc_nounwind]
|
||||
|
|
@ -350,7 +350,7 @@ pub enum AssertKind {
|
|||
}
|
||||
|
||||
/// Internal function for `assert_eq!` and `assert_ne!` macros
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[doc(hidden)]
|
||||
|
|
@ -368,7 +368,7 @@ where
|
|||
}
|
||||
|
||||
/// Internal function for `assert_match!`
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[doc(hidden)]
|
||||
|
|
@ -388,7 +388,7 @@ pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
|
|||
}
|
||||
|
||||
/// Non-generic version of the above functions, to avoid code bloat.
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
fn assert_failed_inner(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
use super::{from_raw_parts, memchr};
|
||||
use crate::cmp::{self, BytewiseEq, Ordering};
|
||||
use crate::intrinsics::compare_bytes;
|
||||
use crate::mem;
|
||||
use crate::num::NonZero;
|
||||
use crate::{ascii, mem};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T, U> PartialEq<[U]> for [T]
|
||||
|
|
@ -182,19 +183,41 @@ impl<A: Ord> SliceOrd for A {
|
|||
}
|
||||
}
|
||||
|
||||
// `compare_bytes` compares a sequence of unsigned bytes lexicographically.
|
||||
// this matches the order we want for [u8], but no others (not even [i8]).
|
||||
impl SliceOrd for u8 {
|
||||
/// Marks that a type should be treated as an unsigned byte for comparisons.
|
||||
///
|
||||
/// # Safety
|
||||
/// * The type must be readable as an `u8`, meaning it has to have the same
|
||||
/// layout as `u8` and always be initialized.
|
||||
/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
|
||||
/// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
|
||||
#[rustc_specialization_trait]
|
||||
unsafe trait UnsignedBytewiseOrd {}
|
||||
|
||||
unsafe impl UnsignedBytewiseOrd for bool {}
|
||||
unsafe impl UnsignedBytewiseOrd for u8 {}
|
||||
unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
|
||||
unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
|
||||
unsafe impl UnsignedBytewiseOrd for ascii::Char {}
|
||||
|
||||
// `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
|
||||
// use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
|
||||
impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
|
||||
#[inline]
|
||||
fn compare(left: &[Self], right: &[Self]) -> Ordering {
|
||||
// Since the length of a slice is always less than or equal to isize::MAX, this never underflows.
|
||||
// Since the length of a slice is always less than or equal to
|
||||
// isize::MAX, this never underflows.
|
||||
let diff = left.len() as isize - right.len() as isize;
|
||||
// This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags.
|
||||
// This comparison gets optimized away (on x86_64 and ARM) because the
|
||||
// subtraction updates flags.
|
||||
let len = if left.len() < right.len() { left.len() } else { right.len() };
|
||||
// SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
|
||||
// We use the minimum of both lengths which guarantees that both regions are
|
||||
// valid for reads in that interval.
|
||||
let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
|
||||
let left = left.as_ptr().cast();
|
||||
let right = right.as_ptr().cast();
|
||||
// SAFETY: `left` and `right` are references and are thus guaranteed to
|
||||
// be valid. `UnsignedBytewiseOrd` is only implemented for types that
|
||||
// are valid u8s and can be compared the same way. We use the minimum
|
||||
// of both lengths which guarantees that both regions are valid for
|
||||
// reads in that interval.
|
||||
let mut order = unsafe { compare_bytes(left, right, len) as isize };
|
||||
if order == 0 {
|
||||
order = diff;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
|
|||
addr2line = { version = "0.22.0", optional = true, default-features = false }
|
||||
|
||||
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
|
||||
libc = { version = "0.2.153", default-features = false, features = [
|
||||
libc = { version = "0.2.156", default-features = false, features = [
|
||||
'rustc-dep-of-std',
|
||||
], public = true }
|
||||
|
||||
|
|
|
|||
|
|
@ -306,10 +306,12 @@
|
|||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
#![feature(no_sanitize)]
|
||||
#![feature(optimize_attribute)]
|
||||
#![feature(prelude_import)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(thread_local)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ where
|
|||
}
|
||||
|
||||
/// The default panic handler.
|
||||
#[optimize(size)]
|
||||
fn default_hook(info: &PanicHookInfo<'_>) {
|
||||
// If this is a double panic, make sure that we print a backtrace
|
||||
// for this panic. Otherwise only print it if logging is enabled.
|
||||
|
|
@ -249,7 +250,8 @@ fn default_hook(info: &PanicHookInfo<'_>) {
|
|||
let thread = thread::try_current();
|
||||
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
|
||||
|
||||
let write = |err: &mut dyn crate::io::Write| {
|
||||
let write = #[optimize(size)]
|
||||
|err: &mut dyn crate::io::Write| {
|
||||
// Use a lock to prevent mixed output in multithreading context.
|
||||
// Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows.
|
||||
let mut lock = backtrace::lock();
|
||||
|
|
@ -527,6 +529,7 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
|
|||
// optimizer (in most cases this function is not inlined even as a normal,
|
||||
// non-cold function, though, as of the writing of this comment).
|
||||
#[cold]
|
||||
#[optimize(size)]
|
||||
unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
|
||||
// SAFETY: The whole unsafe block hinges on a correct implementation of
|
||||
// the panic handler `__rust_panic_cleanup`. As such we can only
|
||||
|
|
@ -686,7 +689,7 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
|
|||
// lang item for CTFE panic support
|
||||
// never inline unless panic_immediate_abort to avoid code
|
||||
// bloat at the call sites as much as possible
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
|
||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))]
|
||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||
#[track_caller]
|
||||
#[rustc_do_not_const_check] // hooked by const-eval
|
||||
|
|
@ -756,6 +759,7 @@ fn payload_as_str(payload: &dyn Any) -> &str {
|
|||
/// Executes the primary logic for a panic, including checking for recursive
|
||||
/// panics, panic hooks, and finally dispatching to the panic runtime to either
|
||||
/// abort or unwind.
|
||||
#[optimize(size)]
|
||||
fn rust_panic_with_hook(
|
||||
payload: &mut dyn PanicPayload,
|
||||
location: &Location<'_>,
|
||||
|
|
|
|||
|
|
@ -498,6 +498,7 @@ impl<T> OnceLock<T> {
|
|||
}
|
||||
|
||||
#[cold]
|
||||
#[optimize(size)]
|
||||
fn initialize<F, E>(&self, f: F) -> Result<(), E>
|
||||
where
|
||||
F: FnOnce() -> Result<T, E>,
|
||||
|
|
|
|||
|
|
@ -1717,7 +1717,7 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
|
|||
run_path_with_cstr(original, &|original| {
|
||||
run_path_with_cstr(link, &|link| {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
|
||||
if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nto"))] {
|
||||
// VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves
|
||||
// it implementation-defined whether `link` follows symlinks, so rely on the
|
||||
// `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ use crate::sys::process::process_common::*;
|
|||
use crate::{fmt, mem, sys};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(target_os = "nto", target_env = "nto71"))] {
|
||||
// This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0
|
||||
if #[cfg(any(target_env = "nto70", target_env = "nto71"))] {
|
||||
use crate::thread;
|
||||
use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
|
||||
use crate::time::Duration;
|
||||
|
|
@ -189,7 +190,8 @@ impl Command {
|
|||
#[cfg(not(any(
|
||||
target_os = "watchos",
|
||||
target_os = "tvos",
|
||||
all(target_os = "nto", target_env = "nto71"),
|
||||
target_env = "nto70",
|
||||
target_env = "nto71"
|
||||
)))]
|
||||
unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
|
||||
cvt(libc::fork())
|
||||
|
|
@ -199,7 +201,8 @@ impl Command {
|
|||
// or closed a file descriptor while the fork() was occurring".
|
||||
// Documentation says "... or try calling fork() again". This is what we do here.
|
||||
// See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
|
||||
#[cfg(all(target_os = "nto", target_env = "nto71"))]
|
||||
// This workaround is only needed for QNX 7.0 and 7.1. The bug should have been fixed in 8.0
|
||||
#[cfg(any(target_env = "nto70", target_env = "nto71"))]
|
||||
unsafe fn do_fork(&mut self) -> Result<pid_t, io::Error> {
|
||||
use crate::sys::os::errno;
|
||||
|
||||
|
|
@ -537,7 +540,7 @@ impl Command {
|
|||
// or closed a file descriptor while the posix_spawn() was occurring".
|
||||
// Documentation says "... or try calling posix_spawn() again". This is what we do here.
|
||||
// See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
|
||||
#[cfg(all(target_os = "nto", target_env = "nto71"))]
|
||||
#[cfg(target_os = "nto")]
|
||||
unsafe fn retrying_libc_posix_spawnp(
|
||||
pid: *mut pid_t,
|
||||
file: *const c_char,
|
||||
|
|
|
|||
|
|
@ -165,8 +165,15 @@ extern "C" {}
|
|||
extern "C" {}
|
||||
|
||||
#[cfg(target_os = "nto")]
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_env = "nto70")] {
|
||||
#[link(name = "gcc")]
|
||||
extern "C" {}
|
||||
} else {
|
||||
#[link(name = "gcc_s")]
|
||||
extern "C" {}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "hurd")]
|
||||
#[link(name = "gcc_s")]
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ target | std | host | notes
|
|||
[`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3
|
||||
[`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon
|
||||
[`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? | | ARM64 TEEOS |
|
||||
[`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS |
|
||||
[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS |
|
||||
`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
|
||||
[`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ Currently, the following QNX Neutrino versions and compilation targets are suppo
|
|||
|----------------------|---------------------|:------------:|:----------------:|
|
||||
| 7.1 | AArch64 | ✓ | ✓ |
|
||||
| 7.1 | x86_64 | ✓ | ✓ |
|
||||
| 7.0 | AArch64 | ? | ✓ |
|
||||
| 7.0 | x86 | | ✓ |
|
||||
|
||||
Adding other architectures that are supported by QNX Neutrino is possible.
|
||||
|
|
@ -43,6 +44,23 @@ When linking `no_std` applications, they must link against `libc.so` (see exampl
|
|||
required because applications always link against the `crt` library and `crt` depends on `libc.so`.
|
||||
This is done automatically when using the standard library.
|
||||
|
||||
### Disabling RELocation Read-Only (RELRO)
|
||||
|
||||
While not recommended by default, some QNX kernel setups may require the `RELRO` to be disabled with `-C relro_level=off`, e.g. by adding it to the `.cargo/config.toml` file:
|
||||
|
||||
```toml
|
||||
[target.aarch64-unknown-nto-qnx700]
|
||||
rustflags = ["-C", "relro_level=off"]
|
||||
```
|
||||
|
||||
If your QNX kernel does not allow it, and `relro` is not disabled, running compiled binary would fail with `syntax error: ... unexpected` or similar. This is due to kernel trying to interpret compiled binary with `/bin/sh`, and obviously failing. To verify that this is really the case, run your binary with the `DL_DEBUG=all` env var, and look for this output. If you see it, you should disable `relro` as described above.
|
||||
|
||||
```text
|
||||
Resolution scope for Executable->/bin/sh:
|
||||
Executable->/bin/sh
|
||||
libc.so.4->/usr/lib/ldqnx-64.so.2
|
||||
```
|
||||
|
||||
### Small example application
|
||||
|
||||
Small `no_std` example is shown below. Applications using the standard library work as well.
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
# `struct_target_features`
|
||||
|
||||
The tracking issue for this feature is: [#129107]
|
||||
|
||||
[#129107]: https://github.com/rust-lang/rust/issues/129107
|
||||
|
||||
------------------------
|
||||
|
|
@ -1,3 +1,14 @@
|
|||
error: elided lifetime has a name
|
||||
--> tests/ui/needless_lifetimes.rs:266:52
|
||||
|
|
||||
LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
|
||||
= note: `-D elided-named-lifetimes` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
|
||||
|
||||
error: the following explicit lifetimes could be elided: 'a, 'b
|
||||
--> tests/ui/needless_lifetimes.rs:17:23
|
||||
|
|
||||
|
|
@ -553,5 +564,5 @@ LL - fn one_input<'a>(x: &'a u8) -> &'a u8 {
|
|||
LL + fn one_input(x: &u8) -> &u8 {
|
||||
|
|
||||
|
||||
error: aborting due to 46 previous errors
|
||||
error: aborting due to 47 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
error: elided lifetime has a name
|
||||
--> tests/ui/ptr_arg.rs:295:56
|
||||
|
|
||||
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `-D elided-named-lifetimes` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
|
||||
|
||||
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
|
||||
--> tests/ui/ptr_arg.rs:13:14
|
||||
|
|
||||
|
|
@ -212,5 +221,5 @@ error: using a reference to `Cow` is not recommended
|
|||
LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
|
||||
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
|
||||
|
||||
error: aborting due to 24 previous errors
|
||||
error: aborting due to 25 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: Undefined Behavior: reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
|
||||
--> RUSTLIB/core/src/slice/cmp.rs:LL:CC
|
||||
|
|
||||
LL | let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
|
||||
LL | let mut order = unsafe { compare_bytes(left, right, len) as isize };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
|
||||
--> RUSTLIB/core/src/slice/cmp.rs:LL:CC
|
||||
|
|
||||
LL | let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
|
||||
LL | let mut order = unsafe { compare_bytes(left, right, len) as isize };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ impl Attrs {
|
|||
}
|
||||
|
||||
impl Attrs {
|
||||
pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'_> {
|
||||
pub fn by_key<'attrs>(&'attrs self, key: &'attrs Symbol) -> AttrQuery<'attrs> {
|
||||
AttrQuery { attrs: self, key }
|
||||
}
|
||||
|
||||
|
|
@ -594,7 +594,7 @@ impl<'attr> AttrQuery<'attr> {
|
|||
/// #[doc(html_root_url = "url")]
|
||||
/// ^^^^^^^^^^^^^ key
|
||||
/// ```
|
||||
pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&str> {
|
||||
pub fn find_string_value_in_tt(self, key: &'attr Symbol) -> Option<&'attr str> {
|
||||
self.tt_values().find_map(|tt| {
|
||||
let name = tt.token_trees.iter()
|
||||
.skip_while(|tt| !matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym, ..} )) if *sym == *key))
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ impl Body {
|
|||
pub fn blocks<'a>(
|
||||
&'a self,
|
||||
db: &'a dyn DefDatabase,
|
||||
) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ {
|
||||
) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + 'a {
|
||||
self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
//@ compile-flags: -O
|
||||
//@ assembly-output: emit-asm
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(struct_target_features)]
|
||||
|
||||
// Check that a struct_target_features type causes the compiler to effectively inline intrinsics.
|
||||
|
||||
use std::arch::x86_64::*;
|
||||
|
||||
#[target_feature(enable = "avx")]
|
||||
struct Avx {}
|
||||
|
||||
#[target_feature(enable = "fma")]
|
||||
struct Fma {}
|
||||
|
||||
pub fn add_simple(_: Avx, v: __m256) -> __m256 {
|
||||
// CHECK-NOT: call
|
||||
// CHECK: vaddps
|
||||
unsafe { _mm256_add_ps(v, v) }
|
||||
}
|
||||
|
||||
pub fn add_complex_type(_: (&Avx, ()), v: __m256) -> __m256 {
|
||||
// CHECK-NOT: call
|
||||
// CHECK: vaddps
|
||||
unsafe { _mm256_add_ps(v, v) }
|
||||
}
|
||||
|
||||
pub fn add_fma_combined(_: (&Avx, &Fma), v: __m256) -> (__m256, __m256) {
|
||||
// CHECK-NOT: call
|
||||
// CHECK-DAG: vaddps
|
||||
let r1 = unsafe { _mm256_add_ps(v, v) };
|
||||
// CHECK-DAG: vfmadd213ps
|
||||
let r2 = unsafe { _mm256_fmadd_ps(v, v, v) };
|
||||
(r1, r2)
|
||||
}
|
||||
|
|
@ -54,6 +54,9 @@
|
|||
//@ revisions: aarch64_unknown_none_softfloat
|
||||
//@ [aarch64_unknown_none_softfloat] compile-flags: --target aarch64-unknown-none-softfloat
|
||||
//@ [aarch64_unknown_none_softfloat] needs-llvm-components: aarch64
|
||||
//@ revisions: aarch64_unknown_nto_qnx700
|
||||
//@ [aarch64_unknown_nto_qnx700] compile-flags: --target aarch64-unknown-nto-qnx700
|
||||
//@ [aarch64_unknown_nto_qnx700] needs-llvm-components: aarch64
|
||||
//@ revisions: aarch64_unknown_nto_qnx710
|
||||
//@ [aarch64_unknown_nto_qnx710] compile-flags: --target aarch64-unknown-nto-qnx710
|
||||
//@ [aarch64_unknown_nto_qnx710] needs-llvm-components: aarch64
|
||||
|
|
|
|||
8
tests/crashes/117460.rs
Normal file
8
tests/crashes/117460.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//@ known-bug: #117460
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
struct Matrix<D = [(); 2 + 2]> {
|
||||
d: D,
|
||||
}
|
||||
|
||||
impl Matrix {}
|
||||
48
tests/crashes/119095.rs
Normal file
48
tests/crashes/119095.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
//@ known-bug: #119095
|
||||
//@ compile-flags: --edition=2021
|
||||
|
||||
fn any<T>() -> T {
|
||||
loop {}
|
||||
}
|
||||
|
||||
trait Acquire {
|
||||
type Connection;
|
||||
}
|
||||
|
||||
impl Acquire for &'static () {
|
||||
type Connection = ();
|
||||
}
|
||||
|
||||
trait Unit {}
|
||||
impl Unit for () {}
|
||||
|
||||
fn get_connection<T>() -> impl Unit
|
||||
where
|
||||
T: Acquire,
|
||||
T::Connection: Unit,
|
||||
{
|
||||
any::<T::Connection>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let future = async { async { get_connection::<&'static ()>() }.await };
|
||||
|
||||
future.resolve_me();
|
||||
}
|
||||
|
||||
trait ResolveMe {
|
||||
fn resolve_me(self);
|
||||
}
|
||||
|
||||
impl<S> ResolveMe for S
|
||||
where
|
||||
(): CheckSend<S>,
|
||||
{
|
||||
fn resolve_me(self) {}
|
||||
}
|
||||
|
||||
trait CheckSend<F> {}
|
||||
impl<F> CheckSend<F> for () where F: Send {}
|
||||
|
||||
trait NeverImplemented {}
|
||||
impl<E, F> CheckSend<F> for E where E: NeverImplemented {}
|
||||
15
tests/crashes/126443.rs
Normal file
15
tests/crashes/126443.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//@ known-bug: #126443
|
||||
//@ compile-flags: -Copt-level=0
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
fn double_up<const M: usize>() -> [(); M * 2] {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn quadruple_up<const N: usize>() -> [(); N * 2 * 2] {
|
||||
double_up()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
quadruple_up::<0>();
|
||||
}
|
||||
6
tests/crashes/128097.rs
Normal file
6
tests/crashes/128097.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//@ known-bug: #128097
|
||||
#![feature(explicit_tail_calls)]
|
||||
fn f(x: &mut ()) {
|
||||
let _y: String;
|
||||
become f(x);
|
||||
}
|
||||
|
|
@ -8,22 +8,22 @@
|
|||
// gdb-command:run
|
||||
|
||||
// gdb-command:print some
|
||||
// gdb-check:$1 = core::option::Option<&u32>::Some(0x12345678)
|
||||
// gdb-check:$1 = core::option::Option<&u32>::Some(0x[...])
|
||||
|
||||
// gdb-command:print none
|
||||
// gdb-check:$2 = core::option::Option<&u32>::None
|
||||
|
||||
// gdb-command:print full
|
||||
// gdb-check:$3 = option_like_enum::MoreFields::Full(454545, 0x87654321, 9988)
|
||||
// gdb-check:$3 = option_like_enum::MoreFields::Full(454545, 0x[...], 9988)
|
||||
|
||||
// gdb-command:print empty_gdb.discr
|
||||
// gdb-check:$4 = (*mut isize) 0x1
|
||||
// gdb-command:print empty
|
||||
// gdb-check:$4 = option_like_enum::MoreFields::Empty
|
||||
|
||||
// gdb-command:print droid
|
||||
// gdb-check:$5 = option_like_enum::NamedFields::Droid{id: 675675, range: 10000001, internals: 0x43218765}
|
||||
// gdb-check:$5 = option_like_enum::NamedFields::Droid{id: 675675, range: 10000001, internals: 0x[...]}
|
||||
|
||||
// gdb-command:print void_droid_gdb.internals
|
||||
// gdb-check:$6 = (*mut isize) 0x1
|
||||
// gdb-command:print void_droid
|
||||
// gdb-check:$6 = option_like_enum::NamedFields::Void
|
||||
|
||||
// gdb-command:print nested_non_zero_yep
|
||||
// gdb-check:$7 = option_like_enum::NestedNonZero::Yep(10.5, option_like_enum::NestedNonZeroField {a: 10, b: 20, c: 0x[...]})
|
||||
|
|
@ -39,19 +39,19 @@
|
|||
// lldb-command:run
|
||||
|
||||
// lldb-command:v some
|
||||
// lldb-check:[...] Some(&0x12345678)
|
||||
// lldb-check:[...] Some(&0x[...])
|
||||
|
||||
// lldb-command:v none
|
||||
// lldb-check:[...] None
|
||||
|
||||
// lldb-command:v full
|
||||
// lldb-check:[...] Full(454545, &0x87654321, 9988)
|
||||
// lldb-check:[...] Full(454545, &0x[...], 9988)
|
||||
|
||||
// lldb-command:v empty
|
||||
// lldb-check:[...] Empty
|
||||
|
||||
// lldb-command:v droid
|
||||
// lldb-check:[...] Droid { id: 675675, range: 10000001, internals: &0x43218765 }
|
||||
// lldb-check:[...] Droid { id: 675675, range: 10000001, internals: &0x[...] }
|
||||
|
||||
// lldb-command:v void_droid
|
||||
// lldb-check:[...] Void
|
||||
|
|
@ -76,11 +76,6 @@
|
|||
// contains a non-nullable pointer, then this value is used as the discriminator.
|
||||
// The test cases in this file make sure that something readable is generated for
|
||||
// this kind of types.
|
||||
// If the non-empty variant contains a single non-nullable pointer than the whole
|
||||
// item is represented as just a pointer and not wrapped in a struct.
|
||||
// Unfortunately (for these test cases) the content of the non-discriminant fields
|
||||
// in the null-case is not defined. So we just read the discriminator field in
|
||||
// this case (by casting the value to a memory-equivalent struct).
|
||||
|
||||
enum MoreFields<'a> {
|
||||
Full(u32, &'a isize, i16),
|
||||
|
|
@ -120,32 +115,26 @@ fn main() {
|
|||
let some_str: Option<&'static str> = Some("abc");
|
||||
let none_str: Option<&'static str> = None;
|
||||
|
||||
let some: Option<&u32> = Some(unsafe { std::mem::transmute(0x12345678_usize) });
|
||||
let some: Option<&u32> = Some(&1234);
|
||||
let none: Option<&u32> = None;
|
||||
|
||||
let full = MoreFields::Full(454545, unsafe { std::mem::transmute(0x87654321_usize) }, 9988);
|
||||
|
||||
let full = MoreFields::Full(454545, &1234, 9988);
|
||||
let empty = MoreFields::Empty;
|
||||
let empty_gdb: &MoreFieldsRepr = unsafe { std::mem::transmute(&MoreFields::Empty) };
|
||||
|
||||
let droid = NamedFields::Droid {
|
||||
id: 675675,
|
||||
range: 10000001,
|
||||
internals: unsafe { std::mem::transmute(0x43218765_usize) }
|
||||
internals: &1234,
|
||||
};
|
||||
|
||||
let void_droid = NamedFields::Void;
|
||||
let void_droid_gdb: &NamedFieldsRepr = unsafe { std::mem::transmute(&NamedFields::Void) };
|
||||
|
||||
let x = 'x';
|
||||
let nested_non_zero_yep = NestedNonZero::Yep(
|
||||
10.5,
|
||||
NestedNonZeroField {
|
||||
a: 10,
|
||||
b: 20,
|
||||
c: &x
|
||||
c: &'x',
|
||||
});
|
||||
|
||||
let nested_non_zero_nope = NestedNonZero::Nope;
|
||||
|
||||
zzz(); // #break
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@
|
|||
field_tys: {
|
||||
_0: CoroutineSavedTy {
|
||||
ty: Coroutine(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[
|
||||
(),
|
||||
std::future::ResumeTy,
|
||||
(),
|
||||
(),
|
||||
CoroutineWitness(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[],
|
||||
),
|
||||
(),
|
||||
|
|
@ -24,14 +24,14 @@
|
|||
},
|
||||
_1: CoroutineSavedTy {
|
||||
ty: Coroutine(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[
|
||||
(),
|
||||
std::future::ResumeTy,
|
||||
(),
|
||||
(),
|
||||
CoroutineWitness(
|
||||
DefId(0:4 ~ async_await[ccf8]::a::{closure#0}),
|
||||
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
|
||||
[],
|
||||
),
|
||||
(),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ trait Foo {}
|
|||
impl Xyz {
|
||||
async fn do_sth<'a>(
|
||||
&'a self, foo: &dyn Foo
|
||||
) -> &dyn Foo
|
||||
) -> &dyn Foo //~ WARNING elided lifetime has a name
|
||||
{
|
||||
//~^ ERROR explicit lifetime required in the type of `foo` [E0621]
|
||||
foo
|
||||
|
|
|
|||
|
|
@ -1,3 +1,14 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/issue-63388-1.rs:12:10
|
||||
|
|
||||
LL | async fn do_sth<'a>(
|
||||
| -- lifetime `'a` declared here
|
||||
LL | &'a self, foo: &dyn Foo
|
||||
LL | ) -> &dyn Foo
|
||||
| ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0621]: explicit lifetime required in the type of `foo`
|
||||
--> $DIR/issue-63388-1.rs:13:5
|
||||
|
|
||||
|
|
@ -10,6 +21,6 @@ LL | | foo
|
|||
LL | | }
|
||||
| |_____^ lifetime `'a` required
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0621`.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/issue-71348.rs:18:68
|
||||
|
|
||||
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/issue-71348.rs:18:68
|
||||
|
|
||||
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error: `&'static str` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-71348.rs:10:24
|
||||
|
|
||||
|
|
@ -30,5 +38,5 @@ help: add `#![feature(unsized_const_params)]` to the crate attributes to enable
|
|||
LL + #![feature(unsized_const_params)]
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ trait Get<'a, const N: &'static str> {
|
|||
impl Foo {
|
||||
fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
|
||||
//[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter
|
||||
//~^^ WARNING elided lifetime has a name
|
||||
where
|
||||
Self: Get<'a, N>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ impl<T> Foo<T> {
|
|||
impl<'a, T> Foo<T> {
|
||||
const fn new_lt(t: T) -> Self { Foo(t) }
|
||||
const fn into_inner_lt(self) -> T { self.0 } //~ destructor of
|
||||
const fn get_lt(&'a self) -> &T { &self.0 }
|
||||
const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
|
||||
const fn get_lt(&'a self) -> &T { &self.0 } //~ WARNING elided lifetime has a name
|
||||
const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } //~ WARNING elided lifetime has a name
|
||||
//~^ mutable references
|
||||
//~| mutable references
|
||||
//~| mutable references
|
||||
|
|
|
|||
|
|
@ -1,3 +1,23 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/min_const_fn.rs:47:34
|
||||
|
|
||||
LL | impl<'a, T> Foo<T> {
|
||||
| -- lifetime `'a` declared here
|
||||
...
|
||||
LL | const fn get_lt(&'a self) -> &T { &self.0 }
|
||||
| ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
warning: elided lifetime has a name
|
||||
--> $DIR/min_const_fn.rs:48:42
|
||||
|
|
||||
LL | impl<'a, T> Foo<T> {
|
||||
| -- lifetime `'a` declared here
|
||||
...
|
||||
LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 }
|
||||
| ^ this elided lifetime gets resolved as `'a`
|
||||
|
||||
error[E0493]: destructor of `Foo<T>` cannot be evaluated at compile-time
|
||||
--> $DIR/min_const_fn.rs:37:25
|
||||
|
|
||||
|
|
@ -228,7 +248,7 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
|
|||
| |
|
||||
| the destructor for this type cannot be evaluated in constant functions
|
||||
|
||||
error: aborting due to 24 previous errors
|
||||
error: aborting due to 24 previous errors; 2 warnings emitted
|
||||
|
||||
Some errors have detailed explanations: E0493, E0658.
|
||||
For more information about an error, try `rustc --explain E0493`.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ note: coroutine is not `Send` as this value is used across a yield
|
|||
--> $DIR/coroutine-print-verbose-1.rs:35:9
|
||||
|
|
||||
LL | let _non_send_gen = make_non_send_coroutine();
|
||||
| ------------- has type `Opaque(DefId(0:34 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine::{opaque#0}), [])` which is not `Send`
|
||||
| ------------- has type `Opaque(DefId(0:24 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine::{opaque#0}), [])` which is not `Send`
|
||||
LL | yield;
|
||||
| ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
|
||||
note: required by a bound in `require_send`
|
||||
|
|
@ -33,12 +33,12 @@ note: required because it's used within this coroutine
|
|||
|
|
||||
LL | #[coroutine] || {
|
||||
| ^^
|
||||
note: required because it appears within the type `Opaque(DefId(0:35 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
|
||||
note: required because it appears within the type `Opaque(DefId(0:29 ~ coroutine_print_verbose_1[75fb]::make_gen2::{opaque#0}), [Arc<RefCell<i32>>])`
|
||||
--> $DIR/coroutine-print-verbose-1.rs:41:30
|
||||
|
|
||||
LL | pub fn make_gen2<T>(t: T) -> impl Coroutine<Return = T> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required because it appears within the type `Opaque(DefId(0:36 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine2::{opaque#0}), [])`
|
||||
note: required because it appears within the type `Opaque(DefId(0:32 ~ coroutine_print_verbose_1[75fb]::make_non_send_coroutine2::{opaque#0}), [])`
|
||||
--> $DIR/coroutine-print-verbose-1.rs:47:34
|
||||
|
|
||||
LL | fn make_non_send_coroutine2() -> impl Coroutine<Return = Arc<RefCell<i32>>> {
|
||||
|
|
|
|||
|
|
@ -13,11 +13,6 @@ warning[E0602]: unknown lint: `bogus`
|
|||
= note: requested on the command line with `-D bogus`
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
warning[E0602]: unknown lint: `bogus`
|
||||
|
|
||||
= note: requested on the command line with `-D bogus`
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
warning: 4 warnings emitted
|
||||
warning: 3 warnings emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0602`.
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
#[target_feature(enable = "avx")] //~ ERROR attribute should be applied to a function definition
|
||||
struct Avx {}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
error: attribute should be applied to a function definition
|
||||
--> $DIR/feature-gate-struct-target-features.rs:1:1
|
||||
|
|
||||
LL | #[target_feature(enable = "avx")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | struct Avx {}
|
||||
| ------------- not a function definition
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, elided_named_lifetimes)]
|
||||
#![deny(no_mangle_generic_items)]
|
||||
|
||||
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, elided_named_lifetimes)]
|
||||
#![deny(no_mangle_generic_items)]
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
|
|||
|
||||
fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
|
||||
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
|
||||
//~| WARNING elided lifetime has a name
|
||||
|x| x
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:19:38
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:20:38
|
||||
|
|
||||
LL | fn d() -> impl Fn() -> (impl Debug + '_) {
|
||||
| ^^ expected named lifetime parameter
|
||||
|
|
@ -10,6 +10,14 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're
|
|||
LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
|
||||
| ~~~~~~~
|
||||
|
||||
warning: elided lifetime has a name
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:14:52
|
||||
|
|
||||
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:4:41
|
||||
|
|
||||
|
|
@ -46,7 +54,7 @@ note: lifetime declared here
|
|||
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0106, E0657.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::fmt::Debug;
|
|||
|
||||
fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||
//~^ ERROR cannot resolve opaque type
|
||||
//~| WARNING elided lifetime has a name
|
||||
|x| x
|
||||
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/impl-fn-predefined-lifetimes.rs:4:48
|
||||
|
|
||||
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0792]: expected generic lifetime parameter, found `'_`
|
||||
--> $DIR/impl-fn-predefined-lifetimes.rs:6:9
|
||||
--> $DIR/impl-fn-predefined-lifetimes.rs:7:9
|
||||
|
|
||||
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| -- this generic parameter must be used with a generic lifetime parameter
|
||||
LL |
|
||||
...
|
||||
LL | |x| x
|
||||
| ^
|
||||
|
||||
|
|
@ -13,7 +21,7 @@ error[E0720]: cannot resolve opaque type
|
|||
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| ^^^^^^^^^^^^^^^ cannot resolve opaque type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0720, E0792.
|
||||
For more information about an error, try `rustc --explain E0720`.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//@ check-pass
|
||||
|
||||
pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
|
||||
//~^ WARNING elided lifetime has a name
|
||||
v.into_iter()
|
||||
}
|
||||
|
||||
|
|
|
|||
10
tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
Normal file
10
tests/ui/impl-trait/rpit-assoc-pair-with-lifetime.stderr
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82
|
||||
|
|
||||
LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
|
@ -47,5 +47,6 @@ fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
|
|||
|
||||
// This is ok because both `'a` are for the same parameter.
|
||||
fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
|
||||
//~^ WARNING elided lifetime has a name
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,16 @@ help: consider using the `'a` lifetime
|
|||
LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" }
|
||||
| ++
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
warning: elided lifetime has a name
|
||||
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:49:29
|
||||
|
|
||||
LL | fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error: aborting due to 7 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ struct Foo {
|
|||
|
||||
impl Foo {
|
||||
fn foo<'a>(&'a self, x: &i32) -> &i32 {
|
||||
//~^ WARNING elided lifetime has a name
|
||||
|
||||
if true { &self.field } else { x } //~ ERROR explicit lifetime
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,22 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:6:36
|
||||
|
|
||||
LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0621]: explicit lifetime required in the type of `x`
|
||||
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:8:36
|
||||
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:9:36
|
||||
|
|
||||
LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
|
||||
| ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
|
||||
LL |
|
||||
...
|
||||
LL | if true { &self.field } else { x }
|
||||
| ^ lifetime `'a` required
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0621`.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue