mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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:
@@ -3515,6 +3515,7 @@ dependencies = [
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_hir",
|
||||
"rustc_macros",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -334,7 +334,7 @@ macro_rules! error_codes {
|
||||
0551,
|
||||
0552,
|
||||
0554,
|
||||
0556,
|
||||
0556, // REMOVED: merged with other attribute error codes
|
||||
0557,
|
||||
0559,
|
||||
0560,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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: ...);
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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,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)]
|
||||
|
||||
@@ -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 _: () =
|
||||
{
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
|
||||
|
|
||||
|
||||
@@ -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 { }
|
||||
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
Reference in New Issue
Block a user