diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 4489a424c0d50..11afd359e5ad3 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -710,6 +710,12 @@ impl Pat {
}
}
+impl From
> for Pat {
+ fn from(value: P) -> Self {
+ *value
+ }
+}
+
/// A single field in a struct pattern.
///
/// Patterns like the fields of `Foo { x, ref y, ref mut z }`
@@ -1553,17 +1559,23 @@ impl Expr {
)
}
- /// Creates a dummy `P`.
+ /// Creates a dummy `Expr`.
///
/// Should only be used when it will be replaced afterwards or as a return value when an error was encountered.
- pub fn dummy() -> P {
- P(Expr {
+ pub fn dummy() -> Expr {
+ Expr {
id: DUMMY_NODE_ID,
kind: ExprKind::Dummy,
span: DUMMY_SP,
attrs: ThinVec::new(),
tokens: None,
- })
+ }
+ }
+}
+
+impl From> for Expr {
+ fn from(value: P) -> Self {
+ *value
}
}
@@ -2374,6 +2386,12 @@ impl Clone for Ty {
}
}
+impl From> for Ty {
+ fn from(value: P) -> Self {
+ *value
+ }
+}
+
impl Ty {
pub fn peel_refs(&self) -> &Self {
let mut final_ty = self;
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 71a47dcfcba2b..07fbe8045fc2f 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -168,7 +168,7 @@ pub trait MutVisitor: Sized + MutVisitorResult {
walk_flat_map_arm(self, arm)
}
- fn visit_pat(&mut self, p: &mut P) {
+ fn visit_pat(&mut self, p: &mut Pat) {
walk_pat(self, p);
}
@@ -176,7 +176,7 @@ pub trait MutVisitor: Sized + MutVisitorResult {
walk_anon_const(self, c);
}
- fn visit_expr(&mut self, e: &mut P) {
+ fn visit_expr(&mut self, e: &mut Expr) {
walk_expr(self, e);
}
@@ -194,7 +194,7 @@ pub trait MutVisitor: Sized + MutVisitorResult {
walk_generic_arg(self, arg);
}
- fn visit_ty(&mut self, t: &mut P) {
+ fn visit_ty(&mut self, t: &mut Ty) {
walk_ty(self, t);
}
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 5ef76fb64aaf2..50eb7c7ae99bd 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -179,6 +179,8 @@ ast_lowering_underscore_expr_lhs_assign =
in expressions, `_` can only be used on the left-hand side of an assignment
.label = `_` not allowed here
+ast_lowering_union_default_field_values = unions cannot have default field values
+
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
using both label and output operands for inline assembly is unstable
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 576fa9731e906..b444324ef9143 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -475,3 +475,10 @@ pub(crate) struct UseConstGenericArg {
#[suggestion_part(code = "{other_args}")]
pub call_args: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(ast_lowering_union_default_field_values)]
+pub(crate) struct UnionWithDefault {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 49110c93954ad..ef27d0ef69b14 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -17,6 +17,7 @@ use tracing::instrument;
use super::errors::{
InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
+ UnionWithDefault,
};
use super::stability::{enabled_names, gate_unstable_abi};
use super::{
@@ -316,7 +317,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
this.arena.alloc_from_iter(
- enum_definition.variants.iter().map(|x| this.lower_variant(x)),
+ enum_definition.variants.iter().map(|x| this.lower_variant(i, x)),
)
},
);
@@ -328,7 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
generics,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- |this| this.lower_variant_data(hir_id, struct_def),
+ |this| this.lower_variant_data(hir_id, i, struct_def),
);
hir::ItemKind::Struct(ident, generics, struct_def)
}
@@ -338,7 +339,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
generics,
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
- |this| this.lower_variant_data(hir_id, vdata),
+ |this| this.lower_variant_data(hir_id, i, vdata),
);
hir::ItemKind::Union(ident, generics, vdata)
}
@@ -714,13 +715,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
- fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> {
+ fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> {
let hir_id = self.lower_node_id(v.id);
self.lower_attrs(hir_id, &v.attrs, v.span);
hir::Variant {
hir_id,
def_id: self.local_def_id(v.id),
- data: self.lower_variant_data(hir_id, &v.data),
+ data: self.lower_variant_data(hir_id, item_kind, &v.data),
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
ident: self.lower_ident(v.ident),
span: self.lower_span(v.span),
@@ -730,15 +731,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn lower_variant_data(
&mut self,
parent_id: hir::HirId,
+ item_kind: &ItemKind,
vdata: &VariantData,
) -> hir::VariantData<'hir> {
match vdata {
- VariantData::Struct { fields, recovered } => hir::VariantData::Struct {
- fields: self
+ VariantData::Struct { fields, recovered } => {
+ let fields = self
.arena
- .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
- recovered: *recovered,
- },
+ .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
+
+ if let ItemKind::Union(..) = item_kind {
+ for field in &fields[..] {
+ if let Some(default) = field.default {
+ // Unions cannot derive `Default`, and it's not clear how to use default
+ // field values of unions if that was supported. Therefore, blanket reject
+ // trying to use field values with unions.
+ if self.tcx.features().default_field_values() {
+ self.dcx().emit_err(UnionWithDefault { span: default.span });
+ } else {
+ let _ = self.dcx().span_delayed_bug(
+ default.span,
+ "expected union default field values feature gate error but none \
+ was produced",
+ );
+ }
+ }
+ }
+ }
+
+ hir::VariantData::Struct { fields, recovered: *recovered }
+ }
VariantData::Tuple(fields, id) => {
let ctor_id = self.lower_node_id(*id);
self.alias_attrs(ctor_id, parent_id);
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index c4b0f503664ee..095c0df98acc1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -342,10 +342,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
}
}
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
- let sp = info
- .span
- .find_ancestor_in_same_ctxt(local_decl.source_info.span)
- .unwrap_or(info.span);
+ let sp = info.span.find_oldest_ancestor_in_same_ctxt();
if info.tail_result_is_ignored {
// #85581: If the first mutable borrow's scope contains
// the second borrow, this suggestion isn't helpful.
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index da01e3e9607bb..fe44350863c9a 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -155,7 +155,7 @@ impl CfgEval<'_> {
impl MutVisitor for CfgEval<'_> {
#[instrument(level = "trace", skip(self))]
- fn visit_expr(&mut self, expr: &mut P) {
+ fn visit_expr(&mut self, expr: &mut ast::Expr) {
self.0.configure_expr(expr, false);
mut_visit::walk_expr(self, expr);
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 0794192621a93..3a20b39798d7b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -1,5 +1,4 @@
use ast::HasAttrs;
-use ast::ptr::P;
use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::visit::BoundKind;
use rustc_ast::{
@@ -378,11 +377,11 @@ struct TypeSubstitution<'a> {
}
impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
- fn visit_ty(&mut self, ty: &mut P) {
+ fn visit_ty(&mut self, ty: &mut ast::Ty) {
if let Some(name) = ty.kind.is_simple_path()
&& name == self.from_name
{
- **ty = self.to_ty.clone();
+ *ty = self.to_ty.clone();
self.rewritten = true;
} else {
ast::mut_visit::walk_ty(self, ty);
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 3cfeb01ea4771..9fd524ef45cd0 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1768,7 +1768,7 @@ impl InvocationCollectorNode for ast::Crate {
}
}
-impl InvocationCollectorNode for P {
+impl InvocationCollectorNode for ast::Ty {
type OutputTy = P;
const KIND: AstFragmentKind = AstFragmentKind::Ty;
fn to_annotatable(self) -> Annotatable {
@@ -1791,7 +1791,7 @@ impl InvocationCollectorNode for P {
}
}
-impl InvocationCollectorNode for P {
+impl InvocationCollectorNode for ast::Pat {
type OutputTy = P;
const KIND: AstFragmentKind = AstFragmentKind::Pat;
fn to_annotatable(self) -> Annotatable {
@@ -1814,11 +1814,11 @@ impl InvocationCollectorNode for P {
}
}
-impl InvocationCollectorNode for P {
+impl InvocationCollectorNode for ast::Expr {
type OutputTy = P;
const KIND: AstFragmentKind = AstFragmentKind::Expr;
fn to_annotatable(self) -> Annotatable {
- Annotatable::Expr(self)
+ Annotatable::Expr(P(self))
}
fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
fragment.make_expr()
@@ -1955,29 +1955,29 @@ impl DummyAstNode for ast::Crate {
}
}
-impl DummyAstNode for P {
+impl DummyAstNode for ast::Ty {
fn dummy() -> Self {
- P(ast::Ty {
+ ast::Ty {
id: DUMMY_NODE_ID,
kind: TyKind::Dummy,
span: Default::default(),
tokens: Default::default(),
- })
+ }
}
}
-impl DummyAstNode for P {
+impl DummyAstNode for ast::Pat {
fn dummy() -> Self {
- P(ast::Pat {
+ ast::Pat {
id: DUMMY_NODE_ID,
kind: PatKind::Wild,
span: Default::default(),
tokens: Default::default(),
- })
+ }
}
}
-impl DummyAstNode for P {
+impl DummyAstNode for ast::Expr {
fn dummy() -> Self {
ast::Expr::dummy()
}
@@ -1985,7 +1985,7 @@ impl DummyAstNode for P {
impl DummyAstNode for AstNodeWrapper, MethodReceiverTag> {
fn dummy() -> Self {
- AstNodeWrapper::new(ast::Expr::dummy(), MethodReceiverTag)
+ AstNodeWrapper::new(P(ast::Expr::dummy()), MethodReceiverTag)
}
}
@@ -2272,7 +2272,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
}
}
- fn visit_node + DummyAstNode>(
+ fn visit_node> + DummyAstNode>(
&mut self,
node: &mut Node,
) {
@@ -2297,6 +2297,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
*node = self
.collect_attr((attr, pos, derives), n.to_annotatable(), Node::KIND)
.make_ast::()
+ .into()
}
},
None if node.is_mac_call() => {
@@ -2304,7 +2305,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
let (mac, attrs, _) = n.take_mac_call();
self.check_attributes(&attrs, &mac);
- *node = self.collect_bang(mac, Node::KIND).make_ast::()
+ *node = self.collect_bang(mac, Node::KIND).make_ast::().into()
}
None if node.delegation().is_some() => unreachable!(),
None => {
@@ -2414,15 +2415,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
self.visit_node(node)
}
- fn visit_ty(&mut self, node: &mut P) {
+ fn visit_ty(&mut self, node: &mut ast::Ty) {
self.visit_node(node)
}
- fn visit_pat(&mut self, node: &mut P) {
+ fn visit_pat(&mut self, node: &mut ast::Pat) {
self.visit_node(node)
}
- fn visit_expr(&mut self, node: &mut P) {
+ fn visit_expr(&mut self, node: &mut ast::Expr) {
// FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`.
if let Some(attr) = node.attrs.first() {
self.cfg().maybe_emit_expr_attr_err(attr);
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 3dcb20c8c7682..2c486a02bdf18 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -332,9 +332,9 @@ impl MutVisitor for PlaceholderExpander {
}
}
- fn visit_expr(&mut self, expr: &mut P) {
+ fn visit_expr(&mut self, expr: &mut ast::Expr) {
match expr.kind {
- ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(),
+ ast::ExprKind::MacCall(_) => *expr = *self.remove(expr.id).make_expr(),
_ => walk_expr(self, expr),
}
}
@@ -399,16 +399,16 @@ impl MutVisitor for PlaceholderExpander {
stmts
}
- fn visit_pat(&mut self, pat: &mut P) {
+ fn visit_pat(&mut self, pat: &mut ast::Pat) {
match pat.kind {
- ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(),
+ ast::PatKind::MacCall(_) => *pat = *self.remove(pat.id).make_pat(),
_ => walk_pat(self, pat),
}
}
- fn visit_ty(&mut self, ty: &mut P) {
+ fn visit_ty(&mut self, ty: &mut ast::Ty) {
match ty.kind {
- ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(),
+ ast::TyKind::MacCall(_) => *ty = *self.remove(ty.id).make_ty(),
_ => walk_ty(self, ty),
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 1953eef81700b..0bc980b4d9f8f 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1,7 +1,7 @@
// Decoding metadata from a single crate's metadata
use std::iter::TrustedLen;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::sync::{Arc, OnceLock};
use std::{io, iter, mem};
@@ -1610,10 +1610,14 @@ impl<'a> CrateMetadataRef<'a> {
/// Proc macro crates don't currently export spans, so this function does not have
/// to work for them.
fn imported_source_file(self, source_file_index: u32, sess: &Session) -> ImportedSourceFile {
- fn filter<'a>(sess: &Session, path: Option<&'a Path>) -> Option<&'a Path> {
+ fn filter<'a>(
+ sess: &Session,
+ real_source_base_dir: &Option,
+ path: Option<&'a Path>,
+ ) -> Option<&'a Path> {
path.filter(|_| {
// Only spend time on further checks if we have what to translate *to*.
- sess.opts.real_rust_source_base_dir.is_some()
+ real_source_base_dir.is_some()
// Some tests need the translation to be always skipped.
&& sess.opts.unstable_opts.translate_remapped_path_to_local_path
})
@@ -1625,57 +1629,92 @@ impl<'a> CrateMetadataRef<'a> {
})
}
- let try_to_translate_virtual_to_real = |name: &mut rustc_span::FileName| {
- // Translate the virtual `/rustc/$hash` prefix back to a real directory
- // that should hold actual sources, where possible.
- //
- // NOTE: if you update this, you might need to also update bootstrap's code for generating
- // the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`.
- let virtual_rust_source_base_dir = [
- filter(sess, option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").map(Path::new)),
- filter(sess, sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref()),
- ];
+ let try_to_translate_virtual_to_real =
+ |virtual_source_base_dir: Option<&str>,
+ real_source_base_dir: &Option,
+ name: &mut rustc_span::FileName| {
+ let virtual_source_base_dir = [
+ filter(sess, real_source_base_dir, virtual_source_base_dir.map(Path::new)),
+ filter(
+ sess,
+ real_source_base_dir,
+ sess.opts.unstable_opts.simulate_remapped_rust_src_base.as_deref(),
+ ),
+ ];
- debug!(
- "try_to_translate_virtual_to_real(name={:?}): \
- virtual_rust_source_base_dir={:?}, real_rust_source_base_dir={:?}",
- name, virtual_rust_source_base_dir, sess.opts.real_rust_source_base_dir,
- );
+ debug!(
+ "try_to_translate_virtual_to_real(name={:?}): \
+ virtual_source_base_dir={:?}, real_source_base_dir={:?}",
+ name, virtual_source_base_dir, real_source_base_dir,
+ );
- for virtual_dir in virtual_rust_source_base_dir.iter().flatten() {
- if let Some(real_dir) = &sess.opts.real_rust_source_base_dir
+ for virtual_dir in virtual_source_base_dir.iter().flatten() {
+ if let Some(real_dir) = &real_source_base_dir
+ && let rustc_span::FileName::Real(old_name) = name
+ && let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
+ old_name
+ && let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
+ {
+ let new_path = real_dir.join(rest);
+
+ debug!(
+ "try_to_translate_virtual_to_real: `{}` -> `{}`",
+ virtual_name.display(),
+ new_path.display(),
+ );
+
+ // Check if the translated real path is affected by any user-requested
+ // remaps via --remap-path-prefix. Apply them if so.
+ // Note that this is a special case for imported rust-src paths specified by
+ // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths.
+ // Other imported paths are not currently remapped (see #66251).
+ let (user_remapped, applied) =
+ sess.source_map().path_mapping().map_prefix(&new_path);
+ let new_name = if applied {
+ rustc_span::RealFileName::Remapped {
+ local_path: Some(new_path.clone()),
+ virtual_name: user_remapped.to_path_buf(),
+ }
+ } else {
+ rustc_span::RealFileName::LocalPath(new_path)
+ };
+ *old_name = new_name;
+ }
+ }
+ };
+
+ let try_to_translate_real_to_virtual =
+ |virtual_source_base_dir: Option<&str>,
+ real_source_base_dir: &Option,
+ subdir: &str,
+ name: &mut rustc_span::FileName| {
+ if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base
+ && let Some(real_dir) = real_source_base_dir
&& let rustc_span::FileName::Real(old_name) = name
- && let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } =
- old_name
- && let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
{
- let new_path = real_dir.join(rest);
-
- debug!(
- "try_to_translate_virtual_to_real: `{}` -> `{}`",
- virtual_name.display(),
- new_path.display(),
- );
-
- // Check if the translated real path is affected by any user-requested
- // remaps via --remap-path-prefix. Apply them if so.
- // Note that this is a special case for imported rust-src paths specified by
- // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths.
- // Other imported paths are not currently remapped (see #66251).
- let (user_remapped, applied) =
- sess.source_map().path_mapping().map_prefix(&new_path);
- let new_name = if applied {
- rustc_span::RealFileName::Remapped {
- local_path: Some(new_path.clone()),
- virtual_name: user_remapped.to_path_buf(),
+ let relative_path = match old_name {
+ rustc_span::RealFileName::LocalPath(local) => {
+ local.strip_prefix(real_dir).ok()
+ }
+ rustc_span::RealFileName::Remapped { virtual_name, .. } => {
+ virtual_source_base_dir
+ .and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok())
}
- } else {
- rustc_span::RealFileName::LocalPath(new_path)
};
- *old_name = new_name;
+ debug!(
+ ?relative_path,
+ ?virtual_dir,
+ ?subdir,
+ "simulate_remapped_rust_src_base"
+ );
+ if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) {
+ *old_name = rustc_span::RealFileName::Remapped {
+ local_path: None,
+ virtual_name: virtual_dir.join(subdir).join(rest),
+ };
+ }
}
- }
- };
+ };
let mut import_info = self.cdata.source_map_import_info.lock();
for _ in import_info.len()..=(source_file_index as usize) {
@@ -1713,36 +1752,45 @@ impl<'a> CrateMetadataRef<'a> {
// This is useful for testing so that tests about the effects of
// `try_to_translate_virtual_to_real` don't have to worry about how the
// compiler is bootstrapped.
- if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base
- && let Some(real_dir) = &sess.opts.real_rust_source_base_dir
- && let rustc_span::FileName::Real(ref mut old_name) = name
- {
- let relative_path = match old_name {
- rustc_span::RealFileName::LocalPath(local) => {
- local.strip_prefix(real_dir).ok()
- }
- rustc_span::RealFileName::Remapped { virtual_name, .. } => {
- option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR")
- .and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok())
- }
- };
- debug!(?relative_path, ?virtual_dir, "simulate_remapped_rust_src_base");
- for subdir in ["library", "compiler"] {
- if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok())
- {
- *old_name = rustc_span::RealFileName::Remapped {
- local_path: None, // FIXME: maybe we should preserve this?
- virtual_name: virtual_dir.join(subdir).join(rest),
- };
- break;
- }
- }
- }
+ try_to_translate_real_to_virtual(
+ option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR"),
+ &sess.opts.real_rust_source_base_dir,
+ "library",
+ &mut name,
+ );
+
+ // If this file is under $sysroot/lib/rustlib/rustc-src/
+ // and the user wish to simulate remapping with -Z simulate-remapped-rust-src-base,
+ // then we change `name` to a similar state as if the rust was bootstrapped
+ // with `remap-debuginfo = true`.
+ try_to_translate_real_to_virtual(
+ option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"),
+ &sess.opts.real_rustc_dev_source_base_dir,
+ "compiler",
+ &mut name,
+ );
// If this file's path has been remapped to `/rustc/$hash`,
- // we might be able to reverse that (also see comments above,
- // on `try_to_translate_virtual_to_real`).
- try_to_translate_virtual_to_real(&mut name);
+ // we might be able to reverse that.
+ //
+ // NOTE: if you update this, you might need to also update bootstrap's code for generating
+ // the `rust-src` component in `Src::run` in `src/bootstrap/dist.rs`.
+ try_to_translate_virtual_to_real(
+ option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR"),
+ &sess.opts.real_rust_source_base_dir,
+ &mut name,
+ );
+
+ // If this file's path has been remapped to `/rustc-dev/$hash`,
+ // we might be able to reverse that.
+ //
+ // NOTE: if you update this, you might need to also update bootstrap's code for generating
+ // the `rustc-dev` component in `Src::run` in `src/bootstrap/dist.rs`.
+ try_to_translate_virtual_to_real(
+ option_env!("CFG_VIRTUAL_RUSTC_DEV_SOURCE_BASE_DIR"),
+ &sess.opts.real_rustc_dev_source_base_dir,
+ &mut name,
+ );
let local_version = sess.source_map().new_imported_source_file(
name,
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 8f88228d9bbd8..a54e548ad70ab 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -74,7 +74,11 @@ impl SimplifyCfg {
}
pub(super) fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- CfgSimplifier::new(tcx, body).simplify();
+ if CfgSimplifier::new(tcx, body).simplify() {
+ // `simplify` returns that it changed something. We must invalidate the CFG caches as they
+ // are not consistent with the modified CFG any more.
+ body.basic_blocks.invalidate_cfg_cache();
+ }
remove_dead_blocks(body);
// FIXME: Should probably be moved into some kind of pass manager
@@ -121,12 +125,16 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
// Preserve `SwitchInt` reads on built and analysis MIR, or if `-Zmir-preserve-ub`.
let preserve_switch_reads = matches!(body.phase, MirPhase::Built | MirPhase::Analysis(_))
|| tcx.sess.opts.unstable_opts.mir_preserve_ub;
- let basic_blocks = body.basic_blocks_mut();
+ // Do not clear caches yet. The caller to `simplify` will do it if anything changed.
+ let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
CfgSimplifier { preserve_switch_reads, basic_blocks, pred_count }
}
- fn simplify(mut self) {
+ /// Returns whether we actually simplified anything. In that case, the caller *must* invalidate
+ /// the CFG caches of the MIR body.
+ #[must_use]
+ fn simplify(mut self) -> bool {
self.strip_nops();
// Vec of the blocks that should be merged. We store the indices here, instead of the
@@ -134,6 +142,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
// We do not push the statements directly into the target block (`bb`) as that is slower
// due to additional reallocations
let mut merged_blocks = Vec::new();
+ let mut outer_changed = false;
loop {
let mut changed = false;
@@ -177,7 +186,11 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
if !changed {
break;
}
+
+ outer_changed = true;
}
+
+ outer_changed
}
/// This function will return `None` if
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 93489aa8ee948..93c76c47f060b 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -4087,7 +4087,7 @@ impl<'a> CondChecker<'a> {
}
impl MutVisitor for CondChecker<'_> {
- fn visit_expr(&mut self, e: &mut P) {
+ fn visit_expr(&mut self, e: &mut Expr) {
self.depth += 1;
use ForbiddenLetReason::*;
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 7a226136e2353..64653ee2a04c9 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1094,7 +1094,7 @@ impl<'a> Parser<'a> {
fn make_all_value_bindings_mutable(pat: &mut P) -> bool {
struct AddMut(bool);
impl MutVisitor for AddMut {
- fn visit_pat(&mut self, pat: &mut P) {
+ fn visit_pat(&mut self, pat: &mut Pat) {
if let PatKind::Ident(BindingMode(ByRef::No, m @ Mutability::Not), ..) =
&mut pat.kind
{
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 406a6bd335a74..b7fb5b690f033 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1364,6 +1364,7 @@ impl Default for Options {
cli_forced_local_thinlto_off: false,
remap_path_prefix: Vec::new(),
real_rust_source_base_dir: None,
+ real_rustc_dev_source_base_dir: None,
edition: DEFAULT_EDITION,
json_artifact_notifications: false,
json_unused_externs: JsonUnusedExterns::No,
@@ -2701,9 +2702,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let sysroot = filesearch::materialize_sysroot(sysroot_opt);
- let real_rust_source_base_dir = {
- // This is the location used by the `rust-src` `rustup` component.
- let mut candidate = sysroot.join("lib/rustlib/src/rust");
+ let real_source_base_dir = |suffix: &str, confirm: &str| {
+ let mut candidate = sysroot.join(suffix);
if let Ok(metadata) = candidate.symlink_metadata() {
// Replace the symlink bootstrap creates, with its destination.
// We could try to use `fs::canonicalize` instead, but that might
@@ -2716,9 +2716,17 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
}
// Only use this directory if it has a file we can expect to always find.
- candidate.join("library/std/src/lib.rs").is_file().then_some(candidate)
+ candidate.join(confirm).is_file().then_some(candidate)
};
+ let real_rust_source_base_dir =
+ // This is the location used by the `rust-src` `rustup` component.
+ real_source_base_dir("lib/rustlib/src/rust", "library/std/src/lib.rs");
+
+ let real_rustc_dev_source_base_dir =
+ // This is the location used by the `rustc-dev` `rustup` component.
+ real_source_base_dir("lib/rustlib/rustc-src/rust", "compiler/rustc/src/main.rs");
+
let mut search_paths = vec![];
for s in &matches.opt_strs("L") {
search_paths.push(SearchPath::from_cli_opt(
@@ -2772,6 +2780,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
cli_forced_local_thinlto_off: disable_local_thinlto,
remap_path_prefix,
real_rust_source_base_dir,
+ real_rustc_dev_source_base_dir,
edition,
json_artifact_notifications,
json_unused_externs,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f76f258d00de9..65c09cd72fbb5 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -395,15 +395,25 @@ top_level_options!(
/// Remap source path prefixes in all output (messages, object files, debug, etc.).
remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
- /// Base directory containing the `src/` for the Rust standard library, and
- /// potentially `rustc` as well, if we can find it. Right now it's always
- /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component).
+
+ /// Base directory containing the `library/` directory for the Rust standard library.
+ /// Right now it's always `$sysroot/lib/rustlib/src/rust`
+ /// (i.e. the `rustup` `rust-src` component).
///
/// This directory is what the virtual `/rustc/$hash` is translated back to,
/// if Rust was built with path remapping to `/rustc/$hash` enabled
/// (the `rust.remap-debuginfo` option in `bootstrap.toml`).
real_rust_source_base_dir: Option [TRACKED_NO_CRATE_HASH],
+ /// Base directory containing the `compiler/` directory for the rustc sources.
+ /// Right now it's always `$sysroot/lib/rustlib/rustc-src/rust`
+ /// (i.e. the `rustup` `rustc-dev` component).
+ ///
+ /// This directory is what the virtual `/rustc-dev/$hash` is translated back to,
+ /// if Rust was built with path remapping to `/rustc/$hash` enabled
+ /// (the `rust.remap-debuginfo` option in `bootstrap.toml`).
+ real_rustc_dev_source_base_dir: Option [TRACKED_NO_CRATE_HASH],
+
edition: Edition [TRACKED],
/// `true` if we're emitting JSON blobs about each artifact produced
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 37614a7ca4571..7c71594c43035 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1489,10 +1489,11 @@ impl String {
Some(ch)
}
- /// Removes a [`char`] from this `String` at a byte position and returns it.
+ /// Removes a [`char`] from this `String` at byte position `idx` and returns it.
///
- /// This is an *O*(*n*) operation, as it requires copying every element in the
- /// buffer.
+ /// Copies all bytes after the removed char to new positions.
+ ///
+ /// Note that calling this in a loop can result in quadratic behavior.
///
/// # Panics
///
@@ -1678,10 +1679,13 @@ impl String {
drop(guard);
}
- /// Inserts a character into this `String` at a byte position.
+ /// Inserts a character into this `String` at byte position `idx`.
+ ///
+ /// Reallocates if `self.capacity()` is insufficient, which may involve copying all
+ /// `self.capacity()` bytes. Makes space for the insertion by copying all bytes of
+ /// `&self[idx..]` to new positions.
///
- /// This is an *O*(*n*) operation as it requires copying every element in the
- /// buffer.
+ /// Note that calling this in a loop can result in quadratic behavior.
///
/// # Panics
///
@@ -1733,10 +1737,13 @@ impl String {
}
}
- /// Inserts a string slice into this `String` at a byte position.
+ /// Inserts a string slice into this `String` at byte position `idx`.
+ ///
+ /// Reallocates if `self.capacity()` is insufficient, which may involve copying all
+ /// `self.capacity()` bytes. Makes space for the insertion by copying all bytes of
+ /// `&self[idx..]` to new positions.
///
- /// This is an *O*(*n*) operation as it requires copying every element in the
- /// buffer.
+ /// Note that calling this in a loop can result in quadratic behavior.
///
/// # Panics
///
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index a4b6efe35fc14..a2c1ba835f366 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -719,7 +719,7 @@ impl Cell<[T; N]> {
#[rustc_diagnostic_item = "RefCell"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RefCell {
- borrow: Cell,
+ borrow: Cell,
// Stores the location of the earliest currently active borrow.
// This gets updated whenever we go from having zero borrows
// to having a single borrow. When a borrow occurs, this gets included
@@ -732,54 +732,48 @@ pub struct RefCell {
/// An error returned by [`RefCell::try_borrow`].
#[stable(feature = "try_borrow", since = "1.13.0")]
#[non_exhaustive]
+#[derive(Debug)]
pub struct BorrowError {
#[cfg(feature = "debug_refcell")]
location: &'static crate::panic::Location<'static>,
}
#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Debug for BorrowError {
+impl Display for BorrowError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = f.debug_struct("BorrowError");
-
#[cfg(feature = "debug_refcell")]
- builder.field("location", self.location);
+ let res = write!(
+ f,
+ "RefCell already mutably borrowed; a previous borrow was at {}",
+ self.location
+ );
- builder.finish()
- }
-}
+ #[cfg(not(feature = "debug_refcell"))]
+ let res = Display::fmt("RefCell already mutably borrowed", f);
-#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Display for BorrowError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Display::fmt("already mutably borrowed", f)
+ res
}
}
/// An error returned by [`RefCell::try_borrow_mut`].
#[stable(feature = "try_borrow", since = "1.13.0")]
#[non_exhaustive]
+#[derive(Debug)]
pub struct BorrowMutError {
#[cfg(feature = "debug_refcell")]
location: &'static crate::panic::Location<'static>,
}
#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Debug for BorrowMutError {
+impl Display for BorrowMutError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = f.debug_struct("BorrowMutError");
-
#[cfg(feature = "debug_refcell")]
- builder.field("location", self.location);
+ let res = write!(f, "RefCell already borrowed; a previous borrow was at {}", self.location);
- builder.finish()
- }
-}
+ #[cfg(not(feature = "debug_refcell"))]
+ let res = Display::fmt("RefCell already borrowed", f);
-#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Display for BorrowMutError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Display::fmt("already borrowed", f)
+ res
}
}
@@ -788,7 +782,7 @@ impl Display for BorrowMutError {
#[track_caller]
#[cold]
fn panic_already_borrowed(err: BorrowMutError) -> ! {
- panic!("already borrowed: {:?}", err)
+ panic!("{err}")
}
// This ensures the panicking code is outlined from `borrow` for `RefCell`.
@@ -796,7 +790,7 @@ fn panic_already_borrowed(err: BorrowMutError) -> ! {
#[track_caller]
#[cold]
fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
- panic!("already mutably borrowed: {:?}", err)
+ panic!("{err}")
}
// Positive values represent the number of `Ref` active. Negative values
@@ -806,22 +800,22 @@ fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
//
// `Ref` and `RefMut` are both two words in size, and so there will likely never
// be enough `Ref`s or `RefMut`s in existence to overflow half of the `usize`
-// range. Thus, a `BorrowFlag` will probably never overflow or underflow.
+// range. Thus, a `BorrowCounter` will probably never overflow or underflow.
// However, this is not a guarantee, as a pathological program could repeatedly
// create and then mem::forget `Ref`s or `RefMut`s. Thus, all code must
// explicitly check for overflow and underflow in order to avoid unsafety, or at
// least behave correctly in the event that overflow or underflow happens (e.g.,
// see BorrowRef::new).
-type BorrowFlag = isize;
-const UNUSED: BorrowFlag = 0;
+type BorrowCounter = isize;
+const UNUSED: BorrowCounter = 0;
#[inline(always)]
-fn is_writing(x: BorrowFlag) -> bool {
+fn is_writing(x: BorrowCounter) -> bool {
x < UNUSED
}
#[inline(always)]
-fn is_reading(x: BorrowFlag) -> bool {
+fn is_reading(x: BorrowCounter) -> bool {
x > UNUSED
}
@@ -1401,12 +1395,12 @@ impl From for RefCell {
impl, U> CoerceUnsized> for RefCell {}
struct BorrowRef<'b> {
- borrow: &'b Cell,
+ borrow: &'b Cell,
}
impl<'b> BorrowRef<'b> {
#[inline]
- fn new(borrow: &'b Cell) -> Option> {
+ fn new(borrow: &'b Cell) -> Option> {
let b = borrow.get().wrapping_add(1);
if !is_reading(b) {
// Incrementing borrow can result in a non-reading value (<= 0) in these cases:
@@ -1447,7 +1441,7 @@ impl Clone for BorrowRef<'_> {
debug_assert!(is_reading(borrow));
// Prevent the borrow counter from overflowing into
// a writing borrow.
- assert!(borrow != BorrowFlag::MAX);
+ assert!(borrow != BorrowCounter::MAX);
self.borrow.set(borrow + 1);
BorrowRef { borrow: self.borrow }
}
@@ -1795,7 +1789,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
}
struct BorrowRefMut<'b> {
- borrow: &'b Cell,
+ borrow: &'b Cell,
}
impl Drop for BorrowRefMut<'_> {
@@ -1809,7 +1803,7 @@ impl Drop for BorrowRefMut<'_> {
impl<'b> BorrowRefMut<'b> {
#[inline]
- fn new(borrow: &'b Cell) -> Option> {
+ fn new(borrow: &'b Cell) -> Option> {
// NOTE: Unlike BorrowRefMut::clone, new is called to create the initial
// mutable reference, and so there must currently be no existing
// references. Thus, while clone increments the mutable refcount, here
@@ -1833,7 +1827,7 @@ impl<'b> BorrowRefMut<'b> {
let borrow = self.borrow.get();
debug_assert!(is_writing(borrow));
// Prevent the borrow counter from underflowing.
- assert!(borrow != BorrowFlag::MIN);
+ assert!(borrow != BorrowCounter::MIN);
self.borrow.set(borrow - 1);
BorrowRefMut { borrow: self.borrow }
}
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 1fae5b8390247..8f1000ca0b8bc 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -20,19 +20,24 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
/// as a discriminant -- `Option>` has the same size as `*mut T`.
/// However the pointer may still dangle if it isn't dereferenced.
///
-/// Unlike `*mut T`, `NonNull` was chosen to be covariant over `T`. This makes it
-/// possible to use `NonNull` when building covariant types, but introduces the
-/// risk of unsoundness if used in a type that shouldn't actually be covariant.
-/// (The opposite choice was made for `*mut T` even though technically the unsoundness
-/// could only be caused by calling unsafe functions.)
+/// Unlike `*mut T`, `NonNull` is covariant over `T`. This is usually the correct
+/// choice for most data structures and safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
+/// and `LinkedList`.
///
-/// Covariance is correct for most safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
-/// and `LinkedList`. This is the case because they provide a public API that follows the
-/// normal shared XOR mutable rules of Rust.
+/// In rare cases, if your type exposes a way to mutate the value of `T` through a `NonNull`,
+/// and you need to prevent unsoundness from variance (for example, if `T` could be a reference
+/// with a shorter lifetime), you should add a field to make your type invariant, such as
+/// `PhantomData>` or `PhantomData<&'a mut T>`.
///
-/// If your type cannot safely be covariant, you must ensure it contains some
-/// additional field to provide invariance. Often this field will be a [`PhantomData`]
-/// type like `PhantomData>` or `PhantomData<&'a mut T>`.
+/// Example of a type that must be invariant:
+/// ```rust
+/// use std::cell::Cell;
+/// use std::marker::PhantomData;
+/// struct Invariant {
+/// ptr: std::ptr::NonNull,
+/// _invariant: PhantomData>,
+/// }
+/// ```
///
/// Notice that `NonNull` has a `From` instance for `&T`. However, this does
/// not change the fact that mutating through a (pointer derived from a) shared
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index ac1c5e9932e1c..53dec105d0c85 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -119,6 +119,23 @@ unsafe extern "system" {
pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
}
+windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile(
+ filehandle: *mut HANDLE,
+ desiredaccess: FILE_ACCESS_RIGHTS,
+ objectattributes: *const OBJECT_ATTRIBUTES,
+ iostatusblock: *mut IO_STATUS_BLOCK,
+ shareaccess: FILE_SHARE_MODE,
+ createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
+ createoptions: NTCREATEFILE_CREATE_OPTIONS,
+ namedpipetype: u32,
+ readmode: u32,
+ completionmode: u32,
+ maximuminstances: u32,
+ inboundquota: u32,
+ outboundquota: u32,
+ defaulttimeout: *const u64,
+) -> NTSTATUS);
+
// Functions that aren't available on every version of Windows that we support,
// but we still use them and just provide some form of a fallback implementation.
compat_fn_with_fallback! {
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index a99c474c763c5..827d96e73db41 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2060,6 +2060,14 @@ FILE_OPEN_REPARSE_POINT
FILE_OPEN_REQUIRING_OPLOCK
FILE_OVERWRITE
FILE_OVERWRITE_IF
+FILE_PIPE_ACCEPT_REMOTE_CLIENTS
+FILE_PIPE_BYTE_STREAM_MODE
+FILE_PIPE_BYTE_STREAM_TYPE
+FILE_PIPE_COMPLETE_OPERATION
+FILE_PIPE_MESSAGE_MODE
+FILE_PIPE_MESSAGE_TYPE
+FILE_PIPE_QUEUE_OPERATION
+FILE_PIPE_REJECT_REMOTE_CLIENTS
FILE_RANDOM_ACCESS
FILE_READ_ATTRIBUTES
FILE_READ_DATA
@@ -2294,7 +2302,16 @@ NtOpenFile
NtReadFile
NTSTATUS
NtWriteFile
+OBJ_CASE_INSENSITIVE
OBJ_DONT_REPARSE
+OBJ_EXCLUSIVE
+OBJ_FORCE_ACCESS_CHECK
+OBJ_IGNORE_IMPERSONATED_DEVICEMAP
+OBJ_INHERIT
+OBJ_KERNEL_HANDLE
+OBJ_OPENIF
+OBJ_OPENLINK
+OBJ_PERMANENT
OPEN_ALWAYS
OPEN_EXISTING
OpenProcessToken
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index 95bf8040229d0..b2e3aabc63353 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -1,4 +1,4 @@
-// Bindings generated by `windows-bindgen` 0.61.0
+// Bindings generated by `windows-bindgen` 0.61.1
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
@@ -2552,6 +2552,14 @@ pub const FILE_OPEN_REPARSE_POINT: NTCREATEFILE_CREATE_OPTIONS = 2097152u32;
pub const FILE_OPEN_REQUIRING_OPLOCK: NTCREATEFILE_CREATE_OPTIONS = 65536u32;
pub const FILE_OVERWRITE: NTCREATEFILE_CREATE_DISPOSITION = 4u32;
pub const FILE_OVERWRITE_IF: NTCREATEFILE_CREATE_DISPOSITION = 5u32;
+pub const FILE_PIPE_ACCEPT_REMOTE_CLIENTS: u32 = 0u32;
+pub const FILE_PIPE_BYTE_STREAM_MODE: u32 = 0u32;
+pub const FILE_PIPE_BYTE_STREAM_TYPE: u32 = 0u32;
+pub const FILE_PIPE_COMPLETE_OPERATION: u32 = 1u32;
+pub const FILE_PIPE_MESSAGE_MODE: u32 = 1u32;
+pub const FILE_PIPE_MESSAGE_TYPE: u32 = 1u32;
+pub const FILE_PIPE_QUEUE_OPERATION: u32 = 0u32;
+pub const FILE_PIPE_REJECT_REMOTE_CLIENTS: u32 = 2u32;
pub const FILE_RANDOM_ACCESS: NTCREATEFILE_CREATE_OPTIONS = 2048u32;
pub const FILE_READ_ATTRIBUTES: FILE_ACCESS_RIGHTS = 128u32;
pub const FILE_READ_DATA: FILE_ACCESS_RIGHTS = 1u32;
@@ -2983,7 +2991,16 @@ impl Default for OBJECT_ATTRIBUTES {
}
}
pub type OBJECT_ATTRIBUTE_FLAGS = u32;
+pub const OBJ_CASE_INSENSITIVE: OBJECT_ATTRIBUTE_FLAGS = 64u32;
pub const OBJ_DONT_REPARSE: OBJECT_ATTRIBUTE_FLAGS = 4096u32;
+pub const OBJ_EXCLUSIVE: OBJECT_ATTRIBUTE_FLAGS = 32u32;
+pub const OBJ_FORCE_ACCESS_CHECK: OBJECT_ATTRIBUTE_FLAGS = 1024u32;
+pub const OBJ_IGNORE_IMPERSONATED_DEVICEMAP: OBJECT_ATTRIBUTE_FLAGS = 2048u32;
+pub const OBJ_INHERIT: OBJECT_ATTRIBUTE_FLAGS = 2u32;
+pub const OBJ_KERNEL_HANDLE: OBJECT_ATTRIBUTE_FLAGS = 512u32;
+pub const OBJ_OPENIF: OBJECT_ATTRIBUTE_FLAGS = 128u32;
+pub const OBJ_OPENLINK: OBJECT_ATTRIBUTE_FLAGS = 256u32;
+pub const OBJ_PERMANENT: OBJECT_ATTRIBUTE_FLAGS = 16u32;
pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32;
pub const OPEN_EXISTING: FILE_CREATION_DISPOSITION = 3u32;
#[repr(C)]
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 00d469fbaf8c7..bc5d05c45052a 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -1,14 +1,9 @@
-use crate::ffi::OsStr;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::ops::Neg;
use crate::os::windows::prelude::*;
-use crate::path::Path;
-use crate::random::{DefaultRandomSource, Random};
-use crate::sync::atomic::Ordering::Relaxed;
-use crate::sync::atomic::{Atomic, AtomicUsize};
+use crate::sys::api::utf16;
use crate::sys::c;
-use crate::sys::fs::{File, OpenOptions};
use crate::sys::handle::Handle;
-use crate::sys::pal::windows::api::{self, WinError};
use crate::sys_common::{FromInner, IntoInner};
use crate::{mem, ptr};
@@ -62,92 +57,113 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
// Note that we specifically do *not* use `CreatePipe` here because
// unfortunately the anonymous pipes returned do not support overlapped
- // operations. Instead, we create a "hopefully unique" name and create a
- // named pipe which has overlapped operations enabled.
+ // operations. Instead, we use `NtCreateNamedPipeFile` to create the
+ // anonymous pipe with overlapped support.
//
- // Once we do this, we connect do it as usual via `CreateFileW`, and then
+ // Once we do this, we connect to it via `NtOpenFile`, and then
// we return those reader/writer halves. Note that the `ours` pipe return
// value is always the named pipe, whereas `theirs` is just the normal file.
// This should hopefully shield us from child processes which assume their
// stdout is a named pipe, which would indeed be odd!
unsafe {
- let ours;
- let mut name;
- let mut tries = 0;
- loop {
- tries += 1;
- name = format!(
- r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}",
- c::GetCurrentProcessId(),
- random_number(),
+ let mut io_status = c::IO_STATUS_BLOCK::default();
+ let mut object_attributes = c::OBJECT_ATTRIBUTES::default();
+ object_attributes.Length = size_of::() as u32;
+
+ // Open a handle to the pipe filesystem (`\??\PIPE\`).
+ // This will be used when creating a new annon pipe.
+ let pipe_fs = {
+ let path = c::UNICODE_STRING::from_ref(utf16!(r"\??\PIPE\"));
+ object_attributes.ObjectName = &path;
+ let mut pipe_fs = ptr::null_mut();
+ let status = c::NtOpenFile(
+ &mut pipe_fs,
+ c::SYNCHRONIZE | c::GENERIC_READ,
+ &object_attributes,
+ &mut io_status,
+ c::FILE_SHARE_READ | c::FILE_SHARE_WRITE,
+ c::FILE_SYNCHRONOUS_IO_NONALERT, // synchronous access
);
- let wide_name = OsStr::new(&name).encode_wide().chain(Some(0)).collect::>();
- let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | c::FILE_FLAG_OVERLAPPED;
- if ours_readable {
- flags |= c::PIPE_ACCESS_INBOUND;
+ if c::nt_success(status) {
+ Handle::from_raw_handle(pipe_fs)
} else {
- flags |= c::PIPE_ACCESS_OUTBOUND;
+ return Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as i32));
}
+ };
- let handle = c::CreateNamedPipeW(
- wide_name.as_ptr(),
- flags,
- c::PIPE_TYPE_BYTE
- | c::PIPE_READMODE_BYTE
- | c::PIPE_WAIT
- | c::PIPE_REJECT_REMOTE_CLIENTS,
+ // From now on we're using handles instead of paths to create and open pipes.
+ // So set the `ObjectName` to a zero length string.
+ let empty = c::UNICODE_STRING::default();
+ object_attributes.ObjectName = ∅
+
+ // Create our side of the pipe for async access.
+ let ours = {
+ // Use the pipe filesystem as the root directory.
+ // With no name provided, an anonymous pipe will be created.
+ object_attributes.RootDirectory = pipe_fs.as_raw_handle();
+
+ // A negative timeout value is a relative time (rather than an absolute time).
+ // The time is given in 100's of nanoseconds so this is 50 milliseconds.
+ // This value was chosen to be consistent with the default timeout set by `CreateNamedPipeW`
+ // See: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createnamedpipew
+ let timeout = (50_i64 * 10000).neg() as u64;
+
+ let mut ours = ptr::null_mut();
+ let status = c::NtCreateNamedPipeFile(
+ &mut ours,
+ c::SYNCHRONIZE | if ours_readable { c::GENERIC_READ } else { c::GENERIC_WRITE },
+ &object_attributes,
+ &mut io_status,
+ if ours_readable { c::FILE_SHARE_WRITE } else { c::FILE_SHARE_READ },
+ c::FILE_CREATE,
+ 0,
+ c::FILE_PIPE_BYTE_STREAM_TYPE,
+ c::FILE_PIPE_BYTE_STREAM_MODE,
+ c::FILE_PIPE_QUEUE_OPERATION,
+ // only allow one client pipe
1,
PIPE_BUFFER_CAPACITY,
PIPE_BUFFER_CAPACITY,
- 0,
- ptr::null_mut(),
+ &timeout,
);
-
- // We pass the `FILE_FLAG_FIRST_PIPE_INSTANCE` flag above, and we're
- // also just doing a best effort at selecting a unique name. If
- // `ERROR_ACCESS_DENIED` is returned then it could mean that we
- // accidentally conflicted with an already existing pipe, so we try
- // again.
- //
- // Don't try again too much though as this could also perhaps be a
- // legit error.
- if handle == c::INVALID_HANDLE_VALUE {
- let error = api::get_last_error();
- if tries < 10 && error == WinError::ACCESS_DENIED {
- continue;
- } else {
- return Err(io::Error::from_raw_os_error(error.code as i32));
- }
+ if c::nt_success(status) {
+ Handle::from_raw_handle(ours)
+ } else {
+ return Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as i32));
}
+ };
- ours = Handle::from_raw_handle(handle);
- break;
- }
+ // Open their side of the pipe for synchronous access.
+ let theirs = {
+ // We can reopen the anonymous pipe without a name by setting
+ // RootDirectory to the pipe handle and not setting a path name,
+ object_attributes.RootDirectory = ours.as_raw_handle();
- // Connect to the named pipe we just created. This handle is going to be
- // returned in `theirs`, so if `ours` is readable we want this to be
- // writable, otherwise if `ours` is writable we want this to be
- // readable.
- //
- // Additionally we don't enable overlapped mode on this because most
- // client processes aren't enabled to work with that.
- let mut opts = OpenOptions::new();
- opts.write(ours_readable);
- opts.read(!ours_readable);
- opts.share_mode(0);
- let size = size_of::();
- let mut sa = c::SECURITY_ATTRIBUTES {
- nLength: size as u32,
- lpSecurityDescriptor: ptr::null_mut(),
- bInheritHandle: their_handle_inheritable as i32,
+ if their_handle_inheritable {
+ object_attributes.Attributes |= c::OBJ_INHERIT;
+ }
+ let mut theirs = ptr::null_mut();
+ let status = c::NtOpenFile(
+ &mut theirs,
+ c::SYNCHRONIZE
+ | if ours_readable {
+ c::GENERIC_WRITE | c::FILE_READ_ATTRIBUTES
+ } else {
+ c::GENERIC_READ
+ },
+ &object_attributes,
+ &mut io_status,
+ 0,
+ c::FILE_NON_DIRECTORY_FILE | c::FILE_SYNCHRONOUS_IO_NONALERT,
+ );
+ if c::nt_success(status) {
+ Handle::from_raw_handle(theirs)
+ } else {
+ return Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as i32));
+ }
};
- opts.security_attributes(&mut sa);
- let theirs = File::open(Path::new(&name), &opts)?;
- Ok(Pipes {
- ours: AnonPipe { inner: ours },
- theirs: AnonPipe { inner: theirs.into_inner() },
- })
+ Ok(Pipes { ours: AnonPipe { inner: ours }, theirs: AnonPipe { inner: theirs } })
}
}
@@ -191,17 +207,6 @@ pub fn spawn_pipe_relay(
Ok(theirs)
}
-fn random_number() -> usize {
- static N: Atomic = AtomicUsize::new(0);
- loop {
- if N.load(Relaxed) != 0 {
- return N.fetch_add(1, Relaxed);
- }
-
- N.store(usize::random(&mut DefaultRandomSource), Relaxed);
- }
-}
-
impl AnonPipe {
pub fn handle(&self) -> &Handle {
&self.inner
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index 25d3efdbb8260..9e4a11044e818 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -113,6 +113,8 @@ Compiletest makes the following replacements on the compiler output:
- The base directory where the test's output goes is replaced with
`$TEST_BUILD_DIR`. This only comes up in a few rare circumstances. Example:
`/path/to/rust/build/x86_64-unknown-linux-gnu/test/ui`
+- The real directory to the standard library source is replaced with `$SRC_DIR_REAL`.
+- The real directory to the compiler source is replaced with `$COMPILER_DIR_REAL`.
- Tabs are replaced with `\t`.
- Backslashes (`\`) are converted to forward slashes (`/`) within paths (using a
heuristic). This helps normalize differences with Windows-style paths.
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index b839b6f56728c..bd8420917f5e6 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -128,7 +128,7 @@ fn remove_all_parens(pat: &mut P) {
}
impl MutVisitor for Visitor {
- fn visit_pat(&mut self, pat: &mut P) {
+ fn visit_pat(&mut self, pat: &mut Pat) {
let is_inner = mem::replace(&mut self.is_inner, true);
walk_pat(self, pat);
let inner = match &mut pat.kind {
@@ -145,7 +145,7 @@ fn remove_all_parens(pat: &mut P) {
fn insert_necessary_parens(pat: &mut P) {
struct Visitor;
impl MutVisitor for Visitor {
- fn visit_pat(&mut self, pat: &mut P) {
+ fn visit_pat(&mut self, pat: &mut Pat) {
use ast::BindingMode;
walk_pat(self, pat);
let target = match &mut pat.kind {
@@ -167,7 +167,7 @@ fn unnest_or_patterns(pat: &mut P) -> bool {
changed: bool,
}
impl MutVisitor for Visitor {
- fn visit_pat(&mut self, p: &mut P) {
+ fn visit_pat(&mut self, p: &mut Pat) {
// This is a bottom up transformation, so recurse first.
walk_pat(self, p);
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 75f24adb70fa5..9edcba5d460c1 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2371,6 +2371,12 @@ impl<'test> TestCx<'test> {
let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf());
normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL");
+ // Real paths into the compiler
+ let rustc_src_dir = &self.config.sysroot_base.join("lib/rustlib/rustc-src/rust");
+ rustc_src_dir.try_exists().expect(&*format!("{} should exists", rustc_src_dir));
+ let rustc_src_dir = rustc_src_dir.read_link_utf8().unwrap_or(rustc_src_dir.to_path_buf());
+ normalize_path(&rustc_src_dir.join("compiler"), "$COMPILER_DIR_REAL");
+
// eg.
// /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui//$name.$revision.$mode/
normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR");
diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs
index a7a98d31f5046..09a34cdeb5e70 100644
--- a/tests/run-make/dump-ice-to-disk/rmake.rs
+++ b/tests/run-make/dump-ice-to-disk/rmake.rs
@@ -17,14 +17,14 @@
//!
//! # Test history
//!
-//! - The previous rmake.rs iteration of this test was flakey for unknown reason on `i686-mingw`
-//! *specifically*, so assertion failures in this test was made extremely verbose to help
-//! diagnose why the ICE messages was different *specifically* on `i686-mingw`.
-//! - An attempt is made to re-enable this test on `i686-mingw` (by removing `ignore-windows`). If
-//! this test is still flakey, please restore the `ignore-windows` directive.
-
-//@ ignore-windows
-//FIXME(#128911): still flakey on i686-mingw.
+//! The previous rmake.rs iteration of this test was flaky for unknown reason on
+//! `i686-pc-windows-gnu` *specifically*, so assertion failures in this test was made extremely
+//! verbose to help diagnose why the ICE messages was different. It appears that backtraces on
+//! `i686-pc-windows-gnu` specifically are quite unpredictable in how many backtrace frames are
+//! involved.
+
+//@ ignore-cross-compile (exercising ICE dump on host)
+//@ ignore-i686-pc-windows-gnu (unwind mechanism produces unpredictable backtraces)
use std::cell::OnceCell;
use std::path::{Path, PathBuf};
diff --git a/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs b/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs
index a7215ca9d50bc..862b2bd5300c3 100644
--- a/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs
+++ b/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs
@@ -7,12 +7,11 @@
//!
//! # Test history
//!
-//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming
-//! those will be present in this test as well on the same platform
+//! - Forked from `dump-ice-to-disk` test, which previously had backtrace unpredictability on
+//! `i686-pc-windows-gnu`.
-//@ needs-target-std
-//@ ignore-windows
-//FIXME(#128911): still flakey on i686-mingw.
+//@ ignore-cross-compile (exercises metrics incremental on host)
+//@ ignore-i686-pc-windows-gnu (unwind mechanism produces unpredictable backtraces)
use std::path::{Path, PathBuf};
@@ -87,9 +86,7 @@ fn test_metrics_errors() {
.env("RUST_BACKTRACE", "short")
.arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist")
.run_fail()
- .assert_stderr_contains(
- "error: cannot dump feature usage metrics: No such file or directory",
- )
+ .assert_stderr_contains("error: cannot dump feature usage metrics")
.assert_stdout_not_contains("internal compiler error");
});
}
diff --git a/tests/run-make/unstable-feature-usage-metrics/rmake.rs b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
index dbe078bf468a5..f987829741c72 100644
--- a/tests/run-make/unstable-feature-usage-metrics/rmake.rs
+++ b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
@@ -7,12 +7,10 @@
//!
//! # Test history
//!
-//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming
-//! those will be present in this test as well on the same platform
+//! - Forked from `dump-ice-to-disk` test, where `i686-pc-windows-gnu` has unpredictable backtraces.
-//@ needs-target-std
-//@ ignore-windows
-//FIXME(#128911): still flakey on i686-mingw.
+//@ ignore-cross-compile (exercises metrics dump on host)
+//@ ignore-i686-pc-windows-gnu (unwind mechanism produces unpredictable backtraces)
use std::path::{Path, PathBuf};
@@ -85,9 +83,7 @@ fn test_metrics_errors() {
.env("RUST_BACKTRACE", "short")
.arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist")
.run_fail()
- .assert_stderr_contains(
- "error: cannot dump feature usage metrics: No such file or directory",
- )
+ .assert_stderr_contains("error: cannot dump feature usage metrics")
.assert_stdout_not_contains("internal compiler error");
});
}
diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
index f5cfa9e0bccff..8bca20852add4 100644
--- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -187,9 +187,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) {
struct RemoveParens;
impl MutVisitor for RemoveParens {
- fn visit_expr(&mut self, e: &mut P) {
+ fn visit_expr(&mut self, e: &mut Expr) {
match e.kind.clone() {
- ExprKind::Paren(inner) => *e = inner,
+ ExprKind::Paren(inner) => *e = *inner,
_ => {}
};
mut_visit::walk_expr(self, e);
@@ -200,11 +200,11 @@ impl MutVisitor for RemoveParens {
struct AddParens;
impl MutVisitor for AddParens {
- fn visit_expr(&mut self, e: &mut P) {
+ fn visit_expr(&mut self, e: &mut Expr) {
mut_visit::walk_expr(self, e);
let expr = std::mem::replace(e, Expr::dummy());
- e.kind = ExprKind::Paren(expr);
+ e.kind = ExprKind::Paren(P(expr));
}
}
diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
index 08bed40abe86b..90e07bed40e75 100644
--- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
+++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
@@ -43,7 +43,6 @@ use std::process::ExitCode;
use parser::parse_expr;
use rustc_ast::ast::{Expr, ExprKind};
use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::ptr::P;
use rustc_ast_pretty::pprust;
use rustc_session::parse::ParseSess;
@@ -157,7 +156,7 @@ static EXPRS: &[&str] = &[
struct Unparenthesize;
impl MutVisitor for Unparenthesize {
- fn visit_expr(&mut self, e: &mut P) {
+ fn visit_expr(&mut self, e: &mut Expr) {
while let ExprKind::Paren(paren) = &mut e.kind {
*e = mem::replace(paren, Expr::dummy());
}
diff --git a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr
new file mode 100644
index 0000000000000..f54b6803b346a
--- /dev/null
+++ b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisfied
+ --> $DIR/rustc-dev-remap.rs:LL:COL
+ |
+LL | type Result = NotAValidResultType;
+ | ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType`
+ |
+ = help: the following other types implement trait `VisitorResult`:
+ ()
+ ControlFlow
+note: required by a bound in `rustc_ast::visit::Visitor::Result`
+ --> /rustc-dev/xyz/compiler/rustc_ast/src/visit.rs:LL:COL
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr
new file mode 100644
index 0000000000000..438c23458e2f5
--- /dev/null
+++ b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisfied
+ --> $DIR/rustc-dev-remap.rs:LL:COL
+ |
+LL | type Result = NotAValidResultType;
+ | ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType`
+ |
+ = help: the following other types implement trait `VisitorResult`:
+ ()
+ ControlFlow
+note: required by a bound in `rustc_ast::visit::Visitor::Result`
+ --> $COMPILER_DIR_REAL/rustc_ast/src/visit.rs:LL:COL
+ |
+LL | type Result: VisitorResult = ();
+ | ^^^^^^^^^^^^^ required by this bound in `Visitor::Result`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui-fulldeps/rustc-dev-remap.rs b/tests/ui-fulldeps/rustc-dev-remap.rs
new file mode 100644
index 0000000000000..aae7d4c0c90d1
--- /dev/null
+++ b/tests/ui-fulldeps/rustc-dev-remap.rs
@@ -0,0 +1,30 @@
+//@ check-fail
+//
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//
+//@ revisions: only-remap remap-unremap
+//@ compile-flags: -Z simulate-remapped-rust-src-base=/rustc-dev/xyz
+//@ [remap-unremap]compile-flags: -Ztranslate-remapped-path-to-local-path=yes
+
+// The $SRC_DIR*.rs:LL:COL normalisation doesn't kick in automatically
+// as the remapped revision will begin with $COMPILER_DIR_REAL,
+// so we have to do it ourselves.
+//@ normalize-stderr: ".rs:\d+:\d+" -> ".rs:LL:COL"
+
+#![feature(rustc_private)]
+
+extern crate rustc_ast;
+
+use rustc_ast::visit::Visitor;
+
+struct MyStruct;
+struct NotAValidResultType;
+
+impl Visitor<'_> for MyStruct {
+ type Result = NotAValidResultType;
+ //~^ ERROR the trait bound `NotAValidResultType: VisitorResult` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.fixed b/tests/ui/borrowck/span-semicolon-issue-139049.fixed
index 0b263b222963f..c01d1242dd73f 100644
--- a/tests/ui/borrowck/span-semicolon-issue-139049.fixed
+++ b/tests/ui/borrowck/span-semicolon-issue-139049.fixed
@@ -1,52 +1,25 @@
-// Make sure the generated suggestion suggest editing the user
-// code instead of the std macro implementation
+// Make sure the generated suggestion suggest editing the user code instead of
+// the macro implementation (which might come from an external crate).
+// issue:
//@ run-rustfix
#![allow(dead_code)]
-use std::fmt::{self, Display};
-
-struct Mutex;
-
-impl Mutex {
- fn lock(&self) -> MutexGuard<'_> {
- MutexGuard(self)
- }
-}
-
-struct MutexGuard<'a>(&'a Mutex);
-
-impl<'a> Drop for MutexGuard<'a> {
- fn drop(&mut self) {}
-}
-
-struct Out;
-
-impl Out {
- fn write_fmt(&self, _args: fmt::Arguments) {}
-}
-
-impl<'a> Display for MutexGuard<'a> {
- fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
- Ok(())
- }
-}
+// You could assume that this comes from an extern crate (it doesn't
+// because an aux crate would be overkill for this test).
+macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+//~^ ERROR does not live long enough
+//~| ERROR does not live long enough
fn main() {
- let _write = {
- let mutex = Mutex;
- write!(Out, "{}", mutex.lock());
- //~^ ERROR `mutex` does not live long enough
- //~| SUGGESTION ;
- };
-
- let _write = {
- use std::io::Write as _;
+ { let l = (); perform!(l); };
+ //~^ SUGGESTION ;
- let mutex = Mutex;
- let x = write!(std::io::stdout(), "{}", mutex.lock()); x
- //~^ ERROR `mutex` does not live long enough
- //~| SUGGESTION let x
- };
+ let _x = { let l = (); let x = perform!(l); x };
+ //~^ SUGGESTION let x
}
+
+struct D(T);
+impl Drop for D { fn drop(&mut self) {} }
+impl D { fn end(&self) -> String { String::new() } }
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.rs b/tests/ui/borrowck/span-semicolon-issue-139049.rs
index a92742ac94b2c..43558756c718d 100644
--- a/tests/ui/borrowck/span-semicolon-issue-139049.rs
+++ b/tests/ui/borrowck/span-semicolon-issue-139049.rs
@@ -1,52 +1,25 @@
-// Make sure the generated suggestion suggest editing the user
-// code instead of the std macro implementation
+// Make sure the generated suggestion suggest editing the user code instead of
+// the macro implementation (which might come from an external crate).
+// issue:
//@ run-rustfix
#![allow(dead_code)]
-use std::fmt::{self, Display};
-
-struct Mutex;
-
-impl Mutex {
- fn lock(&self) -> MutexGuard<'_> {
- MutexGuard(self)
- }
-}
-
-struct MutexGuard<'a>(&'a Mutex);
-
-impl<'a> Drop for MutexGuard<'a> {
- fn drop(&mut self) {}
-}
-
-struct Out;
-
-impl Out {
- fn write_fmt(&self, _args: fmt::Arguments) {}
-}
-
-impl<'a> Display for MutexGuard<'a> {
- fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
- Ok(())
- }
-}
+// You could assume that this comes from an extern crate (it doesn't
+// because an aux crate would be overkill for this test).
+macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+//~^ ERROR does not live long enough
+//~| ERROR does not live long enough
fn main() {
- let _write = {
- let mutex = Mutex;
- write!(Out, "{}", mutex.lock())
- //~^ ERROR `mutex` does not live long enough
- //~| SUGGESTION ;
- };
-
- let _write = {
- use std::io::Write as _;
+ { let l = (); perform!(l) };
+ //~^ SUGGESTION ;
- let mutex = Mutex;
- write!(std::io::stdout(), "{}", mutex.lock())
- //~^ ERROR `mutex` does not live long enough
- //~| SUGGESTION let x
- };
+ let _x = { let l = (); perform!(l) };
+ //~^ SUGGESTION let x
}
+
+struct D(T);
+impl Drop for D { fn drop(&mut self) {} }
+impl D { fn end(&self) -> String { String::new() } }
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.stderr b/tests/ui/borrowck/span-semicolon-issue-139049.stderr
index 123bdf4bc67e4..8d2de67382bd8 100644
--- a/tests/ui/borrowck/span-semicolon-issue-139049.stderr
+++ b/tests/ui/borrowck/span-semicolon-issue-139049.stderr
@@ -1,46 +1,48 @@
-error[E0597]: `mutex` does not live long enough
- --> $DIR/span-semicolon-issue-139049.rs:39:27
+error[E0597]: `l` does not live long enough
+ --> $DIR/span-semicolon-issue-139049.rs:11:41
|
-LL | let mutex = Mutex;
- | ----- binding `mutex` declared here
-LL | write!(Out, "{}", mutex.lock())
- | ^^^^^-------
- | |
- | borrowed value does not live long enough
- | a temporary with access to the borrow is created here ...
+LL | macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+ | --^^^-
+ | | |
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
...
-LL | };
- | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
- | |
- | `mutex` dropped here while still borrowed
+LL | { let l = (); perform!(l) };
+ | - ----------- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `l` dropped here while still borrowed
+ | | in this macro invocation
+ | binding `l` declared here
|
+ = note: this error originates in the macro `perform` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
-LL | write!(Out, "{}", mutex.lock());
- | +
+LL | { let l = (); perform!(l); };
+ | +
-error[E0597]: `mutex` does not live long enough
- --> $DIR/span-semicolon-issue-139049.rs:48:41
+error[E0597]: `l` does not live long enough
+ --> $DIR/span-semicolon-issue-139049.rs:11:41
|
-LL | let mutex = Mutex;
- | ----- binding `mutex` declared here
-LL | write!(std::io::stdout(), "{}", mutex.lock())
- | ^^^^^-------
- | |
- | borrowed value does not live long enough
- | a temporary with access to the borrow is created here ...
+LL | macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+ | --^^^-
+ | | |
+ | | borrowed value does not live long enough
+ | a temporary with access to the borrow is created here ...
...
-LL | };
- | -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
- | |
- | `mutex` dropped here while still borrowed
+LL | let _x = { let l = (); perform!(l) };
+ | - ----------- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+ | | | |
+ | | | `l` dropped here while still borrowed
+ | | in this macro invocation
+ | binding `l` declared here
|
= note: the temporary is part of an expression at the end of a block;
consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
+ = note: this error originates in the macro `perform` (in Nightly builds, run with -Z macro-backtrace for more info)
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
|
-LL | let x = write!(std::io::stdout(), "{}", mutex.lock()); x
- | +++++++ +++
+LL | let _x = { let l = (); let x = perform!(l); x };
+ | +++++++ +++
error: aborting due to 2 previous errors
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.rs b/tests/ui/feature-gates/feature-gate-default-field-values.rs
index d2e41a7160259..4631f51b9d840 100644
--- a/tests/ui/feature-gates/feature-gate-default-field-values.rs
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.rs
@@ -58,6 +58,16 @@ pub enum OptEnum {
}
}
+// Default field values may not be used on `union`s (at least, this is not described in the accepted
+// RFC, and it's not currently clear how to extend the design to do so). We emit a feature gate
+// error when the feature is not enabled, but syntactically reject default field values when used
+// with unions when the feature is enabled. This can be adjusted if there's an acceptable design
+// extension, or just unconditionally reject always.
+union U {
+ x: i32 = 0, //~ ERROR default values on fields are experimental
+ y: f32 = 0.0, //~ ERROR default values on fields are experimental
+}
+
fn main () {
let x = Foo { .. }; //~ ERROR base expression required after `..`
let y = Foo::default();
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
index 104d72a39861d..292c38990726e 100644
--- a/tests/ui/feature-gates/feature-gate-default-field-values.stderr
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
@@ -124,8 +124,28 @@ LL | optional: () = (),
= help: add `#![feature(default_field_values)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+error[E0658]: default values on fields are experimental
+ --> $DIR/feature-gate-default-field-values.rs:67:11
+ |
+LL | x: i32 = 0,
+ | ^^^^
+ |
+ = note: see issue #132162 for more information
+ = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: default values on fields are experimental
+ --> $DIR/feature-gate-default-field-values.rs:68:11
+ |
+LL | y: f32 = 0.0,
+ | ^^^^^^
+ |
+ = note: see issue #132162 for more information
+ = help: add `#![feature(default_field_values)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:62:21
+ --> $DIR/feature-gate-default-field-values.rs:72:21
|
LL | let x = Foo { .. };
| ^
@@ -140,7 +160,7 @@ LL | let x = Foo { ../* expr */ };
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:64:29
+ --> $DIR/feature-gate-default-field-values.rs:74:29
|
LL | let z = Foo { baz: 1, .. };
| ^
@@ -155,7 +175,7 @@ LL | let z = Foo { baz: 1, ../* expr */ };
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:70:26
+ --> $DIR/feature-gate-default-field-values.rs:80:26
|
LL | let x = Bar::Foo { .. };
| ^
@@ -170,7 +190,7 @@ LL | let x = Bar::Foo { ../* expr */ };
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:72:34
+ --> $DIR/feature-gate-default-field-values.rs:82:34
|
LL | let z = Bar::Foo { baz: 1, .. };
| ^
@@ -185,7 +205,7 @@ LL | let z = Bar::Foo { baz: 1, ../* expr */ };
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:78:31
+ --> $DIR/feature-gate-default-field-values.rs:88:31
|
LL | let x = Qux:: { .. };
| ^
@@ -200,7 +220,7 @@ LL | let x = Qux:: { ../* expr */ };
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:79:73
+ --> $DIR/feature-gate-default-field-values.rs:89:73
|
LL | assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
| ^
@@ -215,7 +235,7 @@ LL | assert!(matches!(Qux:: { bar: S, baz: 42, bat: 2, bay: 4, ../*
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:82:38
+ --> $DIR/feature-gate-default-field-values.rs:92:38
|
LL | let y = Opt { mandatory: None, .. };
| ^
@@ -230,7 +250,7 @@ LL | let y = Opt { mandatory: None, ../* expr */ };
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:86:47
+ --> $DIR/feature-gate-default-field-values.rs:96:47
|
LL | assert!(matches!(Opt { mandatory: None, .. }, z));
| ^
@@ -245,7 +265,7 @@ LL | assert!(matches!(Opt { mandatory: None, ../* expr */ }, z));
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:88:30
+ --> $DIR/feature-gate-default-field-values.rs:98:30
|
LL | assert!(matches!(Opt { .. }, z));
| ^
@@ -256,7 +276,7 @@ LL | assert!(matches!(Opt { ../* expr */ }, z));
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:90:44
+ --> $DIR/feature-gate-default-field-values.rs:100:44
|
LL | assert!(matches!(Opt { optional: (), .. }, z));
| ^
@@ -267,7 +287,7 @@ LL | assert!(matches!(Opt { optional: (), ../* expr */ }, z));
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:92:61
+ --> $DIR/feature-gate-default-field-values.rs:102:61
|
LL | assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
| ^
@@ -279,7 +299,7 @@ LL + assert!(matches!(Opt { optional: (), mandatory: None, }, z));
|
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:94:51
+ --> $DIR/feature-gate-default-field-values.rs:104:51
|
LL | let y = OptEnum::Variant { mandatory: None, .. };
| ^
@@ -294,7 +314,7 @@ LL | let y = OptEnum::Variant { mandatory: None, ../* expr */ };
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:98:60
+ --> $DIR/feature-gate-default-field-values.rs:108:60
|
LL | assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
| ^
@@ -309,7 +329,7 @@ LL | assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z)
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:100:43
+ --> $DIR/feature-gate-default-field-values.rs:110:43
|
LL | assert!(matches!(OptEnum::Variant { .. }, z));
| ^
@@ -320,7 +340,7 @@ LL | assert!(matches!(OptEnum::Variant { ../* expr */ }, z));
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:102:57
+ --> $DIR/feature-gate-default-field-values.rs:112:57
|
LL | assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
| ^
@@ -331,7 +351,7 @@ LL | assert!(matches!(OptEnum::Variant { optional: (), ../* expr */ }, z));
| ++++++++++
error[E0797]: base expression required after `..`
- --> $DIR/feature-gate-default-field-values.rs:104:74
+ --> $DIR/feature-gate-default-field-values.rs:114:74
|
LL | assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
| ^
@@ -342,7 +362,7 @@ LL - assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }
LL + assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, }, z));
|
-error: aborting due to 29 previous errors
+error: aborting due to 31 previous errors
Some errors have detailed explanations: E0658, E0797.
For more information about an error, try `rustc --explain E0658`.
diff --git a/tests/ui/structs/default-field-values/failures.rs b/tests/ui/structs/default-field-values/failures.rs
index dee6566bd0ea1..9c5b7172929c6 100644
--- a/tests/ui/structs/default-field-values/failures.rs
+++ b/tests/ui/structs/default-field-values/failures.rs
@@ -49,6 +49,12 @@ enum E {
Variant {} //~ ERROR the `#[default]` attribute may only be used on unit enum variants
}
+union U
+{
+ x: i32 = 1, //~ ERROR unions cannot have default field values
+ y: f32 = 2., //~ ERROR unions cannot have default field values
+}
+
fn main () {
let _ = Foo { .. }; // ok
let _ = Foo::default(); // ok
diff --git a/tests/ui/structs/default-field-values/failures.stderr b/tests/ui/structs/default-field-values/failures.stderr
index aaa75fd3180c5..5e3d4c89c2a3c 100644
--- a/tests/ui/structs/default-field-values/failures.stderr
+++ b/tests/ui/structs/default-field-values/failures.stderr
@@ -12,6 +12,18 @@ error: default fields are not supported in tuple structs
LL | pub struct Rak(i32 = 42);
| ^^ default fields are only supported on structs
+error: unions cannot have default field values
+ --> $DIR/failures.rs:54:14
+ |
+LL | x: i32 = 1,
+ | ^
+
+error: unions cannot have default field values
+ --> $DIR/failures.rs:55:14
+ |
+LL | y: f32 = 2.,
+ | ^^
+
error[E0277]: the trait bound `S: Default` is not satisfied
--> $DIR/failures.rs:16:5
|
@@ -28,19 +40,19 @@ LL | pub struct S;
|
error: missing field `bar` in initializer
- --> $DIR/failures.rs:55:19
+ --> $DIR/failures.rs:61:19
|
LL | let _ = Bar { .. };
| ^ fields that do not have a defaulted value must be provided explicitly
error: missing field `bar` in initializer
- --> $DIR/failures.rs:56:27
+ --> $DIR/failures.rs:62:27
|
LL | let _ = Bar { baz: 0, .. };
| ^ fields that do not have a defaulted value must be provided explicitly
error[E0308]: mismatched types
- --> $DIR/failures.rs:60:17
+ --> $DIR/failures.rs:66:17
|
LL | let _ = Rak(..);
| --- ^^ expected `i32`, found `RangeFull`
@@ -53,19 +65,19 @@ note: tuple struct defined here
LL | pub struct Rak(i32 = 42);
| ^^^
help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
- --> $DIR/failures.rs:60:17
+ --> $DIR/failures.rs:66:17
|
LL | let _ = Rak(..);
| ^^
error[E0061]: this struct takes 1 argument but 2 arguments were supplied
- --> $DIR/failures.rs:62:13
+ --> $DIR/failures.rs:68:13
|
LL | let _ = Rak(0, ..);
| ^^^ -- unexpected argument #2 of type `RangeFull`
|
help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
- --> $DIR/failures.rs:62:20
+ --> $DIR/failures.rs:68:20
|
LL | let _ = Rak(0, ..);
| ^^
@@ -81,13 +93,13 @@ LL + let _ = Rak(0);
|
error[E0061]: this struct takes 1 argument but 2 arguments were supplied
- --> $DIR/failures.rs:64:13
+ --> $DIR/failures.rs:70:13
|
LL | let _ = Rak(.., 0);
| ^^^ -- unexpected argument #1 of type `RangeFull`
|
help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
- --> $DIR/failures.rs:64:17
+ --> $DIR/failures.rs:70:17
|
LL | let _ = Rak(.., 0);
| ^^
@@ -102,7 +114,7 @@ LL - let _ = Rak(.., 0);
LL + let _ = Rak(0);
|
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
Some errors have detailed explanations: E0061, E0277, E0308.
For more information about an error, try `rustc --explain E0061`.
| | |