mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 01:04:03 +00:00
Auto merge of #80641 - Danue1:patch-1, r=oli-obk
Add visitors for checking #[inline] For #80564
This commit is contained in:
commit
d4e3570db4
@ -38,12 +38,14 @@ pub enum Target {
|
|||||||
Enum,
|
Enum,
|
||||||
Variant,
|
Variant,
|
||||||
Struct,
|
Struct,
|
||||||
|
Field,
|
||||||
Union,
|
Union,
|
||||||
Trait,
|
Trait,
|
||||||
TraitAlias,
|
TraitAlias,
|
||||||
Impl,
|
Impl,
|
||||||
Expression,
|
Expression,
|
||||||
Statement,
|
Statement,
|
||||||
|
Arm,
|
||||||
AssocConst,
|
AssocConst,
|
||||||
Method(MethodKind),
|
Method(MethodKind),
|
||||||
AssocTy,
|
AssocTy,
|
||||||
@ -51,6 +53,7 @@ pub enum Target {
|
|||||||
ForeignStatic,
|
ForeignStatic,
|
||||||
ForeignTy,
|
ForeignTy,
|
||||||
GenericParam(GenericParamKind),
|
GenericParam(GenericParamKind),
|
||||||
|
MacroDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Target {
|
impl Display for Target {
|
||||||
@ -73,12 +76,14 @@ impl Display for Target {
|
|||||||
Target::Enum => "enum",
|
Target::Enum => "enum",
|
||||||
Target::Variant => "enum variant",
|
Target::Variant => "enum variant",
|
||||||
Target::Struct => "struct",
|
Target::Struct => "struct",
|
||||||
|
Target::Field => "struct field",
|
||||||
Target::Union => "union",
|
Target::Union => "union",
|
||||||
Target::Trait => "trait",
|
Target::Trait => "trait",
|
||||||
Target::TraitAlias => "trait alias",
|
Target::TraitAlias => "trait alias",
|
||||||
Target::Impl => "item",
|
Target::Impl => "item",
|
||||||
Target::Expression => "expression",
|
Target::Expression => "expression",
|
||||||
Target::Statement => "statement",
|
Target::Statement => "statement",
|
||||||
|
Target::Arm => "match arm",
|
||||||
Target::AssocConst => "associated const",
|
Target::AssocConst => "associated const",
|
||||||
Target::Method(_) => "method",
|
Target::Method(_) => "method",
|
||||||
Target::AssocTy => "associated type",
|
Target::AssocTy => "associated type",
|
||||||
@ -90,6 +95,7 @@ impl Display for Target {
|
|||||||
GenericParamKind::Lifetime => "lifetime parameter",
|
GenericParamKind::Lifetime => "lifetime parameter",
|
||||||
GenericParamKind::Const => "const parameter",
|
GenericParamKind::Const => "const parameter",
|
||||||
},
|
},
|
||||||
|
Target::MacroDef => "macro def",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use rustc_hir::def::{DefKind, Res};
|
|||||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||||
use rustc_hir::definitions::{DefKey, DefPath, Definitions};
|
use rustc_hir::definitions::{DefKey, DefPath, Definitions};
|
||||||
use rustc_hir::intravisit;
|
use rustc_hir::intravisit;
|
||||||
|
use rustc_hir::intravisit::Visitor;
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||||
use rustc_hir::*;
|
use rustc_hir::*;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
@ -494,6 +495,15 @@ impl<'hir> Map<'hir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn visit_exported_macros_in_krate<V>(&self, visitor: &mut V)
|
||||||
|
where
|
||||||
|
V: Visitor<'hir>,
|
||||||
|
{
|
||||||
|
for id in self.krate().exported_macros {
|
||||||
|
visitor.visit_macro_def(self.expect_macro_def(id.hir_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
|
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
|
||||||
pub fn get(&self, id: HirId) -> Node<'hir> {
|
pub fn get(&self, id: HirId) -> Node<'hir> {
|
||||||
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
|
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
|
||||||
@ -802,6 +812,13 @@ impl<'hir> Map<'hir> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expect_macro_def(&self, id: HirId) -> &'hir MacroDef<'hir> {
|
||||||
|
match self.find(id) {
|
||||||
|
Some(Node::MacroDef(macro_def)) => macro_def,
|
||||||
|
_ => bug!("expected macro def, found {}", self.node_to_string(id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> {
|
pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> {
|
||||||
match self.find(id) {
|
match self.find(id) {
|
||||||
Some(Node::Expr(expr)) => expr,
|
Some(Node::Expr(expr)) => expr,
|
||||||
@ -821,6 +838,7 @@ impl<'hir> Map<'hir> {
|
|||||||
Node::GenericParam(param) => param.name.ident().name,
|
Node::GenericParam(param) => param.name.ident().name,
|
||||||
Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
|
Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
|
||||||
Node::Ctor(..) => self.name(self.get_parent_item(id)),
|
Node::Ctor(..) => self.name(self.get_parent_item(id)),
|
||||||
|
Node::MacroDef(md) => md.ident.name,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -70,27 +70,27 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
|
is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
|
||||||
self.check_inline(hir_id, attr, span, target)
|
self.check_inline(hir_id, attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::non_exhaustive) {
|
} else if self.tcx.sess.check_name(attr, sym::non_exhaustive) {
|
||||||
self.check_non_exhaustive(attr, span, target)
|
self.check_non_exhaustive(hir_id, attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::marker) {
|
} else if self.tcx.sess.check_name(attr, sym::marker) {
|
||||||
self.check_marker(attr, span, target)
|
self.check_marker(hir_id, attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::target_feature) {
|
} else if self.tcx.sess.check_name(attr, sym::target_feature) {
|
||||||
self.check_target_feature(hir_id, attr, span, target)
|
self.check_target_feature(hir_id, attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::track_caller) {
|
} else if self.tcx.sess.check_name(attr, sym::track_caller) {
|
||||||
self.check_track_caller(&attr.span, attrs, span, target)
|
self.check_track_caller(hir_id, &attr.span, attrs, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::doc) {
|
} else if self.tcx.sess.check_name(attr, sym::doc) {
|
||||||
self.check_doc_attrs(attr, hir_id, target)
|
self.check_doc_attrs(attr, hir_id, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::no_link) {
|
} else if self.tcx.sess.check_name(attr, sym::no_link) {
|
||||||
self.check_no_link(&attr, span, target)
|
self.check_no_link(hir_id, &attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::export_name) {
|
} else if self.tcx.sess.check_name(attr, sym::export_name) {
|
||||||
self.check_export_name(&attr, span, target)
|
self.check_export_name(hir_id, &attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) {
|
} else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) {
|
||||||
self.check_rustc_args_required_const(&attr, span, target, item)
|
self.check_rustc_args_required_const(&attr, span, target, item)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) {
|
} else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) {
|
||||||
self.check_allow_internal_unstable(&attr, span, target, &attrs)
|
self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) {
|
} else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) {
|
||||||
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
|
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
|
||||||
} else if self.tcx.sess.check_name(attr, sym::naked) {
|
} else if self.tcx.sess.check_name(attr, sym::naked) {
|
||||||
self.check_naked(attr, span, target)
|
self.check_naked(hir_id, attr, span, target)
|
||||||
} else {
|
} else {
|
||||||
// lint-only checks
|
// lint-only checks
|
||||||
if self.tcx.sess.check_name(attr, sym::cold) {
|
if self.tcx.sess.check_name(attr, sym::cold) {
|
||||||
@ -118,6 +118,41 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
self.check_used(attrs, target);
|
self.check_used(attrs, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
|
||||||
|
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||||
|
lint.build(&format!(
|
||||||
|
"`#[{}]` is ignored on struct fields, match arms and macro defs",
|
||||||
|
sym,
|
||||||
|
))
|
||||||
|
.warn(
|
||||||
|
"this was previously accepted by the compiler but is \
|
||||||
|
being phased out; it will become a hard error in \
|
||||||
|
a future release!",
|
||||||
|
)
|
||||||
|
.note(
|
||||||
|
"see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
|
||||||
|
for more information",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
|
||||||
|
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
|
||||||
|
lint.build(&format!("`#[{}]` is ignored on struct fields and match arms", sym))
|
||||||
|
.warn(
|
||||||
|
"this was previously accepted by the compiler but is \
|
||||||
|
being phased out; it will become a hard error in \
|
||||||
|
a future release!",
|
||||||
|
)
|
||||||
|
.note(
|
||||||
|
"see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
|
||||||
|
for more information",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
|
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
|
||||||
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||||
match target {
|
match target {
|
||||||
@ -150,6 +185,11 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
});
|
});
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
// FIXME(#80564): Same for fields, arms, and macro defs
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline");
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
@ -165,10 +205,18 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if `#[naked]` is applied to a function definition.
|
/// Checks if `#[naked]` is applied to a function definition.
|
||||||
fn check_naked(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||||
match target {
|
match target {
|
||||||
Target::Fn
|
Target::Fn
|
||||||
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
|
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
@ -186,6 +234,7 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
|
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
|
||||||
fn check_track_caller(
|
fn check_track_caller(
|
||||||
&self,
|
&self,
|
||||||
|
hir_id: HirId,
|
||||||
attr_span: &Span,
|
attr_span: &Span,
|
||||||
attrs: &'hir [Attribute],
|
attrs: &'hir [Attribute],
|
||||||
span: &Span,
|
span: &Span,
|
||||||
@ -203,6 +252,16 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
|
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[track_caller]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
for attr in attrs {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
@ -218,9 +277,23 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
|
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
|
||||||
fn check_non_exhaustive(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
fn check_non_exhaustive(
|
||||||
|
&self,
|
||||||
|
hir_id: HirId,
|
||||||
|
attr: &Attribute,
|
||||||
|
span: &Span,
|
||||||
|
target: Target,
|
||||||
|
) -> bool {
|
||||||
match target {
|
match target {
|
||||||
Target::Struct | Target::Enum | Target::Variant => true,
|
Target::Struct | Target::Enum | Target::Variant => true,
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[non_exhaustive]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
@ -236,9 +309,17 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
|
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
|
||||||
fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||||
match target {
|
match target {
|
||||||
Target::Trait => true,
|
Target::Trait => true,
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[marker]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
@ -276,6 +357,14 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
});
|
});
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[target_feature]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
@ -464,6 +553,13 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
||||||
match target {
|
match target {
|
||||||
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
|
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[cold]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// FIXME: #[cold] was previously allowed on non-functions and some crates used
|
// FIXME: #[cold] was previously allowed on non-functions and some crates used
|
||||||
// this, so only emit a warning.
|
// this, so only emit a warning.
|
||||||
@ -485,6 +581,13 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
||||||
match target {
|
match target {
|
||||||
Target::ForeignFn | Target::ForeignStatic => {}
|
Target::ForeignFn | Target::ForeignStatic => {}
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[link_name]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// FIXME: #[cold] was previously allowed on non-functions/statics and some crates
|
// FIXME: #[cold] was previously allowed on non-functions/statics and some crates
|
||||||
// used this, so only emit a warning.
|
// used this, so only emit a warning.
|
||||||
@ -517,23 +620,49 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
|
/// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
|
||||||
fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
|
||||||
if target == Target::ExternCrate {
|
match target {
|
||||||
true
|
Target::ExternCrate => true,
|
||||||
} else {
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
self.tcx
|
// `#[no_link]` attribute with just a lint, because we previously
|
||||||
.sess
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
.struct_span_err(attr.span, "attribute should be applied to an `extern crate` item")
|
// with crates depending on them, we can't throw an error here.
|
||||||
.span_label(*span, "not an `extern crate` item")
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
.emit();
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
|
||||||
false
|
true
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(
|
||||||
|
attr.span,
|
||||||
|
"attribute should be applied to an `extern crate` item",
|
||||||
|
)
|
||||||
|
.span_label(*span, "not an `extern crate` item")
|
||||||
|
.emit();
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
|
/// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
|
||||||
fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
|
fn check_export_name(
|
||||||
|
&self,
|
||||||
|
hir_id: HirId,
|
||||||
|
attr: &Attribute,
|
||||||
|
span: &Span,
|
||||||
|
target: Target,
|
||||||
|
) -> bool {
|
||||||
match target {
|
match target {
|
||||||
Target::Static | Target::Fn | Target::Method(..) => true,
|
Target::Static | Target::Fn | Target::Method(..) => true,
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[export_name]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
|
||||||
|
true
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
@ -625,6 +754,13 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
||||||
match target {
|
match target {
|
||||||
Target::Static | Target::Fn | Target::Method(..) => {}
|
Target::Static | Target::Fn | Target::Method(..) => {}
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[link_section]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// FIXME: #[link_section] was previously allowed on non-functions/statics and some
|
// FIXME: #[link_section] was previously allowed on non-functions/statics and some
|
||||||
// crates used this, so only emit a warning.
|
// crates used this, so only emit a warning.
|
||||||
@ -646,6 +782,13 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
|
||||||
match target {
|
match target {
|
||||||
Target::Static | Target::Fn | Target::Method(..) => {}
|
Target::Static | Target::Fn | Target::Method(..) => {}
|
||||||
|
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||||
|
// `#[no_mangle]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
|
// FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
|
||||||
// crates used this, so only emit a warning.
|
// crates used this, so only emit a warning.
|
||||||
@ -828,27 +971,46 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
/// (Allows proc_macro functions)
|
/// (Allows proc_macro functions)
|
||||||
fn check_allow_internal_unstable(
|
fn check_allow_internal_unstable(
|
||||||
&self,
|
&self,
|
||||||
|
hir_id: HirId,
|
||||||
attr: &Attribute,
|
attr: &Attribute,
|
||||||
span: &Span,
|
span: &Span,
|
||||||
target: Target,
|
target: Target,
|
||||||
attrs: &[Attribute],
|
attrs: &[Attribute],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
debug!("Checking target: {:?}", target);
|
debug!("Checking target: {:?}", target);
|
||||||
if target == Target::Fn {
|
match target {
|
||||||
for attr in attrs {
|
Target::Fn => {
|
||||||
if self.tcx.sess.is_proc_macro_attr(attr) {
|
for attr in attrs {
|
||||||
debug!("Is proc macro attr");
|
if self.tcx.sess.is_proc_macro_attr(attr) {
|
||||||
return true;
|
debug!("Is proc macro attr");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
debug!("Is not proc macro attr");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Target::MacroDef => true,
|
||||||
|
// FIXME(#80564): We permit struct fields and match arms to have an
|
||||||
|
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm => {
|
||||||
|
self.inline_attr_str_error_without_macro_def(
|
||||||
|
hir_id,
|
||||||
|
attr,
|
||||||
|
"allow_internal_unstable",
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(attr.span, "attribute should be applied to a macro")
|
||||||
|
.span_label(*span, "not a macro")
|
||||||
|
.emit();
|
||||||
|
false
|
||||||
}
|
}
|
||||||
debug!("Is not proc macro attr");
|
|
||||||
}
|
}
|
||||||
self.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(attr.span, "attribute should be applied to a macro")
|
|
||||||
.span_label(*span, "not a macro")
|
|
||||||
.emit();
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
|
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
|
||||||
@ -860,17 +1022,29 @@ impl CheckAttrVisitor<'tcx> {
|
|||||||
span: &Span,
|
span: &Span,
|
||||||
target: Target,
|
target: Target,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Target::Fn | Target::Method(_) = target {
|
match target {
|
||||||
if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) {
|
Target::Fn | Target::Method(_)
|
||||||
return true;
|
if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
// FIXME(#80564): We permit struct fields and match arms to have an
|
||||||
|
// `#[allow_internal_unstable]` attribute with just a lint, because we previously
|
||||||
|
// erroneously allowed it and some crates used it accidentally, to to be compatible
|
||||||
|
// with crates depending on them, we can't throw an error here.
|
||||||
|
Target::Field | Target::Arm | Target::MacroDef => {
|
||||||
|
self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.tcx
|
||||||
|
.sess
|
||||||
|
.struct_span_err(attr.span, "attribute should be applied to `const fn`")
|
||||||
|
.span_label(*span, "not a `const fn`")
|
||||||
|
.emit();
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tcx
|
|
||||||
.sess
|
|
||||||
.struct_span_err(attr.span, "attribute should be applied to `const fn`")
|
|
||||||
.span_label(*span, "not a `const fn`")
|
|
||||||
.emit();
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,6 +1085,33 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
|
|||||||
intravisit::walk_trait_item(self, trait_item)
|
intravisit::walk_trait_item(self, trait_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_struct_field(&mut self, struct_field: &'tcx hir::StructField<'tcx>) {
|
||||||
|
self.check_attributes(
|
||||||
|
struct_field.hir_id,
|
||||||
|
&struct_field.attrs,
|
||||||
|
&struct_field.span,
|
||||||
|
Target::Field,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
intravisit::walk_struct_field(self, struct_field);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
|
||||||
|
self.check_attributes(arm.hir_id, &arm.attrs, &arm.span, Target::Arm, None);
|
||||||
|
intravisit::walk_arm(self, arm);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
|
||||||
|
self.check_attributes(
|
||||||
|
macro_def.hir_id,
|
||||||
|
¯o_def.attrs,
|
||||||
|
¯o_def.span,
|
||||||
|
Target::MacroDef,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
intravisit::walk_macro_def(self, macro_def);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
|
fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
|
||||||
let target = Target::from_foreign_item(f_item);
|
let target = Target::from_foreign_item(f_item);
|
||||||
self.check_attributes(
|
self.check_attributes(
|
||||||
@ -999,11 +1200,28 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
|
||||||
|
for attr in attrs {
|
||||||
|
if tcx.sess.check_name(attr, sym::inline) {
|
||||||
|
struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
attr.span,
|
||||||
|
E0518,
|
||||||
|
"attribute should be applied to function or closure",
|
||||||
|
)
|
||||||
|
.span_label(attr.span, "not a function or closure")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||||
tcx.hir()
|
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
|
||||||
.visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
|
tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
|
||||||
|
tcx.hir().visit_exported_macros_in_krate(check_attr_visitor);
|
||||||
|
check_invalid_macro_level_attr(tcx, tcx.hir().krate().non_exported_macro_attrs);
|
||||||
if module_def_id.is_top_level_module() {
|
if module_def_id.is_top_level_module() {
|
||||||
CheckAttrVisitor { tcx }.check_attributes(
|
check_attr_visitor.check_attributes(
|
||||||
CRATE_HIR_ID,
|
CRATE_HIR_ID,
|
||||||
tcx.hir().krate_attrs(),
|
tcx.hir().krate_attrs(),
|
||||||
&DUMMY_SP,
|
&DUMMY_SP,
|
||||||
|
@ -6,4 +6,20 @@ fn f() {}
|
|||||||
#[inline] //~ ERROR: attribute should be applied to function or closure
|
#[inline] //~ ERROR: attribute should be applied to function or closure
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
|
struct I {
|
||||||
|
#[inline]
|
||||||
|
i: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
#[inline]
|
||||||
|
macro_rules! m_e {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline] //~ ERROR: attribute should be applied to function or closure
|
||||||
|
macro_rules! m {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -6,6 +6,12 @@ LL | #[inline]
|
|||||||
LL | struct S;
|
LL | struct S;
|
||||||
| --------- not a function or closure
|
| --------- not a function or closure
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0518]: attribute should be applied to function or closure
|
||||||
|
--> $DIR/attr-usage-inline.rs:20:1
|
||||||
|
|
|
||||||
|
LL | #[inline]
|
||||||
|
| ^^^^^^^^^ not a function or closure
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0518`.
|
For more information about this error, try `rustc --explain E0518`.
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
// aux-build:internal_unstable.rs
|
// aux-build:internal_unstable.rs
|
||||||
|
|
||||||
#![feature(allow_internal_unstable)]
|
#![feature(allow_internal_unstable)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate internal_unstable;
|
extern crate internal_unstable;
|
||||||
|
|
||||||
|
struct Baz {
|
||||||
|
#[allow_internal_unstable]
|
||||||
|
//^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms
|
||||||
|
baz: u8,
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! foo {
|
macro_rules! foo {
|
||||||
($e: expr, $f: expr) => {{
|
($e: expr, $f: expr) => {{
|
||||||
$e;
|
$e;
|
||||||
@ -40,4 +47,10 @@ fn main() {
|
|||||||
println!("{:?}", internal_unstable::unstable()); //~ ERROR use of unstable
|
println!("{:?}", internal_unstable::unstable()); //~ ERROR use of unstable
|
||||||
|
|
||||||
bar!(internal_unstable::unstable()); //~ ERROR use of unstable
|
bar!(internal_unstable::unstable()); //~ ERROR use of unstable
|
||||||
|
|
||||||
|
match true {
|
||||||
|
#[allow_internal_unstable]
|
||||||
|
//^ WARN `#[allow_internal_unstable]` is ignored on struct fields and match arms
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0658]: use of unstable library feature 'function'
|
error[E0658]: use of unstable library feature 'function'
|
||||||
--> $DIR/internal-unstable.rs:34:25
|
--> $DIR/internal-unstable.rs:41:25
|
||||||
|
|
|
|
||||||
LL | pass_through_allow!(internal_unstable::unstable());
|
LL | pass_through_allow!(internal_unstable::unstable());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable());
|
|||||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: use of unstable library feature 'function'
|
error[E0658]: use of unstable library feature 'function'
|
||||||
--> $DIR/internal-unstable.rs:36:27
|
--> $DIR/internal-unstable.rs:43:27
|
||||||
|
|
|
|
||||||
LL | pass_through_noallow!(internal_unstable::unstable());
|
LL | pass_through_noallow!(internal_unstable::unstable());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable());
|
|||||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: use of unstable library feature 'function'
|
error[E0658]: use of unstable library feature 'function'
|
||||||
--> $DIR/internal-unstable.rs:40:22
|
--> $DIR/internal-unstable.rs:47:22
|
||||||
|
|
|
|
||||||
LL | println!("{:?}", internal_unstable::unstable());
|
LL | println!("{:?}", internal_unstable::unstable());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable());
|
|||||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: use of unstable library feature 'function'
|
error[E0658]: use of unstable library feature 'function'
|
||||||
--> $DIR/internal-unstable.rs:42:10
|
--> $DIR/internal-unstable.rs:49:10
|
||||||
|
|
|
|
||||||
LL | bar!(internal_unstable::unstable());
|
LL | bar!(internal_unstable::unstable());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -31,7 +31,7 @@ LL | bar!(internal_unstable::unstable());
|
|||||||
= help: add `#![feature(function)]` to the crate attributes to enable
|
= help: add `#![feature(function)]` to the crate attributes to enable
|
||||||
|
|
||||||
error[E0658]: use of unstable library feature 'function'
|
error[E0658]: use of unstable library feature 'function'
|
||||||
--> $DIR/internal-unstable.rs:12:9
|
--> $DIR/internal-unstable.rs:19:9
|
||||||
|
|
|
|
||||||
LL | internal_unstable::unstable();
|
LL | internal_unstable::unstable();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -21,7 +21,9 @@ fn non_macro_expanded_location<#[repr(C)] T>() {
|
|||||||
//~^ ERROR `repr` is ambiguous
|
//~^ ERROR `repr` is ambiguous
|
||||||
//~| ERROR attribute should be applied to a struct, enum, or union
|
//~| ERROR attribute should be applied to a struct, enum, or union
|
||||||
match 0u8 {
|
match 0u8 {
|
||||||
#[repr(C)] //~ ERROR `repr` is ambiguous
|
#[repr(C)]
|
||||||
|
//~^ ERROR `repr` is ambiguous
|
||||||
|
//~| ERROR attribute should be applied to a struct, enum, or union
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0425]: cannot find value `NonExistent` in this scope
|
error[E0425]: cannot find value `NonExistent` in this scope
|
||||||
--> $DIR/ambiguous-builtin-attrs.rs:32:5
|
--> $DIR/ambiguous-builtin-attrs.rs:34:5
|
||||||
|
|
|
|
||||||
LL | NonExistent;
|
LL | NonExistent;
|
||||||
| ^^^^^^^^^^^ not found in this scope
|
| ^^^^^^^^^^^ not found in this scope
|
||||||
@ -61,14 +61,14 @@ LL | use builtin_attrs::*;
|
|||||||
= help: use `crate::repr` to refer to this attribute macro unambiguously
|
= help: use `crate::repr` to refer to this attribute macro unambiguously
|
||||||
|
|
||||||
error[E0659]: `allow` is ambiguous (built-in attribute vs any other name)
|
error[E0659]: `allow` is ambiguous (built-in attribute vs any other name)
|
||||||
--> $DIR/ambiguous-builtin-attrs.rs:36:3
|
--> $DIR/ambiguous-builtin-attrs.rs:38:3
|
||||||
|
|
|
|
||||||
LL | #[allow(unused)]
|
LL | #[allow(unused)]
|
||||||
| ^^^^^ ambiguous name
|
| ^^^^^ ambiguous name
|
||||||
|
|
|
|
||||||
= note: `allow` could refer to a built-in attribute
|
= note: `allow` could refer to a built-in attribute
|
||||||
note: `allow` could also refer to the built-in attribute imported here
|
note: `allow` could also refer to the built-in attribute imported here
|
||||||
--> $DIR/ambiguous-builtin-attrs.rs:35:5
|
--> $DIR/ambiguous-builtin-attrs.rs:37:5
|
||||||
|
|
|
|
||||||
LL | use deny as allow;
|
LL | use deny as allow;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
@ -94,7 +94,16 @@ error[E0517]: attribute should be applied to a struct, enum, or union
|
|||||||
LL | fn non_macro_expanded_location<#[repr(C)] T>() {
|
LL | fn non_macro_expanded_location<#[repr(C)] T>() {
|
||||||
| ^ - not a struct, enum, or union
|
| ^ - not a struct, enum, or union
|
||||||
|
|
||||||
error: aborting due to 8 previous errors
|
error[E0517]: attribute should be applied to a struct, enum, or union
|
||||||
|
--> $DIR/ambiguous-builtin-attrs.rs:24:16
|
||||||
|
|
|
||||||
|
LL | #[repr(C)]
|
||||||
|
| ^
|
||||||
|
...
|
||||||
|
LL | _ => {}
|
||||||
|
| ------- not a struct, enum, or union
|
||||||
|
|
||||||
|
error: aborting due to 9 previous errors
|
||||||
|
|
||||||
Some errors have detailed explanations: E0425, E0517, E0659.
|
Some errors have detailed explanations: E0425, E0517, E0659.
|
||||||
For more information about an error, try `rustc --explain E0425`.
|
For more information about an error, try `rustc --explain E0425`.
|
||||||
|
Loading…
Reference in New Issue
Block a user