Skip to content

Commit 18da3c6

Browse files
committed
Do not expand a derive invocation when derive is not allowed
1. Change the return type of `expand_invoc()` and its subroutines to `Option<Expansion>` from `Expansion`. 2. Return `None` when expanding a derive invocation if the item cannot have derive on it (in `expand_derive_invoc()`).
1 parent 0cd6758 commit 18da3c6

File tree

3 files changed

+126
-79
lines changed

3 files changed

+126
-79
lines changed

src/libsyntax/ext/base.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,18 @@ impl Annotatable {
9696
_ => panic!("expected Item")
9797
}
9898
}
99+
100+
pub fn derive_allowed(&self) -> bool {
101+
match *self {
102+
Annotatable::Item(ref item) => match item.node {
103+
ast::ItemKind::Struct(..) |
104+
ast::ItemKind::Enum(..) |
105+
ast::ItemKind::Union(..) => true,
106+
_ => false,
107+
},
108+
_ => false,
109+
}
110+
}
99111
}
100112

101113
// A more flexible ItemDecorator.

src/libsyntax/ext/expand.rs

Lines changed: 91 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ expansions! {
136136
}
137137

138138
impl ExpansionKind {
139-
fn dummy(self, span: Span) -> Expansion {
140-
self.make_from(DummyResult::any(span)).unwrap()
139+
fn dummy(self, span: Span) -> Option<Expansion> {
140+
self.make_from(DummyResult::any(span))
141141
}
142142

143143
fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(self, items: I) -> Expansion {
@@ -304,21 +304,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
304304
// FIXME(jseyfried): Refactor out the following logic
305305
let (expansion, new_invocations) = if let Some(ext) = ext {
306306
if let Some(ext) = ext {
307-
let expansion = self.expand_invoc(invoc, ext);
307+
let dummy = invoc.expansion_kind.dummy(invoc.span()).unwrap();
308+
let expansion = self.expand_invoc(invoc, ext).unwrap_or(dummy);
308309
self.collect_invocations(expansion, &[])
309310
} else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind {
310-
let derive_allowed = match item {
311-
Annotatable::Item(ref item) => match item.node {
312-
ast::ItemKind::Struct(..) |
313-
ast::ItemKind::Enum(..) |
314-
ast::ItemKind::Union(..) => true,
315-
_ => false,
316-
},
317-
_ => false,
318-
};
319-
if !derive_allowed {
320-
let attr = item.attrs().iter()
321-
.find(|attr| attr.check_name("derive"))
311+
if !item.derive_allowed() {
312+
let attr = attr::find_by_name(item.attrs(), "derive")
322313
.expect("`derive` attribute should exist");
323314
let span = attr.span;
324315
let mut err = self.cx.mut_span_err(span,
@@ -366,7 +357,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
366357
unreachable!()
367358
}
368359
} else {
369-
self.collect_invocations(invoc.expansion_kind.dummy(invoc.span()), &[])
360+
self.collect_invocations(invoc.expansion_kind.dummy(invoc.span()).unwrap(), &[])
370361
};
371362

372363
if expansions.len() < depth {
@@ -446,11 +437,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
446437
}
447438
}
448439

449-
fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
440+
fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Option<Expansion> {
450441
let result = match invoc.kind {
451-
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
452-
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
453-
InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext),
442+
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?,
443+
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?,
444+
InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext)?,
454445
};
455446

456447
if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
@@ -467,13 +458,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
467458
panic!(FatalError);
468459
}
469460

470-
result
461+
Some(result)
471462
}
472463

473-
fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
464+
fn expand_attr_invoc(&mut self,
465+
invoc: Invocation,
466+
ext: Rc<SyntaxExtension>)
467+
-> Option<Expansion> {
474468
let Invocation { expansion_kind: kind, .. } = invoc;
475469
let (attr, item) = match invoc.kind {
476-
InvocationKind::Attr { attr, item, .. } => (attr.unwrap(), item),
470+
InvocationKind::Attr { attr, item, .. } => (attr?, item),
477471
_ => unreachable!(),
478472
};
479473

@@ -490,16 +484,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
490484

491485
match *ext {
492486
MultiModifier(ref mac) => {
493-
let meta = panictry!(attr.parse_meta(self.cx.parse_sess));
487+
let meta = attr.parse_meta(self.cx.parse_sess).ok()?;
494488
let item = mac.expand(self.cx, attr.span, &meta, item);
495-
kind.expect_from_annotatables(item)
489+
Some(kind.expect_from_annotatables(item))
496490
}
497491
MultiDecorator(ref mac) => {
498492
let mut items = Vec::new();
499-
let meta = panictry!(attr.parse_meta(self.cx.parse_sess));
493+
let meta = attr.parse_meta(self.cx.parse_sess).ok()?;
500494
mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item));
501495
items.push(item);
502-
kind.expect_from_annotatables(items)
496+
Some(kind.expect_from_annotatables(items))
503497
}
504498
AttrProcMacro(ref mac) => {
505499
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
@@ -525,7 +519,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
525519
}
526520

527521
/// Expand a macro invocation. Returns the result of expansion.
528-
fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
522+
fn expand_bang_invoc(&mut self,
523+
invoc: Invocation,
524+
ext: Rc<SyntaxExtension>)
525+
-> Option<Expansion> {
529526
let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind);
530527
let (mac, ident, span) = match invoc.kind {
531528
InvocationKind::Bang { mac, ident, span } => (mac, ident, span),
@@ -558,9 +555,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
558555
false, false) {
559556
self.cx.span_err(path.span, &msg);
560557
self.cx.trace_macros_diag();
561-
return kind.dummy(span);
558+
kind.dummy(span)
559+
} else {
560+
kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
562561
}
563-
kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
564562
}
565563

566564
NormalTT {
@@ -574,44 +572,45 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
574572
allow_internal_unsafe) {
575573
self.cx.span_err(path.span, &msg);
576574
self.cx.trace_macros_diag();
577-
return kind.dummy(span);
575+
kind.dummy(span)
576+
} else {
577+
kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
578578
}
579-
kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
580579
}
581580

582581
IdentTT(ref expander, tt_span, allow_internal_unstable) => {
583582
if ident.name == keywords::Invalid.name() {
584583
self.cx.span_err(path.span,
585584
&format!("macro {}! expects an ident argument", path));
586585
self.cx.trace_macros_diag();
587-
return kind.dummy(span);
588-
};
589-
590-
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
591-
call_site: span,
592-
callee: NameAndSpan {
593-
format: macro_bang_format(path),
594-
span: tt_span,
595-
allow_internal_unstable,
596-
allow_internal_unsafe: false,
597-
}
598-
});
586+
kind.dummy(span)
587+
} else {
588+
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
589+
call_site: span,
590+
callee: NameAndSpan {
591+
format: macro_bang_format(path),
592+
span: tt_span,
593+
allow_internal_unstable,
594+
allow_internal_unsafe: false,
595+
}
596+
});
599597

600-
let input: Vec<_> = mac.node.stream().into_trees().collect();
601-
kind.make_from(expander.expand(self.cx, span, ident, input))
598+
let input: Vec<_> = mac.node.stream().into_trees().collect();
599+
kind.make_from(expander.expand(self.cx, span, ident, input))
600+
}
602601
}
603602

604603
MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
605604
self.cx.span_err(path.span,
606605
&format!("`{}` can only be used in attributes", path));
607606
self.cx.trace_macros_diag();
608-
return kind.dummy(span);
607+
kind.dummy(span)
609608
}
610609

611610
ProcMacroDerive(..) | BuiltinDerive(..) => {
612611
self.cx.span_err(path.span, &format!("`{}` is a derive mode", path));
613612
self.cx.trace_macros_diag();
614-
return kind.dummy(span);
613+
kind.dummy(span)
615614
}
616615

617616
ProcMacro(ref expandfun) => {
@@ -620,43 +619,51 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
620619
format!("macro {}! expects no ident argument, given '{}'", path, ident);
621620
self.cx.span_err(path.span, &msg);
622621
self.cx.trace_macros_diag();
623-
return kind.dummy(span);
624-
}
622+
kind.dummy(span)
623+
} else {
624+
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
625+
call_site: span,
626+
callee: NameAndSpan {
627+
format: macro_bang_format(path),
628+
// FIXME procedural macros do not have proper span info
629+
// yet, when they do, we should use it here.
630+
span: None,
631+
// FIXME probably want to follow macro_rules macros here.
632+
allow_internal_unstable: false,
633+
allow_internal_unsafe: false,
634+
},
635+
});
625636

626-
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
627-
call_site: span,
628-
callee: NameAndSpan {
629-
format: macro_bang_format(path),
630-
// FIXME procedural macros do not have proper span info
631-
// yet, when they do, we should use it here.
632-
span: None,
633-
// FIXME probably want to follow macro_rules macros here.
634-
allow_internal_unstable: false,
635-
allow_internal_unsafe: false,
636-
},
637-
});
638-
639-
let tok_result = expandfun.expand(self.cx, span, mac.node.stream());
640-
Some(self.parse_expansion(tok_result, kind, path, span))
637+
let tok_result = expandfun.expand(self.cx, span, mac.node.stream());
638+
self.parse_expansion(tok_result, kind, path, span)
639+
}
641640
}
642641
};
643642

644-
unwrap_or!(opt_expanded, {
643+
if opt_expanded.is_some() {
644+
opt_expanded
645+
} else {
645646
let msg = format!("non-{kind} macro in {kind} position: {name}",
646647
name = path.segments[0].identifier.name, kind = kind.name());
647648
self.cx.span_err(path.span, &msg);
648649
self.cx.trace_macros_diag();
649650
kind.dummy(span)
650-
})
651+
}
651652
}
652653

653654
/// Expand a derive invocation. Returns the result of expansion.
654-
fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
655+
fn expand_derive_invoc(&mut self,
656+
invoc: Invocation,
657+
ext: Rc<SyntaxExtension>)
658+
-> Option<Expansion> {
655659
let Invocation { expansion_kind: kind, .. } = invoc;
656660
let (path, item) = match invoc.kind {
657661
InvocationKind::Derive { path, item } => (path, item),
658662
_ => unreachable!(),
659663
};
664+
if !item.derive_allowed() {
665+
return None;
666+
}
660667

661668
let pretty_name = Symbol::intern(&format!("derive({})", path));
662669
let span = path.span;
@@ -686,15 +693,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
686693
span: DUMMY_SP,
687694
node: ast::MetaItemKind::Word,
688695
};
689-
kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item))
696+
Some(kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item)))
690697
}
691698
BuiltinDerive(func) => {
692699
expn_info.callee.allow_internal_unstable = true;
693700
invoc.expansion_data.mark.set_expn_info(expn_info);
694701
let span = span.with_ctxt(self.cx.backtrace());
695702
let mut items = Vec::new();
696-
func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a));
697-
kind.expect_from_annotatables(items)
703+
func(self.cx, span, &attr.meta()?, &item, &mut |a| items.push(a));
704+
Some(kind.expect_from_annotatables(items))
698705
}
699706
_ => {
700707
let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
@@ -705,19 +712,24 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
705712
}
706713
}
707714

708-
fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, path: &Path, span: Span)
709-
-> Expansion {
715+
fn parse_expansion(&mut self,
716+
toks: TokenStream,
717+
kind: ExpansionKind,
718+
path: &Path,
719+
span: Span)
720+
-> Option<Expansion> {
710721
let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>());
711-
let expansion = match parser.parse_expansion(kind, false) {
712-
Ok(expansion) => expansion,
722+
match parser.parse_expansion(kind, false) {
723+
Ok(expansion) => {
724+
parser.ensure_complete_parse(path, kind.name(), span);
725+
Some(expansion)
726+
}
713727
Err(mut err) => {
714728
err.emit();
715729
self.cx.trace_macros_diag();
716-
return kind.dummy(span);
730+
kind.dummy(span)
717731
}
718-
};
719-
parser.ensure_complete_parse(path, kind.name(), span);
720-
expansion
732+
}
721733
}
722734
}
723735

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
trait Foo {
12+
#[derive(Clone)]
13+
//~^ ERROR `derive` may only be applied to structs, enums and unions
14+
type Bar;
15+
}
16+
17+
impl Bar {
18+
#[derive(Clone)]
19+
//~^ ERROR `derive` may only be applied to structs, enums and unions
20+
fn bar(&self) {}
21+
}
22+
23+
fn main() {}

0 commit comments

Comments
 (0)