diff --git a/Cargo.lock b/Cargo.lock index cfed18eee113c..f0917ce4df51a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3515,6 +3515,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_feature", + "rustc_hir", "rustc_macros", "rustc_session", "rustc_span", diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index fdc735fa8d4ff..c9def6246d1b1 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -13,6 +13,7 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 891570b053e53..8dfec76b22ef8 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -1,11 +1,14 @@ use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{self as ast, AttrVec, NodeId, PatKind, attr, token}; +use rustc_attr_parsing::AttributeParser; use rustc_errors::msg; use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features}; +use rustc_hir::Attribute; +use rustc_hir::attrs::AttributeKind; use rustc_session::Session; use rustc_session::parse::{feature_err, feature_warn}; use rustc_span::source_map::Spanned; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use thin_vec::ThinVec; use crate::errors; @@ -636,17 +639,27 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) return; } let mut errored = false; - for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { + + 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), + ) + { // `feature(...)` used on non-nightly. This is definitely an error. let mut err = errors::FeatureOnNonNightly { - span: attr.span, + span: first_span, channel: option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"), stable_features: vec![], sugg: None, }; let mut all_stable = true; - for ident in attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident()) { + for ident in feature_idents { let name = ident.name; let stable_since = features .enabled_lang_features() @@ -661,7 +674,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) } } if all_stable { - err.sugg = Some(attr.span); + err.sugg = Some(first_span); } sess.dcx().emit_err(err); errored = true; diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 3b3bbf4f0c8af..176af5cdd192e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -301,3 +301,49 @@ impl NoArgsAttributeParser for DefaultLibAllocatorParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator; } + +pub(crate) struct FeatureParser; + +impl CombineAttributeParser for FeatureParser { + const PATH: &[Symbol] = &[sym::feature]; + type Item = Ident; + const CONVERT: ConvertFn = AttributeKind::Feature; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]); + + fn extend( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser, + ) -> impl IntoIterator { + let ArgParser::List(list) = args else { + cx.expected_list(cx.attr_span, args); + return Vec::new(); + }; + + if list.is_empty() { + cx.warn_empty_attribute(cx.attr_span); + } + + let mut res = Vec::new(); + + for elem in list.mixed() { + let Some(elem) = elem.meta_item() else { + cx.expected_identifier(elem.span()); + continue; + }; + if let Err(arg_span) = elem.args().no_args() { + cx.expected_no_args(arg_span); + continue; + } + + let path = elem.path(); + let Some(ident) = path.word() else { + cx.expected_identifier(path.span()); + continue; + }; + res.push(ident); + } + + res + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index b4e91ecebeeb7..7212abbf81243 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -157,6 +157,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, Combine, Combine, Combine, diff --git a/compiler/rustc_error_codes/src/error_codes/E0556.md b/compiler/rustc_error_codes/src/error_codes/E0556.md index 2aac8240d293a..d1eeddc3ab102 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0556.md +++ b/compiler/rustc_error_codes/src/error_codes/E0556.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + The `feature` attribute was badly formed. Erroneous code example: -```compile_fail,E0556 +```compile_fail #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] // error! #![feature] // error! #![feature = "foo"] // error! diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 0537ba23de944..eff9b9d323c25 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -334,7 +334,7 @@ macro_rules! error_codes { 0551, 0552, 0554, -0556, +0556, // REMOVED: merged with other attribute error codes 0557, 0559, 0560, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index a8a305310238e..8e4039b32d942 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, EarlyParsedAttribute, HasAttrs, - HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, + self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, EarlyParsedAttribute, + HasAttrs, HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::{ @@ -20,18 +20,19 @@ use rustc_feature::{ ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; -use rustc_hir::Target; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{ + Target, {self as hir}, +}; use rustc_parse::parser::Recovery; use rustc_session::Session; use rustc_session::parse::feature_err; -use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; -use thin_vec::ThinVec; +use rustc_span::{DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::instrument; use crate::errors::{ CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved, - FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp, - RemoveExprNotSupported, + FeatureRemovedReason, InvalidCfg, RemoveExprNotSupported, }; /// A folder that strips out items that do not belong in the current configuration. @@ -46,44 +47,23 @@ pub struct StripUnconfigured<'a> { } pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features { - fn feature_list(attr: &Attribute) -> ThinVec { - if attr.has_name(sym::feature) - && let Some(list) = attr.meta_item_list() - { - list - } else { - ThinVec::new() - } - } - let mut features = Features::default(); - // Process all features enabled in the code. - for attr in krate_attrs { - for mi in feature_list(attr) { - let name = match mi.ident() { - Some(ident) if mi.is_word() => ident.name, - Some(ident) => { - sess.dcx().emit_err(MalformedFeatureAttribute { - span: mi.span(), - help: MalformedFeatureAttributeHelp::Suggestion { - span: mi.span(), - suggestion: ident.name, - }, - }); - continue; - } - None => { - sess.dcx().emit_err(MalformedFeatureAttribute { - span: mi.span(), - help: MalformedFeatureAttributeHelp::Label { span: mi.span() }, - }); - continue; - } - }; - + 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), + ) + { + for feature_ident in feature_idents { // If the enabled feature has been removed, issue an error. - if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) { + if let Some(f) = + REMOVED_LANG_FEATURES.iter().find(|f| feature_ident.name == f.feature.name) + { let pull_note = if let Some(pull) = f.pull { format!( "; see for more information", @@ -92,7 +72,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - "".to_owned() }; sess.dcx().emit_err(FeatureRemoved { - span: mi.span(), + span: feature_ident.span, reason: f.reason.map(|reason| FeatureRemovedReason { reason }), removed_rustc_version: f.feature.since, pull_note, @@ -101,10 +81,10 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - } // If the enabled feature is stable, record it. - if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) { + if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| feature_ident.name == f.name) { features.set_enabled_lang_feature(EnabledLangFeature { - gate_name: name, - attr_sp: mi.span(), + gate_name: feature_ident.name, + attr_sp: feature_ident.span, stable_since: Some(Symbol::intern(f.since)), }); continue; @@ -114,25 +94,30 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // unstable and not also listed as one of the allowed features, // issue an error. if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() { - if allowed.iter().all(|f| name.as_str() != f) { - sess.dcx().emit_err(FeatureNotAllowed { span: mi.span(), name }); + if allowed.iter().all(|f| feature_ident.name.as_str() != f) { + sess.dcx().emit_err(FeatureNotAllowed { + span: feature_ident.span, + name: feature_ident.name, + }); continue; } } // If the enabled feature is unstable, record it. - if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() { + if UNSTABLE_LANG_FEATURES.iter().find(|f| feature_ident.name == f.name).is_some() { // When the ICE comes from a standard library crate, there's a chance that the person // hitting the ICE may be using -Zbuild-std or similar with an untested target. // The bug is probably in the standard library and not the compiler in that case, // but that doesn't really matter - we want a bug report. - if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { + if features.internal(feature_ident.name) + && !STDLIB_STABLE_CRATES.contains(&crate_name) + { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } features.set_enabled_lang_feature(EnabledLangFeature { - gate_name: name, - attr_sp: mi.span(), + gate_name: feature_ident.name, + attr_sp: feature_ident.span, stable_since: None, }); continue; @@ -140,12 +125,15 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // Otherwise, the feature is unknown. Enable it as a lib feature. // It will be checked later whether the feature really exists. - features - .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() }); + features.set_enabled_lib_feature(EnabledLibFeature { + gate_name: feature_ident.name, + attr_sp: feature_ident.span, + }); // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. - if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { + if features.internal(feature_ident.name) && !STDLIB_STABLE_CRATES.contains(&crate_name) + { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 70e386ceb95ec..8285733c68aa7 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -183,34 +183,6 @@ pub(crate) struct RecursionLimitReached { pub crate_name: Symbol, } -#[derive(Diagnostic)] -#[diag("malformed `feature` attribute input", code = E0556)] -pub(crate) struct MalformedFeatureAttribute { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub help: MalformedFeatureAttributeHelp, -} - -#[derive(Subdiagnostic)] -pub(crate) enum MalformedFeatureAttributeHelp { - #[label("expected just one word")] - Label { - #[primary_span] - span: Span, - }, - #[suggestion( - "expected just one word", - code = "{suggestion}", - applicability = "maybe-incorrect" - )] - Suggestion { - #[primary_span] - span: Span, - suggestion: Symbol, - }, -} - #[derive(Diagnostic)] #[diag("removing an expression is not supported in this position")] pub(crate) struct RemoveExprNotSupported { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 5d154cef66a65..820c43bcd81dc 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -954,6 +954,9 @@ pub enum AttributeKind { /// Represents `#[export_stable]`. ExportStable, + /// Represents `#[feature(...)]` + Feature(ThinVec, Span), + /// Represents `#[ffi_const]`. FfiConst(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 0b20ea4d6a83a..f0684818417f5 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -45,6 +45,7 @@ impl AttributeKind { EiiImpls(..) => No, ExportName { .. } => Yes, ExportStable => No, + Feature(..) => No, FfiConst(..) => No, FfiPure(..) => No, Fundamental { .. } => Yes, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index c83de3b38eb5b..22636959f0db5 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1120,12 +1120,10 @@ declare_lint_pass!( ); impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { - fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) { - if attr.has_name(sym::feature) - && let Some(items) = attr.meta_item_list() - { - for item in items { - cx.emit_span_lint(UNSTABLE_FEATURES, item.span(), BuiltinUnstableFeatures); + fn check_attributes(&mut self, cx: &LateContext<'_>, attrs: &[hir::Attribute]) { + if let Some(features) = find_attr!(attrs, Feature(features, _) => features) { + for feature in features { + cx.emit_span_lint(UNSTABLE_FEATURES, feature.span, BuiltinUnstableFeatures); } } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9af9398d78b96..40f4694b5cce6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -253,6 +253,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::EiiForeignItem | AttributeKind::ExportName { .. } | AttributeKind::ExportStable + | AttributeKind::Feature(..) | AttributeKind::FfiConst(..) | AttributeKind::Fundamental | AttributeKind::Ignore { .. } @@ -1564,75 +1565,82 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option) { // Warn on useless empty attributes. // FIXME(jdonszelmann): this lint should be moved to attribute parsing, see `AcceptContext::warn_empty_attribute` - let note = if attr.has_any_name(&[ - sym::allow, - sym::expect, - sym::warn, - sym::deny, - sym::forbid, - sym::feature, - ]) && attr.meta_item_list().is_some_and(|list| list.is_empty()) - { - errors::UnusedNote::EmptyList { name: attr.name().unwrap() } - } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) - && let Some(meta) = attr.meta_item_list() - && let [meta] = meta.as_slice() - && let Some(item) = meta.meta_item() - && let MetaItemKind::NameValue(_) = &item.kind - && item.path == sym::reason - { - errors::UnusedNote::NoLints { name: attr.name().unwrap() } - } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect]) - && let Some(meta) = attr.meta_item_list() - && meta.iter().any(|meta| { - meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) - }) - { - if hir_id != CRATE_HIR_ID { - match style { - Some(ast::AttrStyle::Outer) => { - let attr_span = attr.span(); - let bang_position = self - .tcx - .sess - .source_map() - .span_until_char(attr_span, '[') - .shrink_to_hi(); - - self.tcx.emit_node_span_lint( + let note = + if attr.has_any_name(&[sym::allow, sym::expect, sym::warn, sym::deny, sym::forbid]) + && attr.meta_item_list().is_some_and(|list| list.is_empty()) + { + errors::UnusedNote::EmptyList { name: attr.name().unwrap() } + } else if attr.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::expect, + ]) && let Some(meta) = attr.meta_item_list() + && let [meta] = meta.as_slice() + && let Some(item) = meta.meta_item() + && let MetaItemKind::NameValue(_) = &item.kind + && item.path == sym::reason + { + errors::UnusedNote::NoLints { name: attr.name().unwrap() } + } else if attr.has_any_name(&[ + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::expect, + ]) && let Some(meta) = attr.meta_item_list() + && meta.iter().any(|meta| { + meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) + }) + { + if hir_id != CRATE_HIR_ID { + match style { + Some(ast::AttrStyle::Outer) => { + let attr_span = attr.span(); + let bang_position = self + .tcx + .sess + .source_map() + .span_until_char(attr_span, '[') + .shrink_to_hi(); + + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::OuterCrateLevelAttr { + suggestion: errors::OuterCrateLevelAttrSuggestion { + bang_position, + }, + }, + ) + } + Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr_span, - errors::OuterCrateLevelAttr { - suggestion: errors::OuterCrateLevelAttrSuggestion { bang_position }, - }, - ) - } - Some(ast::AttrStyle::Inner) | None => self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::InnerCrateLevelAttr, - ), - }; - return; - } else { - let never_needs_link = self - .tcx - .crate_types() - .iter() - .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib)); - if never_needs_link { - errors::UnusedNote::LinkerMessagesBinaryCrateOnly - } else { + attr.span(), + errors::InnerCrateLevelAttr, + ), + }; return; + } else { + let never_needs_link = self + .tcx + .crate_types() + .iter() + .all(|kind| matches!(kind, CrateType::Rlib | CrateType::StaticLib)); + if never_needs_link { + errors::UnusedNote::LinkerMessagesBinaryCrateOnly + } else { + return; + } } - } - } else if attr.has_name(sym::default_method_body_is_const) { - errors::UnusedNote::DefaultMethodBodyConst - } else { - return; - }; + } else if attr.has_name(sym::default_method_body_is_const) { + errors::UnusedNote::DefaultMethodBodyConst + } else { + return; + }; self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, diff --git a/tests/pretty/delegation-inherit-attributes.pp b/tests/pretty/delegation-inherit-attributes.pp index 26ca5e99b885d..bfe5ba03c37d4 100644 --- a/tests/pretty/delegation-inherit-attributes.pp +++ b/tests/pretty/delegation-inherit-attributes.pp @@ -5,7 +5,7 @@ //@ pp-exact:delegation-inherit-attributes.pp #![allow(incomplete_features)] -#![feature(fn_delegation)] +#![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use std::prelude::rust_2021::*; diff --git a/tests/pretty/delegation-inline-attribute.pp b/tests/pretty/delegation-inline-attribute.pp index 9f362fa863f82..54442a210d937 100644 --- a/tests/pretty/delegation-inline-attribute.pp +++ b/tests/pretty/delegation-inline-attribute.pp @@ -3,7 +3,7 @@ //@ pp-exact:delegation-inline-attribute.pp #![allow(incomplete_features)] -#![feature(fn_delegation)] +#![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index 59491b6ebd7c1..efa643313e6b4 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -3,7 +3,7 @@ //@ pp-exact:hir-delegation.pp #![allow(incomplete_features)] -#![feature(fn_delegation)] +#![attr = Feature([fn_delegation#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index 3837b260cc5d6..30423349241b7 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -1,11 +1,11 @@ +#![attr = Feature([c_variadic#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; //@ pretty-compare-only //@ pretty-mode:hir //@ pp-exact:hir-fn-variadic.pp -#![feature(c_variadic)] -extern crate std; -#[attr = PreludeImport] -use ::std::prelude::rust_2015::*; extern "C" { unsafe fn foo(x: i32, va1: ...); diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp index e422edf54e0c5..6c9dec2bfb1fb 100644 --- a/tests/pretty/pin-ergonomics-hir.pp +++ b/tests/pretty/pin-ergonomics-hir.pp @@ -2,8 +2,8 @@ //@ pretty-mode:hir //@ pp-exact:pin-ergonomics-hir.pp -#![feature(pin_ergonomics)] #![allow(dead_code, incomplete_features)] +#![attr = Feature([pin_ergonomics#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; diff --git a/tests/ui/attributes/attr-mix-new.rs b/tests/ui/attributes/attr-mix-new.rs index c4f080eb8c302..3ddb1d0d7335c 100644 --- a/tests/ui/attributes/attr-mix-new.rs +++ b/tests/ui/attributes/attr-mix-new.rs @@ -5,7 +5,7 @@ #[rustc_dummy(bar)] mod foo { #![feature(globs)] - //~^ WARN crate-level attribute should be in the root module + //~^ WARN the `#![feature]` attribute can only be used at the crate root } fn main() {} diff --git a/tests/ui/attributes/attr-mix-new.stderr b/tests/ui/attributes/attr-mix-new.stderr index c1bb8a550bcca..628d93ff534e4 100644 --- a/tests/ui/attributes/attr-mix-new.stderr +++ b/tests/ui/attributes/attr-mix-new.stderr @@ -1,4 +1,4 @@ -warning: crate-level attribute should be in the root module +warning: the `#![feature]` attribute can only be used at the crate root --> $DIR/attr-mix-new.rs:7:3 | LL | #![feature(globs)] diff --git a/tests/ui/consts/const-block-items/hir.stdout b/tests/ui/consts/const-block-items/hir.stdout index 2b7f0818556ff..d031818fdf65b 100644 --- a/tests/ui/consts/const-block-items/hir.stdout +++ b/tests/ui/consts/const-block-items/hir.stdout @@ -1,10 +1,10 @@ -//@ build-pass -//@ compile-flags: -Zunpretty=hir - -#![feature(const_block_items)] +#![attr = Feature([const_block_items#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*; +//@ build-pass +//@ compile-flags: -Zunpretty=hir + const _: () = { diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index 41dc790737dd1..146a9af946d6c 100644 --- a/tests/ui/empty/empty-attributes.stderr +++ b/tests/ui/empty/empty-attributes.stderr @@ -43,14 +43,6 @@ LL | #![forbid()] | = note: attribute `forbid` with an empty list has no effect -error: unused attribute - --> $DIR/empty-attributes.rs:7:1 - | -LL | #![feature()] - | ^^^^^^^^^^^^^ help: remove this attribute - | - = note: attribute `feature` with an empty list has no effect - error: unused attribute --> $DIR/empty-attributes.rs:9:1 | @@ -67,5 +59,13 @@ LL | #[target_feature()] | = note: using `target_feature` with an empty list has no effect +error: unused attribute + --> $DIR/empty-attributes.rs:7:1 + | +LL | #![feature()] + | ^^^^^^^^^^^^^ help: remove this attribute + | + = note: using `feature` with an empty list has no effect + error: aborting due to 8 previous errors diff --git a/tests/ui/feature-gates/feature-gate-feature-gate.rs b/tests/ui/feature-gates/feature-gate-feature-gate.rs index 3c98e16a136a8..b5b6a8da91bd7 100644 --- a/tests/ui/feature-gates/feature-gate-feature-gate.rs +++ b/tests/ui/feature-gates/feature-gate-feature-gate.rs @@ -1,4 +1,4 @@ #![forbid(unstable_features)] #![feature(intrinsics)] //~ ERROR unstable feature -fn main() { } +fn main() {} diff --git a/tests/ui/feature-gates/gated-bad-feature.stderr b/tests/ui/feature-gates/gated-bad-feature.stderr index e0e84d842352d..afcc6b6f11c49 100644 --- a/tests/ui/feature-gates/gated-bad-feature.stderr +++ b/tests/ui/feature-gates/gated-bad-feature.stderr @@ -1,15 +1,3 @@ -error[E0556]: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:1:25 - | -LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] - | ^^^^^^^^ help: expected just one word: `foo` - -error[E0556]: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:1:35 - | -LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] - | ^^^^^^^^^^^ help: expected just one word: `foo` - error[E0557]: feature has been removed --> $DIR/gated-bad-feature.rs:8:12 | @@ -18,17 +6,41 @@ LL | #![feature(test_removed_feature)] | = note: removed in 1.0.0 -error: malformed `feature` attribute input +error[E0565]: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:1:1 + | +LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![feature(feature1, feature2, ...)]` + +error[E0565]: malformed `feature` attribute input + --> $DIR/gated-bad-feature.rs:1:1 + | +LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^ + | | | + | | didn't expect any arguments here + | help: must be of the form: `#![feature(feature1, feature2, ...)]` + +error[E0539]: malformed `feature` attribute input --> $DIR/gated-bad-feature.rs:6:1 | LL | #![feature] - | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]` + | ^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#![feature(feature1, feature2, ...)]` -error: malformed `feature` attribute input +error[E0539]: malformed `feature` attribute input --> $DIR/gated-bad-feature.rs:7:1 | LL | #![feature = "foo"] - | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]` + | ^^^^^^^^^^^-------^ + | | | + | | expected this to be a list + | help: must be of the form: `#![feature(feature1, feature2, ...)]` error[E0635]: unknown feature `foo_bar_baz` --> $DIR/gated-bad-feature.rs:1:12 @@ -44,5 +56,5 @@ LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] error: aborting due to 7 previous errors -Some errors have detailed explanations: E0556, E0557, E0635. -For more information about an error, try `rustc --explain E0556`. +Some errors have detailed explanations: E0539, E0557, E0565, E0635. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs index 83debd17777ae..294cdf659744a 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs @@ -859,26 +859,26 @@ mod crate_type { #[feature(x0600)] //~^ WARN crate-level attribute should be an inner attribute -//~| HELP add a `!` mod feature { +//~^ NOTE this attribute does not have an `!`, which means it is applied to this module mod inner { #![feature(x0600)] } -//~^ WARN crate-level attribute should be in the root module + //~^ WARN the `#![feature]` attribute can only be used at the crate root #[feature(x0600)] fn f() { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this function #[feature(x0600)] struct S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this struct #[feature(x0600)] type T = S; //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this type alias #[feature(x0600)] impl S { } //~^ WARN crate-level attribute should be an inner attribute - //~| HELP add a `!` + //~| NOTE this attribute does not have an `!`, which means it is applied to this implementation block } diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index 482980dde3bf5..b282bcef8960a 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -207,17 +207,6 @@ note: the lint level is defined here LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:1 - | -LL | #[feature(x0600)] - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] - | + - warning: attribute should be applied to an `extern` block with non-Rust ABI --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 | @@ -282,56 +271,6 @@ LL | #[link(name = "x")] extern "Rust" {} | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:17 - | -LL | mod inner { #![feature(x0600)] } - | ^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 - | -LL | #[feature(x0600)] fn f() { } - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] fn f() { } - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 - | -LL | #[feature(x0600)] struct S; - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] struct S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 - | -LL | #[feature(x0600)] type T = S; - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] type T = S; - | + - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:5 - | -LL | #[feature(x0600)] impl S { } - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] impl S { } - | + - warning: `#[macro_use]` attribute cannot be used on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5 | @@ -1303,6 +1242,76 @@ note: this attribute does not have an `!`, which means it is applied to this imp LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^ +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:860:1 + | +LL | #[feature(x0600)] + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this module + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:862:1 + | +LL | / mod feature { +LL | | +LL | | mod inner { #![feature(x0600)] } +... | +LL | | } + | |_^ + +warning: the `#![feature]` attribute can only be used at the crate root + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:864:17 + | +LL | mod inner { #![feature(x0600)] } + | ^^^^^^^^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:5 + | +LL | #[feature(x0600)] fn f() { } + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:23 + | +LL | #[feature(x0600)] fn f() { } + | ^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:5 + | +LL | #[feature(x0600)] struct S; + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this struct + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:871:23 + | +LL | #[feature(x0600)] struct S; + | ^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:5 + | +LL | #[feature(x0600)] type T = S; + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this type alias + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:875:23 + | +LL | #[feature(x0600)] type T = S; + | ^^^^^^^^^^^ + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:5 + | +LL | #[feature(x0600)] impl S { } + | ^^^^^^^^^^^^^^^^^ + | +note: this attribute does not have an `!`, which means it is applied to this implementation block + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:879:23 + | +LL | #[feature(x0600)] impl S { } + | ^^^^^^^^^^ + warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![no_main]` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:885:1 | diff --git a/tests/ui/parser/inner-attr.stderr b/tests/ui/parser/inner-attr.stderr index 3fb2d60ee5b66..0f9c7561490a9 100644 --- a/tests/ui/parser/inner-attr.stderr +++ b/tests/ui/parser/inner-attr.stderr @@ -11,17 +11,18 @@ LL | fn main() {} | = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files -warning: crate-level attribute should be an inner attribute +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` --> $DIR/inner-attr.rs:1:1 | LL | #[feature(lang_items)] | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: requested on the command line with `-W unused-attributes` -help: add a `!` +note: this attribute does not have an `!`, which means it is applied to this function + --> $DIR/inner-attr.rs:4:1 | -LL | #![feature(lang_items)] - | + +LL | fn main() {} + | ^^^^^^^^^^^^ + = note: requested on the command line with `-W unused-attributes` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout index dff748b43119d..99aa6caa30dbd 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.stdout +++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout @@ -1,11 +1,11 @@ +#![attr = Feature([type_alias_impl_trait#0])] +extern crate std; +#[attr = PreludeImport] +use ::std::prelude::rust_2015::*; //@ check-pass //@ compile-flags: -Z unpretty=hir //@ edition: 2015 -#![feature(type_alias_impl_trait)] -extern crate std; -#[attr = PreludeImport] -use ::std::prelude::rust_2015::*; trait Animal { } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 7ee848491d6e5..78403e1704dca 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -8,28 +8,13 @@ // Note: the HIR revision includes a `.stderr` file because there are some // errors that only occur once we get past the AST. -#![feature(auto_traits)] -#![feature(box_patterns)] -#![feature(builtin_syntax)] -#![feature(const_trait_impl)] -#![feature(coroutines)] -#![feature(decl_macro)] -#![feature(deref_patterns)] -#![feature(explicit_tail_calls)] -#![feature(gen_blocks)] -#![feature(more_qualified_paths)] -#![feature(never_patterns)] -#![feature(never_type)] -#![feature(pattern_types)] -#![feature(pattern_type_macro)] -#![feature(prelude_import)] -#![feature(specialization)] -#![feature(trace_macros)] -#![feature(trait_alias)] -#![feature(try_blocks)] -#![feature(try_blocks_heterogeneous)] -#![feature(yeet_expr)] #![allow(incomplete_features)] +#![attr = Feature([auto_traits#0, box_patterns#0, builtin_syntax#0, +const_trait_impl#0, coroutines#0, decl_macro#0, deref_patterns#0, +explicit_tail_calls#0, gen_blocks#0, more_qualified_paths#0, never_patterns#0, +never_type#0, pattern_types#0, pattern_type_macro#0, prelude_import#0, +specialization#0, trace_macros#0, trait_alias#0, try_blocks#0, +try_blocks_heterogeneous#0, yeet_expr#0])] extern crate std; #[attr = PreludeImport] use std::prelude::rust_2024::*; diff --git a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout index c990837d2138a..8c016f5083d24 100644 --- a/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout +++ b/tests/ui/unpretty/struct-exprs-tuple-call-pretty-printing.stdout @@ -1,9 +1,9 @@ //@ compile-flags: -Zunpretty=hir //@ check-pass -#![feature(min_generic_const_args, adt_const_params)] #![expect(incomplete_features)] #![allow(dead_code)] +#![attr = Feature([min_generic_const_args#0, adt_const_params#0])] extern crate std; #[attr = PreludeImport] use ::std::prelude::rust_2015::*;