Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macro syn rewrite #1073

Draft
wants to merge 27 commits into
base: rust-next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6b2262f
kbuild: rust: apply `CONFIG_WERROR` to hostprogs as well
ojeda Apr 7, 2024
a5f77c5
kbuild: rust: use shared host Rust flags for `macros`
ojeda Apr 7, 2024
e4527ff
kbuild: rust-analyzer: support key-value `cfg`s
ojeda Apr 10, 2024
c3b22c6
rust: proc-macro2: import crate
ojeda Oct 9, 2022
617c120
rust: proc-macro2: add SPDX License Identifiers
ojeda Oct 9, 2022
24954e2
rust: proc-macro2: remove `unicode_ident` dependency
ojeda Oct 9, 2022
925b30e
rust: quote: import crate
ojeda Oct 9, 2022
cdad907
rust: quote: add SPDX License Identifiers
ojeda Oct 9, 2022
328f151
rust: syn: import crate
ojeda Oct 9, 2022
cef2d41
rust: syn: add SPDX License Identifiers
ojeda Oct 9, 2022
82e9a4f
rust: syn: remove `unicode-ident` dependency
ojeda Oct 9, 2022
a59391f
rust: Kbuild: enable `proc-macro2`, `quote` and `syn`
ojeda Oct 9, 2022
1b729e1
rust: macros: fix soundness issue in `module!` macro
Apr 1, 2024
ed6e1a8
rust: macros: replace `quote!` with `quote::quote` and use `proc-macro2`
Apr 6, 2024
8938c4f
rust: macros: rewrite `#[vtable]` using `syn`
Apr 6, 2024
638dc79
rust: macros: rewrite `module!` using `syn`
Apr 6, 2024
bdb4cff
rust: macros: rewrite `Zeroable` derive macro using `syn`
Apr 6, 2024
2a88e8a
rust: macros: rewrite `#[pin_data]` using `syn`
Apr 6, 2024
b8459ad
rust: macros: rewrite `#[pinned_drop]` using `syn`
Apr 5, 2024
5d4eb2d
rust: macros: rewrite `__internal_init!` using `syn`
Apr 6, 2024
a8dae43
rust: macros: remove helpers
Apr 6, 2024
45d057b
rust: init: remove macros.rs
Apr 8, 2024
c7790b6
fixup! rust: macros: rewrite `#[pin_data]` using `syn`
Apr 16, 2024
66b9b59
fixup! rust: macros: rewrite `#[pinned_drop]` using `syn`
Apr 16, 2024
8d21a65
fixup! rust: macros: rewrite `__internal_init!` using `syn`
Apr 16, 2024
edd1ce0
fixup! rust: macros: rewrite `Zeroable` derive macro using `syn`
Apr 16, 2024
6ad858d
fixup! rust: macros: rewrite `#[vtable]` using `syn`
Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,9 @@ KBUILD_CFLAGS += $(stackp-flags-y)
KBUILD_RUSTFLAGS-$(CONFIG_WERROR) += -Dwarnings
KBUILD_RUSTFLAGS += $(KBUILD_RUSTFLAGS-y)

KBUILD_HOSTRUSTFLAGS-$(CONFIG_WERROR) += -Dwarnings
KBUILD_HOSTRUSTFLAGS += $(KBUILD_HOSTRUSTFLAGS-y)

ifdef CONFIG_FRAME_POINTER
KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
KBUILD_RUSTFLAGS += -Cforce-frame-pointers=y
Expand Down
5 changes: 3 additions & 2 deletions rust/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ $(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE

quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@
cmd_rustc_procmacro = \
$(RUSTC_OR_CLIPPY) $(rust_common_flags) \
$(RUSTC_OR_CLIPPY) $(KBUILD_HOSTRUSTFLAGS) \
-Clinker-flavor=gcc -Clinker=$(HOSTCC) \
-Clink-args='$(call escsq,$(KBUILD_HOSTLDFLAGS))' \
--emit=dep-info=$(depfile) --emit=link=$@ --extern proc_macro \
Expand All @@ -413,7 +413,8 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L

rust-analyzer:
$(Q)$(srctree)/scripts/generate_rust_analyzer.py \
--cfgs='core=$(core-cfgs)' --cfgs='alloc=$(alloc-cfgs)' \
--cfgs='core=$(call escsq,$(core-cfgs))' \
--cfgs='alloc=$(call escsq,$(alloc-cfgs))' \
$(realpath $(srctree)) $(realpath $(objtree)) \
$(RUST_LIB_SRC) $(KBUILD_EXTMOD) > \
$(if $(KBUILD_EXTMOD),$(extmod_prefix),$(objtree))/rust-project.json
Expand Down
77 changes: 77 additions & 0 deletions rust/proc-macro2/detection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT

use core::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Once;

static WORKS: AtomicUsize = AtomicUsize::new(0);
static INIT: Once = Once::new();

pub(crate) fn inside_proc_macro() -> bool {
match WORKS.load(Ordering::Relaxed) {
1 => return false,
2 => return true,
_ => {}
}

INIT.call_once(initialize);
inside_proc_macro()
}

pub(crate) fn force_fallback() {
WORKS.store(1, Ordering::Relaxed);
}

pub(crate) fn unforce_fallback() {
initialize();
}

#[cfg(not(no_is_available))]
fn initialize() {
let available = proc_macro::is_available();
WORKS.store(available as usize + 1, Ordering::Relaxed);
}

// Swap in a null panic hook to avoid printing "thread panicked" to stderr,
// then use catch_unwind to determine whether the compiler's proc_macro is
// working. When proc-macro2 is used from outside of a procedural macro all
// of the proc_macro crate's APIs currently panic.
//
// The Once is to prevent the possibility of this ordering:
//
// thread 1 calls take_hook, gets the user's original hook
// thread 1 calls set_hook with the null hook
// thread 2 calls take_hook, thinks null hook is the original hook
// thread 2 calls set_hook with the null hook
// thread 1 calls set_hook with the actual original hook
// thread 2 calls set_hook with what it thinks is the original hook
//
// in which the user's hook has been lost.
//
// There is still a race condition where a panic in a different thread can
// happen during the interval that the user's original panic hook is
// unregistered such that their hook is incorrectly not called. This is
// sufficiently unlikely and less bad than printing panic messages to stderr
// on correct use of this crate. Maybe there is a libstd feature request
// here. For now, if a user needs to guarantee that this failure mode does
// not occur, they need to call e.g. `proc_macro2::Span::call_site()` from
// the main thread before launching any other threads.
#[cfg(no_is_available)]
fn initialize() {
use std::panic::{self, PanicInfo};

type PanicHook = dyn Fn(&PanicInfo) + Sync + Send + 'static;

let null_hook: Box<PanicHook> = Box::new(|_panic_info| { /* ignore */ });
let sanity_check = &*null_hook as *const PanicHook;
let original_hook = panic::take_hook();
panic::set_hook(null_hook);

let works = panic::catch_unwind(proc_macro::Span::call_site).is_ok();
WORKS.store(works as usize + 1, Ordering::Relaxed);

let hopefully_null_hook = panic::take_hook();
panic::set_hook(original_hook);
if sanity_check != &*hopefully_null_hook {
panic!("observed race condition in proc_macro2::inside_proc_macro");
}
}
153 changes: 153 additions & 0 deletions rust/proc-macro2/extra.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! Items which do not have a correspondence to any API in the proc_macro crate,
//! but are necessary to include in proc-macro2.

use crate::fallback;
use crate::imp;
use crate::marker::{ProcMacroAutoTraits, MARKER};
use crate::Span;
use core::fmt::{self, Debug};

/// Invalidate any `proc_macro2::Span` that exist on the current thread.
///
/// The implementation of `Span` uses thread-local data structures and this
/// function clears them. Calling any method on a `Span` on the current thread
/// created prior to the invalidation will return incorrect values or crash.
///
/// This function is useful for programs that process more than 2<sup>32</sup>
/// bytes of Rust source code on the same thread. Just like rustc, proc-macro2
/// uses 32-bit source locations, and these wrap around when the total source
/// code processed by the same thread exceeds 2<sup>32</sup> bytes (4
/// gigabytes). After a wraparound, `Span` methods such as `source_text()` can
/// return wrong data.
///
/// # Example
///
/// As of late 2023, there is 200 GB of Rust code published on crates.io.
/// Looking at just the newest version of every crate, it is 16 GB of code. So a
/// workload that involves parsing it all would overflow a 32-bit source
/// location unless spans are being invalidated.
///
/// ```
/// use flate2::read::GzDecoder;
/// use std::ffi::OsStr;
/// use std::io::{BufReader, Read};
/// use std::str::FromStr;
/// use tar::Archive;
///
/// rayon::scope(|s| {
/// for krate in every_version_of_every_crate() {
/// s.spawn(move |_| {
/// proc_macro2::extra::invalidate_current_thread_spans();
///
/// let reader = BufReader::new(krate);
/// let tar = GzDecoder::new(reader);
/// let mut archive = Archive::new(tar);
/// for entry in archive.entries().unwrap() {
/// let mut entry = entry.unwrap();
/// let path = entry.path().unwrap();
/// if path.extension() != Some(OsStr::new("rs")) {
/// continue;
/// }
/// let mut content = String::new();
/// entry.read_to_string(&mut content).unwrap();
/// match proc_macro2::TokenStream::from_str(&content) {
/// Ok(tokens) => {/* ... */},
/// Err(_) => continue,
/// }
/// }
/// });
/// }
/// });
/// #
/// # fn every_version_of_every_crate() -> Vec<std::fs::File> {
/// # Vec::new()
/// # }
/// ```
///
/// # Panics
///
/// This function is not applicable to and will panic if called from a
/// procedural macro.
#[cfg(span_locations)]
#[cfg_attr(doc_cfg, doc(cfg(feature = "span-locations")))]
pub fn invalidate_current_thread_spans() {
crate::imp::invalidate_current_thread_spans();
}

/// An object that holds a [`Group`]'s `span_open()` and `span_close()` together
/// in a more compact representation than holding those 2 spans individually.
///
/// [`Group`]: crate::Group
#[derive(Copy, Clone)]
pub struct DelimSpan {
inner: DelimSpanEnum,
_marker: ProcMacroAutoTraits,
}

#[derive(Copy, Clone)]
enum DelimSpanEnum {
#[cfg(wrap_proc_macro)]
Compiler {
join: proc_macro::Span,
open: proc_macro::Span,
close: proc_macro::Span,
},
Fallback(fallback::Span),
}

impl DelimSpan {
pub(crate) fn new(group: &imp::Group) -> Self {
#[cfg(wrap_proc_macro)]
let inner = match group {
imp::Group::Compiler(group) => DelimSpanEnum::Compiler {
join: group.span(),
open: group.span_open(),
close: group.span_close(),
},
imp::Group::Fallback(group) => DelimSpanEnum::Fallback(group.span()),
};

#[cfg(not(wrap_proc_macro))]
let inner = DelimSpanEnum::Fallback(group.span());

DelimSpan {
inner,
_marker: MARKER,
}
}

/// Returns a span covering the entire delimited group.
pub fn join(&self) -> Span {
match &self.inner {
#[cfg(wrap_proc_macro)]
DelimSpanEnum::Compiler { join, .. } => Span::_new(imp::Span::Compiler(*join)),
DelimSpanEnum::Fallback(span) => Span::_new_fallback(*span),
}
}

/// Returns a span for the opening punctuation of the group only.
pub fn open(&self) -> Span {
match &self.inner {
#[cfg(wrap_proc_macro)]
DelimSpanEnum::Compiler { open, .. } => Span::_new(imp::Span::Compiler(*open)),
DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.first_byte()),
}
}

/// Returns a span for the closing punctuation of the group only.
pub fn close(&self) -> Span {
match &self.inner {
#[cfg(wrap_proc_macro)]
DelimSpanEnum::Compiler { close, .. } => Span::_new(imp::Span::Compiler(*close)),
DelimSpanEnum::Fallback(span) => Span::_new_fallback(span.last_byte()),
}
}
}

impl Debug for DelimSpan {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Debug::fmt(&self.join(), f)
}
}
Loading