Rollup merge of #152985 - JonathanBrouwer:convert-feature, r=jdonszelmann

Port `#[feature]` to the new attribute system

Rebase of https://github.com/rust-lang/rust/pull/146652
This commit is contained in:
Jonathan Brouwer
2026-02-23 20:46:13 +01:00
committed by GitHub
30 changed files with 340 additions and 299 deletions
+1
View File
@@ -3515,6 +3515,7 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_hir",
"rustc_macros",
"rustc_session",
"rustc_span",
+1
View File
@@ -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" }
+18 -5
View File
@@ -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;
@@ -647,17 +650,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()
@@ -672,7 +685,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;
@@ -301,3 +301,49 @@ impl<S: Stage> NoArgsAttributeParser<S> for DefaultLibAllocatorParser {
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::DefaultLibAllocator;
}
pub(crate) struct FeatureParser;
impl<S: Stage> CombineAttributeParser<S> for FeatureParser {
const PATH: &[Symbol] = &[sym::feature];
type Item = Ident;
const CONVERT: ConvertFn<Self::Item> = 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<Item = Self::Item> {
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
}
}
@@ -157,6 +157,7 @@ mod late {
Combine<AllowInternalUnstableParser>,
Combine<CrateTypeParser>,
Combine<DebuggerViualizerParser>,
Combine<FeatureParser>,
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
Combine<ReprParser>,
@@ -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!
+1 -1
View File
@@ -334,7 +334,7 @@ macro_rules! error_codes {
0551,
0552,
0554,
0556,
0556, // REMOVED: merged with other attribute error codes
0557,
0559,
0560,
+43 -55
View File
@@ -7,8 +7,8 @@
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 @@
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<ast::MetaItemInner> {
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 <https://github.com/rust-lang/rust/pull/{pull}> for more information",
@@ -92,7 +72,7 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
"".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 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
}
// 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 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
// 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 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
// 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);
}
}
-28
View File
@@ -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 {
@@ -954,6 +954,9 @@ pub enum AttributeKind {
/// Represents `#[export_stable]`.
ExportStable,
/// Represents `#[feature(...)]`
Feature(ThinVec<Ident>, Span),
/// Represents `#[ffi_const]`.
FfiConst(Span),
@@ -45,6 +45,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
EiiImpls(..) => No,
ExportName { .. } => Yes,
ExportStable => No,
Feature(..) => No,
FfiConst(..) => No,
FfiPure(..) => No,
Fundamental { .. } => Yes,
+4 -6
View File
@@ -1120,12 +1120,10 @@ fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
);
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);
}
}
}
+72 -64
View File
@@ -253,6 +253,7 @@ fn check_attributes(
| AttributeKind::EiiForeignItem
| AttributeKind::ExportName { .. }
| AttributeKind::ExportStable
| AttributeKind::Feature(..)
| AttributeKind::FfiConst(..)
| AttributeKind::Fundamental
| AttributeKind::Ignore { .. }
@@ -1564,75 +1565,82 @@ fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) {
fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute, style: Option<AttrStyle>) {
// 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();
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(
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,
@@ -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::*;
+1 -1
View File
@@ -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::*;
+1 -1
View File
@@ -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::*;
+4 -4
View File
@@ -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: ...);
+1 -1
View File
@@ -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::*;
+1 -1
View File
@@ -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() {}
+1 -1
View File
@@ -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)]
+4 -4
View File
@@ -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 _: () =
{
+8 -8
View File
@@ -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
@@ -1,4 +1,4 @@
#![forbid(unstable_features)]
#![feature(intrinsics)] //~ ERROR unstable feature
fn main() { }
fn main() {}
+30 -18
View File
@@ -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`.
@@ -859,26 +859,26 @@ mod inner { #![crate_type="0800"] }
#[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
}
@@ -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
|
+6 -5
View File
@@ -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
@@ -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 { }
+6 -21
View File
@@ -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::*;
@@ -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::*;