summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_passes/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_passes/src
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_passes/src')
-rw-r--r--compiler/rustc_passes/src/check_attr.rs92
-rw-r--r--compiler/rustc_passes/src/check_const.rs4
-rw-r--r--compiler/rustc_passes/src/dead.rs98
-rw-r--r--compiler/rustc_passes/src/entry.rs41
-rw-r--r--compiler/rustc_passes/src/errors.rs79
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs4
-rw-r--r--compiler/rustc_passes/src/lang_items.rs2
-rw-r--r--compiler/rustc_passes/src/layout_test.rs2
-rw-r--r--compiler/rustc_passes/src/lib.rs3
-rw-r--r--compiler/rustc_passes/src/lib_features.rs8
-rw-r--r--compiler/rustc_passes/src/liveness.rs62
-rw-r--r--compiler/rustc_passes/src/loops.rs55
-rw-r--r--compiler/rustc_passes/src/reachable.rs62
-rw-r--r--compiler/rustc_passes/src/stability.rs72
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs4
15 files changed, 306 insertions, 282 deletions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d92923e78..c5767fd90 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -211,7 +211,6 @@ impl CheckAttrVisitor<'_> {
sym::deprecated => self.check_deprecated(hir_id, attr, span, target),
sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
- sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
sym::macro_export => self.check_macro_export(hir_id, attr, target),
sym::ignore | sym::should_panic => {
self.check_generic_attr(hir_id, attr, target, Target::Fn)
@@ -1076,7 +1075,9 @@ impl CheckAttrVisitor<'_> {
) -> bool {
let mut is_valid = true;
- if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() {
+ if let Some(mi) = attr.meta()
+ && let Some(list) = mi.meta_item_list()
+ {
for meta in list {
if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() {
@@ -1108,6 +1109,7 @@ impl CheckAttrVisitor<'_> {
| sym::html_root_url
| sym::html_no_source
| sym::test
+ | sym::rust_logo
if !self.check_attr_crate_level(attr, meta, hir_id) =>
{
is_valid = false;
@@ -1132,14 +1134,7 @@ impl CheckAttrVisitor<'_> {
is_valid = false;
}
- sym::masked
- if !self.check_doc_masked(
- attr,
- meta,
- hir_id,
- target,
- ) =>
- {
+ sym::masked if !self.check_doc_masked(attr, meta, hir_id, target) => {
is_valid = false;
}
@@ -1166,6 +1161,18 @@ impl CheckAttrVisitor<'_> {
| sym::plugins
| sym::fake_variadic => {}
+ sym::rust_logo => {
+ if !self.tcx.features().rustdoc_internals {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::rustdoc_internals,
+ meta.span(),
+ "the `#[doc(rust_logo)]` attribute is used for Rust branding",
+ )
+ .emit();
+ }
+ }
+
sym::test => {
if !self.check_test_attr(meta, hir_id) {
is_valid = false;
@@ -1179,13 +1186,11 @@ impl CheckAttrVisitor<'_> {
INVALID_DOC_ATTRIBUTES,
hir_id,
i_meta.span,
- errors::DocTestUnknownSpotlight {
- path,
- span: i_meta.span
- }
+ errors::DocTestUnknownSpotlight { path, span: i_meta.span },
);
- } else if i_meta.has_name(sym::include) &&
- let Some(value) = i_meta.value_str() {
+ } else if i_meta.has_name(sym::include)
+ && let Some(value) = i_meta.value_str()
+ {
let applicability = if list.len() == 1 {
Applicability::MachineApplicable
} else {
@@ -1200,16 +1205,19 @@ impl CheckAttrVisitor<'_> {
errors::DocTestUnknownInclude {
path,
value: value.to_string(),
- inner: match attr.style { AttrStyle::Inner=> "!" , AttrStyle::Outer => "" },
+ inner: match attr.style {
+ AttrStyle::Inner => "!",
+ AttrStyle::Outer => "",
+ },
sugg: (attr.meta().unwrap().span, applicability),
- }
+ },
);
} else {
self.tcx.emit_spanned_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
i_meta.span,
- errors::DocTestUnknownAny { path }
+ errors::DocTestUnknownAny { path },
);
}
is_valid = false;
@@ -2189,8 +2197,9 @@ impl CheckAttrVisitor<'_> {
attr.span,
errors::MacroExport::Normal,
);
- } else if let Some(meta_item_list) = attr.meta_item_list() &&
- !meta_item_list.is_empty() {
+ } else if let Some(meta_item_list) = attr.meta_item_list()
+ && !meta_item_list.is_empty()
+ {
if meta_item_list.len() > 1 {
self.tcx.emit_spanned_lint(
INVALID_MACRO_EXPORT_ARGUMENTS,
@@ -2227,17 +2236,6 @@ impl CheckAttrVisitor<'_> {
}
}
- fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
- if target != Target::Fn {
- self.tcx.emit_spanned_lint(
- UNUSED_ATTRIBUTES,
- hir_id,
- attr.span,
- errors::PluginRegistrar,
- );
- }
- }
-
fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
// Warn on useless empty attributes.
let note = if matches!(
@@ -2255,9 +2253,9 @@ impl CheckAttrVisitor<'_> {
{
errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
} else if matches!(
- attr.name_or_empty(),
- sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
- ) && let Some(meta) = attr.meta_item_list()
+ attr.name_or_empty(),
+ sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
+ ) && let Some(meta) = attr.meta_item_list()
&& meta.len() == 1
&& let Some(item) = meta[0].meta_item()
&& let MetaItemKind::NameValue(_) = &item.kind
@@ -2380,7 +2378,7 @@ impl CheckAttrVisitor<'_> {
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
+ infcx.err_ctxt().report_fulfillment_errors(errors);
self.abort.set(true);
}
}
@@ -2524,10 +2522,30 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
if attr.style == AttrStyle::Inner {
for attr_to_check in ATTRS_TO_CHECK {
if attr.has_name(*attr_to_check) {
+ let item = tcx
+ .hir()
+ .items()
+ .map(|id| tcx.hir().item(id))
+ .find(|item| !item.span.is_dummy()) // Skip prelude `use`s
+ .map(|item| errors::ItemFollowingInnerAttr {
+ span: item.ident.span,
+ kind: item.kind.descr(),
+ });
tcx.sess.emit_err(errors::InvalidAttrAtCrateLevel {
span: attr.span,
- snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(),
+ sugg_span: tcx
+ .sess
+ .source_map()
+ .span_to_snippet(attr.span)
+ .ok()
+ .filter(|src| src.starts_with("#!["))
+ .map(|_| {
+ attr.span
+ .with_lo(attr.span.lo() + BytePos(1))
+ .with_hi(attr.span.lo() + BytePos(2))
+ }),
name: *attr_to_check,
+ item,
});
}
}
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 6d176af80..7188c177f 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -86,7 +86,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
let is_feature_allowed = |feature_gate| {
// All features require that the corresponding gate be enabled,
// even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
- if !tcx.features().enabled(feature_gate) {
+ if !tcx.features().active(feature_gate) {
return false;
}
@@ -134,7 +134,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
let required_gates = required_gates.unwrap_or(&[]);
let missing_gates: Vec<_> =
- required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
+ required_gates.iter().copied().filter(|&g| !features.active(g)).collect();
match missing_gates.as_slice() {
[] => {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 493daf314..2e8c58b02 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -1,6 +1,7 @@
-// This implements the dead-code warning pass. It follows middle::reachable
-// closely. The idea is that all reachable symbols are live, codes called
-// from live codes are live, and everything else is dead.
+// This implements the dead-code warning pass.
+// All reachable symbols are live, code called from live code is live, code with certain lint
+// expectations such as `#[expect(unused)]` and `#[expect(dead_code)]` is live, and everything else
+// is dead.
use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
use itertools::Itertools;
@@ -192,15 +193,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind
&& check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
- && !assign.span.from_expansion()
+ && !assign.span.from_expansion()
{
- let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
- self.tcx.emit_spanned_lint(
- lint::builtin::DEAD_CODE,
- assign.hir_id,
- assign.span,
- UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }
- )
+ let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
+ self.tcx.emit_spanned_lint(
+ lint::builtin::DEAD_CODE,
+ assign.hir_id,
+ assign.span,
+ UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) },
+ )
}
}
@@ -256,10 +257,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
let mut current_ty = container;
- for &index in indices {
+ for &(variant, field) in indices {
match current_ty.kind() {
ty::Adt(def, subst) => {
- let field = &def.non_enum_variant().fields[index];
+ let field = &def.variant(variant).fields[field];
self.insert_def_id(field.did);
let field_ty = field.ty(self.tcx, subst);
@@ -270,7 +271,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
// but we may need to mark subfields
ty::Tuple(tys) => {
current_ty =
- self.tcx.normalize_erasing_regions(param_env, tys[index.as_usize()]);
+ self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]);
}
_ => span_bug!(expr.span, "named field access on non-ADT"),
}
@@ -670,7 +671,8 @@ fn check_trait_item(
if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
let trait_item = tcx.hir().trait_item(id);
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
- && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
+ && let Some(comes_from_allow) =
+ has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
{
worklist.push((trait_item.owner_id.def_id, comes_from_allow));
}
@@ -747,7 +749,7 @@ fn live_symbols_and_ignored_derived_traits(
(symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
}
-struct DeadVariant {
+struct DeadItem {
def_id: LocalDefId,
name: Symbol,
level: lint::Level,
@@ -785,7 +787,13 @@ impl<'tcx> DeadVisitor<'tcx> {
ShouldWarnAboutField::Yes(is_positional)
}
- fn warn_multiple_dead_codes(
+ // # Panics
+ // All `dead_codes` must have the same lint level, otherwise we will intentionally ICE.
+ // This is because we emit a multi-spanned lint using the lint level of the `dead_codes`'s
+ // first local def id.
+ // Prefer calling `Self.warn_dead_code` or `Self.warn_dead_code_grouped_by_lint_level`
+ // since those methods group by lint level before calling this method.
+ fn lint_at_single_level(
&self,
dead_codes: &[LocalDefId],
participle: &str,
@@ -796,6 +804,15 @@ impl<'tcx> DeadVisitor<'tcx> {
return;
};
let tcx = self.tcx;
+
+ let first_hir_id = tcx.hir().local_def_id_to_hir_id(first_id);
+ let first_lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, first_hir_id).0;
+ assert!(dead_codes.iter().skip(1).all(|id| {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(*id);
+ let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+ level == first_lint_level
+ }));
+
let names: Vec<_> =
dead_codes.iter().map(|&def_id| tcx.item_name(def_id.to_def_id())).collect();
let spans: Vec<_> = dead_codes
@@ -876,31 +893,26 @@ impl<'tcx> DeadVisitor<'tcx> {
}
};
- self.tcx.emit_spanned_lint(
- lint,
- tcx.hir().local_def_id_to_hir_id(first_id),
- MultiSpan::from_spans(spans),
- diag,
- );
+ self.tcx.emit_spanned_lint(lint, first_hir_id, MultiSpan::from_spans(spans), diag);
}
- fn warn_dead_fields_and_variants(
+ fn warn_multiple(
&self,
def_id: LocalDefId,
participle: &str,
- dead_codes: Vec<DeadVariant>,
+ dead_codes: Vec<DeadItem>,
is_positional: bool,
) {
let mut dead_codes = dead_codes
.iter()
.filter(|v| !v.name.as_str().starts_with('_'))
- .collect::<Vec<&DeadVariant>>();
+ .collect::<Vec<&DeadItem>>();
if dead_codes.is_empty() {
return;
}
dead_codes.sort_by_key(|v| v.level);
for (_, group) in &dead_codes.into_iter().group_by(|v| v.level) {
- self.warn_multiple_dead_codes(
+ self.lint_at_single_level(
&group.map(|v| v.def_id).collect::<Vec<_>>(),
participle,
Some(def_id),
@@ -910,7 +922,7 @@ impl<'tcx> DeadVisitor<'tcx> {
}
fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) {
- self.warn_multiple_dead_codes(&[id], participle, None, false);
+ self.lint_at_single_level(&[id], participle, None, false);
}
fn check_definition(&mut self, def_id: LocalDefId) {
@@ -954,17 +966,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind {
let mut dead_items = Vec::new();
for item in impl_item.items {
- let did = item.id.owner_id.def_id;
- if !visitor.is_live_code(did) {
- dead_items.push(did)
+ let def_id = item.id.owner_id.def_id;
+ if !visitor.is_live_code(def_id) {
+ let name = tcx.item_name(def_id.to_def_id());
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+
+ dead_items.push(DeadItem { def_id, name, level })
}
}
- visitor.warn_multiple_dead_codes(
- &dead_items,
- "used",
- Some(item.owner_id.def_id),
- false,
- );
+ visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, false);
}
if !live_symbols.contains(&item.owner_id.def_id) {
@@ -988,7 +999,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
// Record to group diagnostics.
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
- dead_variants.push(DeadVariant { def_id, name: variant.name, level });
+ dead_variants.push(DeadItem { def_id, name: variant.name, level });
continue;
}
@@ -1013,21 +1024,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
hir_id,
)
.0;
- Some(DeadVariant { def_id, name: field.name, level })
+ Some(DeadItem { def_id, name: field.name, level })
} else {
None
}
})
.collect();
- visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional)
+ visitor.warn_multiple(def_id, "read", dead_fields, is_positional);
}
- visitor.warn_dead_fields_and_variants(
- item.owner_id.def_id,
- "constructed",
- dead_variants,
- false,
- );
+ visitor.warn_multiple(item.owner_id.def_id, "constructed", dead_variants, false);
}
}
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 4f71704b8..51a64b385 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -52,31 +52,6 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
configure_main(tcx, &ctxt)
}
-// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
-// (with `ast::Item`), so make sure to keep them in sync.
-// A small optimization was added so that hir::Item is fetched only when needed.
-// An equivalent optimization was not applied to the duplicated code in test_harness.rs.
-fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
- let attrs = ctxt.tcx.hir().attrs(id.hir_id());
- if attr::contains_name(attrs, sym::start) {
- EntryPointType::Start
- } else if attr::contains_name(attrs, sym::rustc_main) {
- EntryPointType::RustcMainAttr
- } else {
- if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id())
- && name == sym::main {
- if at_root {
- // This is a top-level function so can be `main`.
- EntryPointType::MainNamed
- } else {
- EntryPointType::OtherMain
- }
- } else {
- EntryPointType::None
- }
- }
-}
-
fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
attr::find_by_name(attrs, sym).map(|attr| attr.span)
@@ -85,7 +60,13 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID);
- match entry_point_type(ctxt, id, at_root) {
+ let attrs = ctxt.tcx.hir().attrs(id.hir_id());
+ let entry_point_type = rustc_ast::entry::entry_point_type(
+ attrs,
+ at_root,
+ ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
+ );
+ match entry_point_type {
EntryPointType::None => {
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
@@ -140,9 +121,13 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
let def_id = local_def_id.to_def_id();
Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) }))
} else {
- if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() {
+ if let Some(main_def) = tcx.resolutions(()).main_def
+ && let Some(def_id) = main_def.opt_fn_def_id()
+ {
// non-local main imports are handled below
- if let Some(def_id) = def_id.as_local() && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) {
+ if let Some(def_id) = def_id.as_local()
+ && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_)))
+ {
tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) });
return None;
}
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index f4a6bf017..411c94101 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -717,10 +717,6 @@ pub enum MacroExport {
TooManyItems,
}
-#[derive(LintDiagnostic)]
-#[diag(passes_plugin_registrar)]
-pub struct PluginRegistrar;
-
#[derive(Subdiagnostic)]
pub enum UnusedNote {
#[note(passes_unused_empty_lints_note)]
@@ -856,8 +852,15 @@ pub struct UnknownLangItem {
pub struct InvalidAttrAtCrateLevel {
pub span: Span,
- pub snippet: Option<String>,
+ pub sugg_span: Option<Span>,
pub name: Symbol,
+ pub item: Option<ItemFollowingInnerAttr>,
+}
+
+#[derive(Clone, Copy)]
+pub struct ItemFollowingInnerAttr {
+ pub span: Span,
+ pub kind: &'static str,
}
impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
@@ -871,15 +874,18 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
diag.set_arg("name", self.name);
// Only emit an error with a suggestion if we can create a string out
// of the attribute span
- if let Some(src) = self.snippet {
- let replacement = src.replace("#!", "#");
+ if let Some(span) = self.sugg_span {
diag.span_suggestion_verbose(
- self.span,
+ span,
fluent::passes_suggestion,
- replacement,
+ String::new(),
rustc_errors::Applicability::MachineApplicable,
);
}
+ if let Some(item) = self.item {
+ diag.set_arg("kind", item.kind);
+ diag.span_label(item.span, fluent::passes_invalid_attr_at_crate_level_item);
+ }
diag
}
}
@@ -1106,6 +1112,16 @@ pub struct OutsideLoop<'a> {
pub span: Span,
pub name: &'a str,
pub is_break: bool,
+ #[subdiagnostic]
+ pub suggestion: Option<OutsideLoopSuggestion>,
+}
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_outside_loop_suggestion, applicability = "maybe-incorrect")]
+pub struct OutsideLoopSuggestion {
+ #[suggestion_part(code = "'block: ")]
+ pub block_span: Span,
+ #[suggestion_part(code = " 'block")]
+ pub break_span: Span,
}
#[derive(Diagnostic)]
@@ -1308,7 +1324,9 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
diag.span_label(self.sp.shrink_to_hi(), note);
}
- if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){
+ if let Some(main_def) = self.main_def_opt
+ && main_def.opt_fn_def_id().is_none()
+ {
// There is something at `crate::main`, but it is not a function definition.
diag.span_label(main_def.span, fluent::passes_non_function_main);
}
@@ -1493,16 +1511,6 @@ pub struct UselessStability {
}
#[derive(Diagnostic)]
-#[diag(passes_invalid_stability)]
-pub struct InvalidStability {
- #[primary_span]
- #[label]
- pub span: Span,
- #[label(passes_item)]
- pub item_sp: Span,
-}
-
-#[derive(Diagnostic)]
#[diag(passes_cannot_stabilize_deprecated)]
pub struct CannotStabilizeDeprecated {
#[primary_span]
@@ -1513,16 +1521,6 @@ pub struct CannotStabilizeDeprecated {
}
#[derive(Diagnostic)]
-#[diag(passes_invalid_deprecation_version)]
-pub struct InvalidDeprecationVersion {
- #[primary_span]
- #[label]
- pub span: Span,
- #[label(passes_item)]
- pub item_sp: Span,
-}
-
-#[derive(Diagnostic)]
#[diag(passes_missing_stability_attr)]
pub struct MissingStabilityAttr<'a> {
#[primary_span]
@@ -1756,15 +1754,24 @@ pub struct UnusedVariableTryPrefix {
#[subdiagnostic]
pub string_interp: Vec<UnusedVariableStringInterp>,
#[subdiagnostic]
- pub sugg: UnusedVariableTryPrefixSugg,
+ pub sugg: UnusedVariableSugg,
+ pub name: String,
}
#[derive(Subdiagnostic)]
-#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
-pub struct UnusedVariableTryPrefixSugg {
- #[suggestion_part(code = "_{name}")]
- pub spans: Vec<Span>,
- pub name: String,
+pub enum UnusedVariableSugg {
+ #[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+ TryPrefixSugg {
+ #[suggestion_part(code = "_{name}")]
+ spans: Vec<Span>,
+ name: String,
+ },
+ #[help(passes_unused_variable_args_in_macro)]
+ NoSugg {
+ #[primary_span]
+ span: Span,
+ name: String,
+ },
}
pub struct UnusedVariableStringInterp {
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 24087a4ea..f915c1057 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -567,10 +567,10 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
(self, e, e.kind, Id::None, ast, Expr, ExprKind),
[
Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
- If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
+ If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign,
AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet,
- Become, IncludedBytes, Err
+ Become, IncludedBytes, Gen, Err
]
);
ast_visit::walk_expr(self, e)
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 7e8372439..2aec4ea7e 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -149,7 +149,7 @@ impl<'tcx> LanguageItemCollector<'tcx> {
// Now check whether the lang_item has the expected number of generic
// arguments. Generally speaking, binary and indexing operations have
// one (for the RHS/index), unary operations have none, the closure
- // traits have one for the argument list, generators have one for the
+ // traits have one for the argument list, coroutines have one for the
// resume argument, and ordering/equality relations have one for the RHS
// Some other types like Box and various functions like drop_in_place
// have minimum requirements.
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index e195f9ab6..2129a98cd 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -57,7 +57,7 @@ pub fn ensure_wf<'tcx>(
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors);
+ infcx.err_ctxt().report_fulfillment_errors(errors);
false
} else {
// looks WF!
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 51f3c9ad7..946a9e68d 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,6 +6,9 @@
#![allow(rustc::potential_query_instability)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(map_try_insert)]
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 44174b1b8..0daa273db 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -5,7 +5,7 @@
//! collect them instead.
use rustc_ast::Attribute;
-use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
+use rustc_attr::VERSION_PLACEHOLDER;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::LibFeatures;
@@ -56,8 +56,10 @@ impl<'tcx> LibFeatureCollector<'tcx> {
}
}
- if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER {
- since = Some(rust_version_symbol());
+ if let Some(s) = since
+ && s.as_str() == VERSION_PLACEHOLDER
+ {
+ since = Some(sym::env_CFG_RELEASE);
}
if let Some(feature) = feature {
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 20e996eae..b73fb984c 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -706,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
//
// When computing the liveness for captured variables we take into
// account how variable is captured (ByRef vs ByValue) and what is the
- // closure kind (Generator / FnOnce vs Fn / FnMut).
+ // closure kind (Coroutine / FnOnce vs Fn / FnMut).
//
// Variables captured by reference are assumed to be used on the exit
// from the closure.
@@ -752,7 +752,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
ty::ClosureKind::FnMut => {}
ty::ClosureKind::FnOnce => return succ,
},
- ty::Generator(..) => return succ,
+ ty::Coroutine(..) => return succ,
_ => {
span_bug!(
body.value.span,
@@ -1512,13 +1512,15 @@ impl<'tcx> Liveness<'_, 'tcx> {
Some(body),
|spans, hir_id, ln, var| {
if !self.live_on_entry(ln, var)
- && let Some(name) = self.should_warn(var) {
- self.ir.tcx.emit_spanned_lint(
- lint::builtin::UNUSED_ASSIGNMENTS,
- hir_id,
- spans,
- errors::UnusedAssignPassed { name },
- ); }
+ && let Some(name) = self.should_warn(var)
+ {
+ self.ir.tcx.emit_spanned_lint(
+ lint::builtin::UNUSED_ASSIGNMENTS,
+ hir_id,
+ spans,
+ errors::UnusedAssignPassed { name },
+ );
+ }
},
);
}
@@ -1578,7 +1580,6 @@ impl<'tcx> Liveness<'_, 'tcx> {
opt_body: Option<&hir::Body<'_>>,
) {
let first_hir_id = hir_ids_and_spans[0].0;
-
if let Some(name) = self.should_warn(var).filter(|name| name != "self") {
// annoying: for parameters in funcs like `fn(x: i32)
// {ret}`, there is only one node, so asking about
@@ -1650,11 +1651,29 @@ impl<'tcx> Liveness<'_, 'tcx> {
},
);
} else {
+ // #117284, when `pat_span` and `ident_span` have different contexts
+ // we can't provide a good suggestion, instead we pointed out the spans from macro
+ let from_macro = non_shorthands
+ .iter()
+ .find(|(_, pat_span, ident_span)| {
+ pat_span.ctxt() != ident_span.ctxt() && pat_span.from_expansion()
+ })
+ .map(|(_, pat_span, _)| *pat_span);
let non_shorthands = non_shorthands
.into_iter()
.map(|(_, _, ident_span)| ident_span)
.collect::<Vec<_>>();
+
let suggestions = self.string_interp_suggestions(&name, opt_body);
+ let sugg = if let Some(span) = from_macro {
+ errors::UnusedVariableSugg::NoSugg { span, name: name.clone() }
+ } else {
+ errors::UnusedVariableSugg::TryPrefixSugg {
+ spans: non_shorthands,
+ name: name.clone(),
+ }
+ };
+
self.ir.tcx.emit_spanned_lint(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
@@ -1664,10 +1683,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
.collect::<Vec<_>>(),
errors::UnusedVariableTryPrefix {
label: if !suggestions.is_empty() { Some(pat.span) } else { None },
- sugg: errors::UnusedVariableTryPrefixSugg {
- spans: non_shorthands,
- name,
- },
+ name,
+ sugg,
string_interp: suggestions,
},
);
@@ -1707,13 +1724,14 @@ impl<'tcx> Liveness<'_, 'tcx> {
fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
if !self.live_on_exit(ln, var)
- && let Some(name) = self.should_warn(var) {
- self.ir.tcx.emit_spanned_lint(
- lint::builtin::UNUSED_ASSIGNMENTS,
- hir_id,
- spans,
- errors::UnusedAssign { name },
- );
- }
+ && let Some(name) = self.should_warn(var)
+ {
+ self.ir.tcx.emit_spanned_lint(
+ lint::builtin::UNUSED_ASSIGNMENTS,
+ hir_id,
+ spans,
+ errors::UnusedAssign { name },
+ );
+ }
}
}
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 0aaf85086..25e131d74 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -1,7 +1,7 @@
use Context::*;
use rustc_hir as hir;
-use rustc_hir::def_id::LocalModDefId;
+use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Destination, Movability, Node};
use rustc_middle::hir::map::Map;
@@ -10,19 +10,21 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
use crate::errors::{
BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
- UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
+ OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
};
#[derive(Clone, Copy, Debug, PartialEq)]
enum Context {
Normal,
+ Fn,
Loop(hir::LoopSource),
Closure(Span),
AsyncClosure(Span),
+ UnlabeledBlock(Span),
LabeledBlock,
Constant,
}
@@ -60,6 +62,25 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
}
+ fn visit_fn(
+ &mut self,
+ fk: hir::intravisit::FnKind<'hir>,
+ fd: &'hir hir::FnDecl<'hir>,
+ b: hir::BodyId,
+ _: Span,
+ id: LocalDefId,
+ ) {
+ self.with_context(Fn, |v| intravisit::walk_fn(v, fk, fd, b, id));
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'hir hir::TraitItem<'hir>) {
+ self.with_context(Fn, |v| intravisit::walk_trait_item(v, trait_item));
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &'hir hir::ImplItem<'hir>) {
+ self.with_context(Fn, |v| intravisit::walk_impl_item(v, impl_item));
+ }
+
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
match e.kind {
hir::ExprKind::Loop(ref b, _, source, _) => {
@@ -83,6 +104,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
hir::ExprKind::Block(ref b, Some(_label)) => {
self.with_context(LabeledBlock, |v| v.visit_block(&b));
}
+ hir::ExprKind::Block(ref b, None) if matches!(self.cx, Fn) => {
+ self.with_context(Normal, |v| v.visit_block(&b));
+ }
+ hir::ExprKind::Block(ref b, None)
+ if matches!(self.cx, Normal | Constant | UnlabeledBlock(_)) =>
+ {
+ self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(&b));
+ }
hir::ExprKind::Break(break_label, ref opt_expr) => {
if let Some(e) = opt_expr {
self.visit_expr(e);
@@ -147,7 +176,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
}
- self.require_break_cx("break", e.span);
+ let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32));
+ let label_sp = match break_label.label {
+ Some(label) => sp_lo.with_hi(label.ident.span.hi()),
+ None => sp_lo.shrink_to_lo(),
+ };
+ self.require_break_cx("break", e.span, label_sp);
}
hir::ExprKind::Continue(destination) => {
self.require_label_in_labeled_block(e.span, &destination, "continue");
@@ -169,7 +203,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
Err(_) => {}
}
- self.require_break_cx("continue", e.span)
+ self.require_break_cx("continue", e.span, e.span)
}
_ => intravisit::walk_expr(self, e),
}
@@ -187,7 +221,8 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
self.cx = old_cx;
}
- fn require_break_cx(&self, name: &str, span: Span) {
+ fn require_break_cx(&self, name: &str, span: Span, break_span: Span) {
+ let is_break = name == "break";
match self.cx {
LabeledBlock | Loop(_) => {}
Closure(closure_span) => {
@@ -196,8 +231,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
AsyncClosure(closure_span) => {
self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
}
- Normal | Constant => {
- self.sess.emit_err(OutsideLoop { span, name, is_break: name == "break" });
+ UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
+ let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
+ self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion });
+ }
+ Normal | Constant | Fn | UnlabeledBlock(_) => {
+ self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion: None });
}
}
}
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 1239d6d91..650bb97c4 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -18,43 +18,10 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::CrateType;
use rustc_target::spec::abi::Abi;
-// Returns true if the given item must be inlined because it may be
-// monomorphized or it was marked with `#[inline]`. This will only return
-// true for functions.
-fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenFnAttrs) -> bool {
- if attrs.requests_inline() {
- return true;
- }
-
- match item.kind {
- hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true,
- hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => {
- let generics = tcx.generics_of(item.owner_id);
- generics.requires_monomorphization(tcx)
- }
- _ => false,
- }
-}
-
-fn method_might_be_inlined(
- tcx: TyCtxt<'_>,
- impl_item: &hir::ImplItem<'_>,
- impl_src: LocalDefId,
-) -> bool {
- let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id());
- let generics = tcx.generics_of(impl_item.owner_id);
- if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) {
- return true;
- }
- if let hir::ImplItemKind::Fn(method_sig, _) = &impl_item.kind {
- if method_sig.header.is_const() {
- return true;
- }
- }
- match tcx.hir().find_by_def_id(impl_src) {
- Some(Node::Item(item)) => item_might_be_inlined(tcx, &item, codegen_fn_attrs),
- Some(..) | None => span_bug!(impl_item.span, "impl did is not an item"),
- }
+fn item_might_be_inlined(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ tcx.generics_of(def_id).requires_monomorphization(tcx)
+ || tcx.cross_crate_inlinable(def_id)
+ || tcx.is_const_fn(def_id)
}
// Information needed while computing reachability.
@@ -97,7 +64,9 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
_ => None,
};
- if let Some(res) = res && let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local()) {
+ if let Some(res) = res
+ && let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local())
+ {
if self.def_id_represents_local_inlined_item(def_id.to_def_id()) {
self.worklist.push(def_id);
} else {
@@ -148,9 +117,7 @@ impl<'tcx> ReachableContext<'tcx> {
match self.tcx.hir().find_by_def_id(def_id) {
Some(Node::Item(item)) => match item.kind {
- hir::ItemKind::Fn(..) => {
- item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id))
- }
+ hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, def_id.into()),
_ => false,
},
Some(Node::TraitItem(trait_method)) => match trait_method.kind {
@@ -162,9 +129,7 @@ impl<'tcx> ReachableContext<'tcx> {
Some(Node::ImplItem(impl_item)) => match impl_item.kind {
hir::ImplItemKind::Const(..) => true,
hir::ImplItemKind::Fn(..) => {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- let impl_did = self.tcx.hir().get_parent_item(hir_id);
- method_might_be_inlined(self.tcx, impl_item, impl_did.def_id)
+ item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id())
}
hir::ImplItemKind::Type(_) => false,
},
@@ -224,11 +189,7 @@ impl<'tcx> ReachableContext<'tcx> {
Node::Item(item) => {
match item.kind {
hir::ItemKind::Fn(.., body) => {
- if item_might_be_inlined(
- self.tcx,
- &item,
- self.tcx.codegen_fn_attrs(item.owner_id),
- ) {
+ if item_might_be_inlined(self.tcx, item.owner_id.into()) {
self.visit_nested_body(body);
}
}
@@ -277,8 +238,7 @@ impl<'tcx> ReachableContext<'tcx> {
self.visit_nested_body(body);
}
hir::ImplItemKind::Fn(_, body) => {
- let impl_def_id = self.tcx.local_parent(search_item);
- if method_might_be_inlined(self.tcx, impl_item, impl_def_id) {
+ if item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) {
self.visit_nested_body(body)
}
}
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 9c265e8ec..6a2498f3f 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -3,8 +3,8 @@
use crate::errors;
use rustc_attr::{
- self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
- UnstableReason, VERSION_PLACEHOLDER,
+ self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
+ Unstable, UnstableReason, VERSION_PLACEHOLDER,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_hir as hir;
@@ -24,8 +24,6 @@ use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
-use std::cmp::Ordering;
-use std::iter;
use std::mem::replace;
use std::num::NonZeroU32;
@@ -198,10 +196,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
}
- if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
- if stab.is_none() {
- self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span });
- }
+ if let Some((depr, span)) = &depr && depr.is_since_rustc_version() && stab.is_none() {
+ self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span });
}
if let Some((body_stab, _span)) = body_stab {
@@ -223,40 +219,25 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
// Check if deprecated_since < stable_since. If it is,
// this is *almost surely* an accident.
- if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
- (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
+ if let (
+ &Some(DeprecatedSince::RustcVersion(dep_since)),
+ &attr::Stable { since: stab_since, .. },
+ ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level)
{
- // Explicit version of iter::order::lt to handle parse errors properly
- for (dep_v, stab_v) in
- iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.'))
- {
- match stab_v.parse::<u64>() {
- Err(_) => {
- self.tcx.sess.emit_err(errors::InvalidStability { span, item_sp });
- break;
+ match stab_since {
+ StableSince::Current => {
+ self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
+ }
+ StableSince::Version(stab_since) => {
+ if dep_since < stab_since {
+ self.tcx
+ .sess
+ .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
}
- Ok(stab_vp) => match dep_v.parse::<u64>() {
- Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
- Ordering::Less => {
- self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
- span,
- item_sp,
- });
- break;
- }
- Ordering::Equal => continue,
- Ordering::Greater => break,
- },
- Err(_) => {
- if dep_v != "TBD" {
- self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
- span,
- item_sp,
- });
- }
- break;
- }
- },
+ }
+ StableSince::Err => {
+ // An error already reported. Assume the unparseable stabilization
+ // version is older than the deprecation version.
}
}
}
@@ -998,14 +979,17 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
all_implications: &FxHashMap<Symbol, Symbol>,
) {
for (feature, since) in defined_features {
- if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) {
+ if let Some(since) = since
+ && let Some(span) = remaining_lib_features.get(&feature)
+ {
// Warn if the user has enabled an already-stable lib feature.
if let Some(implies) = all_implications.get(&feature) {
- unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since);
+ unnecessary_partially_stable_feature_lint(
+ tcx, *span, *feature, *implies, *since,
+ );
} else {
unnecessary_stable_feature_lint(tcx, *span, *feature, *since);
}
-
}
remaining_lib_features.remove(feature);
@@ -1106,7 +1090,7 @@ fn unnecessary_stable_feature_lint(
mut since: Symbol,
) {
if since.as_str() == VERSION_PLACEHOLDER {
- since = rust_version_symbol();
+ since = sym::env_CFG_RELEASE;
}
tcx.emit_spanned_lint(
lint::builtin::STABLE_FEATURES,
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 75e071f1f..9a6fb88c2 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -26,7 +26,9 @@ pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) {
for id in crate_items.foreign_items() {
let attrs = tcx.hir().attrs(id.hir_id());
if let Some((lang_item, _)) = lang_items::extract(attrs) {
- if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() {
+ if let Some(item) = LangItem::from_name(lang_item)
+ && item.is_weak()
+ {
if items.get(item).is_none() {
items.missing.push(item);
}