diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1241e230b26d6..d64f3de8daa97 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -240,6 +240,13 @@ impl Invocation { InvocationKind::Derive { ref path, .. } => path.span, } } + + pub fn attr_id(&self) -> Option { + match self.kind { + InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id), + _ => None, + } + } } pub struct MacroExpander<'a, 'b:'a> { @@ -331,10 +338,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; + let attr_id_before = invoc.attr_id(); let ext = match self.cx.resolver.resolve_invoc(&mut invoc, scope, force) { Ok(ext) => Some(ext), Err(Determinacy::Determined) => None, Err(Determinacy::Undetermined) => { + // Sometimes attributes which we thought were invocations + // end up being custom attributes for custom derives. If + // that's the case our `invoc` will have changed out from + // under us. If this is the case we're making progress so we + // want to flag it as such, and we test this by looking if + // the `attr_id()` method has been changing over time. + if invoc.attr_id() != attr_id_before { + progress = true; + } undetermined_invocations.push(invoc); continue } diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-two-attrs.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-two-attrs.rs new file mode 100644 index 0000000000000..d02edb50fb2b5 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-two-attrs.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_derive(A, attributes(b))] +pub fn foo(_x: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-two-attrs.rs b/src/test/run-pass-fulldeps/proc-macro/derive-two-attrs.rs new file mode 100644 index 0000000000000..6a0a3b3a9416a --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/derive-two-attrs.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:derive-two-attrs.rs + +#![feature(use_extern_macros)] + +extern crate derive_two_attrs as foo; + +use foo::A; + +#[derive(A)] +#[b] +#[b] +struct B; + +fn main() {}