Auto merge of #85486 - RalfJung:rollup-4ibcxuu, r=RalfJung
Rollup of 8 pull requests Successful merges: - #84717 (impl FromStr for proc_macro::Literal) - #85169 (Add method-toggle to <details> for methods) - #85287 (Expose `Concurrent` (private type in public i'face)) - #85315 (adding time complexity for partition_in_place iter method) - #85439 (Add diagnostic item to `CStr`) - #85464 (Fix UB in documented example for `ptr::swap`) - #85470 (Fix invalid CSS rules for a:hover) - #85472 (CTFE Machine: do not expose Allocation) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
35bab923c8
19 changed files with 179 additions and 48 deletions
|
@ -1,9 +1,7 @@
|
|||
use crate::base::{ExtCtxt, ResolverExpand};
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::token::Nonterminal;
|
||||
use rustc_ast::token::NtIdent;
|
||||
use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind};
|
||||
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
|
||||
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
|
||||
use rustc_ast_pretty::pprust;
|
||||
|
@ -541,6 +539,33 @@ impl server::Ident for Rustc<'_> {
|
|||
}
|
||||
|
||||
impl server::Literal for Rustc<'_> {
|
||||
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
|
||||
let override_span = None;
|
||||
let stream = parse_stream_from_source_str(
|
||||
FileName::proc_macro_source_code(s),
|
||||
s.to_owned(),
|
||||
self.sess,
|
||||
override_span,
|
||||
);
|
||||
if stream.len() != 1 {
|
||||
return Err(());
|
||||
}
|
||||
let tree = stream.into_trees().next().unwrap();
|
||||
let token = match tree {
|
||||
tokenstream::TokenTree::Token(token) => token,
|
||||
tokenstream::TokenTree::Delimited { .. } => return Err(()),
|
||||
};
|
||||
let span_data = token.span.data();
|
||||
if (span_data.hi.0 - span_data.lo.0) as usize != s.len() {
|
||||
// There is a comment or whitespace adjacent to the literal.
|
||||
return Err(());
|
||||
}
|
||||
let lit = match token.kind {
|
||||
TokenKind::Literal(lit) => lit,
|
||||
_ => return Err(()),
|
||||
};
|
||||
Ok(Literal { lit, span: self.call_site })
|
||||
}
|
||||
fn debug_kind(&mut self, literal: &Self::Literal) -> String {
|
||||
format!("{:?}", literal.lit.kind)
|
||||
}
|
||||
|
|
|
@ -313,7 +313,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
#[inline(always)]
|
||||
fn memory_read(
|
||||
_memory_extra: &Self::MemoryExtra,
|
||||
_alloc: &Allocation<Self::PointerTag, Self::AllocExtra>,
|
||||
_alloc_extra: &Self::AllocExtra,
|
||||
_ptr: Pointer<Self::PointerTag>,
|
||||
_size: Size,
|
||||
) -> InterpResult<'tcx> {
|
||||
|
@ -324,7 +324,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
#[inline(always)]
|
||||
fn memory_written(
|
||||
_memory_extra: &mut Self::MemoryExtra,
|
||||
_alloc: &mut Allocation<Self::PointerTag, Self::AllocExtra>,
|
||||
_alloc_extra: &mut Self::AllocExtra,
|
||||
_ptr: Pointer<Self::PointerTag>,
|
||||
_size: Size,
|
||||
) -> InterpResult<'tcx> {
|
||||
|
@ -335,8 +335,9 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
|||
#[inline(always)]
|
||||
fn memory_deallocated(
|
||||
_memory_extra: &mut Self::MemoryExtra,
|
||||
_alloc: &mut Allocation<Self::PointerTag, Self::AllocExtra>,
|
||||
_alloc_extra: &mut Self::AllocExtra,
|
||||
_ptr: Pointer<Self::PointerTag>,
|
||||
_size: Size,
|
||||
) -> InterpResult<'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -343,10 +343,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
}
|
||||
|
||||
// Let the machine take some extra action
|
||||
M::memory_deallocated(&mut self.extra, &mut alloc, ptr)?;
|
||||
let size = alloc.size();
|
||||
M::memory_deallocated(&mut self.extra, &mut alloc.extra, ptr, size)?;
|
||||
|
||||
// Don't forget to remember size and align of this now-dead allocation
|
||||
let old = self.dead_alloc_map.insert(ptr.alloc_id, (alloc.size(), alloc.align));
|
||||
let old = self.dead_alloc_map.insert(ptr.alloc_id, (size, alloc.align));
|
||||
if old.is_some() {
|
||||
bug!("Nothing can be deallocated twice");
|
||||
}
|
||||
|
@ -591,7 +592,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
},
|
||||
)?;
|
||||
if let Some((ptr, alloc)) = ptr_and_alloc {
|
||||
M::memory_read(&self.extra, alloc, ptr, size)?;
|
||||
M::memory_read(&self.extra, &alloc.extra, ptr, size)?;
|
||||
let range = alloc_range(ptr.offset, size);
|
||||
Ok(Some(AllocRef { alloc, range, tcx: self.tcx, alloc_id: ptr.alloc_id }))
|
||||
} else {
|
||||
|
@ -660,7 +661,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
// FIXME: can we somehow avoid looking up the allocation twice here?
|
||||
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
|
||||
let (alloc, extra) = self.get_raw_mut(ptr.alloc_id)?;
|
||||
M::memory_written(extra, alloc, ptr, size)?;
|
||||
M::memory_written(extra, &mut alloc.extra, ptr, size)?;
|
||||
let range = alloc_range(ptr.offset, size);
|
||||
Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id: ptr.alloc_id }))
|
||||
} else {
|
||||
|
@ -1029,7 +1030,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
Some(src_ptr) => src_ptr,
|
||||
};
|
||||
let src_alloc = self.get_raw(src.alloc_id)?;
|
||||
M::memory_read(&self.extra, src_alloc, src, size)?;
|
||||
M::memory_read(&self.extra, &src_alloc.extra, src, size)?;
|
||||
// We need the `dest` ptr for the next operation, so we get it now.
|
||||
// We already did the source checks and called the hooks so we are good to return early.
|
||||
let dest = match dest {
|
||||
|
@ -1058,7 +1059,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
|||
|
||||
// Destination alloc preparations and access hooks.
|
||||
let (dest_alloc, extra) = self.get_raw_mut(dest.alloc_id)?;
|
||||
M::memory_written(extra, dest_alloc, dest, size * num_copies)?;
|
||||
M::memory_written(extra, &mut dest_alloc.extra, dest, size * num_copies)?;
|
||||
let dest_bytes = dest_alloc
|
||||
.get_bytes_mut_ptr(&tcx, alloc_range(dest.offset, size * num_copies))
|
||||
.as_mut_ptr();
|
||||
|
|
|
@ -132,6 +132,7 @@ symbols! {
|
|||
Borrow,
|
||||
Break,
|
||||
C,
|
||||
CStr,
|
||||
CString,
|
||||
Center,
|
||||
Clone,
|
||||
|
|
|
@ -1849,6 +1849,12 @@ pub trait Iterator {
|
|||
///
|
||||
/// The relative order of partitioned items is not maintained.
|
||||
///
|
||||
/// # Current implementation
|
||||
/// Current algorithms tries finding the first element for which the predicate evaluates
|
||||
/// to false, and the last element for which it evaluates to true and repeatedly swaps them.
|
||||
///
|
||||
/// Time Complexity: *O*(*N*)
|
||||
///
|
||||
/// See also [`is_partitioned()`] and [`partition()`].
|
||||
///
|
||||
/// [`is_partitioned()`]: Iterator::is_partitioned
|
||||
|
|
|
@ -342,10 +342,12 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
|
|||
/// ```
|
||||
/// use std::ptr;
|
||||
///
|
||||
/// let mut array = [0, 1, 2, 3];
|
||||
/// let mut array: [i32; 4] = [0, 1, 2, 3];
|
||||
///
|
||||
/// let x = array[0..].as_mut_ptr() as *mut [u32; 3]; // this is `array[0..3]`
|
||||
/// let y = array[1..].as_mut_ptr() as *mut [u32; 3]; // this is `array[1..4]`
|
||||
/// let array_ptr: *mut i32 = array.as_mut_ptr();
|
||||
///
|
||||
/// let x = array_ptr as *mut [i32; 3]; // this is `array[0..3]`
|
||||
/// let y = unsafe { array_ptr.add(1) } as *mut [i32; 3]; // this is `array[1..4]`
|
||||
///
|
||||
/// unsafe {
|
||||
/// ptr::swap(x, y);
|
||||
|
|
|
@ -107,6 +107,7 @@ macro_rules! with_api {
|
|||
Literal {
|
||||
fn drop($self: $S::Literal);
|
||||
fn clone($self: &$S::Literal) -> $S::Literal;
|
||||
fn from_str(s: &str) -> Result<$S::Literal, ()>;
|
||||
fn debug_kind($self: &$S::Literal) -> String;
|
||||
fn symbol($self: &$S::Literal) -> String;
|
||||
fn suffix($self: &$S::Literal) -> Option<String>;
|
||||
|
@ -315,6 +316,19 @@ impl<T: Unmark> Unmark for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Mark, E: Mark> Mark for Result<T, E> {
|
||||
type Unmarked = Result<T::Unmarked, E::Unmarked>;
|
||||
fn mark(unmarked: Self::Unmarked) -> Self {
|
||||
unmarked.map(T::mark).map_err(E::mark)
|
||||
}
|
||||
}
|
||||
impl<T: Unmark, E: Unmark> Unmark for Result<T, E> {
|
||||
type Unmarked = Result<T::Unmarked, E::Unmarked>;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
self.map(T::unmark).map_err(E::unmark)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! mark_noop {
|
||||
($($ty:ty),* $(,)?) => {
|
||||
$(
|
||||
|
|
|
@ -91,6 +91,12 @@ pub struct LexError {
|
|||
_inner: (),
|
||||
}
|
||||
|
||||
impl LexError {
|
||||
fn new() -> Self {
|
||||
LexError { _inner: () }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")]
|
||||
impl fmt::Display for LexError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
@ -1171,6 +1177,28 @@ impl Literal {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a single literal from its stringified representation.
|
||||
///
|
||||
/// In order to parse successfully, the input string must not contain anything
|
||||
/// but the literal token. Specifically, it must not contain whitespace or
|
||||
/// comments in addition to the literal.
|
||||
///
|
||||
/// The resulting literal token will have a `Span::call_site()` span.
|
||||
///
|
||||
/// NOTE: some errors may cause panics instead of returning `LexError`. We
|
||||
/// reserve the right to change these errors into `LexError`s later.
|
||||
#[stable(feature = "proc_macro_literal_parse", since = "1.54.0")]
|
||||
impl FromStr for Literal {
|
||||
type Err = LexError;
|
||||
|
||||
fn from_str(src: &str) -> Result<Self, LexError> {
|
||||
match bridge::client::Literal::from_str(src) {
|
||||
Ok(literal) => Ok(Literal(literal)),
|
||||
Err(()) => Err(LexError::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// N.B., the bridge only provides `to_string`, implement `fmt::Display`
|
||||
// based on it (the reverse of the usual relationship between the two).
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
|
|
|
@ -185,6 +185,7 @@ pub struct CString {
|
|||
///
|
||||
/// [`&str`]: prim@str
|
||||
#[derive(Hash)]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
// FIXME:
|
||||
// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
|
||||
|
|
|
@ -49,7 +49,7 @@ pub mod test {
|
|||
cli::{parse_opts, TestOpts},
|
||||
filter_tests,
|
||||
helpers::metrics::{Metric, MetricMap},
|
||||
options::{Options, RunIgnored, RunStrategy, ShouldPanic},
|
||||
options::{Concurrent, Options, RunIgnored, RunStrategy, ShouldPanic},
|
||||
run_test, test_main, test_main_static,
|
||||
test_result::{TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk},
|
||||
time::{TestExecTime, TestTimeOptions},
|
||||
|
|
|
@ -1352,8 +1352,11 @@ fn render_impl(
|
|||
}
|
||||
let w = if short_documented && trait_.is_some() { interesting } else { boring };
|
||||
|
||||
if !doc_buffer.is_empty() {
|
||||
w.write_str("<details class=\"rustdoc-toggle\" open><summary>");
|
||||
let toggled = !doc_buffer.is_empty();
|
||||
if toggled {
|
||||
let method_toggle_class =
|
||||
if item_type == ItemType::Method { " method-toggle" } else { "" };
|
||||
write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
|
||||
}
|
||||
match *item.kind {
|
||||
clean::MethodItem(..) | clean::TyMethodItem(_) => {
|
||||
|
@ -1453,7 +1456,7 @@ fn render_impl(
|
|||
}
|
||||
|
||||
w.push_buffer(info_buffer);
|
||||
if !doc_buffer.is_empty() {
|
||||
if toggled {
|
||||
w.write_str("</summary>");
|
||||
w.push_buffer(doc_buffer);
|
||||
w.push_str("</details>");
|
||||
|
|
|
@ -924,24 +924,16 @@ function hideThemeButtonState() {
|
|||
});
|
||||
}
|
||||
|
||||
if (hideMethodDocs) {
|
||||
onEachLazy(document.getElementsByClassName("method"), function(e) {
|
||||
var toggle = e.parentNode;
|
||||
if (toggle) {
|
||||
toggle = toggle.parentNode;
|
||||
}
|
||||
if (toggle && toggle.tagName === "DETAILS") {
|
||||
toggle.open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onEachLazy(document.getElementsByTagName("details"), function (e) {
|
||||
var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle");
|
||||
var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle");
|
||||
if (showLargeItem || showImplementor) {
|
||||
e.open = true;
|
||||
}
|
||||
if (hideMethodDocs && hasClass(e, "method-toggle")) {
|
||||
e.open = false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var currentType = document.getElementsByClassName("type-decl")[0];
|
||||
|
|
|
@ -151,17 +151,14 @@ pre, .rustdoc.source .example-wrap {
|
|||
color: #c5c5c5;
|
||||
}
|
||||
|
||||
.content a:hover {
|
||||
.search-results a:hover {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
.content a:focus {
|
||||
.search-results a:focus {
|
||||
color: #000 !important;
|
||||
background-color: #c6afb3;
|
||||
}
|
||||
.content a:focus {
|
||||
color: #000 !important;
|
||||
}
|
||||
.search-results a {
|
||||
color: #0096cf;
|
||||
}
|
||||
|
|
|
@ -109,11 +109,11 @@ pre, .rustdoc.source .example-wrap {
|
|||
color: #ddd;
|
||||
}
|
||||
|
||||
.content a:hover {
|
||||
.search-results a:hover {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
.content a:focus {
|
||||
.search-results a:focus {
|
||||
color: #eee !important;
|
||||
background-color: #616161;
|
||||
}
|
||||
|
|
|
@ -109,11 +109,11 @@ pre, .rustdoc.source .example-wrap {
|
|||
color: #4E4C4C;
|
||||
}
|
||||
|
||||
.content a:hover {
|
||||
.search-results a:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.content a:focus {
|
||||
.search-results a:focus {
|
||||
color: #000 !important;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#![feature(proc_macro_span)]
|
||||
use proc_macro::{LineColumn, Punct, Spacing};
|
||||
|
||||
use proc_macro::{LineColumn, Punct};
|
||||
pub fn test() {
|
||||
test_line_column_ord();
|
||||
test_punct_eq();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_line_column_ord() {
|
||||
let line0_column0 = LineColumn { line: 0, column: 0 };
|
||||
let line0_column1 = LineColumn { line: 0, column: 1 };
|
||||
|
@ -11,10 +13,9 @@ fn test_line_column_ord() {
|
|||
assert!(line0_column1 < line1_column0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_punct_eq() {
|
||||
// Good enough if it typechecks, since proc_macro::Punct can't exist in a test.
|
||||
fn _check(punct: Punct) {
|
||||
let _ = punct == ':';
|
||||
}
|
||||
let colon_alone = Punct::new(':', Spacing::Alone);
|
||||
assert_eq!(colon_alone, ':');
|
||||
let colon_joint = Punct::new(':', Spacing::Joint);
|
||||
assert_eq!(colon_joint, ':');
|
||||
}
|
24
src/test/ui/proc-macro/auxiliary/api/mod.rs
Normal file
24
src/test/ui/proc-macro/auxiliary/api/mod.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// force-host
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
#![crate_name = "proc_macro_api_tests"]
|
||||
#![feature(proc_macro_span)]
|
||||
#![deny(dead_code)] // catch if a test function is never called
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
mod cmp;
|
||||
mod parse;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn run(input: TokenStream) -> TokenStream {
|
||||
assert!(input.is_empty());
|
||||
|
||||
cmp::test();
|
||||
parse::test();
|
||||
|
||||
TokenStream::new()
|
||||
}
|
23
src/test/ui/proc-macro/auxiliary/api/parse.rs
Normal file
23
src/test/ui/proc-macro/auxiliary/api/parse.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use proc_macro::Literal;
|
||||
|
||||
pub fn test() {
|
||||
test_parse_literal();
|
||||
}
|
||||
|
||||
fn test_parse_literal() {
|
||||
assert_eq!("1".parse::<Literal>().unwrap().to_string(), "1");
|
||||
assert_eq!("1.0".parse::<Literal>().unwrap().to_string(), "1.0");
|
||||
assert_eq!("'a'".parse::<Literal>().unwrap().to_string(), "'a'");
|
||||
assert_eq!("\"\n\"".parse::<Literal>().unwrap().to_string(), "\"\n\"");
|
||||
assert_eq!("b\"\"".parse::<Literal>().unwrap().to_string(), "b\"\"");
|
||||
assert_eq!("r##\"\"##".parse::<Literal>().unwrap().to_string(), "r##\"\"##");
|
||||
assert_eq!("10ulong".parse::<Literal>().unwrap().to_string(), "10ulong");
|
||||
|
||||
assert!("0 1".parse::<Literal>().is_err());
|
||||
assert!("'a".parse::<Literal>().is_err());
|
||||
assert!(" 0".parse::<Literal>().is_err());
|
||||
assert!("0 ".parse::<Literal>().is_err());
|
||||
assert!("/* comment */0".parse::<Literal>().is_err());
|
||||
assert!("0/* comment */".parse::<Literal>().is_err());
|
||||
assert!("0// comment".parse::<Literal>().is_err());
|
||||
}
|
12
src/test/ui/proc-macro/test.rs
Normal file
12
src/test/ui/proc-macro/test.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
// check-pass
|
||||
// aux-build:api/mod.rs
|
||||
|
||||
//! This is for everything that *would* be a #[test] inside of libproc_macro,
|
||||
//! except for the fact that proc_macro objects are not capable of existing
|
||||
//! inside of an ordinary Rust test execution, only inside a macro.
|
||||
|
||||
extern crate proc_macro_api_tests;
|
||||
|
||||
proc_macro_api_tests::run!();
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Reference in a new issue