Skip to content

Commit 9a87b8f

Browse files
committed
proc_macro: handle proc macro panics in their proc_macro instance.
1 parent a3f3b12 commit 9a87b8f

File tree

7 files changed

+51
-34
lines changed

7 files changed

+51
-34
lines changed

src/Cargo.lock

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/libproc_macro/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ version = "0.0.0"
77
path = "lib.rs"
88
crate-type = ["dylib"]
99

10+
[dependencies]
11+
lazy_static = "1.0.0"

src/libproc_macro/bridge.rs

+38-12
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
use std::cell::Cell;
2323
use std::fmt;
2424
use std::ops::Deref;
25+
use std::panic;
2526
use std::path::PathBuf;
2627
use std::ptr::NonNull;
28+
use std::thread;
2729

2830
use self::storage::{FromConcrete, ToConcrete, Storage};
2931

@@ -580,8 +582,20 @@ thread_local! {
580582
static CURRENT_FRONTEND: Cell<Option<NonNull<CurrentFrontend<'static>>>> = Cell::new(None);
581583
}
582584

583-
pub fn has_current_frontend() -> bool {
584-
CURRENT_FRONTEND.with(|p| p.get().is_some())
585+
// Hide the default panic output within `proc_macro` expansions.
586+
// NB. frontends can't do this because they may use a different libstd.
587+
lazy_static! {
588+
static ref DEFAULT_HOOK: Box<Fn(&panic::PanicInfo) + Sync + Send + 'static> = {
589+
let hook = panic::take_hook();
590+
panic::set_hook(Box::new(panic_hook));
591+
hook
592+
};
593+
}
594+
595+
fn panic_hook(info: &panic::PanicInfo) {
596+
if CURRENT_FRONTEND.with(|p| p.get().is_none()) {
597+
(*DEFAULT_HOOK)(info)
598+
}
585599
}
586600

587601
fn with_current_frontend<F, R>(f: F) -> R
@@ -604,6 +618,9 @@ fn set_current_frontend<F, R>(frontend: &CurrentFrontend, f: F) -> R
604618
}
605619
}
606620

621+
// Ensure panic output hiding is set up.
622+
::lazy_static::initialize(&DEFAULT_HOOK);
623+
607624
CURRENT_FRONTEND.with(|p| {
608625
let _reset = Reset { prev: p.get() };
609626
p.set(NonNull::new(frontend as *const _ as *mut _));
@@ -657,8 +674,9 @@ fn erase_concrete_frontend<F, G, R>(ng: extern "C" fn() -> generation::Generatio
657674
pub struct Expand1 {
658675
next_generation: extern "C" fn() -> generation::Generation,
659676
data: *const (),
677+
// FIXME(eddyb) achieve ABI compatibility for the `thread::Result` type.
660678
run: unsafe extern "C" fn(*const (), &&CurrentFrontend, TokenStream)
661-
-> TokenStream,
679+
-> thread::Result<TokenStream>,
662680
}
663681

664682
impl !Send for Expand1 {}
@@ -670,12 +688,15 @@ impl Expand1 {
670688
{
671689
unsafe extern "C" fn run<F>(f: *const (),
672690
frontend: &&CurrentFrontend,
673-
input: TokenStream) -> TokenStream
691+
input: TokenStream)
692+
-> thread::Result<TokenStream>
674693
where F: Fn(::TokenStream) -> ::TokenStream
675694
{
676695
let f = &*(f as *const F);
677696
set_current_frontend(*frontend, || {
678-
f(::TokenStream(input)).0
697+
panic::catch_unwind(panic::AssertUnwindSafe(|| {
698+
f(::TokenStream(input)).0
699+
}))
679700
})
680701
}
681702
Expand1 {
@@ -685,15 +706,16 @@ impl Expand1 {
685706
}
686707
}
687708

688-
pub fn run<F>(&self, frontend: F, input: F::TokenStream) -> F::TokenStream
709+
pub fn run<F>(&self, frontend: F, input: F::TokenStream)
710+
-> thread::Result<F::TokenStream>
689711
where F: FrontendInterface<TokenNode = TokenNode<F>>
690712
{
691713
erase_concrete_frontend(self.next_generation, frontend, |frontend, storage| {
692714
let input = storage.from_concrete(input);
693715
let output = unsafe {
694716
(self.run)(self.data, &frontend, input)
695717
};
696-
storage.to_concrete(output)
718+
output.map(|output| storage.to_concrete(output))
697719
})
698720
}
699721
}
@@ -705,8 +727,9 @@ impl Expand1 {
705727
pub struct Expand2 {
706728
next_generation: extern "C" fn() -> generation::Generation,
707729
data: *const (),
730+
// FIXME(eddyb) achieve ABI compatibility for the `thread::Result` type.
708731
run: unsafe extern "C" fn(*const (), &&CurrentFrontend, TokenStream, TokenStream)
709-
-> TokenStream,
732+
-> thread::Result<TokenStream>,
710733
}
711734

712735
impl !Send for Expand2 {}
@@ -719,12 +742,15 @@ impl Expand2 {
719742
unsafe extern "C" fn run<F>(f: *const (),
720743
frontend: &&CurrentFrontend,
721744
input: TokenStream,
722-
input2: TokenStream) -> TokenStream
745+
input2: TokenStream)
746+
-> thread::Result<TokenStream>
723747
where F: Fn(::TokenStream, ::TokenStream) -> ::TokenStream
724748
{
725749
let f = &*(f as *const F);
726750
set_current_frontend(*frontend, || {
727-
f(::TokenStream(input), ::TokenStream(input2)).0
751+
panic::catch_unwind(panic::AssertUnwindSafe(|| {
752+
f(::TokenStream(input), ::TokenStream(input2)).0
753+
}))
728754
})
729755
}
730756
Expand2 {
@@ -735,7 +761,7 @@ impl Expand2 {
735761
}
736762

737763
pub fn run<F>(&self, frontend: F, input: F::TokenStream, input2: F::TokenStream)
738-
-> F::TokenStream
764+
-> thread::Result<F::TokenStream>
739765
where F: FrontendInterface<TokenNode = TokenNode<F>>
740766
{
741767
erase_concrete_frontend(self.next_generation, frontend, |frontend, storage| {
@@ -744,7 +770,7 @@ impl Expand2 {
744770
let output = unsafe {
745771
(self.run)(self.data, &frontend, input, input2)
746772
};
747-
storage.to_concrete(output)
773+
output.map(|output| storage.to_concrete(output))
748774
})
749775
}
750776
}

src/libproc_macro/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
#![feature(box_into_raw_non_null)]
4343
#![feature(nonnull_cast)]
4444

45+
#[macro_use]
46+
extern crate lazy_static;
47+
4548
#[unstable(feature = "proc_macro_internals", issue = "27812")]
4649
#[doc(hidden)]
4750
pub mod bridge;

src/librustc/util/common.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use std::sync::mpsc::{Sender};
2424
use syntax_pos::{SpanData};
2525
use ty::maps::{QueryMsg};
2626
use dep_graph::{DepNode};
27-
use proc_macro;
2827
use lazy_static;
2928
use session::Session;
3029

@@ -47,9 +46,7 @@ lazy_static! {
4746
}
4847

4948
fn panic_hook(info: &panic::PanicInfo) {
50-
if !proc_macro::bridge::has_current_frontend() {
51-
(*DEFAULT_HOOK)(info)
52-
}
49+
(*DEFAULT_HOOK)(info)
5350
}
5451

5552
pub fn install_panic_hook() {

src/libsyntax_ext/deriving/custom.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::panic;
12-
1311
use errors::FatalError;
1412
use syntax::ast::{self, ItemKind, Attribute, Mac};
1513
use syntax::attr::{mark_used, mark_known};
@@ -79,11 +77,8 @@ impl MultiItemModifier for ProcMacroDerive {
7977
let item = ecx.resolver.eliminate_crate_var(item.clone());
8078
let token = Token::interpolated(token::NtItem(item));
8179
let input = tokenstream::TokenTree::Token(DUMMY_SP, token).into();
82-
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
83-
self.inner.run(::proc_macro_impl::Frontend::new(ecx), input)
84-
}));
8580

86-
let stream = match res {
81+
let stream = match self.inner.run(::proc_macro_impl::Frontend::new(ecx), input) {
8782
Ok(stream) => stream,
8883
Err(e) => {
8984
let msg = "proc-macro derive panicked";

src/libsyntax_ext/proc_macro_impl.rs

+3-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::panic;
1211
use std::path::PathBuf;
1312

1413
use errors::{Diagnostic, DiagnosticBuilder, FatalError, Level};
@@ -36,11 +35,7 @@ impl base::AttrProcMacro for AttrProcMacro {
3635
annotation: TokenStream,
3736
annotated: TokenStream)
3837
-> TokenStream {
39-
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
40-
self.inner.run(Frontend::new(ecx), annotation, annotated)
41-
}));
42-
43-
match res {
38+
match self.inner.run(Frontend::new(ecx), annotation, annotated) {
4439
Ok(stream) => stream,
4540
Err(e) => {
4641
let msg = "custom attribute panicked";
@@ -69,11 +64,7 @@ impl ProcMacro for BangProcMacro {
6964
span: Span,
7065
input: TokenStream)
7166
-> TokenStream {
72-
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
73-
self.inner.run(Frontend::new(ecx), input)
74-
}));
75-
76-
match res {
67+
match self.inner.run(Frontend::new(ecx), input) {
7768
Ok(stream) => stream,
7869
Err(e) => {
7970
let msg = "proc macro panicked";
@@ -105,7 +96,7 @@ impl ProcMacro for Quoter {
10596
info.callee.allow_internal_unstable = true;
10697
cx.current_expansion.mark.set_expn_info(info);
10798

108-
expand_quoter.run(Frontend::new(cx), stream)
99+
expand_quoter.run(Frontend::new(cx), stream).unwrap()
109100
}
110101
}
111102

0 commit comments

Comments
 (0)