forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#49219 - eddyb:proc-macro-decouple, r=alexcric…
…hton 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 rust-lang#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
- Loading branch information
Showing
287 changed files
with
3,327 additions
and
1,168 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// 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 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
//! Buffer management for same-process client<->server communication. | ||
use std::io::{self, Write}; | ||
use std::mem; | ||
use std::ops::{Deref, DerefMut}; | ||
use std::slice; | ||
|
||
#[repr(C)] | ||
struct Slice<'a, T: 'a> { | ||
data: &'a [T; 0], | ||
len: usize, | ||
} | ||
|
||
unsafe impl<'a, T: Sync> Sync for Slice<'a, T> {} | ||
unsafe impl<'a, T: Sync> Send for Slice<'a, T> {} | ||
|
||
impl<T> Copy for Slice<'a, T> {} | ||
impl<T> Clone for Slice<'a, T> { | ||
fn clone(&self) -> Self { | ||
*self | ||
} | ||
} | ||
|
||
impl<T> From<&'a [T]> for Slice<'a, T> { | ||
fn from(xs: &'a [T]) -> Self { | ||
Slice { | ||
data: unsafe { &*(xs.as_ptr() as *const [T; 0]) }, | ||
len: xs.len(), | ||
} | ||
} | ||
} | ||
|
||
impl<T> Deref for Slice<'a, T> { | ||
type Target = [T]; | ||
fn deref(&self) -> &[T] { | ||
unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } | ||
} | ||
} | ||
|
||
#[repr(C)] | ||
pub struct Buffer<T: Copy> { | ||
data: *mut T, | ||
len: usize, | ||
capacity: usize, | ||
extend_from_slice: extern "C" fn(Buffer<T>, Slice<T>) -> Buffer<T>, | ||
drop: extern "C" fn(Buffer<T>), | ||
} | ||
|
||
unsafe impl<T: Copy + Sync> Sync for Buffer<T> {} | ||
unsafe impl<T: Copy + Send> Send for Buffer<T> {} | ||
|
||
impl<T: Copy> Default for Buffer<T> { | ||
fn default() -> Self { | ||
Self::from(vec![]) | ||
} | ||
} | ||
|
||
impl<T: Copy> Deref for Buffer<T> { | ||
type Target = [T]; | ||
fn deref(&self) -> &[T] { | ||
unsafe { slice::from_raw_parts(self.data as *const T, self.len) } | ||
} | ||
} | ||
|
||
impl<T: Copy> DerefMut for Buffer<T> { | ||
fn deref_mut(&mut self) -> &mut [T] { | ||
unsafe { slice::from_raw_parts_mut(self.data, self.len) } | ||
} | ||
} | ||
|
||
impl<T: Copy> Buffer<T> { | ||
pub(super) fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
pub(super) fn clear(&mut self) { | ||
self.len = 0; | ||
} | ||
|
||
pub(super) fn take(&mut self) -> Self { | ||
mem::replace(self, Self::default()) | ||
} | ||
|
||
pub(super) fn extend_from_slice(&mut self, xs: &[T]) { | ||
// Fast path to avoid going through an FFI call. | ||
if let Some(final_len) = self.len.checked_add(xs.len()) { | ||
if final_len <= self.capacity { | ||
let dst = unsafe { slice::from_raw_parts_mut(self.data, self.capacity) }; | ||
dst[self.len..][..xs.len()].copy_from_slice(xs); | ||
self.len = final_len; | ||
return; | ||
} | ||
} | ||
let b = self.take(); | ||
*self = (b.extend_from_slice)(b, Slice::from(xs)); | ||
} | ||
} | ||
|
||
impl Write for Buffer<u8> { | ||
fn write(&mut self, xs: &[u8]) -> io::Result<usize> { | ||
self.extend_from_slice(xs); | ||
Ok(xs.len()) | ||
} | ||
|
||
fn write_all(&mut self, xs: &[u8]) -> io::Result<()> { | ||
self.extend_from_slice(xs); | ||
Ok(()) | ||
} | ||
|
||
fn flush(&mut self) -> io::Result<()> { | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<T: Copy> Drop for Buffer<T> { | ||
fn drop(&mut self) { | ||
let b = self.take(); | ||
(b.drop)(b); | ||
} | ||
} | ||
|
||
impl<T: Copy> From<Vec<T>> for Buffer<T> { | ||
fn from(mut v: Vec<T>) -> Self { | ||
let (data, len, capacity) = (v.as_mut_ptr(), v.len(), v.capacity()); | ||
mem::forget(v); | ||
|
||
// This utility function is nested in here because it can *only* | ||
// be safely called on `Buffer`s created by *this* `proc_macro`. | ||
fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> { | ||
unsafe { | ||
let Buffer { | ||
data, | ||
len, | ||
capacity, | ||
.. | ||
} = b; | ||
mem::forget(b); | ||
Vec::from_raw_parts(data, len, capacity) | ||
} | ||
} | ||
|
||
extern "C" fn extend_from_slice<T: Copy>(b: Buffer<T>, xs: Slice<T>) -> Buffer<T> { | ||
let mut v = to_vec(b); | ||
v.extend_from_slice(&xs); | ||
Buffer::from(v) | ||
} | ||
|
||
extern "C" fn drop<T: Copy>(b: Buffer<T>) { | ||
mem::drop(to_vec(b)); | ||
} | ||
|
||
Buffer { | ||
data, | ||
len, | ||
capacity, | ||
extend_from_slice, | ||
drop, | ||
} | ||
} | ||
} |
Oops, something went wrong.