Skip to content

Commit a063667

Browse files
committed
Auto merge of #49219 - eddyb:proc-macro-decouple, r=alexcrichton
Decouple proc_macro from the rest of the compiler. This PR removes all dependencies of `proc_macro` on compiler crates and allows multiple copies of `proc_macro`, built even by different compilers (but from the same source), to interoperate. Practically, it allows: * running proc macro tests at stage1 (I moved most from `-fulldeps` to the regular suites) * using proc macros in the compiler itself (may require some rustbuild trickery) On the server (i.e. compiler front-end) side: * `server::*` traits are implemented to provide the concrete types and methods * the concrete types are completely separated from the `proc_macro` public API * the only use of the type implementing `Server` is to be passed to `Client::run` On the client (i.e. proc macro) side (potentially using a different `proc_macro` instance!): * `client::Client` wraps around client-side (expansion) function pointers * it encapsulates the `proc_macro` instance used by the client * its `run` method can be called by a server, to execute the client-side function * the client instance is bridged to the provided server, while it runs * ~~currently a thread is spawned, could use process isolation in the future~~ (not the case anymore, see #56058) * proc macro crates get a generated `static` holding a `&[ProcMacro]` * this describes all derives/attr/bang proc macros, replacing the "registrar" function * each variant of `ProcMacro` contains an appropriately typed `Client<fn(...) -> ...>` `proc_macro` public APIs call into the server via an internal "bridge": * only a currently running proc macro `Client` can interact with those APIs * server code might not be able to (if it uses a different `proc_macro` instance) * however, it can always create and `run` its own `Client`, but that may be inefficient * the `bridge` uses serialization, C ABI and integer handles to avoid Rust ABI instability * each invocation of a proc macro results in disjoint integers in its `proc_macro` handles * this prevents using values of those types across invocations (if they even can be kept) r? @alexcrichton cc @jseyfried @nikomatsakis @Zoxc @thepowersgang
2 parents 4632cf2 + e7011d0 commit a063667

File tree

288 files changed

+3279
-1121
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

288 files changed

+3279
-1121
lines changed

Cargo.lock

+1-9
Original file line numberDiff line numberDiff line change
@@ -1599,12 +1599,6 @@ dependencies = [
15991599
[[package]]
16001600
name = "proc_macro"
16011601
version = "0.0.0"
1602-
dependencies = [
1603-
"rustc_data_structures 0.0.0",
1604-
"rustc_errors 0.0.0",
1605-
"syntax 0.0.0",
1606-
"syntax_pos 0.0.0",
1607-
]
16081602

16091603
[[package]]
16101604
name = "profiler_builtins"
@@ -1933,7 +1927,6 @@ dependencies = [
19331927
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
19341928
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
19351929
"polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
1936-
"proc_macro 0.0.0",
19371930
"rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
19381931
"rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
19391932
"rustc_apfloat 0.0.0",
@@ -2351,7 +2344,6 @@ dependencies = [
23512344
"flate2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
23522345
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
23532346
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
2354-
"proc_macro 0.0.0",
23552347
"rustc 0.0.0",
23562348
"rustc_data_structures 0.0.0",
23572349
"rustc_errors 0.0.0",
@@ -2890,7 +2882,6 @@ version = "0.0.0"
28902882
dependencies = [
28912883
"fmt_macros 0.0.0",
28922884
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
2893-
"proc_macro 0.0.0",
28942885
"rustc_data_structures 0.0.0",
28952886
"rustc_errors 0.0.0",
28962887
"rustc_target 0.0.0",
@@ -2980,6 +2971,7 @@ name = "test"
29802971
version = "0.0.0"
29812972
dependencies = [
29822973
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
2974+
"proc_macro 0.0.0",
29832975
"term 0.0.0",
29842976
]
29852977

src/bootstrap/builder.rs

-1
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,6 @@ impl<'a> Builder<'a> {
390390
test::RunPassFullDeps,
391391
test::RunFailFullDeps,
392392
test::CompileFailFullDeps,
393-
test::IncrementalFullDeps,
394393
test::Rustdoc,
395394
test::Pretty,
396395
test::RunPassPretty,

src/bootstrap/test.rs

-6
Original file line numberDiff line numberDiff line change
@@ -839,12 +839,6 @@ host_test!(CompileFailFullDeps {
839839
suite: "compile-fail-fulldeps"
840840
});
841841

842-
host_test!(IncrementalFullDeps {
843-
path: "src/test/incremental-fulldeps",
844-
mode: "incremental",
845-
suite: "incremental-fulldeps"
846-
});
847-
848842
host_test!(Rustdoc {
849843
path: "src/test/rustdoc",
850844
mode: "rustdoc",

src/libproc_macro/Cargo.toml

-7
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,3 @@ version = "0.0.0"
55

66
[lib]
77
path = "lib.rs"
8-
crate-type = ["dylib"]
9-
10-
[dependencies]
11-
syntax = { path = "../libsyntax" }
12-
syntax_pos = { path = "../libsyntax_pos" }
13-
rustc_errors = { path = "../librustc_errors" }
14-
rustc_data_structures = { path = "../librustc_data_structures" }

src/libproc_macro/bridge/buffer.rs

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Copyright 2018 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+
//! Buffer management for same-process client<->server communication.
12+
13+
use std::io::{self, Write};
14+
use std::mem;
15+
use std::ops::{Deref, DerefMut};
16+
use std::slice;
17+
18+
#[repr(C)]
19+
struct Slice<'a, T: 'a> {
20+
data: &'a [T; 0],
21+
len: usize,
22+
}
23+
24+
unsafe impl<'a, T: Sync> Sync for Slice<'a, T> {}
25+
unsafe impl<'a, T: Sync> Send for Slice<'a, T> {}
26+
27+
impl<T> Copy for Slice<'a, T> {}
28+
impl<T> Clone for Slice<'a, T> {
29+
fn clone(&self) -> Self {
30+
*self
31+
}
32+
}
33+
34+
impl<T> From<&'a [T]> for Slice<'a, T> {
35+
fn from(xs: &'a [T]) -> Self {
36+
Slice {
37+
data: unsafe { &*(xs.as_ptr() as *const [T; 0]) },
38+
len: xs.len(),
39+
}
40+
}
41+
}
42+
43+
impl<T> Deref for Slice<'a, T> {
44+
type Target = [T];
45+
fn deref(&self) -> &[T] {
46+
unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) }
47+
}
48+
}
49+
50+
#[repr(C)]
51+
pub struct Buffer<T: Copy> {
52+
data: *mut T,
53+
len: usize,
54+
capacity: usize,
55+
extend_from_slice: extern "C" fn(Buffer<T>, Slice<T>) -> Buffer<T>,
56+
drop: extern "C" fn(Buffer<T>),
57+
}
58+
59+
unsafe impl<T: Copy + Sync> Sync for Buffer<T> {}
60+
unsafe impl<T: Copy + Send> Send for Buffer<T> {}
61+
62+
impl<T: Copy> Default for Buffer<T> {
63+
fn default() -> Self {
64+
Self::from(vec![])
65+
}
66+
}
67+
68+
impl<T: Copy> Deref for Buffer<T> {
69+
type Target = [T];
70+
fn deref(&self) -> &[T] {
71+
unsafe { slice::from_raw_parts(self.data as *const T, self.len) }
72+
}
73+
}
74+
75+
impl<T: Copy> DerefMut for Buffer<T> {
76+
fn deref_mut(&mut self) -> &mut [T] {
77+
unsafe { slice::from_raw_parts_mut(self.data, self.len) }
78+
}
79+
}
80+
81+
impl<T: Copy> Buffer<T> {
82+
pub(super) fn new() -> Self {
83+
Self::default()
84+
}
85+
86+
pub(super) fn clear(&mut self) {
87+
self.len = 0;
88+
}
89+
90+
pub(super) fn take(&mut self) -> Self {
91+
mem::replace(self, Self::default())
92+
}
93+
94+
pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
95+
// Fast path to avoid going through an FFI call.
96+
if let Some(final_len) = self.len.checked_add(xs.len()) {
97+
if final_len <= self.capacity {
98+
let dst = unsafe { slice::from_raw_parts_mut(self.data, self.capacity) };
99+
dst[self.len..][..xs.len()].copy_from_slice(xs);
100+
self.len = final_len;
101+
return;
102+
}
103+
}
104+
let b = self.take();
105+
*self = (b.extend_from_slice)(b, Slice::from(xs));
106+
}
107+
}
108+
109+
impl Write for Buffer<u8> {
110+
fn write(&mut self, xs: &[u8]) -> io::Result<usize> {
111+
self.extend_from_slice(xs);
112+
Ok(xs.len())
113+
}
114+
115+
fn write_all(&mut self, xs: &[u8]) -> io::Result<()> {
116+
self.extend_from_slice(xs);
117+
Ok(())
118+
}
119+
120+
fn flush(&mut self) -> io::Result<()> {
121+
Ok(())
122+
}
123+
}
124+
125+
impl<T: Copy> Drop for Buffer<T> {
126+
fn drop(&mut self) {
127+
let b = self.take();
128+
(b.drop)(b);
129+
}
130+
}
131+
132+
impl<T: Copy> From<Vec<T>> for Buffer<T> {
133+
fn from(mut v: Vec<T>) -> Self {
134+
let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity());
135+
mem::forget(v);
136+
137+
// This utility function is nested in here because it can *only*
138+
// be safely called on `Buffer`s created by *this* `proc_macro`.
139+
fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> {
140+
unsafe {
141+
let Buffer {
142+
data,
143+
len,
144+
capacity,
145+
..
146+
} = b;
147+
mem::forget(b);
148+
Vec::from_raw_parts(data, len, capacity)
149+
}
150+
}
151+
152+
extern "C" fn extend_from_slice<T: Copy>(b: Buffer<T>, xs: Slice<T>) -> Buffer<T> {
153+
let mut v = to_vec(b);
154+
v.extend_from_slice(&xs);
155+
Buffer::from(v)
156+
}
157+
158+
extern "C" fn drop<T: Copy>(b: Buffer<T>) {
159+
mem::drop(to_vec(b));
160+
}
161+
162+
Buffer {
163+
data,
164+
len,
165+
capacity,
166+
extend_from_slice,
167+
drop,
168+
}
169+
}
170+
}

0 commit comments

Comments
 (0)