diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 4e3310d3fb097..5831636a81b2c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -7,7 +7,7 @@ use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; use rustc_session::Session; use rustc_session::parse::{feature_err, feature_warn}; -use rustc_span::{DUMMY_SP, Span, Spanned, Symbol, sym}; +use rustc_span::{Span, Spanned, Symbol, sym}; use thin_vec::ThinVec; use crate::errors; @@ -646,14 +646,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) let mut errored = false; if let Some(Attribute::Parsed(AttributeKind::Feature(feature_idents, first_span))) = - AttributeParser::parse_limited( - sess, - &krate.attrs, - &[sym::feature], - DUMMY_SP, - krate.id, - Some(&features), - ) + AttributeParser::parse_limited(sess, &krate.attrs, &[sym::feature]) { // `feature(...)` used on non-nightly. This is definitely an error. let mut err = errors::FeatureOnNonNightly { diff --git a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs index 913ebe3e9604d..a5364f968b219 100644 --- a/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs +++ b/compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs @@ -16,7 +16,9 @@ impl OnUnknownParser { args: &ArgParser, mode: Mode, ) { - if !cx.features().diagnostic_on_unknown() { + if let Some(features) = cx.features + && !features.diagnostic_on_unknown() + { // `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs return; } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index ad5a541d3a25d..7432d9ca8749c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -161,9 +161,9 @@ impl, S: Stage> AttributeParser for Single if let Some(pa) = T::convert(cx, args) { if let Some((_, used)) = group.1 { T::ON_DUPLICATE.exec::(cx, used, cx.attr_span); + } else { + group.1 = Some((pa, cx.attr_span)); } - - group.1 = Some((pa, cx.attr_span)); } }, )]; diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 85e714a1a917c..a7bbb5f8f7586 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -2,7 +2,7 @@ use std::convert::identity; use rustc_ast as ast; use rustc_ast::token::DocFragmentKind; -use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety}; +use rustc_ast::{AttrItemKind, AttrStyle, CRATE_NODE_ID, NodeId, Safety}; use rustc_errors::{DiagCtxtHandle, MultiSpan}; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -52,18 +52,16 @@ impl<'sess> AttributeParser<'sess, Early> { sess: &'sess Session, attrs: &[ast::Attribute], sym: &'static [Symbol], - target_span: Span, - target_node_id: NodeId, - features: Option<&'sess Features>, ) -> Option { Self::parse_limited_should_emit( sess, attrs, sym, - target_span, - target_node_id, - Target::Crate, // Does not matter, we're not going to emit errors anyways - features, + // Because we're not emitting warnings/errors, the target should not matter + DUMMY_SP, + CRATE_NODE_ID, + Target::Crate, + None, ShouldEmit::Nothing, ) } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index ae0078523adbc..ace4048af26c1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -493,7 +493,7 @@ impl<'a> TraitDef<'a> { match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr], item.span, item.id, None), + AttributeParser::parse_limited(cx.sess, &item.attrs, &[sym::repr]), Some(Attribute::Parsed(AttributeKind::Repr { reprs, .. })) if reprs.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 84f2a8e35b02c..aa936b46eec20 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -1,7 +1,7 @@ use std::{mem, slice}; use rustc_ast::visit::{self, Visitor}; -use rustc_ast::{self as ast, HasNodeId, NodeId, attr}; +use rustc_ast::{self as ast, NodeId, attr}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; use rustc_errors::DiagCtxtHandle; @@ -109,9 +109,6 @@ impl<'a> CollectProcMacros<'a> { self.session, slice::from_ref(attr), &[sym::proc_macro_derive], - item.span, - item.node_id(), - None, ) else { return; diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 071b807109b71..1b761614f3e6d 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -3,7 +3,7 @@ use std::{assert_matches, iter}; -use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents}; +use rustc_ast::{self as ast, GenericParamKind, attr, join_path_idents}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, Diag, Level}; @@ -480,14 +480,7 @@ fn should_ignore_message(i: &ast::Item) -> Option { fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { if let Some(Attribute::Parsed(AttributeKind::ShouldPanic { reason, .. })) = - AttributeParser::parse_limited( - cx.sess, - &i.attrs, - &[sym::should_panic], - i.span, - i.node_id(), - None, - ) + AttributeParser::parse_limited(cx.sess, &i.attrs, &[sym::should_panic]) { ShouldPanic::Yes(reason) } else { diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 1c947ea07d1a9..adcf4086fb1e4 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -61,7 +61,7 @@ pub fn inject( // Do this here so that the test_runner crate attribute gets marked as used // even in non-test builds - let test_runner = get_test_runner(sess, features, krate); + let test_runner = get_test_runner(sess, krate); if sess.is_test_crate() { let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) { @@ -387,15 +387,8 @@ fn get_test_name(i: &ast::Item) -> Option { attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker) } -fn get_test_runner(sess: &Session, features: &Features, krate: &ast::Crate) -> Option { - match AttributeParser::parse_limited( - sess, - &krate.attrs, - &[sym::test_runner], - krate.spans.inner_span, - krate.id, - Some(features), - ) { +fn get_test_runner(sess: &Session, krate: &ast::Crate) -> Option { + match AttributeParser::parse_limited(sess, &krate.attrs, &[sym::test_runner]) { Some(rustc_hir::Attribute::Parsed(AttributeKind::TestRunner(path))) => Some(path), _ => None, } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index bb9c63d224327..c15c3c229398c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -712,8 +712,7 @@ fn print_crate_info( let crate_name = passes::get_crate_name(sess, attrs); let lint_store = crate::unerased_lint_store(sess); let features = rustc_expand::config::features(sess, attrs, crate_name); - let registered_tools = - rustc_resolve::registered_tools_ast(sess.dcx(), attrs, sess, &features); + let registered_tools = rustc_resolve::registered_tools_ast(sess.dcx(), attrs, sess); let lint_levels = rustc_lint::LintLevelsBuilder::crate_root( sess, &features, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index f7ab7957b4e50..b5f85536d9cac 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -7,8 +7,8 @@ use rustc_ast::tokenstream::{ AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree, }; use rustc_ast::{ - self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute, - HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, + self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs, + HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; use rustc_attr_parsing::parser::AllowExprMetavar; use rustc_attr_parsing::{ @@ -28,7 +28,7 @@ use rustc_hir::{ use rustc_parse::parser::Recovery; use rustc_session::Session; use rustc_session::parse::feature_err; -use rustc_span::{DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; +use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::instrument; use crate::errors::{ @@ -51,14 +51,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - let mut features = Features::default(); if let Some(hir::Attribute::Parsed(AttributeKind::Feature(feature_idents, _))) = - AttributeParser::parse_limited( - sess, - krate_attrs, - &[sym::feature], - DUMMY_SP, - DUMMY_NODE_ID, - Some(&features), - ) + AttributeParser::parse_limited(sess, krate_attrs, &[sym::feature]) { for feature_ident in feature_idents { // If the enabled feature has been removed, issue an error. diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 66082d782e0bb..ff08898fe93a0 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -313,9 +313,6 @@ impl EarlyLintPass for UnsafeCode { cx.builder.sess(), &it.attrs, &[sym::allow_internal_unsafe], - it.span, - DUMMY_NODE_ID, - Some(cx.builder.features()), ) { self.report_unsafe(cx, span, BuiltinUnsafe::AllowInternalUnsafe); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 297dfac4a5f78..f5f057c9f3eca 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -145,7 +145,7 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, &[sym::repr], it.span, it.id, None), + AttributeParser::parse_limited(cx.sess(), &it.attrs, &[sym::repr]), Some(Attribute::Parsed(AttributeKind::Repr { reprs, ..})) if reprs.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 828ba698e0f2f..1f27384d4e7ca 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -1,7 +1,6 @@ //! Detecting usage of the `#[debugger_visualizer]` attribute. -use rustc_ast::ast::NodeId; -use rustc_ast::{HasNodeId, ItemKind, ast}; +use rustc_ast::{ItemKind, ast}; use rustc_attr_parsing::AttributeParser; use rustc_expand::base::resolve_path; use rustc_hir::Attribute; @@ -10,26 +9,14 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::sym; use crate::errors::DebugVisualizerUnreadable; impl DebuggerVisualizerCollector<'_> { - fn check_for_debugger_visualizer( - &mut self, - attrs: &[ast::Attribute], - span: Span, - node_id: NodeId, - ) { + fn check_for_debugger_visualizer(&mut self, attrs: &[ast::Attribute]) { if let Some(Attribute::Parsed(AttributeKind::DebuggerVisualizer(visualizers))) = - AttributeParser::parse_limited( - &self.sess, - attrs, - &[sym::debugger_visualizer], - span, - node_id, - None, - ) + AttributeParser::parse_limited(&self.sess, attrs, &[sym::debugger_visualizer]) { for DebugVisualizer { span, visualizer_type, path } in visualizers { let file = match resolve_path(&self.sess, path.as_str(), span) { @@ -69,12 +56,12 @@ struct DebuggerVisualizerCollector<'a> { impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> { fn visit_item(&mut self, item: &'ast rustc_ast::Item) -> Self::Result { if let ItemKind::Mod(..) = item.kind { - self.check_for_debugger_visualizer(&item.attrs, item.span, item.node_id()); + self.check_for_debugger_visualizer(&item.attrs); } rustc_ast::visit::walk_item(self, item); } fn visit_crate(&mut self, krate: &'ast ast::Crate) -> Self::Result { - self.check_for_debugger_visualizer(&krate.attrs, DUMMY_SP, krate.id); + self.check_for_debugger_visualizer(&krate.attrs); rustc_ast::visit::walk_crate(self, krate); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 1c6889efe7501..32a5601300338 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1123,14 +1123,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let mut import_all = None; let mut single_imports = ThinVec::new(); if let Some(Attribute::Parsed(AttributeKind::MacroUse { span, arguments })) = - AttributeParser::parse_limited( - self.r.tcx.sess, - &item.attrs, - &[sym::macro_use], - item.span, - item.id, - None, - ) + AttributeParser::parse_limited(self.r.tcx.sess, &item.attrs, &[sym::macro_use]) { if self.parent_scope.module.parent.is_some() { self.r diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d1a3960afd039..225c9e1f85c80 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -154,9 +154,6 @@ impl OnUnknownData { tcx.sess, &item.attrs, &[sym::diagnostic, sym::on_unknown], - item.span, - item.id, - Some(tcx.features()), ) { Some(Self { directive: Box::new(*directive?) }) diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 68242fba473d6..4729029872cfb 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -4,7 +4,7 @@ use std::mem; use std::sync::Arc; -use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, DelegationSuffixes, NodeId}; +use rustc_ast::{self as ast, Crate, DelegationSuffixes, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; @@ -16,7 +16,6 @@ use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion, }; -use rustc_feature::Features; use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; @@ -123,26 +122,18 @@ fn fast_print_path(path: &ast::Path) -> Symbol { pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { let (_, pre_configured_attrs) = &*tcx.crate_for_resolver(()).borrow(); - registered_tools_ast(tcx.dcx(), pre_configured_attrs, tcx.sess, tcx.features()) + registered_tools_ast(tcx.dcx(), pre_configured_attrs, tcx.sess) } pub fn registered_tools_ast( dcx: DiagCtxtHandle<'_>, pre_configured_attrs: &[ast::Attribute], sess: &Session, - features: &Features, ) -> RegisteredTools { let mut registered_tools = RegisteredTools::default(); if let Some(Attribute::Parsed(AttributeKind::RegisterTool(tools, _))) = - AttributeParser::parse_limited( - sess, - pre_configured_attrs, - &[sym::register_tool], - DUMMY_SP, - DUMMY_NODE_ID, - Some(features), - ) + AttributeParser::parse_limited(sess, pre_configured_attrs, &[sym::register_tool]) { for tool in tools { if let Some(old_tool) = registered_tools.replace(tool) { diff --git a/tests/ui/attributes/attr-order-deprecated.rs b/tests/ui/attributes/attr-order-deprecated.rs new file mode 100644 index 0000000000000..606e714819b50 --- /dev/null +++ b/tests/ui/attributes/attr-order-deprecated.rs @@ -0,0 +1,11 @@ +#[deprecated = "AAA"] +//~^ NOTE also specified here +#[deprecated = "BBB"] +//~^ ERROR multiple `deprecated` attributes +fn deprecated() { } + +fn main() { + deprecated(); + //~^ WARN use of deprecated function `deprecated`: AAA [deprecated] + //~| NOTE `#[warn(deprecated)]` on by default +} diff --git a/tests/ui/attributes/attr-order-deprecated.stderr b/tests/ui/attributes/attr-order-deprecated.stderr new file mode 100644 index 0000000000000..41e26bec761ee --- /dev/null +++ b/tests/ui/attributes/attr-order-deprecated.stderr @@ -0,0 +1,22 @@ +error: multiple `deprecated` attributes + --> $DIR/attr-order-deprecated.rs:3:1 + | +LL | #[deprecated = "BBB"] + | ^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/attr-order-deprecated.rs:1:1 + | +LL | #[deprecated = "AAA"] + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: use of deprecated function `deprecated`: AAA + --> $DIR/attr-order-deprecated.rs:8:5 + | +LL | deprecated(); + | ^^^^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/attributes/attr-order-must-use.rs b/tests/ui/attributes/attr-order-must-use.rs new file mode 100644 index 0000000000000..36ffe9d5ed708 --- /dev/null +++ b/tests/ui/attributes/attr-order-must-use.rs @@ -0,0 +1,19 @@ +#![deny(unused)] +//~^ NOTE lint level is defined here + +#[must_use = "AAA"] +//~^ NOTE also specified here +#[must_use = "BBB"] +//~^ ERROR unused attribute +//~| WARN previously accepted +//~| NOTE `#[deny(unused_attributes)]` implied by `#[deny(unused)]` +fn must_use() -> usize { + 0 +} + +fn main() { + must_use(); + //~^ ERROR unused return value of `must_use` that must be used + //~| NOTE AAA + //~| NOTE `#[deny(unused_must_use)]` implied by `#[deny(unused)]` +} diff --git a/tests/ui/attributes/attr-order-must-use.stderr b/tests/ui/attributes/attr-order-must-use.stderr new file mode 100644 index 0000000000000..18b5811623017 --- /dev/null +++ b/tests/ui/attributes/attr-order-must-use.stderr @@ -0,0 +1,34 @@ +error: unused attribute + --> $DIR/attr-order-must-use.rs:6:1 + | +LL | #[must_use = "BBB"] + | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/attr-order-must-use.rs:4:1 + | +LL | #[must_use = "AAA"] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +note: the lint level is defined here + --> $DIR/attr-order-must-use.rs:1:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` + +error: unused return value of `must_use` that must be used + --> $DIR/attr-order-must-use.rs:15:5 + | +LL | must_use(); + | ^^^^^^^^^^ + | + = note: AAA + = note: `#[deny(unused_must_use)]` implied by `#[deny(unused)]` +help: use `let _ = ...` to ignore the resulting value + | +LL | let _ = must_use(); + | +++++++ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/attributes/malformed-no-std.stderr b/tests/ui/attributes/malformed-no-std.stderr index b2187ae0badc9..d46eaf7368e84 100644 --- a/tests/ui/attributes/malformed-no-std.stderr +++ b/tests/ui/attributes/malformed-no-std.stderr @@ -131,10 +131,10 @@ LL | #![no_std(foo = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/malformed-no-std.rs:5:1 + --> $DIR/malformed-no-std.rs:3:1 | -LL | #![no_std("bar")] - | ^^^^^^^^^^^^^^^^^ +LL | #![no_std = "foo"] + | ^^^^^^^^^^^^^^^^^^ warning: unused attribute --> $DIR/malformed-no-std.rs:13:1 @@ -155,10 +155,10 @@ LL | #![no_core(foo = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/malformed-no-std.rs:13:1 + --> $DIR/malformed-no-std.rs:11:1 | -LL | #![no_core("bar")] - | ^^^^^^^^^^^^^^^^^^ +LL | #![no_core = "foo"] + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors; 4 warnings emitted