diff --git a/.travis.yml b/.travis.yml index c3065fb..396d127 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,13 @@ language: rust rust: - nightly +script: + - cargo build --verbose + - cargo test --verbose + - cargo build --verbose --features=nightly + - cargo test --verbose --features=nightly + +env: + - RUST_FLAGS="--deny warnings" + cache: cargo diff --git a/Cargo.toml b/Cargo.toml index e103c71..e959b62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["edition"] + [package] name = "auto_impl" version = "0.2.0" @@ -13,15 +15,20 @@ keywords = ["plugin"] categories = ["development-tools"] readme = "README.md" autotests = true +edition = '2018' [badges] travis-ci = { repository = "KodrAus/auto_impl" } + [lib] proc-macro = true +[features] +nightly = ["proc-macro2/nightly"] + [dependencies] -proc-macro2 = { version = "0.4.6", features = ["nightly"] } +proc-macro2 = { version = "0.4.6" } quote = "0.6.3" syn = { version = "0.14.4", features = ["full"] } diff --git a/examples/error_messages.rs b/examples/error_messages.rs new file mode 100644 index 0000000..1cc150d --- /dev/null +++ b/examples/error_messages.rs @@ -0,0 +1,30 @@ +//! This file showcases a few error messages emitted by `auto_impl`. You have +//! to add specific lines to see the error. Then simply compile with: +//! +//! ``` +//! cargo build --example error_messages +//! ``` +//! +//! If you want to see nicer error messages, add `--features=nightly`. +#![allow(unused_imports, dead_code)] + +use auto_impl::auto_impl; + + +// Shows the error message for the case that `#[auto_impl]` was used with +// incorrect proxy types. Only proxy types like `&` and `Box` are allowed. Add +// this next line to see the error! +//#[auto_impl(Boxxi)] +trait Foo { + fn foo(&self) -> u32; +} + +// Shows the error message for the case the `#[auto_impl]` wasn't applied to a +// valid trait (in this case a struct). Add this next line to see the error! +//#[auto_impl(&, Box)] +struct Bar { + x: u32, +} + + +fn main() {} diff --git a/examples/greet_closure.rs b/examples/greet_closure.rs index 8f3db35..2f8daf1 100644 --- a/examples/greet_closure.rs +++ b/examples/greet_closure.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - use auto_impl::auto_impl; diff --git a/examples/names.rs b/examples/names.rs index cd5cf56..a39da3b 100644 --- a/examples/names.rs +++ b/examples/names.rs @@ -29,9 +29,7 @@ // This code is really ugly on purpose... #![allow(non_snake_case, dead_code, unused_variables)] -#![feature(use_extern_macros)] -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/examples/refs.rs b/examples/refs.rs index 0845ee9..bcd810e 100644 --- a/examples/refs.rs +++ b/examples/refs.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - use std::fmt::Display; use auto_impl::auto_impl; diff --git a/src/analyze.rs b/src/analyze.rs index 32423aa..6c7cd06 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -1,6 +1,5 @@ use std::collections::HashSet; -use proc_macro::Span; use proc_macro2::Span as Span2; use syn::{ Ident, ItemTrait, Lifetime, Block, @@ -38,7 +37,7 @@ const PROXY_LT_PARAM_NAME: &str = "'__auto_impl_proxy_lifetime"; /// name, we'll use the ugly `PROXY_TY_PARAM_NAME` and `PROXY_LT_PARAM_NAME`. /// /// This method returns two idents: (type_parameter, lifetime_parameter). -pub(crate) fn find_suitable_param_names(trait_def: &ItemTrait) -> (Ident, Lifetime) { +crate fn find_suitable_param_names(trait_def: &ItemTrait) -> (Ident, Lifetime) { // Define the visitor that just collects names struct IdentCollector<'ast> { ty_names: HashSet<&'ast Ident>, @@ -71,11 +70,6 @@ pub(crate) fn find_suitable_param_names(trait_def: &ItemTrait) -> (Ident, Lifeti visit_item_trait(&mut visitor, trait_def); - fn param_span() -> Span2 { - // TODO: change for stable builds - Span::def_site().into() - } - fn char_to_ident(c: u8) -> Ident { let arr = [c]; let s = ::std::str::from_utf8(&arr).unwrap(); @@ -101,3 +95,20 @@ pub(crate) fn find_suitable_param_names(trait_def: &ItemTrait) -> (Ident, Lifeti (ty_name, lt) } + +/// On nightly, we use `def_site` hygiene which puts our names into another +/// universe than the names of the user. This is not strictly required as our +/// name is already pretty much guaranteed to not conflict with another name, +/// but this is cleaner and just the correct thing to do. +#[cfg(feature = "nightly")] +fn param_span() -> Span2 { + ::proc_macro::Span::def_site().into() +} + +/// On stable, we use `call_site()` hygiene. That means that our names could +/// theoretically collide with names of the user. But we made sure this doesn't +/// happen. +#[cfg(not(feature = "nightly"))] +fn param_span() -> Span2 { + Span2::call_site() +} diff --git a/src/diag.rs b/src/diag.rs index 57d8395..1ffb0de 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -1,10 +1,26 @@ -use proc_macro::{Diagnostic, Span}; +//! This module has two purposes: +//! +//! 1. Provide the convenience method `emit_with_attr_note` and add it via +//! extension trait to `Diagnostic`. +//! +//! 2. Make `Diagnostic` work on stable by providing an own `Diagnostic` type +//! that prints the messages in a less-nice way. That way, other modules +//! don't have to worry about the stable/nightly distinction. `SpanExt` is +//! an extension trait that adds the `err()` method to the `Span` type. That +//! method works exactly like `Span::error()` but returns "our" +//! `Diagnostic`. Other modules can simply `use diag::SpanExt` and use +//! `.err()` on spans. +//! +use proc_macro::{Span, TokenStream}; + +/// Extension trait that adds a convenience method to `Diagnostic`. This is +/// simply to reduce duplicate code in other modules. pub trait DiagnosticExt { /// Helper function to add a note to the diagnostic (with a span pointing - /// to the `auto_impl` attribute) and emit the error. Additionally, - /// `Err(())` is always returned. + /// to the `auto_impl` attribute) and emit the error. An `Err(())` is + /// always returned. fn emit_with_attr_note(self) -> Result; } @@ -16,3 +32,152 @@ impl DiagnosticExt for Diagnostic { Err(()) } } + + +// ============================================================== +// Logic for stable/nightly mode starts here. +// +// First, we define a `Diagnostic` type. If we compile with the `nightly` +// feature, it's simple a typedef to `proc_macro::Diagnostic`. If we don't +// compile in nightly mode, we can't use that type, since it's still unstable. +// So in that case, we define our own type that tries to mimic the original +// `Diagnostic`. + +#[cfg(feature = "nightly")] +crate type Diagnostic = ::proc_macro::Diagnostic; + +#[cfg(not(feature = "nightly"))] +crate struct Diagnostic { + span: Span, + msg: String, +} + +// We provide the methods that `proc_macro::Diagnostic` also has here. Or +// rather: we only implement the subset that this crate actually uses. +// +// When we're not on the nightly compiler, we can't show a nice error. So how +// do we show the error then? The idea is to generate a token stream that +// contains `compile_error!(msg)` macro invocations. This macro is part of the +// standard library and emits `msg` as error. This is fairly useful for our +// case. However, a big limitation is that we can only emit one message. So in +// order to also show notes later added to the `Diagnostic`, we simply add +// "note: {the_note}" to the error string. This is crude and ugly, but it +// works. +// +// What about spans? Good question! Spans are important, but without a proper +// `Diagnostic` API, we can't properly support spans on errors and notes. The +// compiler will point to the `compile_error!()` invocation we generate. But we +// can use another hack to improve the situation slightly! On the token stream +// (containing `compile_error!()`) we generate, we can modify the spans of the +// individual token trees. If we set all spans to the span the error originates +// from, the compiler thinks that the `compile_error!()` code snippet has the +// span from the actual error source. That means that the error message will +// point to the actual error source! +// +// There is only a small problem: this only works when we get a proper span. +// Sadly, on stable, we can only get correct spans for individual token trees, +// not even token streams. We can't combine spans. As a consequence, spans are +// only correct if they come directly from a `TokenTree`. In general, errors +// coming from the `proxy` module have proper spans while errors from other +// modules don't have proper spans (on stable!). "Not proper" means that the +// span is simply `call_site()` -- it points to the `#[auto_impl()]` attribute. +// +// It could be worse, but it's simply true: for good error messages, nightly is +// required. +#[cfg(not(feature = "nightly"))] +impl Diagnostic { + crate fn note(mut self, msg: impl Into) -> Diagnostic { + self.msg += &format!("\n\nnote: {}", msg.into()); + self + } + + crate fn span_note(mut self, _: Span, msg: impl Into) -> Diagnostic { + // With out span fake method, we can only handle one span. We take the + // one of the original error and ignore additional ones. + self.msg += &format!("\n\nnote: {}", msg.into()); + self + } + + crate fn emit(self) { + // Create the error token stream that contains the `compile_error!()` + // invocation. + let msg = &self.msg; + let tokens = TokenStream::from(quote! { + compile_error!(#msg); + }); + + // Set the span of each token tree to the span the error originates + // from. + let tokens = tokens.into_iter() + .map(|mut tt| { + tt.set_span(self.span); + tt + }) + .collect(); + + // Push it to the global list of error streams + ERROR_TOKENS.with(|toks| { + toks.borrow_mut().push(tokens) + }); + } +} + +// Another problem with our `Diagnostic` hack on stable: the real +// `Diagnostic::emit()` doesn't return anything and modifies global state (it +// prints directly to stdout). We can't simply print! In our case it would be +// correct to pass a `TokenStream` ass the `Err()` variant of a result back up +// the stack and display it at the end. Two problems with that approach: +// +// - That's not how this application was build. Instead, it's build with the +// future `proc_macro` API in mind. And we wouldn't want to change everything +// back once it's stable. +// - On nightly, we don't want to pass TokenStreams up the stack. We can't have +// a completely different structure on nightly vs. on stable. +// +// Thus, we just "simulate" the original `emit()` by also modifying global +// state. We simply have a list of error token streams. This list is added to +// the final token stream at the end (in case of an error). It's not a very +// nice solution, but it's only a hack while stable doesn't offer something +// proper. +#[cfg(not(feature = "nightly"))] +use std::cell::RefCell; + +#[cfg(not(feature = "nightly"))] +thread_local! { + static ERROR_TOKENS: RefCell> = RefCell::new(vec![]); +} + +/// On stable, we just copy the error token streams from the global variable. +#[cfg(not(feature = "nightly"))] +crate fn error_tokens() -> TokenStream { + ERROR_TOKENS.with(|toks| toks.borrow().iter().cloned().collect()) +} + +/// On nightly, we don't use and don't have a strange global variable. Instead, +/// we just return an empty token stream. That's not a problem because all of +/// our errors were already printed. +#[cfg(feature = "nightly")] +crate fn error_tokens() -> TokenStream { + TokenStream::new() +} + +/// Extension trait to add the `err()` method to `Span`. This makes it easy to +/// start a `Diagnostic` from a span. +crate trait SpanExt { + fn err(self, msg: impl Into) -> Diagnostic; +} + +impl SpanExt for Span { + #[cfg(feature = "nightly")] + fn err(self, msg: impl Into) -> Diagnostic { + Diagnostic::spanned(self, ::proc_macro::Level::Error, msg) + } + + #[cfg(not(feature = "nightly"))] + fn err(self, msg: impl Into) -> Diagnostic { + Diagnostic { + span: self, + msg: msg.into(), + } + } +} diff --git a/src/gen.rs b/src/gen.rs index d3529bf..0de0769 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -7,8 +7,8 @@ use syn::{ }; use crate::{ - analyze::{find_suitable_param_names}, - diag::DiagnosticExt, + analyze::find_suitable_param_names, + diag::{DiagnosticExt, SpanExt}, proxy::ProxyType, spanned::Spanned }; @@ -17,7 +17,7 @@ use crate::{ /// Generates one complete impl of the given trait for each of the given proxy /// types. All impls are returned as token stream. -pub(crate) fn gen_impls( +crate fn gen_impls( proxy_types: &[ProxyType], trait_def: &syn::ItemTrait, ) -> Result<::proc_macro::TokenStream, ()> { @@ -141,7 +141,7 @@ fn gen_fn_type_for_trait( // If this requirement is not satisfied, we emit an error. if method.is_none() || trait_def.items.len() > 1 { return trait_def.span() - .error( + .err( "this trait cannot be auto-implemented for Fn-traits (only traits with exactly \ one method and no other items are allowed)" ) @@ -156,7 +156,7 @@ fn gen_fn_type_for_trait( // Check for forbidden modifier of the method if let Some(const_token) = sig.constness { return const_token.span() - .error(format!( + .err(format!( "the trait '{}' cannot be auto-implemented for Fn-traits: const methods are not \ allowed", trait_def.ident, @@ -166,7 +166,7 @@ fn gen_fn_type_for_trait( if let Some(unsafe_token) = &sig.unsafety { return unsafe_token.span() - .error(format!( + .err(format!( "the trait '{}' cannot be auto-implemented for Fn-traits: unsafe methods are not \ allowed", trait_def.ident, @@ -176,7 +176,7 @@ fn gen_fn_type_for_trait( if let Some(abi_token) = &sig.abi { return abi_token.span() - .error(format!( + .err(format!( "the trait '{}' cannot be implemented for Fn-traits: custom ABIs are not allowed", trait_def.ident, )) @@ -221,7 +221,7 @@ fn gen_fn_type_for_trait( allowed, ); - return method.sig.span().error(msg).emit_with_attr_note(); + return method.sig.span().err(msg).emit_with_attr_note(); } // ======================================================================= @@ -311,7 +311,7 @@ fn gen_items( // if it adds additional items to the trait. Thus, we have to // give up. mac.span() - .error( + .err( "traits with macro invocations in their bodies are not \ supported by auto_impl" ) @@ -321,7 +321,7 @@ fn gen_items( // I don't quite know when this happens, but it's better to // notify the user with a nice error instead of panicking. v.span() - .error("unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)") + .err("unexpected 'verbatim'-item (auto-impl doesn't know how to handle it)") .emit_with_attr_note() } } @@ -342,7 +342,7 @@ fn gen_const_item( // A trait with associated consts cannot be implemented for Fn* types. if proxy_type.is_fn() { return item.span() - .error(format!( + .err(format!( "the trait `{}` cannot be auto-implemented for Fn-traits, because it has \ associated consts (only traits with a single method can be implemented \ for Fn-traits)", @@ -374,7 +374,7 @@ fn gen_type_item( // A trait with associated types cannot be implemented for Fn* types. if proxy_type.is_fn() { return item.span() - .error(format!( + .err(format!( "the trait `{}` cannot be auto-implemented for Fn-traits, because it has \ associated types (only traits with a single method can be implemented \ for Fn-traits)", @@ -488,7 +488,7 @@ fn check_receiver_compatible( (ProxyType::Ref, SelfType::Mut) | (ProxyType::Ref, SelfType::Value) => { sig_span - .error(format!( + .err(format!( "the trait `{}` cannot be auto-implemented for immutable references, because \ this method has a `{}` receiver (only `&self` and no receiver are \ allowed)", @@ -500,7 +500,7 @@ fn check_receiver_compatible( (ProxyType::RefMut, SelfType::Value) => { sig_span - .error(format!( + .err(format!( "the trait `{}` cannot be auto-implemented for mutable references, because \ this method has a `self` receiver (only `&self`, `&mut self` and no \ receiver are allowed)", @@ -520,7 +520,7 @@ fn check_receiver_compatible( }; sig_span - .error(format!( + .err(format!( "the trait `{}` cannot be auto-implemented for {}-smartpointer, because \ this method has a `{}` receiver (only `&self` and no receiver are \ allowed)", @@ -544,7 +544,7 @@ fn check_receiver_compatible( /// Generates a list of comma-separated arguments used to call the function. /// Currently, only simple names are valid and more complex pattern will lead /// to an error being emitted. `self` parameters are ignored. -fn get_arg_list(inputs: impl Iterator) -> Result { +fn get_arg_list<'a>(inputs: impl Iterator) -> Result { let mut args = TokenStream2::new(); for arg in inputs { @@ -564,7 +564,7 @@ fn get_arg_list(inputs: impl Iterator) -> Result TokenStream { // compiler usually does some kind of error recovery to proceed. We // get the recovered tokens. Err(e) => { - let msg = "couldn't parse trait item"; - Diagnostic::spanned(Span::call_site(), Level::Error, msg) + // We have to take the detour through TokenStream2 to get a + // good span for the error. + TokenStream2::from(input.clone()).span() + .err("couldn't parse trait item") .note(e.to_string()) .note("the #[auto_impl] attribute can only be applied to traits!") .emit(); @@ -57,7 +58,7 @@ pub fn auto_impl(args: TokenStream, input: TokenStream) -> TokenStream { Err(()) } } - }().unwrap_or(TokenStream::new()); // If an error occured, we don't add any tokens. + }().unwrap_or_else(|_| diag::error_tokens()); // Combine the original token stream with the additional one containing the // generated impls (or nothing if an error occured). diff --git a/src/proxy.rs b/src/proxy.rs index ae48bb3..7ac47ae 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -2,9 +2,11 @@ use std::iter::Peekable; use proc_macro::{token_stream, TokenStream, TokenTree}; +use crate::diag::SpanExt; + /// Types for which a trait can automatically be implemented. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum ProxyType { +crate enum ProxyType { Ref, RefMut, Arc, @@ -16,7 +18,7 @@ pub(crate) enum ProxyType { } impl ProxyType { - pub(crate) fn is_fn(&self) -> bool { + crate fn is_fn(&self) -> bool { match *self { ProxyType::Fn | ProxyType::FnMut | ProxyType::FnOnce => true, _ => false, @@ -32,7 +34,7 @@ impl ProxyType { /// /// If the given TokenStream is not valid, errors are emitted as appropriate /// and `Err(())` is returned. -pub(crate) fn parse_types(args: TokenStream) -> Result, ()> { +crate fn parse_types(args: TokenStream) -> Result, ()> { let mut out = Vec::new(); let mut iter = args.into_iter().peekable(); @@ -72,7 +74,7 @@ fn eat_type(iter: &mut Peekable) -> Result { group.span() - .error(format!("unexpected group. {}", EXPECTED_TEXT)) + .err(format!("unexpected group. {}", EXPECTED_TEXT)) .note(NOTE_TEXT) .emit(); @@ -81,7 +83,7 @@ fn eat_type(iter: &mut Peekable) -> Result { lit.span() - .error(format!("unexpected literal. {}", EXPECTED_TEXT)) + .err(format!("unexpected literal. {}", EXPECTED_TEXT)) .note(NOTE_TEXT) .emit(); @@ -92,7 +94,7 @@ fn eat_type(iter: &mut Peekable) -> Result) -> Result { let msg = format!("unexpected '{}'. {}", ident, EXPECTED_TEXT); ident.span() - .error(msg) + .err(msg) .note(NOTE_TEXT) .emit(); diff --git a/src/spanned.rs b/src/spanned.rs index 2c433d6..d192e14 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -27,11 +27,21 @@ impl Spanned for T { if tokens.is_empty() { Span::call_site() } else { - let mut iter = tokens.into_iter(); - let mut span = iter.next().unwrap().span(); - if let Some(last) = iter.last() { - span = span.join(last.span()).unwrap(); - } + // If we're on nightly, we can create a correct span. Otherwise we + // just point to the first token. + #[cfg(feature = "nightly")] + let span = { + let mut iter = tokens.into_iter(); + let mut span = iter.next().unwrap().span(); + if let Some(last) = iter.last() { + span = span.join(last.span()).unwrap(); + } + span + }; + + #[cfg(not(feature = "nightly"))] + let span = tokens.into_iter().next().unwrap().span(); + span } } diff --git a/tests/compile-fail/attr_on_enum.rs b/tests/compile-fail/attr_on_enum.rs index 7ef3ddb..79d4d01 100644 --- a/tests/compile-fail/attr_on_enum.rs +++ b/tests/compile-fail/attr_on_enum.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/attr_on_fn.rs b/tests/compile-fail/attr_on_fn.rs index 0edcdab..f37cbd1 100644 --- a/tests/compile-fail/attr_on_fn.rs +++ b/tests/compile-fail/attr_on_fn.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/attr_on_impl_block.rs b/tests/compile-fail/attr_on_impl_block.rs index 96a5b6e..5d8efa7 100644 --- a/tests/compile-fail/attr_on_impl_block.rs +++ b/tests/compile-fail/attr_on_impl_block.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/attr_on_struct.rs b/tests/compile-fail/attr_on_struct.rs index 576f7ad..fa2b4fe 100644 --- a/tests/compile-fail/attr_on_struct.rs +++ b/tests/compile-fail/attr_on_struct.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/attr_on_type.rs b/tests/compile-fail/attr_on_type.rs index 1f6168f..caa5d30 100644 --- a/tests/compile-fail/attr_on_type.rs +++ b/tests/compile-fail/attr_on_type.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/attr_on_unit_struct.rs b/tests/compile-fail/attr_on_unit_struct.rs index 9ddf0f7..d356bc3 100644 --- a/tests/compile-fail/attr_on_unit_struct.rs +++ b/tests/compile-fail/attr_on_unit_struct.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/fn_associated_const.rs b/tests/compile-fail/fn_associated_const.rs index 2600c5a..97b28ff 100644 --- a/tests/compile-fail/fn_associated_const.rs +++ b/tests/compile-fail/fn_associated_const.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/fn_associated_type.rs b/tests/compile-fail/fn_associated_type.rs index d9a25f2..829929d 100644 --- a/tests/compile-fail/fn_associated_type.rs +++ b/tests/compile-fail/fn_associated_type.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/fn_multiple_methods.rs b/tests/compile-fail/fn_multiple_methods.rs index 47ec46b..fb0488b 100644 --- a/tests/compile-fail/fn_multiple_methods.rs +++ b/tests/compile-fail/fn_multiple_methods.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/fn_unsafe_method.rs b/tests/compile-fail/fn_unsafe_method.rs index 846e295..8e1e525 100644 --- a/tests/compile-fail/fn_unsafe_method.rs +++ b/tests/compile-fail/fn_unsafe_method.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-fail/mut_self_for_arc.rs b/tests/compile-fail/mut_self_for_arc.rs index acb602a..2efa899 100644 --- a/tests/compile-fail/mut_self_for_arc.rs +++ b/tests/compile-fail/mut_self_for_arc.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - use auto_impl::auto_impl; diff --git a/tests/compile-fail/mut_self_for_immutable_ref.rs b/tests/compile-fail/mut_self_for_immutable_ref.rs index eef19be..5019cfd 100644 --- a/tests/compile-fail/mut_self_for_immutable_ref.rs +++ b/tests/compile-fail/mut_self_for_immutable_ref.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - use auto_impl::auto_impl; diff --git a/tests/compile-fail/mut_self_for_rc.rs b/tests/compile-fail/mut_self_for_rc.rs index 44510c4..f828756 100644 --- a/tests/compile-fail/mut_self_for_rc.rs +++ b/tests/compile-fail/mut_self_for_rc.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - use auto_impl::auto_impl; diff --git a/tests/compile-fail/value_self_for_immutable_ref.rs b/tests/compile-fail/value_self_for_immutable_ref.rs index 644786e..81feb76 100644 --- a/tests/compile-fail/value_self_for_immutable_ref.rs +++ b/tests/compile-fail/value_self_for_immutable_ref.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - use auto_impl::auto_impl; diff --git a/tests/compile-fail/value_self_for_mutable_ref.rs b/tests/compile-fail/value_self_for_mutable_ref.rs index 86f8936..0a6e49f 100644 --- a/tests/compile-fail/value_self_for_mutable_ref.rs +++ b/tests/compile-fail/value_self_for_mutable_ref.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - use auto_impl::auto_impl; diff --git a/tests/compile-pass/big_trait_for_all_refs.rs b/tests/compile-pass/big_trait_for_all_refs.rs index d5ddf16..afeeda6 100644 --- a/tests/compile-pass/big_trait_for_all_refs.rs +++ b/tests/compile-pass/big_trait_for_all_refs.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/big_trait_for_box.rs b/tests/compile-pass/big_trait_for_box.rs index 9f83f03..87570f4 100644 --- a/tests/compile-pass/big_trait_for_box.rs +++ b/tests/compile-pass/big_trait_for_box.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/big_trait_where_bound_for_all_refs.rs b/tests/compile-pass/big_trait_where_bound_for_all_refs.rs index f8291d9..43c7dd4 100644 --- a/tests/compile-pass/big_trait_where_bound_for_all_refs.rs +++ b/tests/compile-pass/big_trait_where_bound_for_all_refs.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/fn_method_lifetimes.rs b/tests/compile-pass/fn_method_lifetimes.rs index 0a1e29f..8fced96 100644 --- a/tests/compile-pass/fn_method_lifetimes.rs +++ b/tests/compile-pass/fn_method_lifetimes.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/mut_self_for_fn.rs b/tests/compile-pass/mut_self_for_fn.rs index 051c038..d4fbca2 100644 --- a/tests/compile-pass/mut_self_for_fn.rs +++ b/tests/compile-pass/mut_self_for_fn.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/mut_self_for_fn_mut.rs b/tests/compile-pass/mut_self_for_fn_mut.rs index 24ea9b4..3e3cb83 100644 --- a/tests/compile-pass/mut_self_for_fn_mut.rs +++ b/tests/compile-pass/mut_self_for_fn_mut.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/ref_self_for_fn.rs b/tests/compile-pass/ref_self_for_fn.rs index 6900151..5e46594 100644 --- a/tests/compile-pass/ref_self_for_fn.rs +++ b/tests/compile-pass/ref_self_for_fn.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/trait_in_fn.rs b/tests/compile-pass/trait_in_fn.rs index 089b9bb..913fa17 100644 --- a/tests/compile-pass/trait_in_fn.rs +++ b/tests/compile-pass/trait_in_fn.rs @@ -1,7 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; - fn foo() { use auto_impl::auto_impl; diff --git a/tests/compile-pass/trait_in_mods.rs b/tests/compile-pass/trait_in_mods.rs index cd7db98..33d4492 100644 --- a/tests/compile-pass/trait_in_mods.rs +++ b/tests/compile-pass/trait_in_mods.rs @@ -1,11 +1,7 @@ -#![feature(use_extern_macros)] - // Make sure that everything compiles even without the prelude. This basically // forces us to generate full paths for types of the standard/core library. #![no_implicit_prelude] -extern crate auto_impl; - mod outer { use auto_impl::auto_impl; diff --git a/tests/compile-pass/value_self_for_fn.rs b/tests/compile-pass/value_self_for_fn.rs index fe0dca9..9f0d477 100644 --- a/tests/compile-pass/value_self_for_fn.rs +++ b/tests/compile-pass/value_self_for_fn.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/value_self_for_fn_mut.rs b/tests/compile-pass/value_self_for_fn_mut.rs index 444f4bd..702ff6a 100644 --- a/tests/compile-pass/value_self_for_fn_mut.rs +++ b/tests/compile-pass/value_self_for_fn_mut.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/compile-pass/value_self_for_fn_once.rs b/tests/compile-pass/value_self_for_fn_once.rs index daf8697..5ccfcc1 100644 --- a/tests/compile-pass/value_self_for_fn_once.rs +++ b/tests/compile-pass/value_self_for_fn_once.rs @@ -1,6 +1,3 @@ -#![feature(use_extern_macros)] - -extern crate auto_impl; use auto_impl::auto_impl; diff --git a/tests/util/mod.rs b/tests/util/mod.rs index 158d0be..c58d6f3 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -111,6 +111,7 @@ pub(crate) fn run_rustc(file_path: &Path, dep_path: &Path) -> process::Output { .args(&["--crate-type", "lib"]) .args(&["-Z", "no-codegen"]) .args(&["--emit", "metadata"]) + .arg("--edition=2018") .arg("--out-dir").arg(&out_dir) .arg("--extern").arg(&extern_value) .output()