mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #91433 - matthiaskrgr:rollup-118ql06, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #88502 (Add slice take methods) - #91313 (expand: Turn `ast::Crate` into a first class expansion target) - #91424 (Update LLVM with patches for better llvm-cov diagnostics) - #91425 (Include lint errors in error count for `-Ztreat-err-as-bug`) - #91430 (Add tests for `normalize-docs` overflow errors) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
48a5999fce
@ -517,6 +517,8 @@ pub struct Crate {
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub items: Vec<P<Item>>,
|
||||
pub span: Span,
|
||||
// Placeholder ID if the crate node is a macro placeholder.
|
||||
pub is_placeholder: Option<NodeId>,
|
||||
}
|
||||
|
||||
/// Possible values inside of compile-time attribute lists.
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::ptr::P;
|
||||
use super::token::Nonterminal;
|
||||
use super::tokenstream::LazyTokenStream;
|
||||
use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
|
||||
use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
|
||||
use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt};
|
||||
use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
|
||||
use super::{AttrVec, Attribute, Stmt, StmtKind};
|
||||
@ -276,7 +276,7 @@ derive_has_tokens_and_attrs! {
|
||||
// These ast nodes only support inert attributes, so they don't
|
||||
// store tokens (since nothing can observe them)
|
||||
derive_has_attrs_no_tokens! {
|
||||
FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam
|
||||
FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate
|
||||
}
|
||||
|
||||
// These AST nodes don't support attributes, but can
|
||||
|
@ -284,6 +284,10 @@ pub trait MutVisitor: Sized {
|
||||
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
|
||||
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
|
||||
/// method. Abort the program if the closure panics.
|
||||
///
|
||||
/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler.
|
||||
/// Instead of aborting on catching a panic we need to reset the visited node to some valid but
|
||||
/// possibly meaningless value and rethrow the panic.
|
||||
//
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_clobber<T, F>(t: &mut T, f: F)
|
||||
@ -1105,36 +1109,11 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
|
||||
visit_unsafety(unsafety, vis);
|
||||
}
|
||||
|
||||
// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
|
||||
// or make crate visiting first class if necessary.
|
||||
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
|
||||
visit_clobber(krate, |Crate { attrs, items, span }| {
|
||||
let item_vis =
|
||||
Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
|
||||
let item = P(Item {
|
||||
ident: Ident::empty(),
|
||||
attrs,
|
||||
id: DUMMY_NODE_ID,
|
||||
vis: item_vis,
|
||||
span,
|
||||
kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
|
||||
tokens: None,
|
||||
});
|
||||
let items = vis.flat_map_item(item);
|
||||
|
||||
let len = items.len();
|
||||
if len == 0 {
|
||||
Crate { attrs: vec![], items: vec![], span }
|
||||
} else if len == 1 {
|
||||
let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
|
||||
match kind {
|
||||
ItemKind::Mod(_, ModKind::Loaded(items, ..)) => Crate { attrs, items, span },
|
||||
_ => panic!("visitor converted a module to not a module"),
|
||||
}
|
||||
} else {
|
||||
panic!("a crate cannot expand to more than one item");
|
||||
}
|
||||
});
|
||||
let Crate { attrs, items, span, is_placeholder: _ } = krate;
|
||||
visit_attrs(attrs, vis);
|
||||
items.flat_map_in_place(|item| vis.flat_map_item(item));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
// Mutates one item into possibly many items.
|
||||
|
@ -211,6 +211,9 @@ pub trait Visitor<'ast>: Sized {
|
||||
fn visit_pat_field(&mut self, fp: &'ast PatField) {
|
||||
walk_pat_field(self, fp)
|
||||
}
|
||||
fn visit_crate(&mut self, krate: &'ast Crate) {
|
||||
walk_crate(self, krate)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -75,3 +75,12 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String {
|
||||
pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
|
||||
State::new().to_string(f)
|
||||
}
|
||||
|
||||
pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String {
|
||||
State::new().to_string(|s| {
|
||||
s.print_inner_attributes(&krate.attrs);
|
||||
for item in &krate.items {
|
||||
s.print_item(item);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -77,6 +77,10 @@ fn flat_map_annotatable(
|
||||
Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param),
|
||||
Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef),
|
||||
Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant),
|
||||
Annotatable::Crate(mut krate) => {
|
||||
vis.visit_crate(&mut krate);
|
||||
Some(Annotatable::Crate(krate))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +105,7 @@ impl CfgFinder {
|
||||
Annotatable::Param(param) => finder.visit_param(¶m),
|
||||
Annotatable::FieldDef(field) => finder.visit_field_def(&field),
|
||||
Annotatable::Variant(variant) => finder.visit_variant(&variant),
|
||||
Annotatable::Crate(krate) => finder.visit_crate(krate),
|
||||
};
|
||||
finder.has_cfg_or_cfg_attr
|
||||
}
|
||||
|
@ -84,9 +84,35 @@ struct TestHarnessGenerator<'a> {
|
||||
tests: Vec<Test>,
|
||||
}
|
||||
|
||||
impl TestHarnessGenerator<'_> {
|
||||
fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec<Test>) {
|
||||
let mut tests = mem::replace(&mut self.tests, prev_tests);
|
||||
|
||||
if !tests.is_empty() {
|
||||
// Create an identifier that will hygienically resolve the test
|
||||
// case name, even in another module.
|
||||
let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
|
||||
span,
|
||||
AstPass::TestHarness,
|
||||
&[],
|
||||
Some(node_id),
|
||||
);
|
||||
for test in &mut tests {
|
||||
// See the comment on `mk_main` for why we're using
|
||||
// `apply_mark` directly.
|
||||
test.ident.span =
|
||||
test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
|
||||
}
|
||||
self.cx.test_cases.extend(tests);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||
fn visit_crate(&mut self, c: &mut ast::Crate) {
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
noop_visit_crate(c, self);
|
||||
self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests);
|
||||
|
||||
// Create a main function to run our tests
|
||||
c.items.push(mk_main(&mut self.cx));
|
||||
@ -103,34 +129,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
|
||||
|
||||
// We don't want to recurse into anything other than mods, since
|
||||
// mods or tests inside of functions will break things
|
||||
if let ast::ItemKind::Mod(..) = item.kind {
|
||||
let tests = mem::take(&mut self.tests);
|
||||
if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind {
|
||||
let prev_tests = mem::take(&mut self.tests);
|
||||
noop_visit_item_kind(&mut item.kind, self);
|
||||
let mut tests = mem::replace(&mut self.tests, tests);
|
||||
|
||||
if !tests.is_empty() {
|
||||
let parent =
|
||||
if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
|
||||
// Create an identifier that will hygienically resolve the test
|
||||
// case name, even in another module.
|
||||
let inner_span = match item.kind {
|
||||
ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
|
||||
inner_span,
|
||||
AstPass::TestHarness,
|
||||
&[],
|
||||
Some(parent),
|
||||
);
|
||||
for test in &mut tests {
|
||||
// See the comment on `mk_main` for why we're using
|
||||
// `apply_mark` directly.
|
||||
test.ident.span =
|
||||
test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque);
|
||||
}
|
||||
self.cx.test_cases.extend(tests);
|
||||
}
|
||||
self.add_test_cases(item.id, span, prev_tests);
|
||||
}
|
||||
smallvec![P(item)]
|
||||
}
|
||||
@ -146,7 +148,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin
|
||||
} else if sess.contains_name(&item.attrs, sym::rustc_main) {
|
||||
EntryPointType::MainAttr
|
||||
} else if item.ident.name == sym::main {
|
||||
if depth == 1 {
|
||||
if depth == 0 {
|
||||
// This is a top-level function so can be 'main'
|
||||
EntryPointType::MainNamed
|
||||
} else {
|
||||
|
@ -1013,7 +1013,9 @@ impl HandlerInner {
|
||||
}
|
||||
|
||||
fn treat_err_as_bug(&self) -> bool {
|
||||
self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get())
|
||||
self.flags
|
||||
.treat_err_as_bug
|
||||
.map_or(false, |c| self.err_count() + self.lint_err_count >= c.get())
|
||||
}
|
||||
|
||||
fn print_error_count(&mut self, registry: &Registry) {
|
||||
@ -1205,7 +1207,10 @@ impl HandlerInner {
|
||||
|
||||
fn panic_if_treat_err_as_bug(&self) {
|
||||
if self.treat_err_as_bug() {
|
||||
match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) {
|
||||
match (
|
||||
self.err_count() + self.lint_err_count,
|
||||
self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
|
||||
) {
|
||||
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
|
||||
(0, _) | (1, _) => {}
|
||||
(count, as_bug) => panic!(
|
||||
|
@ -48,6 +48,7 @@ pub enum Annotatable {
|
||||
Param(ast::Param),
|
||||
FieldDef(ast::FieldDef),
|
||||
Variant(ast::Variant),
|
||||
Crate(ast::Crate),
|
||||
}
|
||||
|
||||
impl Annotatable {
|
||||
@ -66,6 +67,7 @@ impl Annotatable {
|
||||
Annotatable::Param(ref p) => p.span,
|
||||
Annotatable::FieldDef(ref sf) => sf.span,
|
||||
Annotatable::Variant(ref v) => v.span,
|
||||
Annotatable::Crate(ref c) => c.span,
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,6 +86,7 @@ impl Annotatable {
|
||||
Annotatable::Param(p) => p.visit_attrs(f),
|
||||
Annotatable::FieldDef(sf) => sf.visit_attrs(f),
|
||||
Annotatable::Variant(v) => v.visit_attrs(f),
|
||||
Annotatable::Crate(c) => c.visit_attrs(f),
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,6 +105,7 @@ impl Annotatable {
|
||||
Annotatable::Param(p) => visitor.visit_param(p),
|
||||
Annotatable::FieldDef(sf) => visitor.visit_field_def(sf),
|
||||
Annotatable::Variant(v) => visitor.visit_variant(v),
|
||||
Annotatable::Crate(c) => visitor.visit_crate(c),
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +126,8 @@ impl Annotatable {
|
||||
| Annotatable::GenericParam(..)
|
||||
| Annotatable::Param(..)
|
||||
| Annotatable::FieldDef(..)
|
||||
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
|
||||
| Annotatable::Variant(..)
|
||||
| Annotatable::Crate(..) => panic!("unexpected annotatable"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,6 +225,13 @@ impl Annotatable {
|
||||
_ => panic!("expected variant"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_crate(self) -> ast::Crate {
|
||||
match self {
|
||||
Annotatable::Crate(krate) => krate,
|
||||
_ => panic!("expected krate"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of an expansion that may need to be retried.
|
||||
@ -419,6 +431,11 @@ pub trait MacResult {
|
||||
fn make_variants(self: Box<Self>) -> Option<SmallVec<[ast::Variant; 1]>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn make_crate(self: Box<Self>) -> Option<ast::Crate> {
|
||||
// Fn-like macros cannot produce a crate.
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! make_MacEager {
|
||||
|
@ -14,13 +14,13 @@ use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||
use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall};
|
||||
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
|
||||
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
|
||||
use rustc_ast::{NodeId, PatKind, Path, StmtKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr::is_builtin_attr;
|
||||
use rustc_data_structures::map_in_place::MapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{Applicability, FatalError, PResult};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_feature::Features;
|
||||
use rustc_parse::parser::{
|
||||
AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma,
|
||||
@ -33,7 +33,7 @@ use rustc_session::Limit;
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::{FileName, LocalExpnId, Span};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use smallvec::SmallVec;
|
||||
use std::ops::DerefMut;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
@ -205,6 +205,7 @@ ast_fragments! {
|
||||
Variants(SmallVec<[ast::Variant; 1]>) {
|
||||
"variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
|
||||
}
|
||||
Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
|
||||
}
|
||||
|
||||
pub enum SupportsMacroExpansion {
|
||||
@ -227,9 +228,8 @@ impl AstFragmentKind {
|
||||
AstFragmentKind::Items
|
||||
| AstFragmentKind::TraitItems
|
||||
| AstFragmentKind::ImplItems
|
||||
| AstFragmentKind::ForeignItems => {
|
||||
SupportsMacroExpansion::Yes { supports_inner_attrs: true }
|
||||
}
|
||||
| AstFragmentKind::ForeignItems
|
||||
| AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },
|
||||
AstFragmentKind::Arms
|
||||
| AstFragmentKind::Fields
|
||||
| AstFragmentKind::FieldPats
|
||||
@ -288,6 +288,9 @@ impl AstFragmentKind {
|
||||
AstFragmentKind::OptExpr => {
|
||||
AstFragment::OptExpr(items.next().map(Annotatable::expect_expr))
|
||||
}
|
||||
AstFragmentKind::Crate => {
|
||||
AstFragment::Crate(items.next().expect("expected exactly one crate").expect_crate())
|
||||
}
|
||||
AstFragmentKind::Pat | AstFragmentKind::Ty => {
|
||||
panic!("patterns and types aren't annotatable")
|
||||
}
|
||||
@ -359,9 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
MacroExpander { cx, monotonic }
|
||||
}
|
||||
|
||||
// FIXME: Avoid visiting the crate as a `Mod` item,
|
||||
// make crate a first class expansion target instead.
|
||||
pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
|
||||
pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate {
|
||||
let file_path = match self.cx.source_map().span_to_filename(krate.span) {
|
||||
FileName::Real(name) => name
|
||||
.into_local_path()
|
||||
@ -375,52 +376,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
file_path_stack: vec![file_path],
|
||||
dir_path,
|
||||
});
|
||||
|
||||
let krate_item = AstFragment::Items(smallvec![P(ast::Item {
|
||||
attrs: krate.attrs,
|
||||
span: krate.span,
|
||||
kind: ast::ItemKind::Mod(
|
||||
Unsafe::No,
|
||||
ModKind::Loaded(krate.items, Inline::Yes, krate.span)
|
||||
),
|
||||
ident: Ident::empty(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
vis: ast::Visibility {
|
||||
span: krate.span.shrink_to_lo(),
|
||||
kind: ast::VisibilityKind::Public,
|
||||
tokens: None,
|
||||
},
|
||||
tokens: None,
|
||||
})]);
|
||||
|
||||
match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
|
||||
Some(ast::Item {
|
||||
attrs,
|
||||
kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)),
|
||||
..
|
||||
}) => {
|
||||
krate.attrs = attrs;
|
||||
krate.items = items;
|
||||
}
|
||||
None => {
|
||||
// Resolution failed so we return an empty expansion
|
||||
krate.attrs = vec![];
|
||||
krate.items = vec![];
|
||||
}
|
||||
Some(ast::Item { span, kind, .. }) => {
|
||||
krate.attrs = vec![];
|
||||
krate.items = vec![];
|
||||
self.cx.span_err(
|
||||
span,
|
||||
&format!(
|
||||
"expected crate top-level item to be a module after macro expansion, found {} {}",
|
||||
kind.article(), kind.descr()
|
||||
),
|
||||
);
|
||||
// FIXME: this workaround issue #84569
|
||||
FatalError.raise();
|
||||
}
|
||||
};
|
||||
let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
|
||||
self.cx.trace_macros_diag();
|
||||
krate
|
||||
}
|
||||
@ -708,26 +664,32 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
SyntaxExtensionKind::Attr(expander) => {
|
||||
self.gate_proc_macro_input(&item);
|
||||
self.gate_proc_macro_attr_item(span, &item);
|
||||
let mut fake_tokens = false;
|
||||
if let Annotatable::Item(item_inner) = &item {
|
||||
if let ItemKind::Mod(_, mod_kind) = &item_inner.kind {
|
||||
// FIXME: Collect tokens and use them instead of generating
|
||||
// fake ones. These are unstable, so it needs to be
|
||||
// fixed prior to stabilization
|
||||
// Fake tokens when we are invoking an inner attribute, and:
|
||||
fake_tokens = matches!(attr.style, ast::AttrStyle::Inner) &&
|
||||
// We are invoking an attribute on the crate root, or an outline
|
||||
// module
|
||||
(item_inner.ident.name.is_empty() || !matches!(mod_kind, ast::ModKind::Loaded(_, Inline::Yes, _)));
|
||||
}
|
||||
}
|
||||
let tokens = if fake_tokens {
|
||||
rustc_parse::fake_token_stream(
|
||||
let tokens = match &item {
|
||||
// FIXME: Collect tokens and use them instead of generating
|
||||
// fake ones. These are unstable, so it needs to be
|
||||
// fixed prior to stabilization
|
||||
// Fake tokens when we are invoking an inner attribute, and
|
||||
// we are invoking it on an out-of-line module or crate.
|
||||
Annotatable::Crate(krate) => rustc_parse::fake_token_stream_for_crate(
|
||||
&self.cx.sess.parse_sess,
|
||||
&item.into_nonterminal(),
|
||||
)
|
||||
} else {
|
||||
item.into_tokens(&self.cx.sess.parse_sess)
|
||||
krate,
|
||||
),
|
||||
Annotatable::Item(item_inner)
|
||||
if matches!(attr.style, ast::AttrStyle::Inner)
|
||||
&& matches!(
|
||||
item_inner.kind,
|
||||
ItemKind::Mod(
|
||||
_,
|
||||
ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _),
|
||||
)
|
||||
) =>
|
||||
{
|
||||
rustc_parse::fake_token_stream(
|
||||
&self.cx.sess.parse_sess,
|
||||
&item.into_nonterminal(),
|
||||
)
|
||||
}
|
||||
_ => item.into_tokens(&self.cx.sess.parse_sess),
|
||||
};
|
||||
let attr_item = attr.unwrap_normal_item();
|
||||
if let MacArgs::Eq(..) = attr_item.args {
|
||||
@ -804,7 +766,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
||||
Annotatable::Item(_)
|
||||
| Annotatable::TraitItem(_)
|
||||
| Annotatable::ImplItem(_)
|
||||
| Annotatable::ForeignItem(_) => return,
|
||||
| Annotatable::ForeignItem(_)
|
||||
| Annotatable::Crate(..) => return,
|
||||
Annotatable::Stmt(stmt) => {
|
||||
// Attributes are stable on item statements,
|
||||
// but unstable on all other kinds of statements
|
||||
@ -949,6 +912,7 @@ pub fn parse_ast_fragment<'a>(
|
||||
RecoverComma::No,
|
||||
RecoverColon::Yes,
|
||||
)?),
|
||||
AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),
|
||||
AstFragmentKind::Arms
|
||||
| AstFragmentKind::Fields
|
||||
| AstFragmentKind::FieldPats
|
||||
@ -1195,6 +1159,30 @@ macro_rules! assign_id {
|
||||
}
|
||||
|
||||
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
||||
fn visit_crate(&mut self, krate: &mut ast::Crate) {
|
||||
let span = krate.span;
|
||||
let empty_crate =
|
||||
|| ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None };
|
||||
let mut fold_crate = |krate: ast::Crate| {
|
||||
let mut krate = match self.configure(krate) {
|
||||
Some(krate) => krate,
|
||||
None => return empty_crate(),
|
||||
};
|
||||
|
||||
if let Some(attr) = self.take_first_attr(&mut krate) {
|
||||
return self
|
||||
.collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate)
|
||||
.make_crate();
|
||||
}
|
||||
|
||||
noop_visit_crate(&mut krate, self);
|
||||
krate
|
||||
};
|
||||
|
||||
// Cannot use `visit_clobber` here, see the FIXME on it.
|
||||
*krate = fold_crate(mem::replace(krate, empty_crate()));
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
|
||||
self.cfg.configure_expr(expr);
|
||||
visit_clobber(expr.deref_mut(), |mut expr| {
|
||||
|
@ -46,6 +46,12 @@ pub fn placeholder(
|
||||
|| P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None });
|
||||
|
||||
match kind {
|
||||
AstFragmentKind::Crate => AstFragment::Crate(ast::Crate {
|
||||
attrs: Default::default(),
|
||||
items: Default::default(),
|
||||
span,
|
||||
is_placeholder: Some(id),
|
||||
}),
|
||||
AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
|
||||
AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
|
||||
AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
|
||||
@ -354,4 +360,12 @@ impl MutVisitor for PlaceholderExpander {
|
||||
_ => noop_visit_ty(ty, self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_crate(&mut self, krate: &mut ast::Crate) {
|
||||
if let Some(id) = krate.is_placeholder {
|
||||
*krate = self.remove(id).make_crate();
|
||||
} else {
|
||||
noop_visit_crate(krate, self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ pub fn configure_and_expand(
|
||||
|
||||
let crate_attrs = krate.attrs.clone();
|
||||
let extern_mod_loaded = |ident: Ident, attrs, items, span| {
|
||||
let krate = ast::Crate { attrs, items, span };
|
||||
let krate = ast::Crate { attrs, items, span, is_placeholder: None };
|
||||
pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str());
|
||||
(krate.attrs, krate.items)
|
||||
};
|
||||
|
@ -326,6 +326,12 @@ pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream {
|
||||
parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
|
||||
}
|
||||
|
||||
pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream {
|
||||
let source = pprust::crate_to_string_for_macros(krate);
|
||||
let filename = FileName::macro_expansion_source_code(&source);
|
||||
parse_stream_from_source_str(filename, source, sess, Some(krate.span))
|
||||
}
|
||||
|
||||
pub fn parse_cfg_attr(
|
||||
attr: &Attribute,
|
||||
parse_sess: &ParseSess,
|
||||
|
@ -26,7 +26,7 @@ impl<'a> Parser<'a> {
|
||||
/// Parses a source module as a crate. This is the main entry point for the parser.
|
||||
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
|
||||
let (attrs, items, span) = self.parse_mod(&token::Eof)?;
|
||||
Ok(ast::Crate { attrs, items, span })
|
||||
Ok(ast::Crate { attrs, items, span, is_placeholder: None })
|
||||
}
|
||||
|
||||
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
|
||||
|
@ -651,11 +651,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||
|
||||
/// Constructs the reduced graph for one item.
|
||||
fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
|
||||
if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty {
|
||||
// Fake crate root item from expand.
|
||||
return;
|
||||
}
|
||||
|
||||
let parent_scope = &self.parent_scope;
|
||||
let parent = parent_scope.module;
|
||||
let expansion = parent_scope.expansion;
|
||||
@ -1499,4 +1494,13 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
|
||||
|
||||
visit::walk_variant(self, variant);
|
||||
}
|
||||
|
||||
fn visit_crate(&mut self, krate: &'b ast::Crate) {
|
||||
if let Some(id) = krate.is_placeholder {
|
||||
self.visit_invoc_in_module(id);
|
||||
} else {
|
||||
visit::walk_crate(self, krate);
|
||||
self.contains_macro_use(&krate.attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use rustc_expand::expand::AstFragment;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::definitions::*;
|
||||
use rustc_span::hygiene::LocalExpnId;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use tracing::debug;
|
||||
|
||||
@ -92,10 +92,6 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
|
||||
// information we encapsulate into, the better
|
||||
let def_data = match &i.kind {
|
||||
ItemKind::Impl { .. } => DefPathData::Impl,
|
||||
ItemKind::Mod(..) if i.ident.name == kw::Empty => {
|
||||
// Fake crate root item from expand.
|
||||
return visit::walk_item(self, i);
|
||||
}
|
||||
ItemKind::Mod(..)
|
||||
| ItemKind::Trait(..)
|
||||
| ItemKind::TraitAlias(..)
|
||||
@ -346,4 +342,12 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> {
|
||||
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
||||
self.collect_field(field, None);
|
||||
}
|
||||
|
||||
fn visit_crate(&mut self, krate: &'a Crate) {
|
||||
if let Some(id) = krate.is_placeholder {
|
||||
self.visit_macro_invoc(id)
|
||||
} else {
|
||||
visit::walk_crate(self, krate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,6 +181,9 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
|
||||
#[stable(feature = "inclusive_range", since = "1.26.0")]
|
||||
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
|
||||
|
||||
#[unstable(feature = "one_sided_range", issue = "69780")]
|
||||
pub use self::range::OneSidedRange;
|
||||
|
||||
#[unstable(feature = "try_trait_v2", issue = "84277")]
|
||||
pub use self::try_trait::{FromResidual, Try};
|
||||
|
||||
|
@ -971,3 +971,21 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
|
||||
Included(self.end)
|
||||
}
|
||||
}
|
||||
|
||||
/// `OneSidedRange` is implemented for built-in range types that are unbounded
|
||||
/// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`,
|
||||
/// but `..`, `d..e`, and `f..=g` do not.
|
||||
///
|
||||
/// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded`
|
||||
/// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`.
|
||||
#[unstable(feature = "one_sided_range", issue = "69780")]
|
||||
pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
|
||||
|
||||
#[unstable(feature = "one_sided_range", issue = "69780")]
|
||||
impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
|
||||
|
||||
#[unstable(feature = "one_sided_range", issue = "69780")]
|
||||
impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
|
||||
|
||||
#[unstable(feature = "one_sided_range", issue = "69780")]
|
||||
impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {}
|
||||
|
@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Greater, Less};
|
||||
use crate::marker::Copy;
|
||||
use crate::mem;
|
||||
use crate::num::NonZeroUsize;
|
||||
use crate::ops::{FnMut, Range, RangeBounds};
|
||||
use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
|
||||
use crate::option::Option;
|
||||
use crate::option::Option::{None, Some};
|
||||
use crate::ptr;
|
||||
@ -82,6 +82,29 @@ pub use index::range;
|
||||
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
|
||||
pub use ascii::EscapeAscii;
|
||||
|
||||
/// Calculates the direction and split point of a one-sided range.
|
||||
///
|
||||
/// This is a helper function for `take` and `take_mut` that returns
|
||||
/// the direction of the split (front or back) as well as the index at
|
||||
/// which to split. Returns `None` if the split index would overflow.
|
||||
#[inline]
|
||||
fn split_point_of(range: impl OneSidedRange<usize>) -> Option<(Direction, usize)> {
|
||||
use Bound::*;
|
||||
|
||||
Some(match (range.start_bound(), range.end_bound()) {
|
||||
(Unbounded, Excluded(i)) => (Direction::Front, *i),
|
||||
(Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?),
|
||||
(Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?),
|
||||
(Included(i), Unbounded) => (Direction::Back, *i),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
enum Direction {
|
||||
Front,
|
||||
Back,
|
||||
}
|
||||
|
||||
#[lang = "slice"]
|
||||
#[cfg(not(test))]
|
||||
impl<T> [T] {
|
||||
@ -3517,6 +3540,245 @@ impl<T> [T] {
|
||||
{
|
||||
self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i)
|
||||
}
|
||||
|
||||
/// Removes the subslice corresponding to the given range
|
||||
/// and returns a reference to it.
|
||||
///
|
||||
/// Returns `None` and does not modify the slice if the given
|
||||
/// range is out of bounds.
|
||||
///
|
||||
/// Note that this method only accepts one-sided ranges such as
|
||||
/// `2..` or `..6`, but not `2..6`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Taking the first three elements of a slice:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
|
||||
/// let mut first_three = slice.take(..3).unwrap();
|
||||
///
|
||||
/// assert_eq!(slice, &['d']);
|
||||
/// assert_eq!(first_three, &['a', 'b', 'c']);
|
||||
/// ```
|
||||
///
|
||||
/// Taking the last two elements of a slice:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
|
||||
/// let mut tail = slice.take(2..).unwrap();
|
||||
///
|
||||
/// assert_eq!(slice, &['a', 'b']);
|
||||
/// assert_eq!(tail, &['c', 'd']);
|
||||
/// ```
|
||||
///
|
||||
/// Getting `None` when `range` is out of bounds:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
|
||||
///
|
||||
/// assert_eq!(None, slice.take(5..));
|
||||
/// assert_eq!(None, slice.take(..5));
|
||||
/// assert_eq!(None, slice.take(..=4));
|
||||
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
|
||||
/// assert_eq!(Some(expected), slice.take(..4));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use = "method does not modify the slice if the range is out of bounds"]
|
||||
#[unstable(feature = "slice_take", issue = "62280")]
|
||||
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
|
||||
let (direction, split_index) = split_point_of(range)?;
|
||||
if split_index > self.len() {
|
||||
return None;
|
||||
}
|
||||
let (front, back) = self.split_at(split_index);
|
||||
match direction {
|
||||
Direction::Front => {
|
||||
*self = back;
|
||||
Some(front)
|
||||
}
|
||||
Direction::Back => {
|
||||
*self = front;
|
||||
Some(back)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the subslice corresponding to the given range
|
||||
/// and returns a mutable reference to it.
|
||||
///
|
||||
/// Returns `None` and does not modify the slice if the given
|
||||
/// range is out of bounds.
|
||||
///
|
||||
/// Note that this method only accepts one-sided ranges such as
|
||||
/// `2..` or `..6`, but not `2..6`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Taking the first three elements of a slice:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
|
||||
/// let mut first_three = slice.take_mut(..3).unwrap();
|
||||
///
|
||||
/// assert_eq!(slice, &mut ['d']);
|
||||
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
|
||||
/// ```
|
||||
///
|
||||
/// Taking the last two elements of a slice:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
|
||||
/// let mut tail = slice.take_mut(2..).unwrap();
|
||||
///
|
||||
/// assert_eq!(slice, &mut ['a', 'b']);
|
||||
/// assert_eq!(tail, &mut ['c', 'd']);
|
||||
/// ```
|
||||
///
|
||||
/// Getting `None` when `range` is out of bounds:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
|
||||
///
|
||||
/// assert_eq!(None, slice.take_mut(5..));
|
||||
/// assert_eq!(None, slice.take_mut(..5));
|
||||
/// assert_eq!(None, slice.take_mut(..=4));
|
||||
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
|
||||
/// assert_eq!(Some(expected), slice.take_mut(..4));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use = "method does not modify the slice if the range is out of bounds"]
|
||||
#[unstable(feature = "slice_take", issue = "62280")]
|
||||
pub fn take_mut<'a, R: OneSidedRange<usize>>(
|
||||
self: &mut &'a mut Self,
|
||||
range: R,
|
||||
) -> Option<&'a mut Self> {
|
||||
let (direction, split_index) = split_point_of(range)?;
|
||||
if split_index > self.len() {
|
||||
return None;
|
||||
}
|
||||
let (front, back) = mem::take(self).split_at_mut(split_index);
|
||||
match direction {
|
||||
Direction::Front => {
|
||||
*self = back;
|
||||
Some(front)
|
||||
}
|
||||
Direction::Back => {
|
||||
*self = front;
|
||||
Some(back)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the first element of the slice and returns a reference
|
||||
/// to it.
|
||||
///
|
||||
/// Returns `None` if the slice is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &[_] = &['a', 'b', 'c'];
|
||||
/// let first = slice.take_first().unwrap();
|
||||
///
|
||||
/// assert_eq!(slice, &['b', 'c']);
|
||||
/// assert_eq!(first, &'a');
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "slice_take", issue = "62280")]
|
||||
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
|
||||
let (first, rem) = self.split_first()?;
|
||||
*self = rem;
|
||||
Some(first)
|
||||
}
|
||||
|
||||
/// Removes the first element of the slice and returns a mutable
|
||||
/// reference to it.
|
||||
///
|
||||
/// Returns `None` if the slice is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
|
||||
/// let first = slice.take_first_mut().unwrap();
|
||||
/// *first = 'd';
|
||||
///
|
||||
/// assert_eq!(slice, &['b', 'c']);
|
||||
/// assert_eq!(first, &'d');
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "slice_take", issue = "62280")]
|
||||
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
|
||||
let (first, rem) = mem::take(self).split_first_mut()?;
|
||||
*self = rem;
|
||||
Some(first)
|
||||
}
|
||||
|
||||
/// Removes the last element of the slice and returns a reference
|
||||
/// to it.
|
||||
///
|
||||
/// Returns `None` if the slice is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &[_] = &['a', 'b', 'c'];
|
||||
/// let last = slice.take_last().unwrap();
|
||||
///
|
||||
/// assert_eq!(slice, &['a', 'b']);
|
||||
/// assert_eq!(last, &'c');
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "slice_take", issue = "62280")]
|
||||
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
|
||||
let (last, rem) = self.split_last()?;
|
||||
*self = rem;
|
||||
Some(last)
|
||||
}
|
||||
|
||||
/// Removes the last element of the slice and returns a mutable
|
||||
/// reference to it.
|
||||
///
|
||||
/// Returns `None` if the slice is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(slice_take)]
|
||||
///
|
||||
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
|
||||
/// let last = slice.take_last_mut().unwrap();
|
||||
/// *last = 'd';
|
||||
///
|
||||
/// assert_eq!(slice, &['a', 'b']);
|
||||
/// assert_eq!(last, &'d');
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "slice_take", issue = "62280")]
|
||||
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
|
||||
let (last, rem) = mem::take(self).split_last_mut()?;
|
||||
*self = rem;
|
||||
Some(last)
|
||||
}
|
||||
}
|
||||
|
||||
trait CloneFromSpec<T> {
|
||||
|
@ -36,6 +36,7 @@
|
||||
#![feature(pattern)]
|
||||
#![feature(sort_internals)]
|
||||
#![feature(slice_partition_at_index)]
|
||||
#![feature(slice_take)]
|
||||
#![feature(maybe_uninit_uninit_array)]
|
||||
#![feature(maybe_uninit_array_assume_init)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
|
@ -2234,3 +2234,112 @@ fn slice_split_array_mut_out_of_bounds() {
|
||||
|
||||
v.split_array_mut::<7>();
|
||||
}
|
||||
|
||||
macro_rules! take_tests {
|
||||
(slice: &[], $($tts:tt)*) => {
|
||||
take_tests!(ty: &[()], slice: &[], $($tts)*);
|
||||
};
|
||||
(slice: &mut [], $($tts:tt)*) => {
|
||||
take_tests!(ty: &mut [()], slice: &mut [], $($tts)*);
|
||||
};
|
||||
(slice: &$slice:expr, $($tts:tt)*) => {
|
||||
take_tests!(ty: &[_], slice: &$slice, $($tts)*);
|
||||
};
|
||||
(slice: &mut $slice:expr, $($tts:tt)*) => {
|
||||
take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*);
|
||||
};
|
||||
(ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => {
|
||||
$(
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
let mut slice: $ty = $slice;
|
||||
assert_eq!($output, slice.$method($($args)*));
|
||||
let remaining: $ty = $remaining;
|
||||
assert_eq!(remaining, slice);
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &[0, 1, 2, 3], method: take,
|
||||
(take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]),
|
||||
(take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]),
|
||||
(take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]),
|
||||
(take_oob_range_to, (..5), None, &[0, 1, 2, 3]),
|
||||
(take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]),
|
||||
(take_oob_range_from, (5..), None, &[0, 1, 2, 3]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &mut [0, 1, 2, 3], method: take_mut,
|
||||
(take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]),
|
||||
(take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]),
|
||||
(take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]),
|
||||
(take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]),
|
||||
(take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]),
|
||||
(take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &[1, 2], method: take_first,
|
||||
(take_first_nonempty, (), Some(&1), &[2]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &mut [1, 2], method: take_first_mut,
|
||||
(take_first_mut_nonempty, (), Some(&mut 1), &mut [2]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &[1, 2], method: take_last,
|
||||
(take_last_nonempty, (), Some(&2), &[1]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &mut [1, 2], method: take_last_mut,
|
||||
(take_last_mut_nonempty, (), Some(&mut 2), &mut [1]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &[], method: take_first,
|
||||
(take_first_empty, (), None, &[]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &mut [], method: take_first_mut,
|
||||
(take_first_mut_empty, (), None, &mut []),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &[], method: take_last,
|
||||
(take_last_empty, (), None, &[]),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &mut [], method: take_last_mut,
|
||||
(take_last_mut_empty, (), None, &mut []),
|
||||
}
|
||||
|
||||
const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
|
||||
|
||||
// can't be a constant due to const mutability rules
|
||||
macro_rules! empty_max_mut {
|
||||
() => {
|
||||
&mut [(); usize::MAX] as _
|
||||
};
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &[(); usize::MAX], method: take,
|
||||
(take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]),
|
||||
(take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX),
|
||||
(take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX),
|
||||
}
|
||||
|
||||
take_tests! {
|
||||
slice: &mut [(); usize::MAX], method: take_mut,
|
||||
(take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]),
|
||||
(take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
|
||||
(take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
|
||||
}
|
||||
|
@ -1337,25 +1337,15 @@ fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
|
||||
return None;
|
||||
}
|
||||
|
||||
use crate::rustc_trait_selection::infer::TyCtxtInferExt;
|
||||
use crate::rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
|
||||
// Try to normalize `<X as Y>::T` to a type
|
||||
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
|
||||
let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), cx.param_env)
|
||||
.normalize(lifted)
|
||||
.map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
|
||||
});
|
||||
match normalized {
|
||||
match cx.tcx.try_normalize_erasing_regions(cx.param_env, lifted) {
|
||||
Ok(normalized_value) => {
|
||||
debug!("normalized {:?} to {:?}", ty, normalized_value);
|
||||
trace!("normalized {:?} to {:?}", ty, normalized_value);
|
||||
Some(normalized_value)
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("failed to normalize {:?}: {:?}", ty, err);
|
||||
info!("failed to normalize {:?}: {:?}", ty, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f9b03d0e2d7378f8dd5697ceb72b310060f7598f
|
||||
Subproject commit 01c8b654f9a01371414d1fd69cba38b289510a9e
|
20
src/test/rustdoc-ui/auxiliary/overflow.rs
Normal file
20
src/test/rustdoc-ui/auxiliary/overflow.rs
Normal file
@ -0,0 +1,20 @@
|
||||
pub struct B0;
|
||||
pub struct B1;
|
||||
use std::ops::Shl;
|
||||
use std::ops::Sub;
|
||||
pub type Shleft<A, B> = <A as Shl<B>>::Output;
|
||||
pub type Sub1<A> = <A as Sub<B1>>::Output;
|
||||
pub struct UInt<U, B> {
|
||||
pub(crate) msb: U,
|
||||
pub(crate) lsb: B,
|
||||
}
|
||||
impl<U, B, Ur, Br> Shl<UInt<Ur, Br>> for UInt<U, B>
|
||||
where
|
||||
UInt<Ur, Br>: Sub<B1>,
|
||||
UInt<UInt<U, B>, B0>: Shl<Sub1<UInt<Ur, Br>>>,
|
||||
{
|
||||
type Output = Shleft<UInt<UInt<U, B>, B0>, Sub1<UInt<Ur, Br>>>;
|
||||
fn shl(self, rhs: UInt<Ur, Br>) -> Self::Output {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
25
src/test/rustdoc-ui/normalize-cycle.rs
Normal file
25
src/test/rustdoc-ui/normalize-cycle.rs
Normal file
@ -0,0 +1,25 @@
|
||||
// check-pass
|
||||
// Regresion test for <https://github.com/rust-lang/rust/issues/79459>.
|
||||
pub trait Query {}
|
||||
|
||||
pub trait AsQuery {
|
||||
type Query;
|
||||
}
|
||||
|
||||
impl<T: Query> AsQuery for T {
|
||||
type Query = T;
|
||||
}
|
||||
|
||||
pub trait SelectDsl<Selection> {
|
||||
type Output;
|
||||
}
|
||||
|
||||
impl<T, Selection> SelectDsl<Selection> for T
|
||||
where
|
||||
T: AsQuery,
|
||||
T::Query: SelectDsl<Selection>,
|
||||
{
|
||||
type Output = <T::Query as SelectDsl<Selection>>::Output;
|
||||
}
|
||||
|
||||
pub type Select<Source, Selection> = <Source as SelectDsl<Selection>>::Output;
|
3
src/test/rustdoc-ui/normalize-overflow.rs
Normal file
3
src/test/rustdoc-ui/normalize-overflow.rs
Normal file
@ -0,0 +1,3 @@
|
||||
// aux-crate:overflow=overflow.rs
|
||||
// check-pass
|
||||
// Regression test for <https://github.com/rust-lang/rust/issues/79506>.
|
@ -1 +1 @@
|
||||
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}}
|
||||
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
|
||||
|
@ -1 +1 @@
|
||||
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}}
|
||||
{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
|
||||
|
14
src/test/ui/proc-macro/crate-attrs-multiple.rs
Normal file
14
src/test/ui/proc-macro/crate-attrs-multiple.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Multiple custom crate-level attributes, both inert and active.
|
||||
|
||||
// check-pass
|
||||
// aux-crate:test_macros=test-macros.rs
|
||||
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![feature(prelude_import)]
|
||||
|
||||
#![test_macros::identity_attr]
|
||||
#![rustfmt::skip]
|
||||
#![test_macros::identity_attr]
|
||||
#![rustfmt::skip]
|
||||
|
||||
fn main() {}
|
@ -1,7 +1,10 @@
|
||||
// edition:2018
|
||||
// aux-crate:issue_59191=issue-59191.rs
|
||||
// Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely.
|
||||
// `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`.
|
||||
|
||||
// edition:2018
|
||||
// aux-crate:issue_59191=issue-59191.rs
|
||||
// error-pattern: requires `sized` lang_item
|
||||
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![issue_59191::no_main]
|
||||
//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function
|
||||
#![issue_59191::no_main]
|
||||
|
@ -1,10 +1,4 @@
|
||||
error: expected crate top-level item to be a module after macro expansion, found a function
|
||||
--> $DIR/issue-59191-replace-root-with-fn.rs:6:1
|
||||
|
|
||||
LL | #![issue_59191::no_main]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the attribute macro `issue_59191::no_main` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
error: requires `sized` lang_item
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user