diff --git a/Cargo.lock b/Cargo.lock index 4b264ef3f9faf..00466d3d73184 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 9d26ff6001767..812111a2e7255 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -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" diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index cf268078a2c5d..3e35add9616bd 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -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 diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index c37fec982b116..96562002aa070 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -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, + 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 \ + ") .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, + 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, + 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, 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 diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 05bdd0887f0f6..920635d838738 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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)); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 38c84ad33478b..0edc41e6b4881 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -2512,7 +2512,7 @@ pub enum ItemKind { Fn(P, 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), @@ -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; } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 15598b60f5c0b..5c871bb6b6988 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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, diff --git a/src/librustc_apfloat/Cargo.toml b/src/librustc_apfloat/Cargo.toml index af6c2feed0072..4fc15f99e484e 100644 --- a/src/librustc_apfloat/Cargo.toml +++ b/src/librustc_apfloat/Cargo.toml @@ -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"] } diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index c7d09a423d5e3..2eaae50591673 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -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" diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 61b8cbe369aab..9a826de4b6eaf 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -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, diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml index 06bf30859898a..08ce7fd520e30 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -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" } diff --git a/src/librustc_target/Cargo.toml b/src/librustc_target/Cargo.toml index fba2ea02bb44a..c73d0adea38da 100644 --- a/src/librustc_target/Cargo.toml +++ b/src/librustc_target/Cargo.toml @@ -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" } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b4b8d4566d577..49b33ad466834 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -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); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a0550b5126a9c..001d98aece2a0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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; diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs index 248b687c31cdf..f21fc2df8b913 100644 --- a/src/librustc_typeck/error_codes.rs +++ b/src/librustc_typeck/error_codes.rs @@ -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. diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index d8de21cc6778f..3ce47e6a7b8cd 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -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" diff --git a/src/test/ui/issues/issue-52057.stderr b/src/test/ui/issues/issue-52057.stderr new file mode 100644 index 0000000000000..33b79dba73e0e --- /dev/null +++ b/src/test/ui/issues/issue-52057.stderr @@ -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 + diff --git a/src/test/ui/lint/inline-trait-and-foreign-items.rs b/src/test/ui/lint/inline-trait-and-foreign-items.rs new file mode 100644 index 0000000000000..8bdefbb36ae5f --- /dev/null +++ b/src/test/ui/lint/inline-trait-and-foreign-items.rs @@ -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() {} diff --git a/src/test/ui/lint/inline-trait-and-foreign-items.stderr b/src/test/ui/lint/inline-trait-and-foreign-items.stderr new file mode 100644 index 0000000000000..6c94f88f13948 --- /dev/null +++ b/src/test/ui/lint/inline-trait-and-foreign-items.stderr @@ -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 + +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 + +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`. diff --git a/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.rs b/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.rs new file mode 100644 index 0000000000000..21097197499dd --- /dev/null +++ b/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.rs @@ -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() {} diff --git a/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr b/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr new file mode 100644 index 0000000000000..006cc6c80a64e --- /dev/null +++ b/src/test/ui/lint/warn-unused-inline-on-fn-prototypes.stderr @@ -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 + diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs index 2994f3c06212f..162c6387088e7 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -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() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr index a34acf3fc6142..ad89b142f0ec8 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -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] diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs index 1cd45c8cdbc91..4fd768d640a55 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs @@ -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 { diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr index fb3732b597083..72ed6f89faa96 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr @@ -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] diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs index 0f2020d6fb26b..2139ba5de10c3 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs @@ -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() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr index c212a716c2024..05689c9468bec 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr @@ -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] diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs index 1378ebaa03ffa..b565e11f55b2a 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs @@ -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() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr index 2662fbff7a2c2..707b367484c2c 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr @@ -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] | ^^^^^^^^^^^^^^^