Auto merge of #129115 - jieyouxu:reenable-dump-ice, r=estebank
Re-enable `dump-ice-to-disk` for Windows
This test was previously flakey on `i686-mingw` (reason unknown), but since some modifications (quarantining each ICE test in separate tmp dirs, adding/removing `RUSTC_ICE` env vars as suitable to prevent any kind of environmental influence), I could no longer make it fail on `i686-mingw`.
I tried running this test (without the `ignore-windows` of course) a bunch of times via `i686-mingw` try jobs and it refused to fail (see #128958). I was also never able to reproduce the failure locally.
In any case, if this turns out to be still flakey on `i686-mingw`, we can revert the removal of `ignore-windows` but this time we'll have way more context for why the test failed.
Running the `i686-mingw` alongside some Windows jobs for basic santiy check. But the try jobs succeeding is insufficient to guarantee reproducibility.
cc #129115 for backlink.
try-job: x86_64-msvc
try-job: x86_64-mingw
try-job: i686-msvc
try-job: i686-mingw
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index b137497..5e54cee 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -67,7 +67,7 @@
- name: cargo update rustbook
run: |
echo -e "\nrustbook dependencies:" >> cargo_update.log
- cargo update --manifest-path src/tools/rustbook 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
+ cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: upload Cargo.lock artifact for use in PR
uses: actions/upload-artifact@v4
with:
diff --git a/Cargo.lock b/Cargo.lock
index 4bd99b7..0b546d6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1775,9 +1775,9 @@
[[package]]
name = "indexmap"
-version = "2.2.6"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
dependencies = [
"equivalent",
"hashbrown",
@@ -3149,6 +3149,7 @@
"gimli 0.31.0",
"object 0.36.2",
"regex",
+ "serde_json",
"similar",
"wasmparser 0.214.0",
]
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 300bfa1..9c07313 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -189,7 +189,7 @@ fn lower_delegation_sig(
) -> hir::FnSig<'hir> {
let header = if let Some(local_sig_id) = sig_id.as_local() {
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
- Some(sig) => self.lower_fn_header(sig.header),
+ Some(sig) => self.lower_fn_header(sig.header, hir::Safety::Safe),
None => self.generate_header_error(),
}
} else {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 7af3945..f606525 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -237,7 +237,7 @@ fn lower_item_kind(
});
let sig = hir::FnSig {
decl,
- header: this.lower_fn_header(*header),
+ header: this.lower_fn_header(*header, hir::Safety::Safe),
span: this.lower_span(*fn_sig_span),
};
hir::ItemKind::Fn(sig, generics, body_id)
@@ -668,7 +668,7 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
ForeignItemKind::Fn(box Fn { sig, generics, .. }) => {
let fdec = &sig.decl;
let itctx = ImplTraitContext::Universal;
- let (generics, (fn_dec, fn_args)) =
+ let (generics, (decl, fn_args)) =
self.lower_generics(generics, Const::No, false, i.id, itctx, |this| {
(
// Disallow `impl Trait` in foreign items.
@@ -682,9 +682,15 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir
this.lower_fn_params_to_names(fdec),
)
});
- let safety = self.lower_safety(sig.header.safety, hir::Safety::Unsafe);
- hir::ForeignItemKind::Fn(fn_dec, fn_args, generics, safety)
+ // Unmarked safety in unsafe block defaults to unsafe.
+ let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe);
+
+ hir::ForeignItemKind::Fn(
+ hir::FnSig { header, decl, span: self.lower_span(sig.span) },
+ fn_args,
+ generics,
+ )
}
ForeignItemKind::Static(box StaticItem { ty, mutability, expr: _, safety }) => {
let ty = self
@@ -1390,7 +1396,7 @@ fn lower_method_sig(
coroutine_kind: Option<CoroutineKind>,
parent_constness: Const,
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
- let header = self.lower_fn_header(sig.header);
+ let header = self.lower_fn_header(sig.header, hir::Safety::Safe);
// Don't pass along the user-provided constness of trait associated functions; we don't want to
// synthesize a host effect param for them. We reject `const` on them during AST validation.
let constness =
@@ -1403,14 +1409,18 @@ fn lower_method_sig(
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
- pub(super) fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
+ pub(super) fn lower_fn_header(
+ &mut self,
+ h: FnHeader,
+ default_safety: hir::Safety,
+ ) -> hir::FnHeader {
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
hir::IsAsync::Async(span)
} else {
hir::IsAsync::NotAsync
};
hir::FnHeader {
- safety: self.lower_safety(h.safety, hir::Safety::Safe),
+ safety: self.lower_safety(h.safety, default_safety),
asyncness: asyncness,
constness: self.lower_constness(h.constness),
abi: self.lower_extern(h.ext),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a353c79..837cb80 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -887,7 +887,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_attribute(&mut self, attr: &Attribute) {
- validate_attr::check_attr(&self.features, &self.session.psess, attr);
+ validate_attr::check_attr(&self.session.psess, attr);
}
fn visit_ty(&mut self, ty: &'a Ty) {
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 3ceb8e0..214a37b 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -559,7 +559,6 @@ macro_rules! gate_all {
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
gate_all!(global_registration, "global registration is experimental");
- gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental");
gate_all!(return_type_notation, "return type notation is experimental");
if !visitor.features.never_patterns {
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index ed54c0c..ae2627d 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -328,7 +328,7 @@ pub fn parse_asm_args<'a>(
/// Otherwise, the suggestion will be incorrect.
fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
// Tool-only output
- let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
+ let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
}
@@ -338,7 +338,7 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
/// Otherwise, the suggestion will be incorrect.
fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
// Tool-only output
- let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
+ let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span });
}
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 006b6aa..3d3bd3a 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -47,7 +47,6 @@ fn expand(
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
validate_attr::check_builtin_meta_item(
- &ecx.ecfg.features,
&ecx.sess.psess,
meta_item,
ast::AttrStyle::Outer,
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index 57bddf0..e8704bc 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -38,7 +38,6 @@ fn expand(
let template =
AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
validate_attr::check_builtin_meta_item(
- features,
&sess.psess,
meta_item,
ast::AttrStyle::Outer,
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 73cc8ff..0bcd5ae 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -17,7 +17,6 @@ pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaI
// All the built-in macro attributes are "words" at the moment.
let template = AttributeTemplate { word: true, ..Default::default() };
validate_attr::check_builtin_meta_item(
- &ecx.ecfg.features,
&ecx.sess.psess,
meta_item,
AttrStyle::Outer,
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index a2ab19a..2120fc1 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -106,9 +106,11 @@ fn build(mut self: Box<Self>, output: &Path) -> bool {
impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a> {
- // FIXME use ArArchiveBuilder on most targets again once reading thin archives is
- // implemented
- if true {
+ // Keeping LlvmArchiveBuilder around in case of a regression caused by using
+ // ArArchiveBuilder.
+ // FIXME(#128955) remove a couple of months after #128936 gets merged in case
+ // no regression is found.
+ if false {
Box::new(LlvmArchiveBuilder { sess, additions: Vec::new() })
} else {
Box::new(ArArchiveBuilder::new(sess, &LLVM_OBJECT_READER))
@@ -198,25 +200,11 @@ fn create_dll_import_lib(
get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment,
};
-fn should_use_llvm_reader(buf: &[u8]) -> bool {
- let is_bitcode = unsafe { llvm::LLVMRustIsBitcode(buf.as_ptr(), buf.len()) };
-
- // COFF bigobj file, msvc LTO file or import library. See
- // https://github.com/llvm/llvm-project/blob/453f27bc9/llvm/lib/BinaryFormat/Magic.cpp#L38-L51
- let is_unsupported_windows_obj_file = buf.get(0..4) == Some(b"\0\0\xFF\xFF");
-
- is_bitcode || is_unsupported_windows_obj_file
-}
-
#[deny(unsafe_op_in_unsafe_fn)]
fn get_llvm_object_symbols(
buf: &[u8],
f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
) -> io::Result<bool> {
- if !should_use_llvm_reader(buf) {
- return (DEFAULT_OBJECT_READER.get_symbols)(buf, f);
- }
-
let mut state = Box::new(f);
let err = unsafe {
@@ -253,18 +241,10 @@ fn get_llvm_object_symbols(
}
fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool {
- if !should_use_llvm_reader(buf) {
- return (DEFAULT_OBJECT_READER.is_64_bit_object_file)(buf);
- }
-
unsafe { llvm::LLVMRustIs64BitSymbolicFile(buf.as_ptr(), buf.len()) }
}
fn llvm_is_ec_object_file(buf: &[u8]) -> bool {
- if !should_use_llvm_reader(buf) {
- return (DEFAULT_OBJECT_READER.is_ec_object_file)(buf);
- }
-
unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) }
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index efe6168..0a02c23 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -88,7 +88,7 @@ fn make_mir_scope<'ll, 'tcx>(
let loc = cx.lookup_debug_loc(scope_data.span.lo());
let file_metadata = file_metadata(cx, &loc.file);
- let parent_dbg_scope = match scope_data.inlined {
+ let dbg_scope = match scope_data.inlined {
Some((callee, _)) => {
// FIXME(eddyb) this would be `self.monomorphize(&callee)`
// if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
@@ -102,17 +102,15 @@ fn make_mir_scope<'ll, 'tcx>(
cx.dbg_scope_fn(callee, callee_fn_abi, None)
})
}
- None => parent_scope.dbg_scope,
- };
-
- let dbg_scope = unsafe {
- llvm::LLVMRustDIBuilderCreateLexicalBlock(
- DIB(cx),
- parent_dbg_scope,
- file_metadata,
- loc.line,
- loc.col,
- )
+ None => unsafe {
+ llvm::LLVMRustDIBuilderCreateLexicalBlock(
+ DIB(cx),
+ parent_scope.dbg_scope,
+ file_metadata,
+ loc.line,
+ loc.col,
+ )
+ },
};
let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index 1300663..1810220 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -2,7 +2,7 @@
use libc::c_uint;
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
-use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
+use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::ConstMethods;
use rustc_index::IndexVec;
use rustc_middle::bug;
@@ -12,7 +12,7 @@
use smallvec::smallvec;
use crate::common::CodegenCx;
-use crate::debuginfo::metadata::enums::{tag_base_type, DiscrResult};
+use crate::debuginfo::metadata::enums::DiscrResult;
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
use crate::debuginfo::metadata::{
build_field_di_node, file_metadata, size_and_align_of, type_di_node, unknown_file_metadata,
@@ -190,7 +190,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
let enum_type_and_layout = cx.layout_of(enum_type);
let enum_type_name = compute_debuginfo_type_name(cx.tcx, enum_type, false);
- assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
+ assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
type_map::build_type_with_children(
cx,
@@ -265,7 +265,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
let coroutine_type_and_layout = cx.layout_of(coroutine_type);
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
- assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
+ assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));
type_map::build_type_with_children(
cx,
@@ -381,7 +381,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
tag_field: usize,
untagged_variant_index: Option<VariantIdx>,
) -> SmallVec<&'ll DIType> {
- let tag_base_type = super::tag_base_type(cx, enum_type_and_layout);
+ let tag_base_type = tag_base_type(cx.tcx, enum_type_and_layout);
let variant_names_type_di_node = build_variant_names_type_di_node(
cx,
@@ -676,7 +676,7 @@ fn build_union_fields_for_direct_tag_coroutine<'ll, 'tcx>(
let variant_range = coroutine_args.variant_range(coroutine_def_id, cx.tcx);
let variant_count = (variant_range.start.as_u32()..variant_range.end.as_u32()).len();
- let tag_base_type = tag_base_type(cx, coroutine_type_and_layout);
+ let tag_base_type = tag_base_type(cx.tcx, coroutine_type_and_layout);
let variant_names_type_di_node = build_variant_names_type_di_node(
cx,
@@ -803,7 +803,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
assert_eq!(
cx.size_and_align_of(enum_type_and_layout.field(cx, tag_field).ty),
- cx.size_and_align_of(super::tag_base_type(cx, enum_type_and_layout))
+ cx.size_and_align_of(self::tag_base_type(cx.tcx, enum_type_and_layout))
);
// ... and a field for the tag. If the tag is 128 bits wide, this will actually
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index fc3adaf..77cbcd8 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -1,17 +1,15 @@
use std::borrow::Cow;
use rustc_codegen_ssa::debuginfo::type_names::{compute_debuginfo_type_name, cpp_like_debuginfo};
-use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
+use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_hir::def::CtorKind;
use rustc_index::IndexSlice;
use rustc_middle::bug;
use rustc_middle::mir::CoroutineLayout;
-use rustc_middle::ty::layout::{IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty, VariantDef};
use rustc_span::Symbol;
-use rustc_target::abi::{
- FieldIdx, HasDataLayout, Integer, Primitive, TagEncoding, VariantIdx, Variants,
-};
+use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
use super::type_map::{DINodeCreationResult, UniqueTypeId};
use super::{size_and_align_of, SmallVec};
@@ -39,7 +37,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
let enum_type_and_layout = cx.layout_of(enum_type);
- if wants_c_like_enum_debuginfo(enum_type_and_layout) {
+ if wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout) {
return build_c_style_enum_di_node(cx, enum_adt_def, enum_type_and_layout);
}
@@ -74,7 +72,7 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
di_node: build_enumeration_type_di_node(
cx,
&compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
- tag_base_type(cx, enum_type_and_layout),
+ tag_base_type(cx.tcx, enum_type_and_layout),
enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
(name, discr.val)
@@ -85,48 +83,6 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
}
}
-/// Extract the type with which we want to describe the tag of the given enum or coroutine.
-fn tag_base_type<'ll, 'tcx>(
- cx: &CodegenCx<'ll, 'tcx>,
- enum_type_and_layout: TyAndLayout<'tcx>,
-) -> Ty<'tcx> {
- assert!(match enum_type_and_layout.ty.kind() {
- ty::Coroutine(..) => true,
- ty::Adt(adt_def, _) => adt_def.is_enum(),
- _ => false,
- });
-
- match enum_type_and_layout.layout.variants() {
- // A single-variant enum has no discriminant.
- Variants::Single { .. } => {
- bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
- }
-
- Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
- // Niche tags are always normalized to unsized integers of the correct size.
- match tag.primitive() {
- Primitive::Int(t, _) => t,
- Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
- // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
- Primitive::Pointer(_) => {
- // If the niche is the NULL value of a reference, then `discr_enum_ty` will be
- // a RawPtr. CodeView doesn't know what to do with enums whose base type is a
- // pointer so we fix this up to just be `usize`.
- // DWARF might be able to deal with this but with an integer type we are on
- // the safe side there too.
- cx.data_layout().ptr_sized_integer()
- }
- }
- .to_ty(cx.tcx, false)
- }
-
- Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
- // Direct tags preserve the sign.
- tag.primitive().to_ty(cx.tcx)
- }
- }
-}
-
/// Build a DW_TAG_enumeration_type debuginfo node, with the given base type and variants.
/// This is a helper function and does not register anything in the type map by itself.
///
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index d7e3b47..238fbad 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -2,7 +2,7 @@
use libc::c_uint;
use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name;
-use rustc_codegen_ssa::debuginfo::wants_c_like_enum_debuginfo;
+use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo};
use rustc_codegen_ssa::traits::ConstMethods;
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
@@ -11,7 +11,6 @@
use smallvec::smallvec;
use crate::common::CodegenCx;
-use crate::debuginfo::metadata::enums::tag_base_type;
use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
use crate::debuginfo::metadata::{
file_metadata, size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags,
@@ -54,7 +53,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
let visibility_flags = visibility_di_flags(cx, enum_adt_def.did(), enum_adt_def.did());
- assert!(!wants_c_like_enum_debuginfo(enum_type_and_layout));
+ assert!(!wants_c_like_enum_debuginfo(cx.tcx, enum_type_and_layout));
type_map::build_type_with_children(
cx,
@@ -131,7 +130,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
let containing_scope = get_namespace_for_item(cx, coroutine_def_id);
let coroutine_type_and_layout = cx.layout_of(coroutine_type);
- assert!(!wants_c_like_enum_debuginfo(coroutine_type_and_layout));
+ assert!(!wants_c_like_enum_debuginfo(cx.tcx, coroutine_type_and_layout));
let coroutine_type_name = compute_debuginfo_type_name(cx.tcx, coroutine_type, false);
@@ -321,7 +320,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
&Variants::Single { .. } => None,
&Variants::Multiple { tag_field, .. } => {
- let tag_base_type = tag_base_type(cx, enum_or_coroutine_type_and_layout);
+ let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
let (size, align) = cx.size_and_align_of(tag_base_type);
unsafe {
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index ce55d99..8eb44d1 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -307,10 +307,15 @@ fn add_archive(
let file_name = String::from_utf8(entry.name().to_vec())
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
if !skip(&file_name) {
- self.entries.push((
- file_name.into_bytes(),
- ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
- ));
+ if entry.is_thin() {
+ let member_path = archive_path.parent().unwrap().join(Path::new(&file_name));
+ self.entries.push((file_name.into_bytes(), ArchiveEntry::File(member_path)));
+ } else {
+ self.entries.push((
+ file_name.into_bytes(),
+ ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
+ ));
+ }
}
}
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
index 1eaf593..0918660 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
@@ -1,6 +1,7 @@
-use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{self};
-use rustc_target::abi::Size;
+use rustc_middle::bug;
+use rustc_middle::ty::layout::{IntegerExt, PrimitiveExt, TyAndLayout};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_target::abi::{Integer, Primitive, Size, TagEncoding, Variants};
// FIXME(eddyb) find a place for this (or a way to replace it).
pub mod type_names;
@@ -11,13 +12,25 @@
/// NOTE: This is somewhat inconsistent right now: For empty enums and enums with a single
/// fieldless variant, we generate DW_TAG_struct_type, although a
/// DW_TAG_enumeration_type would be a better fit.
-pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> bool {
+pub fn wants_c_like_enum_debuginfo<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ enum_type_and_layout: TyAndLayout<'tcx>,
+) -> bool {
match enum_type_and_layout.ty.kind() {
ty::Adt(adt_def, _) => {
if !adt_def.is_enum() {
return false;
}
+ if type_names::cpp_like_debuginfo(tcx)
+ && tag_base_type_opt(tcx, enum_type_and_layout)
+ .map(|ty| ty.primitive_size(tcx).bits())
+ == Some(128)
+ {
+ // C++-like debuginfo never uses the C-like representation for 128-bit enums.
+ return false;
+ }
+
match adt_def.variants().len() {
0 => false,
1 => {
@@ -33,3 +46,51 @@ pub fn wants_c_like_enum_debuginfo(enum_type_and_layout: TyAndLayout<'_>) -> boo
_ => false,
}
}
+
+/// Extract the type with which we want to describe the tag of the given enum or coroutine.
+pub fn tag_base_type<'tcx>(tcx: TyCtxt<'tcx>, enum_type_and_layout: TyAndLayout<'tcx>) -> Ty<'tcx> {
+ tag_base_type_opt(tcx, enum_type_and_layout).unwrap_or_else(|| {
+ bug!("tag_base_type() called for enum without tag: {:?}", enum_type_and_layout)
+ })
+}
+
+pub fn tag_base_type_opt<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ enum_type_and_layout: TyAndLayout<'tcx>,
+) -> Option<Ty<'tcx>> {
+ assert!(match enum_type_and_layout.ty.kind() {
+ ty::Coroutine(..) => true,
+ ty::Adt(adt_def, _) => adt_def.is_enum(),
+ _ => false,
+ });
+
+ match enum_type_and_layout.layout.variants() {
+ // A single-variant enum has no discriminant.
+ Variants::Single { .. } => None,
+
+ Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
+ // Niche tags are always normalized to unsized integers of the correct size.
+ Some(
+ match tag.primitive() {
+ Primitive::Int(t, _) => t,
+ Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
+ // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+ Primitive::Pointer(_) => {
+ // If the niche is the NULL value of a reference, then `discr_enum_ty` will be
+ // a RawPtr. CodeView doesn't know what to do with enums whose base type is a
+ // pointer so we fix this up to just be `usize`.
+ // DWARF might be able to deal with this but with an integer type we are on
+ // the safe side there too.
+ tcx.data_layout.ptr_sized_integer()
+ }
+ }
+ .to_ty(tcx, false),
+ )
+ }
+
+ Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, .. } => {
+ // Direct tags preserve the sign.
+ Some(tag.primitive().to_ty(tcx))
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 359043a..f0bc435 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -85,7 +85,7 @@ fn push_debuginfo_type_name<'tcx>(
let layout_for_cpp_like_fallback = if cpp_like_debuginfo && def.is_enum() {
match tcx.layout_of(ParamEnv::reveal_all().and(t)) {
Ok(layout) => {
- if !wants_c_like_enum_debuginfo(layout) {
+ if !wants_c_like_enum_debuginfo(tcx, layout) {
Some(layout)
} else {
// This is a C-like enum so we don't want to use the fallback encoding
@@ -106,6 +106,7 @@ fn push_debuginfo_type_name<'tcx>(
if let Some(ty_and_layout) = layout_for_cpp_like_fallback {
msvc_enum_fallback(
+ tcx,
ty_and_layout,
&|output, visited| {
push_item_name(tcx, def.did(), true, output);
@@ -421,6 +422,7 @@ fn push_debuginfo_type_name<'tcx>(
if cpp_like_debuginfo && t.is_coroutine() {
let ty_and_layout = tcx.layout_of(ParamEnv::reveal_all().and(t)).unwrap();
msvc_enum_fallback(
+ tcx,
ty_and_layout,
&|output, visited| {
push_closure_or_coroutine_name(tcx, def_id, args, true, output, visited);
@@ -455,12 +457,13 @@ fn push_debuginfo_type_name<'tcx>(
// debugger. For more information, look in
// rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs.
fn msvc_enum_fallback<'tcx>(
+ tcx: TyCtxt<'tcx>,
ty_and_layout: TyAndLayout<'tcx>,
push_inner: &dyn Fn(/*output*/ &mut String, /*visited*/ &mut FxHashSet<Ty<'tcx>>),
output: &mut String,
visited: &mut FxHashSet<Ty<'tcx>>,
) {
- assert!(!wants_c_like_enum_debuginfo(ty_and_layout));
+ assert!(!wants_c_like_enum_debuginfo(tcx, ty_and_layout));
output.push_str("enum2$<");
push_inner(output, visited);
push_close_angle_bracket(true, output);
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 0e49597..7569254 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -1,3 +1,4 @@
+use std::collections::hash_map::Entry;
use std::ops::Range;
use rustc_data_structures::fx::FxHashMap;
@@ -447,6 +448,7 @@ pub fn compute_per_local_var_debug_info(
}
let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls);
+ let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default();
for var in &self.mir.var_debug_info {
let dbg_scope_and_span = if full_debug_info {
self.adjusted_span_and_dbg_scope(var.source_info)
@@ -491,7 +493,18 @@ pub fn compute_per_local_var_debug_info(
VariableKind::LocalVariable
};
- self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
+ if let VariableKind::ArgumentVariable(arg_index) = var_kind {
+ match params_seen.entry((dbg_scope, arg_index)) {
+ Entry::Occupied(o) => o.get().clone(),
+ Entry::Vacant(v) => v
+ .insert(
+ self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span),
+ )
+ .clone(),
+ }
+ } else {
+ self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
+ }
});
let fragment = if let Some(ref fragment) = var.composite {
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 4ce0726..de94d87 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -106,7 +106,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
locals: locals::Locals<'tcx, Bx::Value>,
/// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
- /// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed.
+ /// This is `None` if no variable debuginfo/names are needed.
per_local_var_debug_info:
Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>>,
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 81e9641..c5e2d55 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -1,4 +1,5 @@
use std::any::Any;
+use std::hash::Hash;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_data_structures::fx::FxIndexMap;
@@ -30,7 +31,7 @@ pub trait BackendTypes {
// FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `Dbg`, `Debug`, `DebugInfo`, `DI` etc.).
- type DIScope: Copy;
+ type DIScope: Copy + Hash + PartialEq + Eq;
type DILocation: Copy;
type DIVariable: Copy;
}
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 7804042..d825a47 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -6,7 +6,6 @@
#![feature(box_patterns)]
#![feature(decl_macro)]
#![feature(if_let_guard)]
-#![feature(is_none_or)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(rustdoc_internals)]
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 3794a6e..69cbf8c 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -10,7 +10,7 @@
either = "1.0"
elsa = "=1.7.1"
ena = "0.14.3"
-indexmap = { version = "2.0.0" }
+indexmap = { version = "2.4.0" }
jobserver_crate = { version = "0.1.28", package = "jobserver" }
measureme = "11"
rustc-hash = "1.1.0"
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index f6bf9f5..b0d3fec 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -265,12 +265,7 @@ fn process_cfg_attr(&self, attr: &Attribute) -> Vec<Attribute> {
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
- validate_attr::check_attribute_safety(
- self.features.unwrap_or(&Features::default()),
- &self.sess.psess,
- AttributeSafety::Normal,
- &cfg_attr,
- );
+ validate_attr::check_attribute_safety(&self.sess.psess, AttributeSafety::Normal, &cfg_attr);
let Some((cfg_predicate, expanded_attrs)) =
rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess)
@@ -395,11 +390,7 @@ pub(crate) fn cfg_true(&self, attr: &Attribute) -> (bool, Option<MetaItem>) {
}
};
- validate_attr::deny_builtin_meta_unsafety(
- self.features.unwrap_or(&Features::default()),
- &self.sess.psess,
- &meta_item,
- );
+ validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item);
(
parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 37679e1..cb6b132 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1882,7 +1882,7 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
let mut span: Option<Span> = None;
while let Some(attr) = attrs.next() {
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
- validate_attr::check_attr(features, &self.cx.sess.psess, attr);
+ validate_attr::check_attr(&self.cx.sess.psess, attr);
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
span = Some(current_span);
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 6f17710..256713e 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1154,7 +1154,7 @@ fn check_matcher_core<'tt>(
&& matches!(kind, NonterminalKind::Pat(PatParam { inferred: true }))
&& matches!(
next_token,
- TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or)
+ TokenTree::Token(token) if *token == BinOp(token::BinOpToken::Or)
)
{
// It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index e5a1c6c..b2f7c8f 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -54,18 +54,24 @@ pub(super) fn parse(
// For each token tree in `input`, parse the token into a `self::TokenTree`, consuming
// additional trees if need be.
- let mut trees = input.trees();
+ let mut trees = input.trees().peekable();
while let Some(tree) = trees.next() {
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
let tree = parse_tree(tree, &mut trees, parsing_patterns, sess, node_id, features, edition);
match tree {
TokenTree::MetaVar(start_sp, ident) if parsing_patterns => {
- let span = match trees.next() {
+ // Not consuming the next token immediately, as it may not be a colon
+ let span = match trees.peek() {
Some(&tokenstream::TokenTree::Token(
Token { kind: token::Colon, span: colon_span },
_,
)) => {
+ // Consume the colon first
+ trees.next();
+
+ // It's ok to consume the next tree no matter how,
+ // since if it's not a token then it will be an invalid declaration.
match trees.next() {
Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
Some((fragment, _)) => {
@@ -125,12 +131,13 @@ pub(super) fn parse(
}
_ => token.span,
},
- Some(tree) => tree.span(),
- None => colon_span,
+ // Invalid, return a nice source location
+ _ => colon_span.with_lo(start_sp.lo()),
}
}
- Some(tree) => tree.span(),
- None => start_sp,
+ // Whether it's none or some other tree, it doesn't belong to
+ // the current meta variable, returning the original span.
+ _ => start_sp,
};
result.push(TokenTree::MetaVarDecl(span, ident, None));
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 03b40e2..3d5ecba 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -392,6 +392,8 @@ macro_rules! declare_features {
(accepted, universal_impl_trait, "1.26.0", Some(34511)),
/// Allows arbitrary delimited token streams in non-macro attributes.
(accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208)),
+ /// Allows unsafe attributes.
+ (accepted, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)),
/// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
(accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668)),
/// Allows unsafe on extern declarations and safety qualifiers over internal items.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index d593f05..d4c54b6 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -578,12 +578,6 @@ pub struct BuiltinAttribute {
EncodeCrossCrate::No, coroutines, experimental!(coroutines)
),
- // `#[pointee]` attribute to designate the pointee type in SmartPointer derive-macro
- gated!(
- pointee, Normal, template!(Word), ErrorFollowing,
- EncodeCrossCrate::No, derive_smart_pointer, experimental!(pointee)
- ),
-
// RFC 3543
// `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
gated!(
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 24f691e..459df9e 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -622,8 +622,6 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
/// Allows unnamed fields of struct and union type
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
- /// Allows unsafe attributes.
- (unstable, unsafe_attributes, "1.80.0", Some(123757)),
/// Allows const generic parameters to be defined with types that
/// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
(incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 33e8432..6599e70 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3586,7 +3586,7 @@ pub fn foreign_item_id(&self) -> ForeignItemId {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum ForeignItemKind<'hir> {
/// A foreign function.
- Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>, Safety),
+ Fn(FnSig<'hir>, &'hir [Ident], &'hir Generics<'hir>),
/// A foreign static item (`static ext: u8`).
Static(&'hir Ty<'hir>, Mutability, Safety),
/// A foreign type.
@@ -3645,7 +3645,10 @@ pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> {
match self {
OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
| OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
- | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig),
+ | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. })
+ | OwnerNode::ForeignItem(ForeignItem {
+ kind: ForeignItemKind::Fn(fn_sig, _, _), ..
+ }) => Some(fn_sig),
_ => None,
}
}
@@ -3654,11 +3657,10 @@ pub fn fn_decl(self) -> Option<&'hir FnDecl<'hir>> {
match self {
OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
| OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
- | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl),
- OwnerNode::ForeignItem(ForeignItem {
- kind: ForeignItemKind::Fn(fn_decl, _, _, _),
- ..
- }) => Some(fn_decl),
+ | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. })
+ | OwnerNode::ForeignItem(ForeignItem {
+ kind: ForeignItemKind::Fn(fn_sig, _, _), ..
+ }) => Some(fn_sig.decl),
_ => None,
}
}
@@ -3846,11 +3848,13 @@ pub fn fn_decl(self) -> Option<&'hir FnDecl<'hir>> {
match self {
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
- | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl),
- Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. })
- | Node::ForeignItem(ForeignItem {
- kind: ForeignItemKind::Fn(fn_decl, _, _, _), ..
- }) => Some(fn_decl),
+ | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. })
+ | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => {
+ Some(fn_sig.decl)
+ }
+ Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) => {
+ Some(fn_decl)
+ }
_ => None,
}
}
@@ -3874,7 +3878,10 @@ pub fn fn_sig(self) -> Option<&'hir FnSig<'hir>> {
match self {
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
- | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig),
+ | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. })
+ | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_sig, _, _), .. }) => {
+ Some(fn_sig)
+ }
_ => None,
}
}
@@ -3949,7 +3956,7 @@ pub fn body_id(&self) -> Option<BodyId> {
pub fn generics(self) -> Option<&'hir Generics<'hir>> {
match self {
Node::ForeignItem(ForeignItem {
- kind: ForeignItemKind::Fn(_, _, generics, _), ..
+ kind: ForeignItemKind::Fn(_, _, generics), ..
})
| Node::TraitItem(TraitItem { generics, .. })
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
@@ -4039,8 +4046,8 @@ mod size_asserts {
static_assert_size!(Expr<'_>, 64);
static_assert_size!(ExprKind<'_>, 48);
static_assert_size!(FnDecl<'_>, 40);
- static_assert_size!(ForeignItem<'_>, 72);
- static_assert_size!(ForeignItemKind<'_>, 40);
+ static_assert_size!(ForeignItem<'_>, 88);
+ static_assert_size!(ForeignItemKind<'_>, 56);
static_assert_size!(GenericArg<'_>, 16);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(Generics<'_>, 56);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index dd501f84..a54596e 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -611,9 +611,9 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(
try_visit!(visitor.visit_ident(foreign_item.ident));
match foreign_item.kind {
- ForeignItemKind::Fn(ref function_declaration, param_names, ref generics, _) => {
+ ForeignItemKind::Fn(ref sig, param_names, ref generics) => {
try_visit!(visitor.visit_generics(generics));
- try_visit!(visitor.visit_fn_decl(function_declaration));
+ try_visit!(visitor.visit_fn_decl(sig.decl));
walk_list!(visitor, visit_ident, param_names.iter().copied());
}
ForeignItemKind::Static(ref typ, _, _) => {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 2e778fd..0135cdf 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -804,8 +804,8 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let item = tcx.hir().foreign_item(item.id);
match &item.kind {
- hir::ForeignItemKind::Fn(fn_decl, _, _, _) => {
- require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span);
+ hir::ForeignItemKind::Fn(sig, _, _) => {
+ require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span);
}
hir::ForeignItemKind::Static(..) => {
check_static_inhabited(tcx, def_id);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 4b45ced..c2b2f08 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -30,7 +30,7 @@ fn equate_intrinsic_type<'tcx>(
let (generics, span) = match tcx.hir_node_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })
| hir::Node::ForeignItem(hir::ForeignItem {
- kind: hir::ForeignItemKind::Fn(.., generics, _),
+ kind: hir::ForeignItemKind::Fn(_, _, generics),
..
}) => (tcx.generics_of(def_id), generics.span),
_ => {
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index d3b928f..bdf2914 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -350,8 +350,8 @@ fn check_foreign_item<'tcx>(
);
match item.kind {
- hir::ForeignItemKind::Fn(decl, ..) => {
- check_item_fn(tcx, def_id, item.ident, item.span, decl)
+ hir::ForeignItemKind::Fn(sig, ..) => {
+ check_item_fn(tcx, def_id, item.ident, item.span, sig.decl)
}
hir::ForeignItemKind::Static(ty, ..) => {
check_item_type(tcx, def_id, ty.span, UnsizedHandling::AllowIfForeignTail)
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 91fa066..f75954c 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1440,11 +1440,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
}
- ForeignItem(&hir::ForeignItem {
- kind: ForeignItemKind::Fn(fn_decl, _, _, safety), ..
- }) => {
+ ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => {
let abi = tcx.hir().get_foreign_abi(hir_id);
- compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi, safety)
+ compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety)
}
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index e11d3c9..ae0c70d 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -604,7 +604,7 @@ fn visit_precise_capturing_arg(
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
match item.kind {
- hir::ForeignItemKind::Fn(_, _, generics, _) => {
+ hir::ForeignItemKind::Fn(_, _, generics) => {
self.visit_early_late(item.hir_id(), generics, |this| {
intravisit::walk_foreign_item(this, item);
})
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 089cee2..cff2117 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -352,16 +352,11 @@ fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(self.attrs(item.hir_id()));
match item.kind {
- hir::ForeignItemKind::Fn(decl, arg_names, generics, safety) => {
+ hir::ForeignItemKind::Fn(sig, arg_names, generics) => {
self.head("");
self.print_fn(
- decl,
- hir::FnHeader {
- safety,
- constness: hir::Constness::NotConst,
- abi: Abi::Rust,
- asyncness: hir::IsAsync::NotAsync,
- },
+ sig.decl,
+ sig.header,
Some(item.ident.name),
generics,
arg_names,
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 589a9c5..6b813dc 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -14,7 +14,7 @@
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::def_id::LocalDefId;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::error_reporting::traits::ArgKind;
use rustc_trait_selection::traits;
@@ -539,6 +539,10 @@ fn extract_sig_from_projection(
/// we identify the `FnOnce<Args, Output = ?Fut>` bound, and if the output type is
/// an inference variable `?Fut`, we check if that is bounded by a `Future<Output = Ty>`
/// projection.
+ ///
+ /// This function is actually best-effort with the return type; if we don't find a
+ /// `Future` projection, we still will return arguments that we extracted from the `FnOnce`
+ /// projection, and the output will be an unconstrained type variable instead.
fn extract_sig_from_projection_and_future_bound(
&self,
cause_span: Option<Span>,
@@ -564,24 +568,43 @@ fn extract_sig_from_projection_and_future_bound(
};
// FIXME: We may want to elaborate here, though I assume this will be exceedingly rare.
+ let mut return_ty = None;
for bound in self.obligations_for_self_ty(return_vid) {
if let Some(ret_projection) = bound.predicate.as_projection_clause()
&& let Some(ret_projection) = ret_projection.no_bound_vars()
&& self.tcx.is_lang_item(ret_projection.def_id(), LangItem::FutureOutput)
{
- let sig = projection.rebind(self.tcx.mk_fn_sig(
- input_tys,
- ret_projection.term.expect_type(),
- false,
- hir::Safety::Safe,
- Abi::Rust,
- ));
-
- return Some(ExpectedSig { cause_span, sig });
+ return_ty = Some(ret_projection.term.expect_type());
+ break;
}
}
- None
+ // SUBTLE: If we didn't find a `Future<Output = ...>` bound for the return
+ // vid, we still want to attempt to provide inference guidance for the async
+ // closure's arguments. Instantiate a new vid to plug into the output type.
+ //
+ // You may be wondering, what if it's higher-ranked? Well, given that we
+ // found a type variable for the `FnOnce::Output` projection above, we know
+ // that the output can't mention any of the vars.
+ //
+ // Also note that we use a fresh var here for the signature since the signature
+ // records the output of the *future*, and `return_vid` above is the type
+ // variable of the future, not its output.
+ //
+ // FIXME: We probably should store this signature inference output in a way
+ // that does not misuse a `FnSig` type, but that can be done separately.
+ let return_ty =
+ return_ty.unwrap_or_else(|| self.next_ty_var(cause_span.unwrap_or(DUMMY_SP)));
+
+ let sig = projection.rebind(self.tcx.mk_fn_sig(
+ input_tys,
+ return_ty,
+ false,
+ hir::Safety::Safe,
+ Abi::Rust,
+ ));
+
+ return Some(ExpectedSig { cause_span, sig });
}
fn sig_of_closure(
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 758a1ce..9ec1011 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -5,7 +5,6 @@
#![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(if_let_guard)]
-#![feature(is_none_or)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(try_blocks)]
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 3b71e2f..b3cf73b 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -3448,6 +3448,7 @@ fn suggest_traits_to_import(
trait_missing_method: bool,
) {
let mut alt_rcvr_sugg = false;
+ let mut trait_in_other_version_found = false;
if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
debug!(
"suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
@@ -3489,8 +3490,17 @@ fn suggest_traits_to_import(
// self types and rely on the suggestion to `use` the trait from
// `suggest_valid_traits`.
let did = Some(pick.item.container_id(self.tcx));
- let skip = skippable.contains(&did);
- if pick.autoderefs == 0 && !skip {
+ if skippable.contains(&did) {
+ continue;
+ }
+ trait_in_other_version_found = self
+ .detect_and_explain_multiple_crate_versions(
+ err,
+ pick.item.def_id,
+ rcvr.hir_id,
+ *rcvr_ty,
+ );
+ if pick.autoderefs == 0 && !trait_in_other_version_found {
err.span_label(
pick.item.ident(self.tcx).span,
format!("the method is available for `{rcvr_ty}` here"),
@@ -3675,7 +3685,32 @@ fn suggest_traits_to_import(
}
}
}
- if self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true) {
+
+ if let SelfSource::QPath(ty) = source
+ && !valid_out_of_scope_traits.is_empty()
+ && let hir::TyKind::Path(path) = ty.kind
+ && let hir::QPath::Resolved(_, path) = path
+ && let Some(def_id) = path.res.opt_def_id()
+ && let Some(assoc) = self
+ .tcx
+ .associated_items(valid_out_of_scope_traits[0])
+ .filter_by_name_unhygienic(item_name.name)
+ .next()
+ {
+ // See if the `Type::function(val)` where `function` wasn't found corresponds to a
+ // `Trait` that is imported directly, but `Type` came from a different version of the
+ // same crate.
+ let rcvr_ty = self.tcx.type_of(def_id).instantiate_identity();
+ trait_in_other_version_found = self.detect_and_explain_multiple_crate_versions(
+ err,
+ assoc.def_id,
+ ty.hir_id,
+ rcvr_ty,
+ );
+ }
+ if !trait_in_other_version_found
+ && self.suggest_valid_traits(err, item_name, valid_out_of_scope_traits, true)
+ {
return;
}
@@ -4040,6 +4075,62 @@ enum Introducer {
}
}
+ fn detect_and_explain_multiple_crate_versions(
+ &self,
+ err: &mut Diag<'_>,
+ item_def_id: DefId,
+ hir_id: hir::HirId,
+ rcvr_ty: Ty<'_>,
+ ) -> bool {
+ let hir_id = self.tcx.parent_hir_id(hir_id);
+ let Some(traits) = self.tcx.in_scope_traits(hir_id) else { return false };
+ if traits.is_empty() {
+ return false;
+ }
+ let trait_def_id = self.tcx.parent(item_def_id);
+ let krate = self.tcx.crate_name(trait_def_id.krate);
+ let name = self.tcx.item_name(trait_def_id);
+ let candidates: Vec<_> = traits
+ .iter()
+ .filter(|c| {
+ c.def_id.krate != trait_def_id.krate
+ && self.tcx.crate_name(c.def_id.krate) == krate
+ && self.tcx.item_name(c.def_id) == name
+ })
+ .map(|c| (c.def_id, c.import_ids.get(0).cloned()))
+ .collect();
+ if candidates.is_empty() {
+ return false;
+ }
+ let item_span = self.tcx.def_span(item_def_id);
+ let msg = format!(
+ "there are multiple different versions of crate `{krate}` in the dependency graph",
+ );
+ let trait_span = self.tcx.def_span(trait_def_id);
+ let mut multi_span: MultiSpan = trait_span.into();
+ multi_span.push_span_label(trait_span, format!("this is the trait that is needed"));
+ let descr = self.tcx.associated_item(item_def_id).descr();
+ multi_span
+ .push_span_label(item_span, format!("the {descr} is available for `{rcvr_ty}` here"));
+ for (def_id, import_def_id) in candidates {
+ if let Some(import_def_id) = import_def_id {
+ multi_span.push_span_label(
+ self.tcx.def_span(import_def_id),
+ format!(
+ "`{name}` imported here doesn't correspond to the right version of crate \
+ `{krate}`",
+ ),
+ );
+ }
+ multi_span.push_span_label(
+ self.tcx.def_span(def_id),
+ format!("this is the trait that was imported"),
+ );
+ }
+ err.span_note(multi_span, msg);
+ true
+ }
+
/// issue #102320, for `unwrap_or` with closure as argument, suggest `unwrap_or_else`
/// FIXME: currently not working for suggesting `map_or_else`, see #102408
pub(crate) fn suggest_else_fn_with_closure(
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 7438c97..1cb8bc8 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -188,6 +188,11 @@ pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
let min_new_len = elem.index() + 1;
self.raw.resize_with(min_new_len, fill_value);
}
+
+ #[inline]
+ pub fn append(&mut self, other: &mut Self) {
+ self.raw.append(&mut other.raw);
+ }
}
/// `IndexVec` is often used as a map, so it provides some map-like APIs.
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index e37b307..3492df6 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,7 +1,6 @@
// tidy-alphabetical-start
#![feature(decl_macro)]
#![feature(let_chains)]
-#![feature(thread_spawn_unchecked)]
#![feature(try_blocks)]
// tidy-alphabetical-end
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 6b36944..5f6e7fb 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1853,7 +1853,7 @@ fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
if !prev_dollar {
self.check_ident_token(cx, UnderMacro(true), ident);
}
- } else if token.kind == TokenKind::Dollar {
+ } else if *token == TokenKind::Dollar {
prev_dollar = true;
continue;
}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 54bf73a..cb7a071 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1734,13 +1734,16 @@ fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());
match it.kind {
- hir::ForeignItemKind::Fn(decl, _, _, _) if !vis.is_internal_abi(abi) => {
- vis.check_foreign_fn(it.owner_id.def_id, decl);
+ hir::ForeignItemKind::Fn(sig, _, _) => {
+ if vis.is_internal_abi(abi) {
+ vis.check_fn(it.owner_id.def_id, sig.decl)
+ } else {
+ vis.check_foreign_fn(it.owner_id.def_id, sig.decl);
+ }
}
hir::ForeignItemKind::Static(ty, _, _) if !vis.is_internal_abi(abi) => {
vis.check_foreign_static(it.owner_id, ty.span);
}
- hir::ForeignItemKind::Fn(decl, _, _, _) => vis.check_fn(it.owner_id.def_id, decl),
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
}
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c731b03..56d77c9 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -4971,7 +4971,6 @@
/// ### Example
///
/// ```rust
- /// #![feature(unsafe_attributes)]
/// #![warn(unsafe_attr_outside_unsafe)]
///
/// #[no_mangle]
diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
index ccf1a54..d625935 100644
--- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp
@@ -77,22 +77,18 @@
Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr =
getSymbolicFile(Buf->getMemBufferRef(), Context);
if (!ObjOrErr) {
- Error E = ObjOrErr.takeError();
- SmallString<0> ErrorBuf;
- auto Error = raw_svector_ostream(ErrorBuf);
- Error << E << '\0';
- return ErrorCallback(Error.str().data());
+ return ErrorCallback(toString(ObjOrErr.takeError()).c_str());
}
std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr);
+ if (Obj == nullptr) {
+ return 0;
+ }
for (const object::BasicSymbolRef &S : Obj->symbols()) {
if (!isArchiveSymbol(S))
continue;
if (Error E = S.printName(SymName)) {
- SmallString<0> ErrorBuf;
- auto Error = raw_svector_ostream(ErrorBuf);
- Error << E << '\0';
- return ErrorCallback(Error.str().data());
+ return ErrorCallback(toString(std::move(E)).c_str());
}
SymName << '\0';
if (void *E = Callback(State, SymNameBuf.str().data())) {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index edab6b5..0f85998 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -554,53 +554,43 @@ pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
/// }
/// ```
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
- let mut iter = self.parent_iter(id).peekable();
- let mut ignore_tail = false;
- if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
- // When dealing with `return` statements, we don't care about climbing only tail
- // expressions.
- ignore_tail = true;
- }
+ let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));
- let mut prev_hir_id = None;
- while let Some((hir_id, node)) = iter.next() {
- if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
- match next_node {
- Node::Block(Block { expr: None, .. }) => return None,
- // The current node is not the tail expression of its parent.
- Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
+ // Return `None` if the `id` expression is not the returned value of the enclosing body
+ let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
+ while let Some(cur_id) = iter.next() {
+ if enclosing_body_owner == cur_id {
+ break;
+ }
+
+ // A return statement is always the value returned from the enclosing body regardless of
+ // what the parent expressions are.
+ if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) {
+ break;
+ }
+
+ // If the current expression's value doesnt get used as the parent expressions value then return `None`
+ if let Some(&parent_id) = iter.peek() {
+ match self.tcx.hir_node(parent_id) {
+ // The current node is not the tail expression of the block expression parent expr.
+ Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None,
Node::Block(Block { expr: Some(e), .. })
if matches!(e.kind, ExprKind::If(_, _, None)) =>
{
return None;
}
+
+ // The current expression's value does not pass up through these parent expressions
+ Node::Block(Block { expr: None, .. })
+ | Node::Expr(Expr { kind: ExprKind::Loop(..), .. })
+ | Node::LetStmt(..) => return None,
+
_ => {}
}
}
- match node {
- Node::Item(_)
- | Node::ForeignItem(_)
- | Node::TraitItem(_)
- | Node::Expr(Expr { kind: ExprKind::Closure(_), .. })
- | Node::ImplItem(_)
- // The input node `id` must be enclosed in the method's body as opposed
- // to some other place such as its return type (fixes #114918).
- // We verify that indirectly by checking that the previous node is the
- // current node's body
- if node.body_id().map(|b| b.hir_id) == prev_hir_id => {
- return Some(hir_id)
- }
- // Ignore `return`s on the first iteration
- Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
- | Node::LetStmt(_) => {
- return None;
- }
- _ => {}
- }
-
- prev_hir_id = Some(hir_id);
}
- None
+
+ Some(enclosing_body_owner)
}
/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
@@ -826,6 +816,11 @@ fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) ->
})
| Node::ImplItem(ImplItem {
kind: ImplItemKind::Fn(sig, ..), span: outer_span, ..
+ })
+ | Node::ForeignItem(ForeignItem {
+ kind: ForeignItemKind::Fn(sig, ..),
+ span: outer_span,
+ ..
}) => {
// Ensure that the returned span has the item's SyntaxContext, and not the
// SyntaxContext of the visibility.
@@ -884,10 +879,7 @@ fn named_span(item_span: Span, ident: Ident, generics: Option<&Generics<'_>>) ->
},
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
- Node::ForeignItem(item) => match item.kind {
- ForeignItemKind::Fn(decl, _, _, _) => until_within(item.span, decl.output.span()),
- _ => named_span(item.span, item.ident, None),
- },
+ Node::ForeignItem(item) => named_span(item.span, item.ident, None),
Node::Ctor(_) => return self.span(self.tcx.parent_hir_id(hir_id)),
Node::Expr(Expr {
kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index fa521ab..596d9f0 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -202,7 +202,7 @@ pub fn provide(providers: &mut Providers) {
..
})
| Node::ForeignItem(&ForeignItem {
- kind: ForeignItemKind::Fn(_, idents, _, _),
+ kind: ForeignItemKind::Fn(_, idents, _),
..
}) = tcx.hir_node(tcx.local_def_id_to_hir_id(def_id))
{
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index f2d8781..5dd0e69 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1418,21 +1418,19 @@ fn alloc_ids_from_alloc(
alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id())
}
- fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
+ fn alloc_id_from_const_val(val: ConstValue<'_>) -> Option<AllocId> {
match val {
- ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
- Either::Left(std::iter::once(ptr.provenance.alloc_id()))
- }
- ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()),
- ConstValue::ZeroSized => Either::Right(std::iter::empty()),
+ ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()),
+ ConstValue::Scalar(interpret::Scalar::Int { .. }) => None,
+ ConstValue::ZeroSized => None,
ConstValue::Slice { .. } => {
// `u8`/`str` slices, shouldn't contain pointers that we want to print.
- Either::Right(std::iter::empty())
+ None
}
ConstValue::Indirect { alloc_id, .. } => {
// FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR.
// Really we'd want `pretty_print_const_value` to decide which allocations to print, instead of having a separate visitor.
- Either::Left(std::iter::once(alloc_id))
+ Some(alloc_id)
}
}
}
@@ -1443,7 +1441,9 @@ fn visit_const_operand(&mut self, c: &ConstOperand<'tcx>, _: Location) {
match c.const_ {
Const::Ty(_, _) | Const::Unevaluated(..) => {}
Const::Val(val, _) => {
- self.0.extend(alloc_ids_from_const_val(val));
+ if let Some(id) = alloc_id_from_const_val(val) {
+ self.0.insert(id);
+ }
}
}
}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 075eae0..92c8d26 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -65,10 +65,9 @@
};
use crate::traits::query::{
CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal,
- CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
- CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, DropckConstraint,
- DropckOutlivesResult, MethodAutoderefStepsResult, NoSolution, NormalizationResult,
- OutlivesBound,
+ CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal,
+ CanonicalTypeOpProvePredicateGoal, DropckConstraint, DropckOutlivesResult,
+ MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound,
};
use crate::traits::{
specialization_graph, CodegenObligationError, EvaluationResult, ImplSource,
@@ -2090,26 +2089,6 @@
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
}
- /// Do not call this query directly: part of the `Eq` type-op
- query type_op_eq(
- goal: CanonicalTypeOpEqGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
- NoSolution,
- > {
- desc { "evaluating `type_op_eq` `{:?}`", goal.value.value }
- }
-
- /// Do not call this query directly: part of the `Subtype` type-op
- query type_op_subtype(
- goal: CanonicalTypeOpSubtypeGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
- NoSolution,
- > {
- desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value }
- }
-
/// Do not call this query directly: part of the `ProvePredicate` type-op
query type_op_prove_predicate(
goal: CanonicalTypeOpProvePredicateGoal<'tcx>
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index c380019..e373292 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -305,6 +305,10 @@ fn try_from_lit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, expr: &'tcx hir::Expr<'tcx>) ->
// mir.
match tcx.at(expr.span).lit_to_const(lit_input) {
Ok(c) => return Some(c),
+ Err(_) if lit_input.ty.has_aliases() => {
+ // allow the `ty` to be an alias type, though we cannot handle it here
+ return None;
+ }
Err(e) => {
tcx.dcx().span_delayed_bug(
expr.span,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 0a277fe..d60bfb9 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -970,6 +970,10 @@ fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
/// Type utilities
impl<'tcx> Ty<'tcx> {
+ // It would be nicer if this returned the value instead of a reference,
+ // like how `Predicate::kind` and `Region::kind` do. (It would result in
+ // many fewer subsequent dereferences.) But that gives a small but
+ // noticeable performance hit. See #126069 for details.
#[inline(always)]
pub fn kind(self) -> &'tcx TyKind<'tcx> {
self.0.0
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 6120b14..5b5f97c 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -8,7 +8,7 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{HirId, Node};
+use rustc_hir::HirId;
use rustc_middle::bug;
use rustc_middle::middle::region;
use rustc_middle::thir::*;
@@ -110,11 +110,7 @@ fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Cx<'tcx> {
}
#[instrument(level = "debug", skip(self))]
- fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box<Pat<'tcx>> {
- let p = match self.tcx.hir_node(p.hir_id) {
- Node::Pat(p) => p,
- node => bug!("pattern became {:?}", node),
- };
+ fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
}
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 69d21a6..7ea36f0 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -78,6 +78,8 @@
use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
use rustc_target::abi::{FieldIdx, VariantIdx};
+use crate::pass_manager::validate_body;
+
pub struct ByMoveBody;
impl<'tcx> MirPass<'tcx> for ByMoveBody {
@@ -131,20 +133,40 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
|(parent_field_idx, parent_capture), (child_field_idx, child_capture)| {
// Store this set of additional projections (fields and derefs).
// We need to re-apply them later.
- let child_precise_captures =
- &child_capture.place.projections[parent_capture.place.projections.len()..];
+ let mut child_precise_captures = child_capture.place.projections
+ [parent_capture.place.projections.len()..]
+ .to_vec();
- // If the parent captures by-move, and the child captures by-ref, then we
- // need to peel an additional `deref` off of the body of the child.
- let needs_deref = child_capture.is_by_ref() && !parent_capture.is_by_ref();
- if needs_deref {
- assert_ne!(
- coroutine_kind,
- ty::ClosureKind::FnOnce,
+ // If the parent capture is by-ref, then we need to apply an additional
+ // deref before applying any further projections to this place.
+ if parent_capture.is_by_ref() {
+ child_precise_captures.insert(
+ 0,
+ Projection { ty: parent_capture.place.ty(), kind: ProjectionKind::Deref },
+ );
+ }
+ // If the child capture is by-ref, then we need to apply a "ref"
+ // projection (i.e. `&`) at the end. But wait! We don't have that
+ // as a projection kind. So instead, we can apply its dual and
+ // *peel* a deref off of the place when it shows up in the MIR body.
+ // Luckily, by construction this is always possible.
+ let peel_deref = if child_capture.is_by_ref() {
+ assert!(
+ parent_capture.is_by_ref() || coroutine_kind != ty::ClosureKind::FnOnce,
"`FnOnce` coroutine-closures return coroutines that capture from \
their body; it will always result in a borrowck error!"
);
- }
+ true
+ } else {
+ false
+ };
+
+ // Regarding the behavior above, you may think that it's redundant to both
+ // insert a deref and then peel a deref if the parent and child are both
+ // captured by-ref. This would be correct, except for the case where we have
+ // precise capturing projections, since the inserted deref is to the *beginning*
+ // and the peeled deref is at the *end*. I cannot seem to actually find a
+ // case where this happens, though, but let's keep this code flexible.
// Finally, store the type of the parent's captured place. We need
// this when building the field projection in the MIR body later on.
@@ -164,7 +186,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
(
FieldIdx::from_usize(parent_field_idx + num_args),
parent_capture_ty,
- needs_deref,
+ peel_deref,
child_precise_captures,
),
)
@@ -192,6 +214,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
let mut by_move_body = body.clone();
MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
+
+ // Let's just always validate this body.
+ validate_body(tcx, &mut by_move_body, "Initial coroutine_by_move body".to_string());
+
// FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body.
by_move_body.source = mir::MirSource::from_instance(InstanceKind::CoroutineKindShim {
coroutine_def_id: coroutine_def_id.to_def_id(),
@@ -202,7 +228,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
struct MakeByMoveBody<'tcx> {
tcx: TyCtxt<'tcx>,
- field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>,
+ field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, Vec<Projection<'tcx>>)>,
by_move_coroutine_ty: Ty<'tcx>,
}
@@ -223,14 +249,14 @@ fn visit_place(
if place.local == ty::CAPTURE_STRUCT_LOCAL
&& let Some((&mir::ProjectionElem::Field(idx, _), projection)) =
place.projection.split_first()
- && let Some(&(remapped_idx, remapped_ty, needs_deref, bridging_projections)) =
+ && let Some(&(remapped_idx, remapped_ty, peel_deref, ref bridging_projections)) =
self.field_remapping.get(&idx)
{
// As noted before, if the parent closure captures a field by value, and
// the child captures a field by ref, then for the by-move body we're
// generating, we also are taking that field by value. Peel off a deref,
// since a layer of ref'ing has now become redundant.
- let final_projections = if needs_deref {
+ let final_projections = if peel_deref {
let Some((mir::ProjectionElem::Deref, projection)) = projection.split_first()
else {
bug!(
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 324ddc5..61fc5fc 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -726,7 +726,7 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
// Insert all of the (mapped) parts of the callee body into the caller.
caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
- caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
+ caller_body.source_scopes.append(&mut callee_body.source_scopes);
if self
.tcx
.sess
@@ -740,7 +740,7 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
// still getting consistent results from the mir-opt tests.
caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
}
- caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
+ caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut());
caller_body[callsite.block].terminator = Some(Terminator {
source_info: callsite.source_info,
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index f96329a..610ad41 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -371,7 +371,7 @@ fn merge_codegen_units<'tcx>(
// Move the items from `cgu_src` to `cgu_dst`. Some of them may be
// duplicate inlined items, in which case the destination CGU is
// unaffected. Recalculate size estimates afterwards.
- cgu_dst.items_mut().extend(cgu_src.items_mut().drain(..));
+ cgu_dst.items_mut().append(cgu_src.items_mut());
cgu_dst.compute_size_estimate();
// Record that `cgu_dst` now contains all the stuff that was in
@@ -410,7 +410,7 @@ fn merge_codegen_units<'tcx>(
// Move the items from `smallest` to `second_smallest`. Some of them
// may be duplicate inlined items, in which case the destination CGU is
// unaffected. Recalculate size estimates afterwards.
- second_smallest.items_mut().extend(smallest.items_mut().drain(..));
+ second_smallest.items_mut().append(smallest.items_mut());
second_smallest.compute_size_estimate();
// Don't update `cgu_contents`, that's only for incremental builds.
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index fb4ed5b..e7a7105 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -229,7 +229,7 @@ fn bump(&mut self, glue: bool) -> (Token, Spacing) {
} else {
let this_spacing = if next_tok.is_punct() {
Spacing::Joint
- } else if next_tok.kind == token::Eof {
+ } else if next_tok == token::Eof {
Spacing::Alone
} else {
Spacing::JointHidden
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 8fdfbce..6391ff9 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -4,11 +4,14 @@
use rustc_errors::codes::*;
use rustc_errors::{Diag, PResult};
use rustc_span::symbol::kw;
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{BytePos, Span};
use thin_vec::ThinVec;
use tracing::debug;
-use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle};
+use super::{
+ AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle, Trailing,
+ UsePreAttrPos,
+};
use crate::{errors, fluent_generated as fluent, maybe_whole};
// Public for rustfmt usage
@@ -162,7 +165,7 @@ fn annotate_following_item_if_applicable(
}
loop {
// skip any other attributes, we want the item
- if snapshot.token.kind == token::Pound {
+ if snapshot.token == token::Pound {
if let Err(err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) {
err.cancel();
return Some(replacement_span);
@@ -257,11 +260,11 @@ pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerA
pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> {
maybe_whole!(self, NtMeta, |attr| attr.into_inner());
- let do_parse = |this: &mut Self, _empty_attrs| {
+ // Attr items don't have attributes.
+ self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| {
let is_unsafe = this.eat_keyword(kw::Unsafe);
let unsafety = if is_unsafe {
let unsafe_span = this.prev_token.span;
- this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
this.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
ast::Safety::Unsafe(unsafe_span)
} else {
@@ -273,10 +276,12 @@ pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, as
if is_unsafe {
this.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
}
- Ok((ast::AttrItem { unsafety, path, args, tokens: None }, false))
- };
- // Attr items don't have attributes.
- self.collect_tokens_trailing_token(AttrWrapper::empty(), force_collect, do_parse)
+ Ok((
+ ast::AttrItem { unsafety, path, args, tokens: None },
+ Trailing::No,
+ UsePreAttrPos::No,
+ ))
+ })
}
/// Parses attributes that appear after the opening of an item. These should
@@ -309,8 +314,8 @@ pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> {
};
if let Some(attr) = attr {
// If we are currently capturing tokens (i.e. we are within a call to
- // `Parser::collect_tokens_trailing_tokens`) record the token positions of this
- // inner attribute, for possible later processing in a `LazyAttrTokenStream`.
+ // `Parser::collect_tokens`) record the token positions of this inner attribute,
+ // for possible later processing in a `LazyAttrTokenStream`.
if let Capturing::Yes = self.capture_state.capturing {
let end_pos = self.num_bump_calls;
let parser_range = ParserRange(start_pos..end_pos);
@@ -343,7 +348,7 @@ pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrIt
// Presumably, the majority of the time there will only be one attr.
let mut expanded_attrs = Vec::with_capacity(1);
- while self.token.kind != token::Eof {
+ while self.token != token::Eof {
let lo = self.token.span;
let item = self.parse_attr_item(ForceCollect::Yes)?;
expanded_attrs.push((item, lo.to(self.prev_token.span)));
@@ -359,7 +364,7 @@ pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrIt
pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::NestedMetaItem>> {
// Presumably, the majority of the time there will only be one attr.
let mut nmis = ThinVec::with_capacity(1);
- while self.token.kind != token::Eof {
+ while self.token != token::Eof {
nmis.push(self.parse_meta_item_inner()?);
if !self.eat(&token::Comma) {
break;
@@ -400,7 +405,6 @@ pub fn parse_meta_item(
};
let unsafety = if is_unsafe {
let unsafe_span = self.prev_token.span;
- self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span);
self.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
ast::Safety::Unsafe(unsafe_span)
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index abf6103..49df281 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -12,9 +12,23 @@
use super::{
Capturing, FlatToken, ForceCollect, NodeRange, NodeReplacement, Parser, ParserRange,
- TokenCursor,
+ TokenCursor, Trailing,
};
+// When collecting tokens, this fully captures the start point. Usually its
+// just after outer attributes, but occasionally it's before.
+#[derive(Clone, Debug)]
+pub(super) struct CollectPos {
+ start_token: (Token, Spacing),
+ cursor_snapshot: TokenCursor,
+ start_pos: u32,
+}
+
+pub(super) enum UsePreAttrPos {
+ No,
+ Yes,
+}
+
/// A wrapper type to ensure that the parser handles outer attributes correctly.
/// When we parse outer attributes, we need to ensure that we capture tokens
/// for the attribute target. This allows us to perform cfg-expansion on
@@ -22,30 +36,32 @@
///
/// This wrapper prevents direct access to the underlying `ast::AttrVec`.
/// Parsing code can only get access to the underlying attributes
-/// by passing an `AttrWrapper` to `collect_tokens_trailing_token`.
+/// by passing an `AttrWrapper` to `collect_tokens`.
/// This makes it difficult to accidentally construct an AST node
/// (which stores an `ast::AttrVec`) without first collecting tokens.
///
/// This struct has its own module, to ensure that the parser code
/// cannot directly access the `attrs` field.
#[derive(Debug, Clone)]
-pub struct AttrWrapper {
+pub(super) struct AttrWrapper {
attrs: AttrVec,
// The start of the outer attributes in the parser's token stream.
// This lets us create a `NodeReplacement` for the entire attribute
- // target, including outer attributes.
- start_pos: u32,
+ // target, including outer attributes. `None` if there are no outer
+ // attributes.
+ start_pos: Option<u32>,
}
impl AttrWrapper {
pub(super) fn new(attrs: AttrVec, start_pos: u32) -> AttrWrapper {
- AttrWrapper { attrs, start_pos }
- }
- pub fn empty() -> AttrWrapper {
- AttrWrapper { attrs: AttrVec::new(), start_pos: u32::MAX }
+ AttrWrapper { attrs, start_pos: Some(start_pos) }
}
- pub(crate) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec {
+ pub(super) fn empty() -> AttrWrapper {
+ AttrWrapper { attrs: AttrVec::new(), start_pos: None }
+ }
+
+ pub(super) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec {
psess.dcx().span_delayed_bug(
self.attrs.get(0).map(|attr| attr.span).unwrap_or(DUMMY_SP),
"AttrVec is taken for recovery but no error is produced",
@@ -56,12 +72,12 @@ pub(crate) fn take_for_recovery(self, psess: &ParseSess) -> AttrVec {
/// Prepend `self.attrs` to `attrs`.
// FIXME: require passing an NT to prevent misuse of this method
- pub(crate) fn prepend_to_nt_inner(mut self, attrs: &mut AttrVec) {
+ pub(super) fn prepend_to_nt_inner(mut self, attrs: &mut AttrVec) {
mem::swap(attrs, &mut self.attrs);
attrs.extend(self.attrs);
}
- pub fn is_empty(&self) -> bool {
+ pub(super) fn is_empty(&self) -> bool {
self.attrs.is_empty()
}
}
@@ -77,7 +93,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool {
}
// From a value of this type we can reconstruct the `TokenStream` seen by the
-// `f` callback passed to a call to `Parser::collect_tokens_trailing_token`, by
+// `f` callback passed to a call to `Parser::collect_tokens`, by
// replaying the getting of the tokens. This saves us producing a `TokenStream`
// if it is never needed, e.g. a captured `macro_rules!` argument that is never
// passed to a proc macro. In practice, token stream creation happens rarely
@@ -166,16 +182,30 @@ fn to_attr_token_stream(&self) -> AttrTokenStream {
}
impl<'a> Parser<'a> {
+ pub(super) fn collect_pos(&self) -> CollectPos {
+ CollectPos {
+ start_token: (self.token.clone(), self.token_spacing),
+ cursor_snapshot: self.token_cursor.clone(),
+ start_pos: self.num_bump_calls,
+ }
+ }
+
/// Parses code with `f`. If appropriate, it records the tokens (in
/// `LazyAttrTokenStream` form) that were parsed in the result, accessible
- /// via the `HasTokens` trait. The second (bool) part of the callback's
+ /// via the `HasTokens` trait. The `Trailing` part of the callback's
/// result indicates if an extra token should be captured, e.g. a comma or
- /// semicolon.
+ /// semicolon. The `UsePreAttrPos` part of the callback's result indicates
+ /// if we should use `pre_attr_pos` as the collection start position (only
+ /// required in a few cases).
///
/// The `attrs` passed in are in `AttrWrapper` form, which is opaque. The
/// `AttrVec` within is passed to `f`. See the comment on `AttrWrapper` for
/// details.
///
+ /// `pre_attr_pos` is the position before the outer attributes (or the node
+ /// itself, if no outer attributes are present). It is only needed if `f`
+ /// can return `UsePreAttrPos::Yes`.
+ ///
/// Note: If your callback consumes an opening delimiter (including the
/// case where `self.token` is an opening delimiter on entry to this
/// function), you must also consume the corresponding closing delimiter.
@@ -197,11 +227,12 @@ impl<'a> Parser<'a> {
/// } // 32..33
/// } // 33..34
/// ```
- pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
+ pub(super) fn collect_tokens<R: HasAttrs + HasTokens>(
&mut self,
+ pre_attr_pos: Option<CollectPos>,
attrs: AttrWrapper,
force_collect: ForceCollect,
- f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, (R, bool)>,
+ f: impl FnOnce(&mut Self, AttrVec) -> PResult<'a, (R, Trailing, UsePreAttrPos)>,
) -> PResult<'a, R> {
// We must collect if anything could observe the collected tokens, i.e.
// if any of the following conditions hold.
@@ -220,23 +251,20 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
return Ok(f(self, attrs.attrs)?.0);
}
- let start_token = (self.token.clone(), self.token_spacing);
- let cursor_snapshot = self.token_cursor.clone();
- let start_pos = self.num_bump_calls;
+ let mut collect_pos = self.collect_pos();
let has_outer_attrs = !attrs.attrs.is_empty();
let parser_replacements_start = self.capture_state.parser_replacements.len();
// We set and restore `Capturing::Yes` on either side of the call to
- // `f`, so we can distinguish the outermost call to
- // `collect_tokens_trailing_token` (e.g. parsing `m` in the example
- // above) from any inner (indirectly recursive) calls (e.g. parsing `g`
- // in the example above). This distinction is used below and in
- // `Parser::parse_inner_attributes`.
- let (mut ret, capture_trailing) = {
+ // `f`, so we can distinguish the outermost call to `collect_tokens`
+ // (e.g. parsing `m` in the example above) from any inner (indirectly
+ // recursive) calls (e.g. parsing `g` in the example above). This
+ // distinction is used below and in `Parser::parse_inner_attributes`.
+ let (mut ret, capture_trailing, use_pre_attr_pos) = {
let prev_capturing = mem::replace(&mut self.capture_state.capturing, Capturing::Yes);
- let ret_and_trailing = f(self, attrs.attrs);
+ let res = f(self, attrs.attrs);
self.capture_state.capturing = prev_capturing;
- ret_and_trailing?
+ res?
};
// When we're not in `capture_cfg` mode, then skip collecting and
@@ -279,10 +307,18 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
return Ok(ret);
}
+ // Replace the post-attribute collection start position with the
+ // pre-attribute position supplied, if `f` indicated it is necessary.
+ // (The caller is responsible for providing a non-`None` `pre_attr_pos`
+ // if this is a possibility.)
+ if matches!(use_pre_attr_pos, UsePreAttrPos::Yes) {
+ collect_pos = pre_attr_pos.unwrap();
+ }
+
let parser_replacements_end = self.capture_state.parser_replacements.len();
assert!(
- !(self.break_last_token && capture_trailing),
+ !(self.break_last_token && matches!(capture_trailing, Trailing::Yes)),
"Cannot set break_last_token and have trailing token"
);
@@ -294,7 +330,7 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
// `AttrTokenStream`, we will create the proper token.
+ self.break_last_token as u32;
- let num_calls = end_pos - start_pos;
+ let num_calls = end_pos - collect_pos.start_pos;
// Take the captured `ParserRange`s for any inner attributes that we parsed in
// `Parser::parse_inner_attributes`, and pair them in a `ParserReplacement` with `None`,
@@ -328,7 +364,9 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
.iter()
.cloned()
.chain(inner_attr_parser_replacements.iter().cloned())
- .map(|(parser_range, data)| (NodeRange::new(parser_range, start_pos), data))
+ .map(|(parser_range, data)| {
+ (NodeRange::new(parser_range, collect_pos.start_pos), data)
+ })
.collect()
};
@@ -355,9 +393,9 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
// - `tokens`: lazy tokens for `g` (with its inner attr deleted).
let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl {
- start_token,
+ start_token: collect_pos.start_token,
+ cursor_snapshot: collect_pos.cursor_snapshot,
num_calls,
- cursor_snapshot,
break_last_token: self.break_last_token,
node_replacements,
});
@@ -368,9 +406,9 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
}
// If `capture_cfg` is set and we're inside a recursive call to
- // `collect_tokens_trailing_token`, then we need to register a replace range
- // if we have `#[cfg]` or `#[cfg_attr]`. This allows us to run eager cfg-expansion
- // on the captured token stream.
+ // `collect_tokens`, then we need to register a replace range if we
+ // have `#[cfg]` or `#[cfg_attr]`. This allows us to run eager
+ // cfg-expansion on the captured token stream.
if self.capture_cfg
&& matches!(self.capture_state.capturing, Capturing::Yes)
&& has_cfg_or_cfg_attr(ret.attrs())
@@ -389,7 +427,8 @@ pub fn collect_tokens_trailing_token<R: HasAttrs + HasTokens>(
// Set things up so that the entire AST node that we just parsed, including attributes,
// will be replaced with `target` in the lazy token stream. This will allow us to
// cfg-expand this AST node.
- let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos };
+ let start_pos =
+ if has_outer_attrs { attrs.start_pos.unwrap() } else { collect_pos.start_pos };
let target = AttrsTarget { attrs: ret.attrs().iter().cloned().collect(), tokens };
self.capture_state
.parser_replacements
@@ -490,7 +529,6 @@ mod size_asserts {
use super::*;
// tidy-alphabetical-start
- static_assert_size!(AttrWrapper, 16);
static_assert_size!(LazyAttrTokenStreamImpl, 96);
// tidy-alphabetical-end
}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 47ca85b..ef1387c 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -474,8 +474,8 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
// If this isn't the case however, and the suggestion is a token the
// content of which is the same as the found token's, we remove it as well.
if !eq {
- if let TokenType::Token(kind) = &token {
- if kind == &self.token.kind {
+ if let TokenType::Token(kind) = token {
+ if self.token == *kind {
return false;
}
}
@@ -506,7 +506,7 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
} else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
// The current token is in the same line as the prior token, not recoverable.
} else if [token::Comma, token::Colon].contains(&self.token.kind)
- && self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis)
+ && self.prev_token == token::CloseDelim(Delimiter::Parenthesis)
{
// Likely typo: The current token is on a new line and is expected to be
// `.`, `;`, `?`, or an operator after a close delimiter token.
@@ -518,7 +518,7 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
// https://github.com/rust-lang/rust/issues/72253
} else if self.look_ahead(1, |t| {
t == &token::CloseDelim(Delimiter::Brace)
- || t.can_begin_expr() && t.kind != token::Colon
+ || t.can_begin_expr() && *t != token::Colon
}) && [token::Comma, token::Colon].contains(&self.token.kind)
{
// Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
@@ -562,7 +562,7 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
}
}
- if self.token.kind == TokenKind::EqEq
+ if self.token == TokenKind::EqEq
&& self.prev_token.is_ident()
&& expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
{
@@ -655,9 +655,9 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
// positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
// that in the parser requires unbounded lookahead, so we only add a hint to the existing
// error rather than replacing it entirely.
- if ((self.prev_token.kind == TokenKind::Ident(sym::c, IdentIsRaw::No)
+ if ((self.prev_token == TokenKind::Ident(sym::c, IdentIsRaw::No)
&& matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
- || (self.prev_token.kind == TokenKind::Ident(sym::cr, IdentIsRaw::No)
+ || (self.prev_token == TokenKind::Ident(sym::cr, IdentIsRaw::No)
&& matches!(
&self.token.kind,
TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
@@ -673,7 +673,7 @@ fn is_ident_eq_keyword(found: &TokenKind, expected: &TokenType) -> bool {
// `pub` may be used for an item or `pub(crate)`
if self.prev_token.is_ident_named(sym::public)
&& (self.token.can_begin_item()
- || self.token.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
+ || self.token == TokenKind::OpenDelim(Delimiter::Parenthesis))
{
err.span_suggestion_short(
self.prev_token.span,
@@ -772,7 +772,7 @@ pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed {
),
);
if self.token == token::Pound
- && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Bracket))
+ && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
{
// We have
// #[attr]
@@ -867,7 +867,7 @@ fn check_too_many_raw_str_terminators(&mut self, err: &mut Diag<'_>) -> bool {
let str_span = self.prev_token.span;
let mut span = self.token.span;
let mut count = 0;
- while self.token.kind == TokenKind::Pound
+ while self.token == TokenKind::Pound
&& !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
{
span = span.with_hi(self.token.span.hi());
@@ -1167,7 +1167,7 @@ pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut Pa
return;
}
- if token::PathSep == self.token.kind && segment.args.is_none() {
+ if self.token == token::PathSep && segment.args.is_none() {
let snapshot = self.create_snapshot_for_diagnostic();
self.bump();
let lo = self.token.span;
@@ -1176,13 +1176,11 @@ pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut Pa
let span = lo.to(self.prev_token.span);
// Detect trailing `>` like in `x.collect::Vec<_>>()`.
let mut trailing_span = self.prev_token.span.shrink_to_hi();
- while self.token.kind == token::BinOp(token::Shr)
- || self.token.kind == token::Gt
- {
+ while self.token == token::BinOp(token::Shr) || self.token == token::Gt {
trailing_span = trailing_span.to(self.token.span);
self.bump();
}
- if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+ if self.token == token::OpenDelim(Delimiter::Parenthesis) {
// Recover from bad turbofish: `foo.collect::Vec<_>()`.
segment.args = Some(AngleBracketedArgs { args, span }.into());
@@ -1430,7 +1428,7 @@ pub(super) fn check_no_chained_comparison(
self.restore_snapshot(snapshot);
}
}
- return if token::PathSep == self.token.kind {
+ return if self.token == token::PathSep {
// We have some certainty that this was a bad turbofish at this point.
// `foo< bar >::`
if let ExprKind::Binary(o, ..) = inner_op.kind
@@ -1462,7 +1460,7 @@ pub(super) fn check_no_chained_comparison(
Err(self.dcx().create_err(err))
}
}
- } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
+ } else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
// We have high certainty that this was a bad turbofish at this point.
// `foo< bar >(`
if let ExprKind::Binary(o, ..) = inner_op.kind
@@ -1528,7 +1526,7 @@ fn consume_fn_args(&mut self) -> Result<(), ()> {
];
self.consume_tts(1, &modifiers);
- if self.token.kind == token::Eof {
+ if self.token == token::Eof {
// Not entirely sure that what we consumed were fn arguments, rollback.
self.restore_snapshot(snapshot);
Err(())
@@ -1811,7 +1809,7 @@ pub(super) fn maybe_recover_from_bad_qpath_stage_2<T: RecoverQPath>(
/// This function gets called in places where a semicolon is NOT expected and if there's a
/// semicolon it emits the appropriate error and returns true.
pub fn maybe_consume_incorrect_semicolon(&mut self, previous_item: Option<&Item>) -> bool {
- if self.token.kind != TokenKind::Semi {
+ if self.token != TokenKind::Semi {
return false;
}
@@ -2405,10 +2403,10 @@ fn consume_tts(
modifier: &[(token::TokenKind, i64)],
) {
while acc > 0 {
- if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) {
+ if let Some((_, val)) = modifier.iter().find(|(t, _)| self.token == *t) {
acc += *val;
}
- if self.token.kind == token::Eof {
+ if self.token == token::Eof {
break;
}
self.bump();
@@ -2489,13 +2487,14 @@ pub(super) fn handle_ambiguous_unbraced_const_arg(
pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> {
let start = self.token.span;
let attrs = self.parse_outer_attributes()?;
- let expr = self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| {
- err.span_label(
- start.shrink_to_lo(),
- "while parsing a const generic argument starting here",
- );
- err
- })?;
+ let (expr, _) =
+ self.parse_expr_res(Restrictions::CONST_EXPR, attrs).map_err(|mut err| {
+ err.span_label(
+ start.shrink_to_lo(),
+ "while parsing a const generic argument starting here",
+ );
+ err
+ })?;
if !self.expr_is_valid_const_arg(&expr) {
self.dcx().emit_err(ConstGenericWithoutBraces {
span: expr.span,
@@ -2598,7 +2597,7 @@ pub(super) fn recover_const_arg(
}
})
.is_some()
- || self.token.kind == TokenKind::Dot;
+ || self.token == TokenKind::Dot;
// This will be true when a trait object type `Foo +` or a path which was a `const fn` with
// type params has been parsed.
let was_op =
@@ -2615,9 +2614,9 @@ pub(super) fn recover_const_arg(
let attrs = self.parse_outer_attributes()?;
self.parse_expr_res(Restrictions::CONST_EXPR, attrs)
})() {
- Ok(expr) => {
+ Ok((expr, _)) => {
// Find a mistake like `MyTrait<Assoc == S::Assoc>`.
- if token::EqEq == snapshot.token.kind {
+ if snapshot.token == token::EqEq {
err.span_suggestion(
snapshot.token.span,
"if you meant to use an associated type binding, replace `==` with `=`",
@@ -2627,7 +2626,7 @@ pub(super) fn recover_const_arg(
let guar = err.emit();
let value = self.mk_expr_err(start.to(expr.span), guar);
return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
- } else if token::Colon == snapshot.token.kind
+ } else if snapshot.token == token::Colon
&& expr.span.lo() == snapshot.token.span.hi()
&& matches!(expr.kind, ExprKind::Path(..))
{
@@ -2642,8 +2641,7 @@ pub(super) fn recover_const_arg(
return Ok(GenericArg::Type(
self.mk_ty(start.to(expr.span), TyKind::Err(guar)),
));
- } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg()
- {
+ } else if self.token == token::Comma || self.token.kind.should_end_const_arg() {
// Avoid the following output by checking that we consumed a full const arg:
// help: expressions must be enclosed in braces to be used as const generic
// arguments
@@ -2674,7 +2672,7 @@ pub(crate) fn recover_unbraced_const_arg_that_can_begin_ty(
})() {
// Since we don't know the exact reason why we failed to parse the type or the
// expression, employ a simple heuristic to weed out some pathological cases.
- Ok(expr) if let token::Comma | token::Gt = snapshot.token.kind => {
+ Ok((expr, _)) if let token::Comma | token::Gt = snapshot.token.kind => {
self.restore_snapshot(snapshot);
Some(expr)
}
@@ -2846,8 +2844,8 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
// Check for `'a : {`
if !(self.check_lifetime()
- && self.look_ahead(1, |tok| tok.kind == token::Colon)
- && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Brace)))
+ && self.look_ahead(1, |t| *t == token::Colon)
+ && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace)))
{
return false;
}
@@ -3001,7 +2999,7 @@ pub(crate) fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> {
// >>>>>>>
let mut end = None;
loop {
- if self.token.kind == TokenKind::Eof {
+ if self.token == TokenKind::Eof {
break;
}
if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::BinOp(token::Or))
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index cf5d657..e0917ba 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -36,7 +36,7 @@
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{
AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
- SemiColonMode, SeqSep, TokenType, Trailing,
+ SemiColonMode, SeqSep, TokenType, Trailing, UsePreAttrPos,
};
use crate::{errors, maybe_recover_from_interpolated_ty_qpath};
@@ -59,15 +59,30 @@ pub fn parse_expr(&mut self) -> PResult<'a, P<Expr>> {
self.current_closure.take();
let attrs = self.parse_outer_attributes()?;
- self.parse_expr_res(Restrictions::empty(), attrs)
+ self.parse_expr_res(Restrictions::empty(), attrs).map(|res| res.0)
}
/// Parses an expression, forcing tokens to be collected.
pub fn parse_expr_force_collect(&mut self) -> PResult<'a, P<Expr>> {
self.current_closure.take();
+ // If the expression is associative (e.g. `1 + 2`), then any preceding
+ // outer attribute actually belongs to the first inner sub-expression.
+ // In which case we must use the pre-attr pos to include the attribute
+ // in the collected tokens for the outer expression.
+ let pre_attr_pos = self.collect_pos();
let attrs = self.parse_outer_attributes()?;
- self.collect_tokens_no_attrs(|this| this.parse_expr_res(Restrictions::empty(), attrs))
+ self.collect_tokens(
+ Some(pre_attr_pos),
+ AttrWrapper::empty(),
+ ForceCollect::Yes,
+ |this, _empty_attrs| {
+ let (expr, is_assoc) = this.parse_expr_res(Restrictions::empty(), attrs)?;
+ let use_pre_attr_pos =
+ if is_assoc { UsePreAttrPos::Yes } else { UsePreAttrPos::No };
+ Ok((expr, Trailing::No, use_pre_attr_pos))
+ },
+ )
}
pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
@@ -77,7 +92,7 @@ pub fn parse_expr_anon_const(&mut self) -> PResult<'a, AnonConst> {
fn parse_expr_catch_underscore(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> {
let attrs = self.parse_outer_attributes()?;
match self.parse_expr_res(restrictions, attrs) {
- Ok(expr) => Ok(expr),
+ Ok((expr, _)) => Ok(expr),
Err(err) => match self.token.ident() {
Some((Ident { name: kw::Underscore, .. }, IdentIsRaw::No))
if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
@@ -104,18 +119,20 @@ pub(super) fn parse_expr_res(
&mut self,
r: Restrictions,
attrs: AttrWrapper,
- ) -> PResult<'a, P<Expr>> {
+ ) -> PResult<'a, (P<Expr>, bool)> {
self.with_res(r, |this| this.parse_expr_assoc_with(0, attrs))
}
/// Parses an associative expression with operators of at least `min_prec` precedence.
+ /// The `bool` in the return value indicates if it was an assoc expr, i.e. with an operator
+ /// followed by a subexpression (e.g. `1 + 2`).
pub(super) fn parse_expr_assoc_with(
&mut self,
min_prec: usize,
attrs: AttrWrapper,
- ) -> PResult<'a, P<Expr>> {
+ ) -> PResult<'a, (P<Expr>, bool)> {
let lhs = if self.token.is_range_separator() {
- return self.parse_expr_prefix_range(attrs);
+ return self.parse_expr_prefix_range(attrs).map(|res| (res, false));
} else {
self.parse_expr_prefix(attrs)?
};
@@ -123,15 +140,17 @@ pub(super) fn parse_expr_assoc_with(
}
/// Parses the rest of an associative expression (i.e. the part after the lhs) with operators
- /// of at least `min_prec` precedence.
+ /// of at least `min_prec` precedence. The `bool` in the return value indicates if something
+ /// was actually parsed.
pub(super) fn parse_expr_assoc_rest_with(
&mut self,
min_prec: usize,
starts_stmt: bool,
mut lhs: P<Expr>,
- ) -> PResult<'a, P<Expr>> {
+ ) -> PResult<'a, (P<Expr>, bool)> {
+ let mut parsed_something = false;
if !self.should_continue_as_assoc_expr(&lhs) {
- return Ok(lhs);
+ return Ok((lhs, parsed_something));
}
self.expected_tokens.push(TokenType::Operator);
@@ -156,16 +175,17 @@ pub(super) fn parse_expr_assoc_rest_with(
self.err_larrow_operator(self.token.span);
}
+ parsed_something = true;
self.bump();
if op.node.is_comparison() {
if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
- return Ok(expr);
+ return Ok((expr, parsed_something));
}
}
// Look for JS' `===` and `!==` and recover
if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual)
- && self.token.kind == token::Eq
+ && self.token == token::Eq
&& self.prev_token.span.hi() == self.token.span.lo()
{
let sp = op.span.to(self.token.span);
@@ -190,7 +210,7 @@ pub(super) fn parse_expr_assoc_rest_with(
// Look for PHP's `<>` and recover
if op.node == AssocOp::Less
- && self.token.kind == token::Gt
+ && self.token == token::Gt
&& self.prev_token.span.hi() == self.token.span.lo()
{
let sp = op.span.to(self.token.span);
@@ -208,7 +228,7 @@ pub(super) fn parse_expr_assoc_rest_with(
// Look for C++'s `<=>` and recover
if op.node == AssocOp::LessEqual
- && self.token.kind == token::Gt
+ && self.token == token::Gt
&& self.prev_token.span.hi() == self.token.span.lo()
{
let sp = op.span.to(self.token.span);
@@ -263,7 +283,7 @@ pub(super) fn parse_expr_assoc_rest_with(
// the special cases. The code is here only for future convenience.
Fixity::None => 1,
};
- let rhs = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
+ let (rhs, _) = self.with_res(restrictions - Restrictions::STMT_EXPR, |this| {
let attrs = this.parse_outer_attributes()?;
this.parse_expr_assoc_with(prec + prec_adjustment, attrs)
})?;
@@ -319,7 +339,7 @@ pub(super) fn parse_expr_assoc_rest_with(
}
}
- Ok(lhs)
+ Ok((lhs, parsed_something))
}
fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
@@ -441,7 +461,8 @@ fn parse_expr_range(
let attrs = self.parse_outer_attributes()?;
Some(
self.parse_expr_assoc_with(prec + 1, attrs)
- .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?,
+ .map_err(|err| self.maybe_err_dotdotlt_syntax(maybe_lt, err))?
+ .0,
)
} else {
None
@@ -498,7 +519,7 @@ fn parse_expr_prefix_range(&mut self, attrs: AttrWrapper) -> PResult<'a, P<Expr>
// RHS must be parsed with more associativity than the dots.
let attrs = this.parse_outer_attributes()?;
this.parse_expr_assoc_with(op.unwrap().precedence() + 1, attrs)
- .map(|x| (lo.to(x.span), Some(x)))
+ .map(|(x, _)| (lo.to(x.span), Some(x)))
.map_err(|err| this.maybe_err_dotdotlt_syntax(maybe_lt, err))?
} else {
(lo, None)
@@ -882,7 +903,7 @@ pub(super) fn parse_expr_dot_or_call_with(
let mut res = ensure_sufficient_stack(|| {
loop {
let has_question =
- if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
+ if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
// We are using noexpect here because we don't expect a `?` directly after
// a `return` which could be suggested otherwise.
self.eat_noexpect(&token::Question)
@@ -894,20 +915,19 @@ pub(super) fn parse_expr_dot_or_call_with(
e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
continue;
}
- let has_dot =
- if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
- // We are using noexpect here because we don't expect a `.` directly after
- // a `return` which could be suggested otherwise.
- self.eat_noexpect(&token::Dot)
- } else if self.token.kind == TokenKind::RArrow && self.may_recover() {
- // Recovery for `expr->suffix`.
- self.bump();
- let span = self.prev_token.span;
- self.dcx().emit_err(errors::ExprRArrowCall { span });
- true
- } else {
- self.eat(&token::Dot)
- };
+ let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
+ // We are using noexpect here because we don't expect a `.` directly after
+ // a `return` which could be suggested otherwise.
+ self.eat_noexpect(&token::Dot)
+ } else if self.token == TokenKind::RArrow && self.may_recover() {
+ // Recovery for `expr->suffix`.
+ self.bump();
+ let span = self.prev_token.span;
+ self.dcx().emit_err(errors::ExprRArrowCall { span });
+ true
+ } else {
+ self.eat(&token::Dot)
+ };
if has_dot {
// expr.f
e = self.parse_dot_suffix_expr(lo, e)?;
@@ -1206,7 +1226,7 @@ fn parse_floating_field_access(&mut self) -> PResult<'a, P<[Ident]>> {
}
fn mk_expr_tuple_field_access(
- &mut self,
+ &self,
lo: Span,
ident_span: Span,
base: P<Expr>,
@@ -1221,7 +1241,7 @@ fn mk_expr_tuple_field_access(
/// Parse a function call expression, `expr(...)`.
fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
- let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+ let snapshot = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
} else {
None
@@ -1585,7 +1605,7 @@ fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
// Suggests using '<=' if there is an error parsing qpath when the previous token
// is an '=' token. Only emits suggestion if the '<' token and '=' token are
// directly adjacent (i.e. '=<')
- if maybe_eq_tok.kind == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
+ if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
let eq_lt = maybe_eq_tok.span.to(lt_span);
err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
}
@@ -2230,7 +2250,7 @@ fn suggest_missing_semicolon_before_array(
return Ok(());
}
- if self.token.kind == token::Comma {
+ if self.token == token::Comma {
if !self.psess.source_map().is_multiline(prev_span.until(self.token.span)) {
return Ok(());
}
@@ -2336,7 +2356,7 @@ fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
let token = self.token.clone();
let attrs = self.parse_outer_attributes()?;
match self.parse_expr_res(restrictions, attrs) {
- Ok(expr) => expr,
+ Ok((expr, _)) => expr,
Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?,
}
}
@@ -2360,7 +2380,7 @@ fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
None => {}
}
- if self.token.kind == TokenKind::Semi
+ if self.token == TokenKind::Semi
&& matches!(self.token_cursor.stack.last(), Some((.., Delimiter::Parenthesis)))
&& self.may_recover()
{
@@ -2446,7 +2466,7 @@ fn parse_fn_block_decl(&mut self) -> PResult<'a, (P<FnDecl>, Span)> {
fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
let lo = self.token.span;
let attrs = self.parse_outer_attributes()?;
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let pat = this.parse_pat_no_top_alt(Some(Expected::ParameterName), None)?;
let ty = if this.eat(&token::Colon) {
this.parse_ty()?
@@ -2463,7 +2483,8 @@ fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
id: DUMMY_NODE_ID,
is_placeholder: false,
},
- this.token == token::Comma,
+ Trailing::from(this.token == token::Comma),
+ UsePreAttrPos::No,
))
})
}
@@ -2557,7 +2578,7 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
);
} else {
// Look for usages of '=>' where '>=' might be intended
- if maybe_fatarrow.kind == token::FatArrow {
+ if maybe_fatarrow == token::FatArrow {
err.span_suggestion(
maybe_fatarrow.span,
"you might have meant to write a \"greater than or equal to\" comparison",
@@ -2584,7 +2605,7 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
/// Parses the condition of a `if` or `while` expression.
fn parse_expr_cond(&mut self) -> PResult<'a, P<Expr>> {
let attrs = self.parse_outer_attributes()?;
- let mut cond =
+ let (mut cond, _) =
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
CondChecker::new(self).visit_expr(&mut cond);
@@ -2606,7 +2627,7 @@ fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>>
missing_let: None,
comparison: None,
};
- if self.prev_token.kind == token::BinOp(token::Or) {
+ if self.prev_token == token::BinOp(token::Or) {
// This was part of a closure, the that part of the parser recover.
return Err(self.dcx().create_err(err));
} else {
@@ -2633,7 +2654,7 @@ fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>>
self.expect(&token::Eq)?;
}
let attrs = self.parse_outer_attributes()?;
- let expr = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), attrs)?;
+ let (expr, _) = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), attrs)?;
let span = lo.to(expr.span);
Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered)))
}
@@ -2742,7 +2763,7 @@ fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> {
}
fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
- let begin_paren = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+ let begin_paren = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
// Record whether we are about to parse `for (`.
// This is used below for recovery in case of `for ( $stuff ) $block`
// in which case we will suggest `for $stuff $block`.
@@ -2767,7 +2788,7 @@ fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
// We know for sure we have seen `for ($SOMETHING in`. In the happy path this would
// happen right before the return of this method.
let attrs = self.parse_outer_attributes()?;
- let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs) {
+ let (expr, _) = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs) {
Ok(expr) => expr,
Err(expr_err) => {
// We don't know what followed the `in`, so cancel and bubble up the
@@ -2776,7 +2797,7 @@ fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
return Err(err);
}
};
- return if self.token.kind == token::CloseDelim(Delimiter::Parenthesis) {
+ return if self.token == token::CloseDelim(Delimiter::Parenthesis) {
// We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
// parser state and emit a targeted suggestion.
let span = vec![start_span, self.token.span];
@@ -2802,7 +2823,7 @@ fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
}
self.check_for_for_in_in_typo(self.prev_token.span);
let attrs = self.parse_outer_attributes()?;
- let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
+ let (expr, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
Ok((pat, expr))
}
@@ -2922,7 +2943,7 @@ pub(crate) fn eat_label(&mut self) -> Option<Label> {
fn parse_expr_match(&mut self) -> PResult<'a, P<Expr>> {
let match_span = self.prev_token.span;
let attrs = self.parse_outer_attributes()?;
- let scrutinee = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
+ let (scrutinee, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, attrs)?;
self.parse_match_block(match_span, match_span, scrutinee, MatchKind::Prefix)
}
@@ -2995,7 +3016,7 @@ fn parse_arm_body_missing_braces(
first_expr: &P<Expr>,
arrow_span: Span,
) -> Option<(Span, ErrorGuaranteed)> {
- if self.token.kind != token::Semi {
+ if self.token != token::Semi {
return None;
}
let start_snapshot = self.create_snapshot_for_diagnostic();
@@ -3024,18 +3045,18 @@ fn parse_arm_body_missing_braces(
// We might have either a `,` -> `;` typo, or a block without braces. We need
// a more subtle parsing strategy.
loop {
- if self.token.kind == token::CloseDelim(Delimiter::Brace) {
+ if self.token == token::CloseDelim(Delimiter::Brace) {
// We have reached the closing brace of the `match` expression.
return Some(err(self, stmts));
}
- if self.token.kind == token::Comma {
+ if self.token == token::Comma {
self.restore_snapshot(start_snapshot);
return None;
}
let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
match self.parse_pat_no_top_alt(None, None) {
Ok(_pat) => {
- if self.token.kind == token::FatArrow {
+ if self.token == token::FatArrow {
// Reached arm end.
self.restore_snapshot(pre_pat_snapshot);
return Some(err(self, stmts));
@@ -3070,7 +3091,7 @@ fn parse_arm_body_missing_braces(
pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
let attrs = self.parse_outer_attributes()?;
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
let (pat, guard) = this.parse_match_arm_pat_and_guard()?;
@@ -3127,7 +3148,7 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
let arm_start_span = this.token.span;
let attrs = this.parse_outer_attributes()?;
- let expr =
+ let (expr, _) =
this.parse_expr_res(Restrictions::STMT_EXPR, attrs).map_err(|mut err| {
err.span_label(arrow_span, "while parsing the `match` arm starting here");
err
@@ -3244,7 +3265,8 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
id: DUMMY_NODE_ID,
is_placeholder: false,
},
- false,
+ Trailing::No,
+ UsePreAttrPos::No,
))
})
}
@@ -3286,7 +3308,7 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
}
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
- if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+ if self.token == token::OpenDelim(Delimiter::Parenthesis) {
// Detect and recover from `($pat if $cond) => $arm`.
let left = self.token.span;
match self.parse_pat_allow_top_alt(
@@ -3335,8 +3357,9 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Exp
fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
let attrs = self.parse_outer_attributes()?;
- self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs).map_err(
- |mut err| {
+ match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) {
+ Ok((expr, _)) => Ok(expr),
+ Err(mut err) => {
if self.prev_token == token::OpenDelim(Delimiter::Brace) {
let sugg_sp = self.prev_token.span.shrink_to_lo();
// Consume everything within the braces, let's avoid further parse
@@ -3344,7 +3367,7 @@ fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
let msg = "you might have meant to start a match arm after the match guard";
if self.eat(&token::CloseDelim(Delimiter::Brace)) {
- let applicability = if self.token.kind != token::FatArrow {
+ let applicability = if self.token != token::FatArrow {
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
// that ended in a path, immediately followed by a block that was
@@ -3356,9 +3379,9 @@ fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
}
}
- err
- },
- )
+ Err(err)
+ }
+ }
}
pub(crate) fn is_builtin(&self) -> bool {
@@ -3565,7 +3588,7 @@ pub(super) fn parse_struct_fields(
&& self.look_ahead(1, |t| {
AssocOp::from_token(t).is_some()
|| matches!(t.kind, token::OpenDelim(_))
- || t.kind == token::Dot
+ || *t == token::Dot
})
{
// Looks like they tried to write a shorthand, complex expression.
@@ -3709,7 +3732,7 @@ fn recover_ident_into_label(&mut self, ident: Ident) -> Label {
fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
let attrs = self.parse_outer_attributes()?;
self.recover_vcs_conflict_marker();
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
// Check if a colon exists one ahead. This means we're parsing a fieldname.
@@ -3753,7 +3776,8 @@ fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
id: DUMMY_NODE_ID,
is_placeholder: false,
},
- this.token == token::Comma,
+ Trailing::from(this.token == token::Comma),
+ UsePreAttrPos::No,
))
})
}
@@ -3847,15 +3871,17 @@ fn collect_tokens_for_expr(
attrs: AttrWrapper,
f: impl FnOnce(&mut Self, ast::AttrVec) -> PResult<'a, P<Expr>>,
) -> PResult<'a, P<Expr>> {
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let res = f(this, attrs)?;
- let trailing = (this.restrictions.contains(Restrictions::STMT_EXPR)
- && this.token.kind == token::Semi)
- // FIXME: pass an additional condition through from the place
- // where we know we need a comma, rather than assuming that
- // `#[attr] expr,` always captures a trailing comma.
- || this.token.kind == token::Comma;
- Ok((res, trailing))
+ let trailing = Trailing::from(
+ this.restrictions.contains(Restrictions::STMT_EXPR)
+ && this.token == token::Semi
+ // FIXME: pass an additional condition through from the place
+ // where we know we need a comma, rather than assuming that
+ // `#[attr] expr,` always captures a trailing comma.
+ || this.token == token::Comma,
+ );
+ Ok((res, trailing, UsePreAttrPos::No))
})
}
}
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 9124c15..af3b6f7 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -7,7 +7,7 @@
use rustc_span::Span;
use thin_vec::ThinVec;
-use super::{ForceCollect, Parser};
+use super::{ForceCollect, Parser, Trailing, UsePreAttrPos};
use crate::errors::{
self, MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
@@ -169,94 +169,88 @@ pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::Generi
let mut done = false;
while !done {
let attrs = self.parse_outer_attributes()?;
- let param =
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
- if this.eat_keyword_noexpect(kw::SelfUpper) {
- // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
- // as if `Self` never existed.
- this.dcx().emit_err(UnexpectedSelfInGenericParameters {
- span: this.prev_token.span,
- });
+ let param = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
+ if this.eat_keyword_noexpect(kw::SelfUpper) {
+ // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
+ // as if `Self` never existed.
+ this.dcx()
+ .emit_err(UnexpectedSelfInGenericParameters { span: this.prev_token.span });
- // Eat a trailing comma, if it exists.
- let _ = this.eat(&token::Comma);
- }
+ // Eat a trailing comma, if it exists.
+ let _ = this.eat(&token::Comma);
+ }
- let param = if this.check_lifetime() {
- let lifetime = this.expect_lifetime();
- // Parse lifetime parameter.
- let (colon_span, bounds) = if this.eat(&token::Colon) {
- (Some(this.prev_token.span), this.parse_lt_param_bounds())
- } else {
- (None, Vec::new())
- };
-
- if this.check_noexpect(&token::Eq)
- && this.look_ahead(1, |t| t.is_lifetime())
- {
- let lo = this.token.span;
- // Parse `= 'lifetime`.
- this.bump(); // `=`
- this.bump(); // `'lifetime`
- let span = lo.to(this.prev_token.span);
- this.dcx().emit_err(
- UnexpectedDefaultValueForLifetimeInGenericParameters { span },
- );
- }
-
- Some(ast::GenericParam {
- ident: lifetime.ident,
- id: lifetime.id,
- attrs,
- bounds,
- kind: ast::GenericParamKind::Lifetime,
- is_placeholder: false,
- colon_span,
- })
- } else if this.check_keyword(kw::Const) {
- // Parse const parameter.
- Some(this.parse_const_param(attrs)?)
- } else if this.check_ident() {
- // Parse type parameter.
- Some(this.parse_ty_param(attrs)?)
- } else if this.token.can_begin_type() {
- // Trying to write an associated type bound? (#26271)
- let snapshot = this.create_snapshot_for_diagnostic();
- match this.parse_ty_where_predicate() {
- Ok(where_predicate) => {
- this.dcx().emit_err(errors::BadAssocTypeBounds {
- span: where_predicate.span(),
- });
- // FIXME - try to continue parsing other generics?
- return Ok((None, false));
- }
- Err(err) => {
- err.cancel();
- // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`?
- this.restore_snapshot(snapshot);
- return Ok((None, false));
- }
- }
+ let param = if this.check_lifetime() {
+ let lifetime = this.expect_lifetime();
+ // Parse lifetime parameter.
+ let (colon_span, bounds) = if this.eat(&token::Colon) {
+ (Some(this.prev_token.span), this.parse_lt_param_bounds())
} else {
- // Check for trailing attributes and stop parsing.
- if !attrs.is_empty() {
- if !params.is_empty() {
- this.dcx()
- .emit_err(errors::AttrAfterGeneric { span: attrs[0].span });
- } else {
- this.dcx()
- .emit_err(errors::AttrWithoutGenerics { span: attrs[0].span });
- }
- }
- return Ok((None, false));
+ (None, Vec::new())
};
- if !this.eat(&token::Comma) {
- done = true;
+ if this.check_noexpect(&token::Eq) && this.look_ahead(1, |t| t.is_lifetime()) {
+ let lo = this.token.span;
+ // Parse `= 'lifetime`.
+ this.bump(); // `=`
+ this.bump(); // `'lifetime`
+ let span = lo.to(this.prev_token.span);
+ this.dcx().emit_err(UnexpectedDefaultValueForLifetimeInGenericParameters {
+ span,
+ });
}
- // We just ate the comma, so no need to capture the trailing token.
- Ok((param, false))
- })?;
+
+ Some(ast::GenericParam {
+ ident: lifetime.ident,
+ id: lifetime.id,
+ attrs,
+ bounds,
+ kind: ast::GenericParamKind::Lifetime,
+ is_placeholder: false,
+ colon_span,
+ })
+ } else if this.check_keyword(kw::Const) {
+ // Parse const parameter.
+ Some(this.parse_const_param(attrs)?)
+ } else if this.check_ident() {
+ // Parse type parameter.
+ Some(this.parse_ty_param(attrs)?)
+ } else if this.token.can_begin_type() {
+ // Trying to write an associated type bound? (#26271)
+ let snapshot = this.create_snapshot_for_diagnostic();
+ match this.parse_ty_where_predicate() {
+ Ok(where_predicate) => {
+ this.dcx().emit_err(errors::BadAssocTypeBounds {
+ span: where_predicate.span(),
+ });
+ // FIXME - try to continue parsing other generics?
+ }
+ Err(err) => {
+ err.cancel();
+ // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`?
+ this.restore_snapshot(snapshot);
+ }
+ }
+ return Ok((None, Trailing::No, UsePreAttrPos::No));
+ } else {
+ // Check for trailing attributes and stop parsing.
+ if !attrs.is_empty() {
+ if !params.is_empty() {
+ this.dcx().emit_err(errors::AttrAfterGeneric { span: attrs[0].span });
+ } else {
+ this.dcx()
+ .emit_err(errors::AttrWithoutGenerics { span: attrs[0].span });
+ }
+ }
+ return Ok((None, Trailing::No, UsePreAttrPos::No));
+ };
+
+ if !this.eat(&token::Comma) {
+ done = true;
+ }
+ // We just ate the comma, so no need to capture the trailing token.
+ Ok((param, Trailing::No, UsePreAttrPos::No))
+ })?;
if let Some(param) = param {
params.push(param);
@@ -393,7 +387,7 @@ fn parse_ty_where_predicate_or_recover_tuple_struct_body(
if let Some(struct_) = struct_
&& self.may_recover()
- && self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
+ && self.token == token::OpenDelim(Delimiter::Parenthesis)
{
snapshot = Some((struct_, self.create_snapshot_for_diagnostic()));
};
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 8775d79..47820e9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -20,7 +20,9 @@
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing};
+use super::{
+ AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing, UsePreAttrPos,
+};
use crate::errors::{self, MacroExpandsToAdtField};
use crate::{fluent_generated as fluent, maybe_whole};
@@ -127,7 +129,7 @@ pub(super) fn parse_item_common(
Some(item.into_inner())
});
- self.collect_tokens_trailing_token(attrs, force_collect, |this, mut attrs| {
+ self.collect_tokens(None, attrs, force_collect, |this, mut attrs| {
let lo = this.token.span;
let vis = this.parse_visibility(FollowedByType::No)?;
let mut def = this.parse_defaultness();
@@ -145,7 +147,7 @@ pub(super) fn parse_item_common(
let span = lo.to(this.prev_token.span);
let id = DUMMY_NODE_ID;
let item = Item { ident, attrs, id, kind, vis, span, tokens: None };
- return Ok((Some(item), false));
+ return Ok((Some(item), Trailing::No, UsePreAttrPos::No));
}
// At this point, we have failed to parse an item.
@@ -160,7 +162,7 @@ pub(super) fn parse_item_common(
if !attrs_allowed {
this.recover_attrs_no_item(&attrs)?;
}
- Ok((None, false))
+ Ok((None, Trailing::No, UsePreAttrPos::No))
})
}
@@ -354,7 +356,7 @@ pub(super) fn is_path_start_item(&mut self) -> bool {
fn is_reuse_path_item(&mut self) -> bool {
// no: `reuse ::path` for compatibility reasons with macro invocations
self.token.is_keyword(kw::Reuse)
- && self.look_ahead(1, |t| t.is_path_start() && t.kind != token::PathSep)
+ && self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep)
}
/// Are we sure this could not possibly be a macro invocation?
@@ -499,7 +501,7 @@ fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
let mut err = self.dcx().struct_span_err(end.span, msg);
if end.is_doc_comment() {
err.span_label(end.span, "this doc comment doesn't document anything");
- } else if self.token.kind == TokenKind::Semi {
+ } else if self.token == TokenKind::Semi {
err.span_suggestion_verbose(
self.token.span,
"consider removing this semicolon",
@@ -777,12 +779,12 @@ fn parse_item_list<T>(
&& self
.span_to_snippet(self.prev_token.span)
.is_ok_and(|snippet| snippet == "}")
- && self.token.kind == token::Semi;
+ && self.token == token::Semi;
let mut semicolon_span = self.token.span;
if !is_unnecessary_semicolon {
// #105369, Detect spurious `;` before assoc fn body
is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace)
- && self.prev_token.kind == token::Semi;
+ && self.prev_token == token::Semi;
semicolon_span = self.prev_token.span;
}
// We have to bail or we'll potentially never make progress.
@@ -1194,7 +1196,7 @@ fn parse_item_foreign_mod(
// FIXME: This recovery should be tested better.
if safety == Safety::Default
&& self.token.is_keyword(kw::Unsafe)
- && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
+ && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
{
self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit();
safety = Safety::Unsafe(self.token.span);
@@ -1258,7 +1260,7 @@ fn is_unsafe_foreign_mod(&self) -> bool {
&& self.is_keyword_ahead(1, &[kw::Extern])
&& self.look_ahead(
2 + self.look_ahead(2, |t| t.can_begin_string_literal() as usize),
- |t| t.kind == token::OpenDelim(Delimiter::Brace),
+ |t| *t == token::OpenDelim(Delimiter::Brace),
)
}
@@ -1343,7 +1345,7 @@ fn parse_static_item(
) -> PResult<'a, (Ident, StaticItem)> {
let ident = self.parse_ident()?;
- if self.token.kind == TokenKind::Lt && self.may_recover() {
+ if self.token == TokenKind::Lt && self.may_recover() {
let generics = self.parse_generics()?;
self.dcx().emit_err(errors::StaticWithGenerics { span: generics.span });
}
@@ -1546,86 +1548,82 @@ fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> {
self.recover_vcs_conflict_marker();
let help = "enum variants can be `Variant`, `Variant = <integer>`, \
`Variant(Type, ..., TypeN)` or `Variant { fields: Types }`";
- self.collect_tokens_trailing_token(
- variant_attrs,
- ForceCollect::No,
- |this, variant_attrs| {
- let vlo = this.token.span;
+ self.collect_tokens(None, variant_attrs, ForceCollect::No, |this, variant_attrs| {
+ let vlo = this.token.span;
- let vis = this.parse_visibility(FollowedByType::No)?;
- if !this.recover_nested_adt_item(kw::Enum)? {
- return Ok((None, false));
- }
- let ident = this.parse_field_ident("enum", vlo)?;
+ let vis = this.parse_visibility(FollowedByType::No)?;
+ if !this.recover_nested_adt_item(kw::Enum)? {
+ return Ok((None, Trailing::No, UsePreAttrPos::No));
+ }
+ let ident = this.parse_field_ident("enum", vlo)?;
- if this.token == token::Not {
- if let Err(err) = this.unexpected() {
- err.with_note(fluent::parse_macro_expands_to_enum_variant).emit();
- }
-
- this.bump();
- this.parse_delim_args()?;
-
- return Ok((None, this.token == token::Comma));
+ if this.token == token::Not {
+ if let Err(err) = this.unexpected() {
+ err.with_note(fluent::parse_macro_expands_to_enum_variant).emit();
}
- let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
- // Parse a struct variant.
- let (fields, recovered) =
- match this.parse_record_struct_body("struct", ident.span, false) {
- Ok((fields, recovered)) => (fields, recovered),
- Err(mut err) => {
- if this.token == token::Colon {
- // We handle `enum` to `struct` suggestion in the caller.
- return Err(err);
- }
- this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
- this.bump(); // }
- err.span_label(span, "while parsing this enum");
- err.help(help);
- let guar = err.emit();
- (thin_vec![], Recovered::Yes(guar))
- }
- };
- VariantData::Struct { fields, recovered: recovered.into() }
- } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
- let body = match this.parse_tuple_struct_body() {
- Ok(body) => body,
+ this.bump();
+ this.parse_delim_args()?;
+
+ return Ok((None, Trailing::from(this.token == token::Comma), UsePreAttrPos::No));
+ }
+
+ let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) {
+ // Parse a struct variant.
+ let (fields, recovered) =
+ match this.parse_record_struct_body("struct", ident.span, false) {
+ Ok((fields, recovered)) => (fields, recovered),
Err(mut err) => {
if this.token == token::Colon {
// We handle `enum` to `struct` suggestion in the caller.
return Err(err);
}
- this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
- this.bump(); // )
+ this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]);
+ this.bump(); // }
err.span_label(span, "while parsing this enum");
err.help(help);
- err.emit();
- thin_vec![]
+ let guar = err.emit();
+ (thin_vec![], Recovered::Yes(guar))
}
};
- VariantData::Tuple(body, DUMMY_NODE_ID)
- } else {
- VariantData::Unit(DUMMY_NODE_ID)
+ VariantData::Struct { fields, recovered: recovered.into() }
+ } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) {
+ let body = match this.parse_tuple_struct_body() {
+ Ok(body) => body,
+ Err(mut err) => {
+ if this.token == token::Colon {
+ // We handle `enum` to `struct` suggestion in the caller.
+ return Err(err);
+ }
+ this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
+ this.bump(); // )
+ err.span_label(span, "while parsing this enum");
+ err.help(help);
+ err.emit();
+ thin_vec![]
+ }
};
+ VariantData::Tuple(body, DUMMY_NODE_ID)
+ } else {
+ VariantData::Unit(DUMMY_NODE_ID)
+ };
- let disr_expr =
- if this.eat(&token::Eq) { Some(this.parse_expr_anon_const()?) } else { None };
+ let disr_expr =
+ if this.eat(&token::Eq) { Some(this.parse_expr_anon_const()?) } else { None };
- let vr = ast::Variant {
- ident,
- vis,
- id: DUMMY_NODE_ID,
- attrs: variant_attrs,
- data: struct_def,
- disr_expr,
- span: vlo.to(this.prev_token.span),
- is_placeholder: false,
- };
+ let vr = ast::Variant {
+ ident,
+ vis,
+ id: DUMMY_NODE_ID,
+ attrs: variant_attrs,
+ data: struct_def,
+ disr_expr,
+ span: vlo.to(this.prev_token.span),
+ is_placeholder: false,
+ };
- Ok((Some(vr), this.token == token::Comma))
- },
- )
+ Ok((Some(vr), Trailing::from(this.token == token::Comma), UsePreAttrPos::No))
+ })
.map_err(|mut err| {
err.help(help);
err
@@ -1777,7 +1775,7 @@ pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, ThinVec<FieldDef
// Unit like structs are handled in parse_item_struct function
self.parse_paren_comma_seq(|p| {
let attrs = p.parse_outer_attributes()?;
- p.collect_tokens_trailing_token(attrs, ForceCollect::No, |p, attrs| {
+ p.collect_tokens(None, attrs, ForceCollect::No, |p, attrs| {
let mut snapshot = None;
if p.is_vcs_conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
// Account for `<<<<<<<` diff markers. We can't proactively error here because
@@ -1815,7 +1813,8 @@ pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, ThinVec<FieldDef
attrs,
is_placeholder: false,
},
- p.token == token::Comma,
+ Trailing::from(p.token == token::Comma),
+ UsePreAttrPos::No,
))
})
})
@@ -1827,10 +1826,11 @@ fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
self.recover_vcs_conflict_marker();
let attrs = self.parse_outer_attributes()?;
self.recover_vcs_conflict_marker();
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let lo = this.token.span;
let vis = this.parse_visibility(FollowedByType::No)?;
- this.parse_single_struct_field(adt_ty, lo, vis, attrs).map(|field| (field, false))
+ this.parse_single_struct_field(adt_ty, lo, vis, attrs)
+ .map(|field| (field, Trailing::No, UsePreAttrPos::No))
})
}
@@ -1914,7 +1914,7 @@ fn parse_single_struct_field(
let mut err = self.dcx().struct_span_err(sp, msg);
if self.token.is_ident()
- || (self.token.kind == TokenKind::Pound
+ || (self.token == TokenKind::Pound
&& (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket))))
{
// This is likely another field, TokenKind::Pound is used for `#[..]`
@@ -1937,8 +1937,8 @@ fn parse_single_struct_field(
fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
if let Err(err) = self.expect(&token::Colon) {
let sm = self.psess.source_map();
- let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start());
- let semi_typo = self.token.kind == token::Semi
+ let eq_typo = self.token == token::Eq && self.look_ahead(1, |t| t.is_path_start());
+ let semi_typo = self.token == token::Semi
&& self.look_ahead(1, |t| {
t.is_path_start()
// We check that we are in a situation like `foo; bar` to avoid bad suggestions
@@ -1974,7 +1974,7 @@ fn parse_name_and_ty(
attrs: AttrVec,
) -> PResult<'a, FieldDef> {
let name = self.parse_field_ident(adt_ty, lo)?;
- if self.token.kind == token::Not {
+ if self.token == token::Not {
if let Err(mut err) = self.unexpected() {
// Encounter the macro invocation
err.subdiagnostic(MacroExpandsToAdtField { adt_ty });
@@ -1983,10 +1983,10 @@ fn parse_name_and_ty(
}
self.expect_field_ty_separator()?;
let ty = self.parse_ty_for_field_def()?;
- if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
+ if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) {
self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span });
}
- if self.token.kind == token::Eq {
+ if self.token == token::Eq {
self.bump();
let const_expr = self.parse_expr_anon_const()?;
let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
@@ -2064,7 +2064,7 @@ fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
.parse_ident_common(false)
// Cancel this error, we don't need it.
.map_err(|err| err.cancel())
- && self.token.kind == TokenKind::Colon
+ && self.token == TokenKind::Colon
{
err.span_suggestion(
removal_span,
@@ -2367,12 +2367,12 @@ fn error_fn_body_not_found(
match self.expected_one_of_not_found(&[], expected) {
Ok(error_guaranteed) => Ok(error_guaranteed),
Err(mut err) => {
- if self.token.kind == token::CloseDelim(Delimiter::Brace) {
+ if self.token == token::CloseDelim(Delimiter::Brace) {
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
// the AST for typechecking.
err.span_label(ident_span, "while parsing this `fn`");
Ok(err.emit())
- } else if self.token.kind == token::RArrow
+ } else if self.token == token::RArrow
&& let Some(fn_params_end) = fn_params_end
{
// Instead of a function body, the parser has encountered a right arrow
@@ -2445,7 +2445,7 @@ fn parse_fn_body(
fn_params_end: Option<Span>,
) -> PResult<'a, Option<P<Block>>> {
let has_semi = if req_body {
- self.token.kind == TokenKind::Semi
+ self.token == TokenKind::Semi
} else {
// Only include `;` in list of expected tokens if body is not required
self.check(&TokenKind::Semi)
@@ -2458,7 +2458,7 @@ fn parse_fn_body(
} else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
self.parse_block_common(self.token.span, BlockCheckMode::Default, false)
.map(|(attrs, body)| (attrs, Some(body)))?
- } else if self.token.kind == token::Eq {
+ } else if self.token == token::Eq {
// Recover `fn foo() = $expr;`.
self.bump(); // `=`
let eq_sp = self.prev_token.span;
@@ -2761,7 +2761,7 @@ pub(super) fn parse_fn_decl(
pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec<Param>> {
let mut first_param = true;
// Parse the arguments, starting out with `self` being allowed...
- if self.token.kind != TokenKind::OpenDelim(Delimiter::Parenthesis)
+ if self.token != TokenKind::OpenDelim(Delimiter::Parenthesis)
// might be typo'd trait impl, handled elsewhere
&& !self.token.is_keyword(kw::For)
{
@@ -2805,12 +2805,12 @@ pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinV
fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> {
let lo = self.token.span;
let attrs = self.parse_outer_attributes()?;
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
// Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
if let Some(mut param) = this.parse_self_param()? {
param.attrs = attrs;
let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) };
- return Ok((res?, false));
+ return Ok((res?, Trailing::No, UsePreAttrPos::No));
}
let is_name_required = match this.token.kind {
@@ -2826,7 +2826,7 @@ fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResu
this.parameter_without_type(&mut err, pat, is_name_required, first_param)
{
let guar = err.emit();
- Ok((dummy_arg(ident, guar), false))
+ Ok((dummy_arg(ident, guar), Trailing::No, UsePreAttrPos::No))
} else {
Err(err)
};
@@ -2869,7 +2869,8 @@ fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResu
Ok((
Param { attrs, id: ast::DUMMY_NODE_ID, is_placeholder: false, pat, span, ty },
- false,
+ Trailing::No,
+ UsePreAttrPos::No,
))
})
}
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 9b3b6d5..61e3fa2 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -14,7 +14,7 @@
use std::ops::Range;
use std::{fmt, mem, slice};
-use attr_wrapper::AttrWrapper;
+use attr_wrapper::{AttrWrapper, UsePreAttrPos};
pub use diagnostics::AttemptLocalParseRecovery;
pub(crate) use expr::ForbiddenLetReason;
pub(crate) use item::FnParseMode;
@@ -238,6 +238,7 @@ impl NodeRange {
// is the position of the function's start token. This gives
// `NodeRange(10..15)`.
fn new(ParserRange(parser_range): ParserRange, start_pos: u32) -> NodeRange {
+ assert!(parser_range.start >= start_pos && parser_range.end >= start_pos);
NodeRange((parser_range.start - start_pos)..(parser_range.end - start_pos))
}
}
@@ -253,7 +254,7 @@ enum Capturing {
Yes,
}
-// This state is used by `Parser::collect_tokens_trailing_token`.
+// This state is used by `Parser::collect_tokens`.
#[derive(Clone, Debug)]
struct CaptureState {
capturing: Capturing,
@@ -388,6 +389,12 @@ enum Trailing {
Yes,
}
+impl From<bool> for Trailing {
+ fn from(b: bool) -> Trailing {
+ if b { Trailing::Yes } else { Trailing::No }
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum TokenDescription {
ReservedIdentifier,
@@ -459,8 +466,8 @@ pub fn new(
parser.bump();
// Change this from 1 back to 0 after the bump. This eases debugging of
- // `Parser::collect_tokens_trailing_token` nicer because it makes the
- // token positions 0-indexed which is nicer than 1-indexed.
+ // `Parser::collect_tokens` because 0-indexed token positions are nicer
+ // than 1-indexed token positions.
parser.num_bump_calls = 0;
parser
@@ -527,7 +534,7 @@ fn expect_one_of(
} else if inedible.contains(&self.token.kind) {
// leave it in the input
Ok(Recovered::No)
- } else if self.token.kind != token::Eof
+ } else if self.token != token::Eof
&& self.last_unexpected_token_span == Some(self.token.span)
{
FatalError.raise();
@@ -756,7 +763,7 @@ fn check_plus(&mut self) -> bool {
/// compound tokens like multi-character operators in process.
/// Returns `true` if the token was eaten.
fn break_and_eat(&mut self, expected: TokenKind) -> bool {
- if self.token.kind == expected {
+ if self.token == expected {
self.bump();
return true;
}
@@ -882,7 +889,7 @@ fn parse_seq_to_before_tokens<T>(
let token_str = pprust::token_kind_to_string(t);
match self.current_closure.take() {
- Some(closure_spans) if self.token.kind == TokenKind::Semi => {
+ Some(closure_spans) if self.token == TokenKind::Semi => {
// Finding a semicolon instead of a comma
// after a closure body indicates that the
// closure body may be a block but the user
@@ -910,7 +917,7 @@ fn parse_seq_to_before_tokens<T>(
// If this was a missing `@` in a binding pattern
// bail with a suggestion
// https://github.com/rust-lang/rust/issues/72373
- if self.prev_token.is_ident() && self.token.kind == token::DotDot {
+ if self.prev_token.is_ident() && self.token == token::DotDot {
let msg = format!(
"if you meant to bind the contents of the rest of the array \
pattern into `{}`, use `@`",
@@ -1546,11 +1553,9 @@ fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>(
) -> PResult<'a, R> {
// The only reason to call `collect_tokens_no_attrs` is if you want tokens, so use
// `ForceCollect::Yes`
- self.collect_tokens_trailing_token(
- AttrWrapper::empty(),
- ForceCollect::Yes,
- |this, _attrs| Ok((f(this)?, false)),
- )
+ self.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |this, _attrs| {
+ Ok((f(this)?, Trailing::No, UsePreAttrPos::No))
+ })
}
/// `::{` or `::*`
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 5bfb8bd..eb9a957 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -13,7 +13,7 @@
use rustc_span::{BytePos, ErrorGuaranteed, Span};
use thin_vec::{thin_vec, ThinVec};
-use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing};
+use super::{ForceCollect, Parser, PathStyle, Restrictions, Trailing, UsePreAttrPos};
use crate::errors::{
self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
@@ -369,7 +369,7 @@ fn maybe_recover_trailing_expr(
.and_then(|(ident, _)| ident.name.as_str().chars().next())
.is_some_and(char::is_lowercase)
})
- && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis));
+ && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Parenthesis));
// Check for operators.
// `|` is excluded as it is used in pattern alternatives and lambdas,
@@ -377,9 +377,9 @@ fn maybe_recover_trailing_expr(
// `[` is included for indexing operations,
// `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`)
let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or)
- || self.token.kind == token::Question
- || (self.token.kind == token::OpenDelim(Delimiter::Bracket)
- && self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket)));
+ || self.token == token::Question
+ || (self.token == token::OpenDelim(Delimiter::Bracket)
+ && self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket)));
if !has_trailing_method && !has_trailing_operator {
// Nothing to recover here.
@@ -403,7 +403,7 @@ fn maybe_recover_trailing_expr(
// Parse an associative expression such as `+ expr`, `% expr`, ...
// Assignements, ranges and `|` are disabled by [`Restrictions::IS_PAT`].
- if let Ok(expr) =
+ if let Ok((expr, _)) =
snapshot.parse_expr_assoc_rest_with(0, false, expr).map_err(|err| err.cancel())
{
// We got a valid expression.
@@ -413,7 +413,7 @@ fn maybe_recover_trailing_expr(
let is_bound = is_end_bound
// is_start_bound: either `..` or `)..`
|| self.token.is_range_separator()
- || self.token.kind == token::CloseDelim(Delimiter::Parenthesis)
+ || self.token == token::CloseDelim(Delimiter::Parenthesis)
&& self.look_ahead(1, Token::is_range_separator);
// Check that `parse_expr_assoc_with` didn't eat a rhs.
@@ -450,7 +450,7 @@ fn parse_pat_with_range_pat(
lo = self.token.span;
}
- let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
+ let pat = if self.check(&token::BinOp(token::And)) || self.token == token::AndAnd {
self.parse_pat_deref(expected)?
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
self.parse_pat_tuple_or_parens()?
@@ -625,7 +625,7 @@ fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind {
///
/// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
- if self.token.kind != token::At {
+ if self.token != token::At {
// Next token is not `@` so it's not going to be an intersection pattern.
return Ok(lhs);
}
@@ -958,14 +958,14 @@ fn is_pat_range_end_start(&self, dist: usize) -> bool {
self.check_inline_const(dist)
|| self.look_ahead(dist, |t| {
t.is_path_start() // e.g. `MY_CONST`;
- || t.kind == token::Dot // e.g. `.5` for recovery;
+ || *t == token::Dot // e.g. `.5` for recovery;
|| matches!(t.kind, token::Literal(..) | token::BinOp(token::Minus))
|| t.is_bool_lit()
|| t.is_whole_expr()
|| t.is_lifetime() // recover `'a` instead of `'a'`
|| (self.may_recover() // recover leading `(`
- && t.kind == token::OpenDelim(Delimiter::Parenthesis)
- && self.look_ahead(dist + 1, |t| t.kind != token::OpenDelim(Delimiter::Parenthesis))
+ && *t == token::OpenDelim(Delimiter::Parenthesis)
+ && self.look_ahead(dist + 1, |t| *t != token::OpenDelim(Delimiter::Parenthesis))
&& self.is_pat_range_end_start(dist + 1))
})
}
@@ -1302,24 +1302,23 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
}
}
- let field =
- self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
- let field = match this.parse_pat_field(lo, attrs) {
- Ok(field) => Ok(field),
- Err(err) => {
- if let Some(delayed_err) = delayed_err.take() {
- delayed_err.emit();
- }
- return Err(err);
+ let field = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
+ let field = match this.parse_pat_field(lo, attrs) {
+ Ok(field) => Ok(field),
+ Err(err) => {
+ if let Some(delayed_err) = delayed_err.take() {
+ delayed_err.emit();
}
- }?;
- ate_comma = this.eat(&token::Comma);
+ return Err(err);
+ }
+ }?;
+ ate_comma = this.eat(&token::Comma);
- last_non_comma_dotdot_span = Some(this.prev_token.span);
+ last_non_comma_dotdot_span = Some(this.prev_token.span);
- // We just ate a comma, so there's no need to capture a trailing token.
- Ok((field, false))
- })?;
+ // We just ate a comma, so there's no need to capture a trailing token.
+ Ok((field, Trailing::No, UsePreAttrPos::No))
+ })?;
fields.push(field)
}
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 6f82d6b..b58f398 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -358,9 +358,9 @@ pub(super) fn parse_path_segment(
})?;
let span = lo.to(self.prev_token.span);
AngleBracketedArgs { args, span }.into()
- } else if self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
+ } else if self.token == token::OpenDelim(Delimiter::Parenthesis)
// FIXME(return_type_notation): Could also recover `...` here.
- && self.look_ahead(1, |tok| tok.kind == token::DotDot)
+ && self.look_ahead(1, |t| *t == token::DotDot)
{
self.bump(); // (
self.bump(); // ..
@@ -384,7 +384,7 @@ pub(super) fn parse_path_segment(
let token_before_parsing = self.token.clone();
let mut snapshot = None;
if self.may_recover()
- && prev_token_before_parsing.kind == token::PathSep
+ && prev_token_before_parsing == token::PathSep
&& (style == PathStyle::Expr && self.token.can_begin_expr()
|| style == PathStyle::Pat && self.token.can_begin_pattern())
{
@@ -393,7 +393,7 @@ pub(super) fn parse_path_segment(
let (inputs, _) = match self.parse_paren_comma_seq(|p| p.parse_ty()) {
Ok(output) => output,
- Err(mut error) if prev_token_before_parsing.kind == token::PathSep => {
+ Err(mut error) if prev_token_before_parsing == token::PathSep => {
error.span_label(
prev_token_before_parsing.span.to(token_before_parsing.span),
"while parsing this parenthesized list of type arguments starting here",
@@ -913,7 +913,7 @@ pub(super) fn parse_generic_arg(
let snapshot = self.create_snapshot_for_diagnostic();
let attrs = self.parse_outer_attributes()?;
match self.parse_expr_res(Restrictions::CONST_EXPR, attrs) {
- Ok(expr) => {
+ Ok((expr, _)) => {
return Ok(Some(self.dummy_const_arg_needs_braces(
self.dcx().struct_span_err(expr.span, "invalid const generic expression"),
expr.span,
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index b206f13..6904419 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -21,6 +21,7 @@
use super::path::PathStyle;
use super::{
AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
+ Trailing, UsePreAttrPos,
};
use crate::errors::MalformedLoopLabel;
use crate::{errors, maybe_whole};
@@ -45,6 +46,7 @@ pub fn parse_stmt_without_recovery(
capture_semi: bool,
force_collect: ForceCollect,
) -> PResult<'a, Option<Stmt>> {
+ let pre_attr_pos = self.collect_pos();
let attrs = self.parse_outer_attributes()?;
let lo = self.token.span;
@@ -65,11 +67,15 @@ pub fn parse_stmt_without_recovery(
}
Ok(Some(if self.token.is_keyword(kw::Let) {
- self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+ self.collect_tokens(None, attrs, force_collect, |this, attrs| {
this.expect_keyword(kw::Let)?;
let local = this.parse_local(attrs)?;
- let trailing = capture_semi && this.token.kind == token::Semi;
- Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing))
+ let trailing = Trailing::from(capture_semi && this.token == token::Semi);
+ Ok((
+ this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
+ trailing,
+ UsePreAttrPos::No,
+ ))
})?
} else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
self.recover_stmt_local_after_let(
@@ -103,10 +109,18 @@ pub fn parse_stmt_without_recovery(
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
// that starts like a path (1 token), but it fact not a path.
// Also, we avoid stealing syntax from `parse_item_`.
- let stmt = self.collect_tokens_trailing_token(
+ //
+ // `UsePreAttrPos::Yes` here means the attribute belongs unconditionally to the
+ // expression, not the statement. (But the statement attributes/tokens are obtained
+ // from the expression anyway, because `Stmt` delegates `HasAttrs`/`HasTokens` to
+ // the things within `StmtKind`.)
+ let stmt = self.collect_tokens(
+ Some(pre_attr_pos),
AttrWrapper::empty(),
force_collect,
- |this, _empty_attrs| Ok((this.parse_stmt_path_start(lo, attrs)?, false)),
+ |this, _empty_attrs| {
+ Ok((this.parse_stmt_path_start(lo, attrs)?, Trailing::No, UsePreAttrPos::Yes))
+ },
);
match stmt {
Ok(stmt) => stmt,
@@ -128,12 +142,15 @@ pub fn parse_stmt_without_recovery(
self.error_outer_attrs(attrs);
self.mk_stmt(lo, StmtKind::Empty)
} else if self.token != token::CloseDelim(Delimiter::Brace) {
- // Remainder are line-expr stmts.
- let e = self.collect_tokens_trailing_token(
+ // Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case
+ // above.
+ let e = self.collect_tokens(
+ Some(pre_attr_pos),
AttrWrapper::empty(),
force_collect,
|this, _empty_attrs| {
- Ok((this.parse_expr_res(Restrictions::STMT_EXPR, attrs)?, false))
+ let (expr, _) = this.parse_expr_res(Restrictions::STMT_EXPR, attrs)?;
+ Ok((expr, Trailing::No, UsePreAttrPos::Yes))
},
)?;
if matches!(e.kind, ExprKind::Assign(..)) && self.eat_keyword(kw::Else) {
@@ -150,12 +167,16 @@ pub fn parse_stmt_without_recovery(
}
fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a, Stmt> {
- let stmt = self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+ let stmt = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
let path = this.parse_path(PathStyle::Expr)?;
if this.eat(&token::Not) {
let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?;
- return Ok((stmt_mac, this.token == token::Semi));
+ return Ok((
+ stmt_mac,
+ Trailing::from(this.token == token::Semi),
+ UsePreAttrPos::No,
+ ));
}
let expr = if this.eat(&token::OpenDelim(Delimiter::Brace)) {
@@ -169,13 +190,17 @@ fn parse_stmt_path_start(&mut self, lo: Span, attrs: AttrWrapper) -> PResult<'a,
this.parse_expr_dot_or_call_with(attrs, expr, lo)
})?;
// `DUMMY_SP` will get overwritten later in this function
- Ok((this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)), false))
+ Ok((
+ this.mk_stmt(rustc_span::DUMMY_SP, StmtKind::Expr(expr)),
+ Trailing::No,
+ UsePreAttrPos::No,
+ ))
})?;
if let StmtKind::Expr(expr) = stmt.kind {
- // Perform this outside of the `collect_tokens_trailing_token` closure,
- // since our outer attributes do not apply to this part of the expression
- let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
+ // Perform this outside of the `collect_tokens` closure, since our
+ // outer attributes do not apply to this part of the expression.
+ let (expr, _) = self.with_res(Restrictions::STMT_EXPR, |this| {
this.parse_expr_assoc_rest_with(0, true, expr)
})?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
@@ -209,7 +234,7 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac));
let e = self.maybe_recover_from_bad_qpath(e)?;
let e = self.parse_expr_dot_or_call_with(attrs, e, lo)?;
- let e = self.parse_expr_assoc_rest_with(0, false, e)?;
+ let (e, _) = self.parse_expr_assoc_rest_with(0, false, e)?;
StmtKind::Expr(e)
};
Ok(self.mk_stmt(lo.to(hi), kind))
@@ -239,10 +264,14 @@ fn recover_stmt_local_after_let(
subdiagnostic: fn(Span) -> errors::InvalidVariableDeclarationSub,
force_collect: ForceCollect,
) -> PResult<'a, Stmt> {
- let stmt = self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+ let stmt = self.collect_tokens(None, attrs, force_collect, |this, attrs| {
let local = this.parse_local(attrs)?;
// FIXME - maybe capture semicolon in recovery?
- Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), false))
+ Ok((
+ this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)),
+ Trailing::No,
+ UsePreAttrPos::No,
+ ))
})?;
self.dcx()
.emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
@@ -760,7 +789,7 @@ pub fn parse_full_stmt(
)
),
);
- let suggest_eq = if self.token.kind == token::Dot
+ let suggest_eq = if self.token == token::Dot
&& let _ = self.bump()
&& let mut snapshot = self.create_snapshot_for_diagnostic()
&& let Ok(_) = snapshot
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 352ddd9..a8e8270 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -420,7 +420,7 @@ fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResu
let mut trailing_plus = false;
let (ts, trailing) = self.parse_paren_comma_seq(|p| {
let ty = p.parse_ty()?;
- trailing_plus = p.prev_token.kind == TokenKind::BinOp(token::Plus);
+ trailing_plus = p.prev_token == TokenKind::BinOp(token::Plus);
Ok(ty)
})?;
@@ -499,8 +499,8 @@ fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
let elt_ty = match self.parse_ty() {
Ok(ty) => ty,
Err(err)
- if self.look_ahead(1, |t| t.kind == token::CloseDelim(Delimiter::Bracket))
- | self.look_ahead(1, |t| t.kind == token::Semi) =>
+ if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Bracket))
+ | self.look_ahead(1, |t| *t == token::Semi) =>
{
// Recover from `[LIT; EXPR]` and `[LIT]`
self.bump();
@@ -601,7 +601,7 @@ fn parse_ty_bare_fn(
let span_start = self.token.span;
let ast::FnHeader { ext, safety, constness, coroutine_kind } =
self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
- if self.may_recover() && self.token.kind == TokenKind::Lt {
+ if self.may_recover() && self.token == TokenKind::Lt {
self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
}
let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
@@ -681,7 +681,7 @@ fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_generic_bounds()?;
- *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
+ *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::BinOp(token::Plus);
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
}
@@ -727,8 +727,7 @@ fn is_explicit_dyn_type(&mut self) -> bool {
self.check_keyword(kw::Dyn)
&& (self.token.uninterpolated_span().at_least_rust_2018()
|| self.look_ahead(1, |t| {
- (can_begin_dyn_bound_in_edition_2015(t)
- || t.kind == TokenKind::BinOp(token::Star))
+ (can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::BinOp(token::Star))
&& !can_continue_type_after_non_fn_ident(t)
}))
}
@@ -750,7 +749,7 @@ fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> {
// Always parse bounds greedily for better error recovery.
let bounds = self.parse_generic_bounds()?;
- *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
+ *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::BinOp(token::Plus);
Ok(TyKind::TraitObject(bounds, syntax))
}
@@ -1060,7 +1059,7 @@ fn parse_generic_ty_bound(
}
let mut path = if self.token.is_keyword(kw::Fn)
- && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
+ && self.look_ahead(1, |t| *t == TokenKind::OpenDelim(Delimiter::Parenthesis))
&& let Some(path) = self.recover_path_from_fn()
{
path
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index a64c00f..fce41bd 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -7,9 +7,7 @@
NestedMetaItem, Safety,
};
use rustc_errors::{Applicability, FatalError, PResult};
-use rustc_feature::{
- AttributeSafety, AttributeTemplate, BuiltinAttribute, Features, BUILTIN_ATTRIBUTE_MAP,
-};
+use rustc_feature::{AttributeSafety, AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_session::errors::report_lit_error;
use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE};
use rustc_session::lint::BuiltinLintDiag;
@@ -18,7 +16,7 @@
use crate::{errors, parse_in};
-pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
+pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
if attr.is_doc_comment() {
return;
}
@@ -28,7 +26,7 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
// All non-builtin attributes are considered safe
let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal);
- check_attribute_safety(features, psess, safety, attr);
+ check_attribute_safety(psess, safety, attr);
// Check input tokens for built-in and key-value attributes.
match attr_info {
@@ -36,9 +34,9 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) {
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
match parse_meta(psess, attr) {
// Don't check safety again, we just did that
- Ok(meta) => check_builtin_meta_item(
- features, psess, &meta, attr.style, *name, *template, false,
- ),
+ Ok(meta) => {
+ check_builtin_meta_item(psess, &meta, attr.style, *name, *template, false)
+ }
Err(err) => {
err.emit();
}
@@ -157,16 +155,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
}
}
-pub fn check_attribute_safety(
- features: &Features,
- psess: &ParseSess,
- safety: AttributeSafety,
- attr: &Attribute,
-) {
- if !features.unsafe_attributes {
- return;
- }
-
+pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) {
let attr_item = attr.get_normal_item();
if safety == AttributeSafety::Unsafe {
@@ -215,21 +204,18 @@ pub fn check_attribute_safety(
// Called by `check_builtin_meta_item` and code that manually denies
// `unsafe(...)` in `cfg`
-pub fn deny_builtin_meta_unsafety(features: &Features, psess: &ParseSess, meta: &MetaItem) {
+pub fn deny_builtin_meta_unsafety(psess: &ParseSess, meta: &MetaItem) {
// This only supports denying unsafety right now - making builtin attributes
// support unsafety will requite us to thread the actual `Attribute` through
// for the nice diagnostics.
- if features.unsafe_attributes {
- if let Safety::Unsafe(unsafe_span) = meta.unsafety {
- psess
- .dcx()
- .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() });
- }
+ if let Safety::Unsafe(unsafe_span) = meta.unsafety {
+ psess
+ .dcx()
+ .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() });
}
}
pub fn check_builtin_meta_item(
- features: &Features,
psess: &ParseSess,
meta: &MetaItem,
style: ast::AttrStyle,
@@ -246,7 +232,7 @@ pub fn check_builtin_meta_item(
}
if deny_unsafety {
- deny_builtin_meta_unsafety(features, psess, meta);
+ deny_builtin_meta_unsafety(psess, meta);
}
}
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 0318d34..1ea4ca3 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -430,6 +430,10 @@
.warn = {-passes_previously_accepted}
.label = not a function or static
+passes_linkage =
+ attribute should be applied to a function or static
+ .label = not a function definition or static
+
passes_macro_export =
`#[macro_export]` only has an effect on macro definitions
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index bd157d1..a47add9 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -243,6 +243,7 @@ fn check_attributes(
[sym::coroutine, ..] => {
self.check_coroutine(attr, target);
}
+ [sym::linkage, ..] => self.check_linkage(attr, span, target),
[
// ok
sym::allow
@@ -256,7 +257,6 @@ fn check_attributes(
| sym::cfi_encoding // FIXME(cfi_encoding)
| sym::may_dangle // FIXME(dropck_eyepatch)
| sym::pointee // FIXME(derive_smart_pointer)
- | sym::linkage // FIXME(linkage)
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
| sym::used // handled elsewhere to restrict to static items
| sym::repr // handled elsewhere to restrict to type decls items
@@ -2347,6 +2347,19 @@ fn check_coroutine(&self, attr: &Attribute, target: Target) {
}
}
}
+
+ fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) {
+ match target {
+ Target::Fn
+ | Target::Method(..)
+ | Target::Static
+ | Target::ForeignStatic
+ | Target::ForeignFn => {}
+ _ => {
+ self.dcx().emit_err(errors::Linkage { attr_span: attr.span, span });
+ }
+ }
+ }
}
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 36dfc40..3a043e0 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -644,6 +644,15 @@ pub struct CoroutineOnNonClosure {
}
#[derive(Diagnostic)]
+#[diag(passes_linkage)]
+pub struct Linkage {
+ #[primary_span]
+ pub attr_span: Span,
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
#[diag(passes_empty_confusables)]
pub(crate) struct EmptyConfusables {
#[primary_span]
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index bcd3d30..d7885e0 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -774,17 +774,16 @@ fn hoist_pat_range_bdy(
}
}
- /// Convert to a [`print::Pat`] for diagnostic purposes.
- fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> print::Pat<'tcx> {
- use print::{Pat, PatKind};
+ /// Prints an [`IntRange`] to a string for diagnostic purposes.
+ fn print_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> String {
use MaybeInfiniteInt::*;
let cx = self;
- let kind = if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
- PatKind::Wild
+ if matches!((range.lo, range.hi), (NegInfinity, PosInfinity)) {
+ "_".to_string()
} else if range.is_singleton() {
let lo = cx.hoist_pat_range_bdy(range.lo, ty);
let value = lo.as_finite().unwrap();
- PatKind::Constant { value }
+ value.to_string()
} else {
// We convert to an inclusive range for diagnostics.
let mut end = rustc_hir::RangeEnd::Included;
@@ -807,32 +806,24 @@ fn hoist_pat_range(&self, range: &IntRange, ty: RevealedTy<'tcx>) -> print::Pat<
range.hi
};
let hi = cx.hoist_pat_range_bdy(hi, ty);
- PatKind::Range(Box::new(PatRange { lo, hi, end, ty: ty.inner() }))
- };
-
- Pat { ty: ty.inner(), kind }
+ PatRange { lo, hi, end, ty: ty.inner() }.to_string()
+ }
}
/// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes.
+ ///
+ /// This panics for patterns that don't appear in diagnostics, like float ranges.
pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
- // This works by converting the witness pattern to a `print::Pat`
- // and then printing that, but callers don't need to know that.
- self.hoist_witness_pat(pat).to_string()
- }
-
- /// Convert to a [`print::Pat`] for diagnostic purposes. This panics for patterns that don't
- /// appear in diagnostics, like float ranges.
- fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
- use print::{FieldPat, Pat, PatKind};
let cx = self;
- let hoist = |p| Box::new(cx.hoist_witness_pat(p));
- let kind = match pat.ctor() {
- Bool(b) => PatKind::Constant { value: mir::Const::from_bool(cx.tcx, *b) },
- IntRange(range) => return self.hoist_pat_range(range, *pat.ty()),
+ let print = |p| cx.print_witness_pat(p);
+ match pat.ctor() {
+ Bool(b) => b.to_string(),
+ Str(s) => s.to_string(),
+ IntRange(range) => return self.print_pat_range(range, *pat.ty()),
Struct if pat.ty().is_box() => {
// Outside of the `alloc` crate, the only way to create a struct pattern
// of type `Box` is to use a `box` pattern via #[feature(box_patterns)].
- PatKind::Box { subpattern: hoist(&pat.fields[0]) }
+ format!("box {}", print(&pat.fields[0]))
}
Struct | Variant(_) | UnionField => {
let enum_info = match *pat.ty().kind() {
@@ -847,12 +838,29 @@ fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
let subpatterns = pat
.iter_fields()
.enumerate()
- .map(|(i, pat)| FieldPat { field: FieldIdx::new(i), pattern: hoist(pat) })
+ .map(|(i, pat)| print::FieldPat {
+ field: FieldIdx::new(i),
+ pattern: print(pat),
+ is_wildcard: would_print_as_wildcard(cx.tcx, pat),
+ })
.collect::<Vec<_>>();
- PatKind::StructLike { enum_info, subpatterns }
+ let mut s = String::new();
+ print::write_struct_like(
+ &mut s,
+ self.tcx,
+ pat.ty().inner(),
+ &enum_info,
+ &subpatterns,
+ )
+ .unwrap();
+ s
}
- Ref => PatKind::Deref { subpattern: hoist(&pat.fields[0]) },
+ Ref => {
+ let mut s = String::new();
+ print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap();
+ s
+ }
Slice(slice) => {
let (prefix_len, has_dot_dot) = match slice.kind {
SliceKind::FixedLen(len) => (len, false),
@@ -879,14 +887,15 @@ fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
}
}
- let prefix = prefix.iter().map(hoist).collect();
- let suffix = suffix.iter().map(hoist).collect();
+ let prefix = prefix.iter().map(print).collect::<Vec<_>>();
+ let suffix = suffix.iter().map(print).collect::<Vec<_>>();
- PatKind::Slice { prefix, has_dot_dot, suffix }
+ let mut s = String::new();
+ print::write_slice_like(&mut s, &prefix, has_dot_dot, &suffix).unwrap();
+ s
}
- &Str(value) => PatKind::Constant { value },
- Never if self.tcx.features().never_patterns => PatKind::Never,
- Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
+ Never if self.tcx.features().never_patterns => "!".to_string(),
+ Never | Wildcard | NonExhaustive | Hidden | PrivateUninhabited => "_".to_string(),
Missing { .. } => bug!(
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
`Missing` should have been processed in `apply_constructors`"
@@ -894,9 +903,7 @@ fn hoist_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> print::Pat<'tcx> {
F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => {
bug!("can't convert to pattern: {:?}", pat)
}
- };
-
- Pat { ty: pat.ty().inner(), kind }
+ }
}
}
@@ -972,7 +979,7 @@ fn lint_overlapping_range_endpoints(
overlaps_on: IntRange,
overlaps_with: &[&crate::pat::DeconstructedPat<Self>],
) {
- let overlap_as_pat = self.hoist_pat_range(&overlaps_on, *pat.ty());
+ let overlap_as_pat = self.print_pat_range(&overlaps_on, *pat.ty());
let overlaps: Vec<_> = overlaps_with
.iter()
.map(|pat| pat.data().span)
@@ -1012,7 +1019,7 @@ fn lint_non_contiguous_range_endpoints(
suggested_range.end = rustc_hir::RangeEnd::Included;
suggested_range.to_string()
};
- let gap_as_pat = self.hoist_pat_range(&gap, *pat.ty());
+ let gap_as_pat = self.print_pat_range(&gap, *pat.ty());
if gapped_with.is_empty() {
// If `gapped_with` is empty, `gap == T::MAX`.
self.tcx.emit_node_span_lint(
diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs
index 7d63871..17e389d 100644
--- a/compiler/rustc_pattern_analysis/src/rustc/print.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs
@@ -11,75 +11,16 @@
use std::fmt;
-use rustc_middle::thir::PatRange;
+use rustc_middle::bug;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
-use rustc_middle::{bug, mir};
use rustc_span::sym;
use rustc_target::abi::{FieldIdx, VariantIdx};
#[derive(Clone, Debug)]
-pub(crate) struct FieldPat<'tcx> {
+pub(crate) struct FieldPat {
pub(crate) field: FieldIdx,
- pub(crate) pattern: Box<Pat<'tcx>>,
-}
-
-#[derive(Clone, Debug)]
-pub(crate) struct Pat<'tcx> {
- pub(crate) ty: Ty<'tcx>,
- pub(crate) kind: PatKind<'tcx>,
-}
-
-#[derive(Clone, Debug)]
-pub(crate) enum PatKind<'tcx> {
- Wild,
-
- StructLike {
- enum_info: EnumInfo<'tcx>,
- subpatterns: Vec<FieldPat<'tcx>>,
- },
-
- Box {
- subpattern: Box<Pat<'tcx>>,
- },
-
- Deref {
- subpattern: Box<Pat<'tcx>>,
- },
-
- Constant {
- value: mir::Const<'tcx>,
- },
-
- Range(Box<PatRange<'tcx>>),
-
- Slice {
- prefix: Box<[Box<Pat<'tcx>>]>,
- /// True if this slice-like pattern should include a `..` between the
- /// prefix and suffix.
- has_dot_dot: bool,
- suffix: Box<[Box<Pat<'tcx>>]>,
- },
-
- Never,
-}
-
-impl<'tcx> fmt::Display for Pat<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.kind {
- PatKind::Wild => write!(f, "_"),
- PatKind::Never => write!(f, "!"),
- PatKind::Box { ref subpattern } => write!(f, "box {subpattern}"),
- PatKind::StructLike { ref enum_info, ref subpatterns } => {
- ty::tls::with(|tcx| write_struct_like(f, tcx, self.ty, enum_info, subpatterns))
- }
- PatKind::Deref { ref subpattern } => write_ref_like(f, self.ty, subpattern),
- PatKind::Constant { value } => write!(f, "{value}"),
- PatKind::Range(ref range) => write!(f, "{range}"),
- PatKind::Slice { ref prefix, has_dot_dot, ref suffix } => {
- write_slice_like(f, prefix, has_dot_dot, suffix)
- }
- }
- }
+ pub(crate) pattern: String,
+ pub(crate) is_wildcard: bool,
}
/// Returns a closure that will return `""` when called the first time,
@@ -103,12 +44,12 @@ pub(crate) enum EnumInfo<'tcx> {
NotEnum,
}
-fn write_struct_like<'tcx>(
+pub(crate) fn write_struct_like<'tcx>(
f: &mut impl fmt::Write,
tcx: TyCtxt<'_>,
ty: Ty<'tcx>,
enum_info: &EnumInfo<'tcx>,
- subpatterns: &[FieldPat<'tcx>],
+ subpatterns: &[FieldPat],
) -> fmt::Result {
let variant_and_name = match *enum_info {
EnumInfo::Enum { adt_def, variant_index } => {
@@ -139,12 +80,12 @@ fn write_struct_like<'tcx>(
write!(f, " {{ ")?;
let mut printed = 0;
- for p in subpatterns {
- if let PatKind::Wild = p.pattern.kind {
+ for &FieldPat { field, ref pattern, is_wildcard } in subpatterns {
+ if is_wildcard {
continue;
}
- let name = variant.fields[p.field].name;
- write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
+ let field_name = variant.fields[field].name;
+ write!(f, "{}{field_name}: {pattern}", start_or_comma())?;
printed += 1;
}
@@ -184,10 +125,10 @@ fn write_struct_like<'tcx>(
Ok(())
}
-fn write_ref_like<'tcx>(
+pub(crate) fn write_ref_like<'tcx>(
f: &mut impl fmt::Write,
ty: Ty<'tcx>,
- subpattern: &Pat<'tcx>,
+ subpattern: &str,
) -> fmt::Result {
match ty.kind() {
ty::Ref(_, _, mutbl) => {
@@ -198,11 +139,11 @@ fn write_ref_like<'tcx>(
write!(f, "{subpattern}")
}
-fn write_slice_like<'tcx>(
+pub(crate) fn write_slice_like(
f: &mut impl fmt::Write,
- prefix: &[Box<Pat<'tcx>>],
+ prefix: &[String],
has_dot_dot: bool,
- suffix: &[Box<Pat<'tcx>>],
+ suffix: &[String],
) -> fmt::Result {
let mut start_or_comma = start_or_comma();
write!(f, "[")?;
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 672dddf..693867c 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1188,7 +1188,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
let supported_sanitizers = sess.target.options.supported_sanitizers;
- let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
+ let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
+ // Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
+ // we should allow Shadow Call Stack sanitizer.
+ if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == "aarch64" {
+ unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
+ }
match unsupported_sanitizers.into_iter().count() {
0 => {}
1 => {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 8ce51ba..80f89a0 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1561,6 +1561,7 @@ fn $module() {
("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu),
("powerpc-unknown-linux-gnuspe", powerpc_unknown_linux_gnuspe),
("powerpc-unknown-linux-musl", powerpc_unknown_linux_musl),
+ ("powerpc-unknown-linux-muslspe", powerpc_unknown_linux_muslspe),
("powerpc64-ibm-aix", powerpc64_ibm_aix),
("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu),
("powerpc64-unknown-linux-musl", powerpc64_unknown_linux_musl),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs
new file mode 100644
index 0000000..d190157
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs
@@ -0,0 +1,28 @@
+use crate::abi::Endian;
+use crate::spec::{base, Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions};
+
+pub fn target() -> Target {
+ let mut base = base::linux_musl::opts();
+ base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mspe"]);
+ base.max_atomic_width = Some(32);
+ base.stack_probes = StackProbeType::Inline;
+
+ Target {
+ llvm_target: "powerpc-unknown-linux-muslspe".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: Some("PowerPC SPE Linux with musl".into()),
+ tier: Some(3),
+ host_tools: Some(false),
+ std: Some(true),
+ },
+ pointer_width: 32,
+ data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
+ arch: "powerpc".into(),
+ options: TargetOptions {
+ abi: "spe".into(),
+ endian: Endian::Big,
+ mcount: "_mcount".into(),
+ ..base
+ },
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 326a0e4..adeabb3 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1689,11 +1689,11 @@ pub(super) fn report_similar_impl_candidates(
err.highlighted_span_help(
span,
vec![
- StringPart::normal("you have ".to_string()),
+ StringPart::normal("there are ".to_string()),
StringPart::highlighted("multiple different versions".to_string()),
StringPart::normal(" of crate `".to_string()),
StringPart::highlighted(format!("{name}")),
- StringPart::normal("` in your dependency graph".to_string()),
+ StringPart::normal("` the your dependency graph".to_string()),
],
);
let candidates = if impl_candidates.is_empty() {
@@ -2729,6 +2729,10 @@ pub fn get_fn_like_arguments(
| Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
| Node::TraitItem(&hir::TraitItem {
kind: hir::TraitItemKind::Fn(ref sig, _), ..
+ })
+ | Node::ForeignItem(&hir::ForeignItem {
+ kind: hir::ForeignItemKind::Fn(ref sig, _, _),
+ ..
}) => (
sig.span,
None,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
deleted file mode 100644
index 656130c..0000000
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-pub use rustc_middle::traits::query::type_op::Eq;
-use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
-
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
-
-impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
- type QueryResponse = ();
-
- fn try_fast_path(
- _tcx: TyCtxt<'tcx>,
- key: &ParamEnvAnd<'tcx, Eq<'tcx>>,
- ) -> Option<Self::QueryResponse> {
- if key.value.a == key.value.b { Some(()) } else { None }
- }
-
- fn perform_query(
- tcx: TyCtxt<'tcx>,
- canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
- tcx.type_op_eq(canonicalized)
- }
-
- fn perform_locally_with_next_solver(
- ocx: &ObligationCtxt<'_, 'tcx>,
- key: ParamEnvAnd<'tcx, Self>,
- ) -> Result<Self::QueryResponse, NoSolution> {
- ocx.eq(&ObligationCause::dummy(), key.param_env, key.value.a, key.value.b)?;
- Ok(())
- }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 2f64ed9..a765de9 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -16,12 +16,10 @@
pub mod ascribe_user_type;
pub mod custom;
-pub mod eq;
pub mod implied_outlives_bounds;
pub mod normalize;
pub mod outlives;
pub mod prove_predicate;
-pub mod subtype;
pub use rustc_middle::traits::query::type_op::*;
@@ -170,44 +168,12 @@ fn fully_perform(
// collecting region constraints via `region_constraints`.
let (mut output, _) = scrape_region_constraints(
infcx,
- |_ocx| {
- let (output, ei, mut obligations, _) =
+ |ocx| {
+ let (output, ei, obligations, _) =
Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
error_info = ei;
- // Typically, instantiating NLL query results does not
- // create obligations. However, in some cases there
- // are unresolved type variables, and unify them *can*
- // create obligations. In that case, we have to go
- // fulfill them. We do this via a (recursive) query.
- while !obligations.is_empty() {
- trace!("{:#?}", obligations);
- let mut progress = false;
- for obligation in std::mem::take(&mut obligations) {
- let obligation = infcx.resolve_vars_if_possible(obligation);
- match ProvePredicate::fully_perform_into(
- obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
- infcx,
- &mut region_constraints,
- span,
- ) {
- Ok(((), _, new, certainty)) => {
- obligations.extend(new);
- progress = true;
- if let Certainty::Ambiguous = certainty {
- obligations.push(obligation);
- }
- }
- Err(_) => obligations.push(obligation),
- }
- }
- if !progress {
- infcx.dcx().span_bug(
- span,
- format!("ambiguity processing {obligations:?} from {self:?}"),
- );
- }
- }
+ ocx.register_obligations(obligations);
Ok(output)
},
"fully_perform",
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
deleted file mode 100644
index 892c2a1..0000000
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-pub use rustc_middle::traits::query::type_op::Subtype;
-use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
-
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
-
-impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
- type QueryResponse = ();
-
- fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> {
- if key.value.sub == key.value.sup { Some(()) } else { None }
- }
-
- fn perform_query(
- tcx: TyCtxt<'tcx>,
- canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
- tcx.type_op_subtype(canonicalized)
- }
-
- fn perform_locally_with_next_solver(
- ocx: &ObligationCtxt<'_, 'tcx>,
- key: ParamEnvAnd<'tcx, Self>,
- ) -> Result<Self::QueryResponse, NoSolution> {
- ocx.sub(&ObligationCause::dummy(), key.param_env, key.value.sub, key.value.sup)?;
- Ok(())
- }
-}
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 5affada..f34adf8 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -10,18 +10,14 @@
use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
type_op_ascribe_user_type_with_span, AscribeUserType,
};
-use rustc_trait_selection::traits::query::type_op::eq::Eq;
use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
-use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
pub(crate) fn provide(p: &mut Providers) {
*p = Providers {
type_op_ascribe_user_type,
- type_op_eq,
type_op_prove_predicate,
- type_op_subtype,
type_op_normalize_ty,
type_op_normalize_clause,
type_op_normalize_fn_sig,
@@ -39,16 +35,6 @@ fn type_op_ascribe_user_type<'tcx>(
})
}
-fn type_op_eq<'tcx>(
- tcx: TyCtxt<'tcx>,
- canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
-) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
- tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
- let (param_env, Eq { a, b }) = key.into_parts();
- Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?)
- })
-}
-
fn type_op_normalize<'tcx, T>(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Normalize<T>>,
@@ -91,16 +77,6 @@ fn type_op_normalize_poly_fn_sig<'tcx>(
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
}
-fn type_op_subtype<'tcx>(
- tcx: TyCtxt<'tcx>,
- canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>,
-) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
- tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
- let (param_env, Subtype { sub, sup }) = key.into_parts();
- Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?)
- })
-}
-
fn type_op_prove_predicate<'tcx>(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 76a89ea..2150463 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -36,8 +36,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::mem::{self, MaybeUninit};
-use crate::ptr;
+mod uninit;
/// A common trait for the ability to explicitly duplicate an object.
///
@@ -248,7 +247,7 @@ pub unsafe trait CloneToUninit {
/// * `dst` must be properly aligned.
/// * `dst` must have the same [pointer metadata] (slice length or `dyn` vtable) as `self`.
///
- /// [valid]: ptr#safety
+ /// [valid]: crate::ptr#safety
/// [pointer metadata]: crate::ptr::metadata()
///
/// # Panics
@@ -272,124 +271,42 @@ pub unsafe trait CloneToUninit {
#[unstable(feature = "clone_to_uninit", issue = "126799")]
unsafe impl<T: Clone> CloneToUninit for T {
- default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
- // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
- // ptr::write().
- unsafe {
- // We hope the optimizer will figure out to create the cloned value in-place,
- // skipping ever storing it on the stack and the copy to the destination.
- ptr::write(dst, self.clone());
- }
- }
-}
-
-// Specialized implementation for types that are [`Copy`], not just [`Clone`],
-// and can therefore be copied bitwise.
-#[unstable(feature = "clone_to_uninit", issue = "126799")]
-unsafe impl<T: Copy> CloneToUninit for T {
+ #[inline]
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
- // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
- // ptr::copy_nonoverlapping().
- unsafe {
- ptr::copy_nonoverlapping(self, dst, 1);
- }
+ // SAFETY: we're calling a specialization with the same contract
+ unsafe { <T as self::uninit::CopySpec>::clone_one(self, dst) }
}
}
#[unstable(feature = "clone_to_uninit", issue = "126799")]
unsafe impl<T: Clone> CloneToUninit for [T] {
+ #[inline]
#[cfg_attr(debug_assertions, track_caller)]
- default unsafe fn clone_to_uninit(&self, dst: *mut Self) {
- let len = self.len();
- // This is the most likely mistake to make, so check it as a debug assertion.
- debug_assert_eq!(
- len,
- dst.len(),
- "clone_to_uninit() source and destination must have equal lengths",
- );
-
- // SAFETY: The produced `&mut` is valid because:
- // * The caller is obligated to provide a pointer which is valid for writes.
- // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
- // initialization status.
- let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) };
-
- // Copy the elements
- let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
- for element_ref in self.iter() {
- // If the clone() panics, `initializing` will take care of the cleanup.
- initializing.push(element_ref.clone());
- }
- // If we reach here, then the entire slice is initialized, and we've satisfied our
- // responsibilities to the caller. Disarm the cleanup guard by forgetting it.
- mem::forget(initializing);
+ unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+ // SAFETY: we're calling a specialization with the same contract
+ unsafe { <T as self::uninit::CopySpec>::clone_slice(self, dst) }
}
}
#[unstable(feature = "clone_to_uninit", issue = "126799")]
-unsafe impl<T: Copy> CloneToUninit for [T] {
+unsafe impl CloneToUninit for str {
+ #[inline]
#[cfg_attr(debug_assertions, track_caller)]
unsafe fn clone_to_uninit(&self, dst: *mut Self) {
- let len = self.len();
- // This is the most likely mistake to make, so check it as a debug assertion.
- debug_assert_eq!(
- len,
- dst.len(),
- "clone_to_uninit() source and destination must have equal lengths",
- );
-
- // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
- // ptr::copy_nonoverlapping().
- unsafe {
- ptr::copy_nonoverlapping(self.as_ptr(), dst.as_mut_ptr(), len);
- }
+ // SAFETY: str is just a [u8] with UTF-8 invariant
+ unsafe { self.as_bytes().clone_to_uninit(dst as *mut [u8]) }
}
}
-/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
-/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
-/// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
-/// initialized, unless disarmed by forgetting.
-///
-/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
-struct InitializingSlice<'a, T> {
- data: &'a mut [MaybeUninit<T>],
- /// Number of elements of `*self.data` that are initialized.
- initialized_len: usize,
-}
-
-impl<'a, T> InitializingSlice<'a, T> {
- #[inline]
- fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
- Self { data, initialized_len: 0 }
- }
-
- /// Push a value onto the end of the initialized part of the slice.
- ///
- /// # Panics
- ///
- /// Panics if the slice is already fully initialized.
- #[inline]
- fn push(&mut self, value: T) {
- MaybeUninit::write(&mut self.data[self.initialized_len], value);
- self.initialized_len += 1;
- }
-}
-
-impl<'a, T> Drop for InitializingSlice<'a, T> {
- #[cold] // will only be invoked on unwind
- fn drop(&mut self) {
- let initialized_slice = ptr::slice_from_raw_parts_mut(
- MaybeUninit::slice_as_mut_ptr(self.data),
- self.initialized_len,
- );
- // SAFETY:
- // * the pointer is valid because it was made from a mutable reference
- // * `initialized_len` counts the initialized elements as an invariant of this type,
- // so each of the pointed-to elements is initialized and may be dropped.
- unsafe {
- ptr::drop_in_place::<[T]>(initialized_slice);
- }
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for crate::ffi::CStr {
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+ // SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants.
+ // And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).
+ // The pointer metadata properly preserves the length (NUL included).
+ // See: `cstr_metadata_is_length_with_nul` in tests.
+ unsafe { self.to_bytes_with_nul().clone_to_uninit(dst as *mut [u8]) }
}
}
diff --git a/library/core/src/clone/uninit.rs b/library/core/src/clone/uninit.rs
new file mode 100644
index 0000000..8b738be
--- /dev/null
+++ b/library/core/src/clone/uninit.rs
@@ -0,0 +1,128 @@
+use crate::mem::{self, MaybeUninit};
+use crate::ptr;
+
+/// Private specialization trait used by CloneToUninit, as per
+/// [the dev guide](https://std-dev-guide.rust-lang.org/policy/specialization.html).
+pub(super) unsafe trait CopySpec: Clone {
+ unsafe fn clone_one(src: &Self, dst: *mut Self);
+ unsafe fn clone_slice(src: &[Self], dst: *mut [Self]);
+}
+
+unsafe impl<T: Clone> CopySpec for T {
+ #[inline]
+ default unsafe fn clone_one(src: &Self, dst: *mut Self) {
+ // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
+ // ptr::write().
+ unsafe {
+ // We hope the optimizer will figure out to create the cloned value in-place,
+ // skipping ever storing it on the stack and the copy to the destination.
+ ptr::write(dst, src.clone());
+ }
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ default unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
+ let len = src.len();
+ // This is the most likely mistake to make, so check it as a debug assertion.
+ debug_assert_eq!(
+ len,
+ dst.len(),
+ "clone_to_uninit() source and destination must have equal lengths",
+ );
+
+ // SAFETY: The produced `&mut` is valid because:
+ // * The caller is obligated to provide a pointer which is valid for writes.
+ // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
+ // initialization status.
+ let uninit_ref = unsafe { &mut *(dst as *mut [MaybeUninit<T>]) };
+
+ // Copy the elements
+ let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
+ for element_ref in src {
+ // If the clone() panics, `initializing` will take care of the cleanup.
+ initializing.push(element_ref.clone());
+ }
+ // If we reach here, then the entire slice is initialized, and we've satisfied our
+ // responsibilities to the caller. Disarm the cleanup guard by forgetting it.
+ mem::forget(initializing);
+ }
+}
+
+// Specialized implementation for types that are [`Copy`], not just [`Clone`],
+// and can therefore be copied bitwise.
+unsafe impl<T: Copy> CopySpec for T {
+ #[inline]
+ unsafe fn clone_one(src: &Self, dst: *mut Self) {
+ // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
+ // ptr::copy_nonoverlapping().
+ unsafe {
+ ptr::copy_nonoverlapping(src, dst, 1);
+ }
+ }
+
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_slice(src: &[Self], dst: *mut [Self]) {
+ let len = src.len();
+ // This is the most likely mistake to make, so check it as a debug assertion.
+ debug_assert_eq!(
+ len,
+ dst.len(),
+ "clone_to_uninit() source and destination must have equal lengths",
+ );
+
+ // SAFETY: The safety conditions of clone_to_uninit() are a superset of those of
+ // ptr::copy_nonoverlapping().
+ unsafe {
+ ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), len);
+ }
+ }
+}
+
+/// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
+/// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
+/// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
+/// initialized, unless disarmed by forgetting.
+///
+/// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
+struct InitializingSlice<'a, T> {
+ data: &'a mut [MaybeUninit<T>],
+ /// Number of elements of `*self.data` that are initialized.
+ initialized_len: usize,
+}
+
+impl<'a, T> InitializingSlice<'a, T> {
+ #[inline]
+ fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
+ Self { data, initialized_len: 0 }
+ }
+
+ /// Push a value onto the end of the initialized part of the slice.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the slice is already fully initialized.
+ #[inline]
+ fn push(&mut self, value: T) {
+ MaybeUninit::write(&mut self.data[self.initialized_len], value);
+ self.initialized_len += 1;
+ }
+}
+
+impl<'a, T> Drop for InitializingSlice<'a, T> {
+ #[cold] // will only be invoked on unwind
+ fn drop(&mut self) {
+ let initialized_slice = ptr::slice_from_raw_parts_mut(
+ MaybeUninit::slice_as_mut_ptr(self.data),
+ self.initialized_len,
+ );
+ // SAFETY:
+ // * the pointer is valid because it was made from a mutable reference
+ // * `initialized_len` counts the initialized elements as an invariant of this type,
+ // so each of the pointed-to elements is initialized and may be dropped.
+ unsafe {
+ ptr::drop_in_place::<[T]>(initialized_slice);
+ }
+ }
+}
diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs
index a07b63f..6f6da8c 100644
--- a/library/core/src/future/ready.rs
+++ b/library/core/src/future/ready.rs
@@ -34,13 +34,12 @@ impl<T> Ready<T> {
/// # Examples
///
/// ```
- /// #![feature(ready_into_inner)]
/// use std::future;
///
/// let a = future::ready(1);
/// assert_eq!(a.into_inner(), 1);
/// ```
- #[unstable(feature = "ready_into_inner", issue = "101196")]
+ #[stable(feature = "ready_into_inner", since = "CURRENT_RUSTC_VERSION")]
#[must_use]
#[inline]
pub fn into_inner(self) -> T {
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 297dd0a..4c8f9fe 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -317,3 +317,60 @@ fn spec_for_each<F: FnMut(Self::Item)>(mut self, mut f: F) {
}
}
}
+
+#[stable(feature = "exact_size_take_repeat", since = "CURRENT_RUSTC_VERSION")]
+impl<T: Clone> DoubleEndedIterator for Take<crate::iter::Repeat<T>> {
+ #[inline]
+ fn next_back(&mut self) -> Option<Self::Item> {
+ self.next()
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ self.nth(n)
+ }
+
+ #[inline]
+ fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> R,
+ R: Try<Output = Acc>,
+ {
+ self.try_fold(init, fold)
+ }
+
+ #[inline]
+ fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
+ where
+ Self: Sized,
+ Fold: FnMut(Acc, Self::Item) -> Acc,
+ {
+ self.fold(init, fold)
+ }
+
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+ self.advance_by(n)
+ }
+}
+
+// Note: It may be tempting to impl DoubleEndedIterator for Take<RepeatWith>.
+// One must fight that temptation since such implementation wouldn’t be correct
+// because we have no way to return value of nth invocation of repeater followed
+// by n-1st without remembering all results.
+
+#[stable(feature = "exact_size_take_repeat", since = "CURRENT_RUSTC_VERSION")]
+impl<T: Clone> ExactSizeIterator for Take<crate::iter::Repeat<T>> {
+ fn len(&self) -> usize {
+ self.n
+ }
+}
+
+#[stable(feature = "exact_size_take_repeat", since = "CURRENT_RUSTC_VERSION")]
+impl<F: FnMut() -> A, A> ExactSizeIterator for Take<crate::iter::RepeatWith<F>> {
+ fn len(&self) -> usize {
+ self.n
+ }
+}
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 6a83ec2..374fa08 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1060,7 +1060,7 @@ pub trait FnPtr: Copy + Clone {
}
/// Derive macro generating impls of traits related to smart pointers.
-#[rustc_builtin_macro]
+#[rustc_builtin_macro(SmartPointer, attributes(pointee))]
#[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
#[unstable(feature = "derive_smart_pointer", issue = "123430")]
pub macro SmartPointer($item:item) {
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 3e036b8..919f681 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -1,6 +1,7 @@
use super::display_buffer::DisplayBuffer;
use crate::cmp::Ordering;
use crate::fmt::{self, Write};
+use crate::hash::{Hash, Hasher};
use crate::iter;
use crate::mem::transmute;
use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
@@ -67,12 +68,22 @@ pub enum IpAddr {
/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Ipv4Addr {
octets: [u8; 4],
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for Ipv4Addr {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ // Hashers are often more efficient at hashing a fixed-width integer
+ // than a bytestring, so convert before hashing. We don't use to_bits()
+ // here as that may involve a byteswap which is unnecessary.
+ u32::from_ne_bytes(self.octets).hash(state);
+ }
+}
+
/// An IPv6 address.
///
/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
@@ -149,12 +160,22 @@ pub struct Ipv4Addr {
/// assert_eq!("::1".parse(), Ok(localhost));
/// assert_eq!(localhost.is_loopback(), true);
/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Ipv6Addr {
octets: [u8; 16],
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for Ipv6Addr {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ // Hashers are often more efficient at hashing a fixed-width integer
+ // than a bytestring, so convert before hashing. We don't use to_bits()
+ // here as that may involve unnecessary byteswaps.
+ u128::from_ne_bytes(self.octets).hash(state);
+ }
+}
+
/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
///
/// # Stability Guarantees
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 0c04f47..38e69e7 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -290,7 +290,7 @@ pub const fn is_nan(self) -> bool {
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f128 {
- // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+ // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe {
mem::transmute::<u128, f128>(mem::transmute::<f128, u128>(self) & !Self::SIGN_MASK)
}
@@ -439,22 +439,12 @@ pub const fn is_normal(self) -> bool {
#[unstable(feature = "f128", issue = "116909")]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub const fn classify(self) -> FpCategory {
- // Other float types cannot use a bitwise classify because they may suffer a variety
- // of errors if the backend chooses to cast to different float types (x87). `f128` cannot
- // fit into any other float types so this is not a concern, and we rely on bit patterns.
+ // Other float types suffer from various platform bugs that violate the usual IEEE semantics
+ // and also make bitwise classification not always work reliably. However, `f128` cannot fit
+ // into any other float types so this is not a concern, and we can rely on bit patterns.
- // SAFETY: POD bitcast, same as in `to_bits`.
- let bits = unsafe { mem::transmute::<f128, u128>(self) };
- Self::classify_bits(bits)
- }
-
- /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
- /// FIXME(jubilee): In a just world, this would be the entire impl for classify,
- /// plus a transmute. We do not live in a just world, but we can make it more so.
- #[inline]
- #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const fn classify_bits(b: u128) -> FpCategory {
- match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
+ let bits = self.to_bits();
+ match (bits & Self::MAN_MASK, bits & Self::EXP_MASK) {
(0, Self::EXP_MASK) => FpCategory::Infinite,
(_, Self::EXP_MASK) => FpCategory::Nan,
(0, 0) => FpCategory::Zero,
@@ -922,48 +912,7 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_bits(self) -> u128 {
// SAFETY: `u128` is a plain old datatype so we can always transmute to it.
- // ...sorta.
- //
- // It turns out that at runtime, it is possible for a floating point number
- // to be subject to a floating point mode that alters nonzero subnormal numbers
- // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
- //
- // And, of course evaluating to a NaN value is fairly nondeterministic.
- // More precisely: when NaN should be returned is knowable, but which NaN?
- // So far that's defined by a combination of LLVM and the CPU, not Rust.
- // This function, however, allows observing the bitstring of a NaN,
- // thus introspection on CTFE.
- //
- // In order to preserve, at least for the moment, const-to-runtime equivalence,
- // we reject any of these possible situations from happening.
- #[inline]
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_f128_to_u128(ct: f128) -> u128 {
- // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but that
- // is not available on all platforms (needs `netf2` and `unordtf2`). So classify
- // the bits instead.
-
- // SAFETY: this is a POD transmutation
- let bits = unsafe { mem::transmute::<f128, u128>(ct) };
- match f128::classify_bits(bits) {
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f128::to_bits on a NaN")
- }
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f128::to_bits on a subnormal number")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits,
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_f128_to_u128(x: f128) -> u128 {
- // SAFETY: `u128` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute(x) }
- }
- intrinsics::const_eval_select((self,), ct_f128_to_u128, rt_f128_to_u128)
+ unsafe { mem::transmute(self) }
}
/// Raw transmutation from `u128`.
@@ -1011,49 +960,8 @@ fn rt_f128_to_u128(x: f128) -> u128 {
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
pub const fn from_bits(v: u128) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
- // SAFETY: `u128` is a plain old datatype so we can always transmute from it
- // ...sorta.
- //
- // It turns out that at runtime, it is possible for a floating point number
- // to be subject to floating point modes that alter nonzero subnormal numbers
- // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
- // This is not a problem usually, but at least one tier2 platform for Rust
- // actually exhibits this behavior by default: thumbv7neon
- // aka "the Neon FPU in AArch32 state"
- //
- // And, of course evaluating to a NaN value is fairly nondeterministic.
- // More precisely: when NaN should be returned is knowable, but which NaN?
- // So far that's defined by a combination of LLVM and the CPU, not Rust.
- // This function, however, allows observing the bitstring of a NaN,
- // thus introspection on CTFE.
- //
- // In order to preserve, at least for the moment, const-to-runtime equivalence,
- // reject any of these possible situations from happening.
- #[inline]
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_u128_to_f128(ct: u128) -> f128 {
- match f128::classify_bits(ct) {
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f128::from_bits on a subnormal number")
- }
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f128::from_bits on NaN")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
- // SAFETY: It's not a frumious number
- unsafe { mem::transmute::<u128, f128>(ct) }
- }
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_u128_to_f128(x: u128) -> f128 {
- // SAFETY: `u128` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute(x) }
- }
- intrinsics::const_eval_select((v,), ct_u128_to_f128, rt_u128_to_f128)
+ // SAFETY: `u128` is a plain old datatype so we can always transmute from it.
+ unsafe { mem::transmute(v) }
}
/// Returns the memory representation of this floating point number as a byte array in
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index e5b1148..41bd34a 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -284,7 +284,7 @@ pub const fn is_nan(self) -> bool {
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f16 {
- // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+ // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u16, f16>(mem::transmute::<f16, u16>(self) & !Self::SIGN_MASK) }
}
@@ -426,15 +426,15 @@ pub const fn is_normal(self) -> bool {
pub const fn classify(self) -> FpCategory {
// A previous implementation for f32/f64 tried to only use bitmask-based checks,
// using `to_bits` to transmute the float to its bit repr and match on that.
- // Unfortunately, floating point numbers can be much worse than that.
- // This also needs to not result in recursive evaluations of `to_bits`.
+ // If we only cared about being "technically" correct, that's an entirely legit
+ // implementation.
//
-
- // Platforms without native support generally convert to `f32` to perform operations,
- // and most of these platforms correctly round back to `f16` after each operation.
- // However, some platforms have bugs where they keep the excess `f32` precision (e.g.
- // WASM, see llvm/llvm-project#96437). This implementation makes a best-effort attempt
- // to account for that excess precision.
+ // Unfortunately, there are platforms out there that do not correctly implement the IEEE
+ // float semantics Rust relies on: some hardware flushes denormals to zero, and some
+ // platforms convert to `f32` to perform operations without properly rounding back (e.g.
+ // WASM, see llvm/llvm-project#96437). These are platforms bugs, and Rust will misbehave on
+ // such platforms, but we can at least try to make things seem as sane as possible by being
+ // careful here.
if self.is_infinite() {
// Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
FpCategory::Infinite
@@ -446,49 +446,20 @@ pub const fn classify(self) -> FpCategory {
// as correctness requires avoiding equality tests that may be Subnormal == -0.0
// because it may be wrong under "denormals are zero" and "flush to zero" modes.
// Most of std's targets don't use those, but they are used for thumbv7neon.
- // So, this does use bitpattern matching for the rest.
-
- // SAFETY: f16 to u16 is fine. Usually.
- // If classify has gotten this far, the value is definitely in one of these categories.
- unsafe { f16::partial_classify(self) }
- }
- }
-
- /// This doesn't actually return a right answer for NaN on purpose,
- /// seeing as how it cannot correctly discern between a floating point NaN,
- /// and some normal floating point numbers truncated from an x87 FPU.
- ///
- /// # Safety
- ///
- /// This requires making sure you call this function for values it answers correctly on,
- /// otherwise it returns a wrong answer. This is not important for memory safety per se,
- /// but getting floats correct is important for not accidentally leaking const eval
- /// runtime-deviating logic which may or may not be acceptable.
- #[inline]
- #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const unsafe fn partial_classify(self) -> FpCategory {
- // SAFETY: The caller is not asking questions for which this will tell lies.
- let b = unsafe { mem::transmute::<f16, u16>(self) };
- match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
- (0, Self::EXP_MASK) => FpCategory::Infinite,
- (0, 0) => FpCategory::Zero,
- (_, 0) => FpCategory::Subnormal,
- _ => FpCategory::Normal,
- }
- }
-
- /// This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
- /// FIXME(jubilee): In a just world, this would be the entire impl for classify,
- /// plus a transmute. We do not live in a just world, but we can make it more so.
- #[inline]
- #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const fn classify_bits(b: u16) -> FpCategory {
- match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
- (0, Self::EXP_MASK) => FpCategory::Infinite,
- (_, Self::EXP_MASK) => FpCategory::Nan,
- (0, 0) => FpCategory::Zero,
- (_, 0) => FpCategory::Subnormal,
- _ => FpCategory::Normal,
+ // So, this does use bitpattern matching for the rest. On x87, due to the incorrect
+ // float codegen on this hardware, this doesn't actually return a right answer for NaN
+ // because it cannot correctly discern between a floating point NaN, and some normal
+ // floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so
+ // we are fine.
+ // FIXME(jubilee): This probably could at least answer things correctly for Infinity,
+ // like the f64 version does, but I need to run more checks on how things go on x86.
+ // I fear losing mantissa data that would have answered that differently.
+ let b = self.to_bits();
+ match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
+ (0, 0) => FpCategory::Zero,
+ (_, 0) => FpCategory::Subnormal,
+ _ => FpCategory::Normal,
+ }
}
}
@@ -952,48 +923,7 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn to_bits(self) -> u16 {
// SAFETY: `u16` is a plain old datatype so we can always transmute to it.
- // ...sorta.
- //
- // It turns out that at runtime, it is possible for a floating point number
- // to be subject to a floating point mode that alters nonzero subnormal numbers
- // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
- //
- // And, of course evaluating to a NaN value is fairly nondeterministic.
- // More precisely: when NaN should be returned is knowable, but which NaN?
- // So far that's defined by a combination of LLVM and the CPU, not Rust.
- // This function, however, allows observing the bitstring of a NaN,
- // thus introspection on CTFE.
- //
- // In order to preserve, at least for the moment, const-to-runtime equivalence,
- // we reject any of these possible situations from happening.
- #[inline]
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_f16_to_u16(ct: f16) -> u16 {
- // FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but we don't yet
- // want to rely on that on all platforms because it is nondeterministic (e.g. x86 has
- // convention discrepancies calling intrinsics). So just classify the bits instead.
-
- // SAFETY: this is a POD transmutation
- let bits = unsafe { mem::transmute::<f16, u16>(ct) };
- match f16::classify_bits(bits) {
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f16::to_bits on a NaN")
- }
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f16::to_bits on a subnormal number")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits,
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_f16_to_u16(x: f16) -> u16 {
- // SAFETY: `u16` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute(x) }
- }
- intrinsics::const_eval_select((self,), ct_f16_to_u16, rt_f16_to_u16)
+ unsafe { mem::transmute(self) }
}
/// Raw transmutation from `u16`.
@@ -1040,49 +970,8 @@ fn rt_f16_to_u16(x: f16) -> u16 {
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
pub const fn from_bits(v: u16) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
- // SAFETY: `u16` is a plain old datatype so we can always transmute from it
- // ...sorta.
- //
- // It turns out that at runtime, it is possible for a floating point number
- // to be subject to floating point modes that alter nonzero subnormal numbers
- // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
- // This is not a problem usually, but at least one tier2 platform for Rust
- // actually exhibits this behavior by default: thumbv7neon
- // aka "the Neon FPU in AArch32 state"
- //
- // And, of course evaluating to a NaN value is fairly nondeterministic.
- // More precisely: when NaN should be returned is knowable, but which NaN?
- // So far that's defined by a combination of LLVM and the CPU, not Rust.
- // This function, however, allows observing the bitstring of a NaN,
- // thus introspection on CTFE.
- //
- // In order to preserve, at least for the moment, const-to-runtime equivalence,
- // reject any of these possible situations from happening.
- #[inline]
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_u16_to_f16(ct: u16) -> f16 {
- match f16::classify_bits(ct) {
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f16::from_bits on a subnormal number")
- }
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f16::from_bits on NaN")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
- // SAFETY: It's not a frumious number
- unsafe { mem::transmute::<u16, f16>(ct) }
- }
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_u16_to_f16(x: u16) -> f16 {
- // SAFETY: `u16` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute(x) }
- }
- intrinsics::const_eval_select((v,), ct_u16_to_f16, rt_u16_to_f16)
+ // SAFETY: `u16` is a plain old datatype so we can always transmute from it.
+ unsafe { mem::transmute(v) }
}
/// Returns the memory representation of this floating point number as a byte array in
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 7710e23..719727e 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -529,7 +529,7 @@ pub const fn is_nan(self) -> bool {
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f32 {
- // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+ // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u32, f32>(mem::transmute::<f32, u32>(self) & !Self::SIGN_MASK) }
}
@@ -654,18 +654,20 @@ pub const fn is_normal(self) -> bool {
pub const fn classify(self) -> FpCategory {
// A previous implementation tried to only use bitmask-based checks,
// using f32::to_bits to transmute the float to its bit repr and match on that.
- // Unfortunately, floating point numbers can be much worse than that.
- // This also needs to not result in recursive evaluations of f64::to_bits.
+ // If we only cared about being "technically" correct, that's an entirely legit
+ // implementation.
//
- // On some processors, in some cases, LLVM will "helpfully" lower floating point ops,
- // in spite of a request for them using f32 and f64, to things like x87 operations.
- // These have an f64's mantissa, but can have a larger than normal exponent.
+ // Unfortunately, there is hardware out there that does not correctly implement the IEEE
+ // float semantics Rust relies on: x87 uses a too-large mantissa and exponent, and some
+ // hardware flushes subnormals to zero. These are platforms bugs, and Rust will misbehave on
+ // such hardware, but we can at least try to make things seem as sane as possible by being
+ // careful here.
+ //
// FIXME(jubilee): Using x87 operations is never necessary in order to function
// on x86 processors for Rust-to-Rust calls, so this issue should not happen.
// Code generation should be adjusted to use non-C calling conventions, avoiding this.
- //
if self.is_infinite() {
- // Thus, a value may compare unequal to infinity, despite having a "full" exponent mask.
+ // A value may compare unequal to infinity, despite having a "full" exponent mask.
FpCategory::Infinite
} else if self.is_nan() {
// And it may not be NaN, as it can simply be an "overextended" finite value.
@@ -675,48 +677,20 @@ pub const fn classify(self) -> FpCategory {
// as correctness requires avoiding equality tests that may be Subnormal == -0.0
// because it may be wrong under "denormals are zero" and "flush to zero" modes.
// Most of std's targets don't use those, but they are used for thumbv7neon.
- // So, this does use bitpattern matching for the rest.
-
- // SAFETY: f32 to u32 is fine. Usually.
- // If classify has gotten this far, the value is definitely in one of these categories.
- unsafe { f32::partial_classify(self) }
- }
- }
-
- // This doesn't actually return a right answer for NaN on purpose,
- // seeing as how it cannot correctly discern between a floating point NaN,
- // and some normal floating point numbers truncated from an x87 FPU.
- // FIXME(jubilee): This probably could at least answer things correctly for Infinity,
- // like the f64 version does, but I need to run more checks on how things go on x86.
- // I fear losing mantissa data that would have answered that differently.
- //
- // # Safety
- // This requires making sure you call this function for values it answers correctly on,
- // otherwise it returns a wrong answer. This is not important for memory safety per se,
- // but getting floats correct is important for not accidentally leaking const eval
- // runtime-deviating logic which may or may not be acceptable.
- #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const unsafe fn partial_classify(self) -> FpCategory {
- // SAFETY: The caller is not asking questions for which this will tell lies.
- let b = unsafe { mem::transmute::<f32, u32>(self) };
- match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
- (0, 0) => FpCategory::Zero,
- (_, 0) => FpCategory::Subnormal,
- _ => FpCategory::Normal,
- }
- }
-
- // This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
- // FIXME(jubilee): In a just world, this would be the entire impl for classify,
- // plus a transmute. We do not live in a just world, but we can make it more so.
- #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const fn classify_bits(b: u32) -> FpCategory {
- match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
- (0, Self::EXP_MASK) => FpCategory::Infinite,
- (_, Self::EXP_MASK) => FpCategory::Nan,
- (0, 0) => FpCategory::Zero,
- (_, 0) => FpCategory::Subnormal,
- _ => FpCategory::Normal,
+ // So, this does use bitpattern matching for the rest. On x87, due to the incorrect
+ // float codegen on this hardware, this doesn't actually return a right answer for NaN
+ // because it cannot correctly discern between a floating point NaN, and some normal
+ // floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so
+ // we are fine.
+ // FIXME(jubilee): This probably could at least answer things correctly for Infinity,
+ // like the f64 version does, but I need to run more checks on how things go on x86.
+ // I fear losing mantissa data that would have answered that differently.
+ let b = self.to_bits();
+ match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
+ (0, 0) => FpCategory::Zero,
+ (_, 0) => FpCategory::Subnormal,
+ _ => FpCategory::Normal,
+ }
}
}
@@ -1143,51 +1117,7 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
#[inline]
pub const fn to_bits(self) -> u32 {
// SAFETY: `u32` is a plain old datatype so we can always transmute to it.
- // ...sorta.
- //
- // It turns out that at runtime, it is possible for a floating point number
- // to be subject to a floating point mode that alters nonzero subnormal numbers
- // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
- // This is not a problem per se, but at least one tier2 platform for Rust
- // actually exhibits this behavior by default.
- //
- // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
- // i.e. not soft-float, the way Rust does parameter passing can actually alter
- // a number that is "not infinity" to have the same exponent as infinity,
- // in a slightly unpredictable manner.
- //
- // And, of course evaluating to a NaN value is fairly nondeterministic.
- // More precisely: when NaN should be returned is knowable, but which NaN?
- // So far that's defined by a combination of LLVM and the CPU, not Rust.
- // This function, however, allows observing the bitstring of a NaN,
- // thus introspection on CTFE.
- //
- // In order to preserve, at least for the moment, const-to-runtime equivalence,
- // we reject any of these possible situations from happening.
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_f32_to_u32(ct: f32) -> u32 {
- match ct.classify() {
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f32::to_bits on a NaN")
- }
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f32::to_bits on a subnormal number")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
- // SAFETY: We have a normal floating point number. Now we transmute, i.e. do a bitcopy.
- unsafe { mem::transmute::<f32, u32>(ct) }
- }
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_f32_to_u32(x: f32) -> u32 {
- // SAFETY: `u32` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute(x) }
- }
- intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32)
+ unsafe { mem::transmute(self) }
}
/// Raw transmutation from `u32`.
@@ -1232,53 +1162,8 @@ fn rt_f32_to_u32(x: f32) -> u32 {
#[inline]
pub const fn from_bits(v: u32) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
- // SAFETY: `u32` is a plain old datatype so we can always transmute from it
- // ...sorta.
- //
- // It turns out that at runtime, it is possible for a floating point number
- // to be subject to floating point modes that alter nonzero subnormal numbers
- // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
- // This is not a problem usually, but at least one tier2 platform for Rust
- // actually exhibits this behavior by default: thumbv7neon
- // aka "the Neon FPU in AArch32 state"
- //
- // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
- // i.e. not soft-float, the way Rust does parameter passing can actually alter
- // a number that is "not infinity" to have the same exponent as infinity,
- // in a slightly unpredictable manner.
- //
- // And, of course evaluating to a NaN value is fairly nondeterministic.
- // More precisely: when NaN should be returned is knowable, but which NaN?
- // So far that's defined by a combination of LLVM and the CPU, not Rust.
- // This function, however, allows observing the bitstring of a NaN,
- // thus introspection on CTFE.
- //
- // In order to preserve, at least for the moment, const-to-runtime equivalence,
- // reject any of these possible situations from happening.
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_u32_to_f32(ct: u32) -> f32 {
- match f32::classify_bits(ct) {
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f32::from_bits on a subnormal number")
- }
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f32::from_bits on NaN")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
- // SAFETY: It's not a frumious number
- unsafe { mem::transmute::<u32, f32>(ct) }
- }
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_u32_to_f32(x: u32) -> f32 {
- // SAFETY: `u32` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute(x) }
- }
- intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32)
+ // SAFETY: `u32` is a plain old datatype so we can always transmute from it.
+ unsafe { mem::transmute(v) }
}
/// Returns the memory representation of this floating point number as a byte array in
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index a89859b..85eb152 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -528,7 +528,7 @@ pub const fn is_nan(self) -> bool {
#[inline]
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
pub(crate) const fn abs_private(self) -> f64 {
- // SAFETY: This transmutation is fine. Probably. For the reasons std is using it.
+ // SAFETY: This transmutation is fine just like in `to_bits`/`from_bits`.
unsafe { mem::transmute::<u64, f64>(mem::transmute::<f64, u64>(self) & !Self::SIGN_MASK) }
}
@@ -653,12 +653,14 @@ pub const fn is_normal(self) -> bool {
pub const fn classify(self) -> FpCategory {
// A previous implementation tried to only use bitmask-based checks,
// using f64::to_bits to transmute the float to its bit repr and match on that.
- // Unfortunately, floating point numbers can be much worse than that.
- // This also needs to not result in recursive evaluations of f64::to_bits.
+ // If we only cared about being "technically" correct, that's an entirely legit
+ // implementation.
//
- // On some processors, in some cases, LLVM will "helpfully" lower floating point ops,
- // in spite of a request for them using f32 and f64, to things like x87 operations.
- // These have an f64's mantissa, but can have a larger than normal exponent.
+ // Unfortunately, there is hardware out there that does not correctly implement the IEEE
+ // float semantics Rust relies on: x87 uses a too-large exponent, and some hardware flushes
+ // subnormals to zero. These are platforms bugs, and Rust will misbehave on such hardware,
+ // but we can at least try to make things seem as sane as possible by being careful here.
+ //
// FIXME(jubilee): Using x87 operations is never necessary in order to function
// on x86 processors for Rust-to-Rust calls, so this issue should not happen.
// Code generation should be adjusted to use non-C calling conventions, avoiding this.
@@ -672,41 +674,18 @@ pub const fn classify(self) -> FpCategory {
// as correctness requires avoiding equality tests that may be Subnormal == -0.0
// because it may be wrong under "denormals are zero" and "flush to zero" modes.
// Most of std's targets don't use those, but they are used for thumbv7neon.
- // So, this does use bitpattern matching for the rest.
-
- // SAFETY: f64 to u64 is fine. Usually.
- // If control flow has gotten this far, the value is definitely in one of the categories
- // that f64::partial_classify can correctly analyze.
- unsafe { f64::partial_classify(self) }
- }
- }
-
- // This doesn't actually return a right answer for NaN on purpose,
- // seeing as how it cannot correctly discern between a floating point NaN,
- // and some normal floating point numbers truncated from an x87 FPU.
- #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const unsafe fn partial_classify(self) -> FpCategory {
- // SAFETY: The caller is not asking questions for which this will tell lies.
- let b = unsafe { mem::transmute::<f64, u64>(self) };
- match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
- (0, Self::EXP_MASK) => FpCategory::Infinite,
- (0, 0) => FpCategory::Zero,
- (_, 0) => FpCategory::Subnormal,
- _ => FpCategory::Normal,
- }
- }
-
- // This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
- // FIXME(jubilee): In a just world, this would be the entire impl for classify,
- // plus a transmute. We do not live in a just world, but we can make it more so.
- #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
- const fn classify_bits(b: u64) -> FpCategory {
- match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
- (0, Self::EXP_MASK) => FpCategory::Infinite,
- (_, Self::EXP_MASK) => FpCategory::Nan,
- (0, 0) => FpCategory::Zero,
- (_, 0) => FpCategory::Subnormal,
- _ => FpCategory::Normal,
+ // So, this does use bitpattern matching for the rest. On x87, due to the incorrect
+ // float codegen on this hardware, this doesn't actually return a right answer for NaN
+ // because it cannot correctly discern between a floating point NaN, and some normal
+ // floating point numbers truncated from an x87 FPU -- but we took care of NaN above, so
+ // we are fine.
+ let b = self.to_bits();
+ match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
+ (0, Self::EXP_MASK) => FpCategory::Infinite,
+ (0, 0) => FpCategory::Zero,
+ (_, 0) => FpCategory::Subnormal,
+ _ => FpCategory::Normal,
+ }
}
}
@@ -1134,33 +1113,7 @@ pub unsafe fn to_int_unchecked<Int>(self) -> Int
#[inline]
pub const fn to_bits(self) -> u64 {
// SAFETY: `u64` is a plain old datatype so we can always transmute to it.
- // ...sorta.
- //
- // See the SAFETY comment in f64::from_bits for more.
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_f64_to_u64(ct: f64) -> u64 {
- match ct.classify() {
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f64::to_bits on a NaN")
- }
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f64::to_bits on a subnormal number")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
- // SAFETY: We have a normal floating point number. Now we transmute, i.e. do a bitcopy.
- unsafe { mem::transmute::<f64, u64>(ct) }
- }
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_f64_to_u64(rt: f64) -> u64 {
- // SAFETY: `u64` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute::<f64, u64>(rt) }
- }
- intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64)
+ unsafe { mem::transmute(self) }
}
/// Raw transmutation from `u64`.
@@ -1205,58 +1158,8 @@ fn rt_f64_to_u64(rt: f64) -> u64 {
#[inline]
pub const fn from_bits(v: u64) -> Self {
// It turns out the safety issues with sNaN were overblown! Hooray!
- // SAFETY: `u64` is a plain old datatype so we can always transmute from it
- // ...sorta.
- //
- // It turns out that at runtime, it is possible for a floating point number
- // to be subject to floating point modes that alter nonzero subnormal numbers
- // to zero on reads and writes, aka "denormals are zero" and "flush to zero".
- // This is not a problem usually, but at least one tier2 platform for Rust
- // actually exhibits an FTZ behavior by default: thumbv7neon
- // aka "the Neon FPU in AArch32 state"
- //
- // Even with this, not all instructions exhibit the FTZ behaviors on thumbv7neon,
- // so this should load the same bits if LLVM emits the "correct" instructions,
- // but LLVM sometimes makes interesting choices about float optimization,
- // and other FPUs may do similar. Thus, it is wise to indulge luxuriously in caution.
- //
- // In addition, on x86 targets with SSE or SSE2 disabled and the x87 FPU enabled,
- // i.e. not soft-float, the way Rust does parameter passing can actually alter
- // a number that is "not infinity" to have the same exponent as infinity,
- // in a slightly unpredictable manner.
- //
- // And, of course evaluating to a NaN value is fairly nondeterministic.
- // More precisely: when NaN should be returned is knowable, but which NaN?
- // So far that's defined by a combination of LLVM and the CPU, not Rust.
- // This function, however, allows observing the bitstring of a NaN,
- // thus introspection on CTFE.
- //
- // In order to preserve, at least for the moment, const-to-runtime equivalence,
- // reject any of these possible situations from happening.
- #[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
- const fn ct_u64_to_f64(ct: u64) -> f64 {
- match f64::classify_bits(ct) {
- FpCategory::Subnormal => {
- panic!("const-eval error: cannot use f64::from_bits on a subnormal number")
- }
- FpCategory::Nan => {
- panic!("const-eval error: cannot use f64::from_bits on NaN")
- }
- FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
- // SAFETY: It's not a frumious number
- unsafe { mem::transmute::<u64, f64>(ct) }
- }
- }
- }
-
- #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
- fn rt_u64_to_f64(rt: u64) -> f64 {
- // SAFETY: `u64` is a plain old datatype so we can always... uh...
- // ...look, just pretend you forgot what you just read.
- // Stability concerns.
- unsafe { mem::transmute::<u64, f64>(rt) }
- }
- intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64)
+ // SAFETY: `u64` is a plain old datatype so we can always transmute from it.
+ unsafe { mem::transmute(v) }
}
/// Returns the memory representation of this floating point number as a byte array in
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 9cec79c..50cb22b7 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -656,8 +656,6 @@ pub const fn is_none(&self) -> bool {
/// # Examples
///
/// ```
- /// #![feature(is_none_or)]
- ///
/// let x: Option<u32> = Some(2);
/// assert_eq!(x.is_none_or(|x| x > 1), true);
///
@@ -669,7 +667,7 @@ pub const fn is_none(&self) -> bool {
/// ```
#[must_use]
#[inline]
- #[unstable(feature = "is_none_or", issue = "126383")]
+ #[stable(feature = "is_none_or", since = "CURRENT_RUSTC_VERSION")]
pub fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
match self {
None => true,
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 29932c0..7e5c157 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -530,10 +530,18 @@ pub fn will_wake(&self, other: &Waker) -> bool {
/// Returns a reference to a `Waker` that does nothing when used.
///
+ // Note! Much of the documentation for this method is duplicated
+ // in the docs for `LocalWaker::noop`.
+ // If you edit it, consider editing the other copy too.
+ //
/// This is mostly useful for writing tests that need a [`Context`] to poll
/// some futures, but are not expecting those futures to wake the waker or
/// do not need to do anything specific if it happens.
///
+ /// More generally, using `Waker::noop()` to poll a future
+ /// means discarding the notification of when the future should be polled again.
+ /// So it should only be used when such a notification will not be needed to make progress.
+ ///
/// If an owned `Waker` is needed, `clone()` this one.
///
/// # Examples
@@ -783,12 +791,22 @@ pub fn will_wake(&self, other: &LocalWaker) -> bool {
Self { waker }
}
- /// Creates a new `LocalWaker` that does nothing when `wake` is called.
+ /// Returns a reference to a `LocalWaker` that does nothing when used.
///
+ // Note! Much of the documentation for this method is duplicated
+ // in the docs for `Waker::noop`.
+ // If you edit it, consider editing the other copy too.
+ //
/// This is mostly useful for writing tests that need a [`Context`] to poll
/// some futures, but are not expecting those futures to wake the waker or
/// do not need to do anything specific if it happens.
///
+ /// More generally, using `LocalWaker::noop()` to poll a future
+ /// means discarding the notification of when the future should be polled again,
+ /// So it should only be used when such a notification will not be needed to make progress.
+ ///
+ /// If an owned `LocalWaker` is needed, `clone()` this one.
+ ///
/// # Examples
///
/// ```
diff --git a/library/core/tests/clone.rs b/library/core/tests/clone.rs
index b7130f1..71a3287 100644
--- a/library/core/tests/clone.rs
+++ b/library/core/tests/clone.rs
@@ -1,5 +1,7 @@
use core::clone::CloneToUninit;
+use core::ffi::CStr;
use core::mem::MaybeUninit;
+use core::ptr;
#[test]
#[allow(suspicious_double_ref_op)]
@@ -81,3 +83,41 @@ fn drop(&mut self) {
drop(a);
assert_eq!(COUNTER.load(Relaxed), 0);
}
+
+#[test]
+fn test_clone_to_uninit_str() {
+ let a = "hello";
+
+ let mut storage: MaybeUninit<[u8; 5]> = MaybeUninit::uninit();
+ unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut str) };
+ assert_eq!(a.as_bytes(), unsafe { storage.assume_init() }.as_slice());
+
+ let mut b: Box<str> = "world".into();
+ assert_eq!(a.len(), b.len());
+ assert_ne!(a, &*b);
+ unsafe { a.clone_to_uninit(ptr::from_mut::<str>(&mut b)) };
+ assert_eq!(a, &*b);
+}
+
+#[test]
+fn test_clone_to_uninit_cstr() {
+ let a = c"hello";
+
+ let mut storage: MaybeUninit<[u8; 6]> = MaybeUninit::uninit();
+ unsafe { a.clone_to_uninit(storage.as_mut_ptr() as *mut [u8] as *mut CStr) };
+ assert_eq!(a.to_bytes_with_nul(), unsafe { storage.assume_init() }.as_slice());
+
+ let mut b: Box<CStr> = c"world".into();
+ assert_eq!(a.count_bytes(), b.count_bytes());
+ assert_ne!(a, &*b);
+ unsafe { a.clone_to_uninit(ptr::from_mut::<CStr>(&mut b)) };
+ assert_eq!(a, &*b);
+}
+
+#[test]
+fn cstr_metadata_is_length_with_nul() {
+ let s: &CStr = c"abcdef";
+ let p: *const CStr = ptr::from_ref(s);
+ let bytes: *const [u8] = p as *const [u8];
+ assert_eq!(s.to_bytes_with_nul().len(), bytes.len());
+}
diff --git a/library/core/tests/iter/adapters/take.rs b/library/core/tests/iter/adapters/take.rs
index 39afa2c..65a8a93 100644
--- a/library/core/tests/iter/adapters/take.rs
+++ b/library/core/tests/iter/adapters/take.rs
@@ -170,3 +170,93 @@ fn test_byref_take_consumed_items() {
assert_eq!(count, 70);
assert_eq!(inner, 90..90);
}
+
+#[test]
+fn test_exact_size_take_repeat() {
+ let mut iter = core::iter::repeat(42).take(40);
+ assert_eq!((40, Some(40)), iter.size_hint());
+ assert_eq!(40, iter.len());
+
+ assert_eq!(Some(42), iter.next());
+ assert_eq!((39, Some(39)), iter.size_hint());
+ assert_eq!(39, iter.len());
+
+ assert_eq!(Some(42), iter.next_back());
+ assert_eq!((38, Some(38)), iter.size_hint());
+ assert_eq!(38, iter.len());
+
+ assert_eq!(Some(42), iter.nth(3));
+ assert_eq!((34, Some(34)), iter.size_hint());
+ assert_eq!(34, iter.len());
+
+ assert_eq!(Some(42), iter.nth_back(3));
+ assert_eq!((30, Some(30)), iter.size_hint());
+ assert_eq!(30, iter.len());
+
+ assert_eq!(Ok(()), iter.advance_by(10));
+ assert_eq!((20, Some(20)), iter.size_hint());
+ assert_eq!(20, iter.len());
+
+ assert_eq!(Ok(()), iter.advance_back_by(10));
+ assert_eq!((10, Some(10)), iter.size_hint());
+ assert_eq!(10, iter.len());
+}
+
+#[test]
+fn test_exact_size_take_repeat_with() {
+ let mut counter = 0;
+ let mut iter = core::iter::repeat_with(move || {
+ counter += 1;
+ counter
+ })
+ .take(40);
+ assert_eq!((40, Some(40)), iter.size_hint());
+ assert_eq!(40, iter.len());
+
+ assert_eq!(Some(1), iter.next());
+ assert_eq!((39, Some(39)), iter.size_hint());
+ assert_eq!(39, iter.len());
+
+ assert_eq!(Some(5), iter.nth(3));
+ assert_eq!((35, Some(35)), iter.size_hint());
+ assert_eq!(35, iter.len());
+
+ assert_eq!(Ok(()), iter.advance_by(10));
+ assert_eq!((25, Some(25)), iter.size_hint());
+ assert_eq!(25, iter.len());
+
+ assert_eq!(Some(16), iter.next());
+ assert_eq!((24, Some(24)), iter.size_hint());
+ assert_eq!(24, iter.len());
+}
+
+// This is https://github.com/rust-lang/rust/issues/104729 with all uses of
+// repeat(0) were replaced by repeat(0).take(20).
+#[test]
+fn test_reverse_on_zip() {
+ let vec_1 = [1; 10];
+
+ let zipped_iter = vec_1.iter().copied().zip(core::iter::repeat(0).take(20));
+
+ // Forward
+ for (one, zero) in zipped_iter {
+ assert_eq!((1, 0), (one, zero));
+ }
+
+ let rev_vec_iter = vec_1.iter().rev();
+ let rev_repeat_iter = std::iter::repeat(0).take(20).rev();
+
+ // Manual reversed zip
+ let rev_zipped_iter = rev_vec_iter.zip(rev_repeat_iter);
+
+ for (&one, zero) in rev_zipped_iter {
+ assert_eq!((1, 0), (one, zero));
+ }
+
+ let zipped_iter = vec_1.iter().zip(core::iter::repeat(0).take(20));
+
+ // Cannot call rev here for automatic reversed zip constuction
+ for (&one, zero) in zipped_iter.rev() {
+ assert_eq!((1, 0), (one, zero));
+ }
+}
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index a501bcc..918eec2 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -3,10 +3,13 @@
#[cfg(test)]
mod tests;
+use core::clone::CloneToUninit;
+
use crate::borrow::{Borrow, Cow};
use crate::collections::TryReserveError;
use crate::hash::{Hash, Hasher};
use crate::ops::{self, Range};
+use crate::ptr::addr_of_mut;
use crate::rc::Rc;
use crate::str::FromStr;
use crate::sync::Arc;
@@ -1261,6 +1264,16 @@ fn clone(&self) -> Self {
}
}
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for OsStr {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+ // SAFETY: we're just a wrapper around a platform-specific Slice
+ unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+ }
+}
+
#[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<OsString> for Arc<OsStr> {
/// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> by moving the [`OsString`]
diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs
index 5b39b9e..6714793 100644
--- a/library/std/src/ffi/os_str/tests.rs
+++ b/library/std/src/ffi/os_str/tests.rs
@@ -1,4 +1,6 @@
use super::*;
+use crate::mem::MaybeUninit;
+use crate::ptr;
#[test]
fn test_os_string_with_capacity() {
@@ -286,3 +288,18 @@ fn slice_surrogate_edge() {
assert_eq!(post_crab.slice_encoded_bytes(..4), "🦀");
assert_eq!(post_crab.slice_encoded_bytes(4..), surrogate);
}
+
+#[test]
+fn clone_to_uninit() {
+ let a = OsStr::new("hello.txt");
+
+ let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<OsStr>(a)];
+ unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut OsStr) };
+ assert_eq!(a.as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) });
+
+ let mut b: Box<OsStr> = OsStr::new("world.exe").into();
+ assert_eq!(size_of_val::<OsStr>(a), size_of_val::<OsStr>(&b));
+ assert_ne!(a, &*b);
+ unsafe { a.clone_to_uninit(ptr::from_mut::<OsStr>(&mut b)) };
+ assert_eq!(a, &*b);
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 93a74ef..2530a37 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -319,6 +319,7 @@
// tidy-alphabetical-start
#![feature(c_str_module)]
#![feature(char_internals)]
+#![feature(clone_to_uninit)]
#![feature(core_intrinsics)]
#![feature(core_io_borrowed_buf)]
#![feature(duration_constants)]
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index c534236..4620244 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -109,13 +109,21 @@ unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command
/// Schedules a closure to be run just before the `exec` function is
/// invoked.
///
- /// This method is stable and usable, but it should be unsafe. To fix
- /// that, it got deprecated in favor of the unsafe [`pre_exec`].
+ /// `before_exec` used to be a safe method, but it needs to be unsafe since the closure may only
+ /// perform operations that are *async-signal-safe*. Hence it got deprecated in favor of the
+ /// unsafe [`pre_exec`]. Meanwhile, Rust gained the ability to make an existing safe method
+ /// fully unsafe in a new edition, which is how `before_exec` became `unsafe`. It still also
+ /// remains deprecated; `pre_exec` should be used instead.
///
/// [`pre_exec`]: CommandExt::pre_exec
#[stable(feature = "process_exec", since = "1.15.0")]
#[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")]
- fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ #[cfg_attr(bootstrap, rustc_deprecated_safe_2024)]
+ #[cfg_attr(
+ not(bootstrap),
+ rustc_deprecated_safe_2024(audit_that = "the closure is async-signal-safe")
+ )]
+ unsafe fn before_exec<F>(&mut self, f: F) -> &mut process::Command
where
F: FnMut() -> io::Result<()> + Send + Sync + 'static,
{
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 8016366..9eaa0e0 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -70,6 +70,8 @@
#[cfg(test)]
mod tests;
+use core::clone::CloneToUninit;
+
use crate::borrow::{Borrow, Cow};
use crate::collections::TryReserveError;
use crate::error::Error;
@@ -3109,6 +3111,16 @@ pub fn into_path_buf(self: Box<Path>) -> PathBuf {
}
}
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Path {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+ // SAFETY: Path is just a wrapper around OsStr
+ unsafe { self.inner.clone_to_uninit(core::ptr::addr_of_mut!((*dst).inner)) }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRef<OsStr> for Path {
#[inline]
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index a12e42c..6436872 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -3,6 +3,8 @@
use super::*;
use crate::collections::{BTreeSet, HashSet};
use crate::hash::DefaultHasher;
+use crate::mem::MaybeUninit;
+use crate::ptr;
#[allow(unknown_lints, unused_macro_rules)]
macro_rules! t (
@@ -2054,3 +2056,20 @@ fn bench_hash_path_long(b: &mut test::Bencher) {
black_box(hasher.finish());
}
+
+#[test]
+fn clone_to_uninit() {
+ let a = Path::new("hello.txt");
+
+ let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<Path>(a)];
+ unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut Path) };
+ assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe {
+ MaybeUninit::slice_assume_init_ref(&storage)
+ });
+
+ let mut b: Box<Path> = Path::new("world.exe").into();
+ assert_eq!(size_of_val::<Path>(a), size_of_val::<Path>(&b));
+ assert_ne!(a, &*b);
+ unsafe { a.clone_to_uninit(ptr::from_mut::<Path>(&mut b)) };
+ assert_eq!(a, &*b);
+}
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 0f8bd64..9927672 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -1,6 +1,9 @@
//! The underlying OsString/OsStr implementation on Unix and many other
//! systems: just a `Vec<u8>`/`[u8]`.
+use core::clone::CloneToUninit;
+use core::ptr::addr_of_mut;
+
use crate::borrow::Cow;
use crate::collections::TryReserveError;
use crate::fmt::Write;
@@ -345,3 +348,13 @@ pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
self.inner.eq_ignore_ascii_case(&other.inner)
}
}
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Slice {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+ // SAFETY: we're just a wrapper around [u8]
+ unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+ }
+}
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index ed975ba..433237a 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -1,5 +1,8 @@
//! The underlying OsString/OsStr implementation on Windows is a
//! wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
+use core::clone::CloneToUninit;
+use core::ptr::addr_of_mut;
+
use crate::borrow::Cow;
use crate::collections::TryReserveError;
use crate::rc::Rc;
@@ -268,3 +271,13 @@ pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
self.inner.eq_ignore_ascii_case(&other.inner)
}
}
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Slice {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+ // SAFETY: we're just a wrapper around Wtf8
+ unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) }
+ }
+}
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 277c950..063451a 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -19,12 +19,14 @@
mod tests;
use core::char::{encode_utf16_raw, encode_utf8_raw};
+use core::clone::CloneToUninit;
use core::str::next_code_point;
use crate::borrow::Cow;
use crate::collections::TryReserveError;
use crate::hash::{Hash, Hasher};
use crate::iter::FusedIterator;
+use crate::ptr::addr_of_mut;
use crate::rc::Rc;
use crate::sync::Arc;
use crate::sys_common::AsInner;
@@ -1046,3 +1048,13 @@ fn hash<H: Hasher>(&self, state: &mut H) {
0xfeu8.hash(state)
}
}
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Wtf8 {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_to_uninit(&self, dst: *mut Self) {
+ // SAFETY: we're just a wrapper around [u8]
+ unsafe { self.bytes.clone_to_uninit(addr_of_mut!((*dst).bytes)) }
+ }
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 88b31cd..e29c28f 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -412,7 +412,6 @@ pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
/// # Examples
///
/// ```
- /// #![feature(thread_spawn_unchecked)]
/// use std::thread;
///
/// let builder = thread::Builder::new();
@@ -433,7 +432,7 @@ pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
/// ```
///
/// [`io::Result`]: crate::io::Result
- #[unstable(feature = "thread_spawn_unchecked", issue = "55132")]
+ #[stable(feature = "thread_spawn_unchecked", since = "CURRENT_RUSTC_VERSION")]
pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
where
F: FnOnce() -> T,
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 36de832..bdd9fd7 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -36,6 +36,14 @@ macro_rules! check_ci_llvm {
};
}
+/// This file is embedded in the overlay directory of the tarball sources. It is
+/// useful in scenarios where developers want to see how the tarball sources were
+/// generated.
+///
+/// We also use this file to compare the host's config.toml against the CI rustc builder
+/// configuration to detect any incompatible options.
+pub(crate) const BUILDER_CONFIG_FILENAME: &str = "builder-config";
+
#[derive(Clone, Default)]
pub enum DryRun {
/// This isn't a dry run.
@@ -47,7 +55,7 @@ pub enum DryRun {
UserSelected,
}
-#[derive(Copy, Clone, Default, PartialEq, Eq)]
+#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
pub enum DebuginfoLevel {
#[default]
None,
@@ -117,7 +125,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// 2) MSVC
/// - Self-contained: `-Clinker=<path to rust-lld>`
/// - External: `-Clinker=lld`
-#[derive(Default, Copy, Clone)]
+#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub enum LldMode {
/// Do not use LLD
#[default]
@@ -1203,40 +1211,42 @@ pub fn default_opts() -> Config {
}
}
- pub fn parse(flags: Flags) -> Config {
- #[cfg(test)]
- fn get_toml(_: &Path) -> TomlConfig {
- TomlConfig::default()
- }
-
- #[cfg(not(test))]
- fn get_toml(file: &Path) -> TomlConfig {
- let contents =
- t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
- // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
- // TomlConfig and sub types to be monomorphized 5x by toml.
- toml::from_str(&contents)
- .and_then(|table: toml::Value| TomlConfig::deserialize(table))
- .unwrap_or_else(|err| {
- if let Ok(Some(changes)) = toml::from_str(&contents)
- .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table)).map(|change_id| change_id.inner.map(crate::find_recent_config_change_ids))
- {
- if !changes.is_empty() {
- println!(
- "WARNING: There have been changes to x.py since you last updated:\n{}",
- crate::human_readable_changes(&changes)
- );
- }
- }
-
- eprintln!("failed to parse TOML configuration '{}': {err}", file.display());
- exit!(2);
- })
- }
- Self::parse_inner(flags, get_toml)
+ #[cfg(test)]
+ fn get_toml(_: &Path) -> Result<TomlConfig, toml::de::Error> {
+ Ok(TomlConfig::default())
}
- pub(crate) fn parse_inner(mut flags: Flags, get_toml: impl Fn(&Path) -> TomlConfig) -> Config {
+ #[cfg(not(test))]
+ fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
+ let contents =
+ t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
+ // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
+ // TomlConfig and sub types to be monomorphized 5x by toml.
+ toml::from_str(&contents)
+ .and_then(|table: toml::Value| TomlConfig::deserialize(table))
+ .inspect_err(|_| {
+ if let Ok(Some(changes)) = toml::from_str(&contents)
+ .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table))
+ .map(|change_id| change_id.inner.map(crate::find_recent_config_change_ids))
+ {
+ if !changes.is_empty() {
+ println!(
+ "WARNING: There have been changes to x.py since you last updated:\n{}",
+ crate::human_readable_changes(&changes)
+ );
+ }
+ }
+ })
+ }
+
+ pub fn parse(flags: Flags) -> Config {
+ Self::parse_inner(flags, Self::get_toml)
+ }
+
+ pub(crate) fn parse_inner(
+ mut flags: Flags,
+ get_toml: impl Fn(&Path) -> Result<TomlConfig, toml::de::Error>,
+ ) -> Config {
let mut config = Config::default_opts();
// Set flags.
@@ -1344,7 +1354,10 @@ pub(crate) fn parse_inner(mut flags: Flags, get_toml: impl Fn(&Path) -> TomlConf
} else {
toml_path.clone()
});
- get_toml(&toml_path)
+ get_toml(&toml_path).unwrap_or_else(|e| {
+ eprintln!("ERROR: Failed to parse '{}': {e}", toml_path.display());
+ exit!(2);
+ })
} else {
config.config = None;
TomlConfig::default()
@@ -1375,7 +1388,13 @@ pub(crate) fn parse_inner(mut flags: Flags, get_toml: impl Fn(&Path) -> TomlConf
include_path.push("bootstrap");
include_path.push("defaults");
include_path.push(format!("config.{include}.toml"));
- let included_toml = get_toml(&include_path);
+ let included_toml = get_toml(&include_path).unwrap_or_else(|e| {
+ eprintln!(
+ "ERROR: Failed to parse default config profile at '{}': {e}",
+ include_path.display()
+ );
+ exit!(2);
+ });
toml.merge(included_toml, ReplaceOpt::IgnoreDuplicate);
}
@@ -1591,24 +1610,6 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
let mut is_user_configured_rust_channel = false;
if let Some(rust) = toml.rust {
- if let Some(commit) = config.download_ci_rustc_commit(rust.download_rustc.clone()) {
- // Primarily used by CI runners to avoid handling download-rustc incompatible
- // options one by one on shell scripts.
- let disable_ci_rustc_if_incompatible =
- env::var_os("DISABLE_CI_RUSTC_IF_INCOMPATIBLE")
- .is_some_and(|s| s == "1" || s == "true");
-
- if let Err(e) = check_incompatible_options_for_ci_rustc(&rust) {
- if disable_ci_rustc_if_incompatible {
- config.download_rustc_commit = None;
- } else {
- panic!("{}", e);
- }
- } else {
- config.download_rustc_commit = Some(commit);
- }
- }
-
let Rust {
optimize: optimize_toml,
debug: debug_toml,
@@ -1656,7 +1657,7 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
new_symbol_mangling,
profile_generate,
profile_use,
- download_rustc: _,
+ download_rustc,
lto,
validate_mir_opts,
frame_pointers,
@@ -1668,6 +1669,8 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
is_user_configured_rust_channel = channel.is_some();
set(&mut config.channel, channel.clone());
+ config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc);
+
debug = debug_toml;
debug_assertions = debug_assertions_toml;
debug_assertions_std = debug_assertions_std_toml;
@@ -2345,6 +2348,45 @@ pub(crate) fn download_rustc_commit(&self) -> Option<&str> {
None => None,
Some(commit) => {
self.download_ci_rustc(commit);
+
+ if let Some(config_path) = &self.config {
+ let builder_config_path =
+ self.out.join(self.build.triple).join("ci-rustc").join(BUILDER_CONFIG_FILENAME);
+
+ let ci_config_toml = match Self::get_toml(&builder_config_path) {
+ Ok(ci_config_toml) => ci_config_toml,
+ Err(e) if e.to_string().contains("unknown field") => {
+ println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled.");
+ println!("HELP: Consider rebasing to a newer commit if available.");
+ return None;
+ },
+ Err(e) => {
+ eprintln!("ERROR: Failed to parse CI rustc config at '{}': {e}", builder_config_path.display());
+ exit!(2);
+ },
+ };
+
+ let current_config_toml = Self::get_toml(config_path).unwrap();
+
+ // Check the config compatibility
+ // FIXME: this doesn't cover `--set` flags yet.
+ let res = check_incompatible_options_for_ci_rustc(
+ current_config_toml,
+ ci_config_toml,
+ );
+
+ let disable_ci_rustc_if_incompatible =
+ env::var_os("DISABLE_CI_RUSTC_IF_INCOMPATIBLE")
+ .is_some_and(|s| s == "1" || s == "true");
+
+ if disable_ci_rustc_if_incompatible && res.is_err() {
+ println!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env.");
+ return None;
+ }
+
+ res.unwrap();
+ }
+
Some(commit.clone())
}
})
@@ -2662,31 +2704,52 @@ pub fn last_modified_commit(
}
}
-/// Checks the CI rustc incompatible options by destructuring the `Rust` instance
-/// and makes sure that no rust options from config.toml are missed.
-fn check_incompatible_options_for_ci_rustc(rust: &Rust) -> Result<(), String> {
+/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options.
+/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing.
+fn check_incompatible_options_for_ci_rustc(
+ current_config_toml: TomlConfig,
+ ci_config_toml: TomlConfig,
+) -> Result<(), String> {
macro_rules! err {
- ($name:expr) => {
- if $name.is_some() {
- return Err(format!(
- "ERROR: Setting `rust.{}` is incompatible with `rust.download-rustc`.",
- stringify!($name).replace("_", "-")
- ));
- }
+ ($current:expr, $expected:expr) => {
+ if let Some(current) = &$current {
+ if Some(current) != $expected.as_ref() {
+ return Err(format!(
+ "ERROR: Setting `rust.{}` is incompatible with `rust.download-rustc`. \
+ Current value: {:?}, Expected value(s): {}{:?}",
+ stringify!($expected).replace("_", "-"),
+ $current,
+ if $expected.is_some() { "None/" } else { "" },
+ $expected,
+ ));
+ };
+ };
};
}
macro_rules! warn {
- ($name:expr) => {
- if $name.is_some() {
- println!(
- "WARNING: `rust.{}` has no effect with `rust.download-rustc`.",
- stringify!($name).replace("_", "-")
- );
- }
+ ($current:expr, $expected:expr) => {
+ if let Some(current) = &$current {
+ if Some(current) != $expected.as_ref() {
+ println!(
+ "WARNING: `rust.{}` has no effect with `rust.download-rustc`. \
+ Current value: {:?}, Expected value(s): {}{:?}",
+ stringify!($expected).replace("_", "-"),
+ $current,
+ if $expected.is_some() { "None/" } else { "" },
+ $expected,
+ );
+ };
+ };
};
}
+ let (Some(current_rust_config), Some(ci_rust_config)) =
+ (current_config_toml.rust, ci_config_toml.rust)
+ else {
+ return Ok(());
+ };
+
let Rust {
// Following options are the CI rustc incompatible ones.
optimize,
@@ -2744,7 +2807,7 @@ macro_rules! warn {
download_rustc: _,
validate_mir_opts: _,
frame_pointers: _,
- } = rust;
+ } = ci_rust_config;
// There are two kinds of checks for CI rustc incompatible options:
// 1. Checking an option that may change the compiler behaviour/output.
@@ -2752,22 +2815,23 @@ macro_rules! warn {
//
// If the option belongs to the first category, we call `err` macro for a hard error;
// otherwise, we just print a warning with `warn` macro.
- err!(optimize);
- err!(debug_logging);
- err!(debuginfo_level_rustc);
- err!(default_linker);
- err!(rpath);
- err!(strip);
- err!(stack_protector);
- err!(lld_mode);
- err!(llvm_tools);
- err!(llvm_bitcode_linker);
- err!(jemalloc);
- err!(lto);
- warn!(channel);
- warn!(description);
- warn!(incremental);
+ err!(current_rust_config.optimize, optimize);
+ err!(current_rust_config.debug_logging, debug_logging);
+ err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc);
+ err!(current_rust_config.rpath, rpath);
+ err!(current_rust_config.strip, strip);
+ err!(current_rust_config.lld_mode, lld_mode);
+ err!(current_rust_config.llvm_tools, llvm_tools);
+ err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker);
+ err!(current_rust_config.jemalloc, jemalloc);
+ err!(current_rust_config.default_linker, default_linker);
+ err!(current_rust_config.stack_protector, stack_protector);
+ err!(current_rust_config.lto, lto);
+
+ warn!(current_rust_config.channel, channel);
+ warn!(current_rust_config.description, description);
+ warn!(current_rust_config.incremental, incremental);
Ok(())
}
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index 40f3e5e..378d069 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -14,7 +14,7 @@
fn parse(config: &str) -> Config {
Config::parse_inner(
Flags::parse(&["check".to_string(), "--config=/does/not/exist".to_string()]),
- |&_| toml::from_str(&config).unwrap(),
+ |&_| toml::from_str(&config),
)
}
@@ -151,7 +151,6 @@ fn override_toml() {
"#,
)
- .unwrap()
},
);
assert_eq!(config.change_id, Some(1), "setting top-level value");
@@ -208,13 +207,13 @@ fn override_toml_duplicate() {
"--set=change-id=1".to_owned(),
"--set=change-id=2".to_owned(),
]),
- |&_| toml::from_str("change-id = 0").unwrap(),
+ |&_| toml::from_str("change-id = 0"),
);
}
#[test]
fn profile_user_dist() {
- fn get_toml(file: &Path) -> TomlConfig {
+ fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
let contents =
if file.ends_with("config.toml") || env::var_os("RUST_BOOTSTRAP_CONFIG").is_some() {
"profile = \"user\"".to_owned()
@@ -223,9 +222,7 @@ fn get_toml(file: &Path) -> TomlConfig {
std::fs::read_to_string(file).unwrap()
};
- toml::from_str(&contents)
- .and_then(|table: toml::Value| TomlConfig::deserialize(table))
- .unwrap()
+ toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table))
}
Config::parse_inner(Flags::parse(&["check".to_owned()]), get_toml);
}
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index fd85650..ae39afa 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -9,6 +9,7 @@
use build_helper::ci::CiEnv;
use xz2::bufread::XzDecoder;
+use crate::core::config::BUILDER_CONFIG_FILENAME;
use crate::utils::exec::{command, BootstrapCommand};
use crate::utils::helpers::{check_run, exe, hex_encode, move_file, program_out_of_date};
use crate::{t, Config};
@@ -273,11 +274,12 @@ fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) {
let mut tar = tar::Archive::new(decompressor);
+ let is_ci_rustc = dst.ends_with("ci-rustc");
+
// `compile::Sysroot` needs to know the contents of the `rustc-dev` tarball to avoid adding
// it to the sysroot unless it was explicitly requested. But parsing the 100 MB tarball is slow.
// Cache the entries when we extract it so we only have to read it once.
- let mut recorded_entries =
- if dst.ends_with("ci-rustc") { recorded_entries(dst, pattern) } else { None };
+ let mut recorded_entries = if is_ci_rustc { recorded_entries(dst, pattern) } else { None };
for member in t!(tar.entries()) {
let mut member = t!(member);
@@ -287,10 +289,12 @@ fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) {
continue;
}
let mut short_path = t!(original_path.strip_prefix(directory_prefix));
- if !short_path.starts_with(pattern) {
+ let is_builder_config = short_path.to_str() == Some(BUILDER_CONFIG_FILENAME);
+
+ if !(short_path.starts_with(pattern) || (is_ci_rustc && is_builder_config)) {
continue;
}
- short_path = t!(short_path.strip_prefix(pattern));
+ short_path = short_path.strip_prefix(pattern).unwrap_or(short_path);
let dst_path = dst.join(short_path);
self.verbose(|| {
println!("extracting {} to {}", original_path.display(), dst.display())
@@ -703,9 +707,7 @@ pub(crate) fn maybe_download_ci_llvm(&self) {
let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now);
let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build));
- let llvm_config_file = t!(File::options().write(true).open(llvm_config));
-
- t!(llvm_config_file.set_times(file_times));
+ t!(crate::utils::helpers::set_file_times(llvm_config, file_times));
if self.should_fix_bins_and_dylibs() {
let llvm_lib = llvm_root.join("lib");
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index bfd0e42..784519a 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -37,7 +37,9 @@
use crate::core::builder::{Builder, Kind};
use crate::core::config::{flags, DryRun, LldMode, LlvmLibunwind, Target, TargetSelection};
use crate::utils::exec::{command, BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode};
-use crate::utils::helpers::{self, dir_is_empty, exe, libdir, mtime, output, symlink_dir};
+use crate::utils::helpers::{
+ self, dir_is_empty, exe, libdir, mtime, output, set_file_times, symlink_dir,
+};
mod core;
mod utils;
@@ -1056,11 +1058,29 @@ fn run(
}
};
- let fail = |message: &str| {
+ let fail = |message: &str, output: CommandOutput| -> ! {
if self.is_verbose() {
println!("{message}");
} else {
- println!("Command has failed. Rerun with -v to see more details.");
+ let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present());
+ // If the command captures output, the user would not see any indication that
+ // it has failed. In this case, print a more verbose error, since to provide more
+ // context.
+ if stdout.is_some() || stderr.is_some() {
+ if let Some(stdout) =
+ output.stdout_if_present().take_if(|s| !s.trim().is_empty())
+ {
+ println!("STDOUT:\n{stdout}\n");
+ }
+ if let Some(stderr) =
+ output.stderr_if_present().take_if(|s| !s.trim().is_empty())
+ {
+ println!("STDERR:\n{stderr}\n");
+ }
+ println!("Command {command:?} has failed. Rerun with -v to see more details.");
+ } else {
+ println!("Command has failed. Rerun with -v to see more details.");
+ }
}
exit!(1);
};
@@ -1069,14 +1089,14 @@ fn run(
match command.failure_behavior {
BehaviorOnFailure::DelayFail => {
if self.fail_fast {
- fail(&message);
+ fail(&message, output);
}
let mut failures = self.delayed_failures.borrow_mut();
failures.push(message);
}
BehaviorOnFailure::Exit => {
- fail(&message);
+ fail(&message, output);
}
BehaviorOnFailure::Ignore => {
// If failures are allowed, either the error has been printed already
@@ -1774,21 +1794,20 @@ fn copy_link_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool)
}
}
if let Ok(()) = fs::hard_link(&src, dst) {
- // Attempt to "easy copy" by creating a hard link
- // (symlinks don't work on windows), but if that fails
- // just fall back to a slow `copy` operation.
+ // Attempt to "easy copy" by creating a hard link (symlinks are priviledged on windows),
+ // but if that fails just fall back to a slow `copy` operation.
} else {
if let Err(e) = fs::copy(&src, dst) {
panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
}
t!(fs::set_permissions(dst, metadata.permissions()));
+ // Restore file times because changing permissions on e.g. Linux using `chmod` can cause
+ // file access time to change.
let file_times = fs::FileTimes::new()
.set_accessed(t!(metadata.accessed()))
.set_modified(t!(metadata.modified()));
-
- let dst_file = t!(fs::File::open(dst));
- t!(dst_file.set_times(file_times));
+ t!(set_file_times(dst, file_times));
}
}
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 9f0d0b7..530d760 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -292,6 +292,11 @@ pub fn stdout(&self) -> String {
}
#[must_use]
+ pub fn stdout_if_present(&self) -> Option<String> {
+ self.stdout.as_ref().and_then(|s| String::from_utf8(s.clone()).ok())
+ }
+
+ #[must_use]
pub fn stdout_if_ok(&self) -> Option<String> {
if self.is_success() { Some(self.stdout()) } else { None }
}
@@ -303,6 +308,11 @@ pub fn stderr(&self) -> String {
)
.expect("Cannot parse process stderr as UTF-8")
}
+
+ #[must_use]
+ pub fn stderr_if_present(&self) -> Option<String> {
+ self.stderr.as_ref().and_then(|s| String::from_utf8(s.clone()).ok())
+ }
}
impl Default for CommandOutput {
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 65e75f1..a856c99 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -544,3 +544,15 @@ pub fn get_closest_merge_base_commit(
Ok(output_result(git.as_command_mut())?.trim().to_owned())
}
+
+/// Sets the file times for a given file at `path`.
+pub fn set_file_times<P: AsRef<Path>>(path: P, times: fs::FileTimes) -> io::Result<()> {
+ // Windows requires file to be writable to modify file times. But on Linux CI the file does not
+ // need to be writable to modify file times and might be read-only.
+ let f = if cfg!(windows) {
+ fs::File::options().write(true).open(path)?
+ } else {
+ fs::File::open(path)?
+ };
+ f.set_times(times)
+}
diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs
index 103c4d2..86016a9 100644
--- a/src/bootstrap/src/utils/helpers/tests.rs
+++ b/src/bootstrap/src/utils/helpers/tests.rs
@@ -3,7 +3,8 @@
use std::path::PathBuf;
use crate::utils::helpers::{
- check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, symlink_dir,
+ check_cfg_arg, extract_beta_rev, hex_encode, make, program_out_of_date, set_file_times,
+ symlink_dir,
};
use crate::{Config, Flags};
@@ -92,3 +93,25 @@ fn test_symlink_dir() {
#[cfg(not(windows))]
fs::remove_file(link_path).unwrap();
}
+
+#[test]
+fn test_set_file_times_sanity_check() {
+ let config =
+ Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
+ let tempfile = config.tempdir().join(".tmp-file");
+
+ {
+ File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap();
+ assert!(tempfile.exists());
+ }
+
+ // This might only fail on Windows (if file is default read-only then we try to modify file
+ // times).
+ let unix_epoch = std::time::SystemTime::UNIX_EPOCH;
+ let target_time = fs::FileTimes::new().set_accessed(unix_epoch).set_modified(unix_epoch);
+ set_file_times(&tempfile, target_time).unwrap();
+
+ let found_metadata = fs::metadata(tempfile).unwrap();
+ assert_eq!(found_metadata.accessed().unwrap(), unix_epoch);
+ assert_eq!(found_metadata.modified().unwrap(), unix_epoch)
+}
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 3f7f621..3c6c7a7 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -9,6 +9,7 @@
use crate::core::build_steps::dist::distdir;
use crate::core::builder::{Builder, Kind};
+use crate::core::config::BUILDER_CONFIG_FILENAME;
use crate::utils::exec::BootstrapCommand;
use crate::utils::helpers::{move_file, t};
use crate::utils::{channel, helpers};
@@ -320,7 +321,7 @@ fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut BootstrapCommand)) -> Gen
// Add config file if present.
if let Some(config) = &self.builder.config.config {
- self.add_renamed_file(config, &self.overlay_dir, "builder-config");
+ self.add_renamed_file(config, &self.overlay_dir, BUILDER_CONFIG_FILENAME);
}
for file in self.overlay.legal_and_readme() {
diff --git a/src/doc/book b/src/doc/book
index 67fa536..04bc139 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 67fa536768013d9d5a13f3a06790521d511ef711
+Subproject commit 04bc1396bb857f35b5dda1d773c9571e1f253304
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index 5454de3..aeeb287 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit 5454de3d12b9ccc6375b629cf7ccda8264640aac
+Subproject commit aeeb287d41a0332c210da122bea8e0e91844ab3e
diff --git a/src/doc/nomicon b/src/doc/nomicon
index 0ebdaca..6ecf95c 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit 0ebdacadbda8ce2cd8fbf93985e15af61a7ab895
+Subproject commit 6ecf95c5f2bfa0e6314dfe282bf775fd1405f7e9
diff --git a/src/doc/reference b/src/doc/reference
index 2e19181..62cd0df 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 2e191814f163ee1e77e2d6094eee4dd78a289c5b
+Subproject commit 62cd0df95061ba0ac886333f5cd7f3012f149da1
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 89aecb6..8f94061 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 89aecb6951b77bc746da73df8c9f2b2ceaad494a
+Subproject commit 8f94061936e492159f4f6c09c0f917a7521893ff
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index 0c4d55c..43d8378 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit 0c4d55cb59fe440d1a630e4e5774d043968edb3f
+Subproject commit 43d83780db545a1ed6d45773312fc578987e3968
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 467fd6f..cb0b2e6 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -61,6 +61,7 @@
- [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md)
- [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
- [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md)
+ - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md)
- [powerpc64-ibm-aix](platform-support/aix.md)
- [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md)
- [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index bd12172..c3f73a8 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -332,6 +332,7 @@
`msp430-none-elf` | * | | 16-bit MSP430 microcontrollers
`powerpc-unknown-linux-gnuspe` | ✓ | | PowerPC SPE Linux
`powerpc-unknown-linux-musl` | ? | | PowerPC Linux with musl 1.2.3
+[`powerpc-unknown-linux-muslspe`](platform-support/powerpc-unknown-linux-muslspe.md) | ? | | PowerPC SPE Linux
[`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems
[`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | |
[`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ | |
diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md
index 9ddf00e..96499b0 100644
--- a/src/doc/rustc/src/platform-support/android.md
+++ b/src/doc/rustc/src/platform-support/android.md
@@ -61,3 +61,8 @@
* `Zba` (address calculation instructions)
* `Zbb` (base instructions)
* `Zbs` (single-bit instructions)
+
+### aarch64-linux-android on Nightly compilers
+
+As soon as `-Zfixed-x18` compiler flag is supplied, the [`ShadowCallStack` sanitizer](https://releases.llvm.org/7.0.1/tools/clang/docs/ShadowCallStack.html)
+instrumentation is also made avaiable by supplying the second compiler flag `-Zsanitizer=shadow-call-stack`.
diff --git a/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md
new file mode 100644
index 0000000..4c416b5
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md
@@ -0,0 +1,32 @@
+# powerpc-unknown-linux-muslspe
+
+**Tier: 3**
+
+This target is very similar to already existing ones like `powerpc_unknown_linux_musl` and `powerpc_unknown_linux_gnuspe`.
+This one has PowerPC SPE support for musl. Unfortunately, the last supported gcc version with PowerPC SPE is 8.4.0.
+
+## Target maintainers
+
+- [@BKPepe](https://github.com/BKPepe)
+
+## Requirements
+
+This target is cross-compiled. There is no support for `std`. There is no
+default allocator, but it's possible to use `alloc` by supplying an allocator.
+
+This target generated binaries in the ELF format.
+
+## Building the target
+
+This target was tested and used within the `OpenWrt` build system for CZ.NIC Turris 1.x routers using Freescale P2020.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+This is a cross-compiled target and there is no support to run rustc test suite.
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md
index 39f24a1..ebbe141 100644
--- a/src/doc/rustdoc/src/unstable-features.md
+++ b/src/doc/rustdoc/src/unstable-features.md
@@ -515,6 +515,9 @@
Note that the third item is the crate root, which in this case is undocumented.
+If you want the JSON output to be displayed on `stdout` instead of having a file generated, you can
+use `-o -`.
+
### `-w`/`--output-format`: output format
`--output-format json` emits documentation in the experimental
diff --git a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
index 8c8bff5..b215bc8 100644
--- a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
+++ b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
@@ -1,7 +1,7 @@
# `fixed-x18`
This option prevents the compiler from using the x18 register. It is only
-supported on aarch64.
+supported on `aarch64`.
From the [ABI spec][arm-abi]:
@@ -23,6 +23,11 @@
platforms that always treat x18 as a reserved register, and the `-Zfixed-x18`
flag is not required to use the sanitizer on such platforms. However, the
sanitizer may be supported on targets where this is not the case in the future.
+One way to do so now on Nightly compilers is to explicitly supply this `-Zfixed-x18`
+flag with `aarch64` targets, so that the sanitizer is available for instrumentation
+on targets like `aarch64-unknown-none`, for instance. However, discretion is still
+required to make sure that the runtime support is in place for this sanitizer
+to be effective.
It is undefined behavior for `-Zsanitizer=shadow-call-stack` code to call into
code where x18 is a temporary register. On the other hand, when you are *not*
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 72b44e0..edc63a2 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -787,6 +787,10 @@
See the [Clang ShadowCallStack documentation][clang-scs] for more details.
+* `aarch64-unknown-none`
+
+In addition to support from a runtime by the application or operating system, the `-Zfixed-x18` flag is also mandatory.
+
# ThreadSanitizer
ThreadSanitizer is a data race detection tool. It is supported on the following
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5375734..db81b4c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -3094,16 +3094,10 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
let def_id = item.owner_id.to_def_id();
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
- hir::ForeignItemKind::Fn(decl, names, generics, safety) => {
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
- let generics = clean_generics(generics, cx);
- let args = clean_args_from_types_and_names(cx, decl.inputs, names);
- let decl = clean_fn_decl_with_args(cx, decl, None, args);
- (generics, decl)
- });
- ForeignFunctionItem(Box::new(Function { decl, generics }), safety)
- }
+ hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem(
+ clean_function(cx, &sig, generics, FunctionArgs::Names(names)),
+ sig.header.safety,
+ ),
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: None },
safety,
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index d599fea..9e9d8f0 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -286,6 +286,9 @@ pub(crate) struct RenderOptions {
pub(crate) no_emit_shared: bool,
/// If `true`, HTML source code pages won't be generated.
pub(crate) html_no_source: bool,
+ /// This field is only used for the JSON output. If it's set to true, no file will be created
+ /// and content will be displayed in stdout directly.
+ pub(crate) output_to_stdout: bool,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -548,16 +551,17 @@ fn println_condition(condition: Condition) {
dcx.fatal("the `--test` flag must be passed to enable `--no-run`");
}
+ let mut output_to_stdout = false;
let test_builder_wrappers =
matches.opt_strs("test-builder-wrapper").iter().map(PathBuf::from).collect();
- let out_dir = matches.opt_str("out-dir").map(|s| PathBuf::from(&s));
- let output = matches.opt_str("output").map(|s| PathBuf::from(&s));
- let output = match (out_dir, output) {
+ let output = match (matches.opt_str("out-dir"), matches.opt_str("output")) {
(Some(_), Some(_)) => {
dcx.fatal("cannot use both 'out-dir' and 'output' at once");
}
- (Some(out_dir), None) => out_dir,
- (None, Some(output)) => output,
+ (Some(out_dir), None) | (None, Some(out_dir)) => {
+ output_to_stdout = out_dir == "-";
+ PathBuf::from(out_dir)
+ }
(None, None) => PathBuf::from("doc"),
};
@@ -818,6 +822,7 @@ fn println_condition(condition: Condition) {
call_locations,
no_emit_shared: false,
html_no_source,
+ output_to_stdout,
};
Some((options, render_options))
}
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index b91333e..d49fa3ac 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -75,7 +75,6 @@ pub(crate) fn run_merged_tests(
#![allow(internal_features)]
#![feature(test)]
#![feature(rustc_attrs)]
-#![feature(coverage_attribute)]
"
.to_string();
@@ -135,7 +134,6 @@ pub fn doctest_runner(bin: &std::path::Path, test_nb: usize) -> Result<(), Strin
}}
#[rustc_main]
-#[coverage(off)]
fn main() -> std::process::ExitCode {{
const TESTS: [test::TestDescAndFn; {nb_tests}] = [{ids}];
let bin_marker = std::ffi::OsStr::new(__doctest_mod::BIN_OPTION);
@@ -235,11 +233,9 @@ fn main() {returns_result} {{
writeln!(
output,
"
-#[rustc_test_marker = {test_name:?}]
pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest(
{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic},
test::StaticTestFn(
- #[coverage(off)]
|| {{{runner}}},
));
}}",
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index ea191dc..e286029 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -9,16 +9,19 @@
use std::cell::RefCell;
use std::fs::{create_dir_all, File};
-use std::io::{BufWriter, Write};
+use std::io::{stdout, BufWriter, Write};
use std::path::PathBuf;
use std::rc::Rc;
-use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::def_id::LOCAL_CRATE;
use rustdoc_json_types as types;
+// It's important to use the FxHashMap from rustdoc_json_types here, instead of
+// the one from rustc_data_structures, as they're different types due to sysroots.
+// See #110051 and #127456 for details
+use rustdoc_json_types::FxHashMap;
use crate::clean::types::{ExternalCrate, ExternalLocation};
use crate::clean::ItemKind;
@@ -36,8 +39,10 @@ pub(crate) struct JsonRenderer<'tcx> {
/// A mapping of IDs that contains all local items for this crate which gets output as a top
/// level field of the JSON blob.
index: Rc<RefCell<FxHashMap<types::Id, types::Item>>>,
- /// The directory where the blob will be written to.
- out_path: PathBuf,
+ /// The directory where the JSON blob should be written to.
+ ///
+ /// If this is `None`, the blob will be printed to `stdout` instead.
+ out_dir: Option<PathBuf>,
cache: Rc<Cache>,
imported_items: DefIdSet,
}
@@ -97,6 +102,22 @@ fn get_impls(&mut self, id: DefId) -> Vec<types::Id> {
})
.unwrap_or_default()
}
+
+ fn serialize_and_write<T: Write>(
+ &self,
+ output_crate: types::Crate,
+ mut writer: BufWriter<T>,
+ path: &str,
+ ) -> Result<(), Error> {
+ self.sess().time("rustdoc_json_serialize_and_write", || {
+ try_err!(
+ serde_json::ser::to_writer(&mut writer, &output_crate).map_err(|e| e.to_string()),
+ path
+ );
+ try_err!(writer.flush(), path);
+ Ok(())
+ })
+ }
}
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
@@ -120,7 +141,7 @@ fn init(
JsonRenderer {
tcx,
index: Rc::new(RefCell::new(FxHashMap::default())),
- out_path: options.output,
+ out_dir: if options.output_to_stdout { None } else { Some(options.output) },
cache: Rc::new(cache),
imported_items,
},
@@ -220,14 +241,11 @@ fn after_krate(&mut self) -> Result<(), Error> {
let index = (*self.index).clone().into_inner();
debug!("Constructing Output");
- // This needs to be the default HashMap for compatibility with the public interface for
- // rustdoc-json-types
- #[allow(rustc::default_hash_types)]
- let output = types::Crate {
+ let output_crate = types::Crate {
root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())),
crate_version: self.cache.crate_version.clone(),
includes_private: self.cache.document_private,
- index: index.into_iter().collect(),
+ index,
paths: self
.cache
.paths
@@ -264,20 +282,21 @@ fn after_krate(&mut self) -> Result<(), Error> {
.collect(),
format_version: types::FORMAT_VERSION,
};
- let out_dir = self.out_path.clone();
- try_err!(create_dir_all(&out_dir), out_dir);
+ if let Some(ref out_dir) = self.out_dir {
+ try_err!(create_dir_all(&out_dir), out_dir);
- let mut p = out_dir;
- p.push(output.index.get(&output.root).unwrap().name.clone().unwrap());
- p.set_extension("json");
- let mut file = BufWriter::new(try_err!(File::create(&p), p));
- self.tcx
- .sess
- .time("rustdoc_json_serialization", || serde_json::ser::to_writer(&mut file, &output))
- .unwrap();
- try_err!(file.flush(), p);
+ let mut p = out_dir.clone();
+ p.push(output_crate.index.get(&output_crate.root).unwrap().name.clone().unwrap());
+ p.set_extension("json");
- Ok(())
+ self.serialize_and_write(
+ output_crate,
+ BufWriter::new(try_err!(File::create(&p), p)),
+ &p.display().to_string(),
+ )
+ } else {
+ self.serialize_and_write(output_crate, BufWriter::new(stdout().lock()), "<stdout>")
+ }
}
fn cache(&self) -> &Cache {
diff --git a/src/llvm-project b/src/llvm-project
index 57ae1a3..ccf4c38 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 57ae1a3474057fead2c438928ed368b3740bf0ec
+Subproject commit ccf4c38bdd73f1a37ec266c73bdaef80e39f8cf6
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 999134a..40a90c1 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -5,7 +5,7 @@
use std::path::PathBuf;
-use rustc_hash::FxHashMap;
+pub use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
/// The version of JSON output that this crate represents.
diff --git a/src/tools/cargo b/src/tools/cargo
index 0d8d22f..ba8b394 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 0d8d22f83b066503f6b2b755925197e959e58b4f
+Subproject commit ba8b39413c74d08494f94a7542fe79aa636e1661
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index de91233..8711783 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -470,7 +470,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
});
// Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
- while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) {
+ while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token == TokenKind::Ident) {
let mut iter = iter
.by_ref()
.filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
@@ -480,7 +480,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
// matches `!{`
match_tokens!(iter, Bang OpenBrace);
if let Some(LintDeclSearchResult { range, .. }) =
- iter.find(|result| result.token_kind == TokenKind::CloseBrace)
+ iter.find(|result| result.token == TokenKind::CloseBrace)
{
last_decl_curly_offset = Some(range.end);
}
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 966d385..7a11e35 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -12,7 +12,6 @@
#![feature(let_chains)]
#![feature(trait_upcasting)]
#![feature(strict_overflow_ops)]
-#![feature(is_none_or)]
// Configure clippy and other lints
#![allow(
clippy::collapsible_else_if,
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index c4d5446..eae6022 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -11,3 +11,4 @@
regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
gimli = "0.31.0"
build_helper = { path = "../build_helper" }
+serde_json = "1.0"
diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs
index 7af7944..e931585 100644
--- a/src/tools/run-make-support/src/external_deps/llvm.rs
+++ b/src/tools/run-make-support/src/external_deps/llvm.rs
@@ -285,12 +285,24 @@ pub fn obj_to_ar(&mut self) -> &mut Self {
self
}
+ /// Like `obj_to_ar` except creating a thin archive.
+ pub fn obj_to_thin_ar(&mut self) -> &mut Self {
+ self.cmd.arg("rcus").arg("--thin");
+ self
+ }
+
/// Extract archive members back to files.
pub fn extract(&mut self) -> &mut Self {
self.cmd.arg("x");
self
}
+ /// Print the table of contents.
+ pub fn table_of_contents(&mut self) -> &mut Self {
+ self.cmd.arg("t");
+ self
+ }
+
/// Provide an output, then an input file. Bundled in one function, as llvm-ar has
/// no "--output"-style flag.
pub fn output_input(&mut self, out: impl AsRef<Path>, input: impl AsRef<Path>) -> &mut Self {
diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs
index 96c2218..96b1c71 100644
--- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
@@ -71,14 +71,8 @@ pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self
}
- /// Specify path to the output folder.
- pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
- self.cmd.arg("-o");
- self.cmd.arg(path.as_ref());
- self
- }
-
/// Specify output directory.
+ #[doc(alias = "output")]
pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
self.cmd.arg("--out-dir").arg(path.as_ref());
self
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 4bef4f0..fc20fd3 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -38,6 +38,7 @@ pub mod rfs {
pub use gimli;
pub use object;
pub use regex;
+pub use serde_json;
pub use wasmparser;
// Re-exports of external dependencies.
diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs
index b788bc6..1e6e44c 100644
--- a/src/tools/run-make-support/src/path_helpers.rs
+++ b/src/tools/run-make-support/src/path_helpers.rs
@@ -84,3 +84,18 @@ pub fn has_suffix<P: AsRef<Path>>(path: P, suffix: &str) -> bool {
pub fn filename_contains<P: AsRef<Path>>(path: P, needle: &str) -> bool {
path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(needle))
}
+
+/// Helper for reading entries in a given directory and its children.
+pub fn read_dir_entries_recursive<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
+ fn read_dir_entries_recursive_inner<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, callback: &mut F) {
+ for entry in rfs::read_dir(dir) {
+ let path = entry.unwrap().path();
+ callback(&path);
+ if path.is_dir() {
+ read_dir_entries_recursive_inner(path, callback);
+ }
+ }
+ }
+
+ read_dir_entries_recursive_inner(dir, &mut callback);
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 7c48195..f406666 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -1462,7 +1462,7 @@ fn generic_args_sans_defaults<'ga>(
// otherwise, if the arg is equal to the param default, hide it (unless the
// default is an error which can happen for the trait Self type)
#[allow(unstable_name_collisions)]
- default_parameters.get(i).is_none_or(|default_parameter| {
+ IsNoneOr::is_none_or(default_parameters.get(i), |default_parameter| {
// !is_err(default_parameter.skip_binders())
// &&
arg != &default_parameter.clone().substitute(Interner, ¶meters)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 4c9e0a1..21c8451 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -15,8 +15,10 @@
#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_abi as rustc_abi;
-// Use the crates.io version unconditionally until the API settles enough that we can switch to
-// using the in-tree one.
+#[cfg(feature = "in-rust-tree")]
+extern crate rustc_pattern_analysis;
+
+#[cfg(not(feature = "in-rust-tree"))]
extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis;
mod builder;
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index df051ed..3b859fe 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -304,6 +304,12 @@
]
[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
name = "elasticlunr-rs"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -466,6 +472,21 @@
]
[[package]]
+name = "html_parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f56db07b6612644f6f7719f8ef944f75fff9d6378fdf3d316fd32194184abd"
+dependencies = [
+ "doc-comment",
+ "pest",
+ "pest_derive",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -680,13 +701,13 @@
version = "0.1.0"
dependencies = [
"clap",
+ "html_parser",
"mdbook",
"pulldown-cmark",
"pulldown-cmark-to-cmark",
"serde_json",
"thiserror",
"toml 0.8.14",
- "xmlparser",
]
[[package]]
@@ -1768,12 +1789,6 @@
]
[[package]]
-name = "xmlparser"
-version = "0.13.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
-
-[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs
index 60c827f..8d5f7f9 100644
--- a/src/tools/rustfmt/src/parse/macros/mod.rs
+++ b/src/tools/rustfmt/src/parse/macros/mod.rs
@@ -84,9 +84,7 @@ pub(crate) struct ParsedMacroArgs {
fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
for &keyword in RUST_KW.iter() {
if parser.token.is_keyword(keyword)
- && parser.look_ahead(1, |t| {
- t.kind == TokenKind::Eof || t.kind == TokenKind::Comma
- })
+ && parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma)
{
parser.bump();
return Some(MacroArg::Keyword(
@@ -131,7 +129,7 @@ pub(crate) fn parse_macro_args(
Some(arg) => {
args.push(arg);
parser.bump();
- if parser.token.kind == TokenKind::Eof && args.len() == 2 {
+ if parser.token == TokenKind::Eof && args.len() == 2 {
vec_with_semi = true;
break;
}
@@ -150,7 +148,7 @@ pub(crate) fn parse_macro_args(
parser.bump();
- if parser.token.kind == TokenKind::Eof {
+ if parser.token == TokenKind::Eof {
trailing_comma = true;
break;
}
diff --git a/src/tools/rustfmt/tests/target/unsafe_attributes.rs b/src/tools/rustfmt/tests/target/unsafe_attributes.rs
index a05bedc..d79c56f 100644
--- a/src/tools/rustfmt/tests/target/unsafe_attributes.rs
+++ b/src/tools/rustfmt/tests/target/unsafe_attributes.rs
@@ -1,4 +1,3 @@
-#![feature(unsafe_attributes)]
// https://github.com/rust-lang/rust/issues/123757
//
#![simple_ident]
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index bc44655..f55abb5 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,21 +1,13 @@
run-make/branch-protection-check-IBT/Makefile
run-make/cat-and-grep-sanity-check/Makefile
-run-make/dep-info-doesnt-run-much/Makefile
-run-make/dep-info-spaces/Makefile
-run-make/dep-info/Makefile
run-make/emit-to-stdout/Makefile
run-make/extern-fn-reachable/Makefile
run-make/incr-add-rust-src-component/Makefile
run-make/issue-84395-lto-embed-bitcode/Makefile
run-make/jobserver-error/Makefile
run-make/libs-through-symlinks/Makefile
-run-make/libtest-json/Makefile
-run-make/libtest-junit/Makefile
run-make/libtest-thread-limit/Makefile
run-make/macos-deployment-target/Makefile
-run-make/native-link-modifier-bundle/Makefile
-run-make/reproducible-build/Makefile
-run-make/rlib-format-packed-bundled-libs/Makefile
run-make/split-debuginfo/Makefile
run-make/symbol-mangling-hashed/Makefile
run-make/translation/Makefile
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 762df40..c3a0833 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -345,6 +345,9 @@
//@ revisions: powerpc_unknown_linux_musl
//@ [powerpc_unknown_linux_musl] compile-flags: --target powerpc-unknown-linux-musl
//@ [powerpc_unknown_linux_musl] needs-llvm-components: powerpc
+//@ revisions: powerpc_unknown_linux_muslspe
+//@ [powerpc_unknown_linux_muslspe] compile-flags: --target powerpc-unknown-linux-muslspe
+//@ [powerpc_unknown_linux_muslspe] needs-llvm-components: powerpc
//@ revisions: powerpc_unknown_netbsd
//@ [powerpc_unknown_netbsd] compile-flags: --target powerpc-unknown-netbsd
//@ [powerpc_unknown_netbsd] needs-llvm-components: powerpc
diff --git a/tests/codegen/debuginfo-inline-callsite-location.rs b/tests/codegen/debuginfo-inline-callsite-location.rs
index aee07b4..c31788d 100644
--- a/tests/codegen/debuginfo-inline-callsite-location.rs
+++ b/tests/codegen/debuginfo-inline-callsite-location.rs
@@ -9,13 +9,12 @@
// CHECK: tail call void @{{[A-Za-z0-9_]+4core6option13unwrap_failed}}
// CHECK-SAME: !dbg ![[#second_dbg:]]
-// CHECK-DAG: ![[#func_dbg:]] = distinct !DISubprogram(name: "unwrap<i32>"
-// CHECK-DAG: ![[#first_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]],
-// CHECK: ![[#second_scope:]] = distinct !DILexicalBlock(scope: ![[#func_dbg]],
+// CHECK-DAG: ![[#func_scope:]] = distinct !DISubprogram(name: "unwrap<i32>"
+// CHECK-DAG: ![[#]] = !DILocalVariable(name: "self",{{( arg: 1,)?}} scope: ![[#func_scope]]
// CHECK: ![[#first_dbg]] = !DILocation(line: [[#]]
-// CHECK-SAME: scope: ![[#first_scope]], inlinedAt: ![[#]])
+// CHECK-SAME: scope: ![[#func_scope]], inlinedAt: ![[#]])
// CHECK: ![[#second_dbg]] = !DILocation(line: [[#]]
-// CHECK-SAME: scope: ![[#second_scope]], inlinedAt: ![[#]])
+// CHECK-SAME: scope: ![[#func_scope]], inlinedAt: ![[#]])
#![crate_type = "lib"]
diff --git a/tests/codegen/inline-function-args-debug-info.rs b/tests/codegen/inline-function-args-debug-info.rs
index 7263374..53a1791 100644
--- a/tests/codegen/inline-function-args-debug-info.rs
+++ b/tests/codegen/inline-function-args-debug-info.rs
@@ -15,6 +15,7 @@ pub fn outer_function(x: usize, y: usize) -> usize {
fn inner_function(aaaa: usize, bbbb: usize) -> usize {
// CHECK: !DILocalVariable(name: "aaaa", arg: 1
// CHECK-SAME: line: 15
+ // CHECK-NOT: !DILexicalBlock(
// CHECK: !DILocalVariable(name: "bbbb", arg: 2
// CHECK-SAME: line: 15
aaaa + bbbb
diff --git a/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs b/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
new file mode 100644
index 0000000..e2e14ab
--- /dev/null
+++ b/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
@@ -0,0 +1,19 @@
+//@ revisions: aarch64 android
+//@[aarch64] compile-flags: --target aarch64-unknown-none -Zfixed-x18 -Zsanitizer=shadow-call-stack
+//@[aarch64] needs-llvm-components: aarch64
+//@[android] compile-flags: --target aarch64-linux-android -Zsanitizer=shadow-call-stack
+//@[android] needs-llvm-components: aarch64
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+#[no_mangle]
+pub fn foo() {}
+
+// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}}
diff --git a/tests/crashes/128695.rs b/tests/crashes/128695.rs
new file mode 100644
index 0000000..661f427
--- /dev/null
+++ b/tests/crashes/128695.rs
@@ -0,0 +1,11 @@
+//@ known-bug: rust-lang/rust#128695
+//@ edition: 2021
+
+use core::pin::{pin, Pin};
+
+fn main() {
+ let fut = pin!(async {
+ let async_drop_fut = pin!(core::future::async_drop(async {}));
+ (async_drop_fut).await;
+ });
+}
diff --git a/tests/crashes/128848.rs b/tests/crashes/128848.rs
new file mode 100644
index 0000000..636811f
--- /dev/null
+++ b/tests/crashes/128848.rs
@@ -0,0 +1,5 @@
+//@ known-bug: rust-lang/rust#128848
+
+fn f<T>(a: T, b: T, c: T) {
+ f.call_once()
+}
diff --git a/tests/crashes/128870.rs b/tests/crashes/128870.rs
new file mode 100644
index 0000000..2b73196
--- /dev/null
+++ b/tests/crashes/128870.rs
@@ -0,0 +1,18 @@
+//@ known-bug: rust-lang/rust#128870
+//@ compile-flags: -Zvalidate-mir
+
+#[repr(packed)]
+#[repr(u32)]
+enum E {
+ A,
+ B,
+ C,
+}
+
+fn main() {
+ union InvalidTag {
+ int: u32,
+ e: E,
+ }
+ let _invalid_tag = InvalidTag { int: 4 };
+}
diff --git a/tests/crashes/129075.rs b/tests/crashes/129075.rs
new file mode 100644
index 0000000..4a0e920
--- /dev/null
+++ b/tests/crashes/129075.rs
@@ -0,0 +1,16 @@
+//@ known-bug: rust-lang/rust#129075
+//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes
+
+struct Foo<T>([T; 2]);
+
+impl<T: Default + Copy> Default for Foo<T> {
+ fn default(&mut self) -> Self {
+ Foo([Default::default(); 2])
+ }
+}
+
+fn field_array() {
+ let a: i32;
+ let b;
+ Foo([a, b]) = Default::default();
+}
diff --git a/tests/crashes/129095.rs b/tests/crashes/129095.rs
new file mode 100644
index 0000000..ea70c05
--- /dev/null
+++ b/tests/crashes/129095.rs
@@ -0,0 +1,10 @@
+//@ known-bug: rust-lang/rust#129095
+//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+
+pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
+ BYTES
+}
+
+pub fn main() {
+ assert_eq!(function_with_bytes::<b"AAAAb">(), &[0x41, 0x41, 0x41, 0x41]);
+}
diff --git a/tests/crashes/129099.rs b/tests/crashes/129099.rs
new file mode 100644
index 0000000..9aaab75
--- /dev/null
+++ b/tests/crashes/129099.rs
@@ -0,0 +1,15 @@
+//@ known-bug: rust-lang/rust#129099
+
+#![feature(type_alias_impl_trait)]
+
+fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
+ loop {}
+}
+
+pub fn main() {
+ type Opaque = impl Sized;
+ fn define() -> Opaque {
+ let x: Opaque = dyn_hoops::<()>(0);
+ x
+ }
+}
diff --git a/tests/crashes/129109.rs b/tests/crashes/129109.rs
new file mode 100644
index 0000000..8b9ebdf
--- /dev/null
+++ b/tests/crashes/129109.rs
@@ -0,0 +1,10 @@
+//@ known-bug: rust-lang/rust#129109
+//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir
+
+extern "C" {
+ pub static mut symbol: [i8];
+}
+
+fn main() {
+ println!("C", unsafe { &symbol });
+}
diff --git a/tests/crashes/129127.rs b/tests/crashes/129127.rs
new file mode 100644
index 0000000..8ec848d
--- /dev/null
+++ b/tests/crashes/129127.rs
@@ -0,0 +1,21 @@
+//@ known-bug: rust-lang/rust#129127
+//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir -Zcross-crate-inline-threshold=always
+
+
+
+
+pub struct Rows<'a>();
+
+impl<'a> Iterator for Rows<'a> {
+ type Item = ();
+
+ fn next() -> Option<Self::Item> {
+ let mut rows = Rows();
+ rows.map(|row| row).next()
+ }
+}
+
+fn main() {
+ let mut rows = Rows();
+ rows.next();
+}
diff --git a/tests/debuginfo/basic-types-globals-metadata.rs b/tests/debuginfo/basic-types-globals-metadata.rs
index d346b40..13678c3 100644
--- a/tests/debuginfo/basic-types-globals-metadata.rs
+++ b/tests/debuginfo/basic-types-globals-metadata.rs
@@ -1,5 +1,4 @@
//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-g
// gdb-command:run
diff --git a/tests/debuginfo/basic-types-metadata.rs b/tests/debuginfo/basic-types-metadata.rs
index 5f953c8..3aebf25 100644
--- a/tests/debuginfo/basic-types-metadata.rs
+++ b/tests/debuginfo/basic-types-metadata.rs
@@ -1,5 +1,4 @@
//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-g
// gdb-command:run
@@ -36,12 +35,12 @@
// gdb-command:whatis f64
// gdb-check:type = f64
// gdb-command:whatis fnptr
-// gdb-check:type = [...] (*)([...])
+// gdb-check:type = *mut fn ()
// gdb-command:info functions _yyy
// gdbg-check:[...]![...]_yyy([...]);
-// gdbr-check:static fn basic_types_metadata::_yyy() -> !;
+// gdbr-check:static fn basic_types_metadata::_yyy();
// gdb-command:ptype closure_0
-// gdbr-check: type = struct closure
+// gdbr-check: type = struct basic_types_metadata::main::{closure_env#0}
// gdbg-check: type = struct closure {
// gdbg-check: <no data fields>
// gdbg-check: }
@@ -49,18 +48,18 @@
// gdbg-check: type = struct closure {
// gdbg-check: bool *__0;
// gdbg-check: }
-// gdbr-check: type = struct closure (
-// gdbr-check: bool *,
-// gdbr-check: )
+// gdbr-check: type = struct basic_types_metadata::main::{closure_env#1} {
+// gdbr-check: *mut bool,
+// gdbr-check: }
// gdb-command:ptype closure_2
// gdbg-check: type = struct closure {
// gdbg-check: bool *__0;
// gdbg-check: isize *__1;
// gdbg-check: }
-// gdbr-check: type = struct closure (
-// gdbr-check: bool *,
-// gdbr-check: isize *,
-// gdbr-check: )
+// gdbr-check: type = struct basic_types_metadata::main::{closure_env#2} {
+// gdbr-check: *mut bool,
+// gdbr-check: *mut isize,
+// gdbr-check: }
//
// gdb-command:continue
diff --git a/tests/debuginfo/basic-types.rs b/tests/debuginfo/basic-types.rs
index 10ffd74..d836525 100644
--- a/tests/debuginfo/basic-types.rs
+++ b/tests/debuginfo/basic-types.rs
@@ -6,9 +6,6 @@
//@ min-lldb-version: 310
-// This fails on lldb 6.0.1 on x86-64 Fedora 28; so ignore Linux for now.
-//@ ignore-linux
-
//@ compile-flags:-g
// === GDB TESTS ===================================================================================
diff --git a/tests/debuginfo/by-value-non-immediate-argument.rs b/tests/debuginfo/by-value-non-immediate-argument.rs
index e0ae445..68717b7 100644
--- a/tests/debuginfo/by-value-non-immediate-argument.rs
+++ b/tests/debuginfo/by-value-non-immediate-argument.rs
@@ -1,6 +1,5 @@
-//@ ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
-//@ min-lldb-version: 310
-
+//@ min-lldb-version: 1800
+//@ min-gdb-version: 13.0
//@ compile-flags:-g
// === GDB TESTS ===================================================================================
@@ -42,11 +41,11 @@
// lldb-command:run
// lldb-command:v s
-// lldb-check:[...] Struct { a: 1, b: 2.5 }
+// lldb-check:[...] Struct { a = 1 b = 2.5 }
// lldb-command:continue
// lldb-command:v x
-// lldb-check:[...] Struct { a: 3, b: 4.5 }
+// lldb-check:[...] Struct { a = 3 b = 4.5 }
// lldb-command:v y
// lldb-check:[...] 5
// lldb-command:v z
diff --git a/tests/debuginfo/c-style-enum.rs b/tests/debuginfo/c-style-enum.rs
index 395b94c..2ab5d5c 100644
--- a/tests/debuginfo/c-style-enum.rs
+++ b/tests/debuginfo/c-style-enum.rs
@@ -1,5 +1,4 @@
//@ ignore-aarch64
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ min-lldb-version: 310
//@ compile-flags:-g
diff --git a/tests/debuginfo/cross-crate-spans.rs b/tests/debuginfo/cross-crate-spans.rs
index cf3f8e1..a93c8f4 100644
--- a/tests/debuginfo/cross-crate-spans.rs
+++ b/tests/debuginfo/cross-crate-spans.rs
@@ -3,10 +3,6 @@
//@ min-lldb-version: 310
-// This fails on lldb 6.0.1 on x86-64 Fedora 28; so mark it macOS-only
-// for now.
-//@ only-macos
-
//@ aux-build:cross_crate_spans.rs
extern crate cross_crate_spans;
diff --git a/tests/debuginfo/destructured-for-loop-variable.rs b/tests/debuginfo/destructured-for-loop-variable.rs
index 1cad8bc..a8c7cc1 100644
--- a/tests/debuginfo/destructured-for-loop-variable.rs
+++ b/tests/debuginfo/destructured-for-loop-variable.rs
@@ -1,9 +1,5 @@
//@ min-lldb-version: 310
-// This fails on lldb 6.0.1 on x86-64 Fedora 28; so mark it macOS-only
-// for now.
-//@ only-macos
-
//@ compile-flags:-g
// === GDB TESTS ===================================================================================
diff --git a/tests/debuginfo/drop-locations.rs b/tests/debuginfo/drop-locations.rs
index 15b2d0d..0777313 100644
--- a/tests/debuginfo/drop-locations.rs
+++ b/tests/debuginfo/drop-locations.rs
@@ -1,12 +1,11 @@
//@ ignore-windows
//@ ignore-android
-//@ ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ min-lldb-version: 310
+//@ ignore-test: #128971
#![allow(unused)]
-//@ compile-flags:-g -O -C no-prepopulate-passes
-// -O -C no-prepopulate-passes added to work around https://bugs.llvm.org/show_bug.cgi?id=32123
+//@ compile-flags:-g
// This test checks that drop glue code gets attributed to scope's closing brace,
// and function epilogues - to function's closing brace.
diff --git a/tests/debuginfo/function-arg-initialization.rs b/tests/debuginfo/function-arg-initialization.rs
index 05935c3..c641a35 100644
--- a/tests/debuginfo/function-arg-initialization.rs
+++ b/tests/debuginfo/function-arg-initialization.rs
@@ -1,6 +1,3 @@
-//@ ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
-//@ min-lldb-version: 310
-
// This test case checks if function arguments already have the correct value
// when breaking at the first line of the function, that is if the function
// prologue has already been executed at the first line. Note that because of
@@ -8,7 +5,9 @@
// arguments have been properly loaded when setting the breakpoint via the
// function name.
-//@ compile-flags:-g
+//@ min-lldb-version: 1800
+//@ compile-flags:-g -Zmir-enable-passes=-SingleUseConsts
+// SingleUseConsts shouldn't need to be disabled, see #128945
// === GDB TESTS ===================================================================================
diff --git a/tests/debuginfo/function-prologue-stepping-regular.rs b/tests/debuginfo/function-prologue-stepping-regular.rs
index a1f4410..07b9356 100644
--- a/tests/debuginfo/function-prologue-stepping-regular.rs
+++ b/tests/debuginfo/function-prologue-stepping-regular.rs
@@ -1,9 +1,8 @@
// This test case checks if function arguments already have the correct value when breaking at the
// beginning of a function.
-//@ min-lldb-version: 310
+//@ min-lldb-version: 1800
//@ ignore-gdb
-//@ ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-g
// lldb-command:breakpoint set --name immediate_args
diff --git a/tests/debuginfo/lexical-scopes-in-block-expression.rs b/tests/debuginfo/lexical-scopes-in-block-expression.rs
index 5ff7027..bd5a607 100644
--- a/tests/debuginfo/lexical-scopes-in-block-expression.rs
+++ b/tests/debuginfo/lexical-scopes-in-block-expression.rs
@@ -1,5 +1,4 @@
//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-g
diff --git a/tests/debuginfo/limited-debuginfo.rs b/tests/debuginfo/limited-debuginfo.rs
index 32f1495..2e49acd 100644
--- a/tests/debuginfo/limited-debuginfo.rs
+++ b/tests/debuginfo/limited-debuginfo.rs
@@ -1,5 +1,4 @@
//@ ignore-lldb
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-C debuginfo=1
diff --git a/tests/debuginfo/macro-stepping.rs b/tests/debuginfo/macro-stepping.rs
index 5f8d828..3edac3c 100644
--- a/tests/debuginfo/macro-stepping.rs
+++ b/tests/debuginfo/macro-stepping.rs
@@ -1,8 +1,8 @@
//@ ignore-windows
//@ ignore-android
//@ ignore-aarch64
-//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
+//@ min-lldb-version: 1800
+//@ min-gdb-version: 13.0
//@ aux-build:macro-stepping.rs
@@ -11,7 +11,8 @@
#[macro_use]
extern crate macro_stepping; // exports new_scope!()
-//@ compile-flags:-g
+//@ compile-flags:-g -Zmir-enable-passes=-SingleUseConsts
+// SingleUseConsts shouldn't need to be disabled, see #128945
// === GDB TESTS ===================================================================================
diff --git a/tests/debuginfo/method-on-enum.rs b/tests/debuginfo/method-on-enum.rs
index 8a57060..7bee544 100644
--- a/tests/debuginfo/method-on-enum.rs
+++ b/tests/debuginfo/method-on-enum.rs
@@ -1,5 +1,5 @@
-//@ min-lldb-version: 310
-//@ ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
+//@ min-lldb-version: 1800
+//@ min-gdb-version: 13.0
//@ compile-flags:-g
diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs
index a6032cc..a2e2b32 100644
--- a/tests/debuginfo/msvc-pretty-enums.rs
+++ b/tests/debuginfo/msvc-pretty-enums.rs
@@ -206,6 +206,30 @@
// cdb-command: dx -r2 arbitrary_discr2,d
// cdb-check: arbitrary_discr2,d : Def [Type: enum2$<msvc_pretty_enums::ArbitraryDiscr>]
// cdb-check: [+0x[...]] __0 : 5678 [Type: unsigned int]
+//
+// cdb-command: dx c_style_u128_a
+// cdb-check: c_style_u128_a : A [Type: enum2$<msvc_pretty_enums::CStyleU128>]
+//
+// cdb-command: dx c_style_u128_b
+// cdb-check: c_style_u128_b : B [Type: enum2$<msvc_pretty_enums::CStyleU128>]
+//
+// cdb-command: dx c_style_u128_c
+// cdb-check: c_style_u128_c : C [Type: enum2$<msvc_pretty_enums::CStyleU128>]
+//
+// cdb-command: dx c_style_u128_d
+// cdb-check: c_style_u128_d : D [Type: enum2$<msvc_pretty_enums::CStyleU128>]
+//
+// cdb-command: dx c_style_i128_a
+// cdb-check: c_style_i128_a : A [Type: enum2$<msvc_pretty_enums::CStyleI128>]
+//
+// cdb-command: dx c_style_i128_b
+// cdb-check: c_style_i128_b : B [Type: enum2$<msvc_pretty_enums::CStyleI128>]
+//
+// cdb-command: dx c_style_i128_c
+// cdb-check: c_style_i128_c : C [Type: enum2$<msvc_pretty_enums::CStyleI128>]
+//
+// cdb-command: dx c_style_i128_d
+// cdb-check: c_style_i128_d : D [Type: enum2$<msvc_pretty_enums::CStyleI128>]
#![feature(rustc_attrs)]
#![feature(repr128)]
#![feature(arbitrary_enum_discriminant)]
@@ -270,6 +294,22 @@ enum ArbitraryDiscr {
Def(u32) = 5000_000,
}
+#[repr(u128)]
+pub enum CStyleU128 {
+ A = 0_u128,
+ B = 1_u128,
+ C = u64::MAX as u128 + 1,
+ D = u128::MAX,
+}
+
+#[repr(i128)]
+pub enum CStyleI128 {
+ A = 0_i128,
+ B = -1_i128,
+ C = i128::MIN,
+ D = i128::MAX,
+}
+
fn main() {
let a = Some(CStyleEnum::Low);
let b = Option::<CStyleEnum>::None;
@@ -313,6 +353,16 @@ fn main() {
let arbitrary_discr1 = ArbitraryDiscr::Abc(1234);
let arbitrary_discr2 = ArbitraryDiscr::Def(5678);
+ let c_style_u128_a = CStyleU128::A;
+ let c_style_u128_b = CStyleU128::B;
+ let c_style_u128_c = CStyleU128::C;
+ let c_style_u128_d = CStyleU128::D;
+
+ let c_style_i128_a = CStyleI128::A;
+ let c_style_i128_b = CStyleI128::B;
+ let c_style_i128_c = CStyleI128::C;
+ let c_style_i128_d = CStyleI128::D;
+
zzz(); // #break
}
diff --git a/tests/debuginfo/option-like-enum.rs b/tests/debuginfo/option-like-enum.rs
index c782796..da556d6 100644
--- a/tests/debuginfo/option-like-enum.rs
+++ b/tests/debuginfo/option-like-enum.rs
@@ -1,6 +1,5 @@
-//@ ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
-
-//@ min-lldb-version: 310
+//@ min-lldb-version: 1800
+//@ min-gdb-version: 13.0
//@ compile-flags:-g
@@ -22,7 +21,7 @@
// gdbg-command:print empty_gdb->discr
// gdbr-command:print empty_gdb.discr
-// gdb-check:$4 = (isize *) 0x0
+// gdb-check:$4 = (*mut isize) 0x1
// gdb-command:print droid
// gdbg-check:$5 = {RUST$ENCODED$ENUM$2$Void = {id = 675675, range = 10000001, internals = 0x43218765}}
@@ -30,11 +29,11 @@
// gdbg-command:print void_droid_gdb->internals
// gdbr-command:print void_droid_gdb.internals
-// gdb-check:$6 = (isize *) 0x0
+// gdb-check:$6 = (*mut isize) 0x1
// gdb-command:print nested_non_zero_yep
// gdbg-check:$7 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = 10.5, __1 = {a = 10, b = 20, c = [...]}}}
-// gdbr-check:$7 = option_like_enum::NestedNonZero::Yep(10.5, option_like_enum::NestedNonZeroField {a: 10, b: 20, c: 0x[...] "x[...]"})
+// gdbr-check:$7 = option_like_enum::NestedNonZero::Yep(10.5, option_like_enum::NestedNonZeroField {a: 10, b: 20, c: 0x[...]})
// gdb-command:print nested_non_zero_nope
// gdbg-check:$8 = {RUST$ENCODED$ENUM$1$2$Nope = {__0 = [...], __1 = {a = [...], b = [...], c = 0x0}}}
diff --git a/tests/debuginfo/pretty-huge-vec.rs b/tests/debuginfo/pretty-huge-vec.rs
index f4b5345..dcf3521 100644
--- a/tests/debuginfo/pretty-huge-vec.rs
+++ b/tests/debuginfo/pretty-huge-vec.rs
@@ -1,5 +1,4 @@
//@ ignore-windows failing on win32 bot
-//@ ignore-freebsd: gdb package too new
//@ ignore-android: FIXME(#10381)
//@ compile-flags:-g
//@ min-gdb-version: 8.1
diff --git a/tests/debuginfo/pretty-std-collections.rs b/tests/debuginfo/pretty-std-collections.rs
index e9c2c4f..3d5a30d 100644
--- a/tests/debuginfo/pretty-std-collections.rs
+++ b/tests/debuginfo/pretty-std-collections.rs
@@ -1,6 +1,6 @@
//@ ignore-windows failing on win32 bot
-//@ ignore-freebsd: gdb package too new
//@ ignore-android: FIXME(#10381)
+//@ ignore-windows-gnu: #128981
//@ compile-flags:-g
// The pretty printers being tested here require the patch from
diff --git a/tests/debuginfo/pretty-std.rs b/tests/debuginfo/pretty-std.rs
index 45c6dbf..933be97 100644
--- a/tests/debuginfo/pretty-std.rs
+++ b/tests/debuginfo/pretty-std.rs
@@ -1,10 +1,9 @@
// ignore-tidy-linelength
-//@ ignore-freebsd: gdb package too new
-//@ only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
+//@ ignore-windows-gnu: #128981
//@ ignore-android: FIXME(#10381)
//@ compile-flags:-g
//@ min-gdb-version: 7.7
-//@ min-lldb-version: 310
+//@ min-lldb-version: 1800
//@ min-cdb-version: 10.0.18317.1001
// === GDB TESTS ===================================================================================
@@ -12,10 +11,10 @@
// gdb-command: run
// gdb-command: print slice
-// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}
+// gdb-check:$1 = &[i32](size=4) = {0, 1, 2, 3}
// gdb-command: print vec
-// gdb-check:$2 = Vec<u64, alloc::alloc::Global>(len: 4, cap: [...]) = {4, 5, 6, 7}
+// gdb-check:$2 = Vec(size=4) = {4, 5, 6, 7}
// gdb-command: print str_slice
// gdb-check:$3 = "IAMA string slice!"
@@ -24,37 +23,37 @@
// gdb-check:$4 = "IAMA string!"
// gdb-command: print some
-// gdb-check:$5 = Some = {8}
+// gdb-check:$5 = core::option::Option<i16>::Some(8)
// gdb-command: print none
// gdbg-check:$6 = None
-// gdbr-check:$6 = core::option::Option::None
+// gdbr-check:$6 = core::option::Option<i64>::None
// gdb-command: print os_string
// gdb-check:$7 = "IAMA OS string 😃"
// gdb-command: print some_string
-// gdb-check:$8 = Some = {"IAMA optional string!"}
+// gdb-check:$8 = core::option::Option<alloc::string::String>::Some("IAMA optional string!")
-// gdb-command: set print length 5
+// gdb-command: set print elements 5
// gdb-command: print some_string
-// gdb-check:$8 = Some = {"IAMA "...}
+// gdb-check:$9 = core::option::Option<alloc::string::String>::Some("IAMA "...)
// === LLDB TESTS ==================================================================================
// lldb-command:run
// lldb-command:v slice
-// lldb-check:[...] slice = &[0, 1, 2, 3]
+// lldb-check:[...] slice = size=4 { [0] = 0 [1] = 1 [2] = 2 [3] = 3 }
// lldb-command:v vec
-// lldb-check:[...] vec = vec![4, 5, 6, 7]
+// lldb-check:[...] vec = size=4 { [0] = 4 [1] = 5 [2] = 6 [3] = 7 }
// lldb-command:v str_slice
-// lldb-check:[...] str_slice = "IAMA string slice!"
+// lldb-check:[...] str_slice = "IAMA string slice!" { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 's' [6] = 't' [7] = 'r' [8] = 'i' [9] = 'n' [10] = 'g' [11] = ' ' [12] = 's' [13] = 'l' [14] = 'i' [15] = 'c' [16] = 'e' [17] = '!' }
// lldb-command:v string
-// lldb-check:[...] string = "IAMA string!"
+// lldb-check:[...] string = "IAMA string!" { vec = size=12 { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 's' [6] = 't' [7] = 'r' [8] = 'i' [9] = 'n' [10] = 'g' [11] = '!' } }
// lldb-command:v some
// lldb-check:[...] some = Some(8)
@@ -63,7 +62,7 @@
// lldb-check:[...] none = None
// lldb-command:v os_string
-// lldb-check:[...] os_string = "IAMA OS string 😃"[...]
+// lldb-check:[...] os_string = "IAMA OS string 😃" { inner = { inner = size=19 { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 'O' [6] = 'S' [7] = ' ' [8] = 's' [9] = 't' [10] = 'r' [11] = 'i' [12] = 'n' [13] = 'g' [14] = ' ' [15] = '\xf0' [16] = '\x9f' [17] = '\x98' [18] = '\x83' } } }
// === CDB TESTS ==================================================================================
diff --git a/tests/debuginfo/pretty-uninitialized-vec.rs b/tests/debuginfo/pretty-uninitialized-vec.rs
index 225b4a6..5206ff2 100644
--- a/tests/debuginfo/pretty-uninitialized-vec.rs
+++ b/tests/debuginfo/pretty-uninitialized-vec.rs
@@ -1,5 +1,4 @@
//@ ignore-windows failing on win32 bot
-//@ ignore-freebsd: gdb package too new
//@ ignore-android: FIXME(#10381)
//@ compile-flags:-g
//@ min-gdb-version: 8.1
diff --git a/tests/debuginfo/rc_arc.rs b/tests/debuginfo/rc_arc.rs
index ca0feb1..688dc62 100644
--- a/tests/debuginfo/rc_arc.rs
+++ b/tests/debuginfo/rc_arc.rs
@@ -1,4 +1,4 @@
-//@ ignore-windows-gnu: pretty-printers are not loaded
+//@ ignore-windows-gnu: #128981
//@ compile-flags:-g
//@ min-gdb-version: 8.1
diff --git a/tests/debuginfo/simple-struct.rs b/tests/debuginfo/simple-struct.rs
index 968a5c6..aaa654a 100644
--- a/tests/debuginfo/simple-struct.rs
+++ b/tests/debuginfo/simple-struct.rs
@@ -1,5 +1,4 @@
//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags: -g -Zmir-enable-passes=-CheckAlignment
diff --git a/tests/debuginfo/simple-tuple.rs b/tests/debuginfo/simple-tuple.rs
index 8600310..9d809a1 100644
--- a/tests/debuginfo/simple-tuple.rs
+++ b/tests/debuginfo/simple-tuple.rs
@@ -1,5 +1,4 @@
//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-g
diff --git a/tests/debuginfo/struct-in-enum.rs b/tests/debuginfo/struct-in-enum.rs
index 52e419e..e4b647a 100644
--- a/tests/debuginfo/struct-in-enum.rs
+++ b/tests/debuginfo/struct-in-enum.rs
@@ -1,6 +1,5 @@
-//@ min-lldb-version: 310
+//@ min-lldb-version: 1800
//@ ignore-gdb-version: 7.11.90 - 7.12.9
-//@ ignore-test // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-g
diff --git a/tests/debuginfo/union-smoke.rs b/tests/debuginfo/union-smoke.rs
index 9b1cf6e..d786ba6 100644
--- a/tests/debuginfo/union-smoke.rs
+++ b/tests/debuginfo/union-smoke.rs
@@ -1,5 +1,4 @@
//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ ignore-gdb-version: 7.11.90 - 7.12.9
diff --git a/tests/debuginfo/vec.rs b/tests/debuginfo/vec.rs
index cf7de0b..20cfd78 100644
--- a/tests/debuginfo/vec.rs
+++ b/tests/debuginfo/vec.rs
@@ -1,5 +1,4 @@
//@ min-lldb-version: 310
-//@ ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
//@ compile-flags:-g
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-1.rs b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
index 2d35163..d814625 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-1.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-1.rs
@@ -1,6 +1,12 @@
#![crate_name = "dependency"]
#![crate_type = "rlib"]
-pub struct Type;
-pub trait Trait {}
-impl Trait for Type {}
+pub struct Type(pub i32);
+pub trait Trait {
+ fn foo(&self);
+ fn bar();
+}
+impl Trait for Type {
+ fn foo(&self) {}
+ fn bar() {}
+}
pub fn do_something<X: Trait>(_: X) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-2.rs b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
index a5df3dc..0a566fe 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions-2.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions-2.rs
@@ -1,6 +1,12 @@
#![crate_name = "dependency"]
#![crate_type = "rlib"]
-pub struct Type(pub i32);
-pub trait Trait {}
-impl Trait for Type {}
+pub struct Type;
+pub trait Trait {
+ fn foo(&self);
+ fn bar();
+}
+impl Trait for Type {
+ fn foo(&self) {}
+ fn bar() {}
+}
pub fn do_something<X: Trait>(_: X) {}
diff --git a/tests/run-make/crate-loading/multiple-dep-versions-3.rs b/tests/run-make/crate-loading/multiple-dep-versions-3.rs
new file mode 100644
index 0000000..07d888e
--- /dev/null
+++ b/tests/run-make/crate-loading/multiple-dep-versions-3.rs
@@ -0,0 +1,5 @@
+#![crate_name = "foo"]
+#![crate_type = "rlib"]
+
+extern crate dependency;
+pub use dependency::Type;
diff --git a/tests/run-make/crate-loading/multiple-dep-versions.rs b/tests/run-make/crate-loading/multiple-dep-versions.rs
index 5a6cb03..8ef042b 100644
--- a/tests/run-make/crate-loading/multiple-dep-versions.rs
+++ b/tests/run-make/crate-loading/multiple-dep-versions.rs
@@ -1,8 +1,10 @@
extern crate dep_2_reexport;
extern crate dependency;
-use dep_2_reexport::do_something;
-use dependency::Type;
+use dep_2_reexport::Type;
+use dependency::{do_something, Trait};
fn main() {
do_something(Type);
+ Type.foo();
+ Type::bar();
}
diff --git a/tests/run-make/crate-loading/rmake.rs b/tests/run-make/crate-loading/rmake.rs
index d7abd58..13585ed 100644
--- a/tests/run-make/crate-loading/rmake.rs
+++ b/tests/run-make/crate-loading/rmake.rs
@@ -1,26 +1,100 @@
//@ only-linux
//@ ignore-wasm32
//@ ignore-wasm64
+// ignore-tidy-linelength
use run_make_support::{rust_lib_name, rustc};
fn main() {
rustc().input("multiple-dep-versions-1.rs").run();
rustc().input("multiple-dep-versions-2.rs").extra_filename("2").metadata("2").run();
+ rustc()
+ .input("multiple-dep-versions-3.rs")
+ .extern_("dependency", rust_lib_name("dependency2"))
+ .run();
rustc()
.input("multiple-dep-versions.rs")
.extern_("dependency", rust_lib_name("dependency"))
- .extern_("dep_2_reexport", rust_lib_name("dependency2"))
+ .extern_("dep_2_reexport", rust_lib_name("foo"))
.run_fail()
.assert_stderr_contains(
- "you have multiple different versions of crate `dependency` in your dependency graph",
+ r#"error[E0277]: the trait bound `dep_2_reexport::Type: Trait` is not satisfied
+ --> multiple-dep-versions.rs:7:18
+ |
+7 | do_something(Type);
+ | ------------ ^^^^ the trait `Trait` is not implemented for `dep_2_reexport::Type`
+ | |
+ | required by a bound introduced by this call
+ |
+help: there are multiple different versions of crate `dependency` the your dependency graph
+ --> multiple-dep-versions.rs:1:1
+ |
+1 | extern crate dep_2_reexport;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a dependency of crate `foo`
+2 | extern crate dependency;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ one version of crate `dependency` is used here, as a direct dependency of the current crate"#,
)
.assert_stderr_contains(
- "two types coming from two different versions of the same crate are different types \
- even if they look the same",
+ r#"
+3 | pub struct Type(pub i32);
+ | ^^^^^^^^^^^^^^^ this type implements the required trait
+4 | pub trait Trait {
+ | --------------- this is the required trait"#,
)
- .assert_stderr_contains("this type doesn't implement the required trait")
- .assert_stderr_contains("this type implements the required trait")
- .assert_stderr_contains("this is the required trait");
+ .assert_stderr_contains(
+ r#"
+3 | pub struct Type;
+ | ^^^^^^^^^^^^^^^ this type doesn't implement the required trait"#,
+ )
+ .assert_stderr_contains(
+ r#"
+error[E0599]: no method named `foo` found for struct `dep_2_reexport::Type` in the current scope
+ --> multiple-dep-versions.rs:8:10
+ |
+8 | Type.foo();
+ | ^^^ method not found in `Type`
+ |
+note: there are multiple different versions of crate `dependency` in the dependency graph"#,
+ )
+ .assert_stderr_contains(
+ r#"
+4 | pub trait Trait {
+ | ^^^^^^^^^^^^^^^ this is the trait that is needed
+5 | fn foo(&self);
+ | -------------- the method is available for `dep_2_reexport::Type` here
+ |
+ ::: multiple-dep-versions.rs:4:32
+ |
+4 | use dependency::{do_something, Trait};
+ | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#,
+ )
+ .assert_stderr_contains(
+ r#"
+4 | pub trait Trait {
+ | --------------- this is the trait that was imported"#,
+ )
+ .assert_stderr_contains(
+ r#"
+error[E0599]: no function or associated item named `bar` found for struct `dep_2_reexport::Type` in the current scope
+ --> multiple-dep-versions.rs:9:11
+ |
+9 | Type::bar();
+ | ^^^ function or associated item not found in `Type`
+ |
+note: there are multiple different versions of crate `dependency` in the dependency graph"#,
+ )
+ .assert_stderr_contains(
+ r#"
+4 | pub trait Trait {
+ | ^^^^^^^^^^^^^^^ this is the trait that is needed
+5 | fn foo(&self);
+6 | fn bar();
+ | --------- the associated function is available for `dep_2_reexport::Type` here
+ |
+ ::: multiple-dep-versions.rs:4:32
+ |
+4 | use dependency::{do_something, Trait};
+ | ----- `Trait` imported here doesn't correspond to the right version of crate `dependency`"#,
+ );
}
diff --git a/tests/run-make/dep-info-doesnt-run-much/Makefile b/tests/run-make/dep-info-doesnt-run-much/Makefile
deleted file mode 100644
index b4dc44a..0000000
--- a/tests/run-make/dep-info-doesnt-run-much/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
- $(RUSTC) foo.rs --emit dep-info
diff --git a/tests/run-make/dep-info-spaces/Makefile b/tests/run-make/dep-info-spaces/Makefile
deleted file mode 100644
index 0cfe513..0000000
--- a/tests/run-make/dep-info-spaces/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-include ../tools.mk
-
-# ignore-windows
-# ignore-freebsd
-# FIXME: (windows: see `../dep-info/Makefile`)
-
-all:
- cp lib.rs $(TMPDIR)/
- cp 'foo foo.rs' $(TMPDIR)/
- cp bar.rs $(TMPDIR)/
- $(RUSTC) --emit link,dep-info --crate-type=lib $(TMPDIR)/lib.rs
- sleep 1
- touch $(TMPDIR)/'foo foo.rs'
- -rm -f $(TMPDIR)/done
- $(MAKE) -drf Makefile.foo
- rm $(TMPDIR)/done
- pwd
- $(MAKE) -drf Makefile.foo
- rm $(TMPDIR)/done && exit 1 || exit 0
diff --git a/tests/run-make/dep-info-spaces/Makefile.foo b/tests/run-make/dep-info-spaces/Makefile.foo
deleted file mode 100644
index 80a5d43..0000000
--- a/tests/run-make/dep-info-spaces/Makefile.foo
+++ /dev/null
@@ -1,7 +0,0 @@
-LIB := $(shell $(RUSTC) --print file-names --crate-type=lib $(TMPDIR)/lib.rs)
-
-$(TMPDIR)/$(LIB):
- $(RUSTC) --emit link,dep-info --crate-type=lib $(TMPDIR)/lib.rs
- touch $(TMPDIR)/done
-
--include $(TMPDIR)/lib.d
diff --git a/tests/run-make/dep-info-spaces/bar.rs b/tests/run-make/dep-info-spaces/bar.rs
deleted file mode 100644
index c5c0bc6..0000000
--- a/tests/run-make/dep-info-spaces/bar.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub fn bar() {}
diff --git a/tests/run-make/dep-info/Makefile b/tests/run-make/dep-info/Makefile
deleted file mode 100644
index c76f43a..0000000
--- a/tests/run-make/dep-info/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-include ../tools.mk
-
-# ignore-windows
-# ignore-freebsd
-# FIXME: on windows `rustc --dep-info` produces Makefile dependency with
-# windows native paths (e.g. `c:\path\to\libfoo.a`)
-# but msys make seems to fail to recognize such paths, so test fails.
-
-all:
- cp *.rs $(TMPDIR)
- $(RUSTC) --emit dep-info,link --crate-type=lib $(TMPDIR)/lib.rs
- sleep 2
- touch $(TMPDIR)/foo.rs
- -rm -f $(TMPDIR)/done
- $(MAKE) -drf Makefile.foo
- sleep 2
- rm $(TMPDIR)/done
- pwd
- $(MAKE) -drf Makefile.foo
- rm $(TMPDIR)/done && exit 1 || exit 0
-
- # When a source file is deleted `make` should still work
- rm $(TMPDIR)/bar.rs
- cp $(TMPDIR)/lib2.rs $(TMPDIR)/lib.rs
- $(MAKE) -drf Makefile.foo
diff --git a/tests/run-make/dep-info/Makefile.foo b/tests/run-make/dep-info/Makefile.foo
deleted file mode 100644
index e5df31f..0000000
--- a/tests/run-make/dep-info/Makefile.foo
+++ /dev/null
@@ -1,7 +0,0 @@
-LIB := $(shell $(RUSTC) --print file-names --crate-type=lib lib.rs)
-
-$(TMPDIR)/$(LIB):
- $(RUSTC) --emit dep-info,link --crate-type=lib lib.rs
- touch $(TMPDIR)/done
-
--include $(TMPDIR)/foo.d
diff --git a/tests/run-make/dep-info-doesnt-run-much/foo.rs b/tests/run-make/dep-info/erroneous.rs
similarity index 100%
rename from tests/run-make/dep-info-doesnt-run-much/foo.rs
rename to tests/run-make/dep-info/erroneous.rs
diff --git a/tests/run-make/dep-info-spaces/foo foo.rs b/tests/run-make/dep-info/foo foo.rs
similarity index 100%
rename from tests/run-make/dep-info-spaces/foo foo.rs
rename to tests/run-make/dep-info/foo foo.rs
diff --git a/tests/run-make/dep-info-spaces/lib.rs b/tests/run-make/dep-info/lib_foofoo.rs
similarity index 100%
rename from tests/run-make/dep-info-spaces/lib.rs
rename to tests/run-make/dep-info/lib_foofoo.rs
diff --git a/tests/run-make/dep-info/rmake.rs b/tests/run-make/dep-info/rmake.rs
new file mode 100644
index 0000000..508569b
--- /dev/null
+++ b/tests/run-make/dep-info/rmake.rs
@@ -0,0 +1,37 @@
+// This is a simple smoke test for rustc's `--emit dep-info` feature. It prints out
+// information about dependencies in a Makefile-compatible format, as a `.d` file.
+// Note that this test does not check that the `.d` file is Makefile-compatible.
+
+// This test first checks that emitting dep-info disables static analysis, preventing
+// compilation of `erroneous.rs` from causing a compilation failure.
+// Then, it checks that compilation using the flag is successful in general, even with
+// empty source files or source files that contain a whitespace character.
+
+// Finally, it removes one dependency and checks that compilation is still successful.
+// See https://github.com/rust-lang/rust/pull/10698
+
+use run_make_support::{rfs, rustc};
+
+fn main() {
+ // We're only emitting dep info, so we shouldn't be running static analysis to
+ // figure out that this program is erroneous.
+ rustc().input("erroneous.rs").emit("dep-info").run();
+
+ rustc().input("lib.rs").emit("dep-info,link").crate_type("lib").run();
+ rfs::remove_file("foo.rs");
+ rfs::create_file("foo.rs");
+ // Compilation should succeed even if `foo.rs` is empty.
+ rustc().input("lib.rs").emit("dep-info,link").crate_type("lib").run();
+
+ // Again, with a space in the filename this time around.
+ rustc().input("lib_foofoo.rs").emit("dep-info,link").crate_type("lib").run();
+ rfs::remove_file("foo foo.rs");
+ rfs::create_file("foo foo.rs");
+ // Compilation should succeed even if `foo foo.rs` is empty.
+ rustc().input("lib_foofoo.rs").emit("dep-info,link").crate_type("lib").run();
+
+ // When a source file is deleted, compilation should still succeed if the library
+ // also loses this source file dependency.
+ rfs::remove_file("bar.rs");
+ rustc().input("lib2.rs").emit("dep-info,link").crate_type("lib").run();
+}
diff --git a/tests/run-make/deref-impl-rustdoc-ice/rmake.rs b/tests/run-make/deref-impl-rustdoc-ice/rmake.rs
index 91fc0a9..0ad5934 100644
--- a/tests/run-make/deref-impl-rustdoc-ice/rmake.rs
+++ b/tests/run-make/deref-impl-rustdoc-ice/rmake.rs
@@ -12,5 +12,5 @@
fn main() {
rustc().input("foo.rs").run();
rustc().input("bar.rs").run();
- rustdoc().input("baz.rs").library_search_path(cwd()).output(cwd()).run();
+ rustdoc().input("baz.rs").library_search_path(cwd()).out_dir(cwd()).run();
}
diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs
index 8ac9073..e5482af 100644
--- a/tests/run-make/emit-shared-files/rmake.rs
+++ b/tests/run-make/emit-shared-files/rmake.rs
@@ -13,7 +13,7 @@ fn main() {
rustdoc()
.arg("-Zunstable-options")
.arg("--emit=invocation-specific")
- .output("invocation-only")
+ .out_dir("invocation-only")
.arg("--resource-suffix=-xxx")
.args(&["--theme", "y.css"])
.args(&["--extend-css", "z.css"])
@@ -34,7 +34,7 @@ fn main() {
rustdoc()
.arg("-Zunstable-options")
.arg("--emit=toolchain-shared-resources")
- .output("toolchain-only")
+ .out_dir("toolchain-only")
.arg("--resource-suffix=-xxx")
.args(&["--extend-css", "z.css"])
.input("x.rs")
@@ -68,7 +68,7 @@ fn main() {
rustdoc()
.arg("-Zunstable-options")
.arg("--emit=toolchain-shared-resources,unversioned-shared-resources")
- .output("all-shared")
+ .out_dir("all-shared")
.arg("--resource-suffix=-xxx")
.args(&["--extend-css", "z.css"])
.input("x.rs")
diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs
index f290554..d3dcc04 100644
--- a/tests/run-make/exit-code/rmake.rs
+++ b/tests/run-make/exit-code/rmake.rs
@@ -16,7 +16,7 @@ fn main() {
.run_fail()
.assert_exit_code(101);
- rustdoc().arg("success.rs").output("exit-code").run();
+ rustdoc().arg("success.rs").out_dir("exit-code").run();
rustdoc().arg("--invalid-arg-foo").run_fail().assert_exit_code(1);
diff --git a/tests/run-make/libtest-json/Makefile b/tests/run-make/libtest-json/Makefile
deleted file mode 100644
index c8bc7b5..0000000
--- a/tests/run-make/libtest-json/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# ignore-cross-compile
-# needs-unwind
-include ../tools.mk
-
-# Test expected libtest's JSON output
-
-OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-json-output-default.json
-OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-json-output-stdout-success.json
-
-all: f.rs validate_json.py output-default.json output-stdout-success.json
- $(RUSTC) --test f.rs
- RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json > $(OUTPUT_FILE_DEFAULT) || true
- RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=json --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true
-
- cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_json.py
- cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_json.py
-
- # Normalize the actual output and compare to expected output file
- cat $(OUTPUT_FILE_DEFAULT) | sed 's/"exec_time": [0-9.]*/"exec_time": $$TIME/' | diff output-default.json -
- cat $(OUTPUT_FILE_STDOUT_SUCCESS) | sed 's/"exec_time": [0-9.]*/"exec_time": $$TIME/' | diff output-stdout-success.json -
diff --git a/tests/run-make/libtest-json/output-default.json b/tests/run-make/libtest-json/output-default.json
index 01710f5..a2293a0 100644
--- a/tests/run-make/libtest-json/output-default.json
+++ b/tests/run-make/libtest-json/output-default.json
@@ -7,4 +7,4 @@
{ "type": "test", "name": "c", "event": "ok" }
{ "type": "test", "event": "started", "name": "d" }
{ "type": "test", "name": "d", "event": "ignored", "message": "msg" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": "$EXEC_TIME" }
diff --git a/tests/run-make/libtest-json/output-stdout-success.json b/tests/run-make/libtest-json/output-stdout-success.json
index 878eb6c..cf92f01 100644
--- a/tests/run-make/libtest-json/output-stdout-success.json
+++ b/tests/run-make/libtest-json/output-stdout-success.json
@@ -7,4 +7,4 @@
{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'c' panicked at f.rs:15:5:\nassertion failed: false\n" }
{ "type": "test", "event": "started", "name": "d" }
{ "type": "test", "name": "d", "event": "ignored", "message": "msg" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": "$EXEC_TIME" }
diff --git a/tests/run-make/libtest-json/rmake.rs b/tests/run-make/libtest-json/rmake.rs
new file mode 100644
index 0000000..acbd88d
--- /dev/null
+++ b/tests/run-make/libtest-json/rmake.rs
@@ -0,0 +1,31 @@
+// Check libtest's JSON output against snapshots.
+
+//@ ignore-cross-compile
+//@ needs-unwind (test file contains #[should_panic] test)
+
+use run_make_support::{cmd, diff, python_command, rustc};
+
+fn main() {
+ rustc().arg("--test").input("f.rs").run();
+
+ run_tests(&[], "output-default.json");
+ run_tests(&["--show-output"], "output-stdout-success.json");
+}
+
+#[track_caller]
+fn run_tests(extra_args: &[&str], expected_file: &str) {
+ let cmd_out = cmd("./f")
+ .env("RUST_BACKTRACE", "0")
+ .args(&["-Zunstable-options", "--test-threads=1", "--format=json"])
+ .args(extra_args)
+ .run_fail();
+ let test_stdout = &cmd_out.stdout_utf8();
+
+ python_command().arg("validate_json.py").stdin(test_stdout).run();
+
+ diff()
+ .expected_file(expected_file)
+ .actual_text("stdout", test_stdout)
+ .normalize(r#"(?<prefix>"exec_time": )[0-9.]+"#, r#"${prefix}"$$EXEC_TIME""#)
+ .run();
+}
diff --git a/tests/run-make/libtest-junit/Makefile b/tests/run-make/libtest-junit/Makefile
deleted file mode 100644
index 26e5624..0000000
--- a/tests/run-make/libtest-junit/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# ignore-cross-compile
-# needs-unwind contains should_panic test
-include ../tools.mk
-
-# Test expected libtest's junit output
-
-OUTPUT_FILE_DEFAULT := $(TMPDIR)/libtest-junit-output-default.xml
-OUTPUT_FILE_STDOUT_SUCCESS := $(TMPDIR)/libtest-junit-output-stdout-success.xml
-
-all: f.rs validate_junit.py output-default.xml output-stdout-success.xml
- $(RUSTC) --test f.rs
- RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=junit > $(OUTPUT_FILE_DEFAULT) || true
- RUST_BACKTRACE=0 $(call RUN,f) -Z unstable-options --test-threads=1 --format=junit --show-output > $(OUTPUT_FILE_STDOUT_SUCCESS) || true
-
- cat $(OUTPUT_FILE_DEFAULT) | "$(PYTHON)" validate_junit.py
- cat $(OUTPUT_FILE_STDOUT_SUCCESS) | "$(PYTHON)" validate_junit.py
-
- # Normalize the actual output and compare to expected output file
- cat $(OUTPUT_FILE_DEFAULT) | sed 's/time="[0-9.]*"/time="$$TIME"/g' | diff output-default.xml -
- cat $(OUTPUT_FILE_STDOUT_SUCCESS) | sed 's/time="[0-9.]*"/time="$$TIME"/g' | diff output-stdout-success.xml -
diff --git a/tests/run-make/libtest-junit/rmake.rs b/tests/run-make/libtest-junit/rmake.rs
new file mode 100644
index 0000000..d631313
--- /dev/null
+++ b/tests/run-make/libtest-junit/rmake.rs
@@ -0,0 +1,31 @@
+// Check libtest's JUnit (XML) output against snapshots.
+
+//@ ignore-cross-compile
+//@ needs-unwind (test file contains #[should_panic] test)
+
+use run_make_support::{cmd, diff, python_command, rustc};
+
+fn main() {
+ rustc().arg("--test").input("f.rs").run();
+
+ run_tests(&[], "output-default.xml");
+ run_tests(&["--show-output"], "output-stdout-success.xml");
+}
+
+#[track_caller]
+fn run_tests(extra_args: &[&str], expected_file: &str) {
+ let cmd_out = cmd("./f")
+ .env("RUST_BACKTRACE", "0")
+ .args(&["-Zunstable-options", "--test-threads=1", "--format=junit"])
+ .args(extra_args)
+ .run_fail();
+ let test_stdout = &cmd_out.stdout_utf8();
+
+ python_command().arg("validate_junit.py").stdin(test_stdout).run();
+
+ diff()
+ .expected_file(expected_file)
+ .actual_text("stdout", test_stdout)
+ .normalize(r#"\btime="[0-9.]+""#, r#"time="$$TIME""#)
+ .run();
+}
diff --git a/tests/run-make/native-link-modifier-bundle/Makefile b/tests/run-make/native-link-modifier-bundle/Makefile
deleted file mode 100644
index 5277209..0000000
--- a/tests/run-make/native-link-modifier-bundle/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-# ignore-cross-compile
-# ignore-windows-msvc
-
-include ../tools.mk
-
-# We're using the llvm-nm instead of the system nm to ensure it is compatible
-# with the LLVM bitcode generated by rustc.
-# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
-ifndef IS_WINDOWS
-NM = "$(LLVM_BIN_DIR)"/llvm-nm
-else
-NM = nm
-endif
-
-all: $(call NATIVE_STATICLIB,native-staticlib)
- # Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
- $(RUSTC) bundled.rs --crate-type=staticlib --crate-type=rlib
- $(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "T _*native_func"
- $(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "U _*native_func"
- $(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "T _*native_func"
- $(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "U _*native_func"
-
- # Build a staticlib and a rlib, the `native_func` symbol will not be bundled into it
- $(RUSTC) non-bundled.rs --crate-type=staticlib --crate-type=rlib
- $(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -ve "T _*native_func"
- $(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -e "U _*native_func"
- $(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -ve "T _*native_func"
- $(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -e "U _*native_func"
-
- # Build a cdylib, `native-staticlib` will not appear on the linker line because it was bundled previously
- # The cdylib will contain the `native_func` symbol in the end
- $(RUSTC) cdylib-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -ve '-l[" ]*native-staticlib'
- $(NM) $(call DYLIB,cdylib_bundled) | $(CGREP) -e "[Tt] _*native_func"
-
- # Build a cdylib, `native-staticlib` will appear on the linker line because it was not bundled previously
- # The cdylib will contain the `native_func` symbol in the end
- $(RUSTC) cdylib-non-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -e '-l[" ]*native-staticlib'
- $(NM) $(call DYLIB,cdylib_non_bundled) | $(CGREP) -e "[Tt] _*native_func"
diff --git a/tests/run-make/native-link-modifier-bundle/rmake.rs b/tests/run-make/native-link-modifier-bundle/rmake.rs
new file mode 100644
index 0000000..058b66b
--- /dev/null
+++ b/tests/run-make/native-link-modifier-bundle/rmake.rs
@@ -0,0 +1,90 @@
+// This test exercises the `bundle` link argument, which can be turned on or off.
+
+// When building a rlib or staticlib, +bundle means that all object files from the native static
+// library will be added to the rlib or staticlib archive, and then used from it during linking of
+// the final binary.
+
+// When building a rlib -bundle means that the native static library is registered as a dependency
+// of that rlib "by name", and object files from it are included only during linking of the final
+// binary, the file search by that name is also performed during final linking.
+// When building a staticlib -bundle means that the native static library is simply not included
+// into the archive and some higher level build system will need to add it later during linking of
+// the final binary.
+
+// This modifier has no effect when building other targets like executables or dynamic libraries.
+
+// The default for this modifier is +bundle.
+// See https://github.com/rust-lang/rust/pull/95818
+
+//@ ignore-cross-compile
+// Reason: cross-compilation fails to export native symbols
+
+use run_make_support::{
+ build_native_static_lib, dynamic_lib_name, is_msvc, llvm_nm, rust_lib_name, rustc,
+ static_lib_name,
+};
+
+fn main() {
+ build_native_static_lib("native-staticlib");
+ // Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
+ rustc().input("bundled.rs").crate_type("staticlib").crate_type("rlib").run();
+ llvm_nm()
+ .input(static_lib_name("bundled"))
+ .run()
+ .assert_stdout_contains_regex("T _*native_func");
+ llvm_nm()
+ .input(static_lib_name("bundled"))
+ .run()
+ .assert_stdout_contains_regex("U _*native_func");
+ llvm_nm().input(rust_lib_name("bundled")).run().assert_stdout_contains_regex("T _*native_func");
+ llvm_nm().input(rust_lib_name("bundled")).run().assert_stdout_contains_regex("U _*native_func");
+
+ // Build a staticlib and a rlib, the `native_func` symbol will not be bundled into it
+ build_native_static_lib("native-staticlib");
+ rustc().input("non-bundled.rs").crate_type("staticlib").crate_type("rlib").run();
+ llvm_nm()
+ .input(static_lib_name("non_bundled"))
+ .run()
+ .assert_stdout_not_contains_regex("T _*native_func");
+ llvm_nm()
+ .input(static_lib_name("non_bundled"))
+ .run()
+ .assert_stdout_contains_regex("U _*native_func");
+ llvm_nm()
+ .input(rust_lib_name("non_bundled"))
+ .run()
+ .assert_stdout_not_contains_regex("T _*native_func");
+ llvm_nm()
+ .input(rust_lib_name("non_bundled"))
+ .run()
+ .assert_stdout_contains_regex("U _*native_func");
+
+ // This part of the test does not function on Windows MSVC - no symbols are printed.
+ if !is_msvc() {
+ // Build a cdylib, `native-staticlib` will not appear on the linker line because it was
+ // bundled previously. The cdylib will contain the `native_func` symbol in the end.
+ rustc()
+ .input("cdylib-bundled.rs")
+ .crate_type("cdylib")
+ .print("link-args")
+ .run()
+ .assert_stdout_not_contains(r#"-l[" ]*native-staticlib"#);
+ llvm_nm()
+ .input(dynamic_lib_name("cdylib_bundled"))
+ .run()
+ .assert_stdout_contains_regex("[Tt] _*native_func");
+
+ // Build a cdylib, `native-staticlib` will appear on the linker line because it was not
+ // bundled previously. The cdylib will contain the `native_func` symbol in the end
+ rustc()
+ .input("cdylib-non-bundled.rs")
+ .crate_type("cdylib")
+ .print("link-args")
+ .run()
+ .assert_stdout_contains_regex(r#"-l[" ]*native-staticlib"#);
+ llvm_nm()
+ .input(dynamic_lib_name("cdylib_non_bundled"))
+ .run()
+ .assert_stdout_contains_regex("[Tt] _*native_func");
+ }
+}
diff --git a/tests/run-make/reproducible-build/Makefile b/tests/run-make/reproducible-build/Makefile
deleted file mode 100644
index f5d17a2..0000000
--- a/tests/run-make/reproducible-build/Makefile
+++ /dev/null
@@ -1,140 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# ignore-musl
-# Objects are reproducible but their path is not.
-
-all: \
- smoke \
- debug \
- opt \
- link_paths \
- remap_paths \
- different_source_dirs_rlib \
- remap_cwd_rlib \
- remap_cwd_to_empty \
- extern_flags
-
-# TODO: Builds of `bin` crate types are not deterministic with debuginfo=2 on
-# Windows.
-# See: https://github.com/rust-lang/rust/pull/87320#issuecomment-920105533
-# Issue: https://github.com/rust-lang/rust/issues/88982
-#
-# different_source_dirs_bin \
-# remap_cwd_bin \
-
-smoke:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) linker.rs -O
- $(RUSTC) reproducible-build-aux.rs
- $(RUSTC) reproducible-build.rs -C linker=$(call RUN_BINFILE,linker)
- $(RUSTC) reproducible-build.rs -C linker=$(call RUN_BINFILE,linker)
- diff -u "$(TMPDIR)/linker-arguments1" "$(TMPDIR)/linker-arguments2"
-
-debug:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) linker.rs -O
- $(RUSTC) reproducible-build-aux.rs -g
- $(RUSTC) reproducible-build.rs -C linker=$(call RUN_BINFILE,linker) -g
- $(RUSTC) reproducible-build.rs -C linker=$(call RUN_BINFILE,linker) -g
- diff -u "$(TMPDIR)/linker-arguments1" "$(TMPDIR)/linker-arguments2"
-
-opt:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) linker.rs -O
- $(RUSTC) reproducible-build-aux.rs -O
- $(RUSTC) reproducible-build.rs -C linker=$(call RUN_BINFILE,linker) -O
- $(RUSTC) reproducible-build.rs -C linker=$(call RUN_BINFILE,linker) -O
- diff -u "$(TMPDIR)/linker-arguments1" "$(TMPDIR)/linker-arguments2"
-
-link_paths:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- $(RUSTC) reproducible-build.rs --crate-type rlib -L /b
- cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib
- $(RUSTC) reproducible-build.rs --crate-type rlib -L /a
- cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1
-
-remap_paths:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- $(RUSTC) reproducible-build.rs --crate-type rlib --remap-path-prefix=/a=/c
- cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib
- $(RUSTC) reproducible-build.rs --crate-type rlib --remap-path-prefix=/b=/c
- cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1
-
-different_source_dirs_bin:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- mkdir $(TMPDIR)/test
- cp reproducible-build.rs $(TMPDIR)/test
- $(RUSTC) reproducible-build.rs --crate-type bin --remap-path-prefix=$$PWD=/b
- cp $(TMPDIR)/reproducible-build $(TMPDIR)/foo
- (cd $(TMPDIR)/test && $(RUSTC) reproducible-build.rs \
- --remap-path-prefix=$(TMPDIR)/test=/b \
- --crate-type bin)
- cmp "$(TMPDIR)/reproducible-build" "$(TMPDIR)/foo" || exit 1
-
-different_source_dirs_rlib:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- mkdir $(TMPDIR)/test
- cp reproducible-build.rs $(TMPDIR)/test
- $(RUSTC) reproducible-build.rs --crate-type rlib --remap-path-prefix=$$PWD=/b
- cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib
- (cd $(TMPDIR)/test && $(RUSTC) reproducible-build.rs \
- --remap-path-prefix=$(TMPDIR)/test=/b \
- --crate-type rlib)
- cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1
-
-remap_cwd_bin:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- mkdir $(TMPDIR)/test
- cp reproducible-build.rs $(TMPDIR)/test
- $(RUSTC) reproducible-build.rs --crate-type bin -C debuginfo=2 \
- -Z remap-cwd-prefix=.
- cp $(TMPDIR)/reproducible-build $(TMPDIR)/first
- (cd $(TMPDIR)/test && \
- $(RUSTC) reproducible-build.rs --crate-type bin -C debuginfo=2 \
- -Z remap-cwd-prefix=.)
- cmp "$(TMPDIR)/first" "$(TMPDIR)/reproducible-build" || exit 1
-
-remap_cwd_rlib:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- mkdir $(TMPDIR)/test
- cp reproducible-build.rs $(TMPDIR)/test
- $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \
- -Z remap-cwd-prefix=.
- cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfirst.rlib
- (cd $(TMPDIR)/test && \
- $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \
- -Z remap-cwd-prefix=.)
- cmp "$(TMPDIR)/libfirst.rlib" "$(TMPDIR)/libreproducible_build.rlib" || exit 1
-
-remap_cwd_to_empty:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- mkdir $(TMPDIR)/test
- cp reproducible-build.rs $(TMPDIR)/test
- $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \
- -Z remap-cwd-prefix=
- cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfirst.rlib
- (cd $(TMPDIR)/test && \
- $(RUSTC) reproducible-build.rs --crate-type rlib -C debuginfo=2 \
- -Z remap-cwd-prefix=)
- cmp "$(TMPDIR)/libfirst.rlib" "$(TMPDIR)/libreproducible_build.rlib" || exit 1
-
-extern_flags:
- rm -rf $(TMPDIR) && mkdir $(TMPDIR)
- $(RUSTC) reproducible-build-aux.rs
- $(RUSTC) reproducible-build.rs \
- --extern reproducible_build_aux=$(TMPDIR)/libreproducible_build_aux.rlib \
- --crate-type rlib
- cp $(TMPDIR)/libreproducible_build_aux.rlib $(TMPDIR)/libbar.rlib
- cp $(TMPDIR)/libreproducible_build.rlib $(TMPDIR)/libfoo.rlib
- $(RUSTC) reproducible-build.rs \
- --extern reproducible_build_aux=$(TMPDIR)/libbar.rlib \
- --crate-type rlib
- cmp "$(TMPDIR)/libreproducible_build.rlib" "$(TMPDIR)/libfoo.rlib" || exit 1
diff --git a/tests/run-make/reproducible-build/rmake.rs b/tests/run-make/reproducible-build/rmake.rs
new file mode 100644
index 0000000..34410d2
--- /dev/null
+++ b/tests/run-make/reproducible-build/rmake.rs
@@ -0,0 +1,240 @@
+// This test case makes sure that two identical invocations of the compiler
+// (i.e. same code base, same compile-flags, same compiler-versions, etc.)
+// produce the same output. In the past, symbol names of monomorphized functions
+// were not deterministic (which we want to avoid).
+//
+// The test tries to exercise as many different paths into symbol name
+// generation as possible:
+//
+// - regular functions
+// - generic functions
+// - methods
+// - statics
+// - closures
+// - enum variant constructors
+// - tuple struct constructors
+// - drop glue
+// - FnOnce adapters
+// - Trait object shims
+// - Fn Pointer shims
+// See https://github.com/rust-lang/rust/pull/32293
+// Tracking Issue: https://github.com/rust-lang/rust/issues/129080
+
+use run_make_support::{
+ bin_name, cwd, diff, is_darwin, is_windows, rfs, run_in_tmpdir, rust_lib_name, rustc,
+};
+
+fn main() {
+ // Smoke tests. Simple flags, build should be reproducible.
+ eprintln!("smoke_test => None");
+ smoke_test(None);
+ eprintln!("smoke_test => SmokeFlag::Debug");
+ smoke_test(Some(SmokeFlag::Debug));
+ eprintln!("smoke_test => SmokeFlag::Opt");
+ smoke_test(Some(SmokeFlag::Opt));
+
+ // Builds should be reproducible even through custom library search paths
+ // or remap path prefixes.
+ eprintln!("paths_test => PathsFlag::Link");
+ paths_test(PathsFlag::Link);
+ eprintln!("paths_test => PathsFlag::Remap");
+ paths_test(PathsFlag::Remap);
+
+ // Builds should be reproducible even if each build is done in a different directory,
+ // with both --remap-path-prefix and -Z remap-cwd-prefix.
+
+ // FIXME(Oneirical): Building with crate type set to `bin` AND having -Cdebuginfo=2
+ // (or `-g`, the shorthand form) enabled will cause reproducibility failures.
+ // See https://github.com/rust-lang/rust/issues/89911
+
+ if !is_darwin() && !is_windows() {
+ // FIXME(Oneirical): Bin builds are not reproducible on non-Linux targets.
+ eprintln!("diff_dir_test => Bin, Path");
+ diff_dir_test(CrateType::Bin, RemapType::Path);
+ }
+
+ eprintln!("diff_dir_test => Rlib, Path");
+ diff_dir_test(CrateType::Rlib, RemapType::Path);
+
+ // FIXME(Oneirical): This specific case would fail on Linux, should -Cdebuginfo=2
+ // be added.
+ // FIXME(Oneirical): Bin builds are not reproducible on non-Linux targets.
+ // See https://github.com/rust-lang/rust/issues/89911
+ if !is_darwin() && !is_windows() {
+ eprintln!("diff_dir_test => Bin, Cwd false");
+ diff_dir_test(CrateType::Bin, RemapType::Cwd { is_empty: false });
+ }
+
+ eprintln!("diff_dir_test => Rlib, Cwd false");
+ diff_dir_test(CrateType::Rlib, RemapType::Cwd { is_empty: false });
+ eprintln!("diff_dir_test => Rlib, Cwd true");
+ diff_dir_test(CrateType::Rlib, RemapType::Cwd { is_empty: true });
+
+ eprintln!("final extern test");
+ // Builds should be reproducible when using the --extern flag.
+ run_in_tmpdir(|| {
+ rustc().input("reproducible-build-aux.rs").run();
+ rustc()
+ .input("reproducible-build.rs")
+ .crate_type("rlib")
+ .extern_("reproducible_build_aux", rust_lib_name("reproducible_build_aux"))
+ .run();
+ rfs::copy(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
+ rfs::copy(rust_lib_name("reproducible_build_aux"), rust_lib_name("bar"));
+ rustc()
+ .input("reproducible-build.rs")
+ .crate_type("rlib")
+ .extern_("reproducible_build_aux", rust_lib_name("bar"))
+ .run();
+ assert!(rfs::read(rust_lib_name("foo")) == rfs::read(rust_lib_name("reproducible_build")))
+ });
+}
+
+#[track_caller]
+fn smoke_test(flag: Option<SmokeFlag>) {
+ run_in_tmpdir(|| {
+ rustc().input("linker.rs").opt().run();
+ rustc().input("reproducible-build-aux.rs").run();
+ let mut compiler1 = rustc();
+ let mut compiler2 = rustc();
+ if let Some(flag) = flag {
+ match flag {
+ SmokeFlag::Debug => {
+ compiler1.arg("-g");
+ compiler2.arg("-g");
+ }
+ SmokeFlag::Opt => {
+ compiler1.opt();
+ compiler2.opt();
+ }
+ };
+ };
+ compiler1
+ .input("reproducible-build.rs")
+ .linker(&cwd().join(bin_name("linker")).display().to_string())
+ .run();
+ compiler2
+ .input("reproducible-build.rs")
+ .linker(&cwd().join(bin_name("linker")).display().to_string())
+ .run();
+ diff().actual_file("linker-arguments1").expected_file("linker-arguments2").run();
+ });
+}
+
+#[track_caller]
+fn paths_test(flag: PathsFlag) {
+ run_in_tmpdir(|| {
+ rustc().input("reproducible-build-aux.rs").run();
+ let mut compiler1 = rustc();
+ let mut compiler2 = rustc();
+ match flag {
+ PathsFlag::Link => {
+ compiler1.library_search_path("a");
+ compiler2.library_search_path("b");
+ }
+ PathsFlag::Remap => {
+ compiler1.arg("--remap-path-prefix=/a=/c");
+ compiler2.arg("--remap-path-prefix=/b=/c");
+ }
+ }
+ compiler1.input("reproducible-build.rs").crate_type("rlib").run();
+ rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
+ compiler2.input("reproducible-build.rs").crate_type("rlib").run();
+ assert!(rfs::read(rust_lib_name("foo")) == rfs::read(rust_lib_name("reproducible_build")))
+ });
+}
+
+#[track_caller]
+fn diff_dir_test(crate_type: CrateType, remap_type: RemapType) {
+ run_in_tmpdir(|| {
+ let base_dir = cwd();
+ rustc().input("reproducible-build-aux.rs").run();
+ rfs::create_dir("test");
+ rfs::copy("reproducible-build.rs", "test/reproducible-build.rs");
+ let mut compiler1 = rustc();
+ let mut compiler2 = rustc();
+ match crate_type {
+ CrateType::Bin => {
+ compiler1.crate_type("bin");
+ compiler2.crate_type("bin");
+ }
+ CrateType::Rlib => {
+ compiler1.crate_type("rlib");
+ compiler2.crate_type("rlib");
+ }
+ }
+ match remap_type {
+ RemapType::Path => {
+ compiler1.arg(&format!("--remap-path-prefix={}=/b", cwd().display()));
+ compiler2
+ .arg(format!("--remap-path-prefix={}=/b", base_dir.join("test").display()));
+ }
+ RemapType::Cwd { is_empty } => {
+ // FIXME(Oneirical): Building with crate type set to `bin` AND having -Cdebuginfo=2
+ // (or `-g`, the shorthand form) enabled will cause reproducibility failures
+ // for multiple platforms.
+ // See https://github.com/rust-lang/rust/issues/89911
+ // FIXME(#129117): Windows rlib + `-Cdebuginfo=2` + `-Z remap-cwd-prefix=.` seems
+ // to be unreproducible.
+ if !matches!(crate_type, CrateType::Bin) && !is_windows() {
+ compiler1.arg("-Cdebuginfo=2");
+ compiler2.arg("-Cdebuginfo=2");
+ }
+ if is_empty {
+ compiler1.arg("-Zremap-cwd-prefix=");
+ compiler2.arg("-Zremap-cwd-prefix=");
+ } else {
+ compiler1.arg("-Zremap-cwd-prefix=.");
+ compiler2.arg("-Zremap-cwd-prefix=.");
+ }
+ }
+ }
+ compiler1.input("reproducible-build.rs").run();
+ match crate_type {
+ CrateType::Bin => {
+ rfs::rename(bin_name("reproducible-build"), bin_name("foo"));
+ }
+ CrateType::Rlib => {
+ rfs::rename(rust_lib_name("reproducible_build"), rust_lib_name("foo"));
+ }
+ }
+ std::env::set_current_dir("test").unwrap();
+ compiler2
+ .input("reproducible-build.rs")
+ .library_search_path(&base_dir)
+ .out_dir(&base_dir)
+ .run();
+ std::env::set_current_dir(&base_dir).unwrap();
+ match crate_type {
+ CrateType::Bin => {
+ assert!(rfs::read(bin_name("reproducible-build")) == rfs::read(bin_name("foo")));
+ }
+ CrateType::Rlib => {
+ assert!(
+ rfs::read(rust_lib_name("foo"))
+ == rfs::read(rust_lib_name("reproducible_build"))
+ );
+ }
+ }
+ });
+}
+
+enum SmokeFlag {
+ Debug,
+ Opt,
+}
+
+enum PathsFlag {
+ Link,
+ Remap,
+}
+
+enum CrateType {
+ Bin,
+ Rlib,
+}
+
+enum RemapType {
+ Path,
+ Cwd { is_empty: bool },
+}
diff --git a/tests/run-make/rlib-format-packed-bundled-libs/Makefile b/tests/run-make/rlib-format-packed-bundled-libs/Makefile
deleted file mode 100644
index f454da6..0000000
--- a/tests/run-make/rlib-format-packed-bundled-libs/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-include ../tools.mk
-
-# ignore-cross-compile
-
-# Make sure rlib format with -Zpacked_bundled_libs is correct.
-
-# We're using the llvm-nm instead of the system nm to ensure it is compatible
-# with the LLVM bitcode generated by rustc.
-# Except on Windows where piping/IO redirection under MSYS2 is wonky with llvm-nm.
-ifndef IS_WINDOWS
-NM = "$(LLVM_BIN_DIR)"/llvm-nm
-else
-NM = nm
-endif
-
-all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3)
- $(RUSTC) rust_dep_up.rs --crate-type=rlib -Zpacked_bundled_libs
- $(NM) $(TMPDIR)/librust_dep_up.rlib | $(CGREP) -e "U.*native_f2"
- $(NM) $(TMPDIR)/librust_dep_up.rlib | $(CGREP) -e "U.*native_f3"
- $(NM) $(TMPDIR)/librust_dep_up.rlib | $(CGREP) -e "T.*rust_dep_up"
- $(AR) t $(TMPDIR)/librust_dep_up.rlib | $(CGREP) "native_dep_2"
- $(AR) t $(TMPDIR)/librust_dep_up.rlib | $(CGREP) "native_dep_3"
- $(RUSTC) rust_dep_local.rs --extern rlib=$(TMPDIR)/librust_dep_up.rlib -Zpacked_bundled_libs --crate-type=rlib
- $(NM) $(TMPDIR)/librust_dep_local.rlib | $(CGREP) -e "U.*native_f1"
- $(NM) $(TMPDIR)/librust_dep_local.rlib | $(CGREP) -e "T.*rust_dep_local"
- $(AR) t $(TMPDIR)/librust_dep_local.rlib | $(CGREP) "native_dep_1"
-
- # Make sure compiler doesn't use files, that it shouldn't know about.
- rm $(TMPDIR)/*native_dep_*
-
- $(RUSTC) main.rs --extern lib=$(TMPDIR)/librust_dep_local.rlib -o $(TMPDIR)/main.exe -Zpacked_bundled_libs --print link-args | $(CGREP) -e "native_dep_1.*native_dep_2.*native_dep_3"
-
-ifndef IS_MSVC
- $(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*native_f1"
- $(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*native_f2"
- $(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*native_f3"
- $(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*rust_dep_local"
- $(NM) $(TMPDIR)/main.exe | $(CGREP) -e "T.*rust_dep_up"
-endif
diff --git a/tests/run-make/rlib-format-packed-bundled-libs/rmake.rs b/tests/run-make/rlib-format-packed-bundled-libs/rmake.rs
new file mode 100644
index 0000000..ff0438a
--- /dev/null
+++ b/tests/run-make/rlib-format-packed-bundled-libs/rmake.rs
@@ -0,0 +1,84 @@
+// `-Z packed_bundled_libs` is an unstable rustc flag that makes the compiler
+// only require a native library and no supplementary object files to compile.
+// Output files compiled with this flag should still contain all expected symbols -
+// that is what this test checks.
+// See https://github.com/rust-lang/rust/pull/100101
+
+//@ ignore-cross-compile
+// Reason: cross-compilation fails to export native symbols
+
+use run_make_support::{
+ bin_name, build_native_static_lib, cwd, filename_contains, is_msvc, llvm_ar, llvm_nm, rfs,
+ rust_lib_name, rustc, shallow_find_files,
+};
+
+fn main() {
+ build_native_static_lib("native_dep_1");
+ build_native_static_lib("native_dep_2");
+ build_native_static_lib("native_dep_3");
+ rustc().input("rust_dep_up.rs").crate_type("rlib").arg("-Zpacked_bundled_libs").run();
+ llvm_nm()
+ .input(rust_lib_name("rust_dep_up"))
+ .run()
+ .assert_stdout_contains_regex("U.*native_f2");
+ llvm_nm()
+ .input(rust_lib_name("rust_dep_up"))
+ .run()
+ .assert_stdout_contains_regex("U.*native_f3");
+ llvm_nm()
+ .input(rust_lib_name("rust_dep_up"))
+ .run()
+ .assert_stdout_contains_regex("T.*rust_dep_up");
+ llvm_ar()
+ .table_of_contents()
+ .arg(rust_lib_name("rust_dep_up"))
+ .run()
+ .assert_stdout_contains("native_dep_2");
+ llvm_ar()
+ .table_of_contents()
+ .arg(rust_lib_name("rust_dep_up"))
+ .run()
+ .assert_stdout_contains("native_dep_3");
+ rustc()
+ .input("rust_dep_local.rs")
+ .extern_("rlib", rust_lib_name("rust_dep_up"))
+ .arg("-Zpacked_bundled_libs")
+ .crate_type("rlib")
+ .run();
+ llvm_nm()
+ .input(rust_lib_name("rust_dep_local"))
+ .run()
+ .assert_stdout_contains_regex("U.*native_f1");
+ llvm_nm()
+ .input(rust_lib_name("rust_dep_local"))
+ .run()
+ .assert_stdout_contains_regex("T.*rust_dep_local");
+ llvm_ar()
+ .table_of_contents()
+ .arg(rust_lib_name("rust_dep_local"))
+ .run()
+ .assert_stdout_contains("native_dep_1");
+
+ // Ensure the compiler will not use files it should not know about.
+ for file in shallow_find_files(cwd(), |path| filename_contains(path, "native_dep_")) {
+ rfs::remove_file(file);
+ }
+
+ rustc()
+ .input("main.rs")
+ .extern_("lib", rust_lib_name("rust_dep_local"))
+ .output(bin_name("main"))
+ .arg("-Zpacked_bundled_libs")
+ .print("link-args")
+ .run()
+ .assert_stdout_contains_regex("native_dep_1.*native_dep_2.*native_dep_3");
+
+ // The binary "main" will not contain any symbols on MSVC.
+ if !is_msvc() {
+ llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*native_f1");
+ llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*native_f2");
+ llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*native_f3");
+ llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*rust_dep_local");
+ llvm_nm().input(bin_name("main")).run().assert_stdout_contains_regex("T.*rust_dep_up");
+ }
+}
diff --git a/tests/run-make/rustdoc-determinism/rmake.rs b/tests/run-make/rustdoc-determinism/rmake.rs
index aa80901..ce08850 100644
--- a/tests/run-make/rustdoc-determinism/rmake.rs
+++ b/tests/run-make/rustdoc-determinism/rmake.rs
@@ -7,12 +7,12 @@
fn main() {
let foo_first = Path::new("foo_first");
- rustdoc().input("foo.rs").output(&foo_first).run();
- rustdoc().input("bar.rs").output(&foo_first).run();
+ rustdoc().input("foo.rs").out_dir(&foo_first).run();
+ rustdoc().input("bar.rs").out_dir(&foo_first).run();
let bar_first = Path::new("bar_first");
- rustdoc().input("bar.rs").output(&bar_first).run();
- rustdoc().input("foo.rs").output(&bar_first).run();
+ rustdoc().input("bar.rs").out_dir(&bar_first).run();
+ rustdoc().input("foo.rs").out_dir(&bar_first).run();
diff()
.expected_file(foo_first.join("search-index.js"))
diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs
index a5fae36..31441d7 100644
--- a/tests/run-make/rustdoc-io-error/rmake.rs
+++ b/tests/run-make/rustdoc-io-error/rmake.rs
@@ -25,7 +25,7 @@ fn main() {
permissions.set_readonly(true);
rfs::set_permissions(&out_dir, permissions);
- let output = rustdoc().input("foo.rs").output(&out_dir).env("RUST_BACKTRACE", "1").run_fail();
+ let output = rustdoc().input("foo.rs").out_dir(&out_dir).env("RUST_BACKTRACE", "1").run_fail();
rfs::set_permissions(&out_dir, original_permissions);
diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs
index 08f9595..d7e3510 100644
--- a/tests/run-make/rustdoc-map-file/rmake.rs
+++ b/tests/run-make/rustdoc-map-file/rmake.rs
@@ -1,13 +1,54 @@
-use run_make_support::{python_command, rustdoc};
+// This test ensures that all items from `foo` are correctly generated into the `redirect-map.json`
+// file with `--generate-redirect-map` rustdoc option.
+
+use std::path::Path;
+
+use run_make_support::rfs::read_to_string;
+use run_make_support::{path, rustdoc, serde_json};
fn main() {
let out_dir = "out";
+ let crate_name = "foo";
rustdoc()
.input("foo.rs")
+ .crate_name(crate_name)
.arg("-Zunstable-options")
.arg("--generate-redirect-map")
- .output(&out_dir)
+ .out_dir(&out_dir)
.run();
- // FIXME (GuillaumeGomez): Port the python script to Rust as well.
- python_command().arg("validate_json.py").arg(&out_dir).run();
+
+ let generated = read_to_string(path(out_dir).join(crate_name).join("redirect-map.json"));
+ let expected = read_to_string("expected.json");
+ let generated: serde_json::Value =
+ serde_json::from_str(&generated).expect("failed to parse JSON");
+ let expected: serde_json::Value =
+ serde_json::from_str(&expected).expect("failed to parse JSON");
+ let expected = expected.as_object().unwrap();
+
+ let mut differences = Vec::new();
+ for (key, expected_value) in expected.iter() {
+ match generated.get(key) {
+ Some(value) => {
+ if expected_value != value {
+ differences.push(format!(
+ "values for key `{key}` don't match: `{expected_value:?}` != `{value:?}`"
+ ));
+ }
+ }
+ None => differences.push(format!("missing key `{key}`")),
+ }
+ }
+ for (key, data) in generated.as_object().unwrap().iter() {
+ if !expected.contains_key(key) {
+ differences.push(format!("Extra data not expected: key: `{key}`, data: `{data}`"));
+ }
+ }
+
+ if !differences.is_empty() {
+ eprintln!("Found differences in JSON files:");
+ for diff in differences {
+ eprintln!("=> {diff}");
+ }
+ panic!("Found differences in JSON files");
+ }
}
diff --git a/tests/run-make/rustdoc-map-file/validate_json.py b/tests/run-make/rustdoc-map-file/validate_json.py
deleted file mode 100755
index 912dea3..0000000
--- a/tests/run-make/rustdoc-map-file/validate_json.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-
-import os
-import sys
-import json
-
-
-def find_redirect_map_file(folder, errors):
- for root, _dirs, files in os.walk(folder):
- for name in files:
- if not name.endswith("redirect-map.json"):
- continue
- with open(os.path.join(root, name)) as f:
- data = json.load(f)
- with open("expected.json") as f:
- expected = json.load(f)
- for key in expected:
- if expected[key] != data.get(key):
- errors.append("Expected `{}` for key `{}`, found: `{}`".format(
- expected[key], key, data.get(key)))
- else:
- del data[key]
- for key in data:
- errors.append("Extra data not expected: key: `{}`, data: `{}`".format(
- key, data[key]))
- return True
- return False
-
-
-if len(sys.argv) != 2:
- print("Expected doc directory to check!")
- sys.exit(1)
-
-errors = []
-if not find_redirect_map_file(sys.argv[1], errors):
- print("Didn't find the map file in `{}`...".format(sys.argv[1]))
- sys.exit(1)
-for err in errors:
- print("=> {}".format(err))
-if len(errors) != 0:
- sys.exit(1)
diff --git a/tests/run-make/rustdoc-output-path/rmake.rs b/tests/run-make/rustdoc-output-path/rmake.rs
index 3c1ccd3..181239e 100644
--- a/tests/run-make/rustdoc-output-path/rmake.rs
+++ b/tests/run-make/rustdoc-output-path/rmake.rs
@@ -6,6 +6,6 @@
fn main() {
let out_dir = Path::new("foo/bar/doc");
- rustdoc().input("foo.rs").output(&out_dir).run();
+ rustdoc().input("foo.rs").out_dir(&out_dir).run();
assert!(out_dir.exists());
}
diff --git a/tests/run-make/rustdoc-output-stdout/foo.rs b/tests/run-make/rustdoc-output-stdout/foo.rs
new file mode 100644
index 0000000..4a83567
--- /dev/null
+++ b/tests/run-make/rustdoc-output-stdout/foo.rs
@@ -0,0 +1 @@
+pub struct Foo;
diff --git a/tests/run-make/rustdoc-output-stdout/rmake.rs b/tests/run-make/rustdoc-output-stdout/rmake.rs
new file mode 100644
index 0000000..dbc9892
--- /dev/null
+++ b/tests/run-make/rustdoc-output-stdout/rmake.rs
@@ -0,0 +1,25 @@
+// This test verifies that rustdoc `-o -` prints JSON on stdout and doesn't generate
+// a JSON file.
+
+use std::path::PathBuf;
+
+use run_make_support::path_helpers::{cwd, has_extension, read_dir_entries_recursive};
+use run_make_support::rustdoc;
+
+fn main() {
+ // First we check that we generate the JSON in the stdout.
+ rustdoc()
+ .input("foo.rs")
+ .out_dir("-")
+ .arg("-Zunstable-options")
+ .output_format("json")
+ .run()
+ .assert_stdout_contains("{\"");
+
+ // Then we check it didn't generate any JSON file.
+ read_dir_entries_recursive(cwd(), |path| {
+ if path.is_file() && has_extension(path, "json") {
+ panic!("Found a JSON file {path:?}");
+ }
+ });
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
index b77df7a..546a068 100644
--- a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
@@ -35,7 +35,7 @@ fn main() {
.input("examples/ex.rs")
.crate_name("ex")
.crate_type("bin")
- .output(&out_dir)
+ .out_dir(&out_dir)
.extern_(crate_name, rust_lib_name(crate_name))
.extern_(proc_crate_name, dylib_name.trim())
.arg("-Zunstable-options")
@@ -49,7 +49,7 @@ fn main() {
.input("src/lib.rs")
.crate_name(crate_name)
.crate_type("lib")
- .output(&out_dir)
+ .out_dir(&out_dir)
.arg("-Zunstable-options")
.arg("--with-examples")
.arg(&ex_dir)
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
index eca0704..c4d7814 100644
--- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
+++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
@@ -20,7 +20,7 @@ pub fn scrape(extra_args: &[&str]) {
.input(&dep)
.crate_name(&dep_stem)
.crate_type("bin")
- .output(&out_dir)
+ .out_dir(&out_dir)
.extern_(crate_name, format!("lib{crate_name}.rmeta"))
.arg("-Zunstable-options")
.arg("--scrape-examples-output-path")
@@ -35,7 +35,7 @@ pub fn scrape(extra_args: &[&str]) {
let mut rustdoc = rustdoc();
rustdoc
.input("src/lib.rs")
- .output(&out_dir)
+ .out_dir(&out_dir)
.crate_name(crate_name)
.crate_type("lib")
.arg("-Zunstable-options");
diff --git a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
index 3246fc5..fe9587f 100644
--- a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
+++ b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
@@ -7,7 +7,7 @@ fn main() {
rustc().crate_type("lib").input("dummy_core.rs").target("target.json").run();
rustdoc()
.input("my_crate.rs")
- .output(out_dir)
+ .out_dir(out_dir)
.library_search_path(cwd())
.target("target.json")
.run();
diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs
index 8a961be..4577e47 100644
--- a/tests/run-make/rustdoc-themes/rmake.rs
+++ b/tests/run-make/rustdoc-themes/rmake.rs
@@ -27,6 +27,6 @@ fn main() {
rfs::create_dir_all(&out_dir);
rfs::write(&test_css, test_content);
- rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
+ rustdoc().out_dir(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
htmldocck().arg(out_dir).arg("foo.rs").run();
}
diff --git a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
index ded89c9..a82a196 100644
--- a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
+++ b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
@@ -2,6 +2,6 @@
fn main() {
let out_dir = "rustdoc";
- rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run();
+ rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").out_dir(&out_dir).run();
htmldocck().arg(out_dir).arg("src/lib.rs").run();
}
diff --git a/tests/run-make/staticlib-thin-archive/bin.rs b/tests/run-make/staticlib-thin-archive/bin.rs
new file mode 100644
index 0000000..97a2751
--- /dev/null
+++ b/tests/run-make/staticlib-thin-archive/bin.rs
@@ -0,0 +1,5 @@
+fn main() {
+ unsafe {
+ rust_lib::simple_fn();
+ }
+}
diff --git a/tests/run-make/staticlib-thin-archive/rmake.rs b/tests/run-make/staticlib-thin-archive/rmake.rs
new file mode 100644
index 0000000..955c50d
--- /dev/null
+++ b/tests/run-make/staticlib-thin-archive/rmake.rs
@@ -0,0 +1,23 @@
+// Regression test for https://github.com/rust-lang/rust/issues/107407 which
+// checks that rustc can read thin archive. Before the object crate added thin
+// archive support rustc would add emit object files to the staticlib and after
+// the object crate added thin archive support it would previously crash the
+// compiler due to a missing special case for thin archive members.
+use run_make_support::{llvm_ar, path, rfs, rust_lib_name, rustc, static_lib_name};
+
+fn main() {
+ rfs::create_dir("archive");
+
+ // Build a thin archive
+ rustc().input("simple_obj.rs").emit("obj").output("archive/simple_obj.o").run();
+ llvm_ar()
+ .obj_to_thin_ar()
+ .output_input(path("archive").join(static_lib_name("thin_archive")), "archive/simple_obj.o")
+ .run();
+
+ // Build an rlib which includes the members of this thin archive
+ rustc().input("rust_lib.rs").library_search_path("archive").run();
+
+ // Build a binary which requires a symbol from the thin archive
+ rustc().input("bin.rs").extern_("rust_lib", rust_lib_name("rust_lib")).run();
+}
diff --git a/tests/run-make/staticlib-thin-archive/rust_lib.rs b/tests/run-make/staticlib-thin-archive/rust_lib.rs
new file mode 100644
index 0000000..c76b0f2
--- /dev/null
+++ b/tests/run-make/staticlib-thin-archive/rust_lib.rs
@@ -0,0 +1,6 @@
+#![crate_type = "rlib"]
+
+#[link(name = "thin_archive", kind = "static")]
+extern "C" {
+ pub fn simple_fn();
+}
diff --git a/tests/run-make/staticlib-thin-archive/simple_obj.rs b/tests/run-make/staticlib-thin-archive/simple_obj.rs
new file mode 100644
index 0000000..a120c9b
--- /dev/null
+++ b/tests/run-make/staticlib-thin-archive/simple_obj.rs
@@ -0,0 +1,4 @@
+#![crate_type = "staticlib"]
+
+#[no_mangle]
+extern "C" fn simple_fn() {}
diff --git a/tests/run-make/sysroot-crates-are-unstable/rmake.rs b/tests/run-make/sysroot-crates-are-unstable/rmake.rs
index 24da387..2240d87 100644
--- a/tests/run-make/sysroot-crates-are-unstable/rmake.rs
+++ b/tests/run-make/sysroot-crates-are-unstable/rmake.rs
@@ -1,5 +1,102 @@
-use run_make_support::python_command;
+// Check that crates in the sysroot are treated as unstable, unless they are
+// on a list of known-stable sysroot crates.
+
+use std::path::{Path, PathBuf};
+use std::str;
+
+use run_make_support::{rfs, rustc, target};
+
+fn is_stable_crate(name: &str) -> bool {
+ matches!(name, "std" | "alloc" | "core" | "proc_macro")
+}
fn main() {
- python_command().arg("test.py").run();
+ for cr in get_unstable_sysroot_crates() {
+ check_crate_is_unstable(&cr);
+ }
+ println!("Done");
+}
+
+#[derive(Debug)]
+struct Crate {
+ name: String,
+ path: PathBuf,
+}
+
+fn check_crate_is_unstable(cr: &Crate) {
+ let Crate { name, path } = cr;
+
+ print!("- Verifying that sysroot crate '{name}' is an unstable crate ...");
+
+ // Trying to use this crate from a user program should fail.
+ let output = rustc()
+ .crate_type("rlib")
+ .target(target())
+ .extern_(name, path)
+ .input("-")
+ .stdin(format!("extern crate {name};"))
+ .run_fail();
+
+ // Make sure it failed for the intended reason, not some other reason.
+ // (The actual feature required varies between crates.)
+ output.assert_stderr_contains("use of unstable library feature");
+
+ println!(" OK");
+}
+
+fn get_unstable_sysroot_crates() -> Vec<Crate> {
+ let sysroot = PathBuf::from(rustc().print("sysroot").run().stdout_utf8().trim());
+ let sysroot_libs_dir = sysroot.join("lib").join("rustlib").join(target()).join("lib");
+ println!("Sysroot libs dir: {sysroot_libs_dir:?}");
+
+ // Generate a list of all library crates in the sysroot.
+ let sysroot_crates = get_all_crates_in_dir(&sysroot_libs_dir);
+ println!(
+ "Found {} sysroot crates: {:?}",
+ sysroot_crates.len(),
+ sysroot_crates.iter().map(|cr| &cr.name).collect::<Vec<_>>()
+ );
+
+ // Self-check: If we didn't find `core`, we probably checked the wrong directory.
+ assert!(
+ sysroot_crates.iter().any(|cr| cr.name == "core"),
+ "Couldn't find `core` in {sysroot_libs_dir:?}"
+ );
+
+ let unstable_sysroot_crates =
+ sysroot_crates.into_iter().filter(|cr| !is_stable_crate(&cr.name)).collect::<Vec<_>>();
+ // Self-check: There should be at least one unstable crate in the directory.
+ assert!(
+ !unstable_sysroot_crates.is_empty(),
+ "Couldn't find any unstable crates in {sysroot_libs_dir:?}"
+ );
+ unstable_sysroot_crates
+}
+
+fn get_all_crates_in_dir(libs_dir: &Path) -> Vec<Crate> {
+ let mut libs = vec![];
+ rfs::read_dir_entries(libs_dir, |path| {
+ if !path.is_file() {
+ return;
+ }
+ if let Some(name) = crate_name_from_path(path) {
+ libs.push(Crate { name, path: path.to_owned() });
+ }
+ });
+ libs.sort_by(|a, b| a.name.cmp(&b.name));
+ libs
+}
+
+/// Treat a file as a crate if its name begins with `lib` and ends with `.rlib`.
+/// The crate name is the part before the first hyphen (if any).
+fn crate_name_from_path(path: &Path) -> Option<String> {
+ let name = path
+ .file_name()?
+ .to_str()?
+ .strip_prefix("lib")?
+ .strip_suffix(".rlib")?
+ .split('-')
+ .next()
+ .expect("split always yields at least one string");
+ Some(name.to_owned())
}
diff --git a/tests/run-make/sysroot-crates-are-unstable/test.py b/tests/run-make/sysroot-crates-are-unstable/test.py
deleted file mode 100644
index 45cfdd1..0000000
--- a/tests/run-make/sysroot-crates-are-unstable/test.py
+++ /dev/null
@@ -1,75 +0,0 @@
-import sys
-import os
-from os import listdir
-from os.path import isfile, join
-from subprocess import PIPE, Popen
-
-
-# This is n list of files which are stable crates or simply are not crates,
-# we don't check for the instability of these crates as they're all stable!
-STABLE_CRATES = ['std', 'alloc', 'core', 'proc_macro',
- 'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o', 'clang_rt']
-
-
-def convert_to_string(s):
- if s.__class__.__name__ == 'bytes':
- return s.decode('utf-8')
- return s
-
-
-def set_ld_lib_path():
- var = os.environ.get("LD_LIB_PATH_ENVVAR")
- rpath = os.environ.get("HOST_RPATH_DIR")
- if var and rpath:
- path = os.environ.get(var)
- if path:
- os.environ[var] = rpath + os.pathsep + path
- else:
- os.environ[var] = rpath
-
-
-def exec_command(command, to_input=None):
- child = None
- if to_input is None:
- child = Popen(command, stdout=PIPE, stderr=PIPE)
- else:
- child = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
- stdout, stderr = child.communicate(input=to_input)
- return (convert_to_string(stdout), convert_to_string(stderr))
-
-
-def check_lib(lib):
- if lib['name'] in STABLE_CRATES:
- return True
- print('verifying if {} is an unstable crate'.format(lib['name']))
- stdout, stderr = exec_command([os.environ['RUSTC'], '-', '--crate-type', 'rlib',
- '--target', os.environ['TARGET'],
- '--extern', '{}={}'.format(lib['name'], lib['path'])],
- to_input=('extern crate {};'.format(lib['name'])).encode('utf-8'))
- if 'use of unstable library feature' not in '{}{}'.format(stdout, stderr):
- print('crate {} "{}" is not unstable'.format(lib['name'], lib['path']))
- print('{}{}'.format(stdout, stderr))
- print('')
- return False
- return True
-
-# Generate a list of all crates in the sysroot. To do this we list all files in
-# rustc's sysroot, look at the filename, strip everything after the `-`, and
-# strip the leading `lib` (if present)
-def get_all_libs(dir_path):
- return [{ 'path': join(dir_path, f), 'name': f[3:].split('-')[0] }
- for f in listdir(dir_path)
- if isfile(join(dir_path, f)) and f.endswith('.rlib') and f not in STABLE_CRATES]
-
-
-set_ld_lib_path()
-sysroot = exec_command([os.environ['RUSTC'], '--print', 'sysroot'])[0].replace('\n', '')
-assert sysroot, "Could not read the rustc sysroot!"
-libs = get_all_libs(join(sysroot, 'lib/rustlib/{}/lib'.format(os.environ['TARGET'])))
-
-ret = 0
-for lib in libs:
- if not check_lib(lib):
- # We continue so users can see all the not unstable crates.
- ret = 1
-sys.exit(ret)
diff --git a/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
new file mode 100644
index 0000000..d758c90
--- /dev/null
+++ b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: --target aarch64-unknown-none -Zsanitizer=shadow-call-stack
+//@ error-pattern: shadow-call-stack sanitizer is not supported for this target
+//@ dont-check-compiler-stderr
+//@ needs-llvm-components: aarch64
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {}
diff --git a/tests/ui/async-await/async-closures/move-out-of-ref.rs b/tests/ui/async-await/async-closures/move-out-of-ref.rs
new file mode 100644
index 0000000..a054472
--- /dev/null
+++ b/tests/ui/async-await/async-closures/move-out-of-ref.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Zvalidate-mir
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+// NOT copy.
+struct Ty;
+
+fn hello(x: &Ty) {
+ let c = async || {
+ *x;
+ //~^ ERROR cannot move out of `*x` which is behind a shared reference
+ };
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/move-out-of-ref.stderr b/tests/ui/async-await/async-closures/move-out-of-ref.stderr
new file mode 100644
index 0000000..294905a
--- /dev/null
+++ b/tests/ui/async-await/async-closures/move-out-of-ref.stderr
@@ -0,0 +1,18 @@
+error[E0507]: cannot move out of `*x` which is behind a shared reference
+ --> $DIR/move-out-of-ref.rs:11:9
+ |
+LL | *x;
+ | ^^ move occurs because `*x` has type `Ty`, which does not implement the `Copy` trait
+ |
+note: if `Ty` implemented `Clone`, you could clone the value
+ --> $DIR/move-out-of-ref.rs:7:1
+ |
+LL | struct Ty;
+ | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL | *x;
+ | -- you could clone this value
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/async-await/async-closures/sig-from-bare-fn.rs b/tests/ui/async-await/async-closures/sig-from-bare-fn.rs
new file mode 100644
index 0000000..a679471
--- /dev/null
+++ b/tests/ui/async-await/async-closures/sig-from-bare-fn.rs
@@ -0,0 +1,49 @@
+//@ check-pass
+//@ edition: 2021
+
+// Make sure that we infer the args of an async closure even if it's passed to
+// a function that requires the async closure implement `Fn*` but does *not* have
+// a `Future` bound on the return type.
+
+#![feature(async_closure)]
+
+use std::future::Future;
+
+trait TryStream {
+ type Ok;
+ type Err;
+}
+
+trait TryFuture {
+ type Ok;
+ type Err;
+}
+
+impl<F, T, E> TryFuture for F where F: Future<Output = Result<T, E>> {
+ type Ok = T;
+ type Err = E;
+}
+
+trait TryStreamExt: TryStream {
+ fn try_for_each<F, Fut>(&self, f: F)
+ where
+ F: FnMut(Self::Ok) -> Fut,
+ Fut: TryFuture<Ok = (), Err = Self::Err>;
+}
+
+impl<S> TryStreamExt for S where S: TryStream {
+ fn try_for_each<F, Fut>(&self, f: F)
+ where
+ F: FnMut(Self::Ok) -> Fut,
+ Fut: TryFuture<Ok = (), Err = Self::Err>,
+ { }
+}
+
+fn test(stream: impl TryStream<Ok = &'static str, Err = ()>) {
+ stream.try_for_each(async |s| {
+ s.trim(); // Make sure we know the type of `s` at this point.
+ Ok(())
+ });
+}
+
+fn main() {}
diff --git a/tests/ui/attributes/assoc-expr.rs b/tests/ui/attributes/assoc-expr.rs
new file mode 100644
index 0000000..f39557d
--- /dev/null
+++ b/tests/ui/attributes/assoc-expr.rs
@@ -0,0 +1,42 @@
+//@ check-pass
+// This test triggered an assertion failure in token collection due to
+// mishandling of attributes on associative expressions.
+
+#![feature(cfg_eval)]
+#![feature(rustc_attrs)]
+#![feature(stmt_expr_attributes)]
+#![allow(internal_features)]
+
+fn main() {}
+
+#[cfg_eval]
+struct Foo1(
+ [ bool; {
+ let _x = 30;
+ #[cfg_attr(unix, rustc_dummy(aa))] 1
+ } ]
+);
+
+#[cfg_eval]
+struct Foo12(
+ [ bool; {
+ let _x = 30;
+ #[cfg_attr(unix, rustc_dummy(bb))] 1 + 2
+ } ]
+);
+
+#[cfg_eval]
+struct Foox(
+ [ bool; {
+ let _x = 30;
+ #[cfg_attr(unix, rustc_dummy(cc))] _x
+ } ]
+);
+
+#[cfg_eval]
+struct Foox2(
+ [ bool; {
+ let _x = 30;
+ #[cfg_attr(unix, rustc_dummy(dd))] _x + 2
+ } ]
+);
diff --git a/tests/ui/attributes/linkage.rs b/tests/ui/attributes/linkage.rs
new file mode 100644
index 0000000..0d5ce69
--- /dev/null
+++ b/tests/ui/attributes/linkage.rs
@@ -0,0 +1,42 @@
+#![feature(linkage)]
+#![feature(stmt_expr_attributes)]
+#![deny(unused_attributes)]
+#![allow(dead_code)]
+
+#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
+type InvalidTy = ();
+
+#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
+mod invalid_module {}
+
+#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
+struct F;
+
+#[linkage = "weak"] //~ ERROR attribute should be applied to a function or static
+impl F {
+ #[linkage = "weak"]
+ fn valid(&self) {}
+}
+
+#[linkage = "weak"]
+fn f() {
+ #[linkage = "weak"]
+ {
+ 1
+ };
+ //~^^^^ ERROR attribute should be applied to a function or static
+}
+
+extern "C" {
+ #[linkage = "weak"]
+ static A: *const ();
+
+ #[linkage = "weak"]
+ fn bar();
+}
+
+fn main() {
+ let _ = #[linkage = "weak"]
+ (|| 1);
+ //~^^ ERROR attribute should be applied to a function or static
+}
diff --git a/tests/ui/attributes/linkage.stderr b/tests/ui/attributes/linkage.stderr
new file mode 100644
index 0000000..d559552
--- /dev/null
+++ b/tests/ui/attributes/linkage.stderr
@@ -0,0 +1,55 @@
+error: attribute should be applied to a function or static
+ --> $DIR/linkage.rs:6:1
+ |
+LL | #[linkage = "weak"]
+ | ^^^^^^^^^^^^^^^^^^^
+LL | type InvalidTy = ();
+ | -------------------- not a function definition or static
+
+error: attribute should be applied to a function or static
+ --> $DIR/linkage.rs:9:1
+ |
+LL | #[linkage = "weak"]
+ | ^^^^^^^^^^^^^^^^^^^
+LL | mod invalid_module {}
+ | --------------------- not a function definition or static
+
+error: attribute should be applied to a function or static
+ --> $DIR/linkage.rs:12:1
+ |
+LL | #[linkage = "weak"]
+ | ^^^^^^^^^^^^^^^^^^^
+LL | struct F;
+ | --------- not a function definition or static
+
+error: attribute should be applied to a function or static
+ --> $DIR/linkage.rs:15:1
+ |
+LL | #[linkage = "weak"]
+ | ^^^^^^^^^^^^^^^^^^^
+LL | / impl F {
+LL | | #[linkage = "weak"]
+LL | | fn valid(&self) {}
+LL | | }
+ | |_- not a function definition or static
+
+error: attribute should be applied to a function or static
+ --> $DIR/linkage.rs:23:5
+ |
+LL | #[linkage = "weak"]
+ | ^^^^^^^^^^^^^^^^^^^
+LL | / {
+LL | | 1
+LL | | };
+ | |_____- not a function definition or static
+
+error: attribute should be applied to a function or static
+ --> $DIR/linkage.rs:39:13
+ |
+LL | let _ = #[linkage = "weak"]
+ | ^^^^^^^^^^^^^^^^^^^
+LL | (|| 1);
+ | ------ not a function definition or static
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs
index ce365d1..6a9853b 100644
--- a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs
@@ -1,5 +1,4 @@
//@ build-pass
-#![feature(unsafe_attributes)]
#[cfg_attr(all(), unsafe(no_mangle))]
fn a() {}
diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs
index b8edb4a..95fc19f 100644
--- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs
@@ -1,5 +1,3 @@
-#![feature(unsafe_attributes)]
-
#[derive(unsafe(Debug))]
//~^ ERROR: expected identifier, found keyword `unsafe`
//~| ERROR: traits in `#[derive(...)]` don't accept arguments
diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr
index c40a551..4002c93 100644
--- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr
@@ -1,5 +1,5 @@
error: expected identifier, found keyword `unsafe`
- --> $DIR/derive-unsafe-attributes.rs:3:10
+ --> $DIR/derive-unsafe-attributes.rs:1:10
|
LL | #[derive(unsafe(Debug))]
| ^^^^^^ expected identifier, found keyword
@@ -10,13 +10,13 @@
| ++
error: traits in `#[derive(...)]` don't accept arguments
- --> $DIR/derive-unsafe-attributes.rs:3:16
+ --> $DIR/derive-unsafe-attributes.rs:1:16
|
LL | #[derive(unsafe(Debug))]
| ^^^^^^^ help: remove the arguments
error: `derive` is not an unsafe attribute
- --> $DIR/derive-unsafe-attributes.rs:12:3
+ --> $DIR/derive-unsafe-attributes.rs:10:3
|
LL | #[unsafe(derive(Debug))]
| ^^^^^^ this is not an unsafe attribute
@@ -24,7 +24,7 @@
= note: extraneous unsafe is not allowed in attributes
error: expected identifier, found keyword `unsafe`
- --> $DIR/derive-unsafe-attributes.rs:3:10
+ --> $DIR/derive-unsafe-attributes.rs:1:10
|
LL | #[derive(unsafe(Debug))]
| ^^^^^^ expected identifier, found keyword
@@ -36,7 +36,7 @@
| ++
error: expected identifier, found keyword `unsafe`
- --> $DIR/derive-unsafe-attributes.rs:3:10
+ --> $DIR/derive-unsafe-attributes.rs:1:10
|
LL | #[derive(unsafe(Debug))]
| ^^^^^^ expected identifier, found keyword
@@ -48,13 +48,13 @@
| ++
error: cannot find derive macro `r#unsafe` in this scope
- --> $DIR/derive-unsafe-attributes.rs:3:10
+ --> $DIR/derive-unsafe-attributes.rs:1:10
|
LL | #[derive(unsafe(Debug))]
| ^^^^^^
error: cannot find derive macro `r#unsafe` in this scope
- --> $DIR/derive-unsafe-attributes.rs:3:10
+ --> $DIR/derive-unsafe-attributes.rs:1:10
|
LL | #[derive(unsafe(Debug))]
| ^^^^^^
diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
index a6c0ea5..894d132 100644
--- a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
@@ -1,5 +1,3 @@
-#![feature(unsafe_attributes)]
-
#[unsafe(unsafe(no_mangle))]
//~^ ERROR expected identifier, found keyword `unsafe`
//~| ERROR cannot find attribute `r#unsafe` in this scope
diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
index 950b263..0825cf7 100644
--- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
@@ -1,5 +1,5 @@
error: expected identifier, found keyword `unsafe`
- --> $DIR/double-unsafe-attributes.rs:3:10
+ --> $DIR/double-unsafe-attributes.rs:1:10
|
LL | #[unsafe(unsafe(no_mangle))]
| ^^^^^^ expected identifier, found keyword
@@ -10,7 +10,7 @@
| ++
error: `r#unsafe` is not an unsafe attribute
- --> $DIR/double-unsafe-attributes.rs:3:3
+ --> $DIR/double-unsafe-attributes.rs:1:3
|
LL | #[unsafe(unsafe(no_mangle))]
| ^^^^^^ this is not an unsafe attribute
@@ -18,7 +18,7 @@
= note: extraneous unsafe is not allowed in attributes
error: cannot find attribute `r#unsafe` in this scope
- --> $DIR/double-unsafe-attributes.rs:3:10
+ --> $DIR/double-unsafe-attributes.rs:1:10
|
LL | #[unsafe(unsafe(no_mangle))]
| ^^^^^^
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
index 0181add..b561550 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs
@@ -1,6 +1,5 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
-#![feature(unsafe_attributes)]
#[unsafe(cfg(any()))] //~ ERROR: is not an unsafe attribute
fn a() {}
diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
index f39074b..9fb7f06 100644
--- a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr
@@ -1,5 +1,5 @@
error: `cfg` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:5:3
+ --> $DIR/extraneous-unsafe-attributes.rs:4:3
|
LL | #[unsafe(cfg(any()))]
| ^^^^^^ this is not an unsafe attribute
@@ -7,7 +7,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `cfg_attr` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:8:3
+ --> $DIR/extraneous-unsafe-attributes.rs:7:3
|
LL | #[unsafe(cfg_attr(any(), allow(dead_code)))]
| ^^^^^^ this is not an unsafe attribute
@@ -15,7 +15,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `test` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:11:3
+ --> $DIR/extraneous-unsafe-attributes.rs:10:3
|
LL | #[unsafe(test)]
| ^^^^^^ this is not an unsafe attribute
@@ -23,7 +23,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `ignore` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:14:3
+ --> $DIR/extraneous-unsafe-attributes.rs:13:3
|
LL | #[unsafe(ignore = "test")]
| ^^^^^^ this is not an unsafe attribute
@@ -31,7 +31,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `should_panic` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:17:3
+ --> $DIR/extraneous-unsafe-attributes.rs:16:3
|
LL | #[unsafe(should_panic(expected = "test"))]
| ^^^^^^ this is not an unsafe attribute
@@ -39,7 +39,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `macro_use` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:20:3
+ --> $DIR/extraneous-unsafe-attributes.rs:19:3
|
LL | #[unsafe(macro_use)]
| ^^^^^^ this is not an unsafe attribute
@@ -47,7 +47,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `macro_export` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:22:7
+ --> $DIR/extraneous-unsafe-attributes.rs:21:7
|
LL | #[unsafe(macro_export)]
| ^^^^^^ this is not an unsafe attribute
@@ -55,7 +55,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `used` is not an unsafe attribute
- --> $DIR/extraneous-unsafe-attributes.rs:28:3
+ --> $DIR/extraneous-unsafe-attributes.rs:27:3
|
LL | #[unsafe(used)]
| ^^^^^^ this is not an unsafe attribute
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
index f29a5b3..eaf8706 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs
@@ -1,5 +1,3 @@
-#![feature(unsafe_attributes)]
-
#[unsafe(proc_macro)]
//~^ ERROR: is not an unsafe attribute
//~| ERROR attribute is only usable with crates of the `proc-macro` crate type
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
index 79d34d4..9c5751c 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
@@ -1,11 +1,11 @@
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:28:16
+ --> $DIR/proc-unsafe-attributes.rs:26:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:28:16
+ --> $DIR/proc-unsafe-attributes.rs:26:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -13,7 +13,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: `proc_macro` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:3:3
+ --> $DIR/proc-unsafe-attributes.rs:1:3
|
LL | #[unsafe(proc_macro)]
| ^^^^^^ this is not an unsafe attribute
@@ -21,7 +21,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `proc_macro_derive` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:9:3
+ --> $DIR/proc-unsafe-attributes.rs:7:3
|
LL | #[unsafe(proc_macro_derive(Foo))]
| ^^^^^^ this is not an unsafe attribute
@@ -29,7 +29,7 @@
= note: extraneous unsafe is not allowed in attributes
error: expected identifier, found keyword `unsafe`
- --> $DIR/proc-unsafe-attributes.rs:14:21
+ --> $DIR/proc-unsafe-attributes.rs:12:21
|
LL | #[proc_macro_derive(unsafe(Foo))]
| ^^^^^^ expected identifier, found keyword
@@ -40,7 +40,7 @@
| ++
error: `proc_macro_attribute` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:19:3
+ --> $DIR/proc-unsafe-attributes.rs:17:3
|
LL | #[unsafe(proc_macro_attribute)]
| ^^^^^^ this is not an unsafe attribute
@@ -48,7 +48,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:24:3
+ --> $DIR/proc-unsafe-attributes.rs:22:3
|
LL | #[unsafe(allow(dead_code))]
| ^^^^^^ this is not an unsafe attribute
@@ -56,7 +56,7 @@
= note: extraneous unsafe is not allowed in attributes
error: `allow` is not an unsafe attribute
- --> $DIR/proc-unsafe-attributes.rs:28:3
+ --> $DIR/proc-unsafe-attributes.rs:26:3
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^ this is not an unsafe attribute
@@ -64,7 +64,7 @@
= note: extraneous unsafe is not allowed in attributes
error: expected identifier, found keyword `unsafe`
- --> $DIR/proc-unsafe-attributes.rs:28:16
+ --> $DIR/proc-unsafe-attributes.rs:26:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^ expected identifier, found keyword
@@ -75,31 +75,31 @@
| ++
error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
- --> $DIR/proc-unsafe-attributes.rs:3:1
+ --> $DIR/proc-unsafe-attributes.rs:1:1
|
LL | #[unsafe(proc_macro)]
| ^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
- --> $DIR/proc-unsafe-attributes.rs:9:1
+ --> $DIR/proc-unsafe-attributes.rs:7:1
|
LL | #[unsafe(proc_macro_derive(Foo))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
- --> $DIR/proc-unsafe-attributes.rs:14:1
+ --> $DIR/proc-unsafe-attributes.rs:12:1
|
LL | #[proc_macro_derive(unsafe(Foo))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type
- --> $DIR/proc-unsafe-attributes.rs:19:1
+ --> $DIR/proc-unsafe-attributes.rs:17:1
|
LL | #[unsafe(proc_macro_attribute)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:28:16
+ --> $DIR/proc-unsafe-attributes.rs:26:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
@@ -107,7 +107,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error[E0452]: malformed lint attribute input
- --> $DIR/proc-unsafe-attributes.rs:28:16
+ --> $DIR/proc-unsafe-attributes.rs:26:16
|
LL | #[unsafe(allow(unsafe(dead_code)))]
| ^^^^^^^^^^^^^^^^^ bad attribute argument
diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs
index 33a412a..5c57767 100644
--- a/tests/ui/attributes/unsafe/unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs
@@ -1,5 +1,4 @@
//@ build-pass
-#![feature(unsafe_attributes)]
#[unsafe(no_mangle)]
fn a() {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
index 67db36a..5af03a2 100644
--- a/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs
@@ -1,5 +1,3 @@
-#![feature(unsafe_attributes)]
-
#[unsafe(repr(C))] //~ ERROR: is not an unsafe attribute
struct Foo {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
index 584b0ea..55172c9 100644
--- a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr
@@ -1,5 +1,5 @@
error: `repr` is not an unsafe attribute
- --> $DIR/unsafe-safe-attribute.rs:3:3
+ --> $DIR/unsafe-safe-attribute.rs:1:3
|
LL | #[unsafe(repr(C))]
| ^^^^^^ this is not an unsafe attribute
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
index ff2eb61..0f241cc 100644
--- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
@@ -1,5 +1,3 @@
-#![feature(unsafe_attributes)]
-
#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute
message = "testing",
))]
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
index 26b5e4e..3bc291d 100644
--- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
@@ -1,5 +1,5 @@
error: `diagnostic::on_unimplemented` is not an unsafe attribute
- --> $DIR/unsafe-safe-attribute_diagnostic.rs:3:3
+ --> $DIR/unsafe-safe-attribute_diagnostic.rs:1:3
|
LL | #[unsafe(diagnostic::on_unimplemented(
| ^^^^^^ this is not an unsafe attribute
diff --git a/tests/crashes/116308.rs b/tests/ui/const-generics/adt_const_params/116308.rs
similarity index 81%
rename from tests/crashes/116308.rs
rename to tests/ui/const-generics/adt_const_params/116308.rs
index cb96c80..9ea7022 100644
--- a/tests/crashes/116308.rs
+++ b/tests/ui/const-generics/adt_const_params/116308.rs
@@ -1,6 +1,8 @@
-//@ known-bug: #116308
+//@ check-pass
#![feature(adt_const_params)]
+// Regression test for #116308
+
pub trait Identity {
type Identity;
}
diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs
index ba8db4c..45e8ea5 100644
--- a/tests/ui/consts/const-float-bits-conv.rs
+++ b/tests/ui/consts/const-float-bits-conv.rs
@@ -23,6 +23,11 @@ macro_rules! const_assert {
};
}
+fn has_broken_floats() -> bool {
+ // i586 targets are broken due to <https://github.com/rust-lang/rust/issues/114479>.
+ std::env::var("TARGET").is_ok_and(|v| v.contains("i586"))
+}
+
fn f32() {
const_assert!((1f32).to_bits(), 0x3f800000);
const_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000);
@@ -38,6 +43,19 @@ fn f32() {
const_assert!(f32::from_bits(0x44a72000), 1337.0);
const_assert!(f32::from_ne_bytes(0x44a72000u32.to_ne_bytes()), 1337.0);
const_assert!(f32::from_bits(0xc1640000), -14.25);
+
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply!
+ const QUIET_NAN: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
+ const SIGNALING_NAN: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
+
+ const_assert!(f32::from_bits(QUIET_NAN).is_nan());
+ const_assert!(f32::from_bits(SIGNALING_NAN).is_nan());
+ const_assert!(f32::from_bits(QUIET_NAN).to_bits(), QUIET_NAN);
+ if !has_broken_floats() {
+ const_assert!(f32::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN);
+ }
}
fn f64() {
@@ -55,6 +73,19 @@ fn f64() {
const_assert!(f64::from_bits(0x4094e40000000000), 1337.0);
const_assert!(f64::from_ne_bytes(0x4094e40000000000u64.to_ne_bytes()), 1337.0);
const_assert!(f64::from_bits(0xc02c800000000000), -14.25);
+
+ // Check that NaNs roundtrip their bits regardless of signalingness
+ // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
+ // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply!
+ const QUIET_NAN: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
+ const SIGNALING_NAN: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
+
+ const_assert!(f64::from_bits(QUIET_NAN).is_nan());
+ const_assert!(f64::from_bits(SIGNALING_NAN).is_nan());
+ const_assert!(f64::from_bits(QUIET_NAN).to_bits(), QUIET_NAN);
+ if !has_broken_floats() {
+ const_assert!(f64::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN);
+ }
}
fn main() {
diff --git a/tests/ui/consts/const-float-bits-reject-conv.rs b/tests/ui/consts/const-float-bits-reject-conv.rs
deleted file mode 100644
index febb272..0000000
--- a/tests/ui/consts/const-float-bits-reject-conv.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-//@ compile-flags: -Zmir-opt-level=0
-//@ error-pattern: cannot use f32::to_bits on a NaN
-#![feature(const_float_bits_conv)]
-#![feature(const_float_classify)]
-
-// Don't promote
-const fn nop<T>(x: T) -> T { x }
-
-macro_rules! const_assert {
- ($a:expr) => {
- {
- const _: () = assert!($a);
- assert!(nop($a));
- }
- };
- ($a:expr, $b:expr) => {
- {
- const _: () = assert!($a == $b);
- assert_eq!(nop($a), nop($b));
- }
- };
-}
-
-fn f32() {
- // Check that NaNs roundtrip their bits regardless of signalingness
- // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
- // ...actually, let's just check that these break. :D
- const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
- //~^ inside
- const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
- //~^ inside
-
- // The rest of the code is dead because the constants already fail to evaluate.
-
- const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
- const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
-
- // LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern.
- // In practice, this seems to only cause a problem on x86, since the most widely used calling
- // convention mandates that floating point values are returned on the x87 FPU stack. See #73328.
- // However, during CTFE we still preserve bit patterns (though that is not a guarantee).
- const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
- const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
-}
-
-fn f64() {
- // Check that NaNs roundtrip their bits regardless of signalingness
- // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
- // ...actually, let's just check that these break. :D
- const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
- //~^ inside
- const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
- //~^ inside
-
- // The rest of the code is dead because the constants already fail to evaluate.
-
- const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
- const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
-
- // See comment above.
- const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
- const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
-}
-
-fn main() {
- f32();
- f64();
-}
diff --git a/tests/ui/consts/const-float-bits-reject-conv.stderr b/tests/ui/consts/const-float-bits-reject-conv.stderr
deleted file mode 100644
index 1511dab..0000000
--- a/tests/ui/consts/const-float-bits-reject-conv.stderr
+++ /dev/null
@@ -1,115 +0,0 @@
-error[E0080]: evaluation of constant value failed
- --> $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
- = note: the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
-note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32`
- --> $SRC_DIR/core/src/num/f32.rs:LL:COL
-note: inside `core::f32::<impl f32>::to_bits`
- --> $SRC_DIR/core/src/num/f32.rs:LL:COL
-note: inside `f32::MASKED_NAN1`
- --> $DIR/const-float-bits-reject-conv.rs:28:30
- |
-LL | const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA;
- | ^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: evaluation of constant value failed
- --> $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
- = note: the evaluated program panicked at 'const-eval error: cannot use f32::to_bits on a NaN', $SRC_DIR/core/src/num/f32.rs:LL:COL
- |
-note: inside `core::f32::<impl f32>::to_bits::ct_f32_to_u32`
- --> $SRC_DIR/core/src/num/f32.rs:LL:COL
-note: inside `core::f32::<impl f32>::to_bits`
- --> $SRC_DIR/core/src/num/f32.rs:LL:COL
-note: inside `f32::MASKED_NAN2`
- --> $DIR/const-float-bits-reject-conv.rs:30:30
- |
-LL | const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
- | ^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:35:34
- |
-LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
- | ^^^^^^^^^^^
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:36:34
- |
-LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
- | ^^^^^^^^^^^
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:42:34
- |
-LL | const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
- | ^^^^^^^^^^^
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:43:34
- |
-LL | const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
- | ^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
- --> $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
- = note: the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
-note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64`
- --> $SRC_DIR/core/src/num/f64.rs:LL:COL
-note: inside `core::f64::<impl f64>::to_bits`
- --> $SRC_DIR/core/src/num/f64.rs:LL:COL
-note: inside `f64::MASKED_NAN1`
- --> $DIR/const-float-bits-reject-conv.rs:50:30
- |
-LL | const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
- | ^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: evaluation of constant value failed
- --> $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
- = note: the evaluated program panicked at 'const-eval error: cannot use f64::to_bits on a NaN', $SRC_DIR/core/src/num/f64.rs:LL:COL
- |
-note: inside `core::f64::<impl f64>::to_bits::ct_f64_to_u64`
- --> $SRC_DIR/core/src/num/f64.rs:LL:COL
-note: inside `core::f64::<impl f64>::to_bits`
- --> $SRC_DIR/core/src/num/f64.rs:LL:COL
-note: inside `f64::MASKED_NAN2`
- --> $DIR/const-float-bits-reject-conv.rs:52:30
- |
-LL | const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
- | ^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:57:34
- |
-LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
- | ^^^^^^^^^^^
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:58:34
- |
-LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
- | ^^^^^^^^^^^
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:61:34
- |
-LL | const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
- | ^^^^^^^^^^^
-
-note: erroneous constant encountered
- --> $DIR/const-float-bits-reject-conv.rs:62:34
- |
-LL | const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
- | ^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs
new file mode 100644
index 0000000..0a7ec5a
--- /dev/null
+++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.rs
@@ -0,0 +1,34 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+use std::marker::PhantomData;
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a> InvariantRef<'a, ()> {
+ pub const NEW: Self = InvariantRef::new(&());
+ //~^ ERROR: no function or associated item named `new` found
+}
+
+trait Trait {
+ fn foo(&self) -> u8 { 0 }
+ fn bar(&self) -> u8 { 1 }
+ fn meh(&self) -> u8 { 2 }
+}
+
+struct Z(u8);
+
+impl Trait for Z {
+ reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ //~^ ERROR: use of undeclared lifetime name `'a`
+ //~| ERROR: use of undeclared lifetime name `'a`
+ //~| ERROR: use of undeclared lifetime name `'a`
+ //~| ERROR: the trait bound `u8: Trait` is not satisfied
+ //~| ERROR: the trait bound `u8: Trait` is not satisfied
+ //~| ERROR: the trait bound `u8: Trait` is not satisfied
+ //~| ERROR: mismatched types
+ //~| ERROR: mismatched types
+ //~| ERROR: mismatched types
+}
+
+fn main() { }
diff --git a/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
new file mode 100644
index 0000000..2ce3b38
--- /dev/null
+++ b/tests/ui/delegation/correct_body_owner_parent_found_in_diagnostics.stderr
@@ -0,0 +1,113 @@
+error[E0261]: use of undeclared lifetime name `'a`
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^ undeclared lifetime
+ |
+help: consider introducing lifetime `'a` here
+ |
+LL | reuse <u8 as Trait>::{foo'a, , bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | +++
+help: consider introducing lifetime `'a` here
+ |
+LL | impl<'a> Trait for Z {
+ | ++++
+
+error[E0261]: use of undeclared lifetime name `'a`
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^ undeclared lifetime
+ |
+help: consider introducing lifetime `'a` here
+ |
+LL | reuse <u8 as Trait>::{foo, bar'a, , meh} { &const { InvariantRef::<'a>::NEW } }
+ | +++
+help: consider introducing lifetime `'a` here
+ |
+LL | impl<'a> Trait for Z {
+ | ++++
+
+error[E0261]: use of undeclared lifetime name `'a`
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^ undeclared lifetime
+ |
+help: consider introducing lifetime `'a` here
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh'a, } { &const { InvariantRef::<'a>::NEW } }
+ | +++
+help: consider introducing lifetime `'a` here
+ |
+LL | impl<'a> Trait for Z {
+ | ++++
+
+error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
+ |
+LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+ | -------------------------------------- function or associated item `new` not found for this struct
+...
+LL | pub const NEW: Self = InvariantRef::new(&());
+ | ^^^ function or associated item not found in `InvariantRef<'_, _>`
+
+error[E0308]: mismatched types
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+ |
+ = note: expected type `u8`
+ found struct `InvariantRef<'_, ()>`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^ the trait `Trait` is not implemented for `u8`
+ |
+ = help: the trait `Trait` is implemented for `Z`
+
+error[E0308]: mismatched types
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+ |
+ = note: expected type `u8`
+ found struct `InvariantRef<'_, ()>`
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^ the trait `Trait` is not implemented for `u8`
+ |
+ = help: the trait `Trait` is implemented for `Z`
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0308]: mismatched types
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
+ |
+ = note: expected type `u8`
+ found struct `InvariantRef<'_, ()>`
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: the trait bound `u8: Trait` is not satisfied
+ --> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
+ |
+LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
+ | ^^ the trait `Trait` is not implemented for `u8`
+ |
+ = help: the trait `Trait` is implemented for `Z`
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0261, E0277, E0308, E0599.
+For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/deriving/auxiliary/another-proc-macro.rs b/tests/ui/deriving/auxiliary/another-proc-macro.rs
new file mode 100644
index 0000000..a05175c
--- /dev/null
+++ b/tests/ui/deriving/auxiliary/another-proc-macro.rs
@@ -0,0 +1,45 @@
+//@ force-host
+//@ no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, TokenStream};
+
+#[proc_macro_derive(AnotherMacro, attributes(pointee))]
+pub fn derive(_input: TokenStream) -> TokenStream {
+ quote! {
+ const _: () = {
+ const ANOTHER_MACRO_DERIVED: () = ();
+ };
+ }
+ .into()
+}
+
+#[proc_macro_attribute]
+pub fn pointee(
+ _attr: proc_macro::TokenStream,
+ _item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+ quote! {
+ const _: () = {
+ const POINTEE_MACRO_ATTR_DERIVED: () = ();
+ };
+ }
+ .into()
+}
+
+#[proc_macro_attribute]
+pub fn default(
+ _attr: proc_macro::TokenStream,
+ _item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+ quote! {
+ const _: () = {
+ const DEFAULT_MACRO_ATTR_DERIVED: () = ();
+ };
+ }
+ .into()
+}
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs
new file mode 100644
index 0000000..41c95f6
--- /dev/null
+++ b/tests/ui/deriving/built-in-proc-macro-scope.rs
@@ -0,0 +1,25 @@
+//@ check-pass
+//@ aux-build: another-proc-macro.rs
+//@ compile-flags: -Zunpretty=expanded
+
+#![feature(derive_smart_pointer)]
+
+#[macro_use]
+extern crate another_proc_macro;
+
+use another_proc_macro::{pointee, AnotherMacro};
+
+#[derive(core::marker::SmartPointer)]
+#[repr(transparent)]
+pub struct Ptr<'a, #[pointee] T: ?Sized> {
+ data: &'a mut T,
+}
+
+#[pointee]
+fn f() {}
+
+#[derive(AnotherMacro)]
+#[pointee]
+struct MyStruct;
+
+fn main() {}
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout
new file mode 100644
index 0000000..c649b7a
--- /dev/null
+++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout
@@ -0,0 +1,43 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ check-pass
+//@ aux-build: another-proc-macro.rs
+//@ compile-flags: -Zunpretty=expanded
+
+#![feature(derive_smart_pointer)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+#[macro_use]
+extern crate another_proc_macro;
+
+use another_proc_macro::{pointee, AnotherMacro};
+
+#[repr(transparent)]
+pub struct Ptr<'a, #[pointee] T: ?Sized> {
+ data: &'a mut T,
+}
+#[automatically_derived]
+impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized>
+ ::core::ops::DispatchFromDyn<Ptr<'a, __S>> for Ptr<'a, T> {
+}
+#[automatically_derived]
+impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized>
+ ::core::ops::CoerceUnsized<Ptr<'a, __S>> for Ptr<'a, T> {
+}
+
+
+
+const _: () =
+ {
+ const POINTEE_MACRO_ATTR_DERIVED: () = ();
+ };
+#[pointee]
+struct MyStruct;
+const _: () =
+ {
+ const ANOTHER_MACRO_DERIVED: () = ();
+ };
+fn main() {}
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs
new file mode 100644
index 0000000..489665e
--- /dev/null
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs
@@ -0,0 +1,20 @@
+// This test certify that we can mix attribute macros from Rust and external proc-macros.
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// `#[pointee]`.
+// The scoping rule should allow the use of the said two attributes when external proc-macros
+// are in scope.
+
+//@ check-pass
+//@ aux-build: another-proc-macro.rs
+//@ compile-flags: -Zunpretty=expanded
+
+#![feature(derive_smart_pointer)]
+
+#[macro_use]
+extern crate another_proc_macro;
+
+#[pointee]
+fn f() {}
+
+#[default]
+fn g() {}
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
new file mode 100644
index 0000000..f314f6e
--- /dev/null
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
@@ -0,0 +1,30 @@
+#![feature(prelude_import)]
+#![no_std]
+// This test certify that we can mix attribute macros from Rust and external proc-macros.
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// `#[pointee]`.
+// The scoping rule should allow the use of the said two attributes when external proc-macros
+// are in scope.
+
+//@ check-pass
+//@ aux-build: another-proc-macro.rs
+//@ compile-flags: -Zunpretty=expanded
+
+#![feature(derive_smart_pointer)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+#[macro_use]
+extern crate another_proc_macro;
+
+
+const _: () =
+ {
+ const POINTEE_MACRO_ATTR_DERIVED: () = ();
+ };
+const _: () =
+ {
+ const DEFAULT_MACRO_ATTR_DERIVED: () = ();
+ };
diff --git a/tests/ui/extern/extern-main-issue-86110.stderr b/tests/ui/extern/extern-main-issue-86110.stderr
index 8a3262f..d69f4e6 100644
--- a/tests/ui/extern/extern-main-issue-86110.stderr
+++ b/tests/ui/extern/extern-main-issue-86110.stderr
@@ -2,7 +2,7 @@
--> $DIR/extern-main-issue-86110.rs:4:5
|
LL | fn main();
- | ^^^^^^^^^
+ | ^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
index 3257a9c..7b4764e 100644
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
+++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
@@ -3,7 +3,6 @@
#[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer'
#[repr(transparent)]
struct MyPointer<'a, #[pointee] T: ?Sized> {
- //~^ ERROR the `#[pointee]` attribute is an experimental feature
ptr: &'a T,
}
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
index 1950193..ea4d127 100644
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
+++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
@@ -8,16 +8,6 @@
= help: add `#![feature(derive_smart_pointer)]` 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]: the `#[pointee]` attribute is an experimental feature
- --> $DIR/feature-gate-derive-smart-pointer.rs:5:22
- |
-LL | struct MyPointer<'a, #[pointee] T: ?Sized> {
- | ^^^^^^^^^^
- |
- = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
- = help: add `#![feature(derive_smart_pointer)]` 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]: use of unstable library feature 'derive_smart_pointer'
--> $DIR/feature-gate-derive-smart-pointer.rs:1:5
|
@@ -28,6 +18,6 @@
= help: add `#![feature(derive_smart_pointer)]` 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: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs b/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs
deleted file mode 100644
index 9eba415..0000000
--- a/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#[unsafe(no_mangle)] //~ ERROR [E0658]
-extern "C" fn foo() {
-
-}
-
-fn main() {
- foo();
-}
diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr b/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr
deleted file mode 100644
index dfcea75..0000000
--- a/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: `#[unsafe()]` markers for attributes are experimental
- --> $DIR/feature-gate-unsafe-attributes.rs:1:3
- |
-LL | #[unsafe(no_mangle)]
- | ^^^^^^
- |
- = note: see issue #123757 <https://github.com/rust-lang/rust/issues/123757> for more information
- = help: add `#![feature(unsafe_attributes)]` 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: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/foreign/foreign-safe-fn-arg-mismatch.rs b/tests/ui/foreign/foreign-safe-fn-arg-mismatch.rs
new file mode 100644
index 0000000..bb1052b
--- /dev/null
+++ b/tests/ui/foreign/foreign-safe-fn-arg-mismatch.rs
@@ -0,0 +1,13 @@
+// Make sure we don't ICE when a foreign fn doesn't implement `Fn` due to arg mismatch.
+
+unsafe extern "Rust" {
+ pub safe fn foo();
+ pub safe fn bar(x: u32);
+}
+
+fn test(_: impl Fn(i32)) {}
+
+fn main() {
+ test(foo); //~ ERROR function is expected to take 1 argument, but it takes 0 arguments
+ test(bar); //~ ERROR type mismatch in function arguments
+}
diff --git a/tests/ui/foreign/foreign-safe-fn-arg-mismatch.stderr b/tests/ui/foreign/foreign-safe-fn-arg-mismatch.stderr
new file mode 100644
index 0000000..73ccecf
--- /dev/null
+++ b/tests/ui/foreign/foreign-safe-fn-arg-mismatch.stderr
@@ -0,0 +1,44 @@
+error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
+ --> $DIR/foreign-safe-fn-arg-mismatch.rs:11:10
+ |
+LL | pub safe fn foo();
+ | ------------------ takes 0 arguments
+...
+LL | test(foo);
+ | ---- ^^^ expected function that takes 1 argument
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `test`
+ --> $DIR/foreign-safe-fn-arg-mismatch.rs:8:17
+ |
+LL | fn test(_: impl Fn(i32)) {}
+ | ^^^^^^^ required by this bound in `test`
+
+error[E0631]: type mismatch in function arguments
+ --> $DIR/foreign-safe-fn-arg-mismatch.rs:12:10
+ |
+LL | pub safe fn bar(x: u32);
+ | ------------------------ found signature defined here
+...
+LL | test(bar);
+ | ---- ^^^ expected due to this
+ | |
+ | required by a bound introduced by this call
+ |
+ = note: expected function signature `fn(i32) -> _`
+ found function signature `fn(u32) -> _`
+note: required by a bound in `test`
+ --> $DIR/foreign-safe-fn-arg-mismatch.rs:8:17
+ |
+LL | fn test(_: impl Fn(i32)) {}
+ | ^^^^^^^ required by this bound in `test`
+help: consider wrapping the function in a closure
+ |
+LL | test(|arg0: i32| bar(/* u32 */));
+ | +++++++++++ +++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0593, E0631.
+For more information about an error, try `rustc --explain E0593`.
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
index d9a4960..55983a4 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
@@ -7,13 +7,13 @@
--> $DIR/safe-intrinsic-mismatch.rs:11:5
|
LL | fn size_of<T>() -> usize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
--> $DIR/safe-intrinsic-mismatch.rs:11:5
|
LL | fn size_of<T>() -> usize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stock.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stock.stderr
index 6864c0f..c59e357 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stock.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stock.stderr
@@ -2,13 +2,13 @@
--> $DIR/safe-intrinsic-mismatch.rs:11:5
|
LL | fn size_of<T>() -> usize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
--> $DIR/safe-intrinsic-mismatch.rs:11:5
|
LL | fn size_of<T>() -> usize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/issues/issue-16725.stderr b/tests/ui/issues/issue-16725.stderr
index a4a406b..dcb7d58 100644
--- a/tests/ui/issues/issue-16725.stderr
+++ b/tests/ui/issues/issue-16725.stderr
@@ -8,7 +8,7 @@
--> $DIR/auxiliary/issue-16725.rs:2:5
|
LL | fn bar();
- | ^^^^^^^^
+ | ^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr
index 43c8cde..f75ff6d 100644
--- a/tests/ui/lint/clashing-extern-fn.stderr
+++ b/tests/ui/lint/clashing-extern-fn.stderr
@@ -21,10 +21,10 @@
--> $DIR/clashing-extern-fn.rs:14:13
|
LL | fn clash(x: u8);
- | --------------- `clash` previously declared here
+ | ---------------- `clash` previously declared here
...
LL | fn clash(x: u64);
- | ^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn(u8)`
found `unsafe extern "C" fn(u64)`
@@ -41,7 +41,7 @@
| --------------------------------- `extern_link_name` previously declared here
...
LL | fn extern_link_name(x: u32);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn(i16)`
found `unsafe extern "C" fn(u32)`
@@ -50,7 +50,7 @@
--> $DIR/clashing-extern-fn.rs:55:9
|
LL | fn some_other_new_name(x: i16);
- | ------------------------------ `some_other_new_name` previously declared here
+ | ------------------------------- `some_other_new_name` previously declared here
...
LL | #[link_name = "some_other_new_name"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
@@ -74,10 +74,10 @@
--> $DIR/clashing-extern-fn.rs:72:9
|
LL | fn different_mod(x: u8);
- | ----------------------- `different_mod` previously declared here
+ | ------------------------ `different_mod` previously declared here
...
LL | fn different_mod(x: u64);
- | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn(u8)`
found `unsafe extern "C" fn(u64)`
@@ -86,10 +86,10 @@
--> $DIR/clashing-extern-fn.rs:82:9
|
LL | fn variadic_decl(x: u8, ...);
- | ---------------------------- `variadic_decl` previously declared here
+ | ----------------------------- `variadic_decl` previously declared here
...
LL | fn variadic_decl(x: u8);
- | ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn(u8, ...)`
found `unsafe extern "C" fn(u8)`
@@ -98,10 +98,10 @@
--> $DIR/clashing-extern-fn.rs:142:13
|
LL | fn weigh_banana(count: *const Banana) -> u64;
- | -------------------------------------------- `weigh_banana` previously declared here
+ | --------------------------------------------- `weigh_banana` previously declared here
...
LL | fn weigh_banana(count: *const Banana) -> u64;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn(*const one::Banana) -> u64`
found `unsafe extern "C" fn(*const three::Banana) -> u64`
@@ -110,10 +110,10 @@
--> $DIR/clashing-extern-fn.rs:171:13
|
LL | fn draw_point(p: Point);
- | ----------------------- `draw_point` previously declared here
+ | ------------------------ `draw_point` previously declared here
...
LL | fn draw_point(p: Point);
- | ^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn(sameish_members::a::Point)`
found `unsafe extern "C" fn(sameish_members::b::Point)`
@@ -122,10 +122,10 @@
--> $DIR/clashing-extern-fn.rs:197:13
|
LL | fn origin() -> Point3;
- | --------------------- `origin` previously declared here
+ | ---------------------- `origin` previously declared here
...
LL | fn origin() -> Point3;
- | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3`
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
@@ -134,10 +134,10 @@
--> $DIR/clashing-extern-fn.rs:220:13
|
LL | fn transparent_incorrect() -> T;
- | ------------------------------- `transparent_incorrect` previously declared here
+ | -------------------------------- `transparent_incorrect` previously declared here
...
LL | fn transparent_incorrect() -> isize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> T`
found `unsafe extern "C" fn() -> isize`
@@ -146,10 +146,10 @@
--> $DIR/clashing-extern-fn.rs:259:13
|
LL | fn missing_return_type() -> usize;
- | --------------------------------- `missing_return_type` previously declared here
+ | ---------------------------------- `missing_return_type` previously declared here
...
LL | fn missing_return_type();
- | ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> usize`
found `unsafe extern "C" fn()`
@@ -158,10 +158,10 @@
--> $DIR/clashing-extern-fn.rs:277:13
|
LL | fn non_zero_usize() -> core::num::NonZero<usize>;
- | ------------------------------------------------ `non_zero_usize` previously declared here
+ | ------------------------------------------------- `non_zero_usize` previously declared here
...
LL | fn non_zero_usize() -> usize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> NonZero<usize>`
found `unsafe extern "C" fn() -> usize`
@@ -170,10 +170,10 @@
--> $DIR/clashing-extern-fn.rs:279:13
|
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
- | ---------------------------------------------- `non_null_ptr` previously declared here
+ | ----------------------------------------------- `non_null_ptr` previously declared here
...
LL | fn non_null_ptr() -> *const usize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> NonNull<usize>`
found `unsafe extern "C" fn() -> *const usize`
@@ -182,10 +182,10 @@
--> $DIR/clashing-extern-fn.rs:373:13
|
LL | fn option_non_zero_usize_incorrect() -> usize;
- | --------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
+ | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
...
LL | fn option_non_zero_usize_incorrect() -> isize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> usize`
found `unsafe extern "C" fn() -> isize`
@@ -194,10 +194,10 @@
--> $DIR/clashing-extern-fn.rs:375:13
|
LL | fn option_non_null_ptr_incorrect() -> *const usize;
- | -------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
+ | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
...
LL | fn option_non_null_ptr_incorrect() -> *const isize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> *const usize`
found `unsafe extern "C" fn() -> *const isize`
@@ -206,10 +206,10 @@
--> $DIR/clashing-extern-fn.rs:429:13
|
LL | fn hidden_niche_transparent_no_niche() -> usize;
- | ----------------------------------------------- `hidden_niche_transparent_no_niche` previously declared here
+ | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
...
LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> usize`
found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
@@ -218,10 +218,10 @@
--> $DIR/clashing-extern-fn.rs:433:13
|
LL | fn hidden_niche_unsafe_cell() -> usize;
- | -------------------------------------- `hidden_niche_unsafe_cell` previously declared here
+ | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
...
LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZero<usize>>>;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn() -> usize`
found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZero<usize>>>`
diff --git a/tests/ui/lint/issue-1866.stderr b/tests/ui/lint/issue-1866.stderr
index 36d3238..d19a134 100644
--- a/tests/ui/lint/issue-1866.stderr
+++ b/tests/ui/lint/issue-1866.stderr
@@ -2,10 +2,10 @@
--> $DIR/issue-1866.rs:23:13
|
LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
- | ----------------------------------------------------------- `rust_task_is_unwinding` previously declared here
+ | ------------------------------------------------------------ `rust_task_is_unwinding` previously declared here
...
LL | pub fn rust_task_is_unwinding(rt: *const rust_task) -> bool;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn(*const usize) -> bool`
found `unsafe extern "C" fn(*const bool) -> bool`
diff --git a/tests/ui/lint/lint-attr-everywhere-late.stderr b/tests/ui/lint/lint-attr-everywhere-late.stderr
index ddc3190..1937b61 100644
--- a/tests/ui/lint/lint-attr-everywhere-late.stderr
+++ b/tests/ui/lint/lint-attr-everywhere-late.stderr
@@ -406,10 +406,10 @@
--> $DIR/lint-attr-everywhere-late.rs:123:5
|
LL | fn clashing1();
- | -------------- `clashing1` previously declared here
+ | --------------- `clashing1` previously declared here
...
LL | fn clashing1(_: i32);
- | ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn()`
found `unsafe extern "C" fn(i32)`
@@ -423,10 +423,10 @@
--> $DIR/lint-attr-everywhere-late.rs:128:5
|
LL | fn clashing2();
- | -------------- `clashing2` previously declared here
+ | --------------- `clashing2` previously declared here
...
LL | fn clashing2(_: i32);
- | ^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
+ | ^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
= note: expected `unsafe extern "C" fn()`
found `unsafe extern "C" fn(i32)`
diff --git a/tests/ui/lint/lint-missing-doc.stderr b/tests/ui/lint/lint-missing-doc.stderr
index 4e9ee4f..5165ccc 100644
--- a/tests/ui/lint/lint-missing-doc.stderr
+++ b/tests/ui/lint/lint-missing-doc.stderr
@@ -116,7 +116,7 @@
--> $DIR/lint-missing-doc.rs:196:5
|
LL | pub fn extern_fn_undocumented(f: f32) -> f32;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
--> $DIR/lint-missing-doc.rs:201:5
diff --git a/tests/ui/lint/unreachable_pub.stderr b/tests/ui/lint/unreachable_pub.stderr
index 705a537..65f45fb 100644
--- a/tests/ui/lint/unreachable_pub.stderr
+++ b/tests/ui/lint/unreachable_pub.stderr
@@ -130,7 +130,7 @@
--> $DIR/unreachable_pub.rs:48:9
|
LL | pub fn catalyze() -> bool;
- | ---^^^^^^^^^^^^^^^^^^^^^^
+ | ---^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: consider restricting its visibility: `pub(crate)`
|
diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr
index 831579c..f221f92 100644
--- a/tests/ui/macros/macro-match-nonterminal.stderr
+++ b/tests/ui/macros/macro-match-nonterminal.stderr
@@ -1,14 +1,14 @@
error: missing fragment specifier
- --> $DIR/macro-match-nonterminal.rs:2:8
+ --> $DIR/macro-match-nonterminal.rs:2:6
|
LL | ($a, $b) => {
- | ^
+ | ^^
error: missing fragment specifier
- --> $DIR/macro-match-nonterminal.rs:2:8
+ --> $DIR/macro-match-nonterminal.rs:2:6
|
LL | ($a, $b) => {
- | ^
+ | ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
@@ -27,10 +27,10 @@
Future incompatibility report: Future breakage diagnostic:
error: missing fragment specifier
- --> $DIR/macro-match-nonterminal.rs:2:8
+ --> $DIR/macro-match-nonterminal.rs:2:6
|
LL | ($a, $b) => {
- | ^
+ | ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
index f06c1f9..37409dd 100644
--- a/tests/ui/macros/stringify.rs
+++ b/tests/ui/macros/stringify.rs
@@ -33,8 +33,6 @@
macro_rules! ty { ($ty:ty) => { stringify!($ty) }; }
macro_rules! vis { ($vis:vis) => { stringify!($vis) }; }
-// Use this when AST pretty-printing and TokenStream pretty-printing give
-// the same result (which is preferable.)
macro_rules! c1 {
($frag:ident, [$($tt:tt)*], $s:literal) => {
// Prior to #125174:
@@ -66,6 +64,8 @@ fn test_block() {
} ],
"{ let _; true }"
);
+
+ // Attributes are not allowed on vanilla blocks.
}
#[test]
@@ -332,6 +332,20 @@ fn test_expr() {
// ExprKind::FormatArgs: untestable because this test works pre-expansion.
// ExprKind::Err: untestable.
+
+ // Ones involving attributes.
+ c1!(expr, [ #[aa] 1 ], "#[aa] 1");
+ c1!(expr, [ #[aa] #[bb] x ], "#[aa] #[bb] x");
+ c1!(expr, [ #[aa] 1 + 2 ], "#[aa] 1 + 2");
+ c1!(expr, [ #[aa] x + 2 ], "#[aa] x + 2");
+ c1!(expr, [ #[aa] 1 / #[bb] 2 ], "#[aa] 1 / #[bb] 2");
+ c1!(expr, [ #[aa] x / #[bb] 2 ], "#[aa] x / #[bb] 2");
+ c1!(expr, [ 1 << #[bb] 2 ], "1 << #[bb] 2");
+ c1!(expr, [ x << #[bb] 2 ], "x << #[bb] 2");
+ c1!(expr, [ #[aa] (1 + 2) ], "#[aa] (1 + 2)");
+ c1!(expr, [ #[aa] #[bb] (x + 2) ], "#[aa] #[bb] (x + 2)");
+ c1!(expr, [ #[aa] x[0].p ], "#[aa] x[0].p");
+ c1!(expr, [ #[aa] { #![bb] 0 } ], "#[aa] { #![bb] 0 }");
}
#[test]
@@ -484,6 +498,11 @@ macro_rules! stringify {
"macro_rules! stringify { () => {}; }"
);
c1!(item, [ pub macro stringify() {} ], "pub macro stringify() {}");
+
+ // Ones involving attributes.
+ c1!(item, [ #[aa] mod m; ], "#[aa] mod m;");
+ c1!(item, [ mod m { #![bb] } ], "mod m { #![bb] }");
+ c1!(item, [ #[aa] mod m { #![bb] } ], "#[aa] mod m { #![bb] }");
}
#[test]
@@ -492,6 +511,8 @@ fn test_meta() {
c1!(meta, [ k = "v" ], "k = \"v\"");
c1!(meta, [ list(k1, k2 = "v") ], "list(k1, k2 = \"v\")");
c1!(meta, [ serde::k ], "serde::k");
+
+ // Attributes are not allowed on metas.
}
#[test]
@@ -580,6 +601,8 @@ fn test_pat() {
c1!(pat, [ mac!(...) ], "mac!(...)");
c1!(pat, [ mac![...] ], "mac![...]");
c1!(pat, [ mac! { ... } ], "mac! { ... }");
+
+ // Attributes are not allowed on patterns.
}
#[test]
@@ -593,6 +616,8 @@ fn test_path() {
c1!(path, [ Self::<'static> ], "Self::<'static>");
c1!(path, [ Self() ], "Self()");
c1!(path, [ Self() -> () ], "Self() -> ()");
+
+ // Attributes are not allowed on paths.
}
#[test]
@@ -622,6 +647,20 @@ fn test_stmt() {
c1!(stmt, [ mac!(...) ], "mac!(...)");
c1!(stmt, [ mac![...] ], "mac![...]");
c1!(stmt, [ mac! { ... } ], "mac! { ... }");
+
+ // Ones involving attributes.
+ c1!(stmt, [ #[aa] 1 ], "#[aa] 1");
+ c1!(stmt, [ #[aa] #[bb] x ], "#[aa] #[bb] x");
+ c1!(stmt, [ #[aa] 1 as u32 ], "#[aa] 1 as u32");
+ c1!(stmt, [ #[aa] x as u32 ], "#[aa] x as u32");
+ c1!(stmt, [ #[aa] 1 .. #[bb] 2 ], "#[aa] 1 .. #[bb] 2");
+ c1!(stmt, [ #[aa] x .. #[bb] 2 ], "#[aa] x .. #[bb] 2");
+ c1!(stmt, [ 1 || #[bb] 2 ], "1 || #[bb] 2");
+ c1!(stmt, [ x || #[bb] 2 ], "x || #[bb] 2");
+ c1!(stmt, [ #[aa] (1 + 2) ], "#[aa] (1 + 2)");
+ c1!(stmt, [ #[aa] #[bb] (x + 2) ], "#[aa] #[bb] (x + 2)");
+ c1!(stmt, [ #[aa] x[0].p ], "#[aa] x[0].p");
+ c1!(stmt, [ #[aa] { #![bb] 0 } ], "#[aa] { #![bb] 0 }");
}
#[test]
@@ -708,6 +747,8 @@ fn test_ty() {
// TyKind::CVarArgs
// FIXME: todo
+
+ // Attributes are not allowed on types.
}
#[test]
@@ -732,6 +773,8 @@ fn test_vis() {
macro_rules! inherited_vis { ($vis:vis struct) => { vis!($vis) }; }
assert_eq!(inherited_vis!(struct), "");
assert_eq!(stringify!(), "");
+
+ // Attributes are not allowed on visibilities.
}
macro_rules! p {
diff --git a/tests/ui/privacy/private-in-public-warn.stderr b/tests/ui/privacy/private-in-public-warn.stderr
index 3f7b8c2..3743879 100644
--- a/tests/ui/privacy/private-in-public-warn.stderr
+++ b/tests/ui/privacy/private-in-public-warn.stderr
@@ -100,7 +100,7 @@
--> $DIR/private-in-public-warn.rs:28:9
|
LL | pub fn ef1(arg: Priv);
- | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)`
+ | ^^^^^^^^^^^^^^^^^^^^^^ function `types::ef1` is reachable at visibility `pub(crate)`
|
note: but type `types::Priv` is only usable at visibility `pub(self)`
--> $DIR/private-in-public-warn.rs:9:5
@@ -112,7 +112,7 @@
--> $DIR/private-in-public-warn.rs:29:9
|
LL | pub fn ef2() -> Priv;
- | ^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)`
+ | ^^^^^^^^^^^^^^^^^^^^^ function `types::ef2` is reachable at visibility `pub(crate)`
|
note: but type `types::Priv` is only usable at visibility `pub(self)`
--> $DIR/private-in-public-warn.rs:9:5
diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr
index 7866af5..b766b5c 100644
--- a/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr
+++ b/tests/ui/rfcs/rfc-2627-raw-dylib/multiple-declarations.stderr
@@ -2,7 +2,7 @@
--> $DIR/multiple-declarations.rs:13:9
|
LL | fn f(x: i32);
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr
index d7c7344..ef02240 100644
--- a/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr
+++ b/tests/ui/rfcs/rfc-2627-raw-dylib/unsupported-abi.stderr
@@ -2,7 +2,7 @@
--> $DIR/unsupported-abi.rs:6:5
|
LL | fn f(x: i32);
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.rs b/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.rs
index c6f9115..f3b8645 100644
--- a/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.rs
+++ b/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.rs
@@ -1,5 +1,4 @@
#![deny(rust_2024_compatibility)]
-#![feature(unsafe_attributes)]
#[no_mangle]
//~^ ERROR: unsafe attribute used without unsafe
diff --git a/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr b/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr
index f0689d9..4629a15 100644
--- a/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr
+++ b/tests/ui/rust-2024/unsafe-attributes/in_2024_compatibility.stderr
@@ -1,5 +1,5 @@
error: unsafe attribute used without unsafe
- --> $DIR/in_2024_compatibility.rs:4:3
+ --> $DIR/in_2024_compatibility.rs:3:3
|
LL | #[no_mangle]
| ^^^^^^^^^ usage of unsafe attribute
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs
index 279ced2..7c919fe 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs
@@ -4,7 +4,6 @@
//@[edition2024] compile-flags: -Zunstable-options
//@ check-pass
-#![feature(unsafe_attributes)]
#[unsafe(no_mangle)]
extern "C" fn foo() {}
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
index 6ebdff0..586881d 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed
@@ -1,5 +1,4 @@
//@ run-rustfix
-#![feature(unsafe_attributes)]
#![deny(unsafe_attr_outside_unsafe)]
macro_rules! tt {
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
index c78ff45..03e122c 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs
@@ -1,5 +1,4 @@
//@ run-rustfix
-#![feature(unsafe_attributes)]
#![deny(unsafe_attr_outside_unsafe)]
macro_rules! tt {
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
index c95984f..64debc5 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr
@@ -1,5 +1,5 @@
error: unsafe attribute used without unsafe
- --> $DIR/unsafe-attributes-fix.rs:44:6
+ --> $DIR/unsafe-attributes-fix.rs:43:6
|
LL | tt!([no_mangle]);
| ^^^^^^^^^ usage of unsafe attribute
@@ -7,7 +7,7 @@
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
= note: for more information, see issue #123757 <https://github.com/rust-lang/rust/issues/123757>
note: the lint level is defined here
- --> $DIR/unsafe-attributes-fix.rs:3:9
+ --> $DIR/unsafe-attributes-fix.rs:2:9
|
LL | #![deny(unsafe_attr_outside_unsafe)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@
| +++++++ +
error: unsafe attribute used without unsafe
- --> $DIR/unsafe-attributes-fix.rs:14:11
+ --> $DIR/unsafe-attributes-fix.rs:13:11
|
LL | #[$e]
| ^^ usage of unsafe attribute
@@ -34,7 +34,7 @@
| +++++++ +
error: unsafe attribute used without unsafe
- --> $DIR/unsafe-attributes-fix.rs:48:7
+ --> $DIR/unsafe-attributes-fix.rs:47:7
|
LL | meta!(no_mangle);
| ^^^^^^^^^ usage of unsafe attribute
@@ -47,7 +47,7 @@
| +++++++ +
error: unsafe attribute used without unsafe
- --> $DIR/unsafe-attributes-fix.rs:51:8
+ --> $DIR/unsafe-attributes-fix.rs:50:8
|
LL | meta2!(export_name = "baw");
| ^^^^^^^^^^^ usage of unsafe attribute
@@ -60,7 +60,7 @@
| +++++++ +
error: unsafe attribute used without unsafe
- --> $DIR/unsafe-attributes-fix.rs:23:11
+ --> $DIR/unsafe-attributes-fix.rs:22:11
|
LL | #[$e = $l]
| ^^ usage of unsafe attribute
@@ -77,7 +77,7 @@
| +++++++ +
error: unsafe attribute used without unsafe
- --> $DIR/unsafe-attributes-fix.rs:56:3
+ --> $DIR/unsafe-attributes-fix.rs:55:3
|
LL | #[no_mangle]
| ^^^^^^^^^ usage of unsafe attribute
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.edition2024.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.edition2024.stderr
index 35475d6..fb697e1 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.edition2024.stderr
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.edition2024.stderr
@@ -1,5 +1,5 @@
error: unsafe attribute used without unsafe
- --> $DIR/unsafe-attributes.rs:9:3
+ --> $DIR/unsafe-attributes.rs:8:3
|
LL | #[no_mangle]
| ^^^^^^^^^ usage of unsafe attribute
diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.rs
index 3a6af9d..f6f2994 100644
--- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.rs
+++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes.rs
@@ -4,7 +4,6 @@
//@[edition2024] edition:2024
//@[edition2024] compile-flags: -Zunstable-options
-#![feature(unsafe_attributes)]
#[no_mangle] //[edition2024]~ ERROR: unsafe attribute used without unsafe
extern "C" fn foo() {}
diff --git a/tests/ui/rust-2024/unsafe-before_exec.e2024.stderr b/tests/ui/rust-2024/unsafe-before_exec.e2024.stderr
new file mode 100644
index 0000000..2798ccd
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-before_exec.e2024.stderr
@@ -0,0 +1,11 @@
+error[E0133]: call to unsafe function `before_exec` is unsafe and requires unsafe block
+ --> $DIR/unsafe-before_exec.rs:14:5
+ |
+LL | cmd.before_exec(|| Ok(()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/tests/ui/rust-2024/unsafe-before_exec.rs b/tests/ui/rust-2024/unsafe-before_exec.rs
new file mode 100644
index 0000000..540394d
--- /dev/null
+++ b/tests/ui/rust-2024/unsafe-before_exec.rs
@@ -0,0 +1,17 @@
+//@ revisions: e2021 e2024
+//@ only-unix
+//@[e2021] edition: 2021
+//@[e2021] check-pass
+//@[e2024] edition: 2024
+//@[e2024] compile-flags: -Zunstable-options
+
+use std::process::Command;
+use std::os::unix::process::CommandExt;
+
+#[allow(deprecated)]
+fn main() {
+ let mut cmd = Command::new("sleep");
+ cmd.before_exec(|| Ok(()));
+ //[e2024]~^ ERROR call to unsafe function `before_exec` is unsafe
+ drop(cmd); // we don't actually run the command.
+}
diff --git a/tests/ui/typeck/const-in-fn-call-generics.rs b/tests/ui/typeck/const-in-fn-call-generics.rs
new file mode 100644
index 0000000..675dbcc
--- /dev/null
+++ b/tests/ui/typeck/const-in-fn-call-generics.rs
@@ -0,0 +1,16 @@
+fn generic<const N: u32>() {}
+
+trait Collate<const A: u32> {
+ type Pass;
+ fn collate(self) -> Self::Pass;
+}
+
+impl<const B: u32> Collate<B> for i32 {
+ type Pass = ();
+ fn collate(self) -> Self::Pass {
+ generic::<{ true }>()
+ //~^ ERROR: mismatched types
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/const-in-fn-call-generics.stderr b/tests/ui/typeck/const-in-fn-call-generics.stderr
new file mode 100644
index 0000000..12dd454
--- /dev/null
+++ b/tests/ui/typeck/const-in-fn-call-generics.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+ --> $DIR/const-in-fn-call-generics.rs:11:21
+ |
+LL | generic::<{ true }>()
+ | ^^^^ expected `u32`, found `bool`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.