Auto merge of #65588 - Centril:rollup-9k55k3t, r=Centril
Rollup of 6 pull requests Successful merges: - #65174 (Fix zero-size uninitialized boxes) - #65252 (expand: Simplify expansion of derives) - #65485 (Suppress ICE when validators disagree on `LiveDrop`s in presence of `&mut`) - #65542 (Refer to "associated functions" instead of "static methods") - #65545 (More symbol cleanups) - #65576 (Don't add `argc` and `argv` arguments to `main` on WASI.) Failed merges: r? @ghost
This commit is contained in:
commit
9578272d68
31 changed files with 282 additions and 133 deletions
|
@ -142,6 +142,9 @@ impl<T> Box<T> {
|
|||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
|
||||
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
|
||||
if layout.size() == 0 {
|
||||
return Box(NonNull::dangling().into())
|
||||
}
|
||||
let ptr = unsafe {
|
||||
Global.alloc(layout)
|
||||
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
|
||||
|
@ -182,9 +185,16 @@ impl<T> Box<[T]> {
|
|||
#[unstable(feature = "new_uninit", issue = "63291")]
|
||||
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
|
||||
let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
|
||||
let ptr = unsafe { alloc::alloc(layout) };
|
||||
let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
|
||||
let slice = unsafe { slice::from_raw_parts_mut(unique.cast().as_ptr(), len) };
|
||||
let ptr = if layout.size() == 0 {
|
||||
NonNull::dangling()
|
||||
} else {
|
||||
unsafe {
|
||||
Global.alloc(layout)
|
||||
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
|
||||
.cast()
|
||||
}
|
||||
};
|
||||
let slice = unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), len) };
|
||||
Box(Unique::from(slice))
|
||||
}
|
||||
}
|
||||
|
|
18
src/liballoc/tests/boxed.rs
Normal file
18
src/liballoc/tests/boxed.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use std::ptr::NonNull;
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
#[test]
|
||||
fn unitialized_zero_size_box() {
|
||||
assert_eq!(
|
||||
&*Box::<()>::new_uninit() as *const _,
|
||||
NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
|
||||
);
|
||||
assert_eq!(
|
||||
Box::<[()]>::new_uninit_slice(4).as_ptr(),
|
||||
NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
|
||||
);
|
||||
assert_eq!(
|
||||
Box::<[String]>::new_uninit_slice(0).as_ptr(),
|
||||
NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
|
||||
);
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(box_syntax)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(option_flattening)]
|
||||
#![feature(pattern)]
|
||||
#![feature(trusted_len)]
|
||||
|
@ -14,6 +15,7 @@ use std::collections::hash_map::DefaultHasher;
|
|||
|
||||
mod arc;
|
||||
mod binary_heap;
|
||||
mod boxed;
|
||||
mod btree;
|
||||
mod cow_str;
|
||||
mod fmt;
|
||||
|
|
|
@ -90,7 +90,7 @@ impl<'a> DefCollector<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
fn visit_macro_invoc(&mut self, id: NodeId) {
|
||||
self.definitions.set_invocation_parent(id.placeholder_to_expn_id(), self.parent_def);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ pub struct Definitions {
|
|||
/// A unique identifier that we can use to lookup a definition
|
||||
/// precisely. It combines the index of the definition's parent (if
|
||||
/// any) with a `DisambiguatedDefPathData`.
|
||||
#[derive(Clone, PartialEq, Debug, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct DefKey {
|
||||
/// The parent path.
|
||||
pub parent: Option<DefIndex>,
|
||||
|
@ -162,13 +162,13 @@ impl DefKey {
|
|||
/// between them. This introduces some artificial ordering dependency
|
||||
/// but means that if you have, e.g., two impls for the same type in
|
||||
/// the same module, they do get distinct `DefId`s.
|
||||
#[derive(Clone, PartialEq, Debug, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct DisambiguatedDefPathData {
|
||||
pub data: DefPathData,
|
||||
pub disambiguator: u32
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct DefPath {
|
||||
/// The path leading from the crate root to the item.
|
||||
pub data: Vec<DisambiguatedDefPathData>,
|
||||
|
|
|
@ -414,8 +414,11 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
|
|||
rust_main_def_id: DefId,
|
||||
use_start_lang_item: bool,
|
||||
) {
|
||||
let llfty =
|
||||
cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int());
|
||||
let llfty = if cx.sess().target.target.options.main_needs_argc_argv {
|
||||
cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
|
||||
} else {
|
||||
cx.type_func(&[], cx.type_int())
|
||||
};
|
||||
|
||||
let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).output();
|
||||
// Given that `main()` has no arguments,
|
||||
|
@ -445,11 +448,19 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(cx: &'
|
|||
|
||||
bx.insert_reference_to_gdb_debug_scripts_section_global();
|
||||
|
||||
// Params from native main() used as args for rust start function
|
||||
let param_argc = bx.get_param(0);
|
||||
let param_argv = bx.get_param(1);
|
||||
let arg_argc = bx.intcast(param_argc, cx.type_isize(), true);
|
||||
let arg_argv = param_argv;
|
||||
let (arg_argc, arg_argv) = if cx.sess().target.target.options.main_needs_argc_argv {
|
||||
// Params from native main() used as args for rust start function
|
||||
let param_argc = bx.get_param(0);
|
||||
let param_argv = bx.get_param(1);
|
||||
let arg_argc = bx.intcast(param_argc, cx.type_isize(), true);
|
||||
let arg_argv = param_argv;
|
||||
(arg_argc, arg_argv)
|
||||
} else {
|
||||
// The Rust start function doesn't need argc and argv, so just pass zeros.
|
||||
let arg_argc = bx.const_int(cx.type_int(), 0);
|
||||
let arg_argv = bx.const_null(cx.type_ptr_to(cx.type_i8p()));
|
||||
(arg_argc, arg_argv)
|
||||
};
|
||||
|
||||
let (start_fn, args) = if use_start_lang_item {
|
||||
let start_def_id = cx.tcx().require_lang_item(StartFnLangItem, None);
|
||||
|
|
|
@ -14,6 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
#![feature(core_intrinsics)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(exhaustive_patterns)]
|
||||
#![feature(never_type)]
|
||||
#![feature(specialization)]
|
||||
|
|
|
@ -1024,23 +1024,12 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
new_errors.dedup();
|
||||
|
||||
if self.errors != new_errors {
|
||||
error!("old validator: {:?}", self.errors);
|
||||
error!("new validator: {:?}", new_errors);
|
||||
|
||||
// ICE on nightly if the validators do not emit exactly the same errors.
|
||||
// Users can supress this panic with an unstable compiler flag (hopefully after
|
||||
// filing an issue).
|
||||
let opts = &self.tcx.sess.opts;
|
||||
let trigger_ice = opts.unstable_features.is_nightly_build()
|
||||
&& !opts.debugging_opts.suppress_const_validation_back_compat_ice;
|
||||
|
||||
if trigger_ice {
|
||||
span_bug!(
|
||||
body.span,
|
||||
"{}",
|
||||
VALIDATOR_MISMATCH_ERR,
|
||||
);
|
||||
}
|
||||
validator_mismatch(
|
||||
self.tcx,
|
||||
body,
|
||||
std::mem::replace(&mut self.errors, vec![]),
|
||||
new_errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1870,6 +1859,58 @@ fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<FxHashSet<usize
|
|||
Some(ret)
|
||||
}
|
||||
|
||||
fn validator_mismatch(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
mut old_errors: Vec<(Span, String)>,
|
||||
mut new_errors: Vec<(Span, String)>,
|
||||
) {
|
||||
error!("old validator: {:?}", old_errors);
|
||||
error!("new validator: {:?}", new_errors);
|
||||
|
||||
// ICE on nightly if the validators do not emit exactly the same errors.
|
||||
// Users can supress this panic with an unstable compiler flag (hopefully after
|
||||
// filing an issue).
|
||||
let opts = &tcx.sess.opts;
|
||||
let strict_validation_enabled = opts.unstable_features.is_nightly_build()
|
||||
&& !opts.debugging_opts.suppress_const_validation_back_compat_ice;
|
||||
|
||||
if !strict_validation_enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this difference would cause a regression from the old to the new or vice versa, trigger
|
||||
// the ICE.
|
||||
if old_errors.is_empty() || new_errors.is_empty() {
|
||||
span_bug!(body.span, "{}", VALIDATOR_MISMATCH_ERR);
|
||||
}
|
||||
|
||||
// HACK: Borrows that would allow mutation are forbidden in const contexts, but they cause the
|
||||
// new validator to be more conservative about when a dropped local has been moved out of.
|
||||
//
|
||||
// Supress the mismatch ICE in cases where the validators disagree only on the number of
|
||||
// `LiveDrop` errors and both observe the same sequence of `MutBorrow`s.
|
||||
|
||||
let is_live_drop = |(_, s): &mut (_, String)| s.starts_with("LiveDrop");
|
||||
let is_mut_borrow = |(_, s): &&(_, String)| s.starts_with("MutBorrow");
|
||||
|
||||
let old_live_drops: Vec<_> = old_errors.drain_filter(is_live_drop).collect();
|
||||
let new_live_drops: Vec<_> = new_errors.drain_filter(is_live_drop).collect();
|
||||
|
||||
let only_live_drops_differ = old_live_drops != new_live_drops && old_errors == new_errors;
|
||||
|
||||
let old_mut_borrows = old_errors.iter().filter(is_mut_borrow);
|
||||
let new_mut_borrows = new_errors.iter().filter(is_mut_borrow);
|
||||
|
||||
let at_least_one_mut_borrow = old_mut_borrows.clone().next().is_some();
|
||||
|
||||
if only_live_drops_differ && at_least_one_mut_borrow && old_mut_borrows.eq(new_mut_borrows) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_bug!(body.span, "{}", VALIDATOR_MISMATCH_ERR);
|
||||
}
|
||||
|
||||
const VALIDATOR_MISMATCH_ERR: &str =
|
||||
r"Disagreement between legacy and dataflow-based const validators.
|
||||
After filing an issue, use `-Zsuppress-const-validation-back-compat-ice` to compile your code.";
|
||||
|
|
|
@ -880,11 +880,11 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
|
|||
self.tcx,
|
||||
self.tcx.hir().local_def_id(md.hir_id)
|
||||
).unwrap();
|
||||
let mut module_id = self.tcx.hir().as_local_hir_id(macro_module_def_id).unwrap();
|
||||
if !self.tcx.hir().is_hir_id_module(module_id) {
|
||||
// `module_id` doesn't correspond to a `mod`, return early (#63164).
|
||||
return;
|
||||
}
|
||||
let mut module_id = match self.tcx.hir().as_local_hir_id(macro_module_def_id) {
|
||||
Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id,
|
||||
// `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).
|
||||
_ => return,
|
||||
};
|
||||
let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
|
||||
let new_level = self.update(md.hir_id, level);
|
||||
if new_level.is_none() {
|
||||
|
|
|
@ -163,25 +163,15 @@ impl<'a> Resolver<'a> {
|
|||
Some(ext)
|
||||
}
|
||||
|
||||
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
|
||||
crate fn build_reduced_graph(
|
||||
&mut self,
|
||||
fragment: &AstFragment,
|
||||
extra_placeholders: &[NodeId],
|
||||
parent_scope: ParentScope<'a>,
|
||||
) -> LegacyScope<'a> {
|
||||
let mut def_collector = DefCollector::new(&mut self.definitions, parent_scope.expansion);
|
||||
fragment.visit_with(&mut def_collector);
|
||||
for placeholder in extra_placeholders {
|
||||
def_collector.visit_macro_invoc(*placeholder);
|
||||
}
|
||||
|
||||
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
|
||||
fragment.visit_with(&mut visitor);
|
||||
for placeholder in extra_placeholders {
|
||||
visitor.parent_scope.legacy = visitor.visit_invoc(*placeholder);
|
||||
}
|
||||
|
||||
visitor.parent_scope.legacy
|
||||
}
|
||||
|
||||
|
@ -1064,8 +1054,17 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
None
|
||||
}
|
||||
|
||||
// Mark the given macro as unused unless its name starts with `_`.
|
||||
// Macro uses will remove items from this set, and the remaining
|
||||
// items will be reported as `unused_macros`.
|
||||
fn insert_unused_macro(&mut self, ident: Ident, node_id: NodeId, span: Span) {
|
||||
if !ident.as_str().starts_with("_") {
|
||||
self.r.unused_macros.insert(node_id, span);
|
||||
}
|
||||
}
|
||||
|
||||
fn define_macro(&mut self, item: &ast::Item) -> LegacyScope<'a> {
|
||||
let parent_scope = &self.parent_scope;
|
||||
let parent_scope = self.parent_scope;
|
||||
let expansion = parent_scope.expansion;
|
||||
let (ext, ident, span, is_legacy) = match &item.kind {
|
||||
ItemKind::MacroDef(def) => {
|
||||
|
@ -1105,7 +1104,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
(res, vis, span, expansion, IsMacroExport));
|
||||
} else {
|
||||
self.r.check_reserved_macro_name(ident, res);
|
||||
self.r.unused_macros.insert(item.id, span);
|
||||
self.insert_unused_macro(ident, item.id, span);
|
||||
}
|
||||
LegacyScope::Binding(self.r.arenas.alloc_legacy_binding(LegacyBinding {
|
||||
parent_legacy_scope: parent_scope.legacy, binding, ident
|
||||
|
@ -1114,7 +1113,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
|||
let module = parent_scope.module;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
if vis != ty::Visibility::Public {
|
||||
self.r.unused_macros.insert(item.id, span);
|
||||
self.insert_unused_macro(ident, item.id, span);
|
||||
}
|
||||
self.r.define(module, ident, MacroNS, (res, vis, span, expansion));
|
||||
self.parent_scope.legacy
|
||||
|
|
|
@ -1013,7 +1013,8 @@ fn h1() -> i32 {
|
|||
"##,
|
||||
|
||||
E0424: r##"
|
||||
The `self` keyword was used in a static method.
|
||||
The `self` keyword was used inside of an associated function without a "`self`
|
||||
receiver" parameter.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
@ -1021,25 +1022,33 @@ Erroneous code example:
|
|||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn bar(self) {}
|
||||
// `bar` is a method, because it has a receiver parameter.
|
||||
fn bar(&self) {}
|
||||
|
||||
// `foo` is not a method, because it has no receiver parameter.
|
||||
fn foo() {
|
||||
self.bar(); // error: `self` is not available in a static method.
|
||||
self.bar(); // error: `self` value is a keyword only available in
|
||||
// methods with a `self` parameter
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Please check if the method's argument list should have contained `self`,
|
||||
`&self`, or `&mut self` (in case you didn't want to create a static
|
||||
method), and add it if so. Example:
|
||||
The `self` keyword can only be used inside methods, which are associated
|
||||
functions (functions defined inside of a `trait` or `impl` block) that have a
|
||||
`self` receiver as its first parameter, like `self`, `&self`, `&mut self` or
|
||||
`self: &mut Pin<Self>` (this last one is an example of an ["abitrary `self`
|
||||
type"](https://github.com/rust-lang/rust/issues/44874)).
|
||||
|
||||
Check if the associated function's parameter list should have contained a `self`
|
||||
receiver for it to be a method, and add it if so. Example:
|
||||
|
||||
```
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn bar(self) {}
|
||||
fn bar(&self) {}
|
||||
|
||||
fn foo(self) {
|
||||
fn foo(self) { // `foo` is now a method.
|
||||
self.bar(); // ok!
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,6 +345,9 @@ struct LateResolutionVisitor<'a, 'b> {
|
|||
/// The current self item if inside an ADT (used for better errors).
|
||||
current_self_item: Option<NodeId>,
|
||||
|
||||
/// The current enclosing funciton (used for better errors).
|
||||
current_function: Option<Span>,
|
||||
|
||||
/// A list of labels as of yet unused. Labels will be removed from this map when
|
||||
/// they are used (in a `break` or `continue` statement)
|
||||
unused_labels: FxHashMap<NodeId, Span>,
|
||||
|
@ -415,7 +418,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, _: Span, _: NodeId) {
|
||||
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, declaration: &'tcx FnDecl, sp: Span, _: NodeId) {
|
||||
let previous_value = replace(&mut self.current_function, Some(sp));
|
||||
debug!("(resolving function) entering function");
|
||||
let rib_kind = match fn_kind {
|
||||
FnKind::ItemFn(..) => FnItemRibKind,
|
||||
|
@ -441,6 +445,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LateResolutionVisitor<'a, '_> {
|
|||
debug!("(resolving function) leaving function");
|
||||
})
|
||||
});
|
||||
self.current_function = previous_value;
|
||||
}
|
||||
|
||||
fn visit_generics(&mut self, generics: &'tcx Generics) {
|
||||
|
@ -546,6 +551,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> {
|
|||
current_trait_assoc_types: Vec::new(),
|
||||
current_self_type: None,
|
||||
current_self_item: None,
|
||||
current_function: None,
|
||||
unused_labels: Default::default(),
|
||||
current_type_ascription: Vec::new(),
|
||||
}
|
||||
|
|
|
@ -115,8 +115,10 @@ impl<'a> LateResolutionVisitor<'a, '_> {
|
|||
if is_self_type(path, ns) {
|
||||
syntax::diagnostic_used!(E0411);
|
||||
err.code(DiagnosticId::Error("E0411".into()));
|
||||
err.span_label(span, format!("`Self` is only available in impls, traits, \
|
||||
and type definitions"));
|
||||
err.span_label(
|
||||
span,
|
||||
format!("`Self` is only available in impls, traits, and type definitions"),
|
||||
);
|
||||
return (err, Vec::new());
|
||||
}
|
||||
if is_self_value(path, ns) {
|
||||
|
@ -125,17 +127,16 @@ impl<'a> LateResolutionVisitor<'a, '_> {
|
|||
syntax::diagnostic_used!(E0424);
|
||||
err.code(DiagnosticId::Error("E0424".into()));
|
||||
err.span_label(span, match source {
|
||||
PathSource::Pat => {
|
||||
format!("`self` value is a keyword \
|
||||
and may not be bound to \
|
||||
variables or shadowed")
|
||||
}
|
||||
_ => {
|
||||
format!("`self` value is a keyword \
|
||||
only available in methods \
|
||||
with `self` parameter")
|
||||
}
|
||||
PathSource::Pat => format!(
|
||||
"`self` value is a keyword and may not be bound to variables or shadowed",
|
||||
),
|
||||
_ => format!(
|
||||
"`self` value is a keyword only available in methods with a `self` parameter",
|
||||
),
|
||||
});
|
||||
if let Some(span) = &self.current_function {
|
||||
err.span_label(*span, "this function doesn't have a `self` parameter");
|
||||
}
|
||||
return (err, Vec::new());
|
||||
}
|
||||
|
||||
|
|
|
@ -108,15 +108,11 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
// FIXME: `extra_placeholders` should be included into the `fragment` as regular placeholders.
|
||||
fn visit_ast_fragment_with_placeholders(
|
||||
&mut self, expansion: ExpnId, fragment: &AstFragment, extra_placeholders: &[NodeId]
|
||||
) {
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, expansion: ExpnId, fragment: &AstFragment) {
|
||||
// Integrate the new AST fragment into all the definition and module structures.
|
||||
// We are inside the `expansion` now, but other parent scope components are still the same.
|
||||
let parent_scope = ParentScope { expansion, ..self.invocation_parent_scopes[&expansion] };
|
||||
let output_legacy_scope =
|
||||
self.build_reduced_graph(fragment, extra_placeholders, parent_scope);
|
||||
let output_legacy_scope = self.build_reduced_graph(fragment, parent_scope);
|
||||
self.output_legacy_scopes.insert(expansion, output_legacy_scope);
|
||||
|
||||
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
|
||||
|
|
|
@ -691,6 +691,9 @@ pub struct TargetOptions {
|
|||
/// defined in libgcc. If this option is enabled, the target must provide
|
||||
/// `eh_unwind_resume` lang item.
|
||||
pub custom_unwind_resume: bool,
|
||||
/// Whether the runtime startup code requires the `main` function be passed
|
||||
/// `argc` and `argv` values.
|
||||
pub main_needs_argc_argv: bool,
|
||||
|
||||
/// Flag indicating whether ELF TLS (e.g., #[thread_local]) is available for
|
||||
/// this target.
|
||||
|
@ -849,6 +852,7 @@ impl Default for TargetOptions {
|
|||
link_env_remove: Vec::new(),
|
||||
archive_format: "gnu".to_string(),
|
||||
custom_unwind_resume: false,
|
||||
main_needs_argc_argv: true,
|
||||
allow_asm: true,
|
||||
has_elf_tls: false,
|
||||
obj_is_bitcode: false,
|
||||
|
@ -1159,6 +1163,7 @@ impl Target {
|
|||
key!(archive_format);
|
||||
key!(allow_asm, bool);
|
||||
key!(custom_unwind_resume, bool);
|
||||
key!(main_needs_argc_argv, bool);
|
||||
key!(has_elf_tls, bool);
|
||||
key!(obj_is_bitcode, bool);
|
||||
key!(no_integrated_as, bool);
|
||||
|
@ -1376,6 +1381,7 @@ impl ToJson for Target {
|
|||
target_option_val!(archive_format);
|
||||
target_option_val!(allow_asm);
|
||||
target_option_val!(custom_unwind_resume);
|
||||
target_option_val!(main_needs_argc_argv);
|
||||
target_option_val!(has_elf_tls);
|
||||
target_option_val!(obj_is_bitcode);
|
||||
target_option_val!(no_integrated_as);
|
||||
|
|
|
@ -101,6 +101,10 @@ pub fn target() -> Result<Target, String> {
|
|||
// without a main function.
|
||||
options.crt_static_allows_dylibs = true;
|
||||
|
||||
// WASI's `sys::args::init` function ignores its arguments; instead,
|
||||
// `args::args()` makes the WASI API calls itself.
|
||||
options.main_needs_argc_argv = false;
|
||||
|
||||
Ok(Target {
|
||||
llvm_target: "wasm32-wasi".to_string(),
|
||||
target_endian: "little".to_string(),
|
||||
|
|
|
@ -851,8 +851,7 @@ pub trait Resolver {
|
|||
fn next_node_id(&mut self) -> NodeId;
|
||||
|
||||
fn resolve_dollar_crates(&mut self);
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment,
|
||||
extra_placeholders: &[NodeId]);
|
||||
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment);
|
||||
fn register_builtin_macro(&mut self, ident: ast::Ident, ext: SyntaxExtension);
|
||||
|
||||
fn expansion_for_ast_pass(
|
||||
|
|
|
@ -26,7 +26,6 @@ use errors::{Applicability, FatalError};
|
|||
use smallvec::{smallvec, SmallVec};
|
||||
use syntax_pos::{Span, DUMMY_SP, FileName};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use std::io::ErrorKind;
|
||||
use std::{iter, mem, slice};
|
||||
|
@ -75,6 +74,22 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
|
||||
impl AstFragment {
|
||||
pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
|
||||
if placeholders.is_empty() {
|
||||
return;
|
||||
}
|
||||
match self {
|
||||
$($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
|
||||
// We are repeating through arguments with `many`, to do that we have to
|
||||
// mention some macro variable from those arguments even if it's not used.
|
||||
#[cfg_attr(bootstrap, allow(unused_macros))]
|
||||
macro _repeating($flat_map_ast_elt) {}
|
||||
placeholder(AstFragmentKind::$Kind, *id).$make_ast()
|
||||
})),)?)*
|
||||
_ => panic!("unexpected AST fragment kind")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
|
||||
match self {
|
||||
AstFragment::OptExpr(expr) => expr,
|
||||
|
@ -342,7 +357,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
// Unresolved macros produce dummy outputs as a recovery measure.
|
||||
invocations.reverse();
|
||||
let mut expanded_fragments = Vec::new();
|
||||
let mut all_derive_placeholders: FxHashMap<ExpnId, Vec<_>> = FxHashMap::default();
|
||||
let mut undetermined_invocations = Vec::new();
|
||||
let (mut progress, mut force) = (false, !self.monotonic);
|
||||
loop {
|
||||
|
@ -420,9 +434,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
self.cx.resolver.add_derives(invoc.expansion_data.id, SpecialDerives::COPY);
|
||||
}
|
||||
|
||||
let derive_placeholders =
|
||||
all_derive_placeholders.entry(invoc.expansion_data.id).or_default();
|
||||
derive_placeholders.reserve(derives.len());
|
||||
let mut derive_placeholders = Vec::with_capacity(derives.len());
|
||||
invocations.reserve(derives.len());
|
||||
for path in derives {
|
||||
let expn_id = ExpnId::fresh(None);
|
||||
|
@ -438,7 +450,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
let fragment = invoc.fragment_kind
|
||||
.expect_from_annotatables(::std::iter::once(item));
|
||||
self.collect_invocations(fragment, derive_placeholders)
|
||||
self.collect_invocations(fragment, &derive_placeholders)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -457,10 +469,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
|
||||
while let Some(expanded_fragments) = expanded_fragments.pop() {
|
||||
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
|
||||
let derive_placeholders =
|
||||
all_derive_placeholders.remove(&expn_id).unwrap_or_else(Vec::new);
|
||||
placeholder_expander.add(NodeId::placeholder_from_expn_id(expn_id),
|
||||
expanded_fragment, derive_placeholders);
|
||||
expanded_fragment);
|
||||
}
|
||||
}
|
||||
fragment_with_placeholders.mut_visit_with(&mut placeholder_expander);
|
||||
|
@ -493,13 +503,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
monotonic: self.monotonic,
|
||||
};
|
||||
fragment.mut_visit_with(&mut collector);
|
||||
fragment.add_placeholders(extra_placeholders);
|
||||
collector.invocations
|
||||
};
|
||||
|
||||
// FIXME: Merge `extra_placeholders` into the `fragment` as regular placeholders.
|
||||
if self.monotonic {
|
||||
self.cx.resolver.visit_ast_fragment_with_placeholders(
|
||||
self.cx.current_expansion.id, &fragment, extra_placeholders);
|
||||
self.cx.current_expansion.id, &fragment
|
||||
);
|
||||
}
|
||||
|
||||
(fragment, invocations)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(proc_macro_diagnostic)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(proc_macro_span)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::base::ExtCtxt;
|
||||
use crate::expand::{AstFragment, AstFragmentKind};
|
||||
|
||||
use syntax::ast::{self, NodeId};
|
||||
use syntax::ast;
|
||||
use syntax::source_map::{DUMMY_SP, dummy_spanned};
|
||||
use syntax::tokenstream::TokenStream;
|
||||
use syntax::mut_visit::*;
|
||||
|
@ -171,17 +171,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment, placeholders: Vec<NodeId>) {
|
||||
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) {
|
||||
fragment.mut_visit_with(self);
|
||||
if let AstFragment::Items(mut items) = fragment {
|
||||
for placeholder in placeholders {
|
||||
match self.remove(placeholder) {
|
||||
AstFragment::Items(derived_items) => items.extend(derived_items),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fragment = AstFragment::Items(items);
|
||||
}
|
||||
self.expanded_fragments.insert(id, fragment);
|
||||
}
|
||||
|
||||
|
|
|
@ -174,14 +174,12 @@ fn cs_clone(name: &str,
|
|||
all_fields = af;
|
||||
vdata = &variant.data;
|
||||
}
|
||||
EnumNonMatchingCollapsed(..) => {
|
||||
cx.span_bug(trait_span,
|
||||
&format!("non-matching enum variants in \
|
||||
`derive({})`",
|
||||
name))
|
||||
}
|
||||
EnumNonMatchingCollapsed(..) => cx.span_bug(trait_span, &format!(
|
||||
"non-matching enum variants in `derive({})`",
|
||||
name,
|
||||
)),
|
||||
StaticEnum(..) | StaticStruct(..) => {
|
||||
cx.span_bug(trait_span, &format!("static method in `derive({})`", name))
|
||||
cx.span_bug(trait_span, &format!("associated function in `derive({})`", name))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,12 +189,10 @@ fn cs_clone(name: &str,
|
|||
.map(|field| {
|
||||
let ident = match field.name {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
cx.span_bug(trait_span,
|
||||
&format!("unnamed field in normal struct in \
|
||||
`derive({})`",
|
||||
name))
|
||||
}
|
||||
None => cx.span_bug(trait_span, &format!(
|
||||
"unnamed field in normal struct in `derive({})`",
|
||||
name,
|
||||
)),
|
||||
};
|
||||
let call = subcall(cx, field);
|
||||
cx.field_imm(field.span, ident, call)
|
||||
|
|
|
@ -75,6 +75,6 @@ fn default_substructure(cx: &mut ExtCtxt<'_>,
|
|||
// let compilation continue
|
||||
DummyResult::raw_expr(trait_span, true)
|
||||
}
|
||||
_ => cx.span_bug(trait_span, "Non-static method in `derive(Default)`"),
|
||||
_ => cx.span_bug(trait_span, "method in `derive(Default)`"),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1055,9 +1055,7 @@ impl<'a> MethodDef<'a> {
|
|||
})
|
||||
.collect()
|
||||
} else {
|
||||
cx.span_bug(trait_.span,
|
||||
"no self arguments to non-static method in generic \
|
||||
`derive`")
|
||||
cx.span_bug(trait_.span, "no `self` parameter for method in generic `derive`")
|
||||
};
|
||||
|
||||
// body of the inner most destructuring match
|
||||
|
|
|
@ -934,19 +934,19 @@ impl Symbol {
|
|||
|
||||
impl fmt::Debug for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(self, f)
|
||||
self.with(|str| fmt::Debug::fmt(&str, f))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.as_str(), f)
|
||||
self.with(|str| fmt::Display::fmt(&str, f))
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Symbol {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_str(&self.as_str())
|
||||
self.with(|string| s.emit_str(string))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1106,8 +1106,8 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
|
|||
}
|
||||
|
||||
/// An alternative to `Symbol` and `InternedString`, useful when the chars
|
||||
/// within the symbol need to be accessed. It is best used for temporary
|
||||
/// values.
|
||||
/// within the symbol need to be accessed. It deliberately has limited
|
||||
/// functionality and should only be used for temporary values.
|
||||
///
|
||||
/// Because the interner outlives any thread which uses this type, we can
|
||||
/// safely treat `string` which points to interner data, as an immortal string,
|
||||
|
@ -1116,7 +1116,7 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
|
|||
// FIXME: ensure that the interner outlives any thread which uses
|
||||
// `LocalInternedString`, by creating a new thread right after constructing the
|
||||
// interner.
|
||||
#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
|
||||
#[derive(Eq, PartialOrd, Ord)]
|
||||
pub struct LocalInternedString {
|
||||
string: &'static str,
|
||||
}
|
||||
|
|
9
src/test/rustdoc/macro-in-closure.rs
Normal file
9
src/test/rustdoc/macro-in-closure.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// Regression issue for rustdoc ICE encountered in PR #65252.
|
||||
|
||||
#![feature(decl_macro)]
|
||||
|
||||
fn main() {
|
||||
|| {
|
||||
macro m() {}
|
||||
};
|
||||
}
|
13
src/test/ui/consts/const-eval/issue-65394.rs
Normal file
13
src/test/ui/consts/const-eval/issue-65394.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Test for absence of validation mismatch ICE in #65394
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_mir(borrowck_graphviz_postflow="hello.dot")]
|
||||
const _: Vec<i32> = {
|
||||
let mut x = Vec::<i32>::new();
|
||||
let r = &mut x; //~ ERROR references in constants may only refer to immutable values
|
||||
let y = x;
|
||||
y
|
||||
};
|
||||
|
||||
fn main() {}
|
11
src/test/ui/consts/const-eval/issue-65394.stderr
Normal file
11
src/test/ui/consts/const-eval/issue-65394.stderr
Normal file
|
@ -0,0 +1,11 @@
|
|||
error[E0017]: references in constants may only refer to immutable values
|
||||
--> $DIR/issue-65394.rs:8:13
|
||||
|
|
||||
LL | let r = &mut x;
|
||||
| ^^^^^^ constants require immutable values
|
||||
|
||||
[ERROR rustc_mir::transform::qualify_consts] old validator: [($DIR/issue-65394.rs:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })")]
|
||||
[ERROR rustc_mir::transform::qualify_consts] new validator: [($DIR/issue-65394.rs:8:13: 8:19, "MutBorrow(Mut { allow_two_phase_borrow: false })"), ($DIR/issue-65394.rs:7:9: 7:14, "LiveDrop")]
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0017`.
|
|
@ -1,14 +1,20 @@
|
|||
error[E0424]: expected value, found module `self`
|
||||
--> $DIR/E0424.rs:7:9
|
||||
|
|
||||
LL | self.bar();
|
||||
| ^^^^ `self` value is a keyword only available in methods with `self` parameter
|
||||
LL | / fn foo() {
|
||||
LL | | self.bar();
|
||||
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||
LL | | }
|
||||
| |_____- this function doesn't have a `self` parameter
|
||||
|
||||
error[E0424]: expected unit struct/variant or constant, found module `self`
|
||||
--> $DIR/E0424.rs:12:9
|
||||
|
|
||||
LL | let self = "self";
|
||||
| ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
|
||||
LL | / fn main () {
|
||||
LL | | let self = "self";
|
||||
| | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed
|
||||
LL | | }
|
||||
| |_- this function doesn't have a `self` parameter
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ fn y /* 0#0 */() { }
|
|||
/*
|
||||
Expansions:
|
||||
0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root
|
||||
1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, foo)
|
||||
1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, "foo")
|
||||
|
||||
SyntaxContexts:
|
||||
#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
TokenStream [Ident { ident: "fn", span: #0 bytes(197..199) }, Ident { ident: "span_preservation", span: #0 bytes(200..217) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(217..219) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(227..230) }, Ident { ident: "tst", span: #0 bytes(231..234) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(235..236) }, Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(237), hi: BytePos(240), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(240..241) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(241..242) }, Ident { ident: "match", span: #0 bytes(288..293) }, Ident { ident: "tst", span: #0 bytes(294..297) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: 123, suffix: None }, span: Span { lo: BytePos(482), hi: BytePos(485), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(486..488) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(486..488) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(489..491) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(491..492) }, Ident { ident: "_", span: #0 bytes(501..502) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(503..505) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(503..505) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(506..508) }], span: #0 bytes(298..514) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(514..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(516..517) }], span: #0 bytes(221..561) }]
|
||||
TokenStream [Ident { ident: "fn", span: #0 bytes(197..199) }, Ident { ident: "span_preservation", span: #0 bytes(200..217) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(217..219) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "let", span: #0 bytes(227..230) }, Ident { ident: "tst", span: #0 bytes(231..234) }, Punct { ch: '=', spacing: Alone, span: #0 bytes(235..236) }, Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(237), hi: BytePos(240), ctxt: #0 } }, Punct { ch: ';', spacing: Joint, span: #0 bytes(240..241) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(241..242) }, Ident { ident: "match", span: #0 bytes(288..293) }, Ident { ident: "tst", span: #0 bytes(294..297) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: Lit { kind: Integer, symbol: "123", suffix: None }, span: Span { lo: BytePos(482), hi: BytePos(485), ctxt: #0 } }, Punct { ch: '=', spacing: Joint, span: #0 bytes(486..488) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(486..488) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(489..491) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(491..492) }, Ident { ident: "_", span: #0 bytes(501..502) }, Punct { ch: '=', spacing: Joint, span: #0 bytes(503..505) }, Punct { ch: '>', spacing: Alone, span: #0 bytes(503..505) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #0 bytes(506..508) }], span: #0 bytes(298..514) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(514..515) }, Punct { ch: ';', spacing: Joint, span: #0 bytes(515..516) }, Punct { ch: ';', spacing: Alone, span: #0 bytes(516..517) }], span: #0 bytes(221..561) }]
|
||||
error: unnecessary trailing semicolon
|
||||
--> $DIR/redundant-semi-proc-macro.rs:9:19
|
||||
|
|
||||
|
|
|
@ -61,8 +61,14 @@ LL | purr();
|
|||
error[E0424]: expected value, found module `self`
|
||||
--> $DIR/issue-2356.rs:65:8
|
||||
|
|
||||
LL | if self.whiskers > 3 {
|
||||
| ^^^^ `self` value is a keyword only available in methods with `self` parameter
|
||||
LL | / fn meow() {
|
||||
LL | | if self.whiskers > 3 {
|
||||
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||
LL | |
|
||||
LL | | println!("MEOW");
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |___- this function doesn't have a `self` parameter
|
||||
|
||||
error[E0425]: cannot find function `grow_older` in this scope
|
||||
--> $DIR/issue-2356.rs:72:5
|
||||
|
@ -97,8 +103,12 @@ LL | purr_louder();
|
|||
error[E0424]: expected value, found module `self`
|
||||
--> $DIR/issue-2356.rs:92:5
|
||||
|
|
||||
LL | self += 1;
|
||||
| ^^^^ `self` value is a keyword only available in methods with `self` parameter
|
||||
LL | / fn main() {
|
||||
LL | | self += 1;
|
||||
| | ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_- this function doesn't have a `self` parameter
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue