Rollup merge of #65294 - varkor:lint-inline-prototype, r=matthewjasper

Lint ignored `#[inline]` on function prototypes

Fixes https://github.com/rust-lang/rust/issues/51280.

- Adds a `unused_attribute` lint for `#[inline]` on function prototypes.
- As a consequence, foreign items, impl items and trait items now have their attributes checked, which could cause some code to no longer compile (it was previously erroneously ignored).
This commit is contained in:
Mazdak Farrokhzad 2019-10-29 04:08:18 +01:00 committed by GitHub
commit 42d4e261a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 461 additions and 207 deletions

View File

@ -150,9 +150,9 @@ dependencies = [
[[package]]
name = "bitflags"
version = "1.1.0"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2-rfc"

View File

@ -11,7 +11,7 @@ doctest = false
[dependencies]
arena = { path = "../libarena" }
bitflags = "1.0"
bitflags = "1.2.1"
fmt_macros = { path = "../libfmt_macros" }
graphviz = { path = "../libgraphviz" }
jobserver = "0.1"

View File

@ -2219,7 +2219,7 @@ rejected in your own crates.
"##,
E0736: r##"
#[track_caller] and #[naked] cannot be applied to the same function.
`#[track_caller]` and `#[naked]` cannot both be applied to the same function.
Erroneous code example:
@ -2237,6 +2237,57 @@ See [RFC 2091] for details on this and other limitations.
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
"##,
E0738: r##"
`#[track_caller]` cannot be used in traits yet. This is due to limitations in
the compiler which are likely to be temporary. See [RFC 2091] for details on
this and other restrictions.
Erroneous example with a trait method implementation:
```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
fn bar(&self);
}
impl Foo for u64 {
#[track_caller]
fn bar(&self) {}
}
```
Erroneous example with a blanket trait method implementation:
```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
#[track_caller]
fn bar(&self) {}
fn baz(&self);
}
```
Erroneous example with a trait method declaration:
```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
fn bar(&self) {}
#[track_caller]
fn baz(&self);
}
```
Note that while the compiler may be able to support the attribute in traits in
the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
"##,
;
// E0006, // merged with E0005
// E0101, // replaced with E0282

View File

@ -4,9 +4,11 @@
//! conflicts between multiple such attributes attached to the same
//! item.
use crate::hir;
use crate::hir::{self, HirId, HirVec, Attribute, Item, ItemKind, TraitItem, TraitItemKind};
use crate::hir::DUMMY_HIR_ID;
use crate::hir::def_id::DefId;
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
use crate::lint::builtin::UNUSED_ATTRIBUTES;
use crate::ty::TyCtxt;
use crate::ty::query::Providers;
@ -14,6 +16,12 @@ use std::fmt::{self, Display};
use syntax::{attr, symbol::sym};
use syntax_pos::Span;
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum MethodKind {
Trait { body: bool },
Inherent,
}
#[derive(Copy, Clone, PartialEq)]
pub(crate) enum Target {
ExternCrate,
@ -35,6 +43,12 @@ pub(crate) enum Target {
Impl,
Expression,
Statement,
AssocConst,
Method(MethodKind),
AssocTy,
ForeignFn,
ForeignStatic,
ForeignTy,
}
impl Display for Target {
@ -59,29 +73,76 @@ impl Display for Target {
Target::Impl => "item",
Target::Expression => "expression",
Target::Statement => "statement",
Target::AssocConst => "associated const",
Target::Method(_) => "method",
Target::AssocTy => "associated type",
Target::ForeignFn => "foreign function",
Target::ForeignStatic => "foreign static item",
Target::ForeignTy => "foreign type",
})
}
}
impl Target {
pub(crate) fn from_item(item: &hir::Item) -> Target {
pub(crate) fn from_item(item: &Item) -> Target {
match item.kind {
hir::ItemKind::ExternCrate(..) => Target::ExternCrate,
hir::ItemKind::Use(..) => Target::Use,
hir::ItemKind::Static(..) => Target::Static,
hir::ItemKind::Const(..) => Target::Const,
hir::ItemKind::Fn(..) => Target::Fn,
hir::ItemKind::Mod(..) => Target::Mod,
hir::ItemKind::ForeignMod(..) => Target::ForeignMod,
hir::ItemKind::GlobalAsm(..) => Target::GlobalAsm,
hir::ItemKind::TyAlias(..) => Target::TyAlias,
hir::ItemKind::OpaqueTy(..) => Target::OpaqueTy,
hir::ItemKind::Enum(..) => Target::Enum,
hir::ItemKind::Struct(..) => Target::Struct,
hir::ItemKind::Union(..) => Target::Union,
hir::ItemKind::Trait(..) => Target::Trait,
hir::ItemKind::TraitAlias(..) => Target::TraitAlias,
hir::ItemKind::Impl(..) => Target::Impl,
ItemKind::ExternCrate(..) => Target::ExternCrate,
ItemKind::Use(..) => Target::Use,
ItemKind::Static(..) => Target::Static,
ItemKind::Const(..) => Target::Const,
ItemKind::Fn(..) => Target::Fn,
ItemKind::Mod(..) => Target::Mod,
ItemKind::ForeignMod(..) => Target::ForeignMod,
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
ItemKind::TyAlias(..) => Target::TyAlias,
ItemKind::OpaqueTy(..) => Target::OpaqueTy,
ItemKind::Enum(..) => Target::Enum,
ItemKind::Struct(..) => Target::Struct,
ItemKind::Union(..) => Target::Union,
ItemKind::Trait(..) => Target::Trait,
ItemKind::TraitAlias(..) => Target::TraitAlias,
ItemKind::Impl(..) => Target::Impl,
}
}
fn from_trait_item(trait_item: &TraitItem) -> Target {
match trait_item.kind {
TraitItemKind::Const(..) => Target::AssocConst,
TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
Target::Method(MethodKind::Trait { body: false })
}
TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
Target::Method(MethodKind::Trait { body: true })
}
TraitItemKind::Type(..) => Target::AssocTy,
}
}
fn from_foreign_item(foreign_item: &hir::ForeignItem) -> Target {
match foreign_item.kind {
hir::ForeignItemKind::Fn(..) => Target::ForeignFn,
hir::ForeignItemKind::Static(..) => Target::ForeignStatic,
hir::ForeignItemKind::Type => Target::ForeignTy,
}
}
fn from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem) -> Target {
match impl_item.kind {
hir::ImplItemKind::Const(..) => Target::AssocConst,
hir::ImplItemKind::Method(..) => {
let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id);
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(_, _, _, _, tr, _, _) => tr.is_some(),
_ => bug!("parent of an ImplItem must be an Impl"),
};
if containing_impl_is_for_trait {
Target::Method(MethodKind::Trait { body: true })
} else {
Target::Method(MethodKind::Inherent)
}
}
hir::ImplItemKind::TyAlias(..) | hir::ImplItemKind::OpaqueTy(..) => Target::AssocTy,
}
}
}
@ -92,19 +153,26 @@ struct CheckAttrVisitor<'tcx> {
impl CheckAttrVisitor<'tcx> {
/// Checks any attribute.
fn check_attributes(&self, item: &hir::Item, target: Target) {
fn check_attributes(
&self,
hir_id: HirId,
attrs: &HirVec<Attribute>,
span: &Span,
target: Target,
item: Option<&Item>,
) {
let mut is_valid = true;
for attr in &item.attrs {
for attr in attrs {
is_valid &= if attr.check_name(sym::inline) {
self.check_inline(attr, &item.span, target)
self.check_inline(hir_id, attr, span, target)
} else if attr.check_name(sym::non_exhaustive) {
self.check_non_exhaustive(attr, item, target)
self.check_non_exhaustive(attr, span, target)
} else if attr.check_name(sym::marker) {
self.check_marker(attr, item, target)
self.check_marker(attr, span, target)
} else if attr.check_name(sym::target_feature) {
self.check_target_feature(attr, item, target)
self.check_target_feature(attr, span, target)
} else if attr.check_name(sym::track_caller) {
self.check_track_caller(attr, &item, target)
self.check_track_caller(&attr.span, attrs, span, target)
} else {
true
};
@ -115,59 +183,105 @@ impl CheckAttrVisitor<'tcx> {
}
if target == Target::Fn {
self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.hir_id));
self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
}
self.check_repr(item, target);
self.check_used(item, target);
self.check_repr(attrs, span, target, item);
self.check_used(attrs, target);
}
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) -> bool {
if target != Target::Fn && target != Target::Closure {
struct_span_err!(self.tcx.sess,
attr.span,
E0518,
"attribute should be applied to function or closure")
.span_label(*span, "not a function or closure")
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Fn | Target::Closure | Target::Method(MethodKind::Trait { body: true })
| Target::Method(MethodKind::Inherent) => true,
Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
self.tcx.struct_span_lint_hir(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
"`#[inline]` is ignored on function prototypes",
).emit();
true
}
// FIXME(#65833): We permit associated consts to have an `#[inline]` 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::AssocConst => {
self.tcx.struct_span_lint_hir(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
"`#[inline]` is ignored on constants",
).warn("this was previously accepted by the compiler but is \
being phased out; it will become a hard error in \
a future release!")
.note("for more information, see issue #65833 \
<https://github.com/rust-lang/rust/issues/65833>")
.emit();
false
} else {
true
true
}
_ => {
struct_span_err!(
self.tcx.sess,
attr.span,
E0518,
"attribute should be applied to function or closure",
).span_label(*span, "not a function or closure")
.emit();
false
}
}
}
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
fn check_track_caller(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
if target != Target::Fn {
struct_span_err!(
self.tcx.sess,
attr.span,
E0739,
"attribute should be applied to function"
)
.span_label(item.span, "not a function")
.emit();
false
} else if attr::contains_name(&item.attrs, sym::naked) {
struct_span_err!(
self.tcx.sess,
attr.span,
E0736,
"cannot use `#[track_caller]` with `#[naked]`",
)
.emit();
false
} else {
true
fn check_track_caller(
&self,
attr_span: &Span,
attrs: &HirVec<Attribute>,
span: &Span,
target: Target,
) -> bool {
match target {
Target::Fn if attr::contains_name(attrs, sym::naked) => {
struct_span_err!(
self.tcx.sess,
*attr_span,
E0736,
"cannot use `#[track_caller]` with `#[naked]`",
).emit();
false
}
Target::Fn | Target::Method(MethodKind::Inherent) => true,
Target::Method(_) => {
struct_span_err!(
self.tcx.sess,
*attr_span,
E0738,
"`#[track_caller]` may not be used on trait methods",
).emit();
false
}
_ => {
struct_span_err!(
self.tcx.sess,
*attr_span,
E0739,
"attribute should be applied to function"
)
.span_label(*span, "not a function")
.emit();
false
}
}
}
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
fn check_non_exhaustive(
&self,
attr: &hir::Attribute,
item: &hir::Item,
attr: &Attribute,
span: &Span,
target: Target,
) -> bool {
match target {
@ -177,7 +291,7 @@ impl CheckAttrVisitor<'tcx> {
attr.span,
E0701,
"attribute can only be applied to a struct or enum")
.span_label(item.span, "not a struct or enum")
.span_label(*span, "not a struct or enum")
.emit();
false
}
@ -185,13 +299,13 @@ impl CheckAttrVisitor<'tcx> {
}
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) -> bool {
fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Trait => true,
_ => {
self.tcx.sess
.struct_span_err(attr.span, "attribute can only be applied to a trait")
.span_label(item.span, "not a trait")
.span_label(*span, "not a trait")
.emit();
false
}
@ -199,18 +313,14 @@ impl CheckAttrVisitor<'tcx> {
}
/// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
fn check_target_feature(
&self,
attr: &hir::Attribute,
item: &hir::Item,
target: Target,
) -> bool {
fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Fn => true,
Target::Fn | Target::Method(MethodKind::Trait { body: true })
| Target::Method(MethodKind::Inherent) => true,
_ => {
self.tcx.sess
.struct_span_err(attr.span, "attribute should be applied to a function")
.span_label(item.span, "not a function")
.span_label(*span, "not a function")
.emit();
false
},
@ -218,13 +328,19 @@ impl CheckAttrVisitor<'tcx> {
}
/// Checks if the `#[repr]` attributes on `item` are valid.
fn check_repr(&self, item: &hir::Item, target: Target) {
fn check_repr(
&self,
attrs: &HirVec<Attribute>,
span: &Span,
target: Target,
item: Option<&Item>,
) {
// Extract the names of all repr hints, e.g., [foo, bar, align] for:
// ```
// #[repr(foo)]
// #[repr(bar, align(8))]
// ```
let hints: Vec<_> = item.attrs
let hints: Vec<_> = attrs
.iter()
.filter(|attr| attr.check_name(sym::repr))
.filter_map(|attr| attr.meta_item_list())
@ -282,7 +398,7 @@ impl CheckAttrVisitor<'tcx> {
};
self.emit_repr_error(
hint.span(),
item.span,
*span,
&format!("attribute should be applied to {}", allowed_targets),
&format!("not {} {}", article, allowed_targets),
)
@ -301,7 +417,7 @@ impl CheckAttrVisitor<'tcx> {
// Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
if (int_reprs > 1)
|| (is_simd && is_c)
|| (int_reprs == 1 && is_c && is_c_like_enum(item)) {
|| (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item))) {
let hint_spans: Vec<_> = hint_spans.collect();
span_warn!(self.tcx.sess, hint_spans, E0566,
"conflicting representation hints");
@ -325,7 +441,7 @@ impl CheckAttrVisitor<'tcx> {
if let hir::StmtKind::Local(ref l) = stmt.kind {
for attr in l.attrs.iter() {
if attr.check_name(sym::inline) {
self.check_inline(attr, &stmt.span, Target::Statement);
self.check_inline(DUMMY_HIR_ID, attr, &stmt.span, Target::Statement);
}
if attr.check_name(sym::repr) {
self.emit_repr_error(
@ -346,7 +462,7 @@ impl CheckAttrVisitor<'tcx> {
};
for attr in expr.attrs.iter() {
if attr.check_name(sym::inline) {
self.check_inline(attr, &expr.span, target);
self.check_inline(DUMMY_HIR_ID, attr, &expr.span, target);
}
if attr.check_name(sym::repr) {
self.emit_repr_error(
@ -359,8 +475,8 @@ impl CheckAttrVisitor<'tcx> {
}
}
fn check_used(&self, item: &hir::Item, target: Target) {
for attr in &item.attrs {
fn check_used(&self, attrs: &HirVec<Attribute>, target: Target) {
for attr in attrs {
if attr.check_name(sym::used) && target != Target::Static {
self.tcx.sess
.span_err(attr.span, "attribute must be applied to a `static` variable");
@ -374,12 +490,29 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
NestedVisitorMap::OnlyBodies(&self.tcx.hir())
}
fn visit_item(&mut self, item: &'tcx hir::Item) {
fn visit_item(&mut self, item: &'tcx Item) {
let target = Target::from_item(item);
self.check_attributes(item, target);
self.check_attributes(item.hir_id, &item.attrs, &item.span, target, Some(item));
intravisit::walk_item(self, item)
}
fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem) {
let target = Target::from_trait_item(trait_item);
self.check_attributes(trait_item.hir_id, &trait_item.attrs, &trait_item.span, target, None);
intravisit::walk_trait_item(self, trait_item)
}
fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem) {
let target = Target::from_foreign_item(f_item);
self.check_attributes(f_item.hir_id, &f_item.attrs, &f_item.span, target, None);
intravisit::walk_foreign_item(self, f_item)
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
let target = Target::from_impl_item(self.tcx, impl_item);
self.check_attributes(impl_item.hir_id, &impl_item.attrs, &impl_item.span, target, None);
intravisit::walk_impl_item(self, impl_item)
}
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
self.check_stmt_attributes(stmt);
@ -392,12 +525,12 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
}
}
fn is_c_like_enum(item: &hir::Item) -> bool {
if let hir::ItemKind::Enum(ref def, _) = item.kind {
fn is_c_like_enum(item: &Item) -> bool {
if let ItemKind::Enum(ref def, _) = item.kind {
for variant in &def.variants {
match variant.data {
hir::VariantData::Unit(..) => { /* continue */ }
_ => { return false; }
_ => return false,
}
}
true

View File

@ -203,7 +203,7 @@ pub trait Visitor<'v>: Sized {
/// Invoked to visit the body of a function, method or closure. Like
/// visit_nested_item, does nothing by default unless you override
/// `nested_visit_map` to return other htan `None`, in which case it will walk
/// `nested_visit_map` to return other than `None`, in which case it will walk
/// the body.
fn visit_nested_body(&mut self, id: BodyId) {
let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));

View File

@ -2512,7 +2512,7 @@ pub enum ItemKind {
Fn(P<FnDecl>, FnHeader, Generics, BodyId),
/// A module.
Mod(Mod),
/// An external module.
/// An external module, e.g. `extern { .. }`.
ForeignMod(ForeignMod),
/// Module-level inline assembly (from `global_asm!`).
GlobalAsm(P<GlobalAsm>),
@ -2756,10 +2756,10 @@ bitflags! {
/// `#[used]`: indicates that LLVM can't eliminate this function (but the
/// linker can!).
const USED = 1 << 9;
/// #[ffi_returns_twice], indicates that an extern function can return
/// `#[ffi_returns_twice]`, indicates that an extern function can return
/// multiple times
const FFI_RETURNS_TWICE = 1 << 10;
/// #[track_caller]: allow access to the caller location
/// `#[track_caller]`: allow access to the caller location
const TRACK_CALLER = 1 << 11;
}
}

View File

@ -68,6 +68,12 @@ declare_lint! {
"detect unused, unexported items"
}
declare_lint! {
pub UNUSED_ATTRIBUTES,
Warn,
"detects attributes that were not used by the compiler"
}
declare_lint! {
pub UNREACHABLE_CODE,
Warn,

View File

@ -9,5 +9,5 @@ name = "rustc_apfloat"
path = "lib.rs"
[dependencies]
bitflags = "1.0"
bitflags = "1.2.1"
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }

View File

@ -10,7 +10,7 @@ path = "lib.rs"
test = false
[dependencies]
bitflags = "1.0.4"
bitflags = "1.2.1"
cc = "1.0.1"
num_cpus = "1.0"
memmap = "0.6"

View File

@ -1,6 +1,7 @@
use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::DefId;
use rustc::lint;
use rustc::lint::builtin::UNUSED_ATTRIBUTES;
use rustc::ty::{self, Ty};
use rustc::ty::adjustment;
use rustc_data_structures::fx::FxHashMap;
@ -277,12 +278,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
}
}
declare_lint! {
pub UNUSED_ATTRIBUTES,
Warn,
"detects attributes that were not used by the compiler"
}
#[derive(Copy, Clone)]
pub struct UnusedAttributes {
builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,

View File

@ -11,7 +11,7 @@ test = false
doctest = false
[dependencies]
bitflags = "1.0"
bitflags = "1.2.1"
log = "0.4"
syntax = { path = "../libsyntax" }
syntax_expand = { path = "../libsyntax_expand" }

View File

@ -9,7 +9,7 @@ name = "rustc_target"
path = "lib.rs"
[dependencies]
bitflags = "1.0"
bitflags = "1.2.1"
log = "0.4"
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_serialize = { path = "../libserialize", package = "serialize" }

View File

@ -172,18 +172,6 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: DefId) {
_ => None
};
check_associated_item(tcx, trait_item.hir_id, trait_item.span, method_sig);
// Prohibits applying `#[track_caller]` to trait decls
for attr in &trait_item.attrs {
if attr.check_name(sym::track_caller) {
struct_span_err!(
tcx.sess,
attr.span,
E0738,
"`#[track_caller]` is not supported in trait declarations."
).emit();
}
}
}
pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
@ -195,29 +183,6 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: DefId) {
_ => None
};
// Prohibits applying `#[track_caller]` to trait impls
if method_sig.is_some() {
let track_caller_attr = impl_item.attrs.iter()
.find(|a| a.check_name(sym::track_caller));
if let Some(tc_attr) = track_caller_attr {
let parent_hir_id = tcx.hir().get_parent_item(hir_id);
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
hir::ItemKind::Impl(_, _, _, _, tr, _, _) => tr.is_some(),
_ => bug!("parent of an ImplItem must be an Impl"),
};
if containing_impl_is_for_trait {
struct_span_err!(
tcx.sess,
tc_attr.span,
E0738,
"`#[track_caller]` is not supported in traits yet."
).emit();
}
}
}
check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
}

View File

@ -2641,7 +2641,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
tcx.sess,
attr.span,
E0737,
"rust ABI is required to use `#[track_caller]`"
"Rust ABI is required to use `#[track_caller]`"
).emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;

View File

@ -4958,7 +4958,7 @@ and the pin is required to keep it in the same place in memory.
"##,
E0737: r##"
#[track_caller] requires functions to have the "Rust" ABI for implicitly
`#[track_caller]` requires functions to have the `"Rust"` ABI for implicitly
receiving caller location. See [RFC 2091] for details on this and other
restrictions.
@ -4974,57 +4974,6 @@ extern "C" fn foo() {}
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
"##,
E0738: r##"
#[track_caller] cannot be used in traits yet. This is due to limitations in the
compiler which are likely to be temporary. See [RFC 2091] for details on this
and other restrictions.
Erroneous example with a trait method implementation:
```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
fn bar(&self);
}
impl Foo for u64 {
#[track_caller]
fn bar(&self) {}
}
```
Erroneous example with a blanket trait method implementation:
```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
#[track_caller]
fn bar(&self) {}
fn baz(&self);
}
```
Erroneous example with a trait method declaration:
```compile_fail,E0738
#![feature(track_caller)]
trait Foo {
fn bar(&self) {}
#[track_caller]
fn baz(&self);
}
```
Note that while the compiler may be able to support the attribute in traits in
the future, [RFC 2091] prohibits their implementation without a follow-up RFC.
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
"##,
E0741: r##"
Only `structural_match` types (that is, types that derive `PartialEq` and `Eq`)
may be used as the types of const generic parameters.

View File

@ -10,7 +10,7 @@ path = "lib.rs"
doctest = false
[dependencies]
bitflags = "1.0"
bitflags = "1.2.1"
rustc_serialize = { path = "../libserialize", package = "serialize" }
log = "0.4"
scoped-tls = "1.0"

View File

@ -0,0 +1,8 @@
warning: `#[inline]` is ignored on function prototypes
--> $DIR/issue-52057.rs:10:5
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_attributes)]` on by default

View File

@ -0,0 +1,37 @@
#![feature(extern_types)]
#![feature(type_alias_impl_trait)]
#![warn(unused_attributes)]
trait Trait {
#[inline] //~ WARN `#[inline]` is ignored on constants
//~^ WARN this was previously accepted
const X: u32;
#[inline] //~ ERROR attribute should be applied to function or closure
type T;
type U;
}
impl Trait for () {
#[inline] //~ WARN `#[inline]` is ignored on constants
//~^ WARN this was previously accepted
const X: u32 = 0;
#[inline] //~ ERROR attribute should be applied to function or closure
type T = Self;
#[inline] //~ ERROR attribute should be applied to function or closure
type U = impl Trait; //~ ERROR could not find defining uses
}
extern {
#[inline] //~ ERROR attribute should be applied to function or closure
static X: u32;
#[inline] //~ ERROR attribute should be applied to function or closure
type T;
}
fn main() {}

View File

@ -0,0 +1,72 @@
error[E0518]: attribute should be applied to function or closure
--> $DIR/inline-trait-and-foreign-items.rs:30:5
|
LL | #[inline]
| ^^^^^^^^^
LL | static X: u32;
| -------------- not a function or closure
error[E0518]: attribute should be applied to function or closure
--> $DIR/inline-trait-and-foreign-items.rs:33:5
|
LL | #[inline]
| ^^^^^^^^^
LL | type T;
| ------- not a function or closure
warning: `#[inline]` is ignored on constants
--> $DIR/inline-trait-and-foreign-items.rs:7:5
|
LL | #[inline]
| ^^^^^^^^^
|
note: lint level defined here
--> $DIR/inline-trait-and-foreign-items.rs:4:9
|
LL | #![warn(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #65833 <https://github.com/rust-lang/rust/issues/65833>
error[E0518]: attribute should be applied to function or closure
--> $DIR/inline-trait-and-foreign-items.rs:11:5
|
LL | #[inline]
| ^^^^^^^^^
LL | type T;
| ------- not a function or closure
warning: `#[inline]` is ignored on constants
--> $DIR/inline-trait-and-foreign-items.rs:18:5
|
LL | #[inline]
| ^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #65833 <https://github.com/rust-lang/rust/issues/65833>
error[E0518]: attribute should be applied to function or closure
--> $DIR/inline-trait-and-foreign-items.rs:22:5
|
LL | #[inline]
| ^^^^^^^^^
LL | type T = Self;
| -------------- not a function or closure
error[E0518]: attribute should be applied to function or closure
--> $DIR/inline-trait-and-foreign-items.rs:25:5
|
LL | #[inline]
| ^^^^^^^^^
LL | type U = impl Trait;
| -------------------- not a function or closure
error: could not find defining uses
--> $DIR/inline-trait-and-foreign-items.rs:26:5
|
LL | type U = impl Trait;
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0518`.

View File

@ -0,0 +1,13 @@
#![deny(unused_attributes)]
trait Trait {
#[inline] //~ ERROR `#[inline]` is ignored on function prototypes
fn foo();
}
extern {
#[inline] //~ ERROR `#[inline]` is ignored on function prototypes
fn foo();
}
fn main() {}

View File

@ -0,0 +1,20 @@
error: `#[inline]` is ignored on function prototypes
--> $DIR/warn-unused-inline-on-fn-prototypes.rs:9:5
|
LL | #[inline]
| ^^^^^^^^^
|
note: lint level defined here
--> $DIR/warn-unused-inline-on-fn-prototypes.rs:1:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
error: `#[inline]` is ignored on function prototypes
--> $DIR/warn-unused-inline-on-fn-prototypes.rs:4:5
|
LL | #[inline]
| ^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -1,7 +1,6 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
#[track_caller]
#[track_caller] //~ ERROR Rust ABI is required to use `#[track_caller]`
extern "C" fn f() {}
//~^^ ERROR rust ABI is required to use `#[track_caller]`
fn main() {}

View File

@ -6,7 +6,7 @@ LL | #![feature(track_caller)]
|
= note: `#[warn(incomplete_features)]` on by default
error[E0737]: rust ABI is required to use `#[track_caller]`
error[E0737]: Rust ABI is required to use `#[track_caller]`
--> $DIR/error-with-invalid-abi.rs:3:1
|
LL | #[track_caller]

View File

@ -1,9 +1,8 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
trait Trait {
#[track_caller]
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
fn unwrap(&self);
//~^^ ERROR: `#[track_caller]` is not supported in trait declarations.
}
impl Trait for u64 {

View File

@ -6,7 +6,7 @@ LL | #![feature(track_caller)]
|
= note: `#[warn(incomplete_features)]` on by default
error[E0738]: `#[track_caller]` is not supported in trait declarations.
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-decl.rs:4:5
|
LL | #[track_caller]

View File

@ -1,9 +1,8 @@
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
trait Trait {
#[track_caller]
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
fn unwrap(&self) {}
//~^^ ERROR: `#[track_caller]` is not supported in trait declarations.
}
fn main() {}

View File

@ -6,7 +6,7 @@ LL | #![feature(track_caller)]
|
= note: `#[warn(incomplete_features)]` on by default
error[E0738]: `#[track_caller]` is not supported in trait declarations.
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-default-impl.rs:4:5
|
LL | #[track_caller]

View File

@ -1,3 +1,5 @@
// check-fail
#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete
trait Trait {
@ -5,9 +7,15 @@ trait Trait {
}
impl Trait for u64 {
#[track_caller]
#[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods
fn unwrap(&self) {}
//~^^ ERROR: `#[track_caller]` is not supported in traits yet.
}
struct S;
impl S {
#[track_caller] // ok
fn foo() {}
}
fn main() {}

View File

@ -1,13 +1,13 @@
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
--> $DIR/error-with-trait-fn-impl.rs:1:12
--> $DIR/error-with-trait-fn-impl.rs:3:12
|
LL | #![feature(track_caller)]
| ^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
error[E0738]: `#[track_caller]` is not supported in traits yet.
--> $DIR/error-with-trait-fn-impl.rs:8:5
error[E0738]: `#[track_caller]` may not be used on trait methods
--> $DIR/error-with-trait-fn-impl.rs:10:5
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^