]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #62069 - Centril:rollup-m8n4uw7, r=Centril
authorbors <bors@rust-lang.org>
Sun, 23 Jun 2019 00:10:17 +0000 (00:10 +0000)
committerbors <bors@rust-lang.org>
Sun, 23 Jun 2019 00:10:17 +0000 (00:10 +0000)
Rollup of 5 pull requests

Successful merges:

 - #62047 (Trigger `unused_attribute` lint on `#[cfg_attr($pred,)]`)
 - #62049 (Fix one missing `dyn`.)
 - #62051 (Lint empty `#[derive()]` as unused attribute.)
 - #62057 (Deny explicit_outlives_requirements in the compiler)
 - #62068 (Fix meta-variable binding errors in macros)

Failed merges:

r? @ghost

38 files changed:
src/libcore/fmt/mod.rs
src/libcore/hash/mod.rs
src/libcore/iter/traits/accum.rs
src/libcore/macros.rs
src/libcore/marker.rs
src/libcore/ptr/mod.rs
src/libproc_macro/bridge/rpc.rs
src/librustc/hir/itemlikevisit.rs
src/librustc/infer/nll_relate/mod.rs
src/librustc/lib.rs
src/librustc/middle/weak_lang_items.rs
src/librustc/ty/context.rs
src/librustc/ty/query/plumbing.rs
src/librustc_codegen_llvm/builder.rs
src/librustc_codegen_llvm/lib.rs
src/librustc_codegen_ssa/lib.rs
src/librustc_data_structures/indexed_vec.rs
src/librustc_lint/types.rs
src/librustc_mir/dataflow/graphviz.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/interpret/intern.rs
src/librustc_mir/lib.rs
src/librustc_mir/util/elaborate_drops.rs
src/librustc_target/spec/mod.rs
src/librustc_typeck/lib.rs
src/libserialize/serialize.rs
src/libsyntax/config.rs
src/libsyntax/ext/derive.rs
src/libsyntax/ext/expand.rs
src/libsyntax_ext/deriving/mod.rs
src/libsyntax_ext/proc_macro_server.rs
src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr [new file with mode: 0644]
src/test/ui/derives/deriving-meta-empty-trait-list.rs
src/test/ui/derives/deriving-meta-empty-trait-list.stderr
src/test/ui/issues/issue-22814.rs
src/test/ui/malformed/malformed-derive-entry.rs
src/test/ui/malformed/malformed-derive-entry.stderr

index 2f6d745d146d647d3fd5716e57db7dc020964b39..17ea58438810e20f10684df14daf83d51d8abee6 100644 (file)
@@ -2070,19 +2070,19 @@ macro_rules! tuple {
     () => ();
     ( $($name:ident,)+ ) => (
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<$($name:Debug),*> Debug for ($($name,)*) where last_type!($($name,)+): ?Sized {
+        impl<$($name:Debug),+> Debug for ($($name,)+) where last_type!($($name,)+): ?Sized {
             #[allow(non_snake_case, unused_assignments)]
             fn fmt(&self, f: &mut Formatter<'_>) -> Result {
                 let mut builder = f.debug_tuple("");
-                let ($(ref $name,)*) = *self;
+                let ($(ref $name,)+) = *self;
                 $(
                     builder.field(&$name);
-                )*
+                )+
 
                 builder.finish()
             }
         }
-        peel! { $($name,)* }
+        peel! { $($name,)+ }
     )
 }
 
index 98150fd9f821ea5679eec470a382340aa23dae6b..38e38642842403bf88843ca2f8a22fd1e2b94f7d 100644 (file)
@@ -617,11 +617,11 @@ fn hash<H: Hasher>(&self, _state: &mut H) {}
 
         ( $($name:ident)+) => (
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($name: Hash),*> Hash for ($($name,)*) where last_type!($($name,)+): ?Sized {
+            impl<$($name: Hash),+> Hash for ($($name,)+) where last_type!($($name,)+): ?Sized {
                 #[allow(non_snake_case)]
                 fn hash<S: Hasher>(&self, state: &mut S) {
-                    let ($(ref $name,)*) = *self;
-                    $($name.hash(state);)*
+                    let ($(ref $name,)+) = *self;
+                    $($name.hash(state);)+
                 }
             }
         );
index 4eac5cbc8e6623142563d8e3186994e4ceb3bfe1..adfb639bae341ceb0aca1aea55ef4723d32333d6 100644 (file)
@@ -72,10 +72,10 @@ fn product<I: Iterator<Item=&'a $a>>(iter: I) -> $a {
     ($($a:ty)*) => (
         integer_sum_product!(@impls 0, 1,
                 #[stable(feature = "iter_arith_traits", since = "1.12.0")],
-                $($a)+);
+                $($a)*);
         integer_sum_product!(@impls Wrapping(0), Wrapping(1),
                 #[stable(feature = "wrapping_iter_arith", since = "1.14.0")],
-                $(Wrapping<$a>)+);
+                $(Wrapping<$a>)*);
     );
 }
 
index 8b44025f91f5e710f88141df83c262f13661c3af..589061b2826818107a82961647e0caf3fd7ce6a8 100644 (file)
@@ -15,7 +15,7 @@ macro_rules! panic {
         $crate::panic!($msg)
     );
     ($fmt:expr, $($arg:tt)+) => ({
-        $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*),
+        $crate::panicking::panic_fmt(format_args!($fmt, $($arg)+),
                                      &(file!(), line!(), __rust_unstable_column!()))
     });
 }
@@ -558,7 +558,7 @@ macro_rules! unreachable {
 #[stable(feature = "rust1", since = "1.0.0")]
 macro_rules! unimplemented {
     () => (panic!("not yet implemented"));
-    ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)*)));
+    ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+)));
 }
 
 /// Indicates unfinished code.
@@ -617,7 +617,7 @@ macro_rules! unimplemented {
 #[unstable(feature = "todo_macro", issue = "59277")]
 macro_rules! todo {
     () => (panic!("not yet implemented"));
-    ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)*)));
+    ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)+)));
 }
 
 /// Creates an array of [`MaybeUninit`].
index 74f685a6de20ed64373a15386853e0433254ea92..3f4ff7c2f437e71197d0911e426a02668940d951 100644 (file)
@@ -103,7 +103,7 @@ pub trait Sized {
 /// `Unsize` is implemented for:
 ///
 /// - `[T; N]` is `Unsize<[T]>`
-/// - `T` is `Unsize<Trait>` when `T: Trait`
+/// - `T` is `Unsize<dyn Trait>` when `T: Trait`
 /// - `Foo<..., T, ...>` is `Unsize<Foo<..., U, ...>>` if:
 ///   - `T: Unsize<U>`
 ///   - Foo is a struct
index ba88fde6ebc97afa70aa3f7eddecafd1b93171ea..fccb00d768cd852f69f35135d68fedcff29c26fc 100644 (file)
@@ -2725,12 +2725,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 macro_rules! fnptr_impls_args {
     ($($Arg: ident),+) => {
-        fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),*) -> Ret, $($Arg),* }
-        fnptr_impls_safety_abi! { extern "C" fn($($Arg),*) -> Ret, $($Arg),* }
-        fnptr_impls_safety_abi! { extern "C" fn($($Arg),* , ...) -> Ret, $($Arg),* }
-        fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),*) -> Ret, $($Arg),* }
-        fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),*) -> Ret, $($Arg),* }
-        fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),* , ...) -> Ret, $($Arg),* }
+        fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
+        fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
     };
     () => {
         // No variadic functions with 0 parameters
index 5018be74f89973930906a0f9a768186e0c2b57e9..5c2f9ec9848dda7d26b1b6d5b2545cd70313f5ec 100644 (file)
@@ -59,7 +59,7 @@ fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
         }
     };
     (enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => {
-        impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)* {
+        impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
             fn encode(self, w: &mut Writer, s: &mut S) {
                 // HACK(eddyb): `Tag` enum duplicated between the
                 // two impls as there's no other place to stash it.
@@ -79,8 +79,8 @@ mod tag {
             }
         }
 
-        impl<S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)*> DecodeMut<'a, '_, S>
-            for $name $(<$($T),+>)*
+        impl<S, $($($T: for<'s> DecodeMut<'a, 's, S>),+)?> DecodeMut<'a, '_, S>
+            for $name $(<$($T),+>)?
         {
             fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
                 // HACK(eddyb): `Tag` enum duplicated between the
index bfc9e8f06e235ccc5fb586b7bfd45d7bd789f490..35b181245837f2bf17e6454f7dea2c53cdc0533f 100644 (file)
@@ -51,7 +51,7 @@ pub trait ItemLikeVisitor<'hir> {
     fn visit_impl_item(&mut self, impl_item: &'hir ImplItem);
 }
 
-pub struct DeepVisitor<'v, V: 'v> {
+pub struct DeepVisitor<'v, V> {
     visitor: &'v mut V,
 }
 
index 21489965b1bf66d6f427d36086c03dee84abb11e..a1a93eb5521387ee03fcbd30c2f1371e3a6d80ee 100644 (file)
@@ -800,7 +800,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
 /// [blog post]: https://is.gd/0hKvIr
 struct TypeGeneralizer<'me, 'tcx, D>
 where
-    D: TypeRelatingDelegate<'tcx> + 'me,
+    D: TypeRelatingDelegate<'tcx>,
 {
     infcx: &'me InferCtxt<'me, 'tcx>,
 
index e2f2799d9634dfadfd599ea5e66031379476b2ea..257d5159f113195128fc4db2f3c935342bbe45df 100644 (file)
@@ -31,7 +31,6 @@
 #![deny(rust_2018_idioms)]
 #![deny(internal)]
 #![deny(unused_lifetimes)]
-#![allow(explicit_outlives_requirements)]
 
 #![feature(arbitrary_self_types)]
 #![feature(box_patterns)]
index b6cd24c291ac77860e1005407c1eaf9def733fe6..4fb88dadd1f44628ece3ec4df0707b83f071f11c 100644 (file)
@@ -147,7 +147,7 @@ pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool {
         let lang_items = self.lang_items();
         let did = Some(item_def_id);
 
-        $(lang_items.$name() == did)||+
+        $(lang_items.$name() == did)||*
     }
 }
 
index ce785f9a0246bb9493aa89e8bfaf66d6ed97b1c7..28399ed5439f79de9a3bcba7bb9dde3ad7bf3fca 100644 (file)
@@ -231,7 +231,7 @@ pub struct CommonConsts<'tcx> {
     pub err: &'tcx Const<'tcx>,
 }
 
-pub struct LocalTableInContext<'a, V: 'a> {
+pub struct LocalTableInContext<'a, V> {
     local_id_root: Option<DefId>,
     data: &'a ItemLocalMap<V>
 }
@@ -294,7 +294,7 @@ fn index(&self, key: hir::HirId) -> &V {
     }
 }
 
-pub struct LocalTableInContextMut<'a, V: 'a> {
+pub struct LocalTableInContextMut<'a, V> {
     local_id_root: Option<DefId>,
     data: &'a mut ItemLocalMap<V>
 }
@@ -2171,7 +2171,7 @@ pub fn print_debug_stats(self) {
 
 
 /// An entry in an interner.
-struct Interned<'tcx, T: 'tcx+?Sized>(&'tcx T);
+struct Interned<'tcx, T: ?Sized>(&'tcx T);
 
 impl<'tcx, T: 'tcx+?Sized> Clone for Interned<'tcx, T> {
     fn clone(&self) -> Self {
index 0f158d2982a20dc8d2d87772e6cd560fd3782ba3..7d5f984c1b6f24e93f2b74359bcd44819311ab91 100644 (file)
@@ -89,7 +89,7 @@ macro_rules! profq_query_msg {
 
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
-pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx> + 'a> {
+pub(super) struct JobOwner<'a, 'tcx, Q: QueryDescription<'tcx>> {
     cache: &'a Lock<QueryCache<'tcx, Q>>,
     key: Q::Key,
     job: Lrc<QueryJob<'tcx>>,
@@ -230,7 +230,7 @@ pub struct CycleError<'tcx> {
 }
 
 /// The result of `try_get_lock`
-pub(super) enum TryGetJob<'a, 'tcx, D: QueryDescription<'tcx> + 'a> {
+pub(super) enum TryGetJob<'a, 'tcx, D: QueryDescription<'tcx>> {
     /// The query is not yet started. Contains a guard to the cache eventually used to start it.
     NotYetStarted(JobOwner<'a, 'tcx, D>),
 
index e06b4d8b3063e8cd7a3666853be08d171dd0421f..0709368ad860ef973792a951cd7f16f180e5ab70 100644 (file)
@@ -110,7 +110,7 @@ macro_rules! builder_methods_for_value_instructions {
             unsafe {
                 llvm::$llvm_capi(self.llbuilder, $($arg,)* UNNAMED)
             }
-        })*
+        })+
     }
 }
 
index 1eb6e9a5283bd2e81ed564c06db4e3b5bd552b51..7283aa95b3027e7d9182d596bd9cd0a6bbda3331 100644 (file)
@@ -24,7 +24,6 @@
 #![deny(rust_2018_idioms)]
 #![deny(internal)]
 #![deny(unused_lifetimes)]
-#![allow(explicit_outlives_requirements)]
 
 use back::write::{create_target_machine, create_informational_target_machine};
 use syntax_pos::symbol::Symbol;
index 71393e224e42db145197adacbfd5b92a099c25bb..b76f098773f0b6a26b6758dca781c1f669433537 100644 (file)
@@ -15,7 +15,6 @@
 #![deny(rust_2018_idioms)]
 #![deny(internal)]
 #![deny(unused_lifetimes)]
-#![allow(explicit_outlives_requirements)]
 
 #![recursion_limit="256"]
 
index c7f6e54c3d56b1dd713af054614859256a7721bb..635edbb927e5c4c1e86cdc6c02e88c057474682f 100644 (file)
@@ -423,7 +423,7 @@ fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
     (@derives      [$($derives:ident,)*]
      @attrs        [$(#[$attrs:meta])*]
      @type         [$type:ident]
-     @max          [$_max:expr]
+     @max          [$max:expr]
      @vis          [$v:vis]
      @debug_format [$debug_format:tt]
                    $(#[doc = $doc:expr])*
index cd4eecf26387fbb7108c8ec76a7fcc280af6f41a..2fb534e8228e6f8fb969fdd6577212626c51cde8 100644 (file)
@@ -219,7 +219,7 @@ macro_rules! find_fit {
                             return Some(format!("{:?}", $itypes))
                         })*
                         None
-                    },)*
+                    },)+
                     _ => None
                 }
             }
index f62ad2fbef71f06bcd8d3d8e7cac5f55440f761f..7896592eea68582238a68760f310f9332c9336db 100644 (file)
@@ -30,7 +30,7 @@ fn body(&self) -> &Body<'tcx> { self.flow_state.body() }
     fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> { &self.flow_state.flow_state }
 }
 
-struct Graph<'a, 'tcx, MWF:'a, P> where
+struct Graph<'a, 'tcx, MWF, P> where
     MWF: MirWithFlowState<'tcx>
 {
     mbcx: &'a MWF,
index 0728d5b21bbd18f548ebabd5902881204543330e..89b952e9f8b5aaa4031f29e62719f3bc79390e9d 100644 (file)
@@ -181,7 +181,7 @@ pub(crate) fn run<P>(
 
 struct PropagationContext<'b, 'a, 'tcx, O>
 where
-    O: 'b + BitDenotation<'tcx>,
+    O: BitDenotation<'tcx>,
 {
     builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
 }
index d998f40c86eccf4665f5b80e7a8ab38fb3b1433c..416b66daa05940fc958522e9a3bac1daed7c46f1 100644 (file)
@@ -21,7 +21,7 @@
 };
 use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};
 
-struct InternVisitor<'rt, 'mir: 'rt, 'tcx: 'rt + 'mir> {
+struct InternVisitor<'rt, 'mir, 'tcx> {
     /// previously encountered safe references
     ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
     ecx: &'rt mut CompileTimeEvalContext<'mir, 'tcx>,
index a7cbe84330d899a9e10a5b760cb3649f928361a3..cb02e1a778c93af78f38da3bc6ed78d3db92564e 100644 (file)
@@ -30,7 +30,6 @@
 #![deny(rust_2018_idioms)]
 #![deny(internal)]
 #![deny(unused_lifetimes)]
-#![allow(explicit_outlives_requirements)]
 
 #[macro_use] extern crate log;
 #[macro_use]
index 815d210d36ea4fcbbfbe93e3483be9ac1254b43d..91fc19b71d8ba7407d60619ba74b387091b5681a 100644 (file)
@@ -92,7 +92,7 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug {
 #[derive(Debug)]
 struct DropCtxt<'l, 'b, 'tcx, D>
 where
-    D: DropElaborator<'b, 'tcx> + 'l,
+    D: DropElaborator<'b, 'tcx>,
 {
     elaborator: &'l mut D,
 
index 08cf062e85818f7d5071c5aac7bd3ed39a304fd5..75821aba4706e1bedc19ba12c221e01f300abfa0 100644 (file)
@@ -119,19 +119,19 @@ macro_rules! flavor_mappings {
     ($((($($flavor:tt)*), $string:expr),)*) => (
         impl LinkerFlavor {
             pub const fn one_of() -> &'static str {
-                concat!("one of: ", $($string, " ",)+)
+                concat!("one of: ", $($string, " ",)*)
             }
 
             pub fn from_str(s: &str) -> Option<Self> {
                 Some(match s {
-                    $($string => $($flavor)*,)+
+                    $($string => $($flavor)*,)*
                     _ => return None,
                 })
             }
 
             pub fn desc(&self) -> &str {
                 match *self {
-                    $($($flavor)* => $string,)+
+                    $($($flavor)* => $string,)*
                 }
             }
         }
index cc6f7a07d9621c841099ca8045a359097be8bb47..ec0f431d9b25e211d2dcb0059f13624547a7ffe9 100644 (file)
@@ -75,7 +75,6 @@
 #![deny(rust_2018_idioms)]
 #![deny(internal)]
 #![deny(unused_lifetimes)]
-#![allow(explicit_outlives_requirements)]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
index 95095c712d2c58631b8e381ac4052f85d96f75c7..2def2a455fb6448158a844a465d29e37fa900f07 100644 (file)
@@ -739,33 +739,33 @@ macro_rules! count {
 macro_rules! tuple {
     () => ();
     ( $($name:ident,)+ ) => (
-        impl<$($name:Decodable),*> Decodable for ($($name,)*) {
+        impl<$($name:Decodable),+> Decodable for ($($name,)+) {
             #[allow(non_snake_case)]
-            fn decode<D: Decoder>(d: &mut D) -> Result<($($name,)*), D::Error> {
-                let len: usize = count!($($name)*);
+            fn decode<D: Decoder>(d: &mut D) -> Result<($($name,)+), D::Error> {
+                let len: usize = count!($($name)+);
                 d.read_tuple(len, |d| {
                     let mut i = 0;
                     let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name, D::Error> {
                         Decodable::decode(d)
-                    })?,)*);
+                    })?,)+);
                     Ok(ret)
                 })
             }
         }
-        impl<$($name:Encodable),*> Encodable for ($($name,)*) {
+        impl<$($name:Encodable),+> Encodable for ($($name,)+) {
             #[allow(non_snake_case)]
             fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-                let ($(ref $name,)*) = *self;
+                let ($(ref $name,)+) = *self;
                 let mut n = 0;
-                $(let $name = $name; n += 1;)*
+                $(let $name = $name; n += 1;)+
                 s.emit_tuple(n, |s| {
                     let mut i = 0;
-                    $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)*
+                    $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)+
                     Ok(())
                 })
             }
         }
-        peel! { $($name,)* }
+        peel! { $($name,)+ }
     )
 }
 
index 3b42e1de61497244f0fb038431d7ed9e507d8f7f..1ab367f73c1b31a1da288c8a293fc999d5ee150a 100644 (file)
@@ -91,10 +91,10 @@ pub fn process_cfg_attrs<T: HasAttrs>(&mut self, node: &mut T) {
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
     fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
-        if !attr.check_name(sym::cfg_attr) {
+        if attr.path != sym::cfg_attr {
             return vec![attr];
         }
-        if attr.tokens.len() == 0 {
+        if attr.tokens.is_empty() {
             self.sess.span_diagnostic
                 .struct_span_err(
                     attr.span,
@@ -108,7 +108,7 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
                        <https://doc.rust-lang.org/reference/conditional-compilation.html\
                        #the-cfg_attr-attribute>")
                 .emit();
-            return Vec::new();
+            return vec![];
         }
 
         let (cfg_predicate, expanded_attrs) = match attr.parse(self.sess, |parser| {
@@ -133,17 +133,18 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
             Ok(result) => result,
             Err(mut e) => {
                 e.emit();
-                return Vec::new();
+                return vec![];
             }
         };
 
-        // Check feature gate and lint on zero attributes in source. Even if the feature is gated,
-        // we still compute as if it wasn't, since the emitted error will stop compilation further
-        // along the compilation.
-        if expanded_attrs.len() == 0 {
-            // FIXME: Emit unused attribute lint here.
+        // Lint on zero attributes in source.
+        if expanded_attrs.is_empty() {
+            return vec![attr];
         }
 
+        // At this point we know the attribute is considered used.
+        attr::mark_used(&attr);
+
         if attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
             // We call `process_cfg_attr` recursively in case there's a
             // `cfg_attr` inside of another `cfg_attr`. E.g.
@@ -159,7 +160,7 @@ fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec<ast::Attribute> {
             }))
             .collect()
         } else {
-            Vec::new()
+            vec![]
         }
     }
 
index abc451c96ae0ef9f1cdc794fb08a6e6f0f42e39b..3b4243ed24f7c5519f4a2715fa3f344bcd84ea36 100644 (file)
@@ -30,10 +30,6 @@ pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) ->
 
         match attr.parse_list(cx.parse_sess,
                               |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
-            Ok(ref traits) if traits.is_empty() => {
-                cx.span_warn(attr.span, "empty trait list in `derive`");
-                false
-            }
             Ok(traits) => {
                 result.extend(traits);
                 true
index cfd67575b6fe120ac720d12bb3e776e73143b5be..945cf36af46fe42788090c0d975da0133fe84880 100644 (file)
@@ -98,9 +98,9 @@ pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
                             }
                         });
                     }
-                    $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)*)*
+                    $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
                     $($(AstFragment::$Kind(ast) =>
-                        ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)*)*
+                        ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
                 }
             }
 
@@ -108,10 +108,10 @@ pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
                 match *self {
                     AstFragment::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
                     AstFragment::OptExpr(None) => {}
-                    $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)*)*
+                    $($(AstFragment::$Kind(ref ast) => visitor.$visit_ast(ast),)?)*
                     $($(AstFragment::$Kind(ref ast) => for ast_elt in &ast[..] {
                         visitor.$visit_ast_elt(ast_elt);
-                    })*)*
+                    })?)*
                 }
             }
         }
@@ -122,10 +122,10 @@ fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
             }
             $($(fn $mut_visit_ast(&mut self, ast: &mut $AstTy) {
                 visit_clobber(ast, |ast| self.expand_fragment(AstFragment::$Kind(ast)).$make_ast());
-            })*)*
+            })?)*
             $($(fn $flat_map_ast_elt(&mut self, ast_elt: <$AstTy as IntoIterator>::Item) -> $AstTy {
                 self.expand_fragment(AstFragment::$Kind(smallvec![ast_elt])).$make_ast()
-            })*)*
+            })?)*
         }
 
         impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> {
index 1fe6094fca6861eeb1f2ba417f99769b2e5ed0ef..e75eff2e85714a48e4ea71778d11ab3fccde832b 100644 (file)
@@ -88,7 +88,7 @@ pub fn register_builtin_derives(resolver: &mut dyn Resolver, edition: Edition) {
                         )
                     }),
                 );
-            )*
+            )+
         }
     }
 }
index b5d5a38ce5b3872872d06fba9ab68c57e2883024..c9d99e5831ac47b5348abdf348042ccd8ef87a8b 100644 (file)
@@ -70,7 +70,7 @@ fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mu
         macro_rules! tt {
             ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => (
                 TokenTree::$ty(self::$ty {
-                    $($field $(: $value)*,)*
+                    $($field $(: $value)*,)+
                     span,
                 })
             );
diff --git a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.rs
new file mode 100644 (file)
index 0000000..4c96d6e
--- /dev/null
@@ -0,0 +1,13 @@
+// Check that `#[cfg_attr($PREDICATE,)]` triggers the `unused_attribute` lint.
+
+// compile-flags: --cfg TRUE
+
+#![deny(unused)]
+
+#[cfg_attr(FALSE,)] //~ ERROR unused attribute
+fn _f() {}
+
+#[cfg_attr(TRUE,)] //~ ERROR unused attribute
+fn _g() {}
+
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr b/src/test/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr
new file mode 100644 (file)
index 0000000..cd3563e
--- /dev/null
@@ -0,0 +1,21 @@
+error: unused attribute
+  --> $DIR/cfg-attr-empty-is-unused.rs:7:1
+   |
+LL | #[cfg_attr(FALSE,)]
+   | ^^^^^^^^^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/cfg-attr-empty-is-unused.rs:5:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: #[deny(unused_attributes)] implied by #[deny(unused)]
+
+error: unused attribute
+  --> $DIR/cfg-attr-empty-is-unused.rs:10:1
+   |
+LL | #[cfg_attr(TRUE,)]
+   | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
index 882484146152da358edf97d419aa5d4d7387020a..4f2e31e8efb15af3bb080b542b2910d359847aeb 100644 (file)
@@ -1,6 +1,6 @@
-// compile-pass
+#![deny(unused)]
 
-#[derive()] //~ WARNING empty trait list in `derive`
-struct Bar;
+#[derive()] //~ ERROR unused attribute
+struct _Bar;
 
 pub fn main() {}
index f8414b6e65e62becab8ea040a88ab4c8691eb41f..95c94ded3eaf1589a6444f40705ab386389a4442 100644 (file)
@@ -1,6 +1,15 @@
-warning: empty trait list in `derive`
+error: unused attribute
   --> $DIR/deriving-meta-empty-trait-list.rs:3:1
    |
 LL | #[derive()]
    | ^^^^^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/deriving-meta-empty-trait-list.rs:1:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: #[deny(unused_attributes)] implied by #[deny(unused)]
+
+error: aborting due to previous error
 
index b008c751064926da2d6badae585c855a5d165eff..bcc7a8a5ae0a3255845de805d45abd2408565780 100644 (file)
@@ -3,7 +3,7 @@ trait Test {}
 
 macro_rules! test {
 ( $($name:ident)+) => (
-    impl<$($name: Test),*> Test for ($($name,)*) {
+    impl<$($name: Test),+> Test for ($($name,)+) {
     }
 )
 }
index 3e53e15601b0b9aafd601ca3a6ada5668a1b40b5..a6d886318e8202b281d53217155934f2ade49805 100644 (file)
@@ -4,9 +4,6 @@
 #[derive(Copy="bad")] //~ ERROR expected one of `)`, `,`, or `::`, found `=`
 struct Test2;
 
-#[derive()] //~ WARNING empty trait list
-struct Test3;
-
 #[derive] //~ ERROR malformed `derive` attribute input
 struct Test4;
 
index dfbc5faedac592098bd536f9dc1cd3f651c624d2..f7500febe97192db77328bcc67aa871ddc804c58 100644 (file)
@@ -10,14 +10,8 @@ error: expected one of `)`, `,`, or `::`, found `=`
 LL | #[derive(Copy="bad")]
    |              ^ expected one of `)`, `,`, or `::` here
 
-warning: empty trait list in `derive`
-  --> $DIR/malformed-derive-entry.rs:7:1
-   |
-LL | #[derive()]
-   | ^^^^^^^^^^^
-
 error: malformed `derive` attribute input
-  --> $DIR/malformed-derive-entry.rs:10:1
+  --> $DIR/malformed-derive-entry.rs:7:1
    |
 LL | #[derive]
    | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]`