diff --git a/Cargo.lock b/Cargo.lock index 715d580e051d1..f5a93bfabd2de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3417,6 +3417,7 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fluent_macro", + "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 3e04f8b11ec9d..38c9e67ca0a95 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -14,6 +14,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +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 608ccfefeb69d..d20d05df4d353 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 as ast; use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor}; use rustc_ast::{NodeId, PatKind, attr, token}; +use rustc_attr_parsing::AttributeParser; 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; @@ -587,17 +590,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() @@ -612,7 +625,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/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 81ec17077c13c..510a065d6a85f 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -259,3 +259,7 @@ attr_parsing_whole_archive_needs_static = attr_parsing_limit_invalid = `limit` must be a non-negative integer .label = {$error_str} + +attr_parsing_feature_single_word = + rust features are always a single identifier, not paths with multiple segments + .help = did you maybe mean `{$first_segment}`? diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs index 20ec0fd0c7b63..1cf0127f7a814 100644 --- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs +++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs @@ -1,4 +1,5 @@ use super::prelude::*; +use crate::session_diagnostics::{FeatureExpectedSingleWord, LimitInvalid}; pub(crate) struct CrateNameParser; @@ -147,3 +148,55 @@ impl NoArgsAttributeParser for RustcCoherenceIsCoreParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel; const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore; } + +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::CrateLevel; + const TEMPLATE: AttributeTemplate = template!(List: &["feature1, feature2, ..."]); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator + 'c { + let ArgParser::List(list) = args else { + cx.expected_list(cx.attr_span); + 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 { + let first_segment = elem.path().segments().next().expect("at least one segment"); + cx.emit_err(FeatureExpectedSingleWord { + span: path.span(), + first_segment_span: first_segment.span, + first_segment: first_segment.name, + }); + continue; + }; + + res.push(ident); + } + + res + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index b9929d6f1f8ee..d980233cb1818 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -92,9 +92,15 @@ fn parse_derive_like( return None; }; + // updated if we see `attributes(...)` to keep track of the last + // argument we did accept for the final diagnostic + let mut last = trait_ident.span; + // Parse optional attributes let mut attributes = ThinVec::new(); if let Some(attrs) = items.next() { + last = attrs.span(); + let Some(attr_list) = attrs.meta_item() else { cx.expected_list(attrs.span()); return None; @@ -132,7 +138,7 @@ fn parse_derive_like( // If anything else is specified, we should reject it if let Some(next) = items.next() { - cx.expected_no_args(next.span()); + cx.expected_end_of_list(last, next.span()); } Some((Some(trait_ident.name), attributes)) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d7ccf3c78069c..4de1063ddcc46 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -25,8 +25,9 @@ use crate::attributes::codegen_attrs::{ }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ - CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser, - RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser, + CrateNameParser, FeatureParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, + PatternComplexityLimitParser, RecursionLimitParser, RustcCoherenceIsCoreParser, + TypeLengthLimitParser, }; use crate::attributes::debugger::DebuggerViualizerParser; use crate::attributes::deprecation::DeprecationParser; @@ -165,6 +166,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, Combine, Combine, Combine, @@ -513,6 +515,21 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + /// Expected the end of an argument list. + /// + /// Note: only useful when arguments in an attribute are ordered and we've seen the last one we expected. + /// Most attributes shouldn't care about their argument order. + pub(crate) fn expected_end_of_list(&self, last_item_span: Span, span: Span) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedEnd { last: last_item_span }, + attr_style: self.attr_style, + }) + } + pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2c2b14c8a68bc..c4dacae891ff5 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -605,6 +605,9 @@ pub(crate) enum AttributeParseErrorReason<'a> { list: bool, }, ExpectedIdentifier, + ExpectedEnd { + last: Span, + }, } pub(crate) struct AttributeParseError<'a> { @@ -744,6 +747,10 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { AttributeParseErrorReason::ExpectedIdentifier => { diag.span_label(self.span, "expected a valid identifier here"); } + AttributeParseErrorReason::ExpectedEnd { last } => { + diag.span_label(last, "expected no more arguments after this"); + diag.span_label(self.span, "remove this argument"); + } } if let Some(link) = self.template.docs { @@ -968,3 +975,14 @@ pub(crate) struct LimitInvalid<'a> { pub value_span: Span, pub error_str: &'a str, } + +#[derive(Diagnostic)] +#[diag(attr_parsing_feature_single_word)] +pub(crate) struct FeatureExpectedSingleWord { + #[primary_span] + pub span: Span, + + #[help] + pub first_segment_span: Span, + pub first_segment: Symbol, +} 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 0aff1c06e0a8c..adac13a315fee 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -338,7 +338,7 @@ E0550: 0550, E0551: 0551, E0552: 0552, E0554: 0554, -E0556: 0556, +E0556: 0556, // REMOVED: merged with other attribute error codes E0557: 0557, E0559: 0559, E0560: 0560, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 2925e337071ca..209d5c29af380 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, AttrKind, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, MetaItemInner, - NodeId, NormalAttr, + self as ast, AttrKind, AttrStyle, Attribute, DUMMY_NODE_ID, HasAttrs, HasTokens, MetaItem, + MetaItemInner, NodeId, NormalAttr, }; use rustc_attr_parsing as attr; use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety; @@ -21,16 +21,16 @@ use rustc_feature::{ ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{self as hir}; 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. @@ -45,44 +45,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 +71,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 +80,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 +93,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 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 +124,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 c37c2d88d9cd2..d54fe88e798c8 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -143,30 +143,6 @@ pub(crate) struct RecursionLimitReached { pub crate_name: Symbol, } -#[derive(Diagnostic)] -#[diag(expand_malformed_feature_attribute, code = E0556)] -pub(crate) struct MalformedFeatureAttribute { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub help: MalformedFeatureAttributeHelp, -} - -#[derive(Subdiagnostic)] -pub(crate) enum MalformedFeatureAttributeHelp { - #[label(expand_expected)] - Label { - #[primary_span] - span: Span, - }, - #[suggestion(expand_expected, code = "{suggestion}", applicability = "maybe-incorrect")] - Suggestion { - #[primary_span] - span: Span, - suggestion: Symbol, - }, -} - #[derive(Diagnostic)] #[diag(expand_remove_expr_not_supported)] 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 ddcbaeaad8803..1f1ed164c265f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -528,6 +528,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 1611b865c7726..8f63e60118cd5 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 { Dummy => 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 75a0f89321b97..f03adf700eb5d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1133,12 +1133,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, AttributeKind::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 4ea237cfa0321..afeba95a53a04 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -283,6 +283,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::ObjcSelector { .. } | AttributeKind::RustcCoherenceIsCore(..) | AttributeKind::DebuggerVisualizer(..) + | AttributeKind::Feature(..) ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -1902,75 +1903,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/hir-delegation.pp b/tests/pretty/hir-delegation.pp index f8ad02f2fccce..813b08a18970a 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])] #[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index c0f5b7069a2d7..2d5766aeef463 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -1,12 +1,12 @@ -//@ pretty-compare-only -//@ pretty-mode:hir -//@ pp-exact:hir-fn-variadic.pp - -#![feature(c_variadic)] +#![attr = Feature([c_variadic#0])] #[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; +//@ pretty-compare-only +//@ pretty-mode:hir +//@ pp-exact:hir-fn-variadic.pp + 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 beca5988017dc..8ba1726947be6 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])] #[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index f0be56ddc6aa4..bfb0d2098aecb 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 | @@ -63,5 +55,11 @@ error: unused attribute LL | #[target_feature()] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute +error: unused attribute + --> $DIR/empty-attributes.rs:7:1 + | +LL | #![feature()] + | ^^^^^^^^^^^^^ help: remove this attribute + 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..268d6511025ff 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 aa5aab41e7258..2cdd32a09e5da 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 @@ -862,26 +862,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 5e2029c45165a..782aa23c041f9 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 @@ -240,17 +240,6 @@ help: add a `!` LL | #![crate_type = "0800"] | + -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:863:1 - | -LL | #[feature(x0600)] - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] - | + - warning: crate-level attribute should be an inner attribute --> $DIR/issue-43106-gating-of-builtin-attrs.rs:888:1 | @@ -487,56 +476,6 @@ help: add a `!` LL | #![crate_type = "0800"] impl S { } | + -warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:867:17 - | -LL | mod inner { #![feature(x0600)] } - | ^^^^^^^^^^^^^^^^^^ - -warning: crate-level attribute should be an inner attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:870: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:874: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:878: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:882:5 - | -LL | #[feature(x0600)] impl S { } - | ^^^^^^^^^^^^^^^^^ - | -help: add a `!` - | -LL | #![feature(x0600)] impl S { } - | + - warning: crate-level attribute should be in the root module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:892:17 | @@ -1380,6 +1319,76 @@ note: This attribute does not have an `!`, which means it is applied to this imp LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^ +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![feature]` + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:863: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:865: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:867: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:870: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:870: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:874: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:874: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:878: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:878: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:882: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:882:23 + | +LL | #[feature(x0600)] impl S { } + | ^^^^^^^^^^ + warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![recursion_limit]` --> $DIR/issue-43106-gating-of-builtin-attrs.rs:936:1 | diff --git a/tests/ui/proc-macro/attribute.rs b/tests/ui/proc-macro/attribute.rs index dfb267383775e..1fd1c919afed5 100644 --- a/tests/ui/proc-macro/attribute.rs +++ b/tests/ui/proc-macro/attribute.rs @@ -10,97 +10,132 @@ use proc_macro::*; //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected this to be a list //~| NOTE for more information, visit -pub fn foo1(input: TokenStream) -> TokenStream { input } +pub fn foo1(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive = ""] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected this to be a list //~| NOTE for more information, visit -pub fn foo2(input: TokenStream) -> TokenStream { input } +pub fn foo2(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d3, a, b)] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE the only valid argument here is `attributes` //~| NOTE for more information, visit -pub fn foo3(input: TokenStream) -> TokenStream { input } +pub fn foo3(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d4, attributes(a), b)] //~^ ERROR malformed `proc_macro_derive` attribute -//~| NOTE didn't expect any arguments here +//~| NOTE expected no more arguments after this +//~| NOTE remove this argument //~| NOTE for more information, visit -pub fn foo4(input: TokenStream) -> TokenStream { input } +pub fn foo4(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive("a")] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE didn't expect a literal here //~| NOTE for more information, visit -pub fn foo5(input: TokenStream) -> TokenStream { input } +pub fn foo5(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d6 = "")] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE didn't expect any arguments here //~| NOTE for more information, visit -pub fn foo6(input: TokenStream) -> TokenStream { input } +pub fn foo6(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(m::d7)] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected a valid identifier here //~| NOTE for more information, visit -pub fn foo7(input: TokenStream) -> TokenStream { input } +pub fn foo7(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d8(a))] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE didn't expect any arguments here //~| NOTE for more information, visit -pub fn foo8(input: TokenStream) -> TokenStream { input } +pub fn foo8(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(self)] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected a valid identifier here //~| NOTE for more information, visit -pub fn foo9(input: TokenStream) -> TokenStream { input } +pub fn foo9(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(PartialEq)] // OK -pub fn foo10(input: TokenStream) -> TokenStream { input } +pub fn foo10(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d11, a)] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE the only valid argument here is `attributes` //~| NOTE for more information, visit -pub fn foo11(input: TokenStream) -> TokenStream { input } +pub fn foo11(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d12, attributes)] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected this to be a list //~| NOTE for more information, visit -pub fn foo12(input: TokenStream) -> TokenStream { input } +pub fn foo12(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d13, attributes("a"))] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected a valid identifier here //~| NOTE for more information, visit -pub fn foo13(input: TokenStream) -> TokenStream { input } +pub fn foo13(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d14, attributes(a = ""))] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE didn't expect any arguments here //~| NOTE for more information, visit -pub fn foo14(input: TokenStream) -> TokenStream { input } +pub fn foo14(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d15, attributes(m::a))] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected a valid identifier here //~| NOTE for more information, visit -pub fn foo15(input: TokenStream) -> TokenStream { input } +pub fn foo15(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d16, attributes(a(b)))] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE didn't expect any arguments here //~| NOTE for more information, visit -pub fn foo16(input: TokenStream) -> TokenStream { input } +pub fn foo16(input: TokenStream) -> TokenStream { + input +} #[proc_macro_derive(d17, attributes(self))] //~^ ERROR malformed `proc_macro_derive` attribute //~| NOTE expected a valid identifier here //~| NOTE for more information, visit -pub fn foo17(input: TokenStream) -> TokenStream { input } +pub fn foo17(input: TokenStream) -> TokenStream { + input +} diff --git a/tests/ui/proc-macro/attribute.stderr b/tests/ui/proc-macro/attribute.stderr index e7127c8ef1d2e..4ff0794287581 100644 --- a/tests/ui/proc-macro/attribute.stderr +++ b/tests/ui/proc-macro/attribute.stderr @@ -13,7 +13,7 @@ LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | ++++++++++++++++++++++++++++++++++++++++++ error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:15:1 + --> $DIR/attribute.rs:17:1 | LL | #[proc_macro_derive = ""] | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected this to be a list @@ -29,7 +29,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:21:1 + --> $DIR/attribute.rs:25:1 | LL | #[proc_macro_derive(d3, a, b)] | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^ @@ -46,13 +46,14 @@ LL - #[proc_macro_derive(d3, a, b)] LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | -error[E0565]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:27:1 +error[E0539]: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:33:1 | LL | #[proc_macro_derive(d4, attributes(a), b)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ - | | - | didn't expect any arguments here + | ^^^^^^^^^^^^^^^^^^^^^^^^-------------^^-^^ + | | | + | | remove this argument + | expected no more arguments after this | = note: for more information, visit help: try changing it to one of the following valid forms of the attribute @@ -65,7 +66,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0565]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:33:1 + --> $DIR/attribute.rs:42:1 | LL | #[proc_macro_derive("a")] | ^^^^^^^^^^^^^^^^^^^^---^^ @@ -83,7 +84,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0565]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:39:1 + --> $DIR/attribute.rs:50:1 | LL | #[proc_macro_derive(d6 = "")] | ^^^^^^^^^^^^^^^^^^^^^^^----^^ @@ -101,7 +102,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:45:1 + --> $DIR/attribute.rs:58:1 | LL | #[proc_macro_derive(m::d7)] | ^^^^^^^^^^^^^^^^^^^^-----^^ @@ -119,7 +120,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0565]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:51:1 + --> $DIR/attribute.rs:66:1 | LL | #[proc_macro_derive(d8(a))] | ^^^^^^^^^^^^^^^^^^^^^^---^^ @@ -137,7 +138,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:57:1 + --> $DIR/attribute.rs:74:1 | LL | #[proc_macro_derive(self)] | ^^^^^^^^^^^^^^^^^^^^----^^ @@ -155,7 +156,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:66:1 + --> $DIR/attribute.rs:87:1 | LL | #[proc_macro_derive(d11, a)] | ^^^^^^^^^^^^^^^^^^^^^^^^^-^^ @@ -173,7 +174,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:72:1 + --> $DIR/attribute.rs:95:1 | LL | #[proc_macro_derive(d12, attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^----------^^ @@ -191,7 +192,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:78:1 + --> $DIR/attribute.rs:103:1 | LL | #[proc_macro_derive(d13, attributes("a"))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^ @@ -209,7 +210,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0565]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:84:1 + --> $DIR/attribute.rs:111:1 | LL | #[proc_macro_derive(d14, attributes(a = ""))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^ @@ -227,7 +228,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:90:1 + --> $DIR/attribute.rs:119:1 | LL | #[proc_macro_derive(d15, attributes(m::a))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^ @@ -245,7 +246,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0565]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:96:1 + --> $DIR/attribute.rs:127:1 | LL | #[proc_macro_derive(d16, attributes(a(b)))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^ @@ -263,7 +264,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))] | error[E0539]: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:102:1 + --> $DIR/attribute.rs:135:1 | LL | #[proc_macro_derive(d17, attributes(self))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^ diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout index 7ad29c88bcfe5..a93ddaadf7021 100644 --- a/tests/ui/type-alias-impl-trait/issue-60662.stdout +++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout @@ -1,12 +1,12 @@ -//@ check-pass -//@ compile-flags: -Z unpretty=hir -//@ edition: 2015 - -#![feature(type_alias_impl_trait)] +#![attr = Feature([type_alias_impl_trait#0])] #[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import] use ::std::prelude::rust_2015::*; +//@ check-pass +//@ compile-flags: -Z unpretty=hir +//@ edition: 2015 + trait Animal { } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 27cba6560300a..31a1cbe4fc704 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -8,27 +8,12 @@ // 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(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, yeet_expr#0])] #[attr = MacroUse {arguments: UseAll}] extern crate std; #[prelude_import]