diff options
470 files changed, 5579 insertions, 3080 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c17dfd8c8e..44f789c592b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -322,7 +322,7 @@ jobs: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-latest + os: macos-12-xl - name: dist-apple-various env: SCRIPT: "./x.py dist bootstrap --include-default-paths --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim" @@ -333,7 +333,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: dist-x86_64-apple-alt env: SCRIPT: "./x.py dist bootstrap --include-default-paths" @@ -344,7 +344,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: x86_64-apple-1 env: SCRIPT: "./x.py --stage 2 test --exclude tests/ui --exclude tests/rustdoc --exclude tests/run-make-fulldeps" @@ -355,7 +355,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: x86_64-apple-2 env: SCRIPT: "./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps" @@ -366,7 +366,7 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 - os: macos-latest + os: macos-12-xl - name: dist-aarch64-apple env: SCRIPT: "./x.py dist bootstrap --include-default-paths --stage 2" @@ -381,7 +381,7 @@ jobs: NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 JEMALLOC_SYS_WITH_LG_PAGE: 14 - os: macos-latest + os: macos-12-xl - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" diff --git a/.mailmap b/.mailmap index 726d4c3d1d2..715bc4d3085 100644 --- a/.mailmap +++ b/.mailmap @@ -15,7 +15,7 @@ Adrien Tétar <adri-from-59@hotmail.fr> Ahmed Charles <ahmedcharles@gmail.com> <acharles@outlook.com> Alan Egerton <eggyal@gmail.com> Alan Stoate <alan.stoate@gmail.com> -Albert Larsan <albert.larsan@gmail.com> Albert Larsan <74931857+albertlarsan68@users.noreply.github.com> +Albert Larsan <albert.larsan@gmail.com> <74931857+albertlarsan68@users.noreply.github.com> Alessandro Decina <alessandro.d@gmail.com> Alex Burka <durka42+github@gmail.com> Alex Burka <aburka@seas.upenn.edu> Alex Hansen <ahansen2@trinity.edu> diff --git a/Cargo.lock b/Cargo.lock index bff657b35fb..5530541cdd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2319,9 +2319,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" dependencies = [ "rustc-std-workspace-core", ] @@ -3801,6 +3801,8 @@ dependencies = [ "rustc_span", "rustc_symbol_mangling", "rustc_target", + "serde", + "serde_json", "smallvec", "tempfile", "tracing", diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 81efdaa44b3..3a0af04f9eb 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -225,7 +225,7 @@ impl AssocOp { AssignOp(_) | // `{ 42 } +=` As | // `{ 42 } as usize` // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect - // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery. + // NotEqual | // `{ 42 } != { 42 }` struct literals parser recovery. Colon, // `{ 42 }: usize` ) } diff --git a/compiler/rustc_ast_lowering/locales/en-US.ftl b/compiler/rustc_ast_lowering/locales/en-US.ftl index a2837deafde..3ccd84398ec 100644 --- a/compiler/rustc_ast_lowering/locales/en-US.ftl +++ b/compiler/rustc_ast_lowering/locales/en-US.ftl @@ -22,9 +22,6 @@ ast_lowering_misplaced_impl_trait = ast_lowering_misplaced_assoc_ty_binding = associated type bounds are only allowed in where clauses and function signatures, not in {$position} -ast_lowering_rustc_box_attribute_error = - #[rustc_box] requires precisely one argument and no other attributes are allowed - ast_lowering_underscore_expr_lhs_assign = in expressions, `_` can only be used on the left-hand side of an assignment .label = `_` not allowed here diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index def74c2adee..5e6b6050bc0 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -88,13 +88,6 @@ pub struct MisplacedAssocTyBinding<'a> { } #[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_rustc_box_attribute_error)] -pub struct RustcBoxAttributeError { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic, Clone, Copy)] #[diag(ast_lowering_underscore_expr_lhs_assign)] pub struct UnderscoreExprLhsAssign { #[primary_span] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d4fafe38638..ffb30b1b391 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2,7 +2,7 @@ use super::errors::{ AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure, - RustcBoxAttributeError, UnderscoreExprLhsAssign, + UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; @@ -83,15 +83,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(f, args) => { - if e.attrs.get(0).map_or(false, |a| a.has_name(sym::rustc_box)) { - if let [inner] = &args[..] && e.attrs.len() == 1 { - let kind = hir::ExprKind::Box(self.lower_expr(&inner)); - return hir::Expr { hir_id, kind, span: self.lower_span(e.span) }; - } else { - let guar = self.tcx.sess.emit_err(RustcBoxAttributeError { span: e.span }); - hir::ExprKind::Err(guar) - } - } else if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { + if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) } else { let f = self.lower_expr(f); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7325bce6055..41295f2b7b6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1339,13 +1339,19 @@ impl<'hir> LoweringContext<'_, 'hir> { .map(|predicate| self.lower_where_predicate(predicate)), ); - let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = - self.lower_generic_params_mut(&generics.params).collect(); + let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self + .lower_generic_params_mut(&generics.params, hir::GenericParamSource::Generics) + .collect(); // Introduce extra lifetimes if late resolution tells us to. let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) + self.lifetime_res_to_generic_param( + ident, + node_id, + res, + hir::GenericParamSource::Generics, + ) })); let has_where_clause_predicates = !generics.where_clause.predicates.is_empty(); @@ -1449,7 +1455,8 @@ impl<'hir> LoweringContext<'_, 'hir> { span, }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { hir_id: self.next_id(), - bound_generic_params: self.lower_generic_params(bound_generic_params), + bound_generic_params: self + .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), bounded_ty: self .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5d78d914b6d..b20157f2c7c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -804,6 +804,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ident: Ident, node_id: NodeId, res: LifetimeRes, + source: hir::GenericParamSource, ) -> Option<hir::GenericParam<'hir>> { let (name, kind) = match res { LifetimeRes::Param { .. } => { @@ -837,6 +838,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source, }) } @@ -852,11 +854,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { binder: NodeId, generic_params: &[GenericParam], ) -> &'hir [hir::GenericParam<'hir>] { - let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect(); + let mut generic_params: Vec<_> = self + .lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder) + .collect(); let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); debug!(?extra_lifetimes); generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) + self.lifetime_res_to_generic_param(ident, node_id, res, hir::GenericParamSource::Binder) })); let generic_params = self.arena.alloc_from_iter(generic_params); debug!(?generic_params); @@ -1375,8 +1379,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, ); let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); - let (param, bounds, path) = - self.lower_generic_and_bounds(*def_node_id, span, ident, bounds); + let (param, bounds, path) = self.lower_universal_param_and_bounds( + *def_node_id, + span, + ident, + bounds, + ); self.impl_trait_defs.push(param); if let Some(bounds) = bounds { self.impl_trait_bounds.push(bounds); @@ -1530,6 +1538,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source: hir::GenericParamSource::Generics, } }, )); @@ -1598,7 +1607,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item)) } - /// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be + /// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the /// new definition, adds it to the remapping with the definition of the given lifetime and /// returns a list of lifetimes to be lowered afterwards. @@ -1987,6 +1996,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, colon_span: None, + source: hir::GenericParamSource::Generics, } }, )); @@ -2152,16 +2162,25 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_params_mut<'s>( &'s mut self, params: &'s [GenericParam], + source: hir::GenericParamSource, ) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> { - params.iter().map(move |param| self.lower_generic_param(param)) + params.iter().map(move |param| self.lower_generic_param(param, source)) } - fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params)) + fn lower_generic_params( + &mut self, + params: &[GenericParam], + source: hir::GenericParamSource, + ) -> &'hir [hir::GenericParam<'hir>] { + self.arena.alloc_from_iter(self.lower_generic_params_mut(params, source)) } #[instrument(level = "trace", skip(self))] - fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> { + fn lower_generic_param( + &mut self, + param: &GenericParam, + source: hir::GenericParamSource, + ) -> hir::GenericParam<'hir> { let (name, kind) = self.lower_generic_param_kind(param); let hir_id = self.lower_node_id(param.id); @@ -2174,6 +2193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { pure_wrt_drop: self.tcx.sess.contains_name(¶m.attrs, sym::may_dangle), kind, colon_span: param.colon_span.map(|s| self.lower_span(s)), + source, } } @@ -2266,7 +2286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self), ret)] - fn lower_generic_and_bounds( + fn lower_universal_param_and_bounds( &mut self, node_id: NodeId, span: Span, @@ -2286,6 +2306,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, kind: hir::GenericParamKind::Type { default: None, synthetic: true }, colon_span: None, + source: hir::GenericParamSource::Generics, }; let preds = self.lower_generic_bound_predicate( diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1c561375626..2cc009410f4 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -192,7 +192,7 @@ impl<'a> AstValidator<'a> { // We allow these: // - `Option<impl Trait>` // - `option::Option<impl Trait>` - // - `option::Option<T>::Foo<impl Trait> + // - `option::Option<T>::Foo<impl Trait>` // // But not these: // - `<impl Trait>::Foo` diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 4baf1b6aa87..ffe82b46cfd 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -415,7 +415,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x } /// ``` /// - /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`. + /// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`. pub(crate) fn report_region_error( &mut self, fr: RegionVid, @@ -949,7 +949,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); multi_span.push_span_label( ident.span, - "calling this method introduces the `impl`'s 'static` requirement", + "calling this method introduces the `impl`'s `'static` requirement", ); err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span }); err.span_suggestion_verbose( diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 941da2dd3b5..21b5bd7cb94 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -889,7 +889,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// from a universe it can't name; at present, the only way for /// this to be true is if `scc` outlives `'static`. This is /// actually stricter than necessary: ideally, we'd support bounds - /// like `for<'a: 'b`>` that might then allow us to approximate + /// like `for<'a: 'b>` that might then allow us to approximate /// `'a` with `'b` and not `'static`. But it will have to do for /// now. fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index c361357ca21..8132800f107 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -235,7 +235,7 @@ pub(crate) struct RegionValues<N: Idx> { free_regions: SparseBitMatrix<N, RegionVid>, /// Placeholders represent bound regions -- so something like `'a` - /// in for<'a> fn(&'a u32)`. + /// in `for<'a> fn(&'a u32)`. placeholders: SparseBitMatrix<N, PlaceholderIndex>, } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 6aa900f0201..f011cb754cb 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -53,7 +53,7 @@ pub fn expand_env<'cx>( tts: TokenStream, ) -> Box<dyn base::MacResult + 'cx> { let mut exprs = match get_exprs_from_tts(cx, tts) { - Some(exprs) if exprs.is_empty() => { + Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { cx.span_err(sp, "env! takes 1 or 2 arguments"); return DummyResult::any(sp); } @@ -64,28 +64,48 @@ pub fn expand_env<'cx>( let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else { return DummyResult::any(sp); }; - let msg = match exprs.next() { - None => Symbol::intern(&format!("environment variable `{}` not defined", var)), + + let custom_msg = match exprs.next() { + None => None, Some(second) => match expr_to_string(cx, second, "expected string literal") { None => return DummyResult::any(sp), - Some((s, _style)) => s, + Some((s, _style)) => Some(s), }, }; - if exprs.next().is_some() { - cx.span_err(sp, "env! takes 1 or 2 arguments"); - return DummyResult::any(sp); - } - let sp = cx.with_def_site_ctxt(sp); let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern); cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { - cx.span_err(sp, msg.as_str()); + let (msg, help) = match custom_msg { + None => ( + format!("environment variable `{var}` not defined at compile time"), + Some(help_for_missing_env_var(var.as_str())), + ), + Some(s) => (s.to_string(), None), + }; + let mut diag = cx.struct_span_err(sp, &msg); + if let Some(help) = help { + diag.help(help); + } + diag.emit(); return DummyResult::any(sp); } Some(value) => cx.expr_str(sp, value), }; MacEager::expr(e) } + +fn help_for_missing_env_var(var: &str) -> String { + if var.starts_with("CARGO_") + || var.starts_with("DEP_") + || matches!(var, "OUT_DIR" | "OPT_LEVEL" | "PROFILE" | "HOST" | "TARGET") + { + format!( + "Cargo sets build script variables at run time. Use `std::env::var(\"{var}\")` instead" + ) + } else { + format!("Use `std::env::var(\"{var}\")` to read the variable at run time") + } +} diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index f00e9321070..e74aabf2fcb 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -22,7 +22,7 @@ pub(crate) use cpuid::codegen_cpuid_call; pub(crate) use llvm::codegen_llvm_intrinsic_call; use rustc_middle::ty; -use rustc_middle::ty::layout::{HasParamEnv, InitKind}; +use rustc_middle::ty::layout::{HasParamEnv, ValidityRequirement}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::SubstsRef; use rustc_span::symbol::{kw, sym, Symbol}; @@ -628,57 +628,39 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (); intrinsic); let ty = substs.type_at(0); - let layout = fx.layout_of(ty); - if layout.abi.is_uninhabited() { - with_no_trimmed_paths!({ - crate::base::codegen_panic_nounwind( - fx, - &format!("attempted to instantiate uninhabited type `{}`", layout.ty), - source_info, - ) - }); - return; - } - if intrinsic == sym::assert_zero_valid - && !fx - .tcx - .check_validity_of_init((InitKind::Zero, fx.param_env().and(ty))) - .expect("expected to have layout during codegen") - { - with_no_trimmed_paths!({ - crate::base::codegen_panic_nounwind( - fx, - &format!( - "attempted to zero-initialize type `{}`, which is invalid", - layout.ty - ), - source_info, - ); - }); - return; - } + let requirement = ValidityRequirement::from_intrinsic(intrinsic); - if intrinsic == sym::assert_mem_uninitialized_valid - && !fx + if let Some(requirement) = requirement { + let do_panic = !fx .tcx - .check_validity_of_init(( - InitKind::UninitMitigated0x01Fill, - fx.param_env().and(ty), - )) - .expect("expected to have layout during codegen") - { - with_no_trimmed_paths!({ - crate::base::codegen_panic_nounwind( - fx, - &format!( - "attempted to leave type `{}` uninitialized, which is invalid", - layout.ty - ), - source_info, - ) - }); - return; + .check_validity_requirement((requirement, fx.param_env().and(ty))) + .expect("expect to have layout during codegen"); + + if do_panic { + let layout = fx.layout_of(ty); + + with_no_trimmed_paths!({ + crate::base::codegen_panic_nounwind( + fx, + &if layout.abi.is_uninhabited() { + format!("attempted to instantiate uninhabited type `{}`", layout.ty) + } else if requirement == ValidityRequirement::Zero { + format!( + "attempted to zero-initialize type `{}`, which is invalid", + layout.ty + ) + } else { + format!( + "attempted to leave type `{}` uninitialized, which is invalid", + layout.ty + ) + }, + source_info, + ) + }); + return; + } } } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 773c0ebbe59..a7ba2f8b695 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -36,3 +36,5 @@ smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } tempfile = "3.2.0" +serde = { version = "1", features = [ "derive" ]} +serde_json = "1" diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 40f0594b40d..a4ae1b01e86 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -761,6 +761,7 @@ pub(crate) unsafe fn codegen( EmitObj::None => {} } + record_llvm_cgu_instructions_stats(&cgcx.prof, llmod); drop(handlers); } @@ -974,3 +975,23 @@ fn record_artifact_size( self_profiler_ref.artifact_size(artifact_kind, artifact_name.to_string_lossy(), file_size); } } + +fn record_llvm_cgu_instructions_stats(prof: &SelfProfilerRef, llmod: &llvm::Module) { + if !prof.enabled() { + return; + } + + let raw_stats = + llvm::build_string(|s| unsafe { llvm::LLVMRustModuleInstructionStats(&llmod, s) }) + .expect("cannot get module instruction stats"); + + #[derive(serde::Deserialize)] + struct InstructionsStats { + module: String, + total: u64, + } + + let InstructionsStats { module, total } = + serde_json::from_str(&raw_stats).expect("cannot parse llvm cgu instructions stats"); + prof.artifact_size("cgu_instructions", module, total); +} diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index edb1c160626..b0a9a30ab46 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -10,6 +10,7 @@ use crate::value::Value; use rustc_ast::Mutability; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; @@ -252,8 +253,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), _ => self.static_addr_of(init, alloc.align, None), }; - if !self.sess().fewer_names() { - llvm::set_value_name(value, format!("{:?}", alloc_id).as_bytes()); + if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() { + let hash = self.tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + alloc.hash_stable(&mut hcx, &mut hasher); + hasher.finish::<u128>() + }); + llvm::set_value_name(value, format!("alloc_{hash:032x}").as_bytes()); } (value, AddressSpace::DATA) } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 7aab666fc5e..253c2ca7c76 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1814,8 +1814,6 @@ extern "C" { /// Creates a legacy pass manager -- only used for final codegen. pub fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>; - pub fn LLVMInitializePasses(); - pub fn LLVMTimeTraceProfilerInitialize(); pub fn LLVMTimeTraceProfilerFinishThread(); @@ -2410,6 +2408,8 @@ extern "C" { pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize; pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer); pub fn LLVMRustModuleCost(M: &Module) -> u64; + #[allow(improper_ctypes)] + pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString); pub fn LLVMRustThinLTOBufferCreate(M: &Module, is_thin: bool) -> &'static mut ThinLTOBuffer; pub fn LLVMRustThinLTOBufferFree(M: &'static mut ThinLTOBuffer); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 20b1dd94153..ba58a2e68e9 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -120,8 +120,6 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMTimeTraceProfilerInitialize(); } - llvm::LLVMInitializePasses(); - rustc_llvm::initialize_available_targets(); llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 3619cb48d64..7d5c0048626 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -224,23 +224,34 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).skip_binder().unsafety() == hir::Unsafety::Normal { - // The `#[target_feature]` attribute is allowed on - // WebAssembly targets on all functions, including safe - // ones. Other targets have conditions on the usage of - // `#[target_feature]` because on most targets - // execution of instructions that are not supported is - // considered undefined behavior. For WebAssembly which is a - // 100% safe target at execution time it's not possible to - // execute undefined instructions, and even if a future - // feature was added in some form for this it would be a - // deterministic trap. There is no undefined behavior when - // executing WebAssembly so `#[target_feature]` is allowed - // on safe functions (but again, only for WebAssembly) - // - // Note that this is also allowed if `actually_rustdoc` so - // if a target is documenting some wasm-specific code then - // it's not spuriously denied. - if !(tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc) { + if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { + // The `#[target_feature]` attribute is allowed on + // WebAssembly targets on all functions, including safe + // ones. Other targets require that `#[target_feature]` is + // only applied to unsafe functions (pending the + // `target_feature_11` feature) because on most targets + // execution of instructions that are not supported is + // considered undefined behavior. For WebAssembly which is a + // 100% safe target at execution time it's not possible to + // execute undefined instructions, and even if a future + // feature was added in some form for this it would be a + // deterministic trap. There is no undefined behavior when + // executing WebAssembly so `#[target_feature]` is allowed + // on safe functions (but again, only for WebAssembly) + // + // Note that this is also allowed if `actually_rustdoc` so + // if a target is documenting some wasm-specific code then + // it's not spuriously denied. + } else if !tcx.features().target_feature_11 { + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::target_feature_11, + attr.span, + "`#[target_feature(..)]` can only be applied to `unsafe` functions", + ); + err.span_label(tcx.def_span(did), "not an `unsafe` function"); + err.emit(); + } else { check_target_feature_trait_unsafe(tcx, did, attr.span); } } @@ -467,7 +478,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { }); // #73631: closures inherit `#[target_feature]` annotations - if tcx.is_closure(did.to_def_id()) { + if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) { let owner_id = tcx.parent(did.to_def_id()); if tcx.def_kind(owner_id).has_codegen_attrs() { codegen_fn_attrs diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b1abbd673a5..57a19a4ab1e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -14,7 +14,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::mir::{self, AssertKind, SwitchTargets}; -use rustc_middle::ty::layout::{HasTyCtxt, InitKind, LayoutOf}; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeVisitableExt}; use rustc_session::config::OptLevel; @@ -655,44 +655,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. - #[derive(Debug, PartialEq)] - enum AssertIntrinsic { - Inhabited, - ZeroValid, - MemUninitializedValid, - } - let panic_intrinsic = intrinsic.and_then(|i| match i { - sym::assert_inhabited => Some(AssertIntrinsic::Inhabited), - sym::assert_zero_valid => Some(AssertIntrinsic::ZeroValid), - sym::assert_mem_uninitialized_valid => Some(AssertIntrinsic::MemUninitializedValid), - _ => None, - }); - if let Some(intrinsic) = panic_intrinsic { - use AssertIntrinsic::*; - + let panic_intrinsic = intrinsic.and_then(|s| ValidityRequirement::from_intrinsic(s)); + if let Some(requirement) = panic_intrinsic { let ty = instance.unwrap().substs.type_at(0); + + let do_panic = !bx + .tcx() + .check_validity_requirement((requirement, bx.param_env().and(ty))) + .expect("expect to have layout during codegen"); + let layout = bx.layout_of(ty); - let do_panic = match intrinsic { - Inhabited => layout.abi.is_uninhabited(), - ZeroValid => !bx - .tcx() - .check_validity_of_init((InitKind::Zero, bx.param_env().and(ty))) - .expect("expected to have layout during codegen"), - MemUninitializedValid => !bx - .tcx() - .check_validity_of_init(( - InitKind::UninitMitigated0x01Fill, - bx.param_env().and(ty), - )) - .expect("expected to have layout during codegen"), - }; + Some(if do_panic { let msg_str = with_no_visible_paths!({ with_no_trimmed_paths!({ if layout.abi.is_uninhabited() { // Use this error even for the other intrinsics as it is more precise. format!("attempted to instantiate uninhabited type `{}`", ty) - } else if intrinsic == ZeroValid { + } else if requirement == ValidityRequirement::Zero { format!("attempted to zero-initialize type `{}`, which is invalid", ty) } else { format!( diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 26c84b4ce61..a29cdade023 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ BinOp, NonDivergingIntrinsic, }; use rustc_middle::ty; -use rustc_middle::ty::layout::{InitKind, LayoutOf as _}; +use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; @@ -418,57 +418,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => { let ty = instance.substs.type_at(0); - let layout = self.layout_of(ty)?; - - // For *all* intrinsics we first check `is_uninhabited` to give a more specific - // error message. - if layout.abi.is_uninhabited() { - // The run-time intrinsic panics just to get a good backtrace; here we abort - // since there is no problem showing a backtrace even for aborts. - M::abort( - self, - format!( + let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); + + let should_panic = !self + .tcx + .check_validity_requirement((requirement, self.param_env.and(ty))) + .map_err(|_| err_inval!(TooGeneric))?; + + if should_panic { + let layout = self.layout_of(ty)?; + + let msg = match requirement { + // For *all* intrinsics we first check `is_uninhabited` to give a more specific + // error message. + _ if layout.abi.is_uninhabited() => format!( "aborted execution: attempted to instantiate uninhabited type `{}`", ty ), - )?; - } - - if intrinsic_name == sym::assert_zero_valid { - let should_panic = !self - .tcx - .check_validity_of_init((InitKind::Zero, self.param_env.and(ty))) - .map_err(|_| err_inval!(TooGeneric))?; - - if should_panic { - M::abort( - self, - format!( - "aborted execution: attempted to zero-initialize type `{}`, which is invalid", - ty - ), - )?; - } - } + ValidityRequirement::Inhabited => bug!("handled earlier"), + ValidityRequirement::Zero => format!( + "aborted execution: attempted to zero-initialize type `{}`, which is invalid", + ty + ), + ValidityRequirement::UninitMitigated0x01Fill => format!( + "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", + ty + ), + ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), + }; - if intrinsic_name == sym::assert_mem_uninitialized_valid { - let should_panic = !self - .tcx - .check_validity_of_init(( - InitKind::UninitMitigated0x01Fill, - self.param_env.and(ty), - )) - .map_err(|_| err_inval!(TooGeneric))?; - - if should_panic { - M::abort( - self, - format!( - "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", - ty - ), - )?; - } + M::abort(self, msg)?; } } sym::simd_insert => { @@ -479,7 +458,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(input_len, dest_len, "Return vector length must match input length"); assert!( index < dest_len, - "Index `{}` must be in bounds of vector with length {}`", + "Index `{}` must be in bounds of vector with length {}", index, dest_len ); @@ -499,7 +478,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (input, input_len) = self.operand_to_simd(&args[0])?; assert!( index < input_len, - "index `{}` must be in bounds of vector with length `{}`", + "index `{}` must be in bounds of vector with length {}", index, input_len ); diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 450488315ef..92fa59aec6e 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -16,8 +16,8 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::const_eval::CheckAlignment; use super::{ - AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, - MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, + AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, + InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, }; /// Data returned by Machine::stack_pop, @@ -105,10 +105,16 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Extra data stored in every allocation. type AllocExtra: Debug + Clone + 'static; + /// Type for the bytes of the allocation. + type Bytes: AllocBytes + 'static; + /// Memory's allocation map type MemoryMap: AllocMap< AllocId, - (MemoryKind<Self::MemoryKind>, Allocation<Self::Provenance, Self::AllocExtra>), + ( + MemoryKind<Self::MemoryKind>, + Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>, + ), > + Default + Clone; @@ -338,7 +344,7 @@ pub trait Machine<'mir, 'tcx>: Sized { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option<MemoryKind<Self::MemoryKind>>, - ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>>; + ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>; fn eval_inline_asm( _ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -459,6 +465,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type AllocExtra = (); type FrameExtra = (); + type Bytes = Box<[u8]>; #[inline(always)] fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index f4e03ad8c59..a3764a7d142 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -21,8 +21,9 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use crate::const_eval::CheckAlignment; use super::{ - alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx, - InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar, + alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, + GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, + Scalar, }; #[derive(Debug, PartialEq, Copy, Clone)] @@ -114,16 +115,16 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. #[derive(Copy, Clone)] -pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra> { - alloc: &'a Allocation<Prov, Extra>, +pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> { + alloc: &'a Allocation<Prov, Extra, Bytes>, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, } /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. -pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra> { - alloc: &'a mut Allocation<Prov, Extra>, +pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> { + alloc: &'a mut Allocation<Prov, Extra, Bytes>, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, @@ -483,7 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, id: AllocId, is_write: bool, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra>>> { + ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra, M::Bytes>>> { let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Memory(mem)) => { // Memory of a constant or promoted or anonymous memory referenced by a static. @@ -526,6 +527,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) } + /// Get the base address for the bytes in an `Allocation` specified by the + /// `AllocID` passed in; error if no such allocation exists. + /// + /// It is up to the caller to take sufficient care when using this address: + /// there could be provenance or uninit memory in there, and other memory + /// accesses could invalidate the exposed pointer. + pub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { + let alloc = self.get_alloc_raw(id)?; + Ok(alloc.base_addr()) + } + /// Gives raw access to the `Allocation`, without bounds or alignment checks. /// The caller is responsible for calling the access hooks! /// @@ -533,7 +545,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw( &self, id: AllocId, - ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra>> { + ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>> { // The error type of the inner closure here is somewhat funny. We have two // ways of "erroring": An actual error, or because we got a reference from // `get_global_alloc` that we can actually use directly without inserting anything anywhere. @@ -569,7 +581,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> { + ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> + { let ptr_and_alloc = self.check_and_deref_ptr( ptr, size, @@ -612,7 +625,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw_mut( &mut self, id: AllocId, - ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra>, &mut M)> { + ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)> { // We have "NLL problem case #3" here, which cannot be worked around without loss of // efficiency even for the common case where the key is in the map. // <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions> @@ -641,7 +654,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer<Option<M::Provenance>>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra>>> { + ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> + { let parts = self.get_ptr_access(ptr, size, align)?; if let Some((alloc_id, offset, prov)) = parts { let tcx = *self.tcx; @@ -840,11 +854,11 @@ pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Cannot be a closure because it is generic in `Prov`, `Extra`. - fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>( + fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'tcx>, allocs_to_print: &mut VecDeque<AllocId>, - alloc: &Allocation<Prov, Extra>, + alloc: &Allocation<Prov, Extra, Bytes>, ) -> std::fmt::Result { for alloc_id in alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()) { @@ -912,7 +926,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } /// Reading and writing. -impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { +impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> + AllocRefMut<'a, 'tcx, Prov, Extra, Bytes> +{ /// `range` is relative to this allocation reference, not the base of the allocation. pub fn write_scalar(&mut self, range: AllocRange, val: Scalar<Prov>) -> InterpResult<'tcx> { let range = self.range.subrange(range); @@ -937,7 +953,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { } } -impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { +impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn read_scalar( &self, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 244fa8030af..3c463500a60 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -353,7 +353,8 @@ where pub(super) fn get_place_alloc( &self, place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra>>> { + ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> + { assert!(place.layout.is_sized()); assert!(!place.meta.has_meta()); let size = place.layout.size; @@ -364,7 +365,8 @@ where pub(super) fn get_place_alloc_mut( &mut self, place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra>>> { + ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> + { assert!(place.layout.is_sized()); assert!(!place.meta.has_meta()); let size = place.layout.size; diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 092a7dc3d3b..ed9efe568fb 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -61,7 +61,7 @@ pub fn provide(providers: &mut Providers) { let (param_env, value) = param_env_and_value.into_parts(); const_eval::deref_mir_constant(tcx, param_env, value) }; - providers.check_validity_of_init = |tcx, (init_kind, param_env_and_ty)| { - util::might_permit_raw_init(tcx, init_kind, param_env_and_ty) + providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { + util::check_validity_requirement(tcx, init_kind, param_env_and_ty) }; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index e4366f655e4..aa24d9053b9 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -332,7 +332,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { fn check_static(&mut self, def_id: DefId, span: Span) { if self.tcx.is_thread_local_static(def_id) { - self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef"); + self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`"); } self.check_op_spanned(ops::StaticAccess, span) } diff --git a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index a78bf927ca1..23fcd22c52b 100644 --- a/compiler/rustc_const_eval/src/util/might_permit_raw_init.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -1,4 +1,4 @@ -use rustc_middle::ty::layout::{InitKind, LayoutCx, LayoutError, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_session::Limit; use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; @@ -18,16 +18,23 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy}; /// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to /// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and /// to the full uninit check). -pub fn might_permit_raw_init<'tcx>( +pub fn check_validity_requirement<'tcx>( tcx: TyCtxt<'tcx>, - kind: InitKind, + kind: ValidityRequirement, param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Result<bool, LayoutError<'tcx>> { - if tcx.sess.opts.unstable_opts.strict_init_checks { - might_permit_raw_init_strict(tcx.layout_of(param_env_and_ty)?, tcx, kind) + let layout = tcx.layout_of(param_env_and_ty)?; + + // There is nothing strict or lax about inhabitedness. + if kind == ValidityRequirement::Inhabited { + return Ok(!layout.abi.is_uninhabited()); + } + + if kind == ValidityRequirement::Uninit || tcx.sess.opts.unstable_opts.strict_init_checks { + might_permit_raw_init_strict(layout, tcx, kind) } else { let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env }; - might_permit_raw_init_lax(tcx.layout_of(param_env_and_ty)?, &layout_cx, kind) + might_permit_raw_init_lax(layout, &layout_cx, kind) } } @@ -36,7 +43,7 @@ pub fn might_permit_raw_init<'tcx>( fn might_permit_raw_init_strict<'tcx>( ty: TyAndLayout<'tcx>, tcx: TyCtxt<'tcx>, - kind: InitKind, + kind: ValidityRequirement, ) -> Result<bool, LayoutError<'tcx>> { let machine = CompileTimeInterpreter::new( Limit::new(0), @@ -50,7 +57,7 @@ fn might_permit_raw_init_strict<'tcx>( .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) .expect("OOM: failed to allocate for uninit check"); - if kind == InitKind::Zero { + if kind == ValidityRequirement::Zero { cx.write_bytes_ptr( allocated.ptr, std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()), @@ -72,15 +79,18 @@ fn might_permit_raw_init_strict<'tcx>( fn might_permit_raw_init_lax<'tcx>( this: TyAndLayout<'tcx>, cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, - init_kind: InitKind, + init_kind: ValidityRequirement, ) -> Result<bool, LayoutError<'tcx>> { let scalar_allows_raw_init = move |s: Scalar| -> bool { match init_kind { - InitKind::Zero => { + ValidityRequirement::Inhabited => { + bug!("ValidityRequirement::Inhabited should have been handled above") + } + ValidityRequirement::Zero => { // The range must contain 0. s.valid_range(cx).contains(0) } - InitKind::UninitMitigated0x01Fill => { + ValidityRequirement::UninitMitigated0x01Fill => { // The range must include an 0x01-filled buffer. let mut val: u128 = 0x01; for _ in 1..s.size(cx).bytes() { @@ -89,6 +99,9 @@ fn might_permit_raw_init_lax<'tcx>( } s.valid_range(cx).contains(val) } + ValidityRequirement::Uninit => { + bug!("ValidityRequirement::Uninit should have been handled above") + } } }; diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 51735e33e0f..c0aabd77cee 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -1,14 +1,14 @@ mod alignment; mod call_kind; +mod check_validity_requirement; pub mod collect_writes; mod compare_types; mod find_self_call; -mod might_permit_raw_init; mod type_name; pub use self::alignment::is_disaligned; pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind}; +pub use self::check_validity_requirement::check_validity_requirement; pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype}; pub use self::find_self_call::find_self_call; -pub use self::might_permit_raw_init::might_permit_raw_init; pub use self::type_name::type_name; diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 16f401f2057..91abdaadabd 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -426,6 +426,7 @@ impl<O: ForestObligation> ObligationForest<O> { // nodes. Therefore we use a `while` loop. let mut index = 0; while let Some(node) = self.nodes.get_mut(index) { + // This test is extremely hot. if node.state.get() != NodeState::Pending || !processor.needs_process_obligation(&node.obligation) { @@ -439,6 +440,7 @@ impl<O: ForestObligation> ObligationForest<O> { // out of sync with `nodes`. It's not very common, but it does // happen, and code in `compress` has to allow for it. + // This code is much less hot. match processor.process_obligation(&mut node.obligation) { ProcessResult::Unchanged => { // No change in state. diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index 814e7c7fb9b..7d23ff51948 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -100,6 +100,11 @@ impl<I: Idx, K: Ord, V> SortedIndexMultiMap<I, K, V> { (k == &key).then_some((i, v)) }) } + + #[inline] + pub fn contains_key(&self, key: K) -> bool { + self.get_by_key(key).next().is_some() + } } impl<I: Idx, K: Eq, V: Eq> Eq for SortedIndexMultiMap<I, K, V> {} diff --git a/compiler/rustc_data_structures/src/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs index 3cc250862df..def7a7112fb 100644 --- a/compiler/rustc_data_structures/src/sorted_map/tests.rs +++ b/compiler/rustc_data_structures/src/sorted_map/tests.rs @@ -17,6 +17,10 @@ fn test_sorted_index_multi_map() { assert_eq!(set.get_by_key(3).copied().collect::<Vec<_>>(), vec![0]); assert!(set.get_by_key(4).next().is_none()); + // `contains_key` works + assert!(set.contains_key(3)); + assert!(!set.contains_key(4)); + // `get_by_key` returns items in insertion order. let twos: Vec<_> = set.get_by_key_enumerated(2).collect(); let idxs: Vec<usize> = twos.iter().map(|(i, _)| *i).collect(); diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index b0d66c32a07..724be5888dd 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -150,7 +150,7 @@ fn test_isize_compression() { let hash_b = hash(&(b as isize, a as isize)); assert_ne!( hash_a, hash_b, - "The hash stayed the same when permuting values `{a}` and `{b}!", + "The hash stayed the same when permuting values `{a}` and `{b}`!", ); } diff --git a/compiler/rustc_expand/locales/en-US.ftl b/compiler/rustc_expand/locales/en-US.ftl index b475d285f6b..cfae781bdee 100644 --- a/compiler/rustc_expand/locales/en-US.ftl +++ b/compiler/rustc_expand/locales/en-US.ftl @@ -133,3 +133,6 @@ expand_trace_macro = trace_macro expand_proc_macro_panicked = proc macro panicked .help = message: {$message} + +expand_proc_macro_derive_tokens = + proc-macro derive produced unparseable tokens diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 70ab222b484..e5102a952e7 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -390,3 +390,10 @@ pub(crate) struct ProcMacroPanicked { pub(crate) struct ProcMacroPanickedHelp { pub message: String, } + +#[derive(Diagnostic)] +#[diag(expand_proc_macro_derive_tokens)] +pub struct ProcMacroDeriveTokens { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index b79835be73a..47a8b4bc488 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -282,7 +282,7 @@ pub(super) fn transcribe<'a>( } // There should be no meta-var declarations in the invocation of a macro. - mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), + mbe::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl`"), } } } diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index cef64a10479..ddba1441719 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -176,7 +176,7 @@ impl MultiItemModifier for DeriveProcMacro { // fail if there have been errors emitted if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before { - ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit(); + ecx.sess.emit_err(errors::ProcMacroDeriveTokens { span }); } ExpandResult::Ready(items) diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs index 14918d3c190..480d95b77e9 100644 --- a/compiler/rustc_expand/src/tests.rs +++ b/compiler/rustc_expand/src/tests.rs @@ -43,7 +43,6 @@ pub(crate) fn string_to_stream(source_str: String) -> TokenStream { ps.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str), None, ) - .0 } /// Parses a string, returns a crate. diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 761f1ebdbac..e7b2df34ccc 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -314,8 +314,6 @@ declare_features! ( (accepted, struct_variant, "1.0.0", None, None), /// Allows `#[target_feature(...)]`. (accepted, target_feature, "1.27.0", None, None), - /// Allows the use of `#[target_feature]` on safe functions. - (accepted, target_feature_11, "CURRENT_RUSTC_VERSION", Some(69098), None), /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301), None), /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 300348d78ed..a01914f969e 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -316,8 +316,6 @@ declare_features! ( (active, c_unwind, "1.52.0", Some(74990), None), /// Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), - /// Allows capturing disjoint fields in a closure/generator (RFC 2229). - (incomplete, capture_disjoint_fields, "1.49.0", Some(53488), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. @@ -512,6 +510,8 @@ declare_features! ( (active, strict_provenance, "1.61.0", Some(95228), None), /// Allows string patterns to dereference values to match them. (active, string_deref_patterns, "1.67.0", Some(87121), None), + /// Allows the use of `#[target_feature]` on safe functions. + (active, target_feature_11, "1.45.0", Some(69098), None), /// Allows using `#[thread_local]` on `static` items. (active, thread_local, "1.0.0", Some(29594), None), /// Allows defining `trait X = A + B;` alias items. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 79a12801de2..04d4f6cb14e 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -52,6 +52,8 @@ declare_features! ( (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")), (removed, await_macro, "1.38.0", Some(50547), None, Some("subsumed by `.await` syntax")), + /// Allows capturing disjoint fields in a closure/generator (RFC 2229). + (removed, capture_disjoint_fields, "1.49.0", Some(53488), None, Some("stabilized in Rust 2021")), /// Allows comparing raw pointers during const eval. (removed, const_compare_raw_pointers, "1.46.0", Some(53020), None, Some("cannot be allowed in const eval in any meaningful way")), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 72e9f7c1343..19d3d41c984 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -498,6 +498,7 @@ pub struct GenericParam<'hir> { pub pure_wrt_drop: bool, pub kind: GenericParamKind<'hir>, pub colon_span: Option<Span>, + pub source: GenericParamSource, } impl<'hir> GenericParam<'hir> { @@ -516,6 +517,20 @@ impl<'hir> GenericParam<'hir> { } } +/// Records where the generic parameter originated from. +/// +/// This can either be from an item's generics, in which case it's typically +/// early-bound (but can be a late-bound lifetime in functions, for example), +/// or from a `for<...>` binder, in which case it's late-bound (and notably, +/// does not show up in the parent item's generics). +#[derive(Debug, HashStable_Generic, PartialEq, Eq, Copy, Clone)] +pub enum GenericParamSource { + // Early or late-bound parameters defined on an item + Generics, + // Late-bound parameters defined via a `for<...>` + Binder, +} + #[derive(Default)] pub struct GenericParamCount { pub lifetimes: usize, diff --git a/compiler/rustc_hir_analysis/locales/en-US.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl index 40b5bc2a32e..1d313945b52 100644 --- a/compiler/rustc_hir_analysis/locales/en-US.ftl +++ b/compiler/rustc_hir_analysis/locales/en-US.ftl @@ -147,3 +147,11 @@ hir_analysis_main_function_generic_parameters = `main` function is not allowed t hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions} .label = C-variadic function must have a compatible calling convention + +hir_analysis_cannot_capture_late_bound_ty_in_anon_const = + cannot capture late-bound type parameter in a constant + .label = parameter defined here + +hir_analysis_cannot_capture_late_bound_const_in_anon_const = + cannot capture late-bound const parameter in a constant + .label = parameter defined here diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index a15cf454df7..f5ce02c9e61 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -50,6 +50,7 @@ use rustc_trait_selection::traits::{self, astconv_object_safety_violations, Obli use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; +use std::fmt::Display; use std::slice; #[derive(Debug)] @@ -1095,11 +1096,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // those that do. self.one_bound_for_assoc_type( || traits::supertraits(tcx, trait_ref), - || trait_ref.print_only_trait_path().to_string(), + trait_ref.print_only_trait_path(), binding.item_name, path_span, - || match binding.kind { - ConvertedBindingKind::Equality(ty) => Some(ty.to_string()), + match binding.kind { + ConvertedBindingKind::Equality(term) => Some(term), _ => None, }, )? @@ -1789,10 +1790,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assoc_name, ) }, - || param_name.to_string(), + param_name, assoc_name, span, - || None, + None, ) } @@ -1802,10 +1803,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn one_bound_for_assoc_type<I>( &self, all_candidates: impl Fn() -> I, - ty_param_name: impl Fn() -> String, + ty_param_name: impl Display, assoc_name: Ident, span: Span, - is_equality: impl Fn() -> Option<String>, + is_equality: Option<ty::Term<'tcx>>, ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> where I: Iterator<Item = ty::PolyTraitRef<'tcx>>, @@ -1821,7 +1822,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (None, None) => { let reported = self.complain_about_assoc_type_not_found( all_candidates, - &ty_param_name(), + &ty_param_name.to_string(), assoc_name, span, ); @@ -1833,7 +1834,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(bound2) = next_cand { debug!(?bound2); - let is_equality = is_equality(); let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates); let mut err = if is_equality.is_some() { // More specific Error Index entry. @@ -1843,7 +1843,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { E0222, "ambiguous associated type `{}` in bounds of `{}`", assoc_name, - ty_param_name() + ty_param_name ) } else { struct_span_err!( @@ -1852,7 +1852,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { E0221, "ambiguous associated type `{}` in bounds of `{}`", assoc_name, - ty_param_name() + ty_param_name ) }; err.span_label(span, format!("ambiguous associated type `{}`", assoc_name)); @@ -1886,18 +1886,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_suggestion_verbose( span.with_hi(assoc_name.span.lo()), "use fully qualified syntax to disambiguate", - format!( - "<{} as {}>::", - ty_param_name(), - bound.print_only_trait_path(), - ), + format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } } else { err.note(&format!( "associated type `{}` could derive from `{}`", - ty_param_name(), + ty_param_name, bound.print_only_trait_path(), )); } @@ -1906,7 +1902,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.help(&format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ \n where\n T: {},\n{}", - ty_param_name(), + ty_param_name, where_bounds.join(",\n"), )); } @@ -2070,10 +2066,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.one_bound_for_assoc_type( || traits::supertraits(tcx, ty::Binder::dummy(trait_ref.subst_identity())), - || "Self".to_string(), + kw::SelfUpper, assoc_ident, span, - || None, + None, )? } ( @@ -2403,8 +2399,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { infcx .can_eq( ty::ParamEnv::empty(), - tcx.erase_regions(impl_.self_ty()), - tcx.erase_regions(qself_ty), + impl_.self_ty(), + // Must fold past escaping bound vars too, + // since we have those at this point in astconv. + tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased), ) }) && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4ea471f8f05..848828175e2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -792,8 +792,10 @@ fn check_impl_items_against_trait<'tcx>( trait_def.must_implement_one_of.as_deref(); for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) { - let is_implemented = ancestors - .leaf_def(tcx, trait_item_id) + let leaf_def = ancestors.leaf_def(tcx, trait_item_id); + + let is_implemented = leaf_def + .as_ref() .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value()); if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { @@ -801,8 +803,8 @@ fn check_impl_items_against_trait<'tcx>( } // true if this item is specifically implemented in this impl - let is_implemented_here = ancestors - .leaf_def(tcx, trait_item_id) + let is_implemented_here = leaf_def + .as_ref() .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); if !is_implemented_here { @@ -831,6 +833,36 @@ fn check_impl_items_against_trait<'tcx>( } } } + + if let Some(leaf_def) = &leaf_def + && !leaf_def.is_final() + && let def_id = leaf_def.item.def_id + && tcx.impl_method_has_trait_impl_trait_tys(def_id) + { + let def_kind = tcx.def_kind(def_id); + let descr = tcx.def_kind_descr(def_kind, def_id); + let (msg, feature) = if tcx.asyncness(def_id).is_async() { + ( + format!("async {descr} in trait cannot be specialized"), + sym::async_fn_in_trait, + ) + } else { + ( + format!( + "{descr} with return-position `impl Trait` in trait cannot be specialized" + ), + sym::return_position_impl_trait_in_trait, + ) + }; + tcx.sess + .struct_span_err(tcx.def_span(def_id), msg) + .note(format!( + "specialization behaves in inconsistent and \ + surprising ways with `#![feature({feature})]`, \ + and for now is disallowed" + )) + .emit(); + } } if !missing_items.is_empty() { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index b0dc6b1dcac..691d3f8d942 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1873,7 +1873,7 @@ pub(super) fn check_type_bounds<'tcx>( // type Bar<C> =... // } // - // - `impl_trait_ref` would be `<(A, B) as Foo<u32>> + // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>` // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0) // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from // the *trait* with the generic associated type parameters (as bound vars). diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 875c5f1fd00..ffb68abf978 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -437,7 +437,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn } // Here we are considering a case of converting - // `S<P0...Pn>` to S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`, + // `S<P0...Pn>` to `S<Q0...Qn>`. As an example, let's imagine a struct `Foo<T, U>`, // which acts like a pointer to `U`, but carries along some extra data of type `T`: // // struct Foo<T, U> { 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 6c00b8ff7bd..65a9052a60a 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -24,6 +24,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use std::fmt; +use crate::errors; + trait RegionExt { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg); @@ -161,6 +163,15 @@ enum Scope<'a> { s: ScopeRef<'a>, }, + /// Disallows capturing non-lifetime binders from parent scopes. + /// + /// This is necessary for something like `for<T> [(); { /* references T */ }]:`, + /// since we don't do something more correct like replacing any captured + /// late-bound vars with early-bound params in the const's own generics. + AnonConstBoundary { + s: ScopeRef<'a>, + }, + Root { opt_parent_item: Option<LocalDefId>, }, @@ -211,6 +222,7 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("s", &"..") .finish(), Scope::TraitRefBoundary { s: _ } => f.debug_struct("TraitRefBoundary").finish(), + Scope::AnonConstBoundary { s: _ } => f.debug_struct("AnonConstBoundary").finish(), Scope::Root { opt_parent_item } => { f.debug_struct("Root").field("opt_parent_item", &opt_parent_item).finish() } @@ -312,7 +324,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { break (vec![], BinderScopeType::Normal); } - Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { + Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } @@ -1029,50 +1043,64 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_poly_trait_ref(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) { self.visit_poly_trait_ref_inner(trait_ref, NonLifetimeBinderAllowed::Allow); } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + self.with(Scope::AnonConstBoundary { s: self.scope }, |this| { + intravisit::walk_anon_const(this, c); + }); + } } fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: DefId) -> ObjectLifetimeDefault { debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); let param_def_id = param_def_id.expect_local(); - let parent_def_id = tcx.local_parent(param_def_id); - let generics = tcx.hir().get_generics(parent_def_id).unwrap(); - let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); - let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); - - // Scan the bounds and where-clauses on parameters to extract bounds - // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` - // for each type parameter. - match param.kind { - GenericParamKind::Type { .. } => { - let mut set = Set1::Empty; - - // Look for `type: ...` where clauses. - for bound in generics.bounds_for_param(param_def_id) { - // Ignore `for<'a> type: ...` as they can change what - // lifetimes mean (although we could "just" handle it). - if !bound.bound_generic_params.is_empty() { - continue; - } + let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(param_def_id) else { + bug!("expected GenericParam for object_lifetime_default"); + }; + match param.source { + hir::GenericParamSource::Generics => { + let parent_def_id = tcx.local_parent(param_def_id); + let generics = tcx.hir().get_generics(parent_def_id).unwrap(); + let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); + let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); + + // Scan the bounds and where-clauses on parameters to extract bounds + // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` + // for each type parameter. + match param.kind { + GenericParamKind::Type { .. } => { + let mut set = Set1::Empty; + + // Look for `type: ...` where clauses. + for bound in generics.bounds_for_param(param_def_id) { + // Ignore `for<'a> type: ...` as they can change what + // lifetimes mean (although we could "just" handle it). + if !bound.bound_generic_params.is_empty() { + continue; + } - for bound in bound.bounds { - if let hir::GenericBound::Outlives(lifetime) = bound { - set.insert(lifetime.res); + for bound in bound.bounds { + if let hir::GenericBound::Outlives(lifetime) = bound { + set.insert(lifetime.res); + } + } } - } - } - match set { - Set1::Empty => ObjectLifetimeDefault::Empty, - Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, - Set1::One(hir::LifetimeName::Param(param_def_id)) => { - ObjectLifetimeDefault::Param(param_def_id.to_def_id()) + match set { + Set1::Empty => ObjectLifetimeDefault::Empty, + Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, + Set1::One(hir::LifetimeName::Param(param_def_id)) => { + ObjectLifetimeDefault::Param(param_def_id.to_def_id()) + } + _ => ObjectLifetimeDefault::Ambiguous, + } + } + _ => { + bug!("object_lifetime_default_raw must only be called on a type parameter") } - _ => ObjectLifetimeDefault::Ambiguous, } } - _ => { - bug!("object_lifetime_default_raw must only be called on a type parameter") - } + hir::GenericParamSource::Binder => ObjectLifetimeDefault::Empty, } } @@ -1267,7 +1295,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } @@ -1332,7 +1361,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } @@ -1351,6 +1381,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // search. let mut late_depth = 0; let mut scope = self.scope; + let mut crossed_anon_const = false; let result = loop { match *scope { Scope::Body { s, .. } => { @@ -1384,17 +1415,44 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { | Scope::TraitRefBoundary { s, .. } => { scope = s; } + + Scope::AnonConstBoundary { s } => { + crossed_anon_const = true; + scope = s; + } } }; if let Some(def) = result { + if let ResolvedArg::LateBound(..) = def && crossed_anon_const { + let use_span = self.tcx.hir().span(hir_id); + let def_span = self.tcx.def_span(param_def_id); + match self.tcx.def_kind(param_def_id) { + DefKind::ConstParam => { + self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Const { + use_span, + def_span, + }); + } + DefKind::TyParam => { + self.tcx.sess.emit_err(errors::CannotCaptureLateBoundInAnonConst::Type { + use_span, + def_span, + }); + } + _ => unreachable!(), + } + return; + } + self.map.defs.insert(hir_id, def); return; } - self.tcx - .sess - .delay_span_bug(self.tcx.hir().span(hir_id), "could not resolve {param_def_id:?}"); + self.tcx.sess.delay_span_bug( + self.tcx.hir().span(hir_id), + format!("could not resolve {param_def_id:?}"), + ); } #[instrument(level = "debug", skip(self))] @@ -1465,7 +1523,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { | Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } | Scope::Supertrait { s, .. } - | Scope::TraitRefBoundary { s, .. } => { + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } @@ -1701,7 +1760,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, - Scope::Supertrait { s, .. } | Scope::TraitRefBoundary { s, .. } => { + Scope::Supertrait { s, .. } + | Scope::TraitRefBoundary { s, .. } + | Scope::AnonConstBoundary { s } => { scope = s; } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 203e0f85cad..3e069275775 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -381,3 +381,21 @@ pub(crate) struct VariadicFunctionCompatibleConvention<'a> { pub span: Span, pub conventions: &'a str, } + +#[derive(Diagnostic)] +pub(crate) enum CannotCaptureLateBoundInAnonConst { + #[diag(hir_analysis_cannot_capture_late_bound_ty_in_anon_const)] + Type { + #[primary_span] + use_span: Span, + #[label] + def_span: Span, + }, + #[diag(hir_analysis_cannot_capture_late_bound_const_in_anon_const)] + Const { + #[primary_span] + use_span: Span, + #[label] + def_span: Span, + }, +} diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 34d62987c3b..7ba57b3b7a2 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -315,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { probe::ProbeScope::TraitsInScope, None, ) { - Ok(pick) => pick.self_ty, + Ok(pick) => eraser.fold_ty(pick.self_ty), Err(_) => rcvr_ty, }; // Remove one layer of references to account for `&mut self` and diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index d64492e503d..b09886fe3a9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -714,12 +714,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.parent(expr_ctor_def_id) } hir::def::DefKind::Ctor(hir::def::CtorOf::Variant, hir::def::CtorKind::Fn) => { - // If this is a variant, its parent is the type definition. - if in_ty_adt.did() != self.tcx.parent(expr_ctor_def_id) { + // For a typical enum like + // `enum Blah<T> { Variant(T) }` + // we get the following resolutions: + // - expr_ctor_def_id ::: DefId(0:29 ~ source_file[b442]::Blah::Variant::{constructor#0}) + // - self.tcx.parent(expr_ctor_def_id) ::: DefId(0:28 ~ source_file[b442]::Blah::Variant) + // - self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) ::: DefId(0:26 ~ source_file[b442]::Blah) + + // Therefore, we need to go up once to obtain the variant and up twice to obtain the type. + // Note that this pattern still holds even when we `use` a variant or `use` an enum type to rename it, or chain `use` expressions + // together; this resolution is handled automatically by `qpath_res`. + + // FIXME: Deal with type aliases? + if in_ty_adt.did() == self.tcx.parent(self.tcx.parent(expr_ctor_def_id)) { + // The constructor definition refers to the "constructor" of the variant: + // For example, `Some(5)` triggers this case. + self.tcx.parent(expr_ctor_def_id) + } else { // FIXME: Deal with type aliases? return Err(expr); } - expr_ctor_def_id } _ => { return Err(expr); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 2e62e13648c..a46bdeb417d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -36,7 +36,6 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext} use std::iter; use std::mem; -use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&mut self) { @@ -1507,11 +1506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let coerce = if blk.targeted_by_break { CoerceMany::new(coerce_to_ty) } else { - let tail_expr: &[&hir::Expr<'_>] = match tail_expr { - Some(e) => slice::from_ref(e), - None => &[], - }; - CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) + CoerceMany::with_coercion_sites(coerce_to_ty, blk.expr.as_slice()) }; let prev_diverges = self.diverges.get(); diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 91fd8fad73c..e397dfd4570 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -5,6 +5,7 @@ #![feature(min_specialization)] #![feature(control_flow_enum)] #![feature(drain_filter)] +#![feature(option_as_slice)] #![allow(rustc::potential_query_instability)] #![recursion_limit = "256"] diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index bcfc61bffb2..4d3969d28aa 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -636,7 +636,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { // `&&Some(x,)` `place_foo` // `&Some(x,)` `deref { place_foo}` // `Some(x,)` `deref { deref { place_foo }}` - // (x,)` `field0 { deref { deref { place_foo }}}` <- resulting place + // `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place // // The above example has no adjustments. If the code were instead the (after adjustments, // equivalent) version diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 47a4d4e72df..60d56263d2e 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -333,6 +333,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty.prefix_string(self.tcx), ty_str_reported, ); + if tcx.sess.source_map().is_multiline(sugg_span) { + err.span_label(sugg_span.with_hi(span.lo()), ""); + } let ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { short_ty_str } else { diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index a4b325a9b79..80279ed969a 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -749,14 +749,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let opname = Ident::with_dummy_span(opname); - let input_types = - opt_rhs.as_ref().map(|(_, ty)| std::slice::from_ref(ty)).unwrap_or_default(); + let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); + let input_types = opt_rhs_ty.as_slice(); let cause = self.cause( span, traits::BinOp { - rhs_span: opt_rhs.map(|(expr, _)| expr.span), - is_lit: opt_rhs - .map_or(false, |(expr, _)| matches!(expr.kind, hir::ExprKind::Lit(_))), + rhs_span: opt_rhs_expr.map(|expr| expr.span), + is_lit: opt_rhs_expr + .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), output_ty: expected.only_has_type(self), }, ); diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 8fcec3363c0..2cca45de5e9 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already. @@ -393,11 +392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1)) } }; - let arg_tys = match arg_ty { - None => &[], - Some(ref ty) => slice::from_ref(ty), - }; - + let arg_tys = arg_ty.as_slice(); let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op); let method = match method { Some(ok) => self.register_infer_ok_obligations(ok), diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 3e27a78135e..4a432328c4d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We now fake capture information for all variables that are mentioned within the closure // We do this after handling migrations so that min_captures computes before - if !enable_precise_capture(self.tcx, span) { + if !enable_precise_capture(span) { let mut capture_information: InferredCaptureInformation<'tcx> = Default::default(); if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { @@ -265,7 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we have an origin, store it. if let Some(origin) = origin { - let origin = if enable_precise_capture(self.tcx, span) { + let origin = if enable_precise_capture(span) { (origin.0, origin.1) } else { (origin.0, Place { projections: vec![], ..origin.1 }) @@ -1243,8 +1243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// This will make more sense with an example: /// - /// ```rust - /// #![feature(capture_disjoint_fields)] + /// ```rust,edition2021 /// /// struct FancyInteger(i32); // This implements Drop /// @@ -2224,7 +2223,7 @@ fn determine_place_ancestry_relation<'tcx>( /// || drop(&*m.a.field_of_a) /// // Here we really do want to capture `*m.a` because that outlives `'static` /// -/// // If we capture `m`, then the closure no longer outlives `'static' +/// // If we capture `m`, then the closure no longer outlives `'static` /// // it is constrained to `'a` /// } /// ``` @@ -2250,12 +2249,10 @@ fn truncate_capture_for_optimization( (place, curr_mode) } -/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if -/// user is using Rust Edition 2021 or higher. -/// +/// Precise capture is enabled if user is using Rust Edition 2021 or higher. /// `span` is the span of the closure. -fn enable_precise_capture(tcx: TyCtxt<'_>, span: Span) -> bool { +fn enable_precise_capture(span: Span) -> bool { // We use span here to ensure that if the closure was generated by a macro with a different // edition. - tcx.features().capture_disjoint_fields || span.rust_2021() + span.rust_2021() } diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index b4b0ea00c50..c550e553bb0 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -18,7 +18,7 @@ //! the HIR doesn't change as a result of the annotations, which might //! perturb the reuse results. //! -//! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")] +//! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")]` //! allows for doing a more fine-grained check to see if pre- or post-lto data //! was re-used. diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 15179392c88..cbf169afb18 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1870,7 +1870,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { } } - /// Subtracts `set from `row`. `set` can be either `BitSet` or + /// Subtracts `set` from `row`. `set` can be either `BitSet` or /// `HybridBitSet`. Has no effect if `row` does not exist. /// /// Returns true if the row was changed. diff --git a/compiler/rustc_infer/locales/en-US.ftl b/compiler/rustc_infer/locales/en-US.ftl index c5b2b6c2d73..15780898dc6 100644 --- a/compiler/rustc_infer/locales/en-US.ftl +++ b/compiler/rustc_infer/locales/en-US.ftl @@ -79,7 +79,7 @@ infer_subtype = ...so that the {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] #[start]` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type [intristic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible @@ -92,7 +92,7 @@ infer_subtype_2 = ...so that {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] #[start]` function has the correct type + [fn_start_correct_type] `#[start]` function has the correct type [intristic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type *[other] types are compatible @@ -277,7 +277,7 @@ infer_tid_consider_borrowing = consider borrowing this type parameter in the tra infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement -infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement +infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement infer_dtcs_has_req_note = the used `impl` has a `'static` requirement infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement @@ -313,7 +313,7 @@ infer_but_needs_to_satisfy = {$has_param_name -> [false] ...and is required to live as long as `'static` here } .used_here = ...is used here... - .introduced_by_bound = 'static` lifetime requirement introduced by this bound + .introduced_by_bound = `'static` lifetime requirement introduced by this bound infer_more_targeted = {$has_param_name -> [true] `{$param_name}` @@ -345,3 +345,6 @@ infer_prlf_defined_without_sub = the lifetime defined here... infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) + +infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds + .label = opaque type defined here diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 7dccd0bb930..6bbd3fd3e6e 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1147,3 +1147,13 @@ pub enum PlaceholderRelationLfNotSatisfied { note: (), }, } + +#[derive(Diagnostic)] +#[diag(infer_opaque_captures_lifetime, code = "E0700")] +pub struct OpaqueCapturesLifetime<'tcx> { + #[primary_span] + pub span: Span, + #[label] + pub opaque_ty_span: Span, + pub opaque_ty: Ty<'tcx>, +} diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index c952ddc827a..7d9bae735e5 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -369,6 +369,34 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { + fn to_trace( + _: TyCtxt<'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self, + ) -> TypeTrace<'tcx> { + use GenericArgKind::*; + TypeTrace { + cause: cause.clone(), + values: match (a.unpack(), b.unpack()) { + (Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)), + (Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + (Const(a), Const(b)) => { + Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + } + + (Lifetime(_), Type(_) | Const(_)) + | (Type(_), Lifetime(_) | Const(_)) + | (Const(_), Lifetime(_) | Type(_)) => { + bug!("relating different kinds: {a:?} {b:?}") + } + }, + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { fn to_trace( _: TyCtxt<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 7ffd39de781..678c4a0beb6 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -50,7 +50,7 @@ impl<'tcx> InferCtxt<'tcx> { /// Like [Self::canonicalize_query], but preserves distinct universes. For /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and - /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1` + /// `'?1` is in `U3` would be canonicalized to have `?0` in `U1` and `'?1` /// in `U2`. /// /// This is used for Chalk integration. diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 8c782a933a5..ce230afdab3 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{self, List, TyCtxt}; use rustc_span::source_map::Span; pub use rustc_middle::infer::canonical::*; -use substitute::CanonicalExt; +pub use substitute::CanonicalExt; mod canonicalizer; pub mod query_response; @@ -100,7 +100,11 @@ impl<'tcx> InferCtxt<'tcx> { /// variable for it. If this is an existentially quantified /// variable, then you'll get a new inference variable; if it is a /// universally quantified variable, you get a placeholder. - fn instantiate_canonical_var( + /// + /// FIXME(-Ztrait-solver=next): This is public because it's used by the + /// new trait solver which has a different canonicalization routine. + /// We should somehow deduplicate all of this. + pub fn instantiate_canonical_var( &self, span: Span, cv_info: CanonicalVarInfo<'tcx>, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 832af91a431..436d29c2449 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -151,11 +151,21 @@ impl<'tcx> InferCtxt<'tcx> { }) } - /// FIXME: This method should only be used for canonical queries and therefore be private. - /// - /// As the new solver does canonicalization slightly differently, this is also used there - /// for now. This should hopefully change fairly soon. - pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + /// Used by the new solver as that one takes the opaque types at the end of a probe + /// to deal with multiple candidates without having to recompute them. + pub fn clone_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + self.inner + .borrow() + .opaque_type_storage + .opaque_types + .iter() + .map(|&(k, ref v)| { + (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty) + }) + .collect() + } + + fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index c5c6fc41b9e..cac3b407251 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -11,7 +11,9 @@ use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, TyCtxt}; -pub(super) trait CanonicalExt<'tcx, V> { +/// FIXME(-Ztrait-solver=next): This or public because it is shared with the +/// new trait solver implementation. We should deduplicate canonicalization. +pub trait CanonicalExt<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 79efc1ce7bf..8a2b800af0e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -49,6 +49,7 @@ use super::lexical_region_resolve::RegionResolutionError; use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; +use crate::errors; use crate::infer; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::ExpectedFound; @@ -281,15 +282,13 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( span: Span, hidden_ty: Ty<'tcx>, hidden_region: ty::Region<'tcx>, - opaque_ty: ty::OpaqueTypeKey<'tcx>, + opaque_ty_key: ty::OpaqueTypeKey<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let opaque_ty = tcx.mk_opaque(opaque_ty.def_id.to_def_id(), opaque_ty.substs); - let mut err = struct_span_err!( - tcx.sess, + let mut err = tcx.sess.create_err(errors::OpaqueCapturesLifetime { span, - E0700, - "hidden type for `{opaque_ty}` captures lifetime that does not appear in bounds", - ); + opaque_ty: tcx.mk_opaque(opaque_ty_key.def_id.to_def_id(), opaque_ty_key.substs), + opaque_ty_span: tcx.def_span(opaque_ty_key.def_id), + }); // Explain the region we are capturing. match *hidden_region { @@ -1690,7 +1689,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("{name} is defined in the current crate") } else { let crate_name = self.tcx.crate_name(defid.krate); - format!("{name} is defined in crate `{crate_name}") + format!("{name} is defined in crate `{crate_name}`") }; diagnostic.span_note(def_span, msg); }; diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index a499018d3a2..2c480355085 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -70,7 +70,7 @@ pub enum RegionResolutionError<'tcx> { /// `o` requires that `a <= b`, but this does not hold ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>), - /// `GenericBoundFailure(p, s, a) + /// `GenericBoundFailure(p, s, a)`: /// /// The parameter/associated-type `p` must be known to outlive the lifetime /// `a` (but none of the known bounds are sufficient). diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index cf8007c964d..bd1f96635a6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -156,7 +156,7 @@ pub struct InferCtxtInner<'tcx> { undo_log: InferCtxtUndoLogs<'tcx>, /// Caches for opaque type inference. - pub opaque_type_storage: OpaqueTypeStorage<'tcx>, + opaque_type_storage: OpaqueTypeStorage<'tcx>, } impl<'tcx> InferCtxtInner<'tcx> { @@ -195,41 +195,17 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - fn int_unification_table( - &mut self, - ) -> ut::UnificationTable< - ut::InPlace< - ty::IntVid, - &mut ut::UnificationStorage<ty::IntVid>, - &mut InferCtxtUndoLogs<'tcx>, - >, - > { + fn int_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::IntVid> { self.int_unification_storage.with_log(&mut self.undo_log) } #[inline] - fn float_unification_table( - &mut self, - ) -> ut::UnificationTable< - ut::InPlace< - ty::FloatVid, - &mut ut::UnificationStorage<ty::FloatVid>, - &mut InferCtxtUndoLogs<'tcx>, - >, - > { + fn float_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::FloatVid> { self.float_unification_storage.with_log(&mut self.undo_log) } #[inline] - fn const_unification_table( - &mut self, - ) -> ut::UnificationTable< - ut::InPlace< - ty::ConstVid<'tcx>, - &mut ut::UnificationStorage<ty::ConstVid<'tcx>>, - &mut InferCtxtUndoLogs<'tcx>, - >, - > { + fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::ConstVid<'tcx>> { self.const_unification_storage.with_log(&mut self.undo_log) } @@ -1429,17 +1405,14 @@ impl<'tcx> InferCtxt<'tcx> { } } + /// Attempts to resolve all type/region/const variables in + /// `value`. Region inference must have been run already (e.g., + /// by calling `resolve_regions_and_report_errors`). If some + /// variable was never unified, an `Err` results. + /// + /// This method is idempotent, but it not typically not invoked + /// except during the writeback phase. pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> { - /*! - * Attempts to resolve all type/region/const variables in - * `value`. Region inference must have been run already (e.g., - * by calling `resolve_regions_and_report_errors`). If some - * variable was never unified, an `Err` results. - * - * This method is idempotent, but it not typically not invoked - * except during the writeback phase. - */ - let value = resolve::fully_resolve(self, value); assert!( value.as_ref().map_or(true, |value| !value.needs_infer()), @@ -1754,7 +1727,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // in this case. The typechecker should only ever report type errors involving mismatched // types using one of these methods, and should not call span_err directly for such // errors. - pub fn type_error_struct_with_diag<M>( &self, sp: Span, diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 6e413a7f412..573cd91a2a2 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -50,7 +50,7 @@ where /// /// - Covariant means `a <: b`. /// - Contravariant means `b <: a`. - /// - Invariant means `a == b. + /// - Invariant means `a == b`. /// - Bivariant means that it doesn't matter. ambient_variance: ty::Variance, diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 33514eedfc3..872f617474c 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -249,7 +249,7 @@ pub enum VerifyBound<'tcx> { /// in that case we can show `'b: 'c`. But if `'?x` winds up being something /// else, the bound isn't relevant. /// -/// In the [`VerifyBound`], this struct is enclosed in `Binder to account +/// In the [`VerifyBound`], this struct is enclosed in `Binder` to account /// for cases like /// /// ```rust diff --git a/compiler/rustc_interface/locales/en-US.ftl b/compiler/rustc_interface/locales/en-US.ftl index da58492ccf2..37994899a20 100644 --- a/compiler/rustc_interface/locales/en-US.ftl +++ b/compiler/rustc_interface/locales/en-US.ftl @@ -33,7 +33,7 @@ interface_rustc_error_fatal = fatal error triggered by #[rustc_error] interface_rustc_error_unexpected_annotation = - unexpected annotation used with `#[rustc_error(...)]! + unexpected annotation used with `#[rustc_error(...)]`! interface_failed_writing_file = failed to write file {$path}: {$error}" diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index e6f04fe0aaa..322ec31fb2c 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -166,15 +166,17 @@ pub enum DocStyle { Inner, } -// Note that the suffix is *not* considered when deciding the `LiteralKind` in -// this type. This means that float literals like `1f32` are classified by this -// type as `Int`. (Compare against `rustc_ast::token::LitKind` and -// `rustc_ast::ast::LitKind.) +/// Enum representing the literal types supported by the lexer. +/// +/// Note that the suffix is *not* considered when deciding the `LiteralKind` in +/// this type. This means that float literals like `1f32` are classified by this +/// type as `Int`. (Compare against `rustc_ast::token::LitKind` and +/// `rustc_ast::ast::LitKind`). #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum LiteralKind { /// "12_u8", "0o100", "0b120i99", "1f32". Int { base: Base, empty_int: bool }, - /// "12.34f32", "1e3", but not "1f32`. + /// "12.34f32", "1e3", but not "1f32". Float { base: Base, empty_exponent: bool }, /// "'a'", "'\\'", "'''", "';" Char { terminated: bool }, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 59540aaf18f..5b2100b5da9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1288,7 +1288,7 @@ declare_lint! { } declare_lint_pass!( - /// Explains corresponding feature flag must be enabled for the `#[track_caller] attribute to + /// Explains corresponding feature flag must be enabled for the `#[track_caller]` attribute to /// do anything UngatedAsyncFnTrackCaller => [UNGATED_ASYNC_FN_TRACK_CALLER] ); diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 9146a3739b2..05890628378 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -14,6 +14,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/Host.h" #include "llvm/Support/Memory.h" #include "llvm/Support/SourceMgr.h" diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 0a42265a6ba..4761ce83fab 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -9,7 +9,6 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" -#include "llvm/InitializePasses.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/IntrinsicInst.h" @@ -58,22 +57,6 @@ typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef) DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) -extern "C" void LLVMInitializePasses() { - PassRegistry &Registry = *PassRegistry::getPassRegistry(); - initializeCore(Registry); - initializeCodeGen(Registry); - initializeScalarOpts(Registry); - initializeVectorization(Registry); - initializeIPO(Registry); - initializeAnalysis(Registry); - initializeTransformUtils(Registry); - initializeInstCombine(Registry); -#if LLVM_VERSION_LT(16, 0) - initializeInstrumentation(Registry); -#endif - initializeTarget(Registry); -} - extern "C" void LLVMTimeTraceProfilerInitialize() { timeTraceProfilerInitialize( /* TimeTraceGranularity */ 0, @@ -1004,23 +987,8 @@ LLVMRustPrintModule(LLVMModuleRef M, const char *Path, DemangleFn Demangle) { } extern "C" void LLVMRustPrintPasses() { - LLVMInitializePasses(); - struct MyListener : PassRegistrationListener { - void passEnumerate(const PassInfo *Info) { - StringRef PassArg = Info->getPassArgument(); - StringRef PassName = Info->getPassName(); - if (!PassArg.empty()) { - // These unsigned->signed casts could theoretically overflow, but - // realistically never will (and even if, the result is implementation - // defined rather plain UB). - printf("%15.*s - %.*s\n", (int)PassArg.size(), PassArg.data(), - (int)PassName.size(), PassName.data()); - } - } - } Listener; - - PassRegistry *PR = PassRegistry::getPassRegistry(); - PR->enumerateWith(&Listener); + PassBuilder PB; + PB.printPassNames(outs()); } extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b1e6534944d..e3493caaaf7 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1751,6 +1751,19 @@ LLVMRustModuleCost(LLVMModuleRef M) { return std::distance(std::begin(f), std::end(f)); } +extern "C" void +LLVMRustModuleInstructionStats(LLVMModuleRef M, RustStringRef Str) +{ + RawRustStringOstream OS(Str); + llvm::json::OStream JOS(OS); + auto Module = unwrap(M); + + JOS.object([&] { + JOS.attribute("module", Module->getName()); + JOS.attribute("total", Module->getInstructionCount()); + }); +} + // Vector reductions: extern "C" LLVMValueRef LLVMRustBuildVectorReduceFAdd(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Src) { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f0dafe73c00..3ab01f7809b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1101,37 +1101,18 @@ fn should_encode_const(def_kind: DefKind) -> bool { } } -fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if tcx.def_kind(def_id) != DefKind::AssocFn { - return false; - } - - let Some(item) = tcx.opt_associated_item(def_id) else { return false; }; - if item.container != ty::AssocItemContainer::ImplContainer { - return false; +// We only encode impl trait in trait when using `lower-impl-trait-in-trait-to-assoc-ty` unstable +// option. +fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty + && let Some(assoc_item) = tcx.opt_associated_item(def_id) + && assoc_item.container == ty::AssocItemContainer::TraitContainer + && assoc_item.kind == ty::AssocKind::Fn + { + true + } else { + false } - - let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; - - // FIXME(RPITIT): This does a somewhat manual walk through the signature - // of the trait fn to look for any RPITITs, but that's kinda doing a lot - // of work. We can probably remove this when we refactor RPITITs to be - // associated types. - tcx.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { - if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection, data) = ty.kind() - && tcx.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder - { - true - } else { - false - } - }) -} - -// Return `false` to avoid encoding impl trait in trait, while we don't use the query. -fn should_encode_fn_impl_trait_in_trait<'tcx>(_tcx: TyCtxt<'tcx>, _def_id: DefId) -> bool { - false } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { @@ -1211,7 +1192,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(def_id); } - if should_encode_trait_impl_trait_tys(tcx, def_id) + if tcx.impl_method_has_trait_impl_trait_tys(def_id) && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id) { record!(self.tables.trait_impl_trait_tys[def_id] <- table); @@ -1640,7 +1621,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn encode_info_for_closure(&mut self, def_id: LocalDefId) { // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic, - // including on the signature, which is inferred in `typeck. + // including on the signature, which is inferred in `typeck`. let typeck_result: &'tcx ty::TypeckResults<'tcx> = self.tcx.typeck(def_id); let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let ty = typeck_result.node_type(hir_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index ad119c4e073..c9da711e556 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -177,6 +177,7 @@ pub fn provide(providers: &mut Providers) { } }; providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local()); + providers.opt_rpitit_info = |_, _| None; providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; providers.expn_that_defined = |tcx, id| { let id = id.expect_local(); diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 8712514a384..7f8fc17744d 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -123,6 +123,11 @@ impl<'tcx> CanonicalVarInfo<'tcx> { self.kind.universe() } + #[must_use] + pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarInfo<'tcx> { + CanonicalVarInfo { kind: self.kind.with_updated_universe(ui) } + } + pub fn is_existential(&self) -> bool { match self.kind { CanonicalVarKind::Ty(_) => true, @@ -133,6 +138,28 @@ impl<'tcx> CanonicalVarInfo<'tcx> { CanonicalVarKind::PlaceholderConst(_, _) => false, } } + + pub fn is_region(&self) -> bool { + match self.kind { + CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, + CanonicalVarKind::Ty(_) + | CanonicalVarKind::PlaceholderTy(_) + | CanonicalVarKind::Const(_, _) + | CanonicalVarKind::PlaceholderConst(_, _) => false, + } + } + + pub fn expect_anon_placeholder(self) -> u32 { + match self.kind { + CanonicalVarKind::Ty(_) + | CanonicalVarKind::Region(_) + | CanonicalVarKind::Const(_, _) => bug!("expected placeholder: {self:?}"), + + CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.name.expect_anon(), + CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.name.expect_anon(), + CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.name.as_u32(), + } + } } /// Describes the "kind" of the canonical variable. This is a "kind" @@ -177,6 +204,38 @@ impl<'tcx> CanonicalVarKind<'tcx> { CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe, } } + + /// Replaces the universe of this canonical variable with `ui`. + /// + /// In case this is a float or int variable, this causes an ICE if + /// the updated universe is not the root. + pub fn with_updated_universe(self, ui: ty::UniverseIndex) -> CanonicalVarKind<'tcx> { + match self { + CanonicalVarKind::Ty(kind) => match kind { + CanonicalTyVarKind::General(_) => { + CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) + } + CanonicalTyVarKind::Int | CanonicalTyVarKind::Float => { + assert_eq!(ui, ty::UniverseIndex::ROOT); + CanonicalVarKind::Ty(kind) + } + }, + CanonicalVarKind::PlaceholderTy(placeholder) => { + CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: ui, ..placeholder }) + } + CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), + CanonicalVarKind::PlaceholderRegion(placeholder) => { + CanonicalVarKind::PlaceholderRegion(ty::Placeholder { universe: ui, ..placeholder }) + } + CanonicalVarKind::Const(_, ty) => CanonicalVarKind::Const(ui, ty), + CanonicalVarKind::PlaceholderConst(placeholder, ty) => { + CanonicalVarKind::PlaceholderConst( + ty::Placeholder { universe: ui, ..placeholder }, + ty, + ) + } + } + } } /// Rust actually has more than one category of type variables; @@ -213,7 +272,8 @@ pub struct QueryResponse<'tcx, R> { pub value: R, } -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec<QueryOutlivesConstraint<'tcx>>, pub member_constraints: Vec<MemberConstraint<'tcx>>, diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 38868c21049..2db59f37f40 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -12,7 +12,8 @@ use rustc_span::Span; /// ```text /// R0 member of [O1..On] /// ``` -#[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct MemberConstraint<'tcx> { /// The `DefId` and substs of the opaque type causing this constraint. /// Used for error reporting. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 221105ac48f..48375ed301d 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -8,7 +8,8 @@ mod tests; use std::borrow::Cow; use std::fmt; use std::hash; -use std::ops::Range; +use std::hash::Hash; +use std::ops::{Deref, DerefMut, Range}; use std::ptr; use either::{Left, Right}; @@ -29,6 +30,39 @@ use provenance_map::*; pub use init_mask::{InitChunk, InitChunkIter}; +/// Functionality required for the bytes of an `Allocation`. +pub trait AllocBytes: + Clone + fmt::Debug + Eq + PartialEq + Hash + Deref<Target = [u8]> + DerefMut<Target = [u8]> +{ + /// Adjust the bytes to the specified alignment -- by default, this is a no-op. + fn adjust_to_align(self, _align: Align) -> Self; + + /// Create an `AllocBytes` from a slice of `u8`. + fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align) -> Self; + + /// Create a zeroed `AllocBytes` of the specified size and alignment; + /// call the callback error handler if there is an error in allocating the memory. + fn zeroed(size: Size, _align: Align) -> Option<Self>; +} + +// Default `bytes` for `Allocation` is a `Box<[u8]>`. +impl AllocBytes for Box<[u8]> { + fn adjust_to_align(self, _align: Align) -> Self { + self + } + + fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align) -> Self { + Box::<[u8]>::from(slice.into()) + } + + fn zeroed(size: Size, _align: Align) -> Option<Self> { + let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).ok()?; + // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> + let bytes = unsafe { bytes.assume_init() }; + Some(bytes) + } +} + /// This type represents an Allocation in the Miri/CTFE core engine. /// /// Its public API is rather low-level, working directly with allocation offsets and a custom error @@ -38,10 +72,10 @@ pub use init_mask::{InitChunk, InitChunkIter}; // hashed. (see the `Hash` impl below for more details), so the impl is not derived. #[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)] #[derive(HashStable)] -pub struct Allocation<Prov: Provenance = AllocId, Extra = ()> { +pub struct Allocation<Prov: Provenance = AllocId, Extra = (), Bytes = Box<[u8]>> { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer. - bytes: Box<[u8]>, + bytes: Bytes, /// Maps from byte addresses to extra provenance data for each pointer. /// Only the first byte of a pointer is inserted into the map; i.e., /// every entry in this map applies to `pointer_size` consecutive bytes starting @@ -220,14 +254,27 @@ impl AllocRange { } // The constructors are all without extra; the extra gets added by a machine hook later. -impl<Prov: Provenance> Allocation<Prov> { +impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { + /// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support + pub fn from_raw_bytes(bytes: Bytes, align: Align, mutability: Mutability) -> Self { + let size = Size::from_bytes(bytes.len()); + Self { + bytes, + provenance: ProvenanceMap::new(), + init_mask: InitMask::new(size, true), + align, + mutability, + extra: (), + } + } + /// Creates an allocation initialized by the given bytes pub fn from_bytes<'a>( slice: impl Into<Cow<'a, [u8]>>, align: Align, mutability: Mutability, ) -> Self { - let bytes = Box::<[u8]>::from(slice.into()); + let bytes = Bytes::from_bytes(slice, align); let size = Size::from_bytes(bytes.len()); Self { bytes, @@ -248,7 +295,7 @@ impl<Prov: Provenance> Allocation<Prov> { /// /// If `panic_on_fail` is true, this will never return `Err`. pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> { - let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| { + let bytes = Bytes::zeroed(size, align).ok_or_else(|| { // This results in an error that can happen non-deterministically, since the memory // available to the compiler can change between runs. Normally queries are always // deterministic. However, we can be non-deterministic here because all uses of const @@ -262,8 +309,7 @@ impl<Prov: Provenance> Allocation<Prov> { }); InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) })?; - // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> - let bytes = unsafe { bytes.assume_init() }; + Ok(Allocation { bytes, provenance: ProvenanceMap::new(), @@ -275,7 +321,7 @@ impl<Prov: Provenance> Allocation<Prov> { } } -impl Allocation { +impl<Bytes: AllocBytes> Allocation<AllocId, (), Bytes> { /// Adjust allocation from the ones in tcx to a custom Machine instance /// with a different Provenance and Extra type. pub fn adjust_from_tcx<Prov: Provenance, Extra, Err>( @@ -283,9 +329,11 @@ impl Allocation { cx: &impl HasDataLayout, extra: Extra, mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>, - ) -> Result<Allocation<Prov, Extra>, Err> { - // Compute new pointer provenance, which also adjusts the bytes. - let mut bytes = self.bytes; + ) -> Result<Allocation<Prov, Extra, Bytes>, Err> { + // Compute new pointer provenance, which also adjusts the bytes, and realign the pointer if + // necessary. + let mut bytes = self.bytes.adjust_to_align(self.align); + let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len()); let ptr_size = cx.data_layout().pointer_size.bytes_usize(); let endian = cx.data_layout().endian; @@ -311,7 +359,7 @@ impl Allocation { } /// Raw accessors. Provide access to otherwise private bytes. -impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { +impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> { pub fn len(&self) -> usize { self.bytes.len() } @@ -340,7 +388,11 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { } /// Byte accessors. -impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { +impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> { + pub fn base_addr(&self) -> *const u8 { + self.bytes.as_ptr() + } + /// This is the entirely abstraction-violating way to just grab the raw bytes without /// caring about provenance or initialization. /// @@ -412,7 +464,7 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { } /// Reading and writing. -impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { +impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> { /// Sets the init bit for the given range. fn mark_init(&mut self, range: AllocRange, is_init: bool) { if range.size.bytes() == 0 { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b0975616b61..1766d7a6698 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -127,8 +127,8 @@ pub use self::error::{ pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; pub use self::allocation::{ - alloc_range, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk, - InitChunkIter, + alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, + InitChunk, InitChunkIter, }; pub use self::pointer::{Pointer, PointerArithmetic, Provenance}; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0d78c6135b3..99cdb769da1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2908,7 +2908,7 @@ fn pretty_print_const_value<'tcx>( // the `destructure_const` query with an empty `ty::ParamEnv` without // introducing ICEs (e.g. via `layout_of`) from missing bounds. // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` - // to be able to destructure the tuple into `(0u8, *mut T) + // to be able to destructure the tuple into `(0u8, *mut T)` // // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the // correct `ty::ParamEnv` to allow printing *all* constant values. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 16daf63b82d..d8829e3e782 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -12,8 +12,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{ - alloc_range, read_target_uint, AllocId, Allocation, ConstAllocation, ConstValue, GlobalAlloc, - Pointer, Provenance, + alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, ConstAllocation, ConstValue, + GlobalAlloc, Pointer, Provenance, }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; @@ -787,21 +787,21 @@ pub fn write_allocations<'tcx>( /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control /// characters or characters whose value is larger than 127) with a `.` /// This also prints provenance adequately. -pub fn display_allocation<'a, 'tcx, Prov: Provenance, Extra>( +pub fn display_allocation<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( tcx: TyCtxt<'tcx>, - alloc: &'a Allocation<Prov, Extra>, -) -> RenderAllocation<'a, 'tcx, Prov, Extra> { + alloc: &'a Allocation<Prov, Extra, Bytes>, +) -> RenderAllocation<'a, 'tcx, Prov, Extra, Bytes> { RenderAllocation { tcx, alloc } } #[doc(hidden)] -pub struct RenderAllocation<'a, 'tcx, Prov: Provenance, Extra> { +pub struct RenderAllocation<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> { tcx: TyCtxt<'tcx>, - alloc: &'a Allocation<Prov, Extra>, + alloc: &'a Allocation<Prov, Extra, Bytes>, } -impl<'a, 'tcx, Prov: Provenance, Extra> std::fmt::Display - for RenderAllocation<'a, 'tcx, Prov, Extra> +impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> std::fmt::Display + for RenderAllocation<'a, 'tcx, Prov, Extra, Bytes> { fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let RenderAllocation { tcx, alloc } = *self; @@ -845,9 +845,9 @@ fn write_allocation_newline( /// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there /// is only one line). Note that your prefix should contain a trailing space as the lines are /// printed directly after it. -fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( +fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( tcx: TyCtxt<'tcx>, - alloc: &Allocation<Prov, Extra>, + alloc: &Allocation<Prov, Extra, Bytes>, w: &mut dyn std::fmt::Write, prefix: &str, ) -> std::fmt::Result { diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 1610ae1ce14..28a3b51b7fc 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -11,7 +11,7 @@ use std::io::{self, Write}; pub const TOOLTIP_INDENT: &str = " "; const CARET: char = '\u{2038}'; // Unicode `CARET` -const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET +const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET` const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` const NEW_LINE_SPAN: &str = "</span>\n<span class=\"line\">"; const HEADER: &str = r#"<!DOCTYPE html> diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 111ea6b8cdd..78ee8a6a8fd 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -4,7 +4,7 @@ use crate::infer::canonical::Canonical; use crate::mir; use crate::traits; use crate::ty::fast_reject::SimplifiedType; -use crate::ty::layout::{InitKind, TyAndLayout}; +use crate::ty::layout::{TyAndLayout, ValidityRequirement}; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; @@ -698,7 +698,7 @@ impl Key for HirId { } } -impl<'tcx> Key for (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { +impl<'tcx> Key for (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>) { type CacheSelector = DefaultCacheSelector<Self>; // Just forward to `Ty<'tcx>` diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8fe5586723d..5133da3429a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -90,6 +90,7 @@ rustc_queries! { /// Definitions that were generated with no HIR, would be feeded to return `None`. query opt_local_def_id_to_hir_id(key: LocalDefId) -> Option<hir::HirId>{ desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) } + feedable } /// Gives access to the HIR node's parent for the HIR owner `key`. @@ -166,6 +167,7 @@ rustc_queries! { } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } query collect_return_position_impl_trait_in_trait_tys(key: DefId) @@ -222,6 +224,7 @@ rustc_queries! { arena_cache cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the @@ -264,6 +267,7 @@ rustc_queries! { desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Elaborated version of the predicates from `explicit_item_bounds`. @@ -588,6 +592,7 @@ rustc_queries! { desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Returns the inferred outlives predicates (e.g., for `struct @@ -596,6 +601,7 @@ rustc_queries! { desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Maps from the `DefId` of a trait to the list of @@ -728,6 +734,7 @@ rustc_queries! { desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern + feedable } /// Collects the associated items defined on a trait or impl. @@ -1142,6 +1149,15 @@ rustc_queries! { desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable + } + + /// The `opt_rpitit_info` query returns the pair of the def id of the function where the RPIT + /// is defined and the opaque def id if any. + query opt_rpitit_info(def_id: DefId) -> Option<ty::ImplTraitInTraitData> { + desc { |tcx| "opt_rpitit_info `{}`", tcx.def_path_str(def_id) } + cache_on_disk_if { def_id.is_local() } + feedable } /// Gets the span for the definition. @@ -1157,6 +1173,7 @@ rustc_queries! { desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable } query lookup_stability(def_id: DefId) -> Option<attr::Stability> { @@ -1498,6 +1515,7 @@ rustc_queries! { desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern + feedable } query check_well_formed(key: hir::OwnerId) -> () { @@ -1654,7 +1672,7 @@ rustc_queries! { /// Does lifetime resolution on items. Importantly, we can't resolve /// lifetimes directly on things like trait methods, because of trait params. - /// See `rustc_resolve::late::lifetimes for details. + /// See `rustc_resolve::late::lifetimes` for details. query resolve_bound_vars(_: hir::OwnerId) -> &'tcx ResolveBoundVars { arena_cache desc { "resolving lifetimes" } @@ -1695,6 +1713,7 @@ rustc_queries! { query visibility(def_id: DefId) -> ty::Visibility<DefId> { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } separate_provide_extern + feedable } query inhabited_predicate_adt(key: DefId) -> ty::inhabitedness::InhabitedPredicate<'tcx> { @@ -2166,8 +2185,8 @@ rustc_queries! { separate_provide_extern } - query check_validity_of_init(key: (InitKind, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> { - desc { "checking to see if `{}` permits being left {}", key.1.value, key.0 } + query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> { + desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 } } query compare_impl_const( diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 2b3601bec7b..3b11fab8cdf 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -237,6 +237,9 @@ pub struct LocalVarId(pub hir::HirId); /// A THIR expression. #[derive(Clone, Debug, HashStable)] pub struct Expr<'tcx> { + /// kind of expression + pub kind: ExprKind<'tcx>, + /// The type of this expression pub ty: Ty<'tcx>, @@ -246,9 +249,6 @@ pub struct Expr<'tcx> { /// span of the expression in the source pub span: Span, - - /// kind of expression - pub kind: ExprKind<'tcx>, } #[derive(Clone, Debug, HashStable)] diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index c5bf9717f03..bd43867a3da 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -2,6 +2,7 @@ use std::ops::ControlFlow; use rustc_data_structures::intern::Interned; +use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; @@ -18,20 +19,25 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { } /// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)] +#[derive(Debug, PartialEq, Eq, Clone, Hash, Default, TypeFoldable, TypeVisitable)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. - pub regions: (), + pub region_constraints: QueryRegionConstraints<'tcx>, pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>, } +// FIXME: Having to clone `region_constraints` for folding feels bad and +// probably isn't great wrt performance. +// +// Not sure how to fix this, maybe we should also intern `opaque_types` and +// `region_constraints` here or something. impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, folder: &mut F, ) -> Result<Self, F::Error> { Ok(FallibleTypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { - regions: (), + region_constraints: self.region_constraints.clone().try_fold_with(folder)?, opaque_types: self .opaque_types .iter() @@ -42,7 +48,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self { TypeFolder::interner(folder).mk_external_constraints(ExternalConstraintsData { - regions: (), + region_constraints: self.region_constraints.clone().fold_with(folder), opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(), }) } @@ -53,7 +59,7 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> { &self, visitor: &mut V, ) -> std::ops::ControlFlow<V::BreakTy> { - self.regions.visit_with(visitor)?; + self.region_constraints.visit_with(visitor)?; self.opaque_types.visit_with(visitor)?; ControlFlow::Continue(()) } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 884ae7f5da2..527ec9f6e1c 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -16,7 +16,7 @@ pub use int::*; pub use kind::*; pub use valtree::*; -/// Use this rather than `ConstData, whenever possible. +/// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_pass_by_value] pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0333198c203..d9af2fd74ce 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -310,7 +310,7 @@ pub struct CommonLifetimes<'tcx> { pub re_vars: Vec<Region<'tcx>>, /// Pre-interned values of the form: - /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(v, None) }) + /// `ReLateBound(DebruijnIndex(i), BoundRegion { var: v, kind: BrAnon(v, None) })` /// for small values of `i` and `v`. pub re_late_bounds: Vec<Vec<Region<'tcx>>>, } @@ -794,8 +794,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool { - let cname = self.crate_name(LOCAL_CRATE); - self.sess.consider_optimizing(cname.as_str(), msg) + self.sess.consider_optimizing(|| self.crate_name(LOCAL_CRATE), msg) } /// Obtain all lang items of this crate and all dependencies (recursively) @@ -2187,7 +2186,7 @@ impl<'tcx> TyCtxt<'tcx> { // Actually intern type lists as lists of `GenericArg`s. // // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound - // as explained in ty_slice_as_generic_arg`. With this, + // as explained in `ty_slice_as_generic_arg`. With this, // we guarantee that even when transmuting between `List<Ty<'tcx>>` // and `List<GenericArg<'tcx>>`, the uniqueness requirement for // lists is upheld. @@ -2450,7 +2449,7 @@ impl<'tcx> TyCtxtAt<'tcx> { self.tcx.ty_error_with_message(self.span, "TyKind::Error constructed but no error reported") } - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to /// ensure it gets used. #[track_caller] pub fn ty_error_with_message(self, msg: &str) -> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 355b8d8b431..92a040068dd 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -105,7 +105,7 @@ impl<'tcx> VariantDef { impl<'tcx> Ty<'tcx> { pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> { match self.kind() { - // For now, union`s are always considered inhabited + // For now, unions are always considered inhabited Adt(adt, _) if adt.is_union() => InhabitedPredicate::True, // Non-exhaustive ADTs from other crates are always considered inhabited Adt(adt, _) if adt.is_variant_list_non_exhaustive() && !adt.did().is_local() => { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f0b52455889..254ffc33c96 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -7,6 +7,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_session::config::OptLevel; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::call::FnAbi; use rustc_target::abi::*; @@ -92,7 +93,7 @@ impl IntegerExt for Integer { if discr < fit { bug!( "Integer::repr_discr: `#[repr]` hint too small for \ - discriminant range of enum `{}", + discriminant range of enum `{}`", ty ) } @@ -169,19 +170,37 @@ pub const FAT_PTR_EXTRA: usize = 1; /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. pub const MAX_SIMD_LANES: u64 = 1 << 0xF; -/// Used in `might_permit_raw_init` to indicate the kind of initialisation +/// Used in `check_validity_requirement` to indicate the kind of initialization /// that is checked to be valid #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)] -pub enum InitKind { +pub enum ValidityRequirement { + Inhabited, Zero, + /// The return value of mem::uninitialized, 0x01 + /// (unless -Zstrict-init-checks is on, in which case it's the same as Uninit). UninitMitigated0x01Fill, + /// True uninitialized memory. + Uninit, } -impl fmt::Display for InitKind { +impl ValidityRequirement { + pub fn from_intrinsic(intrinsic: Symbol) -> Option<Self> { + match intrinsic { + sym::assert_inhabited => Some(Self::Inhabited), + sym::assert_zero_valid => Some(Self::Zero), + sym::assert_mem_uninitialized_valid => Some(Self::UninitMitigated0x01Fill), + _ => None, + } + } +} + +impl fmt::Display for ValidityRequirement { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Zero => f.write_str("zeroed"), - Self::UninitMitigated0x01Fill => f.write_str("filled with 0x01"), + Self::Inhabited => f.write_str("is inhabited"), + Self::Zero => f.write_str("allows being left zeroed"), + Self::UninitMitigated0x01Fill => f.write_str("allows being filled with 0x01"), + Self::Uninit => f.write_str("allows being left uninitialized"), } } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fc5757564a7..dce18a5850f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -710,7 +710,7 @@ impl<'tcx> Predicate<'tcx> { // The substitution from the input trait-ref is therefore going to be // `'a => 'x` (where `'x` has a DB index of 1). // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an - // early-bound parameter and `'b' is a late-bound parameter with a + // early-bound parameter and `'b` is a late-bound parameter with a // DB index of 1. // - If we replace `'a` with `'x` from the input, it too will have // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` @@ -2071,6 +2071,12 @@ pub enum ImplOverlapKind { Issue33140, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] +pub enum ImplTraitInTraitData { + Trait { fn_def_id: DefId, opaque_def_id: DefId }, + Impl { fn_def_id: DefId }, +} + impl<'tcx> TyCtxt<'tcx> { pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> { self.typeck(self.hir().body_owner_def_id(body)) @@ -2438,7 +2444,7 @@ impl<'tcx> TyCtxt<'tcx> { None } - /// Check if the given `DefId` is `#\[automatically_derived\], *and* + /// Check if the given `DefId` is `#\[automatically_derived\]`, *and* /// whether it was produced by expanding a builtin derive macro. pub fn is_builtin_derived(self, def_id: DefId) -> bool { if self.is_automatically_derived(def_id) @@ -2541,6 +2547,34 @@ impl<'tcx> TyCtxt<'tcx> { } def_id } + + pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { + if self.def_kind(def_id) != DefKind::AssocFn { + return false; + } + + let Some(item) = self.opt_associated_item(def_id) else { return false; }; + if item.container != ty::AssocItemContainer::ImplContainer { + return false; + } + + let Some(trait_item_def_id) = item.trait_item_def_id else { return false; }; + + // FIXME(RPITIT): This does a somewhat manual walk through the signature + // of the trait fn to look for any RPITITs, but that's kinda doing a lot + // of work. We can probably remove this when we refactor RPITITs to be + // associated types. + self.fn_sig(trait_item_def_id).subst_identity().skip_binder().output().walk().any(|arg| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() + && let ty::Alias(ty::Projection, data) = ty.kind() + && self.def_kind(data.def_id) == DefKind::ImplTraitPlaceholder + { + true + } else { + false + } + }) + } } /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition. diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 57c8f3075b0..578cd82aa4c 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -7,7 +7,6 @@ //! `normalize_generic_arg_after_erasing_regions` query for each type //! or constant found within. (This underlying query is what is cached.) -use crate::mir; use crate::traits::query::NoSolution; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder}; use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeVisitableExt}; @@ -16,7 +15,6 @@ use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeVisitableExt}; pub enum NormalizationError<'tcx> { Type(Ty<'tcx>), Const(ty::Const<'tcx>), - ConstantKind(mir::ConstantKind<'tcx>), } impl<'tcx> NormalizationError<'tcx> { @@ -24,7 +22,6 @@ impl<'tcx> NormalizationError<'tcx> { match self { NormalizationError::Type(t) => format!("{}", t), NormalizationError::Const(c) => format!("{}", c), - NormalizationError::ConstantKind(ck) => format!("{}", ck), } } } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs index d743c306849..2bc51baf879 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -32,7 +32,7 @@ use crate::traits::specialization_graph; use crate::traits::{self, ImplSource}; use crate::ty::context::TyCtxtFeed; use crate::ty::fast_reject::SimplifiedType; -use crate::ty::layout::InitKind; +use crate::ty::layout::ValidityRequirement; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::GeneratorDiagnosticData; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ba714541c9e..e6a73e8bb1c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -107,6 +107,15 @@ impl BoundRegionKind { _ => None, } } + + pub fn expect_anon(&self) -> u32 { + match *self { + BoundRegionKind::BrNamed(_, _) | BoundRegionKind::BrEnv => { + bug!("expected anon region: {self:?}") + } + BoundRegionKind::BrAnon(idx, _) => idx, + } + } } pub trait Article { diff --git a/compiler/rustc_mir_build/locales/en-US.ftl b/compiler/rustc_mir_build/locales/en-US.ftl index f9bda721df3..93e7fb330e0 100644 --- a/compiler/rustc_mir_build/locales/en-US.ftl +++ b/compiler/rustc_mir_build/locales/en-US.ftl @@ -374,3 +374,9 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co } matched mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits + + +mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly + .attributes = no other attributes may be applied + .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call + .missing_box = `#[rustc_box]` requires the `owned_box` lang item diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 2f63333d46b..cfacb5ea327 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -55,7 +55,7 @@ pub fn as_constant_inner<'tcx>( ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar)) } Err(LitToConstError::TypeError) => { - bug!("encountered type error in `lit_to_mir_constant") + bug!("encountered type error in `lit_to_mir_constant`") } }; diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index eb20b2308c0..33200b80a57 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::AdtDef; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_span::Span; use rustc_target::abi::VariantIdx; @@ -183,7 +183,7 @@ fn to_upvars_resolved_place_builder<'tcx>( &projection, ) else { let closure_span = cx.tcx.def_span(closure_def_id); - if !enable_precise_capture(cx.tcx, closure_span) { + if !enable_precise_capture(closure_span) { bug!( "No associated capture found for {:?}[{:#?}] even though \ capture_disjoint_fields isn't enabled", @@ -745,8 +745,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if -/// user is using Rust Edition 2021 or higher. -fn enable_precise_capture(tcx: TyCtxt<'_>, closure_span: Span) -> bool { - tcx.features().capture_disjoint_fields || closure_span.rust_2021() +/// Precise capture is enabled if user is using Rust Edition 2021 or higher. +fn enable_precise_capture(closure_span: Span) -> bool { + closure_span.rust_2021() } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index c1f6b8b59ce..dc4d2276e4a 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -888,3 +888,22 @@ pub enum MiscPatternSuggestion { start_span: Span, }, } + +#[derive(Diagnostic)] +#[diag(mir_build_rustc_box_attribute_error)] +pub struct RustcBoxAttributeError { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub reason: RustcBoxAttrReason, +} + +#[derive(Subdiagnostic)] +pub enum RustcBoxAttrReason { + #[note(mir_build_attributes)] + Attributes, + #[note(mir_build_not_box)] + NotBoxNew, + #[note(mir_build_missing_box)] + MissingBox, +} diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 1b790e16b48..9086412c09a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,3 +1,4 @@ +use crate::errors; use crate::thir::cx::region::Scope; use crate::thir::cx::Cx; use crate::thir::util::UserAnnotatedTyHelpers; @@ -18,7 +19,7 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{ self, AdtKind, InlineConstSubsts, InlineConstSubstsParts, ScalarInt, Ty, UpvarSubsts, UserType, }; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::abi::VariantIdx; impl<'tcx> Cx<'tcx> { @@ -260,6 +261,7 @@ impl<'tcx> Cx<'tcx> { } } + #[instrument(level = "debug", skip(self), ret)] fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let tcx = self.tcx; let expr_ty = self.typeck_results().expr_ty(expr); @@ -320,6 +322,34 @@ impl<'tcx> Cx<'tcx> { fn_span: expr.span, } } else { + let attrs = tcx.hir().attrs(expr.hir_id); + if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_box) { + if attrs.len() != 1 { + tcx.sess.emit_err(errors::RustcBoxAttributeError { + span: attrs[0].span, + reason: errors::RustcBoxAttrReason::Attributes, + }); + } else if let Some(box_item) = tcx.lang_items().owned_box() { + if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = fun.kind + && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind + && path.res.opt_def_id().map_or(false, |did| did == box_item) + && fn_path.ident.name == sym::new + && let [value] = args + { + return Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: ExprKind::Box { value: self.mirror_expr(value) } } + } else { + tcx.sess.emit_err(errors::RustcBoxAttributeError { + span: expr.span, + reason: errors::RustcBoxAttrReason::NotBoxNew + }); + } + } else { + tcx.sess.emit_err(errors::RustcBoxAttributeError { + span: attrs[0].span, + reason: errors::RustcBoxAttrReason::MissingBox, + }); + } + } let adt_data = if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind { // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index fa5f392fa74..536745d2cfe 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -74,7 +74,7 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { // // `unsafe { *FOO = 0; *BAR.field = 1; }` // `unsafe { &mut *FOO }` - // `unsafe { (*ARRAY)[0] = val; } + // `unsafe { (*ARRAY)[0] = val; }` if !place.projection.iter().any(|p| matches!(p, PlaceElem::Deref)) { let source_info = self.body.source_info(location); let lint_root = self.body.source_scopes[source_info.scope] diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f973c1ed28f..8ee316773ae 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -407,7 +407,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() { // Macros that expand to include branching (such as // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or - // `trace!()) typically generate callee spans with identical + // `trace!()`) typically generate callee spans with identical // ranges (typically the full span of the macro) for all // `BasicBlocks`. This makes it impossible to distinguish // the condition (`if val1 != val2`) from the optional @@ -694,7 +694,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`. /// If prev.span() was split off to the right of a closure, prev.span().lo() will be /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is - /// not as important as knowing that `prev()` **used to have the same span** as `curr(), + /// not as important as knowing that `prev()` **used to have the same span** as `curr()`, /// which means their sort order is still meaningful for determining the dominator /// relationship. /// diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs index 05286b71d47..4182da1957e 100644 --- a/compiler/rustc_mir_transform/src/instcombine.rs +++ b/compiler/rustc_mir_transform/src/instcombine.rs @@ -6,9 +6,9 @@ use rustc_middle::mir::{ BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp, }; -use rustc_middle::ty::layout::InitKind; +use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::Symbol; pub struct InstCombine; @@ -256,16 +256,8 @@ fn intrinsic_assert_panics<'tcx>( ty: Ty<'tcx>, intrinsic_name: Symbol, ) -> Option<bool> { - Some(match intrinsic_name { - sym::assert_inhabited => tcx.layout_of(param_env.and(ty)).ok()?.abi.is_uninhabited(), - sym::assert_zero_valid => { - !tcx.check_validity_of_init((InitKind::Zero, param_env.and(ty))).ok()? - } - sym::assert_mem_uninitialized_valid => !tcx - .check_validity_of_init((InitKind::UninitMitigated0x01Fill, param_env.and(ty))) - .ok()?, - _ => return None, - }) + let requirement = ValidityRequirement::from_intrinsic(intrinsic_name)?; + Some(!tcx.check_validity_requirement((requirement, param_env.and(ty))).ok()?) } fn resolve_rust_intrinsic<'tcx>( diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4193eb7d6e8..cdd28ae0c01 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -248,7 +248,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> // N.B., this `borrow()` is guaranteed to be valid (i.e., the value // cannot yet be stolen), because `mir_promoted()`, which steals - // from `mir_const(), forces this query to execute before + // from `mir_const()`, forces this query to execute before // performing the steal. let body = &tcx.mir_const(def).borrow(); diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index 2f02d00ec9f..c6e7468aab4 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -68,8 +68,11 @@ fn lower_slice_len_call<'tcx>( ty::FnDef(fn_def_id, _) if fn_def_id == &slice_len_fn_item_def_id => { // perform modifications // from something like `_5 = core::slice::<impl [u8]>::len(move _6) -> bb1` - // into `_5 = Len(*_6) + // into: + // ``` + // _5 = Len(*_6) // goto bb1 + // ``` // make new RValue for Len let deref_arg = tcx.mk_place_deref(arg); diff --git a/compiler/rustc_parse/locales/en-US.ftl b/compiler/rustc_parse/locales/en-US.ftl index 4ddeeed5b7e..e76e91fc1b1 100644 --- a/compiler/rustc_parse/locales/en-US.ftl +++ b/compiler/rustc_parse/locales/en-US.ftl @@ -151,6 +151,10 @@ parse_missing_in_in_for_loop = missing `in` in `for` loop parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop .suggestion = try adding an expression to the `for` loop +parse_loop_else = `{$loop_kind}...else` loops are not supported + .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + .loop_keyword = `else` is attached to this loop + parse_missing_comma_after_match_arm = expected `,` following `match` arm .suggestion = missing a comma here to end this `match` arm diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index c746a870964..1662db36d10 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -452,6 +452,17 @@ pub(crate) struct MissingExpressionInForLoop { } #[derive(Diagnostic)] +#[diag(parse_loop_else)] +#[note] +pub(crate) struct LoopElseNotSupported { + #[primary_span] + pub span: Span, + pub loop_kind: &'static str, + #[label(parse_loop_keyword)] + pub loop_kw: Span, +} + +#[derive(Diagnostic)] #[diag(parse_missing_comma_after_match_arm)] pub(crate) struct MissingCommaAfterMatchArm { #[primary_span] diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 386bf026bb4..27f4428d306 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -1,4 +1,4 @@ -use super::UnmatchedBrace; +use super::UnmatchedDelim; use rustc_ast::token::Delimiter; use rustc_errors::Diagnostic; use rustc_span::source_map::SourceMap; @@ -8,7 +8,7 @@ use rustc_span::Span; pub struct TokenTreeDiagInfo { /// Stack of open delimiters and their spans. Used for error message. pub open_braces: Vec<(Delimiter, Span)>, - pub unmatched_braces: Vec<UnmatchedBrace>, + pub unmatched_delims: Vec<UnmatchedDelim>, /// Used only for error recovery when arriving to EOF with mismatched braces. pub last_unclosed_found_span: Option<Span>, @@ -32,10 +32,10 @@ pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> b // it's more friendly compared to report `unmatched error` in later phase pub fn report_missing_open_delim( err: &mut Diagnostic, - unmatched_braces: &[UnmatchedBrace], + unmatched_delims: &[UnmatchedDelim], ) -> bool { let mut reported_missing_open = false; - for unmatch_brace in unmatched_braces.iter() { + for unmatch_brace in unmatched_delims.iter() { if let Some(delim) = unmatch_brace.found_delim && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket) { @@ -60,7 +60,7 @@ pub fn report_suspicious_mismatch_block( sm: &SourceMap, delim: Delimiter, ) { - if report_missing_open_delim(err, &diag_info.unmatched_braces) { + if report_missing_open_delim(err, &diag_info.unmatched_delims) { return; } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 37449aaabed..9dbddee5a56 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,10 +1,11 @@ use crate::errors; use crate::lexer::unicode_chars::UNICODE_ARRAY; +use crate::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, PResult, StashKey}; +use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::Cursor; use rustc_lexer::{Base, DocStyle, RawStrError}; @@ -31,7 +32,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char}; rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12); #[derive(Clone, Debug)] -pub struct UnmatchedBrace { +pub struct UnmatchedDelim { pub expected_delim: Delimiter, pub found_delim: Option<Delimiter>, pub found_span: Span, @@ -44,7 +45,7 @@ pub(crate) fn parse_token_trees<'a>( mut src: &'a str, mut start_pos: BytePos, override_span: Option<Span>, -) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) { +) -> Result<TokenStream, Vec<Diagnostic>> { // Skip `#!`, if present. if let Some(shebang_len) = rustc_lexer::strip_shebang(src) { src = &src[shebang_len..]; @@ -61,7 +62,29 @@ pub(crate) fn parse_token_trees<'a>( override_span, nbsp_is_whitespace: false, }; - tokentrees::TokenTreesReader::parse_all_token_trees(string_reader) + let (token_trees, unmatched_delims) = + tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); + match token_trees { + Ok(stream) if unmatched_delims.is_empty() => Ok(stream), + _ => { + // Return error if there are unmatched delimiters or unclosng delimiters. + // We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch + // because the delimiter mismatch is more likely to be the root cause of error + + let mut buffer = Vec::with_capacity(1); + // Not using `emit_unclosed_delims` to use `db.buffer` + for unmatched in unmatched_delims { + if let Some(err) = make_unclosed_delims_error(unmatched, &sess) { + err.buffer(&mut buffer); + } + } + if let Err(err) = token_trees { + // Add unclosing delimiter error + err.buffer(&mut buffer); + } + Err(buffer) + } + } } struct StringReader<'a> { diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 0de8f79112c..36fd1e37d65 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -1,7 +1,7 @@ use super::diagnostics::report_suspicious_mismatch_block; use super::diagnostics::same_identation_level; use super::diagnostics::TokenTreeDiagInfo; -use super::{StringReader, UnmatchedBrace}; +use super::{StringReader, UnmatchedDelim}; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; @@ -18,14 +18,14 @@ pub(super) struct TokenTreesReader<'a> { impl<'a> TokenTreesReader<'a> { pub(super) fn parse_all_token_trees( string_reader: StringReader<'a>, - ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) { + ) -> (PResult<'a, TokenStream>, Vec<UnmatchedDelim>) { let mut tt_reader = TokenTreesReader { string_reader, token: Token::dummy(), diag_info: TokenTreeDiagInfo::default(), }; let res = tt_reader.parse_token_trees(/* is_delimited */ false); - (res, tt_reader.diag_info.unmatched_braces) + (res, tt_reader.diag_info.unmatched_delims) } // Parse a stream of tokens into a list of `TokenTree`s. @@ -34,7 +34,7 @@ impl<'a> TokenTreesReader<'a> { let mut buf = Vec::new(); loop { match self.token.kind { - token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)), + token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)?), token::CloseDelim(delim) => { return if is_delimited { Ok(TokenStream::new(buf)) @@ -43,10 +43,11 @@ impl<'a> TokenTreesReader<'a> { }; } token::Eof => { - if is_delimited { - self.eof_err().emit(); - } - return Ok(TokenStream::new(buf)); + return if is_delimited { + Err(self.eof_err()) + } else { + Ok(TokenStream::new(buf)) + }; } _ => { // Get the next normal token. This might require getting multiple adjacent @@ -78,7 +79,7 @@ impl<'a> TokenTreesReader<'a> { let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg); for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); - self.diag_info.unmatched_braces.push(UnmatchedBrace { + self.diag_info.unmatched_delims.push(UnmatchedDelim { expected_delim: Delimiter::Brace, found_delim: None, found_span: self.token.span, @@ -98,7 +99,7 @@ impl<'a> TokenTreesReader<'a> { err } - fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> TokenTree { + fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> PResult<'a, TokenTree> { // The span for beginning of the delimited section let pre_span = self.token.span; @@ -107,7 +108,7 @@ impl<'a> TokenTreesReader<'a> { // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user // uses an incorrect delimiter. - let tts = self.parse_token_trees(/* is_delimited */ true).unwrap(); + let tts = self.parse_token_trees(/* is_delimited */ true)?; // Expand to cover the entire delimited token tree let delim_span = DelimSpan::from_pair(pre_span, self.token.span); @@ -160,7 +161,7 @@ impl<'a> TokenTreesReader<'a> { } } let (tok, _) = self.diag_info.open_braces.pop().unwrap(); - self.diag_info.unmatched_braces.push(UnmatchedBrace { + self.diag_info.unmatched_delims.push(UnmatchedDelim { expected_delim: tok, found_delim: Some(close_delim), found_span: self.token.span, @@ -190,7 +191,7 @@ impl<'a> TokenTreesReader<'a> { _ => unreachable!(), } - TokenTree::Delimited(delim_span, open_delim, tts) + Ok(TokenTree::Delimited(delim_span, open_delim, tts)) } fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'a> { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 6f37e9758fc..d1c3fd0cd0f 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -30,7 +30,7 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); #[macro_use] pub mod parser; -use parser::{emit_unclosed_delims, make_unclosed_delims_error, Parser}; +use parser::{make_unclosed_delims_error, Parser}; pub mod lexer; pub mod validate_attr; @@ -96,10 +96,7 @@ pub fn parse_stream_from_source_str( sess: &ParseSess, override_span: Option<Span>, ) -> TokenStream { - let (stream, mut errors) = - source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span); - emit_unclosed_delims(&mut errors, &sess); - stream + source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span) } /// Creates a new parser from a source string. @@ -135,9 +132,8 @@ fn maybe_source_file_to_parser( source_file: Lrc<SourceFile>, ) -> Result<Parser<'_>, Vec<Diagnostic>> { let end_pos = source_file.end_pos; - let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?; + let stream = maybe_file_to_stream(sess, source_file, None)?; let mut parser = stream_to_parser(sess, stream, None); - parser.unclosed_delims = unclosed_delims; if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); } @@ -182,7 +178,7 @@ pub fn source_file_to_stream( sess: &ParseSess, source_file: Lrc<SourceFile>, override_span: Option<Span>, -) -> (TokenStream, Vec<lexer::UnmatchedBrace>) { +) -> TokenStream { panictry_buffer!(&sess.span_diagnostic, maybe_file_to_stream(sess, source_file, override_span)) } @@ -192,7 +188,7 @@ pub fn maybe_file_to_stream( sess: &ParseSess, source_file: Lrc<SourceFile>, override_span: Option<Span>, -) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> { +) -> Result<TokenStream, Vec<Diagnostic>> { let src = source_file.src.as_ref().unwrap_or_else(|| { sess.span_diagnostic.bug(&format!( "cannot lex `source_file` without source: {}", @@ -200,23 +196,7 @@ pub fn maybe_file_to_stream( )); }); - let (token_trees, unmatched_braces) = - lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span); - - match token_trees { - Ok(stream) => Ok((stream, unmatched_braces)), - Err(err) => { - let mut buffer = Vec::with_capacity(1); - err.buffer(&mut buffer); - // Not using `emit_unclosed_delims` to use `db.buffer` - for unmatched in unmatched_braces { - if let Some(err) = make_unclosed_delims_error(unmatched, &sess) { - err.buffer(&mut buffer); - } - } - Err(buffer) - } - } + lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span) } /// Given a stream and the `ParseSess`, produces a parser. diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index dbd3b76786f..b0ab0f10624 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -134,11 +134,11 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // Process the replace ranges, starting from the highest start // position and working our way back. If have tokens like: // - // `#[cfg(FALSE)]` struct Foo { #[cfg(FALSE)] field: bool }` + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` // // Then we will generate replace ranges for both // the `#[cfg(FALSE)] field: bool` and the entire - // `#[cfg(FALSE)]` struct Foo { #[cfg(FALSE)] field: bool }` + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` // // By starting processing from the replace range with the greatest // start position, we ensure that any replace range which encloses diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b4948dddcc9..a051dbe9ff5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -19,7 +19,7 @@ use crate::errors::{ }; use crate::fluent_generated as fluent; -use crate::lexer::UnmatchedBrace; +use crate::lexer::UnmatchedDelim; use crate::parser; use rustc_ast as ast; use rustc_ast::ptr::P; @@ -165,8 +165,6 @@ enum IsStandalone { #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum IncOrDec { Inc, - // FIXME: `i--` recovery isn't implemented yet - #[allow(dead_code)] Dec, } @@ -222,7 +220,7 @@ impl MultiSugg { /// is dropped. pub struct SnapshotParser<'a> { parser: Parser<'a>, - unclosed_delims: Vec<UnmatchedBrace>, + unclosed_delims: Vec<UnmatchedDelim>, } impl<'a> Deref for SnapshotParser<'a> { @@ -264,7 +262,7 @@ impl<'a> Parser<'a> { self.unclosed_delims.extend(snapshot.unclosed_delims); } - pub fn unclosed_delims(&self) -> &[UnmatchedBrace] { + pub fn unclosed_delims(&self) -> &[UnmatchedDelim] { &self.unclosed_delims } @@ -1357,6 +1355,20 @@ impl<'a> Parser<'a> { self.recover_from_inc_dec(operand_expr, kind, op_span) } + pub(super) fn recover_from_postfix_decrement( + &mut self, + operand_expr: P<Expr>, + op_span: Span, + start_stmt: bool, + ) -> PResult<'a, P<Expr>> { + let kind = IncDecRecovery { + standalone: if start_stmt { IsStandalone::Standalone } else { IsStandalone::Subexpr }, + op: IncOrDec::Dec, + fixity: UnaryFixity::Post, + }; + self.recover_from_inc_dec(operand_expr, kind, op_span) + } + fn recover_from_inc_dec( &mut self, base: P<Expr>, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 33254d034c9..95a7ca80d5d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -282,6 +282,18 @@ impl<'a> Parser<'a> { continue; } + if self.prev_token == token::BinOp(token::Minus) + && self.token == token::BinOp(token::Minus) + && self.prev_token.span.between(self.token.span).is_empty() + && !self.look_ahead(1, |tok| tok.can_begin_expr()) + { + let op_span = self.prev_token.span.to(self.token.span); + // Eat the second `-` + self.bump(); + lhs = self.recover_from_postfix_decrement(lhs, op_span, starts_stmt)?; + continue; + } + let op = op.node; // Special cases: if op == AssocOp::As { @@ -1198,8 +1210,13 @@ impl<'a> Parser<'a> { // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`. self.restore_snapshot(snapshot); let close_paren = self.prev_token.span; - let span = lo.to(self.prev_token.span); - if !fields.is_empty() { + let span = lo.to(close_paren); + if !fields.is_empty() && + // `token.kind` should not be compared here. + // This is because the `snapshot.token.kind` is treated as the same as + // that of the open delim in `TokenTreesReader::parse_token_tree`, even if they are different. + self.span_to_snippet(close_paren).map_or(false, |snippet| snippet == ")") + { let mut replacement_err = errors::ParenthesesWithStructFields { span, r#type: path, @@ -2491,9 +2508,27 @@ impl<'a> Parser<'a> { let (attrs, loop_block) = self.parse_inner_attrs_and_block()?; let kind = ExprKind::ForLoop(pat, expr, loop_block, opt_label); + + self.recover_loop_else("for", lo)?; + Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs)) } + /// Recovers from an `else` clause after a loop (`for...else`, `while...else`) + fn recover_loop_else(&mut self, loop_kind: &'static str, loop_kw: Span) -> PResult<'a, ()> { + if self.token.is_keyword(kw::Else) && self.may_recover() { + let else_span = self.token.span; + self.bump(); + let else_clause = self.parse_expr_else()?; + self.sess.emit_err(errors::LoopElseNotSupported { + span: else_span.to(else_clause.span), + loop_kind, + loop_kw, + }); + } + Ok(()) + } + fn error_missing_in_for_loop(&mut self) { let (span, sub): (_, fn(_) -> _) = if self.token.is_ident_named(sym::of) { // Possibly using JS syntax (#75311). @@ -2518,6 +2553,9 @@ impl<'a> Parser<'a> { err.span_label(cond.span, "this `while` condition successfully parsed"); err })?; + + self.recover_loop_else("while", lo)?; + Ok(self.mk_expr_with_attrs( lo.to(self.prev_token.span), ExprKind::While(cond, body, opt_label), @@ -2529,6 +2567,7 @@ impl<'a> Parser<'a> { fn parse_expr_loop(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { let loop_span = self.prev_token.span; let (attrs, body) = self.parse_inner_attrs_and_block()?; + self.recover_loop_else("loop", lo)?; Ok(self.mk_expr_with_attrs( lo.to(self.prev_token.span), ExprKind::Loop(body, opt_label, loop_span), diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index fda9151478f..da82e4724d1 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -10,7 +10,7 @@ mod path; mod stmt; mod ty; -use crate::lexer::UnmatchedBrace; +use crate::lexer::UnmatchedDelim; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use item::FnParseMode; @@ -149,7 +149,7 @@ pub struct Parser<'a> { /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery /// it gets removed from here. Every entry left at the end gets emitted as an independent /// error. - pub(super) unclosed_delims: Vec<UnmatchedBrace>, + pub(super) unclosed_delims: Vec<UnmatchedDelim>, last_unexpected_token_span: Option<Span>, /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it /// looked like it could have been a mistyped path or literal `Option:Some(42)`). @@ -335,7 +335,7 @@ impl TokenCursor { num_of_hashes = cmp::max(num_of_hashes, count); } - // `/// foo` becomes `doc = r"foo". + // `/// foo` becomes `doc = r"foo"`. let delim_span = DelimSpan::from_single(span); let body = TokenTree::Delimited( delim_span, @@ -1521,11 +1521,11 @@ impl<'a> Parser<'a> { } pub(crate) fn make_unclosed_delims_error( - unmatched: UnmatchedBrace, + unmatched: UnmatchedDelim, sess: &ParseSess, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to - // `unmatched_braces` only for error recovery in the `Parser`. + // `unmatched_delims` only for error recovery in the `Parser`. let found_delim = unmatched.found_delim?; let mut spans = vec![unmatched.found_span]; if let Some(sp) = unmatched.unclosed_span { @@ -1542,7 +1542,7 @@ pub(crate) fn make_unclosed_delims_error( Some(err) } -pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &ParseSess) { +pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedDelim>, sess: &ParseSess) { *sess.reached_eof.borrow_mut() |= unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()); for unmatched in unclosed_delims.drain(..) { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 51a19c8e3c0..5e2d2d3e5a7 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -646,7 +646,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one - // non-inline use (in `ast::UseTreeKind::Nested). The former case is more + // non-inline use (in `ast::UseTreeKind::Nested`). The former case is more // common, so we don't implement `visit_use_tree` and tolerate the missed // coverage in the latter case. diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs index 6d5983f53dc..053bf5c234a 100644 --- a/compiler/rustc_passes/src/liveness/rwu_table.rs +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -9,7 +9,7 @@ pub(super) struct RWU { } /// Conceptually, this is like a `Vec<Vec<RWU>>`. But the number of -/// RWU`s can get very large, so it uses a more compact representation. +/// RWU's can get very large, so it uses a more compact representation. pub(super) struct RWUTable { /// Total number of live nodes. live_nodes: usize, diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 70c481fb0ee..46e34462cf2 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -333,7 +333,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> { }, ); - // `Encode the file footer. + // Encode the file footer. let footer_pos = encoder.position() as u64; encoder.encode_tagged( TAG_FILE_FOOTER, diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 586bd38fbb8..5f003fa70e1 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -25,7 +25,6 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::mem; -use std::ptr; use thin_vec::ThinVec; use super::QueryConfig; @@ -250,13 +249,16 @@ where where C: QueryCache<Key = K>, { - // We can move out of `self` here because we `mem::forget` it below - let key = unsafe { ptr::read(&self.key) }; + let key = self.key; let state = self.state; // Forget ourself so our destructor won't poison the query mem::forget(self); + // Mark as complete before we remove the job from the active state + // so no other thread can re-execute this query. + cache.complete(key, result, dep_node_index); + let job = { #[cfg(parallel_compiler)] let mut lock = state.active.get_shard_by_value(&key).lock(); @@ -267,7 +269,6 @@ where QueryResult::Poisoned => panic!(), } }; - cache.complete(key, result, dep_node_index); job.signal_complete(); } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index ba7f04239c3..52f0b65fad6 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -368,7 +368,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during /// expansion and import resolution (perhaps they can be merged in the future). /// The function is used for resolving initial segments of macro paths (e.g., `foo` in - /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. + /// `foo::bar!();` or `foo!();`) and also for import paths on 2018 edition. #[instrument(level = "debug", skip(self, scope_set))] pub(crate) fn early_resolve_ident_in_lexical_scope( &mut self, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 36415936bdc..b8ddc455257 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -878,7 +878,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); let is_assoc_fn = self.self_type_is_available(); if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function { - // The current function has a `self' parameter, but we were unable to resolve + // The current function has a `self` parameter, but we were unable to resolve // a reference to `self`. This can only happen if the `self` identifier we // are resolving came from a different hygiene context. if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) { diff --git a/compiler/rustc_session/locales/en-US.ftl b/compiler/rustc_session/locales/en-US.ftl index fe553edab42..ff53f22d43f 100644 --- a/compiler/rustc_session/locales/en-US.ftl +++ b/compiler/rustc_session/locales/en-US.ftl @@ -5,7 +5,7 @@ session_incorrect_cgu_reuse_type = }`{$expected_reuse}` session_cgu_not_recorded = - CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded` + CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded session_feature_gate_error = {$explain} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 295e93f6103..d4e4ace889b 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2245,7 +2245,7 @@ pub fn parse_externs( early_error( error_format, "the `-Z unstable-options` flag must also be passed to \ - enable `--extern options", + enable `--extern` options", ); } for opt in opts.split(',') { @@ -2792,7 +2792,7 @@ pub enum PpMode { HirTree, /// `-Zunpretty=thir-tree` ThirTree, - /// `-Zunpretty=`thir-flat` + /// `-Zunpretty=thir-flat` ThirFlat, /// `-Zunpretty=mir` Mir, diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 2075ed57a94..f1fbf38217d 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -182,7 +182,17 @@ pub fn get_or_default_sysroot() -> Result<PathBuf, String> { if dir.ends_with(crate::config::host_triple()) { dir.parent() // chop off `$target` .and_then(|p| p.parent()) // chop off `rustlib` - .and_then(|p| p.parent()) // chop off `lib` + .and_then(|p| { + // chop off `lib` (this could be also $arch dir if the host sysroot uses a + // multi-arch layout like Debian or Ubuntu) + match p.parent() { + Some(p) => match p.file_name() { + Some(f) if f == "lib" => p.parent(), // first chop went for $arch, so chop again for `lib` + _ => Some(p), + }, + None => None, + } + }) .map(|s| s.to_owned()) .ok_or(format!( "Could not move 3 levels upper using `parent()` on {}", diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4beac931632..b466a3fcdee 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1503,6 +1503,9 @@ options! { "what location details should be tracked when using caller_location, either \ `none`, or a comma separated list of location details, for which \ valid options are `file`, `line`, and `column` (default: `file,line,column`)"), + lower_impl_trait_in_trait_to_assoc_ty: bool = (false, parse_bool, [TRACKED], + "modify the lowering strategy for `impl Trait` in traits so that they are lowered to \ + generic associated types"), ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate (default: no)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 446ba63ed1c..12634f67185 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -882,10 +882,14 @@ impl Session { /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. - pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool { + pub fn consider_optimizing( + &self, + get_crate_name: impl Fn() -> Symbol, + msg: impl Fn() -> String, + ) -> bool { let mut ret = true; if let Some((ref c, _)) = self.opts.unstable_opts.fuel { - if c == crate_name { + if c == get_crate_name().as_str() { assert_eq!(self.threads(), 1); let mut fuel = self.optimization_fuel.lock(); ret = fuel.remaining != 0; @@ -903,7 +907,7 @@ impl Session { } } if let Some(ref c) = self.opts.unstable_opts.print_fuel { - if c == crate_name { + if c == get_crate_name().as_str() { assert_eq!(self.threads(), 1); self.print_fuel.fetch_add(1, SeqCst); } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 2340d501d5a..162c15574b5 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -235,7 +235,7 @@ impl<D: Decoder> Decodable<D> for DefIndex { pub struct DefId { // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in // the lower bits no matter the endianness. This allows the compiler to turn that `Hash` impl - // into a direct call to 'u64::hash(_)`. + // into a direct call to `u64::hash(_)`. #[cfg(not(all(target_pointer_width = "64", target_endian = "big")))] pub index: DefIndex, pub krate: CrateNum, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index fb579e4ff77..6272bf7f25e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1954,7 +1954,7 @@ impl Interner { let name = Symbol::new(inner.strings.len() as u32); // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena, - // and immediately convert the clone back to `&[u8], all because there + // and immediately convert the clone back to `&[u8]`, all because there // is no `inner.arena.alloc_str()` method. This is clearly safe. let string: &str = unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) }; diff --git a/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs new file mode 100644 index 00000000000..c048d4a2aad --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/canonical/canonicalize.rs @@ -0,0 +1,390 @@ +use std::cmp::Ordering; + +use crate::infer::InferCtxt; +use rustc_middle::infer::canonical::Canonical; +use rustc_middle::infer::canonical::CanonicalTyVarKind; +use rustc_middle::infer::canonical::CanonicalVarInfo; +use rustc_middle::infer::canonical::CanonicalVarInfos; +use rustc_middle::infer::canonical::CanonicalVarKind; +use rustc_middle::ty::BoundRegionKind::BrAnon; +use rustc_middle::ty::BoundTyKind; +use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable}; + +/// Whether we're canonicalizing a query input or the query reponse. +/// +/// When canonicalizing an input we're in the context of the caller +/// while canonicalizing the response happens in the context of the +/// query. +#[derive(Debug, Clone, Copy)] +pub enum CanonicalizeMode { + Input, + /// FIXME: We currently return region constraints refering to + /// placeholders and inference variables from a binder instantiated + /// inside of the query. + /// + /// In the long term we should eagerly deal with these constraints + /// inside of the query and only propagate constraints which are + /// actually nameable by the caller. + Response { + /// The highest universe nameable by the caller. + /// + /// All variables in a universe nameable by the caller get mapped + /// to the root universe in the response and then mapped back to + /// their correct universe when applying the query response in the + /// context of the caller. + /// + /// This doesn't work for universes created inside of the query so + /// we do remember their universe in the response. + max_input_universe: ty::UniverseIndex, + }, +} + +pub struct Canonicalizer<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + canonicalize_mode: CanonicalizeMode, + + variables: &'a mut Vec<ty::GenericArg<'tcx>>, + primitive_var_infos: Vec<CanonicalVarInfo<'tcx>>, + binder_index: ty::DebruijnIndex, +} + +impl<'a, 'tcx> Canonicalizer<'a, 'tcx> { + #[instrument(level = "debug", skip(infcx), ret)] + pub fn canonicalize<T: TypeFoldable<TyCtxt<'tcx>>>( + infcx: &'a InferCtxt<'tcx>, + canonicalize_mode: CanonicalizeMode, + variables: &'a mut Vec<ty::GenericArg<'tcx>>, + value: T, + ) -> Canonical<'tcx, T> { + let mut canonicalizer = Canonicalizer { + infcx, + canonicalize_mode, + + variables, + primitive_var_infos: Vec::new(), + binder_index: ty::INNERMOST, + }; + + let value = value.fold_with(&mut canonicalizer); + assert!(!value.needs_infer()); + assert!(!value.has_placeholders()); + + let (max_universe, variables) = canonicalizer.finalize(); + + Canonical { max_universe, variables, value } + } + + fn finalize(self) -> (ty::UniverseIndex, CanonicalVarInfos<'tcx>) { + let mut var_infos = self.primitive_var_infos; + // See the rustc-dev-guide section about how we deal with universes + // during canonicalization in the new solver. + match self.canonicalize_mode { + // We try to deduplicate as many query calls as possible and hide + // all information which should not matter for the solver. + // + // For this we compress universes as much as possible. + CanonicalizeMode::Input => {} + // When canonicalizing a response we map a universes already entered + // by the caller to the root universe and only return useful universe + // information for placeholders and inference variables created inside + // of the query. + CanonicalizeMode::Response { max_input_universe } => { + for var in var_infos.iter_mut() { + let uv = var.universe(); + let new_uv = ty::UniverseIndex::from( + uv.index().saturating_sub(max_input_universe.index()), + ); + *var = var.with_updated_universe(new_uv); + } + let max_universe = var_infos + .iter() + .map(|info| info.universe()) + .max() + .unwrap_or(ty::UniverseIndex::ROOT); + + let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos); + return (max_universe, var_infos); + } + } + + // Given a `var_infos` with existentials `En` and universals `Un` in + // universes `n`, this algorithm compresses them in place so that: + // + // - the new universe indices are as small as possible + // - we only create a new universe if we would otherwise put a placeholder in + // the same compressed universe as an existential which cannot name it + // + // Let's walk through an example: + // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0 + // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1 + // - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2 + // - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5 + // - var_infos: [E0, U1, E1, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 6 + // - var_infos: [E0, U1, E1, U1, E1, E2, U2], curr_compressed_uv: 2, next_orig_uv: - + // + // This algorithm runs in `O(n²)` where `n` is the number of different universe + // indices in the input. This should be fine as `n` is expected to be small. + let mut curr_compressed_uv = ty::UniverseIndex::ROOT; + let mut existential_in_new_uv = false; + let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); + while let Some(orig_uv) = next_orig_uv.take() { + let mut update_uv = |var: &mut CanonicalVarInfo<'tcx>, orig_uv, is_existential| { + let uv = var.universe(); + match uv.cmp(&orig_uv) { + Ordering::Less => (), // Already updated + Ordering::Equal => { + if is_existential { + existential_in_new_uv = true; + } else if existential_in_new_uv { + // `var` is a placeholder from a universe which is not nameable + // by an existential which we already put into the compressed + // universe `curr_compressed_uv`. We therefore have to create a + // new universe for `var`. + curr_compressed_uv = curr_compressed_uv.next_universe(); + existential_in_new_uv = false; + } + + *var = var.with_updated_universe(curr_compressed_uv); + } + Ordering::Greater => { + // We can ignore this variable in this iteration. We only look at + // universes which actually occur in the input for performance. + // + // For this we set `next_orig_uv` to the next smallest, not yet compressed, + // universe of the input. + if next_orig_uv.map_or(true, |curr_next_uv| uv.cannot_name(curr_next_uv)) { + next_orig_uv = Some(uv); + } + } + } + }; + + // For each universe which occurs in the input, we first iterate over all + // placeholders and then over all inference variables. + // + // Whenever we compress the universe of a placeholder, no existential with + // an already compressed universe can name that placeholder. + for is_existential in [false, true] { + for var in var_infos.iter_mut() { + // We simply put all regions from the input into the highest + // compressed universe, so we only deal with them at the end. + if !var.is_region() { + if is_existential == var.is_existential() { + update_uv(var, orig_uv, is_existential) + } + } + } + } + } + + for var in var_infos.iter_mut() { + if var.is_region() { + assert!(var.is_existential()); + *var = var.with_updated_universe(curr_compressed_uv); + } + } + + let var_infos = self.infcx.tcx.mk_canonical_var_infos(&var_infos); + (curr_compressed_uv, var_infos) + } +} + +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> + where + T: TypeFoldable<TyCtxt<'tcx>>, + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + let r = self.infcx.shallow_resolve(r); + let kind = match *r { + ty::ReLateBound(..) => return r, + + ty::ReStatic => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => return r, + }, + + ty::ReErased | ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"), + }, + + ty::RePlaceholder(placeholder) => match self.canonicalize_mode { + // We canonicalize placeholder regions as existentials in query inputs. + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { max_input_universe } => { + // If we have a placeholder region inside of a query, it must be from + // a new universe. + if max_input_universe.can_name(placeholder.universe) { + bug!("new placeholder in universe {max_input_universe:?}: {r:?}"); + } + CanonicalVarKind::PlaceholderRegion(placeholder) + } + }, + + ty::ReVar(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::Region(self.infcx.universe_of_region(r)) + } + }, + + ty::ReError(_) => return r, + }; + + let existing_bound_var = match self.canonicalize_mode { + CanonicalizeMode::Input => None, + CanonicalizeMode::Response { .. } => { + self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from) + } + }; + let var = existing_bound_var.unwrap_or_else(|| { + let var = ty::BoundVar::from(self.variables.len()); + self.variables.push(r.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }); + let br = ty::BoundRegion { var, kind: BrAnon(var.as_u32(), None) }; + self.interner().mk_re_late_bound(self.binder_index, br) + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + let kind = match *t.kind() { + ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) { + Ok(t) => return self.fold_ty(t), + Err(ui) => CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), + }, + ty::Infer(ty::IntVar(_)) => { + let nt = self.infcx.shallow_resolve(t); + if nt != t { + return self.fold_ty(nt); + } else { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int) + } + } + ty::Infer(ty::FloatVar(_)) => { + let nt = self.infcx.shallow_resolve(t); + if nt != t { + return self.fold_ty(nt); + } else { + CanonicalVarKind::Ty(CanonicalTyVarKind::Int) + } + } + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("fresh var during canonicalization: {t:?}") + } + ty::Placeholder(placeholder) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder { + universe: placeholder.universe, + name: BoundTyKind::Anon(self.variables.len() as u32), + }), + CanonicalizeMode::Response { .. } => CanonicalVarKind::PlaceholderTy(placeholder), + }, + ty::Param(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderTy(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundTyKind::Anon(self.variables.len() as u32), + }), + CanonicalizeMode::Response { .. } => bug!("param ty in response: {t:?}"), + }, + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::GeneratorWitnessMIR(..) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Bound(_, _) + | ty::Error(_) => return t.super_fold_with(self), + }; + + let var = ty::BoundVar::from( + self.variables.iter().position(|&v| v == t.into()).unwrap_or_else(|| { + let var = self.variables.len(); + self.variables.push(t.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }), + ); + let bt = ty::BoundTy { var, kind: BoundTyKind::Anon(var.index() as u32) }; + self.interner().mk_bound(self.binder_index, bt) + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + let kind = match c.kind() { + ty::ConstKind::Infer(ty::InferConst::Var(vid)) => match self.infcx.probe_const_var(vid) + { + Ok(c) => return self.fold_const(c), + Err(universe) => CanonicalVarKind::Const(universe, c.ty()), + }, + ty::ConstKind::Infer(ty::InferConst::Fresh(_)) => { + bug!("fresh var during canonicalization: {c:?}") + } + ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( + ty::Placeholder { + universe: placeholder.universe, + name: ty::BoundVar::from(self.variables.len()), + }, + c.ty(), + ), + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::PlaceholderConst(placeholder, c.ty()) + } + }, + ty::ConstKind::Param(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( + ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundVar::from(self.variables.len()), + }, + c.ty(), + ), + CanonicalizeMode::Response { .. } => bug!("param ty in response: {c:?}"), + }, + ty::ConstKind::Bound(_, _) + | ty::ConstKind::Unevaluated(_) + | ty::ConstKind::Value(_) + | ty::ConstKind::Error(_) + | ty::ConstKind::Expr(_) => return c.super_fold_with(self), + }; + + let var = ty::BoundVar::from( + self.variables.iter().position(|&v| v == c.into()).unwrap_or_else(|| { + let var = self.variables.len(); + self.variables.push(c.into()); + self.primitive_var_infos.push(CanonicalVarInfo { kind }); + var + }), + ); + self.interner().mk_const(ty::ConstKind::Bound(self.binder_index, var), c.ty()) + } +} diff --git a/compiler/rustc_trait_selection/src/solve/canonical/mod.rs b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs new file mode 100644 index 00000000000..8c3be8da16b --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/canonical/mod.rs @@ -0,0 +1,240 @@ +/// Canonicalization is used to separate some goal from its context, +/// throwing away unnecessary information in the process. +/// +/// This is necessary to cache goals containing inference variables +/// and placeholders without restricting them to the current `InferCtxt`. +/// +/// Canonicalization is fairly involved, for more details see the relevant +/// section of the [rustc-dev-guide][c]. +/// +/// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html +use self::canonicalize::{CanonicalizeMode, Canonicalizer}; +use super::{CanonicalGoal, Certainty, EvalCtxt, Goal}; +use super::{CanonicalResponse, ExternalConstraints, QueryResult, Response}; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::canonical::CanonicalVarValues; +use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; +use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::solve::ExternalConstraintsData; +use rustc_infer::traits::ObligationCause; +use rustc_middle::ty::{self, GenericArgKind}; +use rustc_span::DUMMY_SP; +use std::iter; +use std::ops::Deref; + +mod canonicalize; + +impl<'tcx> EvalCtxt<'_, 'tcx> { + /// Canonicalizes the goal remembering the original values + /// for each bound variable. + pub(super) fn canonicalize_goal( + &self, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalGoal<'tcx>) { + let mut orig_values = Default::default(); + let canonical_goal = Canonicalizer::canonicalize( + self.infcx, + CanonicalizeMode::Input, + &mut orig_values, + goal, + ); + (orig_values, canonical_goal) + } + + /// To return the constraints of a canonical query to the caller, we canonicalize: + /// + /// - `var_values`: a map from bound variables in the canonical goal to + /// the values inferred while solving the instantiated goal. + /// - `external_constraints`: additional constraints which aren't expressable + /// using simple unification of inference variables. + #[instrument(level = "debug", skip(self))] + pub(super) fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { + let external_constraints = self.compute_external_query_constraints()?; + + let response = Response { var_values: self.var_values, external_constraints, certainty }; + let canonical = Canonicalizer::canonicalize( + self.infcx, + CanonicalizeMode::Response { max_input_universe: self.max_input_universe }, + &mut Default::default(), + response, + ); + Ok(canonical) + } + + #[instrument(level = "debug", skip(self), ret)] + fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> { + // Cannot use `take_registered_region_obligations` as we may compute the response + // inside of a `probe` whenever we have multiple choices inside of the solver. + let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); + let region_constraints = self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.tcx(), + region_obligations + .iter() + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), + region_constraints, + ) + }); + let opaque_types = self.infcx.clone_opaque_types_for_query_response(); + Ok(self + .tcx() + .mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types })) + } + + /// After calling a canonical query, we apply the constraints returned + /// by the query using this function. + /// + /// This happens in three steps: + /// - we instantiate the bound variables of the query response + /// - we unify the `var_values` of the response with the `original_values` + /// - we apply the `external_constraints` returned by the query + pub(super) fn instantiate_and_apply_query_response( + &mut self, + param_env: ty::ParamEnv<'tcx>, + original_values: Vec<ty::GenericArg<'tcx>>, + response: CanonicalResponse<'tcx>, + ) -> Result<Certainty, NoSolution> { + let substitution = self.compute_query_response_substitution(&original_values, &response); + + let Response { var_values, external_constraints, certainty } = + response.substitute(self.tcx(), &substitution); + + self.unify_query_var_values(param_env, &original_values, var_values)?; + + // FIXME: implement external constraints. + let ExternalConstraintsData { region_constraints, opaque_types: _ } = + external_constraints.deref(); + self.register_region_constraints(region_constraints); + + Ok(certainty) + } + + /// This returns the substitutions to instantiate the bound variables of + /// the canonical reponse. This depends on the `original_values` for the + /// bound variables. + fn compute_query_response_substitution( + &self, + original_values: &[ty::GenericArg<'tcx>], + response: &CanonicalResponse<'tcx>, + ) -> CanonicalVarValues<'tcx> { + // FIXME: Longterm canonical queries should deal with all placeholders + // created inside of the query directly instead of returning them to the + // caller. + let prev_universe = self.infcx.universe(); + let universes_created_in_query = response.max_universe.index() + 1; + for _ in 0..universes_created_in_query { + self.infcx.create_next_universe(); + } + + let var_values = response.value.var_values; + assert_eq!(original_values.len(), var_values.len()); + + // If the query did not make progress with constraining inference variables, + // we would normally create a new inference variables for bound existential variables + // only then unify this new inference variable with the inference variable from + // the input. + // + // We therefore instantiate the existential variable in the canonical response with the + // inference variable of the input right away, which is more performant. + let mut opt_values = vec![None; response.variables.len()]; + for (original_value, result_value) in iter::zip(original_values, var_values.var_values) { + match result_value.unpack() { + GenericArgKind::Type(t) => { + if let &ty::Bound(debruijn, b) = t.kind() { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[b.var.index()] = Some(*original_value); + } + } + GenericArgKind::Lifetime(r) => { + if let ty::ReLateBound(debruijn, br) = *r { + assert_eq!(debruijn, ty::INNERMOST); + opt_values[br.var.index()] = Some(*original_value); + } + } + GenericArgKind::Const(c) => { + if let ty::ConstKind::Bound(debrujin, b) = c.kind() { + assert_eq!(debrujin, ty::INNERMOST); + opt_values[b.index()] = Some(*original_value); + } + } + } + } + + let var_values = self.tcx().mk_substs_from_iter(response.variables.iter().enumerate().map( + |(index, info)| { + if info.universe() != ty::UniverseIndex::ROOT { + // A variable from inside a binder of the query. While ideally these shouldn't + // exist at all (see the FIXME at the start of this method), we have to deal with + // them for now. + self.infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| { + ty::UniverseIndex::from(prev_universe.index() + idx.index()) + }) + } else if info.is_existential() { + // As an optimization we sometimes avoid creating a new inference variable here. + // + // All new inference variables we create start out in the current universe of the caller. + // This is conceptionally wrong as these inference variables would be able to name + // more placeholders then they should be able to. However the inference variables have + // to "come from somewhere", so by equating them with the original values of the caller + // later on, we pull them down into their correct universe again. + if let Some(v) = opt_values[index] { + v + } else { + self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) + } + } else { + // For placeholders which were already part of the input, we simply map this + // universal bound variable back the placeholder of the input. + original_values[info.expect_anon_placeholder() as usize] + } + }, + )); + + CanonicalVarValues { var_values } + } + + #[instrument(level = "debug", skip(self, param_env), ret)] + fn unify_query_var_values( + &self, + param_env: ty::ParamEnv<'tcx>, + original_values: &[ty::GenericArg<'tcx>], + var_values: CanonicalVarValues<'tcx>, + ) -> Result<(), NoSolution> { + assert_eq!(original_values.len(), var_values.len()); + for (&orig, response) in iter::zip(original_values, var_values.var_values) { + // This can fail due to the occurs check, see + // `tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs` for an example + // where that can happen. + // + // FIXME: To deal with #105787 I also expect us to emit nested obligations here at + // some point. We can figure out how to deal with this once we actually have + // an ICE. + let nested_goals = self.eq(param_env, orig, response)?; + assert!(nested_goals.is_empty(), "{nested_goals:?}"); + } + + Ok(()) + } + + fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { + for &(ty::OutlivesPredicate(lhs, rhs), _) in ®ion_constraints.outlives { + match lhs.unpack() { + GenericArgKind::Lifetime(lhs) => self.infcx.region_outlives_predicate( + &ObligationCause::dummy(), + ty::Binder::dummy(ty::OutlivesPredicate(lhs, rhs)), + ), + GenericArgKind::Type(lhs) => self.infcx.register_region_obligation_with_cause( + lhs, + rhs, + &ObligationCause::dummy(), + ), + GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"), + } + } + + for member_constraint in ®ion_constraints.member_constraints { + // FIXME: Deal with member constraints :< + let _ = member_constraint; + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index c8097e81953..95612674eb9 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -19,8 +19,17 @@ use super::Goal; pub struct EvalCtxt<'a, 'tcx> { // FIXME: should be private. pub(super) infcx: &'a InferCtxt<'tcx>, - pub(super) var_values: CanonicalVarValues<'tcx>, + /// The highest universe index nameable by the caller. + /// + /// When we enter a new binder inside of the query we create new universes + /// which the caller cannot name. We have to be careful with variables from + /// these new universes when creating the query response. + /// + /// Both because these new universes can prevent us from reaching a fixpoint + /// if we have a coinductive cycle and because that's the only way we can return + /// new placeholders to the caller. + pub(super) max_input_universe: ty::UniverseIndex, pub(super) search_graph: &'a mut SearchGraph<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 71f536dd3cb..57b6a452737 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -19,11 +19,9 @@ use std::mem; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; -use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::Obligation; -use rustc_middle::infer::canonical::Certainty as OldCertainty; use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ @@ -35,6 +33,7 @@ use crate::solve::search_graph::OverflowHandler; use crate::traits::ObligationCause; mod assembly; +mod canonical; mod eval_ctxt; mod fulfill; mod project_goals; @@ -89,11 +88,8 @@ trait CanonicalResponseExt { impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { fn has_no_inference_or_external_constraints(&self) -> bool { - // so that we get a compile error when regions are supported - // so this code can be checked for being correct - let _: () = self.value.external_constraints.regions; - - self.value.var_values.is_identity() + self.value.external_constraints.region_constraints.is_empty() + && self.value.var_values.is_identity() && self.value.external_constraints.opaque_types.is_empty() } } @@ -169,6 +165,8 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { let result = EvalCtxt { search_graph: &mut search_graph, infcx: self, + // Only relevant when canonicalizing the response. + max_input_universe: ty::UniverseIndex::ROOT, var_values: CanonicalVarValues::dummy(), in_projection_eq_hack: false, } @@ -201,36 +199,33 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { search_graph.with_new_goal(tcx, canonical_goal, |search_graph| { let (ref infcx, goal, var_values) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical_goal); - let mut ecx = - EvalCtxt { infcx, var_values, search_graph, in_projection_eq_hack: false }; + let mut ecx = EvalCtxt { + infcx, + var_values, + max_input_universe: canonical_goal.max_universe, + search_graph, + in_projection_eq_hack: false, + }; ecx.compute_goal(goal) }) } - fn make_canonical_response(&self, certainty: Certainty) -> QueryResult<'tcx> { - let external_constraints = compute_external_query_constraints(self.infcx)?; - - Ok(self.infcx.canonicalize_response(Response { - var_values: self.var_values, - external_constraints, - certainty, - })) - } - /// Recursively evaluates `goal`, returning whether any inference vars have /// been constrained and the certainty of the result. fn evaluate_goal( &mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty), NoSolution> { - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = self.infcx.canonicalize_query(goal, &mut orig_values); + let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; let has_changed = !canonical_response.value.var_values.is_identity(); - let certainty = - instantiate_canonical_query_response(self.infcx, &orig_values, canonical_response); + let certainty = self.instantiate_and_apply_query_response( + goal.param_env, + orig_values, + canonical_response, + )?; // Check that rerunning this query with its inference constraints applied // doesn't result in new inference constraints and has the same result. @@ -244,8 +239,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { && !self.in_projection_eq_hack && !self.search_graph.in_cycle() { - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = self.infcx.canonicalize_query(goal, &mut orig_values); + let (_orig_values, canonical_goal) = self.canonicalize_goal(goal); let canonical_response = EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?; if !canonical_response.value.var_values.is_identity() { @@ -316,15 +310,21 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { fn compute_type_outlives_goal( &mut self, - _goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, + goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { + let ty::OutlivesPredicate(ty, lt) = goal.predicate; + self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); self.make_canonical_response(Certainty::Yes) } fn compute_region_outlives_goal( &mut self, - _goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, + goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, ) -> QueryResult<'tcx> { + self.infcx.region_outlives_predicate( + &ObligationCause::dummy(), + ty::Binder::dummy(goal.predicate), + ); self.make_canonical_response(Certainty::Yes) } @@ -561,49 +561,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } -#[instrument(level = "debug", skip(infcx), ret)] -fn compute_external_query_constraints<'tcx>( - infcx: &InferCtxt<'tcx>, -) -> Result<ExternalConstraints<'tcx>, NoSolution> { - let region_obligations = infcx.take_registered_region_obligations(); - let opaque_types = infcx.take_opaque_types_for_query_response(); - Ok(infcx.tcx.mk_external_constraints(ExternalConstraintsData { - // FIXME: Now that's definitely wrong :) - // - // Should also do the leak check here I think - regions: drop(region_obligations), - opaque_types, - })) -} - -fn instantiate_canonical_query_response<'tcx>( - infcx: &InferCtxt<'tcx>, - original_values: &OriginalQueryValues<'tcx>, - response: CanonicalResponse<'tcx>, -) -> Certainty { - let Ok(InferOk { value, obligations }) = infcx - .instantiate_query_response_and_region_obligations( - &ObligationCause::dummy(), - ty::ParamEnv::empty(), - original_values, - &response.unchecked_map(|resp| QueryResponse { - var_values: resp.var_values, - region_constraints: QueryRegionConstraints::default(), - certainty: match resp.certainty { - Certainty::Yes => OldCertainty::Proven, - Certainty::Maybe(_) => OldCertainty::Ambiguous, - }, - // FIXME: This to_owned makes me sad, but we should eventually impl - // `instantiate_query_response_and_region_obligations` separately - // instead of piggybacking off of the old implementation. - opaque_types: resp.external_constraints.opaque_types.to_owned(), - value: resp.certainty, - }), - ) else { bug!(); }; - assert!(obligations.is_empty()); - value -} - pub(super) fn response_no_constraints<'tcx>( tcx: TyCtxt<'tcx>, goal: Canonical<'tcx, impl Sized>, diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 88fd8bb8bd0..33c66d072e9 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -77,10 +77,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let nested_goals = self .eq(goal.param_env, goal.predicate.term, normalized_alias.into()) .expect("failed to unify with unconstrained term"); - let rhs_certainty = + + let unify_certainty = self.evaluate_all(nested_goals).expect("failed to unify with unconstrained term"); - self.make_canonical_response(normalization_certainty.unify_and(rhs_certainty)) + self.make_canonical_response(normalization_certainty.unify_and(unify_certainty)) } } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index da2416b9646..944436ab82f 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -212,36 +212,44 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { /// Identifies whether a predicate obligation needs processing. /// - /// This is always inlined, despite its size, because it has a single - /// callsite and it is called *very* frequently. + /// This is always inlined because it has a single callsite and it is + /// called *very* frequently. Be careful modifying this code! Several + /// compile-time benchmarks are very sensitive to even small changes. #[inline(always)] fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { // If we were stalled on some unresolved variables, first check whether // any of them have been resolved; if not, don't bother doing more work // yet. - match pending_obligation.stalled_on.len() { - // Match arms are in order of frequency, which matters because this - // code is so hot. 1 and 0 dominate; 2+ is fairly rare. - 1 => { - let infer_var = pending_obligation.stalled_on[0]; - self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) - } - 0 => { - // In this case we haven't changed, but wish to make a change. - true - } - _ => { - // This `for` loop was once a call to `all()`, but this lower-level - // form was a perf win. See #64545 for details. - (|| { - for &infer_var in &pending_obligation.stalled_on { - if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { - return true; - } + let stalled_on = &pending_obligation.stalled_on; + match stalled_on.len() { + // This case is the hottest most of the time, being hit up to 99% + // of the time. `keccak` and `cranelift-codegen-0.82.1` are + // benchmarks that particularly stress this path. + 1 => self.selcx.infcx.ty_or_const_infer_var_changed(stalled_on[0]), + + // In this case we haven't changed, but wish to make a change. Note + // that this is a special case, and is not equivalent to the `_` + // case below, which would return `false` for an empty `stalled_on` + // vector. + // + // This case is usually hit only 1% of the time or less, though it + // reaches 20% in `wasmparser-0.101.0`. + 0 => true, + + // This case is usually hit only 1% of the time or less, though it + // reaches 95% in `mime-0.3.16`, 64% in `wast-54.0.0`, and 12% in + // `inflate-0.4.5`. + // + // The obvious way of writing this, with a call to `any()` and no + // closure, is currently slower than this version. + _ => (|| { + for &infer_var in stalled_on { + if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { + return true; } - false - })() - } + } + false + })(), } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index d542240be9b..870ecc2a970 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1175,7 +1175,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( /// paths you want to take. To make things worse, it was possible for /// cycles to arise, where you basically had a setup like `<MyType<$0> /// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as -/// Trait>::Foo> to `[type error]` would lead to an obligation of +/// Trait>::Foo>` to `[type error]` would lead to an obligation of /// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report /// an error for this obligation, but we legitimately should not, /// because it contains `[type error]`. Yuck! (See issue #29857 for @@ -1307,25 +1307,8 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>( let _ = selcx.infcx.commit_if_ok(|_| { match selcx.select(&obligation.with(tcx, trait_predicate)) { Ok(Some(super::ImplSource::UserDefined(data))) => { - let Ok(leaf_def) = specialization_graph::assoc_def(tcx, data.impl_def_id, trait_fn_def_id) else { - return Err(()); - }; - // Only reveal a specializable default if we're past type-checking - // and the obligation is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - if leaf_def.is_final() - || (obligation.param_env.reveal() == Reveal::All - && !selcx - .infcx - .resolve_vars_if_possible(obligation.predicate.trait_ref(tcx)) - .still_further_specializable()) - { - candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); - Ok(()) - } else { - Err(()) - } + candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data)); + Ok(()) } Ok(None) => { candidate_set.mark_ambiguous(); @@ -2216,7 +2199,8 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>( Ok(assoc_ty) => assoc_ty, Err(guar) => return Progress::error(tcx, guar), }; - if !leaf_def.item.defaultness(tcx).has_value() { + // We don't support specialization for RPITITs anyways... yet. + if !leaf_def.is_final() { return Progress { term: tcx.ty_error_misc().into(), obligations }; } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 4ad13dcb645..e91057356a2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -339,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Essentially any user-written impl will match with an error type, // so creating `ImplCandidates` isn't useful. However, we might - // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized) + // end up finding a candidate elsewhere (e.g. a `BuiltinCandidate` for `Sized`) // This helps us avoid overflow: see issue #72839 // Since compilation is already guaranteed to fail, this is just // to try to show the 'nicest' possible errors to the user. diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 01c1ad3a4ce..4377de15829 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -151,7 +151,7 @@ struct TraitObligationStack<'prev, 'tcx> { /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` /// is `EvaluatedToOk`; this is because they were only considered /// ok on the premise that if `A: AutoTrait` held, but we indeed - /// encountered a problem (later on) with `A: AutoTrait. So we + /// encountered a problem (later on) with `A: AutoTrait`. So we /// currently set a flag on the stack node for `B: AutoTrait` (as /// well as the second instance of `A: AutoTrait`) to suppress /// caching. @@ -727,7 +727,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Otherwise, we can say that `T: NonAutoTrait` is // true. // Let's imagine we have a predicate stack like - // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto + // `Foo: Bar -> WF(T) -> T: NonAutoTrait -> T: Auto` // depth ^1 ^2 ^3 // and the current predicate is `WF(T)`. `wf_args` // would contain `(T, 1)`. We want to check all diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index d4866b5dbdd..0648784b265 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,7 +4,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; -use rustc_middle::ty::{self, DefIdTree, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, ImplTraitInTraitData, InternalSubsts, TyCtxt}; +use rustc_span::symbol::kw; pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { @@ -21,12 +22,68 @@ pub fn provide(providers: &mut ty::query::Providers) { fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { let item = tcx.hir().expect_item(def_id.expect_local()); match item.kind { - hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter( - trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()), - ), - hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter( - impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()), - ), + hir::ItemKind::Trait(.., ref trait_item_refs) => { + if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty { + // We collect RPITITs for each trait method's return type and create a + // corresponding associated item using associated_items_for_impl_trait_in_trait + // query. + tcx.arena.alloc_from_iter( + trait_item_refs + .iter() + .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()) + .chain( + trait_item_refs + .iter() + .filter(|trait_item_ref| { + matches!(trait_item_ref.kind, hir::AssocItemKind::Fn { .. }) + }) + .flat_map(|trait_item_ref| { + let trait_fn_def_id = + trait_item_ref.id.owner_id.def_id.to_def_id(); + tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id) + }) + .map(|def_id| *def_id), + ), + ) + } else { + tcx.arena.alloc_from_iter( + trait_item_refs + .iter() + .map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()), + ) + } + } + hir::ItemKind::Impl(ref impl_) => { + if tcx.sess.opts.unstable_opts.lower_impl_trait_in_trait_to_assoc_ty { + // We collect RPITITs for each trait method's return type, on the impl side too and + // create a corresponding associated item using + // associated_items_for_impl_trait_in_trait query. + tcx.arena.alloc_from_iter( + impl_ + .items + .iter() + .map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()) + .chain(impl_.of_trait.iter().flat_map(|_| { + impl_ + .items + .iter() + .filter(|impl_item_ref| { + matches!(impl_item_ref.kind, hir::AssocItemKind::Fn { .. }) + }) + .flat_map(|impl_item_ref| { + let impl_fn_def_id = + impl_item_ref.id.owner_id.def_id.to_def_id(); + tcx.associated_items_for_impl_trait_in_trait(impl_fn_def_id) + }) + .map(|def_id| *def_id) + })), + ) + } else { + tcx.arena.alloc_from_iter( + impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()), + ) + } + } _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), } } @@ -193,10 +250,65 @@ fn associated_item_for_impl_trait_in_trait( let span = tcx.def_span(opaque_ty_def_id); let trait_assoc_ty = tcx.at(span).create_def(trait_def_id.expect_local(), DefPathData::ImplTraitAssocTy); - trait_assoc_ty.def_id() + + let local_def_id = trait_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + trait_assoc_ty.opt_def_kind(Some(DefKind::AssocTy)); + + // There's no HIR associated with this new synthesized `def_id`, so feed + // `opt_local_def_id_to_hir_id` with `None`. + trait_assoc_ty.opt_local_def_id_to_hir_id(None); + + // Copy span of the opaque. + trait_assoc_ty.def_ident_span(Some(span)); + + // Add the def_id of the function and opaque that generated this synthesized associated type. + trait_assoc_ty.opt_rpitit_info(Some(ImplTraitInTraitData::Trait { + fn_def_id, + opaque_def_id: opaque_ty_def_id.to_def_id(), + })); + + trait_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: None, + container: ty::TraitContainer, + fn_has_self_parameter: false, + }); + + // Copy visility of the containing function. + trait_assoc_ty.visibility(tcx.visibility(fn_def_id)); + + // Copy impl_defaultness of the containing function. + trait_assoc_ty.impl_defaultness(tcx.impl_defaultness(fn_def_id)); + + // Copy type_of of the opaque. + trait_assoc_ty.type_of(ty::EarlyBinder(tcx.mk_opaque( + opaque_ty_def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, opaque_ty_def_id.to_def_id()), + ))); + + // Copy generics_of of the opaque. + trait_assoc_ty.generics_of(tcx.generics_of(opaque_ty_def_id).clone()); + + // There are no predicates for the synthesized associated type. + trait_assoc_ty.explicit_predicates_of(ty::GenericPredicates { + parent: Some(trait_def_id), + predicates: &[], + }); + + // There are no inferred outlives for the synthesized associated type. + trait_assoc_ty.inferred_outlives_of(&[]); + + // FIXME implement this. + trait_assoc_ty.explicit_item_bounds(&[]); + + local_def_id } -/// Given an `trait_assoc_def_id` that corresponds to a previously synthethized impl trait in trait +/// Given an `trait_assoc_def_id` that corresponds to a previously synthesized impl trait in trait /// into an associated type and an `impl_def_id` corresponding to an impl block, create and return /// the corresponding associated item inside the impl block. fn impl_associated_item_for_impl_trait_in_trait( @@ -206,8 +318,40 @@ fn impl_associated_item_for_impl_trait_in_trait( ) -> LocalDefId { let impl_def_id = tcx.local_parent(impl_fn_def_id); - let span = tcx.def_span(trait_assoc_def_id); + // FIXME fix the span, we probably want the def_id of the return type of the function + let span = tcx.def_span(impl_fn_def_id); let impl_assoc_ty = tcx.at(span).create_def(impl_def_id, DefPathData::ImplTraitAssocTy); - impl_assoc_ty.def_id() + let local_def_id = impl_assoc_ty.def_id(); + let def_id = local_def_id.to_def_id(); + + impl_assoc_ty.opt_def_kind(Some(DefKind::AssocTy)); + + // There's no HIR associated with this new synthesized `def_id`, so feed + // `opt_local_def_id_to_hir_id` with `None`. + impl_assoc_ty.opt_local_def_id_to_hir_id(None); + + // Add the def_id of the function that generated this synthesized associated type. + impl_assoc_ty.opt_rpitit_info(Some(ImplTraitInTraitData::Impl { + fn_def_id: impl_fn_def_id.to_def_id(), + })); + + impl_assoc_ty.associated_item(ty::AssocItem { + name: kw::Empty, + kind: ty::AssocKind::Type, + def_id, + trait_item_def_id: Some(trait_assoc_def_id.to_def_id()), + container: ty::ImplContainer, + fn_has_self_parameter: false, + }); + + // Copy impl_defaultness of the containing function. + impl_assoc_ty.impl_defaultness(tcx.impl_defaultness(impl_fn_def_id)); + + // Copy generics_of the trait's associated item. + // FIXME: This is not correct, in particular the parent is going to be wrong. So we would need + // to copy from trait_assoc_def_id and adjust things. + impl_assoc_ty.generics_of(tcx.generics_of(trait_assoc_def_id).clone()); + + local_def_id } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index a563b258723..44a37899007 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -283,9 +283,7 @@ impl<T> Box<T> { #[must_use] #[inline(always)] pub fn pin(x: T) -> Pin<Box<T>> { - (#[rustc_box] - Box::new(x)) - .into() + Box::new(x).into() } /// Allocates memory on the heap then places `x` into it, @@ -1242,8 +1240,8 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T: Default> Default for Box<T> { /// Creates a `Box<T>`, with the `Default` value for T. + #[inline] fn default() -> Self { - #[rustc_box] Box::new(T::default()) } } @@ -1252,6 +1250,7 @@ impl<T: Default> Default for Box<T> { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] impl<T> const Default for Box<[T]> { + #[inline] fn default() -> Self { let ptr: Unique<[T]> = Unique::<[T; 0]>::dangling(); Box(ptr, Global) @@ -1262,6 +1261,7 @@ impl<T> const Default for Box<[T]> { #[stable(feature = "default_box_extra", since = "1.17.0")] #[rustc_const_unstable(feature = "const_default_impls", issue = "87864")] impl const Default for Box<str> { + #[inline] fn default() -> Self { // SAFETY: This is the same as `Unique::cast<U>` but with an unsized `U = str`. let ptr: Unique<str> = unsafe { @@ -1616,7 +1616,6 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> { /// println!("{boxed:?}"); /// ``` fn from(array: [T; N]) -> Box<[T]> { - #[rustc_box] Box::new(array) } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index d4a12509b1c..8317ac431a5 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1924,7 +1924,7 @@ impl<T, A: Allocator> VecDeque<T, A> { #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { if T::IS_ZST { - self.len += other.len; + self.len = self.len.checked_add(other.len).expect("capacity overflow"); other.len = 0; other.head = 0; return; diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 5198bf297d9..4c6ae8f2579 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -48,6 +48,8 @@ macro_rules! vec { ); ($($x:expr),+ $(,)?) => ( $crate::__rust_force_expr!(<[_]>::into_vec( + // This rustc_box is not required, but it produces a dramatic improvement in compile + // time when constructing arrays with many elements. #[rustc_box] $crate::boxed::Box::new([$($x),+]) )) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index fd1e3e0f75b..932a537c598 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2145,7 +2145,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I { Rc::from_iter_exact(self, low) } } else { - // TrustedLen contract guarantees that `upper_bound == `None` implies an iterator + // TrustedLen contract guarantees that `upper_bound == None` implies an iterator // length exceeding `usize::MAX`. // The default implementation would collect into a vec which would panic. // Thus we panic here immediately without invoking `Vec` code. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 2b843647dd5..c7e7ed3e95e 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2213,10 +2213,6 @@ impl PartialEq for String { fn eq(&self, other: &String) -> bool { PartialEq::eq(&self[..], &other[..]) } - #[inline] - fn ne(&self, other: &String) -> bool { - PartialEq::ne(&self[..], &other[..]) - } } macro_rules! impl_eq { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index f20486ca9e4..fdd341a06ef 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2895,7 +2895,7 @@ impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> for I { Arc::from_iter_exact(self, low) } } else { - // TrustedLen contract guarantees that `upper_bound == `None` implies an iterator + // TrustedLen contract guarantees that `upper_bound == None` implies an iterator // length exceeding `usize::MAX`. // The default implementation would collect into a vec which would panic. // Thus we panic here immediately without invoking `Vec` code. diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b279f21b524..f2aa30f18fc 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3131,10 +3131,7 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> { /// ``` #[cfg(not(test))] fn from(s: [T; N]) -> Vec<T> { - <[T]>::into_vec( - #[rustc_box] - Box::new(s), - ) + <[T]>::into_vec(Box::new(s)) } #[cfg(test)] diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 0b8f5281b78..5a0b852e8d5 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1046,6 +1046,20 @@ fn test_append_double_drop() { } #[test] +#[should_panic] +fn test_append_zst_capacity_overflow() { + let mut v = Vec::with_capacity(usize::MAX); + // note: using resize instead of set_len here would + // be *extremely* slow in unoptimized builds. + // SAFETY: `v` has capacity `usize::MAX`, and no initialization + // is needed for empty tuples. + unsafe { v.set_len(usize::MAX) }; + let mut v = VecDeque::from(v); + let mut w = vec![()].into(); + v.append(&mut w); +} + +#[test] fn test_retain() { let mut buf = VecDeque::new(); buf.extend(1..5); diff --git a/library/core/src/any.rs b/library/core/src/any.rs index c0fb0d993c3..c27646b8f33 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -56,7 +56,7 @@ //! let value_any = value as &dyn Any; //! //! // Try to convert our value to a `String`. If successful, we want to -//! // output the String`'s length as well as its value. If not, it's a +//! // output the `String`'s length as well as its value. If not, it's a //! // different type: just print it out unadorned. //! match value_any.downcast_ref::<String>() { //! Some(as_string) => { diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index b2c895f882c..d749865f76f 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -1,6 +1,5 @@ +use crate::cmp::BytewiseEq; use crate::convert::TryInto; -use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; -use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; #[stable(feature = "rust1", since = "1.0.0")] impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N] @@ -144,74 +143,14 @@ impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T { } } -impl<T: IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T { +impl<T: BytewiseEq<U>, U, const N: usize> SpecArrayEq<U, N> for T { fn spec_eq(a: &[T; N], b: &[U; N]) -> bool { - // SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`. - unsafe { - let b = &*b.as_ptr().cast::<[T; N]>(); - crate::intrinsics::raw_eq(a, b) - } + // SAFETY: Arrays are compared element-wise, and don't add any padding + // between elements, so when the elements are `BytewiseEq`, we can + // compare the entire array at once. + unsafe { crate::intrinsics::raw_eq(a, crate::mem::transmute(b)) } } fn spec_ne(a: &[T; N], b: &[U; N]) -> bool { !Self::spec_eq(a, b) } } - -/// `U` exists on here mostly because `min_specialization` didn't let me -/// repeat the `T` type parameter in the above specialization, so instead -/// the `T == U` constraint comes from the impls on this. -/// # Safety -/// - Neither `Self` nor `U` has any padding. -/// - `Self` and `U` have the same layout. -/// - `Self: PartialEq<U>` is byte-wise (this means no floats, among other things) -#[rustc_specialization_trait] -unsafe trait IsRawEqComparable<U>: PartialEq<U> {} - -macro_rules! is_raw_eq_comparable { - ($($t:ty),+ $(,)?) => {$( - unsafe impl IsRawEqComparable<$t> for $t {} - )+}; -} - -// SAFETY: All the ordinary integer types have no padding, and are not pointers. -is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); - -// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this -// is sound -is_raw_eq_comparable!(bool, char); - -// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers, -// and they compare like their underlying numeric type. -is_raw_eq_comparable!( - NonZeroU8, - NonZeroU16, - NonZeroU32, - NonZeroU64, - NonZeroU128, - NonZeroUsize, - NonZeroI8, - NonZeroI16, - NonZeroI32, - NonZeroI64, - NonZeroI128, - NonZeroIsize, -); - -// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus -// are also safe to equality-compare bitwise inside an `Option`. -// The way `PartialOrd` is defined for `Option` means that this wouldn't work -// for `<` or `>` on the signed types, but since we only do `==` it's fine. -is_raw_eq_comparable!( - Option<NonZeroU8>, - Option<NonZeroU16>, - Option<NonZeroU32>, - Option<NonZeroU64>, - Option<NonZeroU128>, - Option<NonZeroUsize>, - Option<NonZeroI8>, - Option<NonZeroI16>, - Option<NonZeroI32>, - Option<NonZeroI64>, - Option<NonZeroI128>, - Option<NonZeroIsize>, -); diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 7f109491350..897d03595d7 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -632,7 +632,7 @@ pub struct RefCell<T: ?Sized> { // Stores the location of the earliest currently active borrow. // This gets updated whenever we go from having zero borrows // to having a single borrow. When a borrow occurs, this gets included - // in the generated `BorrowError/`BorrowMutError` + // in the generated `BorrowError`/`BorrowMutError` #[cfg(feature = "debug_refcell")] borrowed_at: Cell<Option<&'static crate::panic::Location<'static>>>, value: UnsafeCell<T>, diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index b4d58376aea..5b5f55d0e65 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -22,6 +22,9 @@ #![stable(feature = "rust1", since = "1.0.0")] +mod bytewise; +pub(crate) use bytewise::BytewiseEq; + use crate::marker::Destruct; use self::Ordering::*; diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/bytewise.rs new file mode 100644 index 00000000000..2548d9e24c9 --- /dev/null +++ b/library/core/src/cmp/bytewise.rs @@ -0,0 +1,83 @@ +use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; +use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + +/// Types where `==` & `!=` are equivalent to comparing their underlying bytes. +/// +/// Importantly, this means no floating-point types, as those have different +/// byte representations (like `-0` and `+0`) which compare as the same. +/// Since byte arrays are `Eq`, that implies that these types are probably also +/// `Eq`, but that's not technically required to use this trait. +/// +/// `Rhs` is *de facto* always `Self`, but the separate parameter is important +/// to avoid the `specializing impl repeats parameter` error when consuming this. +/// +/// # Safety +/// +/// - `Self` and `Rhs` have no padding. +/// - `Self` and `Rhs` have the same layout (size and alignment). +/// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct. +/// - `<Self as PartialEq<Rhs>>::{eq,ne}` are equivalent to comparing the bytes. +#[rustc_specialization_trait] +pub(crate) unsafe trait BytewiseEq<Rhs = Self>: PartialEq<Rhs> + Sized {} + +macro_rules! is_bytewise_comparable { + ($($t:ty),+ $(,)?) => {$( + unsafe impl BytewiseEq for $t {} + )+}; +} + +// SAFETY: All the ordinary integer types have no padding, and are not pointers. +is_bytewise_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); + +// SAFETY: These have *niches*, but no *padding* and no *provenance*, +// so we can compare them directly. +is_bytewise_comparable!(bool, char, super::Ordering); + +// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers, +// and they compare like their underlying numeric type. +is_bytewise_comparable!( + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU128, + NonZeroUsize, + NonZeroI8, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI128, + NonZeroIsize, +); + +// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus +// are also safe to equality-compare bitwise inside an `Option`. +// The way `PartialOrd` is defined for `Option` means that this wouldn't work +// for `<` or `>` on the signed types, but since we only do `==` it's fine. +is_bytewise_comparable!( + Option<NonZeroU8>, + Option<NonZeroU16>, + Option<NonZeroU32>, + Option<NonZeroU64>, + Option<NonZeroU128>, + Option<NonZeroUsize>, + Option<NonZeroI8>, + Option<NonZeroI16>, + Option<NonZeroI32>, + Option<NonZeroI64>, + Option<NonZeroI128>, + Option<NonZeroIsize>, +); + +macro_rules! is_bytewise_comparable_array_length { + ($($n:literal),+ $(,)?) => {$( + // SAFETY: Arrays have no padding between elements, so if the elements are + // `BytewiseEq`, then the whole array can be too. + unsafe impl<T: BytewiseEq<U>, U> BytewiseEq<[U; $n]> for [T; $n] {} + )+}; +} + +// Frustratingly, this can't be made const-generic as it gets +// error: specializing impl repeats parameter `N` +// so just do it for a couple of plausibly-common ones. +is_bytewise_comparable_array_length!(0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64); diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 76daceecd7b..27f6659049c 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -144,6 +144,7 @@ mod c_char_definition { ) ), all(target_os = "fuchsia", target_arch = "aarch64"), + all(target_os = "nto", target_arch = "aarch64"), target_os = "horizon" ))] { pub type c_char = u8; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b1ed3b31e43..18a90599c4d 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2093,6 +2093,10 @@ extern "rust-intrinsic" { /// Above some backend-decided threshold this will emit calls to `memcmp`, /// like slice equality does, instead of causing massive code size. /// + /// Since this works by comparing the underlying bytes, the actual `T` is + /// not particularly important. It will be used for its size and alignment, + /// but any validity restrictions will be ignored, not enforced. + /// /// # Safety /// /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 995d66dca56..72db1d87ca3 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -42,7 +42,7 @@ //! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect //! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]` //! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect = -//! "runtime", phase = "optimized")] if you don't. +//! "runtime", phase = "optimized")]` if you don't. //! //! [dialect docs]: //! https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d17ff651f4f..24bad799fc8 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -136,6 +136,7 @@ #![feature(const_option)] #![feature(const_option_ext)] #![feature(const_pin)] +#![feature(const_pointer_byte_offsets)] #![feature(const_pointer_is_aligned)] #![feature(const_ptr_sub_ptr)] #![feature(const_replace)] @@ -232,6 +233,7 @@ #![feature(simd_ffi)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] +#![feature(target_feature_11)] #![feature(trait_alias)] #![feature(transparent_unions)] #![feature(try_blocks)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 5d5e9559034..994c08d1fb5 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -553,6 +553,7 @@ use crate::pin::Pin; use crate::{ cmp, convert, hint, mem, ops::{self, ControlFlow, Deref, DerefMut}, + slice, }; /// The `Option` type. See [the module level documentation](self) for more. @@ -734,6 +735,124 @@ impl<T> Option<T> { } } + const fn get_some_offset() -> isize { + if mem::size_of::<Option<T>>() == mem::size_of::<T>() { + // niche optimization means the `T` is always stored at the same position as the Option. + 0 + } else { + assert!(mem::size_of::<Option<T>>() == mem::size_of::<Option<mem::MaybeUninit<T>>>()); + let some_uninit = Some(mem::MaybeUninit::<T>::uninit()); + // SAFETY: This gets the byte offset of the `Some(_)` value following the fact that + // niche optimization is not active, and thus Option<T> and Option<MaybeUninit<t>> share + // the same layout. + unsafe { + (some_uninit.as_ref().unwrap() as *const mem::MaybeUninit<T>) + .byte_offset_from(&some_uninit as *const Option<mem::MaybeUninit<T>>) + } + } + } + + /// Returns a slice of the contained value, if any. If this is `None`, an + /// empty slice is returned. This can be useful to have a single type of + /// iterator over an `Option` or slice. + /// + /// Note: Should you have an `Option<&T>` and wish to get a slice of `T`, + /// you can unpack it via `opt.map_or(&[], std::slice::from_ref)`. + /// + /// # Examples + /// + /// ```rust + /// #![feature(option_as_slice)] + /// + /// assert_eq!( + /// [Some(1234).as_slice(), None.as_slice()], + /// [&[1234][..], &[][..]], + /// ); + /// ``` + /// + /// The inverse of this function is (discounting + /// borrowing) [`[_]::first`](slice::first): + /// + /// ```rust + /// #![feature(option_as_slice)] + /// + /// for i in [Some(1234_u16), None] { + /// assert_eq!(i.as_ref(), i.as_slice().first()); + /// } + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "option_as_slice", issue = "108545")] + pub fn as_slice(&self) -> &[T] { + // SAFETY: This is sound as long as `get_some_offset` returns the + // correct offset. Though in the `None` case, the slice may be located + // at a pointer pointing into padding, the fact that the slice is + // empty, and the padding is at a properly aligned position for a + // value of that type makes it sound. + unsafe { + slice::from_raw_parts( + (self as *const Option<T>).wrapping_byte_offset(Self::get_some_offset()) + as *const T, + self.is_some() as usize, + ) + } + } + + /// Returns a mutable slice of the contained value, if any. If this is + /// `None`, an empty slice is returned. This can be useful to have a + /// single type of iterator over an `Option` or slice. + /// + /// Note: Should you have an `Option<&mut T>` instead of a + /// `&mut Option<T>`, which this method takes, you can obtain a mutable + /// slice via `opt.map_or(&mut [], std::slice::from_mut)`. + /// + /// # Examples + /// + /// ```rust + /// #![feature(option_as_slice)] + /// + /// assert_eq!( + /// [Some(1234).as_mut_slice(), None.as_mut_slice()], + /// [&mut [1234][..], &mut [][..]], + /// ); + /// ``` + /// + /// The result is a mutable slice of zero or one items that points into + /// our original `Option`: + /// + /// ```rust + /// #![feature(option_as_slice)] + /// + /// let mut x = Some(1234); + /// x.as_mut_slice()[0] += 1; + /// assert_eq!(x, Some(1235)); + /// ``` + /// + /// The inverse of this method (discounting borrowing) + /// is [`[_]::first_mut`](slice::first_mut): + /// + /// ```rust + /// #![feature(option_as_slice)] + /// + /// assert_eq!(Some(123).as_mut_slice().first_mut(), Some(&mut 123)) + /// ``` + #[inline] + #[must_use] + #[unstable(feature = "option_as_slice", issue = "108545")] + pub fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: This is sound as long as `get_some_offset` returns the + // correct offset. Though in the `None` case, the slice may be located + // at a pointer pointing into padding, the fact that the slice is + // empty, and the padding is at a properly aligned position for a + // value of that type makes it sound. + unsafe { + slice::from_raw_parts_mut( + (self as *mut Option<T>).wrapping_byte_offset(Self::get_some_offset()) as *mut T, + self.is_some() as usize, + ) + } + } + ///////////////////////////////////////////////////////////////////////// // Getting to contained values ///////////////////////////////////////////////////////////////////////// diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index d6e9da187e8..6f78811a186 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -587,8 +587,10 @@ mod prim_pointer {} /// There are two syntactic forms for creating an array: /// /// * A list with each element, i.e., `[x, y, z]`. -/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. -/// The type of `x` must be [`Copy`]. +/// * A repeat expression `[expr; N]` where `N` is how many times to repeat `expr` in the array. `expr` must either be: +/// +/// * A value of a type implementing the [`Copy`] trait +/// * A `const` value /// /// Note that `[expr; 0]` is allowed, and produces an empty array. /// This will still evaluate `expr`, however, and immediately drop the resulting value, so diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 2123147c7e4..efe6d4183e3 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -41,7 +41,7 @@ impl Alignment { /// Returns the alignment for a type. /// /// This provides the same numerical value as [`mem::align_of`], - /// but in an `Alignment` instead of a `usize. + /// but in an `Alignment` instead of a `usize`. #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] pub const fn of<T>() -> Self { diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 5e1b218e507..7601dd3c756 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -1,6 +1,6 @@ //! Comparison traits for `[T]`. -use crate::cmp::{self, Ordering}; +use crate::cmp::{self, BytewiseEq, Ordering}; use crate::ffi; use crate::mem; @@ -77,7 +77,7 @@ where // Use memcmp for bytewise equality when the types allow impl<A, B> SlicePartialEq<B> for [A] where - A: BytewiseEquality<B>, + A: BytewiseEq<B>, { fn equal(&self, other: &[B]) -> bool { if self.len() != other.len() { @@ -203,29 +203,6 @@ impl SliceOrd for u8 { } } -// Hack to allow specializing on `Eq` even though `Eq` has a method. -#[rustc_unsafe_specialization_marker] -trait MarkerEq<T>: PartialEq<T> {} - -impl<T: Eq> MarkerEq<T> for T {} - -#[doc(hidden)] -/// Trait implemented for types that can be compared for equality using -/// their bytewise representation -#[rustc_specialization_trait] -trait BytewiseEquality<T>: MarkerEq<T> + Copy {} - -macro_rules! impl_marker_for { - ($traitname:ident, $($ty:ty)*) => { - $( - impl $traitname<$ty> for $ty { } - )* - } -} - -impl_marker_for!(BytewiseEquality, - u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); - pub(super) trait SliceContains: Sized { fn slice_contains(&self, x: &[Self]) -> bool; } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e8374784501..1cd86b445b0 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2955,7 +2955,7 @@ impl<T> [T] { // This operation is still `O(n)`. // // Example: We start in this state, where `r` represents "next - // read" and `w` represents "next_write`. + // read" and `w` represents "next_write". // // r // +---+---+---+---+---+---+ diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 7b8062c431e..2333f60a888 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -317,7 +317,7 @@ where // 1. `block` - Number of elements in the block. // 2. `start` - Start pointer into the `offsets` array. // 3. `end` - End pointer into the `offsets` array. - // 4. `offsets - Indices of out-of-order elements within the block. + // 4. `offsets` - Indices of out-of-order elements within the block. // The current block on the left side (from `l` to `l.add(block_l)`). let mut l = v.as_mut_ptr(); @@ -327,7 +327,7 @@ where let mut offsets_l = [MaybeUninit::<u8>::uninit(); BLOCK]; // The current block on the right side (from `r.sub(block_r)` to `r`). - // SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe` + // SAFETY: The documentation for .add() specifically mention that `vec.as_ptr().add(vec.len())` is always safe let mut r = unsafe { l.add(v.len()) }; let mut block_r = BLOCK; let mut start_r = ptr::null_mut(); diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index d3ed811b157..68f62ce8be5 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -28,10 +28,6 @@ impl PartialEq for str { fn eq(&self, other: &str) -> bool { self.as_bytes() == other.as_bytes() } - #[inline] - fn ne(&self, other: &str) -> bool { - !(*self).eq(other) - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 00bcaf3e18c..040a59184a6 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -305,6 +305,50 @@ impl AtomicBool { AtomicBool { v: UnsafeCell::new(v as u8) } } + /// Creates a new `AtomicBool` from a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_ptr, pointer_is_aligned)] + /// use std::sync::atomic::{self, AtomicBool}; + /// use std::mem::align_of; + /// + /// // Get a pointer to an allocated value + /// let ptr: *mut bool = Box::into_raw(Box::new(false)); + /// + /// assert!(ptr.is_aligned_to(align_of::<AtomicBool>())); + /// + /// { + /// // Create an atomic view of the allocated value + /// let atomic = unsafe { AtomicBool::from_ptr(ptr) }; + /// + /// // Use `atomic` for atomic operations, possibly share it with other threads + /// atomic.store(true, atomic::Ordering::Relaxed); + /// } + /// + /// // It's ok to non-atomically access the value behind `ptr`, + /// // since the reference to the atomic ended its lifetime in the block above + /// assert_eq!(unsafe { *ptr }, true); + /// + /// // Deallocate the value + /// unsafe { drop(Box::from_raw(ptr)) } + /// ``` + /// + /// # Safety + /// + /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`). + /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. + /// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`. + /// + /// [valid]: crate::ptr#safety + #[unstable(feature = "atomic_from_ptr", issue = "108652")] + #[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")] + pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { + // SAFETY: guaranteed by the caller + unsafe { &*ptr.cast() } + } + /// Returns a mutable reference to the underlying [`bool`]. /// /// This is safe because the mutable reference guarantees that no other threads are @@ -1017,6 +1061,50 @@ impl<T> AtomicPtr<T> { AtomicPtr { p: UnsafeCell::new(p) } } + /// Creates a new `AtomicPtr` from a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_ptr, pointer_is_aligned)] + /// use std::sync::atomic::{self, AtomicPtr}; + /// use std::mem::align_of; + /// + /// // Get a pointer to an allocated value + /// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut())); + /// + /// assert!(ptr.is_aligned_to(align_of::<AtomicPtr<u8>>())); + /// + /// { + /// // Create an atomic view of the allocated value + /// let atomic = unsafe { AtomicPtr::from_ptr(ptr) }; + /// + /// // Use `atomic` for atomic operations, possibly share it with other threads + /// atomic.store(std::ptr::NonNull::dangling().as_ptr(), atomic::Ordering::Relaxed); + /// } + /// + /// // It's ok to non-atomically access the value behind `ptr`, + /// // since the reference to the atomic ended its lifetime in the block above + /// assert!(!unsafe { *ptr }.is_null()); + /// + /// // Deallocate the value + /// unsafe { drop(Box::from_raw(ptr)) } + /// ``` + /// + /// # Safety + /// + /// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this can be bigger than `align_of::<*mut T>()`). + /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. + /// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`. + /// + /// [valid]: crate::ptr#safety + #[unstable(feature = "atomic_from_ptr", issue = "108652")] + #[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")] + pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> { + // SAFETY: guaranteed by the caller + unsafe { &*ptr.cast() } + } + /// Returns a mutable reference to the underlying pointer. /// /// This is safe because the mutable reference guarantees that no other threads are @@ -1958,6 +2046,53 @@ macro_rules! atomic_int { Self {v: UnsafeCell::new(v)} } + /// Creates a new reference to an atomic integer from a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_ptr, pointer_is_aligned)] + #[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")] + /// use std::mem::align_of; + /// + /// // Get a pointer to an allocated value + #[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")] + /// + #[doc = concat!("assert!(ptr.is_aligned_to(align_of::<", stringify!($atomic_type), ">()));")] + /// + /// { + /// // Create an atomic view of the allocated value + // SAFETY: this is a doc comment, tidy, it can't hurt you (also guaranteed by the construction of `ptr` and the assert above) + #[doc = concat!(" let atomic = unsafe {", stringify!($atomic_type), "::from_ptr(ptr) };")] + /// + /// // Use `atomic` for atomic operations, possibly share it with other threads + /// atomic.store(1, atomic::Ordering::Relaxed); + /// } + /// + /// // It's ok to non-atomically access the value behind `ptr`, + /// // since the reference to the atomic ended its lifetime in the block above + /// assert_eq!(unsafe { *ptr }, 1); + /// + /// // Deallocate the value + /// unsafe { drop(Box::from_raw(ptr)) } + /// ``` + /// + /// # Safety + /// + /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`). + #[doc = concat!(" * `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this can be bigger than `align_of::<", stringify!($int_type), ">()`).")] + /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. + /// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`. + /// + /// [valid]: crate::ptr#safety + #[unstable(feature = "atomic_from_ptr", issue = "108652")] + #[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")] + pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { + // SAFETY: guaranteed by the caller + unsafe { &*ptr.cast() } + } + + /// Returns a mutable reference to the underlying integer. /// /// This is safe because the mutable reference guarantees that no other threads are diff --git a/library/core/tests/iter/adapters/mod.rs b/library/core/tests/iter/adapters/mod.rs index ffd5f3857ae..ca3463aa7f7 100644 --- a/library/core/tests/iter/adapters/mod.rs +++ b/library/core/tests/iter/adapters/mod.rs @@ -24,7 +24,7 @@ mod zip; use core::cell::Cell; -/// An iterator that panics whenever `next` or next_back` is called +/// An iterator that panics whenever `next` or `next_back` is called /// after `None` has already been returned. This does not violate /// `Iterator`'s contract. Used to test that iterator adapters don't /// poll their inner iterators after exhausting them. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 3947a64e5c6..ccb7be68eb1 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -67,6 +67,7 @@ #![feature(slice_internals)] #![feature(slice_partition_dedup)] #![feature(ip)] +#![feature(ip_in_core)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_collect_into)] diff --git a/library/portable-simd/crates/core_simd/src/vector.rs b/library/portable-simd/crates/core_simd/src/vector.rs index 78f56402eba..d52d1ac4d3a 100644 --- a/library/portable-simd/crates/core_simd/src/vector.rs +++ b/library/portable-simd/crates/core_simd/src/vector.rs @@ -28,7 +28,7 @@ use crate::simd::{ /// let zm_add = a0.zip(a1).map(|(lhs, rhs)| lhs + rhs); /// let zm_mul = a0.zip(a1).map(|(lhs, rhs)| lhs * rhs); /// -/// // `Simd<T, N>` implements `From<[T; N]> +/// // `Simd<T, N>` implements `From<[T; N]>` /// let (v0, v1) = (Simd::from(a0), Simd::from(a1)); /// // Which means arrays implement `Into<Simd<T, N>>`. /// assert_eq!(v0 + v1, zm_add.into()); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 311b2e21c17..598a4bf9282 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -15,7 +15,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.138", default-features = false, features = ['rustc-dep-of-std'] } +libc = { version = "0.2.139", default-features = false, features = ['rustc-dep-of-std'] } compiler_builtins = { version = "0.1.87" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } diff --git a/library/std/build.rs b/library/std/build.rs index 8b1a06ee750..ea879667558 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -31,6 +31,7 @@ fn main() { || target.contains("espidf") || target.contains("solid") || target.contains("nintendo-3ds") + || target.contains("nto") { // These platforms don't have any special requirements. } else { diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index 8c0adcfb0eb..e019bc0b67a 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -670,7 +670,10 @@ fn debug() { // FIXME: re-enabled openbsd tests once their socket timeout code // no longer has rounding errors. // VxWorks ignores SO_SNDTIMEO. -#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"), + ignore +)] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 #[test] fn timeouts() { diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index f82904ffbbf..892fe2ba8ba 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -180,7 +180,10 @@ fn debug() { // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code // no longer has rounding errors. // VxWorks ignores SO_SNDTIMEO. -#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] +#[cfg_attr( + any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"), + ignore +)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index af137c9bd85..b148d8a0091 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -127,6 +127,8 @@ pub mod l4re; pub mod macos; #[cfg(target_os = "netbsd")] pub mod netbsd; +#[cfg(target_os = "nto")] +pub mod nto; #[cfg(target_os = "openbsd")] pub mod openbsd; #[cfg(target_os = "redox")] diff --git a/library/std/src/os/nto/fs.rs b/library/std/src/os/nto/fs.rs new file mode 100644 index 00000000000..8f915b08c9e --- /dev/null +++ b/library/std/src/os/nto/fs.rs @@ -0,0 +1,92 @@ +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_sec as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atim.tv_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_sec as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtim.tv_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_sec as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctim.tv_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/nto/mod.rs b/library/std/src/os/nto/mod.rs new file mode 100644 index 00000000000..3e591dace92 --- /dev/null +++ b/library/std/src/os/nto/mod.rs @@ -0,0 +1,4 @@ +#![stable(feature = "raw_ext", since = "1.1.0")] + +pub mod fs; +pub(super) mod raw; diff --git a/library/std/src/os/nto/raw.rs b/library/std/src/os/nto/raw.rs new file mode 100644 index 00000000000..90e9ad54643 --- /dev/null +++ b/library/std/src/os/nto/raw.rs @@ -0,0 +1,40 @@ +#![stable(feature = "raw_ext", since = "1.1.0")] +#![deprecated( + since = "1.8.0", + note = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +use crate::os::raw::c_int; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = u32; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = u32; + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = c_int; + +#[doc(inline)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, time_t}; + +mod arch { + use crate::os::raw::c_long; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = i64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = i32; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = i64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = c_long; +} diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 3fc6cc44ce4..a0e664acd13 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -17,6 +17,10 @@ use crate::sealed::Sealed; #[allow(unused_imports)] use io::{Read, Write}; +// Tests for this module +#[cfg(test)] +mod tests; + /// Unix-specific extensions to [`fs::File`]. #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { @@ -54,6 +58,16 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; + /// Like `read_at`, except that it reads into a slice of buffers. + /// + /// Data is copied to fill each buffer in order, with the final buffer + /// written to possibly being only partially filled. This method must behave + /// equivalently to a single call to read with concatenated buffers. + #[unstable(feature = "unix_file_vectored_at", issue = "89517")] + fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + io::default_read_vectored(|b| self.read_at(b, offset), bufs) + } + /// Reads the exact number of byte required to fill `buf` from the given offset. /// /// The offset is relative to the start of the file and thus independent @@ -155,6 +169,16 @@ pub trait FileExt { #[stable(feature = "file_offset", since = "1.15.0")] fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; + /// Like `write_at`, except that it writes from a slice of buffers. + /// + /// Data is copied from each buffer in order, with the final buffer read + /// from possibly being only partially consumed. This method must behave as + /// a call to `write_at` with the buffers concatenated would. + #[unstable(feature = "unix_file_vectored_at", issue = "89517")] + fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> { + io::default_write_vectored(|b| self.write_at(b, offset), bufs) + } + /// Attempts to write an entire buffer starting from a given offset. /// /// The offset is relative to the start of the file and thus independent @@ -218,9 +242,15 @@ impl FileExt for fs::File { fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.as_inner().read_at(buf, offset) } + fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + self.as_inner().read_vectored_at(bufs, offset) + } fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.as_inner().write_at(buf, offset) } + fn write_vectored_at(&self, bufs: &[io::IoSlice<'_>], offset: u64) -> io::Result<usize> { + self.as_inner().write_vectored_at(bufs, offset) + } } /// Unix-specific extensions to [`fs::Permissions`]. diff --git a/library/std/src/os/unix/fs/tests.rs b/library/std/src/os/unix/fs/tests.rs new file mode 100644 index 00000000000..67f607bd468 --- /dev/null +++ b/library/std/src/os/unix/fs/tests.rs @@ -0,0 +1,57 @@ +use super::*; + +#[test] +fn read_vectored_at() { + let msg = b"preadv is working!"; + let dir = crate::sys_common::io::test::tmpdir(); + + let filename = dir.join("preadv.txt"); + { + let mut file = fs::File::create(&filename).unwrap(); + file.write_all(msg).unwrap(); + } + { + let file = fs::File::open(&filename).unwrap(); + let mut buf0 = [0; 4]; + let mut buf1 = [0; 3]; + + let mut iovec = [io::IoSliceMut::new(&mut buf0), io::IoSliceMut::new(&mut buf1)]; + + let n = file.read_vectored_at(&mut iovec, 4).unwrap(); + + assert!(n == 4 || n == 7); + assert_eq!(&buf0, b"dv i"); + + if n == 7 { + assert_eq!(&buf1, b"s w"); + } + } +} + +#[test] +fn write_vectored_at() { + let msg = b"pwritev is not working!"; + let dir = crate::sys_common::io::test::tmpdir(); + + let filename = dir.join("preadv.txt"); + { + let mut file = fs::File::create(&filename).unwrap(); + file.write_all(msg).unwrap(); + } + let expected = { + let file = fs::File::options().write(true).open(&filename).unwrap(); + let buf0 = b" "; + let buf1 = b"great "; + + let iovec = [io::IoSlice::new(buf0), io::IoSlice::new(buf1)]; + + let n = file.write_vectored_at(&iovec, 11).unwrap(); + + assert!(n == 4 || n == 11); + + if n == 4 { b"pwritev is working!" } else { b"pwritev is great !" } + }; + + let content = fs::read(&filename).unwrap(); + assert_eq!(&content, expected); +} diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs index f97fa0fb06f..eb2d7ce1174 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -65,6 +65,8 @@ mod platform { pub use crate::os::macos::*; #[cfg(target_os = "netbsd")] pub use crate::os::netbsd::*; + #[cfg(target_os = "nto")] + pub use crate::os::nto::*; #[cfg(target_os = "openbsd")] pub use crate::os::openbsd::*; #[cfg(target_os = "redox")] @@ -95,7 +97,8 @@ pub mod thread; target_os = "watchos", target_os = "macos", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", + target_os = "nto", ))] pub mod ucred; diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index f758f88d0a3..272b4f5dcd5 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -19,7 +19,8 @@ use crate::{fmt, io}; target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku" + target_os = "haiku", + target_os = "nto", ))] use libc::MSG_NOSIGNAL; #[cfg(not(any( @@ -29,7 +30,8 @@ use libc::MSG_NOSIGNAL; target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku" + target_os = "haiku", + target_os = "nto", )))] const MSG_NOSIGNAL: libc::c_int = 0x0; diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index 37fcfa8446b..f8c29a6d3a1 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -167,6 +167,7 @@ fn long_path() { } #[test] +#[cfg(not(target_os = "nto"))] fn timeouts() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 09b2bfe39f0..729c63d184f 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -12,15 +12,23 @@ use crate::sealed::Sealed; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; -#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))] -type UserId = u32; -#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))] -type GroupId = u32; - -#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] -type UserId = u16; -#[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] -type GroupId = u16; +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon"))] { + type UserId = u16; + type GroupId = u16; + } else if #[cfg(target_os = "nto")] { + // Both IDs are signed, see `sys/target_nto.h` of the QNX Neutrino SDP. + // Only positive values should be used, see e.g. + // https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setuid.html + type UserId = i32; + type GroupId = i32; + } else { + type UserId = u32; + type GroupId = u32; + } +} /// Unix-specific extensions to the [`process::Command`] builder. /// diff --git a/library/std/src/os/unix/ucred.rs b/library/std/src/os/unix/ucred.rs index ae4faf27b4d..95967eac295 100644 --- a/library/std/src/os/unix/ucred.rs +++ b/library/std/src/os/unix/ucred.rs @@ -79,7 +79,8 @@ pub mod impl_linux { target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", - target_os = "netbsd" + target_os = "netbsd", + target_os = "nto", ))] pub mod impl_bsd { use super::UCred; diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index d6e9da187e8..6f78811a186 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -587,8 +587,10 @@ mod prim_pointer {} /// There are two syntactic forms for creating an array: /// /// * A list with each element, i.e., `[x, y, z]`. -/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. -/// The type of `x` must be [`Copy`]. +/// * A repeat expression `[expr; N]` where `N` is how many times to repeat `expr` in the array. `expr` must either be: +/// +/// * A value of a type implementing the [`Copy`] trait +/// * A `const` value /// /// Note that `[expr; 0]` is allowed, and produces an empty array. /// This will still evaluate `expr`, however, and immediately drop the resulting value, so diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 62ce2cb33dc..1952e19e607 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1416,7 +1416,7 @@ impl From<fs::File> for Stdio { /// use std::fs::File; /// use std::process::Command; /// - /// // With the `foo.txt` file containing `Hello, world!" + /// // With the `foo.txt` file containing "Hello, world!" /// let file = File::open("foo.txt").unwrap(); /// /// let reverse = Command::new("rev") diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs index 19350b83fab..ae0f718535b 100644 --- a/library/std/src/sys/itron/thread.rs +++ b/library/std/src/sys/itron/thread.rs @@ -247,7 +247,7 @@ impl Thread { // [FINISHED → JOINED] // To synchronize with the child task's memory accesses to // `inner` up to the point of the assignment of `FINISHED`, - // `Ordering::Acquire` must be used for the above `swap` call`. + // `Ordering::Acquire` must be used for the above `swap` call. } _ => unsafe { hint::unreachable_unchecked() }, } diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index a5ce6d5120d..3d79058b320 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -69,7 +69,8 @@ impl DoubleEndedIterator for Args { target_os = "fuchsia", target_os = "redox", target_os = "vxworks", - target_os = "horizon" + target_os = "horizon", + target_os = "nto", ))] mod imp { use super::Args; diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs index c9ba661c829..1a9276f1110 100644 --- a/library/std/src/sys/unix/env.rs +++ b/library/std/src/sys/unix/env.rs @@ -185,6 +185,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "nto")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "nto"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "redox")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 66c33d58d6c..9874af4d3e2 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -53,7 +53,12 @@ const fn max_iov() -> usize { libc::IOV_MAX as usize } -#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] +#[cfg(any( + target_os = "android", + target_os = "emscripten", + target_os = "linux", + target_os = "nto", +))] const fn max_iov() -> usize { libc::UIO_MAXIOV as usize } @@ -67,6 +72,7 @@ const fn max_iov() -> usize { target_os = "linux", target_os = "macos", target_os = "netbsd", + target_os = "nto", target_os = "openbsd", target_os = "horizon", target_os = "watchos", @@ -92,7 +98,7 @@ impl FileDesc { let ret = cvt(unsafe { libc::readv( self.as_raw_fd(), - bufs.as_ptr() as *const libc::iovec, + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, cmp::min(bufs.len(), max_iov()) as libc::c_int, ) })?; @@ -101,7 +107,7 @@ impl FileDesc { #[cfg(any(target_os = "espidf", target_os = "horizon"))] pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - return crate::io::default_read_vectored(|b| self.read(b), bufs); + io::default_read_vectored(|b| self.read(b), bufs) } #[inline] @@ -147,6 +153,95 @@ impl FileDesc { Ok(()) } + #[cfg(any( + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + ))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + let ret = cvt(unsafe { + libc::preadv( + self.as_raw_fd(), + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + )))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + io::default_read_vectored(|b| self.read_at(b, offset), bufs) + } + + // We support some old Android versions that do not have `preadv` in libc, + // so we use weak linkage and fallback to a direct syscall if not available. + // + // On 32-bit targets, we don't want to deal with weird ABI issues around + // passing 64-bits parameters to syscalls, so we fallback to the default + // implementation if `preadv` is not available. + #[cfg(all(target_os = "android", target_pointer_width = "64"))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + super::weak::syscall! { + fn preadv( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t + ) -> isize + } + + let ret = cvt(unsafe { + preadv( + self.as_raw_fd(), + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + // We support old MacOS and iOS versions that do not have `preadv`. There is + // no `syscall` possible in these platform. + #[cfg(any( + all(target_os = "android", target_pointer_width = "32"), + target_os = "ios", + target_os = "macos", + ))] + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + + match preadv64.get() { + Some(preadv) => { + let ret = cvt(unsafe { + preadv( + self.as_raw_fd(), + bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + None => io::default_read_vectored(|b| self.read_at(b, offset), bufs), + } + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { let ret = cvt(unsafe { libc::write( @@ -172,7 +267,7 @@ impl FileDesc { #[cfg(any(target_os = "espidf", target_os = "horizon"))] pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - return crate::io::default_write_vectored(|b| self.write(b), bufs); + io::default_write_vectored(|b| self.write(b), bufs) } #[inline] @@ -197,6 +292,95 @@ impl FileDesc { } } + #[cfg(any( + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + ))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + let ret = cvt(unsafe { + libc::pwritev( + self.as_raw_fd(), + bufs.as_ptr() as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + #[cfg(not(any( + target_os = "android", + target_os = "emscripten", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "illumos", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + )))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + io::default_write_vectored(|b| self.write_at(b, offset), bufs) + } + + // We support some old Android versions that do not have `pwritev` in libc, + // so we use weak linkage and fallback to a direct syscall if not available. + // + // On 32-bit targets, we don't want to deal with weird ABI issues around + // passing 64-bits parameters to syscalls, so we fallback to the default + // implementation if `pwritev` is not available. + #[cfg(all(target_os = "android", target_pointer_width = "64"))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + super::weak::syscall! { + fn pwritev( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t + ) -> isize + } + + let ret = cvt(unsafe { + pwritev( + self.as_raw_fd(), + bufs.as_ptr() as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + + // We support old MacOS and iOS versions that do not have `pwritev`. There is + // no `syscall` possible in these platform. + #[cfg(any( + all(target_os = "android", target_pointer_width = "32"), + target_os = "ios", + target_os = "macos", + ))] + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + + match pwritev64.get() { + Some(pwritev) => { + let ret = cvt(unsafe { + pwritev( + self.as_raw_fd(), + bufs.as_ptr() as *const libc::iovec, + cmp::min(bufs.len(), max_iov()) as libc::c_int, + offset as _, + ) + })?; + Ok(ret as usize) + } + None => io::default_write_vectored(|b| self.write_at(b, offset), bufs), + } + } + #[cfg(not(any( target_env = "newlib", target_os = "solaris", @@ -207,7 +391,8 @@ impl FileDesc { target_os = "linux", target_os = "haiku", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "nto", )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -225,7 +410,8 @@ impl FileDesc { target_os = "linux", target_os = "haiku", target_os = "redox", - target_os = "vxworks" + target_os = "vxworks", + target_os = "nto", ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8e1f35d6cc9..7566fafda24 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -13,7 +13,8 @@ use crate::mem; target_os = "solaris", target_os = "fuchsia", target_os = "redox", - target_os = "illumos" + target_os = "illumos", + target_os = "nto", ))] use crate::mem::MaybeUninit; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; @@ -54,7 +55,8 @@ use libc::fstatat64; target_os = "solaris", target_os = "fuchsia", target_os = "redox", - target_os = "illumos" + target_os = "illumos", + target_os = "nto", ))] use libc::readdir as readdir64; #[cfg(target_os = "linux")] @@ -69,7 +71,8 @@ use libc::readdir64_r; target_os = "illumos", target_os = "l4re", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "nto", )))] use libc::readdir_r as readdir64_r; #[cfg(target_os = "android")] @@ -277,7 +280,8 @@ unsafe impl Sync for Dir {} target_os = "solaris", target_os = "illumos", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "nto", ))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -297,11 +301,12 @@ pub struct DirEntry { target_os = "solaris", target_os = "illumos", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "nto", ))] struct dirent64_min { d_ino: u64, - #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "nto")))] d_type: u8, } @@ -311,7 +316,8 @@ struct dirent64_min { target_os = "solaris", target_os = "illumos", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "nto", )))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -438,7 +444,7 @@ impl FileAttr { } } -#[cfg(not(target_os = "netbsd"))] +#[cfg(not(any(target_os = "netbsd", target_os = "nto")))] impl FileAttr { #[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))] pub fn modified(&self) -> io::Result<SystemTime> { @@ -524,6 +530,21 @@ impl FileAttr { } } +#[cfg(target_os = "nto")] +impl FileAttr { + pub fn modified(&self) -> io::Result<SystemTime> { + Ok(SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec)) + } + + pub fn accessed(&self) -> io::Result<SystemTime> { + Ok(SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec)) + } + + pub fn created(&self) -> io::Result<SystemTime> { + Ok(SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec)) + } +} + impl AsInner<stat64> for FileAttr { fn as_inner(&self) -> &stat64 { &self.stat @@ -603,7 +624,8 @@ impl Iterator for ReadDir { target_os = "solaris", target_os = "fuchsia", target_os = "redox", - target_os = "illumos" + target_os = "illumos", + target_os = "nto", ))] fn next(&mut self) -> Option<io::Result<DirEntry>> { if self.end_of_stream { @@ -686,7 +708,11 @@ impl Iterator for ReadDir { let entry = dirent64_min { d_ino: *offset_ptr!(entry_ptr, d_ino) as u64, - #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "nto", + )))] d_type: *offset_ptr!(entry_ptr, d_type) as u8, }; @@ -705,7 +731,8 @@ impl Iterator for ReadDir { target_os = "solaris", target_os = "fuchsia", target_os = "redox", - target_os = "illumos" + target_os = "illumos", + target_os = "nto", )))] fn next(&mut self) -> Option<io::Result<DirEntry>> { if self.end_of_stream { @@ -794,7 +821,8 @@ impl DirEntry { target_os = "solaris", target_os = "illumos", target_os = "haiku", - target_os = "vxworks" + target_os = "vxworks", + target_os = "nto", ))] pub fn file_type(&self) -> io::Result<FileType> { self.metadata().map(|m| m.file_type()) @@ -804,7 +832,8 @@ impl DirEntry { target_os = "solaris", target_os = "illumos", target_os = "haiku", - target_os = "vxworks" + target_os = "vxworks", + target_os = "nto", )))] pub fn file_type(&self) -> io::Result<FileType> { match self.entry.d_type { @@ -834,7 +863,8 @@ impl DirEntry { target_os = "redox", target_os = "vxworks", target_os = "espidf", - target_os = "horizon" + target_os = "horizon", + target_os = "nto", ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -887,7 +917,8 @@ impl DirEntry { target_os = "solaris", target_os = "illumos", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "nto", )))] fn name_cstr(&self) -> &CStr { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } @@ -898,7 +929,8 @@ impl DirEntry { target_os = "solaris", target_os = "illumos", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "nto", ))] fn name_cstr(&self) -> &CStr { &self.name @@ -1051,7 +1083,8 @@ impl File { target_os = "linux", target_os = "android", target_os = "netbsd", - target_os = "openbsd" + target_os = "openbsd", + target_os = "nto", ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) @@ -1065,6 +1098,7 @@ impl File { target_os = "netbsd", target_os = "openbsd", target_os = "watchos", + target_os = "nto", )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) @@ -1098,6 +1132,10 @@ impl File { self.0.read_buf(cursor) } + pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { + self.0.read_vectored_at(bufs, offset) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } @@ -1115,6 +1153,10 @@ impl File { self.0.write_at(buf, offset) } + pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { + self.0.write_vectored_at(bufs, offset) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } @@ -1750,13 +1792,25 @@ pub fn chroot(dir: &Path) -> io::Result<()> { pub use remove_dir_impl::remove_dir_all; // Fallback for REDOX, ESP-ID, Horizon, and Miri -#[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri))] +#[cfg(any( + target_os = "redox", + target_os = "espidf", + target_os = "horizon", + target_os = "nto", + miri +))] mod remove_dir_impl { pub use crate::sys_common::fs::remove_dir_all; } // Modern implementation using openat(), unlinkat() and fdopendir() -#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri)))] +#[cfg(not(any( + target_os = "redox", + target_os = "espidf", + target_os = "horizon", + target_os = "nto", + miri +)))] mod remove_dir_impl { use super::{lstat, Dir, DirEntry, InnerReadDir, ReadDir}; use crate::ffi::CStr; diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index 6be1abc2b08..192fa216dfa 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -2,7 +2,10 @@ use crate::cell::UnsafeCell; use crate::ptr; use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed}; use crate::sys::locks::{pthread_mutex, Mutex}; +#[cfg(not(target_os = "nto"))] use crate::sys::time::TIMESPEC_MAX; +#[cfg(target_os = "nto")] +use crate::sys::time::TIMESPEC_MAX_CAPPED; use crate::sys_common::lazy_box::{LazyBox, LazyInit}; use crate::time::Duration; @@ -132,10 +135,18 @@ impl Condvar { let mutex = pthread_mutex::raw(mutex); self.verify(mutex); + #[cfg(not(target_os = "nto"))] let timeout = Timespec::now(libc::CLOCK_MONOTONIC) .checked_add_duration(&dur) .and_then(|t| t.to_timespec()) .unwrap_or(TIMESPEC_MAX); + + #[cfg(target_os = "nto")] + let timeout = Timespec::now(libc::CLOCK_MONOTONIC) + .checked_add_duration(&dur) + .and_then(|t| t.to_timespec_capped()) + .unwrap_or(TIMESPEC_MAX_CAPPED); + let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout); assert!(r == libc::ETIMEDOUT || r == 0); r == 0 diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 30a96be1430..68c9520cc9e 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -329,7 +329,7 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { // do so. In 1003.1-2004 this was fixed. // // glibc's implementation did the flush, unsafely, before glibc commit -// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]' by Florian +// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]` by Florian // Weimer. According to glibc's NEWS: // // The abort function terminates the process immediately, without flushing diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index c86f80972a6..8e05b618daa 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -78,6 +78,7 @@ impl Socket { target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "nto", ))] { // On platforms that support it we pass the SOCK_CLOEXEC // flag to atomically create the socket and set it as @@ -115,6 +116,7 @@ impl Socket { target_os = "linux", target_os = "netbsd", target_os = "openbsd", + target_os = "nto", ))] { // Like above, set cloexec atomically cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?; diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 2f2663db607..21b035fb373 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -62,6 +62,7 @@ extern "C" { link_name = "__errno" )] #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] + #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")] #[cfg_attr( any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"), link_name = "__error" @@ -361,6 +362,17 @@ pub fn current_exe() -> io::Result<PathBuf> { } } +#[cfg(target_os = "nto")] +pub fn current_exe() -> io::Result<PathBuf> { + let mut e = crate::fs::read("/proc/self/exefile")?; + // Current versions of QNX Neutrino provide a null-terminated path. + // Ensure the trailing null byte is not returned here. + if let Some(0) = e.last() { + e.pop(); + } + Ok(PathBuf::from(OsString::from_vec(e))) +} + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] pub fn current_exe() -> io::Result<PathBuf> { unsafe { diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 3bc17b7754d..ceaff596684 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -18,6 +18,7 @@ use crate::sys::weak::raw_syscall; target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), + target_os = "nto", ))] use crate::sys::weak::weak; @@ -30,6 +31,15 @@ use libc::{c_int, pid_t}; #[cfg(not(any(target_os = "vxworks", target_os = "l4re")))] use libc::{gid_t, uid_t}; +cfg_if::cfg_if! { + if #[cfg(all(target_os = "nto", target_env = "nto71"))] { + use crate::thread; + use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t}; + // arbitrary number of tries: + const MAX_FORKSPAWN_TRIES: u32 = 4; + } +} + //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// @@ -140,11 +150,31 @@ impl Command { // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, -1)) in the parent. - #[cfg(not(target_os = "linux"))] + #[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))] unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { cvt(libc::fork()).map(|res| (res, -1)) } + // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened + // or closed a file descriptor while the fork() was occurring". + // Documentation says "... or try calling fork() again". This is what we do here. + // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html + #[cfg(all(target_os = "nto", target_env = "nto71"))] + unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> { + use crate::sys::os::errno; + + let mut tries_left = MAX_FORKSPAWN_TRIES; + loop { + let r = libc::fork(); + if r == -1 as libc::pid_t && tries_left > 0 && errno() as libc::c_int == libc::EBADF { + thread::yield_now(); + tries_left -= 1; + } else { + return cvt(r).map(|res| (res, -1)); + } + } + } + // Attempts to fork the process. If successful, returns Ok((0, -1)) // in the child, and Ok((child_pid, child_pidfd)) in the parent. #[cfg(target_os = "linux")] @@ -389,6 +419,7 @@ impl Command { target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), + target_os = "nto", )))] fn posix_spawn( &mut self, @@ -405,6 +436,7 @@ impl Command { target_os = "freebsd", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), + target_os = "nto", ))] fn posix_spawn( &mut self, @@ -436,6 +468,34 @@ impl Command { } } + // On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened + // or closed a file descriptor while the posix_spawn() was occurring". + // Documentation says "... or try calling posix_spawn() again". This is what we do here. + // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html + #[cfg(all(target_os = "nto", target_env = "nto71"))] + unsafe fn retrying_libc_posix_spawnp( + pid: *mut pid_t, + file: *const c_char, + file_actions: *const posix_spawn_file_actions_t, + attrp: *const posix_spawnattr_t, + argv: *const *mut c_char, + envp: *const *mut c_char, + ) -> i32 { + let mut tries_left = MAX_FORKSPAWN_TRIES; + loop { + match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) { + libc::EBADF if tries_left > 0 => { + thread::yield_now(); + tries_left -= 1; + continue; + } + r => { + return r; + } + } + } + } + // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory, // and maybe others will gain this non-POSIX function too. We'll check // for this weak symbol as soon as it's needed, so we can return early @@ -555,7 +615,12 @@ impl Command { // Make sure we synchronize access to the global `environ` resource let _env_lock = sys::os::env_read_lock(); let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); - cvt_nz(libc::posix_spawnp( + + #[cfg(not(target_os = "nto"))] + let spawn_fn = libc::posix_spawnp; + #[cfg(target_os = "nto")] + let spawn_fn = retrying_libc_posix_spawnp; + cvt_nz(spawn_fn( &mut p.pid, self.get_program_cstr().as_ptr(), file_actions.0.as_ptr(), @@ -760,7 +825,7 @@ fn signal_string(signal: i32) -> &'static str { ) ))] libc::SIGSTKFLT => " (SIGSTKFLT)", - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "nto"))] libc::SIGPWR => " (SIGPWR)", #[cfg(any( target_os = "macos", @@ -769,7 +834,8 @@ fn signal_string(signal: i32) -> &'static str { target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", - target_os = "dragonfly" + target_os = "dragonfly", + target_os = "nto", ))] libc::SIGEMT => " (SIGEMT)", #[cfg(any( diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index cc0e5929569..15070b1f6a7 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -9,7 +9,7 @@ use crate::time::Duration; #[cfg(all(target_os = "linux", target_env = "gnu"))] use crate::sys::weak::dlsym; -#[cfg(any(target_os = "solaris", target_os = "illumos"))] +#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] use crate::sys::weak::weak; #[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; @@ -173,7 +173,7 @@ impl Thread { } } - #[cfg(any(target_os = "solaris", target_os = "illumos"))] + #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] pub fn set_name(name: &CStr) { weak! { fn pthread_setname_np( @@ -381,6 +381,17 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { } Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) + } else if #[cfg(target_os = "nto")] { + unsafe { + use libc::_syspage_ptr; + if _syspage_ptr.is_null() { + Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available")) + } else { + let cpus = (*_syspage_ptr).num_cpu; + NonZeroUsize::new(cpus as usize) + .ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")) + } + } } else if #[cfg(target_os = "haiku")] { // system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus` // `get_system_info` calls then `smp_get_num_cpus` diff --git a/library/std/src/sys/unix/thread_parking/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs index 082d25e68f5..43046ed07b8 100644 --- a/library/std/src/sys/unix/thread_parking/pthread.rs +++ b/library/std/src/sys/unix/thread_parking/pthread.rs @@ -6,7 +6,10 @@ use crate::pin::Pin; use crate::ptr::addr_of_mut; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::SeqCst; +#[cfg(not(target_os = "nto"))] use crate::sys::time::TIMESPEC_MAX; +#[cfg(target_os = "nto")] +use crate::sys::time::TIMESPEC_MAX_CAPPED; use crate::time::Duration; const EMPTY: usize = 0; @@ -80,8 +83,14 @@ unsafe fn wait_timeout( (Timespec::now(libc::CLOCK_MONOTONIC), dur) }; + #[cfg(not(target_os = "nto"))] let timeout = now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX); + #[cfg(target_os = "nto")] + let timeout = now + .checked_add_duration(&dur) + .and_then(|t| t.to_timespec_capped()) + .unwrap_or(TIMESPEC_MAX_CAPPED); let r = libc::pthread_cond_timedwait(cond, lock, &timeout); debug_assert!(r == libc::ETIMEDOUT || r == 0); } diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index 2daad981b73..0f11de8f5b8 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -9,6 +9,14 @@ pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; pub const TIMESPEC_MAX: libc::timespec = libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 }; +// This additional constant is only used when calling +// `libc::pthread_cond_timedwait`. +#[cfg(target_os = "nto")] +pub(super) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec { + tv_sec: (u64::MAX / NSEC_PER_SEC) as i64, + tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64, +}; + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -144,6 +152,20 @@ impl Timespec { tv_nsec: self.tv_nsec.0.try_into().ok()?, }) } + + // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait + // is 2^64 nanoseconds + #[cfg(target_os = "nto")] + pub(super) fn to_timespec_capped(&self) -> Option<libc::timespec> { + // Check if timeout in nanoseconds would fit into an u64 + if (self.tv_nsec.0 as u64) + .checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?) + .is_none() + { + return None; + } + self.to_timespec() + } } impl From<libc::timespec> for Timespec { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index f1d804ef40c..8752f46ff81 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -91,6 +91,19 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: if stop { return false; } + #[cfg(target_os = "nto")] + if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { + if !hit && start { + use crate::backtrace_rs::SymbolName; + res = bt_fmt.frame().print_raw( + frame.ip(), + Some(SymbolName::new("__my_thread_exit".as_bytes())), + None, + None, + ); + } + return false; + } if !hit && start { res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 2c38dfecf97..85ecc1def3a 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -21,7 +21,7 @@ cfg_if::cfg_if! { target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "watchos", target_os = "openbsd", target_os = "netbsd", target_os = "illumos", - target_os = "solaris", target_os = "haiku", target_os = "l4re"))] { + target_os = "solaris", target_os = "haiku", target_os = "l4re", target_os = "nto"))] { use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; use crate::sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; } else { @@ -35,7 +35,7 @@ cfg_if::cfg_if! { target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku"))] { + target_os = "haiku", target_os = "nto"))] { use libc::MSG_NOSIGNAL; } else { const MSG_NOSIGNAL: c_int = 0x0; @@ -46,7 +46,8 @@ cfg_if::cfg_if! { if #[cfg(any( target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris", target_os = "illumos"))] { + target_os = "solaris", target_os = "illumos", + target_os = "nto"))] { use crate::ffi::c_uchar; type IpV4MultiCastType = c_uchar; } else { diff --git a/library/std/src/sys_common/net/tests.rs b/library/std/src/sys_common/net/tests.rs index ac75d9ebfc8..fc236b8027b 100644 --- a/library/std/src/sys_common/net/tests.rs +++ b/library/std/src/sys_common/net/tests.rs @@ -6,7 +6,7 @@ fn no_lookup_host_duplicates() { let mut addrs = HashMap::new(); let lh = match LookupHost::try_from(("localhost", 0)) { Ok(lh) => lh, - Err(e) => panic!("couldn't resolve `localhost': {e}"), + Err(e) => panic!("couldn't resolve `localhost`: {e}"), }; for sa in lh { *addrs.entry(sa).or_insert(0) += 1; diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 2672a2a75b0..89360e45601 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -117,9 +117,15 @@ pub struct Key { /// This value specifies no destructor by default. pub const INIT: StaticKey = StaticKey::new(None); -// Define a sentinel value that is unlikely to be returned -// as a TLS key (but it may be returned). +// Define a sentinel value that is likely not to be returned +// as a TLS key. +#[cfg(not(target_os = "nto"))] const KEY_SENTVAL: usize = 0; +// On QNX Neutrino, 0 is always returned when currently not in use. +// Using 0 would mean to always create two keys and remote the first +// one (with value of 0) immediately afterwards. +#[cfg(target_os = "nto")] +const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1; impl StaticKey { #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index e202d17e1c2..bc588bdbb3c 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -594,7 +594,7 @@ impl Wtf8 { } /// Returns the code point at `position` if it is in the ASCII range, - /// or `b'\xFF' otherwise. + /// or `b'\xFF'` otherwise. /// /// # Panics /// diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 69fb529d7f5..88d8e5fe97a 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -204,7 +204,7 @@ fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn { } /// Invoked when unit tests terminate. Returns `Result::Err` if the test is -/// considered a failure. By default, invokes `report() and checks for a `0` +/// considered a failure. By default, invokes `report()` and checks for a `0` /// result. pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> { let code = result.report().to_i32(); diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 3753071d5f0..edc10aa39af 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -127,3 +127,7 @@ extern "C" {} #[cfg(target_os = "haiku")] #[link(name = "gcc_s")] extern "C" {} + +#[cfg(target_os = "nto")] +#[link(name = "gcc_s")] +extern "C" {} diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 036a35869a5..eeeed3afcd3 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -89,7 +89,7 @@ pub type _Unwind_Exception_Cleanup_Fn = // FIXME: The `#[link]` attributes on `extern "C"` block marks those symbols declared in // the block are reexported in dylib build of std. This is needed when build rustc with -// feature `llvm-libunwind', as no other cdylib will provided those _Unwind_* symbols. +// feature `llvm-libunwind`, as no other cdylib will provided those _Unwind_* symbols. // However the `link` attribute is duplicated multiple times and does not just export symbol, // a better way to manually export symbol would be another attribute like `#[export]`. // See the logic in function rustc_codegen_ssa::src::back::exported_symbols, module diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 468efc1114c..7ebd0a8f270 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -62,6 +62,7 @@ macro_rules! clean_crate_tree { let target = compiler.host; let mut cargo = builder.bare_cargo(compiler, $mode, target, "clean"); for krate in &*self.crates { + cargo.arg("-p"); cargo.arg(krate); } diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index 681ecbfeb5b..5a105007f21 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -11,6 +11,11 @@ fn parse(config: &str) -> Config { #[test] fn download_ci_llvm() { + if crate::native::is_ci_llvm_modified(&parse("")) { + eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); + return; + } + let parse_llvm = |s| parse(s).llvm_from_ci; let if_available = parse_llvm("llvm.download-ci-llvm = \"if-available\""); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 04e798e3949..ab3d0829296 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -442,6 +442,8 @@ def to_toml(value): return value else: return "'" + value + "'" + elif isinstance(value, dict): + return "{" + ", ".join(map(lambda a: "{} = {}".format(to_toml(a[0]), to_toml(a[1])), value.items())) + "}" else: raise RuntimeError('no toml') diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 7f8aa2573dd..cc80763ef44 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -62,6 +62,7 @@ macro_rules! book { target: self.target, name: INTERNER.intern_str($book_name), src: INTERNER.intern_path(builder.src.join($path)), + parent: Some(self), }) } } @@ -119,18 +120,20 @@ impl Step for UnstableBook { target: self.target, name: INTERNER.intern_str("unstable-book"), src: INTERNER.intern_path(builder.md_doc_out(self.target).join("unstable-book")), + parent: Some(self), }) } } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -struct RustbookSrc { +struct RustbookSrc<P: Step> { target: TargetSelection, name: Interned<String>, src: Interned<PathBuf>, + parent: Option<P>, } -impl Step for RustbookSrc { +impl<P: Step> Step for RustbookSrc<P> { type Output = (); fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -152,13 +155,18 @@ impl Step for RustbookSrc { let index = out.join("index.html"); let rustbook = builder.tool_exe(Tool::Rustbook); let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); - if builder.config.dry_run() || up_to_date(&src, &index) && up_to_date(&rustbook, &index) { - return; + + if !builder.config.dry_run() && !(up_to_date(&src, &index) || up_to_date(&rustbook, &index)) + { + builder.info(&format!("Rustbook ({}) - {}", target, name)); + let _ = fs::remove_dir_all(&out); + + builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(out)); } - builder.info(&format!("Rustbook ({}) - {}", target, name)); - let _ = fs::remove_dir_all(&out); - builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(out)); + if self.parent.is_some() { + builder.maybe_open_in_browser::<P>(index) + } } } @@ -205,6 +213,7 @@ impl Step for TheBook { target, name: INTERNER.intern_str("book"), src: INTERNER.intern_path(builder.src.join(&relative_path)), + parent: Some(self), }); // building older edition redirects @@ -213,6 +222,9 @@ impl Step for TheBook { target, name: INTERNER.intern_string(format!("book/{}", edition)), src: INTERNER.intern_path(builder.src.join(&relative_path).join(edition)), + // There should only be one book that is marked as the parent for each target, so + // treat the other editions as not having a parent. + parent: Option::<Self>::None, }); } @@ -228,10 +240,6 @@ impl Step for TheBook { invoke_rustdoc(builder, compiler, &shared_assets, target, path); } - - let out = builder.doc_out(target); - let index = out.join("book").join("index.html"); - builder.maybe_open_in_browser::<Self>(index); } } @@ -1032,10 +1040,7 @@ impl Step for RustcBook { target: self.target, name: INTERNER.intern_str("rustc"), src: INTERNER.intern_path(out_base), + parent: Some(self), }); - - let out = builder.doc_out(self.target); - let index = out.join("rustc").join("index.html"); - builder.maybe_open_in_browser::<Self>(index); } } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 21157b02a78..5987b641b39 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -216,21 +216,24 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { } } - if CiEnv::is_ci() { + if is_ci_llvm_modified(config) { + eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); + return false; + } + + true +} + +/// Returns true if we're running in CI with modified LLVM (and thus can't download it) +pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { + CiEnv::is_ci() && { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); let head_sha = output(config.git().arg("rev-parse").arg("HEAD")); let head_sha = head_sha.trim(); - if llvm_sha == head_sha { - eprintln!( - "Detected LLVM as non-available: running in CI and modified LLVM in this change" - ); - return false; - } + llvm_sha == head_sha } - - true } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index c3d532c4b27..e7d1d9781d5 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -9,6 +9,7 @@ https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-unk import argparse from dataclasses import dataclass +import fcntl import glob import hashlib import json @@ -146,6 +147,9 @@ class TestEnvironment: def zxdb_script_path(self): return os.path.join(self.tmp_dir(), "zxdb_script") + def pm_lockfile_path(self): + return os.path.join(self.tmp_dir(), "pm.lock") + def log_info(self, msg): print(msg) @@ -460,6 +464,9 @@ class TestEnvironment: stderr=self.subprocess_output(), ) + # Create lockfiles + open(self.pm_lockfile_path(), 'a').close() + # Write to file self.write_to_file() @@ -676,19 +683,25 @@ class TestEnvironment: log("Publishing package to repo...") # Publish package to repo - subprocess.check_call( - [ - self.tool_path("pm"), - "publish", - "-a", - "-repo", - self.repo_dir(), - "-f", - far_path, - ], - stdout=log_file, - stderr=log_file, - ) + with open(self.pm_lockfile_path(), 'w') as pm_lockfile: + fcntl.lockf(pm_lockfile.fileno(), fcntl.LOCK_EX) + subprocess.check_call( + [ + self.tool_path("pm"), + "publish", + "-a", + "-repo", + self.repo_dir(), + "-f", + far_path, + ], + stdout=log_file, + stderr=log_file, + ) + # This lock should be released automatically when the pm + # lockfile is closed, but we'll be polite and unlock it now + # since the spec leaves some wiggle room. + fcntl.lockf(pm_lockfile.fileno(), fcntl.LOCK_UN) log("Running ffx test...") diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index ad9c308ad85..11f1532bef5 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -78,7 +78,7 @@ x--expand-yaml-anchors--remove: <<: *base-job - &job-macos-xl - os: macos-latest # We don't have an XL builder for this + os: macos-12-xl <<: *base-job - &job-windows-xl diff --git a/src/ci/pgo.sh b/src/ci/pgo.sh deleted file mode 100755 index cbe32920a74..00000000000 --- a/src/ci/pgo.sh +++ /dev/null @@ -1,230 +0,0 @@ -#!/bin/bash -# ignore-tidy-linelength - -set -euxo pipefail - -ci_dir=`cd $(dirname $0) && pwd` -source "$ci_dir/shared.sh" - -# The root checkout, where the source is located -CHECKOUT=/checkout - -DOWNLOADED_LLVM=/rustroot - -# The main directory where the build occurs, which can be different between linux and windows -BUILD_ROOT=$CHECKOUT/obj - -if isWindows; then - CHECKOUT=$(pwd) - DOWNLOADED_LLVM=$CHECKOUT/citools/clang-rust - BUILD_ROOT=$CHECKOUT -fi - -# The various build artifacts used in other commands: to launch rustc builds, build the perf -# collector, and run benchmarks to gather profiling data -BUILD_ARTIFACTS=$BUILD_ROOT/build/$PGO_HOST -RUSTC_STAGE_0=$BUILD_ARTIFACTS/stage0/bin/rustc -CARGO_STAGE_0=$BUILD_ARTIFACTS/stage0/bin/cargo -RUSTC_STAGE_2=$BUILD_ARTIFACTS/stage2/bin/rustc - -# Windows needs these to have the .exe extension -if isWindows; then - RUSTC_STAGE_0="${RUSTC_STAGE_0}.exe" - CARGO_STAGE_0="${CARGO_STAGE_0}.exe" - RUSTC_STAGE_2="${RUSTC_STAGE_2}.exe" -fi - -# Make sure we have a temporary PGO work folder -PGO_TMP=/tmp/tmp-pgo -mkdir -p $PGO_TMP -rm -rf $PGO_TMP/* - -RUSTC_PERF=$PGO_TMP/rustc-perf - -# Compile several crates to gather execution PGO profiles. -# Arg0 => profiles (Debug, Opt) -# Arg1 => scenarios (Full, IncrFull, All) -# Arg2 => crates (syn, cargo, ...) -gather_profiles () { - cd $BUILD_ROOT - - # Compile libcore, both in opt-level=0 and opt-level=3 - RUSTC_BOOTSTRAP=1 $RUSTC_STAGE_2 \ - --edition=2021 --crate-type=lib $CHECKOUT/library/core/src/lib.rs \ - --out-dir $PGO_TMP - RUSTC_BOOTSTRAP=1 $RUSTC_STAGE_2 \ - --edition=2021 --crate-type=lib -Copt-level=3 $CHECKOUT/library/core/src/lib.rs \ - --out-dir $PGO_TMP - - cd $RUSTC_PERF - - # Run rustc-perf benchmarks - # Benchmark using profile_local with eprintln, which essentially just means - # don't actually benchmark -- just make sure we run rustc a bunch of times. - RUST_LOG=collector=debug \ - RUSTC=$RUSTC_STAGE_0 \ - RUSTC_BOOTSTRAP=1 \ - $CARGO_STAGE_0 run -p collector --bin collector -- \ - profile_local \ - eprintln \ - $RUSTC_STAGE_2 \ - --id Test \ - --profiles $1 \ - --cargo $CARGO_STAGE_0 \ - --scenarios $2 \ - --include $3 - - cd $BUILD_ROOT -} - -# This path has to be absolute -LLVM_PROFILE_DIRECTORY_ROOT=$PGO_TMP/llvm-pgo - -# We collect LLVM profiling information and rustc profiling information in -# separate phases. This increases build time -- though not by a huge amount -- -# but prevents any problems from arising due to different profiling runtimes -# being simultaneously linked in. -# LLVM IR PGO does not respect LLVM_PROFILE_FILE, so we have to set the profiling file -# path through our custom environment variable. We include the PID in the directory path -# to avoid updates to profile files being lost because of race conditions. -LLVM_PROFILE_DIR=${LLVM_PROFILE_DIRECTORY_ROOT}/prof-%p python3 $CHECKOUT/x.py build \ - --target=$PGO_HOST \ - --host=$PGO_HOST \ - --stage 2 library/std \ - --llvm-profile-generate - -# Compile rustc-perf: -# - get the expected commit source code: on linux, the Dockerfile downloads a source archive before -# running this script. On Windows, we do that here. -if isLinux; then - cp -r /tmp/rustc-perf $RUSTC_PERF - chown -R $(whoami): $RUSTC_PERF -else - # rustc-perf version from 2022-07-22 - PERF_COMMIT=3c253134664fdcba862c539d37f0de18557a9a4c - retry curl -LS -o $PGO_TMP/perf.zip \ - https://github.com/rust-lang/rustc-perf/archive/$PERF_COMMIT.zip && \ - cd $PGO_TMP && unzip -q perf.zip && \ - mv rustc-perf-$PERF_COMMIT $RUSTC_PERF && \ - rm perf.zip -fi - -# - build rustc-perf's collector ahead of time, which is needed to make sure the rustc-fake binary -# used by the collector is present. -cd $RUSTC_PERF - -RUSTC=$RUSTC_STAGE_0 \ -RUSTC_BOOTSTRAP=1 \ -$CARGO_STAGE_0 build -p collector - -# Here we're profiling LLVM, so we only care about `Debug` and `Opt`, because we want to stress -# codegen. We also profile some of the most prolific crates. -gather_profiles "Debug,Opt" "Full" \ - "syn-1.0.89,cargo-0.60.0,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18" - -LLVM_PROFILE_MERGED_FILE=$PGO_TMP/llvm-pgo.profdata - -# Merge the profile data we gathered for LLVM -# Note that this uses the profdata from the clang we used to build LLVM, -# which likely has a different version than our in-tree clang. -$DOWNLOADED_LLVM/bin/llvm-profdata merge -o ${LLVM_PROFILE_MERGED_FILE} ${LLVM_PROFILE_DIRECTORY_ROOT} - -echo "LLVM PGO statistics" -du -sh ${LLVM_PROFILE_MERGED_FILE} -du -sh ${LLVM_PROFILE_DIRECTORY_ROOT} -echo "Profile file count" -find ${LLVM_PROFILE_DIRECTORY_ROOT} -type f | wc -l - -# We don't need the individual .profraw files now that they have been merged into a final .profdata -rm -r $LLVM_PROFILE_DIRECTORY_ROOT - -# Rustbuild currently doesn't support rebuilding LLVM when PGO options -# change (or any other llvm-related options); so just clear out the relevant -# directories ourselves. -rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld - -# Okay, LLVM profiling is done, switch to rustc PGO. - -# The path has to be absolute -RUSTC_PROFILE_DIRECTORY_ROOT=$PGO_TMP/rustc-pgo - -python3 $CHECKOUT/x.py build --target=$PGO_HOST --host=$PGO_HOST \ - --stage 2 library/std \ - --rust-profile-generate=${RUSTC_PROFILE_DIRECTORY_ROOT} - -# Here we're profiling the `rustc` frontend, so we also include `Check`. -# The benchmark set includes various stress tests that put the frontend under pressure. -if isLinux; then - # The profile data is written into a single filepath that is being repeatedly merged when each - # rustc invocation ends. Empirically, this can result in some profiling data being lost. That's - # why we override the profile path to include the PID. This will produce many more profiling - # files, but the resulting profile will produce a slightly faster rustc binary. - LLVM_PROFILE_FILE=${RUSTC_PROFILE_DIRECTORY_ROOT}/default_%m_%p.profraw gather_profiles \ - "Check,Debug,Opt" "All" \ - "externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0" -else - # On windows, we don't do that yet (because it generates a lot of data, hitting disk space - # limits on the builder), and use the default profraw merging behavior. - gather_profiles \ - "Check,Debug,Opt" "All" \ - "externs,ctfe-stress-5,cargo-0.60.0,token-stream-stress,match-stress,tuple-stress,diesel-1.4.8,bitmaps-3.1.0" -fi - -RUSTC_PROFILE_MERGED_FILE=$PGO_TMP/rustc-pgo.profdata - -# Merge the profile data we gathered -$BUILD_ARTIFACTS/llvm/bin/llvm-profdata \ - merge -o ${RUSTC_PROFILE_MERGED_FILE} ${RUSTC_PROFILE_DIRECTORY_ROOT} - -echo "Rustc PGO statistics" -du -sh ${RUSTC_PROFILE_MERGED_FILE} -du -sh ${RUSTC_PROFILE_DIRECTORY_ROOT} -echo "Profile file count" -find ${RUSTC_PROFILE_DIRECTORY_ROOT} -type f | wc -l - -# We don't need the individual .profraw files now that they have been merged into a final .profdata -rm -r $RUSTC_PROFILE_DIRECTORY_ROOT - -# Rustbuild currently doesn't support rebuilding LLVM when PGO options -# change (or any other llvm-related options); so just clear out the relevant -# directories ourselves. -rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld - -if isLinux; then - # Gather BOLT profile (BOLT is currently only available on Linux) - python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \ - --stage 2 library/std \ - --llvm-profile-use=${LLVM_PROFILE_MERGED_FILE} \ - --llvm-bolt-profile-generate - - BOLT_PROFILE_MERGED_FILE=/tmp/bolt.profdata - - # Here we're profiling Bolt. - gather_profiles "Check,Debug,Opt" "Full" \ - "syn-1.0.89,serde-1.0.136,ripgrep-13.0.0,regex-1.5.5,clap-3.1.6,hyper-0.14.18" - - merge-fdata /tmp/prof.fdata* > ${BOLT_PROFILE_MERGED_FILE} - - echo "BOLT statistics" - du -sh /tmp/prof.fdata* - du -sh ${BOLT_PROFILE_MERGED_FILE} - echo "Profile file count" - find /tmp/prof.fdata* -type f | wc -l - - rm -r $BUILD_ARTIFACTS/llvm $BUILD_ARTIFACTS/lld - - # This produces the actual final set of artifacts, using both the LLVM and rustc - # collected profiling data. - $@ \ - --rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \ - --llvm-profile-use=${LLVM_PROFILE_MERGED_FILE} \ - --llvm-bolt-profile-use=${BOLT_PROFILE_MERGED_FILE} -else - $@ \ - --rust-profile-use=${RUSTC_PROFILE_MERGED_FILE} \ - --llvm-profile-use=${LLVM_PROFILE_MERGED_FILE} -fi - -echo "Rustc binary size" -ls -la ./build/$PGO_HOST/stage2/bin -ls -la ./build/$PGO_HOST/stage2/lib diff --git a/src/doc/book b/src/doc/book -Subproject d94e03a18a2590ed3f1c67b859cb11528d2a2d5 +Subproject 21a2ed14f4480dab62438dcc1130291bebc6537 diff --git a/src/doc/reference b/src/doc/reference -Subproject e5adb99c04817b7fbe08f4ffce5b36702667345 +Subproject a9afb04b47a84a6753e4dc657348c324c876102 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject efe23c4fe12e06351b8dc8c3d18312c76145510 +Subproject af0998b7473839ca75563ba3d3e7fd0160bef23 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 41a96ab971cb45e2a184df20619ad1829765c99 +Subproject b06dab84083390e0ee1e998f466545a8a1a76a9 diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 16057048259..9eafa27e2b7 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -13,6 +13,8 @@ for targets at each tier, see the [Target Tier Policy](target-tier-policy.md). Targets are identified by their "target triple" which is the string to inform the compiler what kind of output should be produced. +Component availability is tracked [here](https://rust-lang.github.io/rustup-components-history/). + ## Tier 1 with Host Tools Tier 1 targets can be thought of as "guaranteed to work". The Rust project @@ -216,7 +218,7 @@ target | std | host | notes [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | -[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.1 RTOS | +[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) @@ -308,7 +310,7 @@ target | std | host | notes `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 `x86_64-apple-tvos` | * | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator -[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ? | | x86 64-bit QNX Neutrino 7.1 RTOS | +[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support `x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 63dde2aaedd..4d97b8c6cb9 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -12,7 +12,6 @@ The [Fuchsia team]: - Tyler Mandry ([@tmandry](https://github.com/tmandry)) - Dan Johnson ([@computerdruid](https://github.com/computerdruid)) - David Koloski ([@djkoloski](https://github.com/djkoloski)) -- Andrew Pollack ([@andrewpollack](https://github.com/andrewpollack)) - Joseph Ryan ([@P1n3appl3](https://github.com/P1n3appl3)) As the team evolves over time, the specific members listed here may differ from @@ -717,7 +716,7 @@ run the full `tests/ui` test suite: --stage=2 \ test tests/ui \ --target x86_64-unknown-fuchsia \ - --run=always --jobs 1 \ + --run=always \ --test-args --target-rustcflags \ --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/sysroot/lib \ --test-args --target-rustcflags \ @@ -729,9 +728,6 @@ run the full `tests/ui` test suite: ) ``` -*Note: The test suite cannot be run in parallel at the moment, so `x.py` -must be run with `--jobs 1` to ensure only one test runs at a time.* - By default, `x.py` compiles test binaries with `panic=unwind`. If you built your Rust toolchain with `-Cpanic=abort`, you need to tell `x.py` to compile test binaries with `panic=abort` as well: @@ -908,7 +904,7 @@ through our `x.py` invocation. The full invocation is: --stage=2 \ test tests/${TEST} \ --target x86_64-unknown-fuchsia \ - --run=always --jobs 1 \ + --run=always \ --test-args --target-rustcflags \ --test-args -Lnative=${SDK_PATH}/arch/{x64|arm64}/sysroot/lib \ --test-args --target-rustcflags \ diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 37d0c31976c..38198fe6c3a 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -2,9 +2,9 @@ **Tier: 3** -[BlackBerry® QNX®][BlackBerry] Neutrino (nto) Real-time operating system. +[QNX®][BlackBerry] Neutrino (nto) Real-time operating system. The support has been implemented jointly by [Elektrobit Automotive GmbH][Elektrobit] -and [BlackBerry][BlackBerry]. +and [Blackberry QNX][BlackBerry]. [BlackBerry]: https://blackberry.qnx.com [Elektrobit]: https://www.elektrobit.com @@ -19,19 +19,24 @@ and [BlackBerry][BlackBerry]. Currently, only cross-compilation for QNX Neutrino on AArch64 and x86_64 are supported (little endian). Adding other architectures that are supported by QNX Neutrino is possible. -The standard library does not yet support QNX Neutrino. Therefore, only `no_std` code can -be compiled. +The standard library, including `core` and `alloc` (with default allocator) are supported. -`core` and `alloc` (with default allocator) are supported. +For building or using the Rust toolchain for QNX Neutrino, the +[QNX Software Development Platform (SDP)](https://blackberry.qnx.com/en/products/foundation-software/qnx-software-development-platform) +must be installed and initialized. +Initialization is usually done by sourcing `qnxsdp-env.sh` (this will be installed as part of the SDP, see also installation instruction provided with the SDP). +Afterwards [`qcc`](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.utilities/topic/q/qcc.html) (QNX C/C++ compiler) +should be available (in the `$PATH` variable). +`qcc` will be called e.g. for linking executables. -Applications must link against `libc.so` (see example). This is required because applications -always link against the `crt` library and `crt` depends on `libc.so`. - -The correct version of `qcc` must be available by setting the `$PATH` variable (e.g. by sourcing `qnxsdp-env.sh` of the -QNX Neutrino toolchain). +When linking `no_std` applications, they must link against `libc.so` (see example). This is +required because applications always link against the `crt` library and `crt` depends on `libc.so`. +This is done automatically when using the standard library. ### Small example application +Small `no_std` example is shown below. Applications using the standard library work as well. + ```rust,ignore (platform-specific) #![no_std] #![no_main] @@ -89,30 +94,150 @@ changelog-seen = 2 2. Compile the Rust toolchain for an `x86_64-unknown-linux-gnu` host (for both `aarch64` and `x86_64` targets) -Run the following: +Compiling the Rust toolchain requires the same environment variables used for compiling C binaries. +Refer to the [QNX developer manual](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.prog/topic/devel_OS_version.html). + +To compile for QNX Neutrino (aarch64 and x86_64) and Linux (x86_64): ```bash -env \ - CC_aarch64-unknown-nto-qnx710="qcc" \ - CFLAGS_aarch64-unknown-nto-qnx710="-Vgcc_ntoaarch64le_cxx" \ - CXX_aarch64-unknown-nto-qnx710="qcc" \ - AR_aarch64_unknown_nto_qnx710="ntoaarch64-ar" \ - CC_x86_64-pc-nto-qnx710="qcc" \ - CFLAGS_x86_64-pc-nto-qnx710="-Vgcc_ntox86_64_cxx" \ - CXX_x86_64-pc-nto-qnx710="qcc" \ - AR_x86_64_pc_nto_qnx710="ntox86_64-ar" \ - ./x.py build --target aarch64-unknown-nto-qnx710 --target x86_64-pc-nto-qnx710 --target x86_64-unknown-linux-gnu rustc library/core library/alloc/ +export build_env=' + CC_aarch64-unknown-nto-qnx710=qcc + CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx + CXX_aarch64-unknown-nto-qnx710=qcc + AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar + CC_x86_64-pc-nto-qnx710=qcc + CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx + CXX_x86_64-pc-nto-qnx710=qcc + AR_x86_64_pc_nto_qnx710=ntox86_64-ar' + +env $build_env \ + ./x.py build \ + --target aarch64-unknown-nto-qnx710 \ + --target x86_64-pc-nto-qnx710 \ + --target x86_64-unknown-linux-gnu \ + rustc library/core library/alloc ``` +## Running the Rust test suite + +The test suites of the Rust compiler and standard library can be executed much like other Rust targets. +The environment for testing should match the one used during compiler compilation (refer to `build_env` and `qcc`/`PATH` above) with the +addition of the TEST_DEVICE_ADDR environment variable. +The TEST_DEVICE_ADDR variable controls the remote runner and should point to the target, despite localhost being shown in the following example. +Note that some tests are failing which is why they are currently excluded by the target maintainers which can be seen in the following example. + +To run all tests on a x86_64 QNX Neutrino target: + +```bash +export TEST_DEVICE_ADDR="localhost:12345" # must address the test target, can be a SSH tunnel +export build_env=' + CC_aarch64-unknown-nto-qnx710=qcc + CFLAGS_aarch64-unknown-nto-qnx710=-Vgcc_ntoaarch64le_cxx + CXX_aarch64-unknown-nto-qnx710=qcc + AR_aarch64_unknown_nto_qnx710=ntoaarch64-ar + CC_x86_64-pc-nto-qnx710=qcc + CFLAGS_x86_64-pc-nto-qnx710=-Vgcc_ntox86_64_cxx + CXX_x86_64-pc-nto-qnx710=qcc + AR_x86_64_pc_nto_qnx710=ntox86_64-ar' + +# Disable tests that only work on the host or don't make sense for this target. +# See also: +# - src/ci/docker/host-x86_64/i686-gnu/Dockerfile +# - https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Running.20tests.20on.20remote.20target +# - .github/workflows/ci.yml +export exclude_tests=' + --exclude src/bootstrap + --exclude src/tools/error_index_generator + --exclude src/tools/linkchecker + --exclude tests/ui-fulldeps + --exclude rustc + --exclude rustdoc + --exclude tests/run-make-fulldeps' + +env $build_env \ + ./x.py test -j 1 \ + $exclude_tests \ + --stage 1 \ + --target x86_64-pc-nto-qnx710 +``` + +Currently, only one thread can be used when testing due to limitations in `libc::fork` and `libc::posix_spawnp`. +See [fork documentation](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html) +(error section) for more information. +This can be achieved by using the `-j 1` parameter in the `x.py` call. +This issue is being researched and we will try to allow parallelism in the future. + ## Building Rust programs -Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you must either build Rust with the target enabled (see "Building the target" above), or build your own copy of `core` by using -`build-std` or similar. +Rust does not yet ship pre-compiled artifacts for this target. +To compile for this target, you must either 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 -Compiled executables can directly be run on QNX Neutrino. +Compiled executables can run directly on QNX Neutrino. + +### Rust std library test suite + +The target needs sufficient resources to execute all tests. The commands below assume that a QEMU image +is used. + +* Ensure that the temporary directory used by `remote-test-server` has enough free space and inodes. + 5GB of free space and 40000 inodes are known to be sufficient (the test will create more than 32k files). + To create a QEMU image in an empty directory, run this command inside the directory: + + ```bash + mkqnximage --type=qemu --ssh-ident=$HOME/.ssh/id_ed25519.pub --data-size=5000 --data-inodes=40000 + ``` + + `/data` should have enough free resources. + Set the `TMPDIR` environment variable accordingly when running `remote-test-server`, e.g.: + ```bash + TMPDIR=/data/tmp/rust remote-test-server --bind 0.0.0.0:12345 + ``` + +* Ensure the TCP stack can handle enough parallel connections (default is 200, should be 300 or higher). + After creating an image (see above), edit the file `output/build/startup.sh`: + 1. Search for `io-pkt-v6-hc` + 2. Add the parameter `-ptcpip threads_max=300`, e.g.: + ```text + io-pkt-v6-hc -U 33:33 -d e1000 -ptcpip threads_max=300 + ``` + 3. Update the image by running `mkqnximage` again with the same parameters as above for creating it. + +* Running and stopping the virtual machine + + To start the virtual machine, run inside the directory of the VM: + + ```bash + mkqnximage --run=-h + ``` + + To stop the virtual machine, run inside the directory of the VM: + + ```bash + mkqnximage --stop + ``` + +* Ensure local networking + + Ensure that 'localhost' is getting resolved to 127.0.0.1. If you can't ping the localhost, some tests may fail. + Ensure it's appended to /etc/hosts (if first `ping` command fails). + Commands have to be executed inside the virtual machine! + + ```bash + $ ping localhost + ping: Cannot resolve "localhost" (Host name lookup failure) + + $ echo "127.0.0.1 localhost" >> /etc/hosts + + $ ping localhost + PING localhost (127.0.0.1): 56 data bytes + 64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=1 ms + ``` ## Cross-compilation toolchains and C code -Compiling C code requires the same environment variables to be set as compiling the Rust toolchain (see above), to ensure `qcc` is used with proper arguments. To ensure compatibility, do not specify any further arguments that for example change calling conventions or memory layout. +Compiling C code requires the same environment variables to be set as compiling the Rust toolchain (see above), +to ensure `qcc` is used with proper arguments. +To ensure compatibility, do not specify any further arguments that for example change calling conventions or memory layout. diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index d666d54b315..28a004a9253 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -84,6 +84,9 @@ When typing in the search bar, you can prefix your search term with a type followed by a colon (such as `mod:`) to restrict the results to just that kind of item. (The available items are listed in the help popup.) +Searching for `println!` will search for a macro named `println`, just like +searching for `macro:println` does. + ### Changing displayed theme You can change the displayed theme by opening the settings menu (the gear diff --git a/src/doc/unstable-book/src/compiler-flags/export-executable-symbols.md b/src/doc/unstable-book/src/compiler-flags/export-executable-symbols.md new file mode 100644 index 00000000000..c7f10afaccc --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/export-executable-symbols.md @@ -0,0 +1,43 @@ +# `export-executable-symbols` + +The tracking issue for this feature is: [#84161](https://github.com/rust-lang/rust/issues/84161). + +------------------------ + +The `-Zexport-executable-symbols` compiler flag makes `rustc` export symbols from executables. The resulting binary is runnable, but can also be used as a dynamic library. This is useful for interoperating with programs written in other languages, in particular languages with a runtime like Java or Lua. + +For example on windows: +```rust +#[no_mangle] +fn my_function() -> usize { + return 42; +} + +fn main() { + println!("Hello, world!"); +} +``` + +A standard `cargo build` will produce a `.exe` without an export directory. When the `export-executable-symbols` flag is added + +```Bash +export RUSTFLAGS="-Zexport-executable-symbols" +cargo build +``` + +the binary has an export directory with the functions: + +```plain +The Export Tables (interpreted .edata section contents) + +... + +[Ordinal/Name Pointer] Table + [ 0] my_function + [ 1] main +``` +(the output of `objdump -x` on the binary) + +Please note that the `#[no_mangle]` attribute is required. Without it, the symbol is not exported. + +The equivalent of this flag in C and C++ compilers is the `__declspec(dllexport)` annotation or the `-rdynamic` linker flag. diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 8a73d25d3f0..9cf84acc79f 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -769,8 +769,8 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) { Ok(p) => p, Err(_) => { - debug!("Cannot build a parser to check mod attr so skipping..."); - return true; + // If there is an unclosed delimiter, an error will be returned by the tokentrees. + return false; } }; // If a parsing error happened, it's very likely that the attribute is incomplete. @@ -778,15 +778,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { e.cancel(); return false; } - // We now check if there is an unclosed delimiter for the attribute. To do so, we look at - // the `unclosed_delims` and see if the opening square bracket was closed. - parser - .unclosed_delims() - .get(0) - .map(|unclosed| { - unclosed.unclosed_span.map(|s| s.lo()).unwrap_or(BytePos(0)) != BytePos(2) - }) - .unwrap_or(true) + true }) }) .unwrap_or(false) diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index fcd925bb358..1a34530c2d1 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -90,7 +90,6 @@ module.exports = { "no-return-assign": "error", "no-script-url": "error", "no-sequences": "error", - "no-throw-literal": "error", "no-div-regex": "error", } }; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index d18b56eb19c..95528e70e35 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1260,6 +1260,11 @@ a.tooltip:hover::after { color: var(--search-tab-title-count-color); } +#search .error code { + border-radius: 3px; + background-color: var(--search-error-code-background-color); +} + #src-sidebar-toggle { position: sticky; top: 0; diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 472a725f053..90cf689ad33 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -43,6 +43,7 @@ Original by Dempfi (https://github.com/dempfi/ayu) --search-result-link-focus-background-color: #3c3c3c; --search-result-border-color: #aaa3; --search-color: #fff; + --search-error-code-background-color: #4f4c4c; --search-results-alias-color: #c5c5c5; --search-results-grey-color: #999; --search-tab-title-count-color: #888; diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index 5612bde96a8..e8cd0693139 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -38,6 +38,7 @@ --search-result-link-focus-background-color: #616161; --search-result-border-color: #aaa3; --search-color: #111; + --search-error-code-background-color: #484848; --search-results-alias-color: #fff; --search-results-grey-color: #ccc; --search-tab-title-count-color: #888; diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 34b35c405a8..5e3f14e483f 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -38,6 +38,7 @@ --search-result-link-focus-background-color: #ccc; --search-result-border-color: #aaa3; --search-color: #000; + --search-error-code-background-color: #d0cccc; --search-results-alias-color: #000; --search-results-grey-color: #999; --search-tab-title-count-color: #888; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index b3fc889431b..b98bced4126 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -144,7 +144,7 @@ function initSearch(rawSearchIndex) { function itemTypeFromName(typename) { const index = itemTypes.findIndex(i => i === typename); if (index < 0) { - throw new Error("Unknown type filter `" + typename + "`"); + throw ["Unknown type filter ", typename]; } return index; } @@ -164,21 +164,21 @@ function initSearch(rawSearchIndex) { */ function getStringElem(query, parserState, isInGenerics) { if (isInGenerics) { - throw new Error("`\"` cannot be used in generics"); + throw ["Unexpected ", "\"", " in generics"]; } else if (query.literalSearch) { - throw new Error("Cannot have more than one literal search element"); + throw ["Cannot have more than one literal search element"]; } else if (parserState.totalElems - parserState.genericsElems > 0) { - throw new Error("Cannot use literal search when there is more than one element"); + throw ["Cannot use literal search when there is more than one element"]; } parserState.pos += 1; const start = parserState.pos; const end = getIdentEndPosition(parserState); if (parserState.pos >= parserState.length) { - throw new Error("Unclosed `\"`"); + throw ["Unclosed ", "\""]; } else if (parserState.userQuery[end] !== "\"") { - throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`); + throw ["Unexpected ", parserState.userQuery[end], " in a string element"]; } else if (start === end) { - throw new Error("Cannot have empty string element"); + throw ["Cannot have empty string element"]; } // To skip the quote at the end. parserState.pos += 1; @@ -257,7 +257,7 @@ function initSearch(rawSearchIndex) { return; } if (query.literalSearch && parserState.totalElems - parserState.genericsElems > 0) { - throw new Error("You cannot have more than one element if you use quotes"); + throw ["You cannot have more than one element if you use quotes"]; } const pathSegments = name.split("::"); if (pathSegments.length > 1) { @@ -266,17 +266,17 @@ function initSearch(rawSearchIndex) { if (pathSegment.length === 0) { if (i === 0) { - throw new Error("Paths cannot start with `::`"); + throw ["Paths cannot start with ", "::"]; } else if (i + 1 === len) { - throw new Error("Paths cannot end with `::`"); + throw ["Paths cannot end with ", "::"]; } - throw new Error("Unexpected `::::`"); + throw ["Unexpected ", "::::"]; } } } // In case we only have something like `<p>`, there is no name. if (pathSegments.length === 0 || (pathSegments.length === 1 && pathSegments[0] === "")) { - throw new Error("Found generics without a path"); + throw ["Found generics without a path"]; } parserState.totalElems += 1; if (isInGenerics) { @@ -300,22 +300,23 @@ function initSearch(rawSearchIndex) { * @return {integer} */ function getIdentEndPosition(parserState) { + const start = parserState.pos; let end = parserState.pos; - let foundExclamation = false; + let foundExclamation = -1; while (parserState.pos < parserState.length) { const c = parserState.userQuery[parserState.pos]; if (!isIdentCharacter(c)) { if (c === "!") { - if (foundExclamation) { - throw new Error("Cannot have more than one `!` in an ident"); + if (foundExclamation !== -1) { + throw ["Cannot have more than one ", "!", " in an ident"]; } else if (parserState.pos + 1 < parserState.length && isIdentCharacter(parserState.userQuery[parserState.pos + 1]) ) { - throw new Error("`!` can only be at the end of an ident"); + throw ["Unexpected ", "!", ": it can only be at the end of an ident"]; } - foundExclamation = true; + foundExclamation = parserState.pos; } else if (isErrorCharacter(c)) { - throw new Error(`Unexpected \`${c}\``); + throw ["Unexpected ", c]; } else if ( isStopCharacter(c) || isSpecialStartCharacter(c) || @@ -326,16 +327,40 @@ function initSearch(rawSearchIndex) { if (!isPathStart(parserState)) { break; } + if (foundExclamation !== -1) { + if (start <= (end - 2)) { + throw ["Cannot have associated items in macros"]; + } else { + // if start == end - 1, we got the never type + // while the never type has no associated macros, we still + // can parse a path like that + foundExclamation = -1; + } + } // Skip current ":". parserState.pos += 1; - foundExclamation = false; } else { - throw new Error(`Unexpected \`${c}\``); + throw ["Unexpected ", c]; } } parserState.pos += 1; end = parserState.pos; } + // if start == end - 1, we got the never type + if (foundExclamation !== -1 && start <= (end - 2)) { + if (parserState.typeFilter === null) { + parserState.typeFilter = "macro"; + } else if (parserState.typeFilter !== "macro") { + throw [ + "Invalid search type: macro ", + "!", + " and ", + parserState.typeFilter, + " both specified", + ]; + } + end = foundExclamation; + } return end; } @@ -362,9 +387,9 @@ function initSearch(rawSearchIndex) { parserState.userQuery[parserState.pos] === "<" ) { if (isInGenerics) { - throw new Error("Unexpected `<` after `<`"); + throw ["Unexpected ", "<", " after ", "<"]; } else if (start >= end) { - throw new Error("Found generics without a path"); + throw ["Found generics without a path"]; } parserState.pos += 1; getItemsBefore(query, parserState, generics, ">"); @@ -408,24 +433,51 @@ function initSearch(rawSearchIndex) { foundStopChar = true; continue; } else if (c === ":" && isPathStart(parserState)) { - throw new Error("Unexpected `::`: paths cannot start with `::`"); + throw ["Unexpected ", "::", ": paths cannot start with ", "::"]; } else if (c === ":" || isEndCharacter(c)) { let extra = ""; if (endChar === ">") { - extra = "`<`"; + extra = "<"; } else if (endChar === "") { - extra = "`->`"; + extra = "->"; + } else { + extra = endChar; } - throw new Error("Unexpected `" + c + "` after " + extra); + throw ["Unexpected ", c, " after ", extra]; } if (!foundStopChar) { if (endChar !== "") { - throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``); + throw [ + "Expected ", + ",", // comma + ", ", + " ", // whitespace + " or ", + endChar, + ", found ", + c, + ]; } - throw new Error(`Expected \`,\` or \` \`, found \`${c}\``); + throw [ + "Expected ", + ",", // comma + " or ", + " ", // whitespace + ", found ", + c, + ]; } const posBefore = parserState.pos; getNextElem(query, parserState, elems, endChar === ">"); + if (endChar !== "") { + if (parserState.pos >= parserState.length) { + throw ["Unclosed ", "<"]; + } + const c2 = parserState.userQuery[parserState.pos]; + if (!isSeparatorCharacter(c2) && c2 !== endChar) { + throw ["Expected ", endChar, ", found ", c2]; + } + } // This case can be encountered if `getNextElem` encountered a "stop character" right // from the start. For example if you have `,,` or `<>`. In this case, we simply move up // the current position to continue the parsing. @@ -434,7 +486,10 @@ function initSearch(rawSearchIndex) { } foundStopChar = false; } - // We are either at the end of the string or on the `endChar`` character, let's move forward + if (parserState.pos >= parserState.length && endChar !== "") { + throw ["Unclosed ", "<"]; + } + // We are either at the end of the string or on the `endChar` character, let's move forward // in any case. parserState.pos += 1; } @@ -450,7 +505,7 @@ function initSearch(rawSearchIndex) { for (let pos = 0; pos < parserState.pos; ++pos) { if (!isIdentCharacter(query[pos]) && !isWhitespaceCharacter(query[pos])) { - throw new Error(`Unexpected \`${query[pos]}\` in type filter`); + throw ["Unexpected ", query[pos], " in type filter"]; } } } @@ -476,19 +531,19 @@ function initSearch(rawSearchIndex) { if (isReturnArrow(parserState)) { break; } - throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`); + throw ["Unexpected ", c, " (did you mean ", "->", "?)"]; } - throw new Error(`Unexpected \`${c}\``); + throw ["Unexpected ", c]; } else if (c === ":" && !isPathStart(parserState)) { if (parserState.typeFilter !== null) { - throw new Error("Unexpected `:`"); + throw ["Unexpected ", ":"]; } if (query.elems.length === 0) { - throw new Error("Expected type filter before `:`"); + throw ["Expected type filter before ", ":"]; } else if (query.elems.length !== 1 || parserState.totalElems !== 1) { - throw new Error("Unexpected `:`"); + throw ["Unexpected ", ":"]; } else if (query.literalSearch) { - throw new Error("You cannot use quotes on type filter"); + throw ["You cannot use quotes on type filter"]; } checkExtraTypeFilterCharacters(parserState); // The type filter doesn't count as an element since it's a modifier. @@ -501,9 +556,29 @@ function initSearch(rawSearchIndex) { } if (!foundStopChar) { if (parserState.typeFilter !== null) { - throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``); + throw [ + "Expected ", + ",", // comma + ", ", + " ", // whitespace + " or ", + "->", // arrow + ", found ", + c, + ]; } - throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``); + throw [ + "Expected ", + ",", // comma + ", ", + " ", // whitespace + ", ", + ":", // colon + " or ", + "->", // arrow + ", found ", + c, + ]; } const before = query.elems.length; getNextElem(query, parserState, query.elems, false); @@ -520,7 +595,7 @@ function initSearch(rawSearchIndex) { getItemsBefore(query, parserState, query.returned, ""); // Nothing can come afterward! if (query.returned.length === 0) { - throw new Error("Expected at least one item after `->`"); + throw ["Expected at least one item after ", "->"]; } break; } else { @@ -589,8 +664,8 @@ function initSearch(rawSearchIndex) { * * The supported syntax by this parser is as follow: * - * ident = *(ALPHA / DIGIT / "_") [!] - * path = ident *(DOUBLE-COLON ident) + * ident = *(ALPHA / DIGIT / "_") + * path = ident *(DOUBLE-COLON ident) [!] * arg = path [generics] * arg-without-generic = path * type-sep = COMMA/WS *(COMMA/WS) @@ -674,7 +749,7 @@ function initSearch(rawSearchIndex) { } } catch (err) { query = newParsedQuery(userQuery); - query.error = err.message; + query.error = err; query.typeFilter = -1; return query; } @@ -1740,7 +1815,16 @@ function initSearch(rawSearchIndex) { let output = `<h1 class="search-results-title">Results${crates}</h1>`; if (results.query.error !== null) { - output += `<h3>Query parser error: "${results.query.error}".</h3>`; + const error = results.query.error; + error.forEach((value, index) => { + value = value.split("<").join("<").split(">").join(">"); + if (index % 2 !== 0) { + error[index] = `<code>${value}</code>`; + } else { + error[index] = value; + } + }); + output += `<h3 class="error">Query parser error: "${error.join("")}".</h3>`; output += "<div id=\"search-tabs\">" + makeTabHeader(0, "In Names", ret_others[1]) + "</div>"; diff --git a/src/llvm-project b/src/llvm-project -Subproject 477e7285b12f876ad105188cfcfc8adda7dc29a +Subproject fd949f3034f8a422ecfffa889c2823485dde4bd diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 33f2b5c1de9..995dd2f04b1 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -306,7 +306,7 @@ The maximum number of lines a function or method can have ### array-size-threshold The maximum allowed size for arrays on the stack -**Default Value:** `512000` (`u128`) +**Default Value:** `512000` (`u64`) * [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) * [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 145cf524652..c626e0bd998 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -777,7 +777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); store.register_late_pass(|_| Box::new(exit::Exit)); store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); - let array_size_threshold = conf.array_size_threshold; + let array_size_threshold = u128::from(conf.array_size_threshold); store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 5f74de5a288..1c7f3e96db8 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -334,7 +334,7 @@ define_Conf! { /// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. /// /// The maximum allowed size for arrays on the stack - (array_size_threshold: u128 = 512_000), + (array_size_threshold: u64 = 512_000), /// Lint: VEC_BOX. /// /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 4604ae5c2c7..50bef370930 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -287,15 +287,12 @@ impl<'a> VecArgs<'a> { Some(VecArgs::Repeat(&args[0], &args[1])) } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 { // `vec![a, b, c]` case - if_chain! { - if let hir::ExprKind::Box(boxed) = args[0].kind; - if let hir::ExprKind::Array(args) = boxed.kind; - then { - return Some(VecArgs::Vec(args)); - } + if let hir::ExprKind::Call(_, [arg]) = &args[0].kind + && let hir::ExprKind::Array(args) = arg.kind { + Some(VecArgs::Vec(args)) + } else { + None } - - None } else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() { Some(VecArgs::Vec(&[])) } else { diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.rs b/src/tools/clippy/tests/ui/crashes/ice-10044.rs deleted file mode 100644 index 65f38fe7118..00000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-10044.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - [0; usize::MAX]; -} diff --git a/src/tools/clippy/tests/ui/crashes/ice-10044.stderr b/src/tools/clippy/tests/ui/crashes/ice-10044.stderr deleted file mode 100644 index 731f8265ad6..00000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-10044.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: statement with no effect - --> $DIR/ice-10044.rs:2:5 - | -LL | [0; usize::MAX]; - | ^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::no-effect` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.rs b/src/tools/clippy/tests/ui/large_stack_arrays.rs index 6790765f803..99787ffd3d3 100644 --- a/src/tools/clippy/tests/ui/large_stack_arrays.rs +++ b/src/tools/clippy/tests/ui/large_stack_arrays.rs @@ -24,6 +24,7 @@ fn main() { [S { data: [0; 32] }; 5000], [Some(""); 20_000_000], [E::T(0); 5000], + [0u8; usize::MAX], ); let good = ( diff --git a/src/tools/clippy/tests/ui/large_stack_arrays.stderr b/src/tools/clippy/tests/ui/large_stack_arrays.stderr index c7bf941ad00..24e90094982 100644 --- a/src/tools/clippy/tests/ui/large_stack_arrays.stderr +++ b/src/tools/clippy/tests/ui/large_stack_arrays.stderr @@ -31,5 +31,13 @@ LL | [E::T(0); 5000], | = help: consider allocating on the heap with `vec![E::T(0); 5000].into_boxed_slice()` -error: aborting due to 4 previous errors +error: allocating a local array larger than 512000 bytes + --> $DIR/large_stack_arrays.rs:27:9 + | +LL | [0u8; usize::MAX], + | ^^^^^^^^^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![0u8; usize::MAX].into_boxed_slice()` + +error: aborting due to 5 previous errors diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 7824ef81d7a..41c23ff86b2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1432,12 +1432,13 @@ impl<'test> TestCx<'test> { expect_help: bool, expect_note: bool, ) -> bool { - match actual_error.kind { - Some(ErrorKind::Help) => expect_help, - Some(ErrorKind::Note) => expect_note, - Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true, - Some(ErrorKind::Suggestion) | None => false, - } + !actual_error.msg.is_empty() + && match actual_error.kind { + Some(ErrorKind::Help) => expect_help, + Some(ErrorKind::Note) => expect_note, + Some(ErrorKind::Error) | Some(ErrorKind::Warning) => true, + Some(ErrorKind::Suggestion) | None => false, + } } fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit { diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 8bbf9f87b43..969c81f7e32 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -777,10 +777,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { type Provenance = Provenance; type ProvenanceExtra = ProvenanceExtra; + type Bytes = Box<[u8]>; type MemoryMap = MonoHashMap< AllocId, - (MemoryKind<MiriMemoryKind>, Allocation<Provenance, Self::AllocExtra>), + (MemoryKind<MiriMemoryKind>, Allocation<Provenance, Self::AllocExtra, Self::Bytes>), >; const GLOBAL_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Global); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 3da4fed33e1..ea5780f66d7 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -138,8 +138,20 @@ function valueCheck(fullPath, expected, result, error_text, queryName) { error_text.push('==> Unknown key "' + key + '"'); break; } + let result_v = result[key]; + if (result_v !== null && key === "error") { + result_v.forEach((value, index) => { + value = value.split(" ").join(" "); + if (index % 2 === 1) { + result_v[index] = "`" + value + "`"; + } else { + result_v[index] = value; + } + }); + result_v = result_v.join(""); + } const obj_path = fullPath + (fullPath.length > 0 ? '.' : '') + key; - valueCheck(obj_path, expected[key], result[key], error_text, queryName); + valueCheck(obj_path, expected[key], result_v, error_text, queryName); } } else { expectedValue = JSON.stringify(expected); diff --git a/tests/codegen/array-equality.rs b/tests/codegen/array-equality.rs index cd5e82a9205..abfe295f8b6 100644 --- a/tests/codegen/array-equality.rs +++ b/tests/codegen/array-equality.rs @@ -1,4 +1,4 @@ -// compile-flags: -O +// compile-flags: -O -Z merge-functions=disabled // only-x86_64 #![crate_type = "lib"] @@ -43,6 +43,15 @@ pub fn array_eq_long(a: &[u16; 1234], b: &[u16; 1234]) -> bool { a == b } +// CHECK-LABEL: @array_char_eq +#[no_mangle] +pub fn array_char_eq(a: [char; 2], b: [char; 2]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i64 %0, %1 + // CHECK-NEXT: ret i1 %[[EQ]] + a == b +} + // CHECK-LABEL: @array_eq_zero_short(i48 #[no_mangle] pub fn array_eq_zero_short(x: [u16; 3]) -> bool { @@ -52,6 +61,25 @@ pub fn array_eq_zero_short(x: [u16; 3]) -> bool { x == [0; 3] } +// CHECK-LABEL: @array_eq_none_short(i40 +#[no_mangle] +pub fn array_eq_none_short(x: [Option<std::num::NonZeroU8>; 5]) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: %[[EQ:.+]] = icmp eq i40 %0, 0 + // CHECK-NEXT: ret i1 %[[EQ]] + x == [None; 5] +} + +// CHECK-LABEL: @array_eq_zero_nested( +#[no_mangle] +pub fn array_eq_zero_nested(x: [[u8; 3]; 3]) -> bool { + // CHECK: %[[VAL:.+]] = load i72 + // CHECK-SAME: align 1 + // CHECK: %[[EQ:.+]] = icmp eq i72 %[[VAL]], 0 + // CHECK: ret i1 %[[EQ]] + x == [[0; 3]; 3] +} + // CHECK-LABEL: @array_eq_zero_mid( #[no_mangle] pub fn array_eq_zero_mid(x: [u16; 8]) -> bool { diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs index d0418d11142..dd22fd0f7e8 100644 --- a/tests/codegen/consts.rs +++ b/tests/codegen/consts.rs @@ -9,11 +9,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @alloc12 = {{.*}}, align 2 +// CHECK: @alloc_76bfe2f13a3e3b01074971d122eac57e = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@alloc[0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs new file mode 100644 index 00000000000..d5077dbf6cc --- /dev/null +++ b/tests/codegen/option-as-slice.rs @@ -0,0 +1,28 @@ +// compile-flags: -O +// only-x86_64 + +#![crate_type = "lib"] +#![feature(option_as_slice)] + +extern crate core; + +use core::num::NonZeroU64; +use core::option::Option; + +// CHECK-LABEL: @u64_opt_as_slice +#[no_mangle] +pub fn u64_opt_as_slice(o: &Option<u64>) -> &[u64] { + // CHECK: start: + // CHECK-NOT: select + // CHECK: ret + o.as_slice() +} + +// CHECK-LABEL: @nonzero_u64_opt_as_slice +#[no_mangle] +pub fn nonzero_u64_opt_as_slice(o: &Option<NonZeroU64>) -> &[NonZeroU64] { + // CHECK: start: + // CHECK-NOT: select + // CHECK: ret + o.as_slice() +} diff --git a/tests/codegen/remap_path_prefix/main.rs b/tests/codegen/remap_path_prefix/main.rs index 78ebbccfce1..6c0cd6997d0 100644 --- a/tests/codegen/remap_path_prefix/main.rs +++ b/tests/codegen/remap_path_prefix/main.rs @@ -12,7 +12,7 @@ mod aux_mod; include!("aux_mod.rs"); // Here we check that the expansion of the file!() macro is mapped. -// CHECK: @alloc2 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }> +// CHECK: @alloc_92a59126a55aa3c0019b6c8a007fe001 = private unnamed_addr constant <{ [34 x i8] }> <{ [34 x i8] c"/the/src/remap_path_prefix/main.rs" }> pub static FILE_PATH: &'static str = file!(); fn main() { diff --git a/tests/codegen/slice-ref-equality.rs b/tests/codegen/slice-ref-equality.rs index 47fde12bf30..8f0adab35e7 100644 --- a/tests/codegen/slice-ref-equality.rs +++ b/tests/codegen/slice-ref-equality.rs @@ -1,7 +1,10 @@ -// compile-flags: -C opt-level=3 -Zmerge-functions=disabled +// compile-flags: -O -Zmerge-functions=disabled +// ignore-debug (the extra assertions get in the way) #![crate_type = "lib"] +use std::num::{NonZeroI16, NonZeroU32}; + // #71602 reported a simple array comparison just generating a loop. // This was originally fixed by ensuring it generates a single bcmp, // but we now generate it as a load+icmp instead. `is_zero_slice` was @@ -36,3 +39,54 @@ pub fn is_zero_array(data: &[u8; 4]) -> bool { // CHECK-NEXT: ret i1 %[[EQ]] *data == [0; 4] } + +// The following test the extra specializations to make sure that slice +// equality for non-byte types also just emit a `bcmp`, not a loop. + +// CHECK-LABEL: @eq_slice_of_nested_u8( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_nested_u8(x: &[[u8; 3]], y: &[[u8; 3]]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = mul nsw [[USIZE]] %1, 3 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i8\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_i32( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_i32(x: &[i32], y: &[i32]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_nonzero( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_nonzero(x: &[NonZeroU32], y: &[NonZeroU32]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 2 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i32\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} + +// CHECK-LABEL: @eq_slice_of_option_of_nonzero( +// CHECK-SAME: [[USIZE:i16|i32|i64]] noundef %1 +// CHECK-SAME: [[USIZE]] noundef %3 +#[no_mangle] +fn eq_slice_of_option_of_nonzero(x: &[Option<NonZeroI16>], y: &[Option<NonZeroI16>]) -> bool { + // CHECK: icmp eq [[USIZE]] %1, %3 + // CHECK: %[[BYTES:.+]] = shl nsw [[USIZE]] %1, 1 + // CHECK: tail call{{( noundef)?}} i32 @{{bcmp|memcmp}}({{i16\*|ptr}} + // CHECK-SAME: , [[USIZE]]{{( noundef)?}} %[[BYTES]]) + x == y +} diff --git a/tests/codegen/thread-local.rs b/tests/codegen/thread-local.rs index 0f1b29ca79b..aa7fab7fb17 100644 --- a/tests/codegen/thread-local.rs +++ b/tests/codegen/thread-local.rs @@ -4,6 +4,7 @@ // ignore-wasm globals are used instead of thread locals // ignore-emscripten globals are used instead of thread locals // ignore-android does not use #[thread_local] +// ignore-nto does not use #[thread_local] #![crate_type = "lib"] diff --git a/tests/debuginfo/captured-fields-1.rs b/tests/debuginfo/captured-fields-1.rs index afbf942d404..b71734c2354 100644 --- a/tests/debuginfo/captured-fields-1.rs +++ b/tests/debuginfo/captured-fields-1.rs @@ -1,5 +1,5 @@ // compile-flags:-g - +// edition:2021 // === GDB TESTS =================================================================================== // gdb-command:run @@ -44,7 +44,6 @@ // lldbg-check:(captured_fields_1::main::{closure_env#5}) $5 = { my_var = { my_field1 = 11 my_field2 = 22 } } // lldb-command:continue -#![feature(capture_disjoint_fields)] #![allow(unused)] struct MyStruct { diff --git a/tests/debuginfo/captured-fields-2.rs b/tests/debuginfo/captured-fields-2.rs index c872354a924..8d463fb2451 100644 --- a/tests/debuginfo/captured-fields-2.rs +++ b/tests/debuginfo/captured-fields-2.rs @@ -1,5 +1,5 @@ // compile-flags:-g - +// edition:2021 // === GDB TESTS =================================================================================== // gdb-command:run @@ -20,7 +20,6 @@ // lldbg-check:(unsigned int) $1 = 22 // lldb-command:continue -#![feature(capture_disjoint_fields)] #![allow(unused)] struct MyStruct { @@ -29,10 +28,7 @@ struct MyStruct { } fn main() { - let mut my_var = MyStruct { - my_field1: 11, - my_field2: 22, - }; + let mut my_var = MyStruct { my_field1: 11, my_field2: 22 }; let my_ref = &mut my_var; let test = || { diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff index c7978ac328f..e30a5e116ea 100644 --- a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff +++ b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff @@ -4,14 +4,14 @@ fn inlined_no_sanitize() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:37: +0:37 let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18 -+ scope 1 (inlined no_sanitize) { // at $DIR/inline_compatibility.rs:23:5: 23:18 ++ scope 1 (inlined no_sanitize) { // at $DIR/inline_compatibility.rs:24:5: 24:18 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18 - _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18 - // mir::Constant -- // + span: $DIR/inline_compatibility.rs:23:5: 23:16 +- // + span: $DIR/inline_compatibility.rs:24:5: 24:16 - // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff index 2fe277ae37b..c2b3c46a30c 100644 --- a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff +++ b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff @@ -4,14 +4,14 @@ fn inlined_target_feature() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:40: +0:40 let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21 -+ scope 1 (inlined target_feature) { // at $DIR/inline_compatibility.rs:12:5: 12:21 ++ scope 1 (inlined target_feature) { // at $DIR/inline_compatibility.rs:13:5: 13:21 + } bb0: { StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21 - _1 = target_feature() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21 - // mir::Constant -- // + span: $DIR/inline_compatibility.rs:12:5: 12:19 +- // + span: $DIR/inline_compatibility.rs:13:5: 13:19 - // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) } - } - diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff index 9803ca0f8a4..0ca5a5f70b7 100644 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff +++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff @@ -12,7 +12,7 @@ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:9: +1:10 _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:13: +1:52 // mir::Constant - // + span: $DIR/inline_compatibility.rs:41:13: 41:16 + // + span: $DIR/inline_compatibility.rs:42:13: 42:16 // + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(<ZST>) } } diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff index 356ab4b51c2..00d405c77f9 100644 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff +++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff @@ -9,7 +9,7 @@ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18 _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18 // mir::Constant - // + span: $DIR/inline_compatibility.rs:28:5: 28:16 + // + span: $DIR/inline_compatibility.rs:29:5: 29:16 // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) } } diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff index f0fee4ca98a..8b9c86f5515 100644 --- a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff +++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff @@ -9,7 +9,7 @@ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21 _1 = target_feature() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21 // mir::Constant - // + span: $DIR/inline_compatibility.rs:17:5: 17:19 + // + span: $DIR/inline_compatibility.rs:18:5: 18:19 // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) } } diff --git a/tests/mir-opt/inline/inline_compatibility.rs b/tests/mir-opt/inline/inline_compatibility.rs index ec6ce3d0258..30aff0a64ef 100644 --- a/tests/mir-opt/inline/inline_compatibility.rs +++ b/tests/mir-opt/inline/inline_compatibility.rs @@ -4,6 +4,7 @@ #![crate_type = "lib"] #![feature(no_sanitize)] +#![feature(target_feature_11)] #![feature(c_variadic)] // EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml new file mode 100644 index 00000000000..2a10a647b53 --- /dev/null +++ b/tests/rustdoc-gui/search-error.goml @@ -0,0 +1,39 @@ +// Checks that the crate search filtering is handled correctly and changes the results. +goto: "file://" + |DOC_PATH| + "/test_docs/index.html?search=sa'%3Bda'%3Bds" +show-text: true + +define-function: ( + "check-colors", + (theme, error_background), + block { + // Setting the theme. + local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} + // We reload the page so the local storage settings are being used. + reload: + + wait-for: "#search .error code" + assert-css: ("#search .error code", {"background-color": |error_background|}) + } +) + +call-function: ( + "check-colors", + { + "theme": "ayu", + "error_background": "rgb(79, 76, 76)", + }, +) +call-function: ( + "check-colors", + { + "theme": "dark", + "error_background": "rgb(72, 72, 72)", + }, +) +call-function: ( + "check-colors", + { + "theme": "light", + "error_background": "rgb(208, 204, 204)", + }, +) diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index dc42031e05f..98c6f27ca61 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -37,6 +37,9 @@ const QUERY = [ "mod : :", "a!a", "a!!", + "mod:a!", + "a!::a", + "a<", ]; const PARSED = [ @@ -65,7 +68,7 @@ const PARSED = [ returned: [], typeFilter: -1, userQuery: "a<\"p\">", - error: "`\"` cannot be used in generics", + error: "Unexpected `\"` in generics", }, { elems: [], @@ -371,7 +374,7 @@ const PARSED = [ returned: [], typeFilter: -1, userQuery: "a!a", - error: '`!` can only be at the end of an ident', + error: 'Unexpected `!`: it can only be at the end of an ident', }, { elems: [], @@ -382,4 +385,31 @@ const PARSED = [ userQuery: "a!!", error: 'Cannot have more than one `!` in an ident', }, + { + elems: [], + foundElems: 0, + original: "mod:a!", + returned: [], + typeFilter: -1, + userQuery: "mod:a!", + error: 'Invalid search type: macro `!` and `mod` both specified', + }, + { + elems: [], + foundElems: 0, + original: "a!::a", + returned: [], + typeFilter: -1, + userQuery: "a!::a", + error: 'Cannot have associated items in macros', + }, + { + elems: [], + foundElems: 0, + original: "a<", + returned: [], + typeFilter: -1, + userQuery: "a<", + error: "Unclosed `<`", + }, ]; diff --git a/tests/rustdoc-js-std/parser-filter.js b/tests/rustdoc-js-std/parser-filter.js index e5a87a415ac..01f65b478f8 100644 --- a/tests/rustdoc-js-std/parser-filter.js +++ b/tests/rustdoc-js-std/parser-filter.js @@ -1,4 +1,4 @@ -const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo']; +const QUERY = ['fn:foo', 'enum : foo', 'macro<f>:foo', 'macro!', 'macro:mac!', 'a::mac!']; const PARSED = [ { @@ -40,4 +40,49 @@ const PARSED = [ userQuery: "macro<f>:foo", error: "Unexpected `:`", }, + { + elems: [{ + name: "macro", + fullPath: ["macro"], + pathWithoutLast: [], + pathLast: "macro", + generics: [], + }], + foundElems: 1, + original: "macro!", + returned: [], + typeFilter: 14, + userQuery: "macro!", + error: null, + }, + { + elems: [{ + name: "mac", + fullPath: ["mac"], + pathWithoutLast: [], + pathLast: "mac", + generics: [], + }], + foundElems: 1, + original: "macro:mac!", + returned: [], + typeFilter: 14, + userQuery: "macro:mac!", + error: null, + }, + { + elems: [{ + name: "a::mac", + fullPath: ["a", "mac"], + pathWithoutLast: ["a"], + pathLast: "mac", + generics: [], + }], + foundElems: 1, + original: "a::mac!", + returned: [], + typeFilter: 14, + userQuery: "a::mac!", + error: null, + }, ]; diff --git a/tests/rustdoc-js-std/parser-ident.js b/tests/rustdoc-js-std/parser-ident.js index 4b5ab01ac76..6c17d00f16e 100644 --- a/tests/rustdoc-js-std/parser-ident.js +++ b/tests/rustdoc-js-std/parser-ident.js @@ -3,6 +3,7 @@ const QUERY = [ "!", "a!", "a!::b", + "!::b", "a!::b!", ]; @@ -47,47 +48,50 @@ const PARSED = [ }, { elems: [{ - name: "a!", - fullPath: ["a!"], + name: "a", + fullPath: ["a"], pathWithoutLast: [], - pathLast: "a!", + pathLast: "a", generics: [], }], foundElems: 1, original: "a!", returned: [], - typeFilter: -1, + typeFilter: 14, userQuery: "a!", error: null, }, { - elems: [{ - name: "a!::b", - fullPath: ["a!", "b"], - pathWithoutLast: ["a!"], - pathLast: "b", - generics: [], - }], - foundElems: 1, + elems: [], + foundElems: 0, original: "a!::b", returned: [], typeFilter: -1, userQuery: "a!::b", - error: null, + error: "Cannot have associated items in macros", }, { elems: [{ - name: "a!::b!", - fullPath: ["a!", "b!"], - pathWithoutLast: ["a!"], - pathLast: "b!", + name: "!::b", + fullPath: ["!", "b"], + pathWithoutLast: ["!"], + pathLast: "b", generics: [], }], foundElems: 1, + original: "!::b", + returned: [], + typeFilter: -1, + userQuery: "!::b", + error: null, + }, + { + elems: [], + foundElems: 0, original: "a!::b!", returned: [], typeFilter: -1, userQuery: "a!::b!", - error: null, + error: "Cannot have associated items in macros", }, ]; diff --git a/tests/rustdoc-js/macro-search.js b/tests/rustdoc-js/macro-search.js new file mode 100644 index 00000000000..2b179ce146b --- /dev/null +++ b/tests/rustdoc-js/macro-search.js @@ -0,0 +1,10 @@ +// exact-check + +const QUERY = 'abracadabra!'; + +const EXPECTED = { + 'others': [ + { 'path': 'macro_search', 'name': 'abracadabra' }, + { 'path': 'macro_search', 'name': 'abracadabra_b' }, + ], +}; diff --git a/tests/rustdoc-js/macro-search.rs b/tests/rustdoc-js/macro-search.rs new file mode 100644 index 00000000000..dc397490cf5 --- /dev/null +++ b/tests/rustdoc-js/macro-search.rs @@ -0,0 +1,10 @@ +#[macro_export] +macro_rules! abracadabra { + () => {} +} +#[macro_export] +macro_rules! abracadabra_b { + () => {} +} +pub fn abracadabra() {} +pub fn abracadabra_c() {} diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 6aa9785f44e..79e6b94f1ac 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -87,6 +87,7 @@ -Z llvm-plugins=val -- a list LLVM plugins to enable (space separated) -Z llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no) -Z location-detail=val -- what location details should be tracked when using caller_location, either `none`, or a comma separated list of location details, for which valid options are `file`, `line`, and `column` (default: `file,line,column`) + -Z lower-impl-trait-in-trait-to-assoc-ty=val -- modify the lowering strategy for `impl Trait` in traits so that they are lowered to generic associated types -Z ls=val -- list the symbols defined by a library crate (default: no) -Z macro-backtrace=val -- show macro backtraces (default: no) -Z maximal-hir-to-mir-coverage=val -- save as much information as possible about the correspondence between MIR and HIR as source scopes (default: no) diff --git a/tests/ui-toml/array_size_threshold/array_size_threshold.rs b/tests/ui-toml/array_size_threshold/array_size_threshold.rs new file mode 100644 index 00000000000..7f623c7a9ec --- /dev/null +++ b/tests/ui-toml/array_size_threshold/array_size_threshold.rs @@ -0,0 +1,10 @@ +#![allow(unused)] +#![warn(clippy::large_const_arrays, clippy::large_stack_arrays)] + +const ABOVE: [u8; 11] = [0; 11]; +const BELOW: [u8; 10] = [0; 10]; + +fn main() { + let above = [0u8; 11]; + let below = [0u8; 10]; +} diff --git a/tests/ui-toml/array_size_threshold/array_size_threshold.stderr b/tests/ui-toml/array_size_threshold/array_size_threshold.stderr new file mode 100644 index 00000000000..ac017b20916 --- /dev/null +++ b/tests/ui-toml/array_size_threshold/array_size_threshold.stderr @@ -0,0 +1,29 @@ +error: large array defined as const + --> $DIR/array_size_threshold.rs:4:1 + | +LL | const ABOVE: [u8; 11] = [0; 11]; + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: make this a static item: `static` + | + = note: `-D clippy::large-const-arrays` implied by `-D warnings` + +error: allocating a local array larger than 10 bytes + --> $DIR/array_size_threshold.rs:4:25 + | +LL | const ABOVE: [u8; 11] = [0; 11]; + | ^^^^^^^ + | + = help: consider allocating on the heap with `vec![0; 11].into_boxed_slice()` + = note: `-D clippy::large-stack-arrays` implied by `-D warnings` + +error: allocating a local array larger than 10 bytes + --> $DIR/array_size_threshold.rs:8:17 + | +LL | let above = [0u8; 11]; + | ^^^^^^^^^ + | + = help: consider allocating on the heap with `vec![0u8; 11].into_boxed_slice()` + +error: aborting due to 3 previous errors + diff --git a/tests/ui-toml/array_size_threshold/clippy.toml b/tests/ui-toml/array_size_threshold/clippy.toml new file mode 100644 index 00000000000..3f1fe9a1209 --- /dev/null +++ b/tests/ui-toml/array_size_threshold/clippy.toml @@ -0,0 +1 @@ +array-size-threshold = 10 diff --git a/tests/ui/abi/stack-probes-lto.rs b/tests/ui/abi/stack-probes-lto.rs index 6d934538f4c..a455eef42ea 100644 --- a/tests/ui/abi/stack-probes-lto.rs +++ b/tests/ui/abi/stack-probes-lto.rs @@ -13,5 +13,6 @@ // ignore-fuchsia no exception handler registered for segfault // compile-flags: -C lto // no-prefer-dynamic +// ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino include!("stack-probes.rs"); diff --git a/tests/ui/abi/stack-probes.rs b/tests/ui/abi/stack-probes.rs index e7b91644b3b..8dba54c3f81 100644 --- a/tests/ui/abi/stack-probes.rs +++ b/tests/ui/abi/stack-probes.rs @@ -9,6 +9,7 @@ // ignore-emscripten no processes // ignore-sgx no processes // ignore-fuchsia no exception handler registered for segfault +// ignore-nto Crash analysis impossible at SIGSEGV in QNX Neutrino use std::env; use std::mem::MaybeUninit; diff --git a/tests/ui/asm/x86_64/issue-89875.rs b/tests/ui/asm/x86_64/issue-89875.rs index e793690ddbe..669fd7e7e46 100644 --- a/tests/ui/asm/x86_64/issue-89875.rs +++ b/tests/ui/asm/x86_64/issue-89875.rs @@ -2,6 +2,8 @@ // needs-asm-support // only-x86_64 +#![feature(target_feature_11)] + use std::arch::asm; #[target_feature(enable = "avx")] diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 371122ea71e..f71fd9980a2 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -7,20 +7,13 @@ LL | #![feature(async_fn_in_trait)] = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/dont-project-to-specializable-projection.rs:14:35 +error: async associated function in trait cannot be specialized + --> $DIR/dont-project-to-specializable-projection.rs:14:5 | LL | default async fn foo(_: T) -> &'static str { - | ^^^^^^^^^^^^ expected associated type, found future + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: type in trait - --> $DIR/dont-project-to-specializable-projection.rs:10:27 - | -LL | async fn foo(_: T) -> &'static str; - | ^^^^^^^^^^^^ - = note: expected signature `fn(_) -> impl Future<Output = &'static str>` - found signature `fn(_) -> impl Future<Output = &'static str>` + = note: specialization behaves in inconsistent and surprising ways with `#![feature(async_fn_in_trait)]`, and for now is disallowed error: aborting due to previous error; 1 warning emitted -For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/async-await/issues/issue-107280.rs b/tests/ui/async-await/issues/issue-107280.rs new file mode 100644 index 00000000000..85fce87403a --- /dev/null +++ b/tests/ui/async-await/issues/issue-107280.rs @@ -0,0 +1,15 @@ +// edition:2021 + +async fn foo() { + inner::<false>().await + //~^ ERROR: function takes 2 generic arguments but 1 generic argument was supplied + //~| ERROR: type inside `async fn` body must be known in this context + //~| ERROR: type inside `async fn` body must be known in this context + //~| ERROR: type inside `async fn` body must be known in this context + //~| ERROR: type inside `async fn` body must be known in this context + //~| ERROR: type inside `async fn` body must be known in this context +} + +async fn inner<T, const PING: bool>() {} + +fn main() {} diff --git a/tests/ui/async-await/issues/issue-107280.stderr b/tests/ui/async-await/issues/issue-107280.stderr new file mode 100644 index 00000000000..dd3e10fcc18 --- /dev/null +++ b/tests/ui/async-await/issues/issue-107280.stderr @@ -0,0 +1,82 @@ +error[E0107]: function takes 2 generic arguments but 1 generic argument was supplied + --> $DIR/issue-107280.rs:4:5 + | +LL | inner::<false>().await + | ^^^^^ ----- supplied 1 generic argument + | | + | expected 2 generic arguments + | +note: function defined here, with 2 generic parameters: `T`, `PING` + --> $DIR/issue-107280.rs:13:10 + | +LL | async fn inner<T, const PING: bool>() {} + | ^^^^^ - ---------------- +help: add missing generic argument + | +LL | inner::<false, PING>().await + | ++++++ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/issue-107280.rs:4:5 + | +LL | inner::<false>().await + | ^^^^^^^^^^^^^^ cannot infer the value of const parameter `PING` declared on the function `inner` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/issue-107280.rs:4:21 + | +LL | inner::<false>().await + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/issue-107280.rs:4:5 + | +LL | inner::<false>().await + | ^^^^^^^^^^^^^^ cannot infer the value of const parameter `PING` declared on the function `inner` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/issue-107280.rs:4:21 + | +LL | inner::<false>().await + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/issue-107280.rs:4:5 + | +LL | inner::<false>().await + | ^^^^^^^^^^^^^^ cannot infer the value of const parameter `PING` declared on the function `inner` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/issue-107280.rs:4:21 + | +LL | inner::<false>().await + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/issue-107280.rs:4:5 + | +LL | inner::<false>().await + | ^^^^^^^^^^^^^^ cannot infer the value of const parameter `PING` declared on the function `inner` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/issue-107280.rs:4:21 + | +LL | inner::<false>().await + | ^^^^^^ + +error[E0698]: type inside `async fn` body must be known in this context + --> $DIR/issue-107280.rs:4:5 + | +LL | inner::<false>().await + | ^^^^^^^^^^^^^^ cannot infer the value of const parameter `PING` declared on the function `inner` + | +note: the type is part of the `async fn` body because of this `await` + --> $DIR/issue-107280.rs:4:21 + | +LL | inner::<false>().await + | ^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0107, E0698. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index ae4d0d5853c..5ae1d78a92b 100644 --- a/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/tests/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -17,8 +17,9 @@ error[E0700]: hidden type for `impl Trait<'a>` captures lifetime that does not a --> $DIR/ret-impl-trait-one.rs:16:80 | LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { - | ____________________________________--__________________________________________^ - | | | + | ____________________________________--___________________________--------------_^ + | | | | + | | | opaque type defined here | | hidden type `(&'a u8, &'b u8)` captures the lifetime `'b` as defined here LL | | LL | | (a, b) diff --git a/tests/ui/attributes/rustc-box.rs b/tests/ui/attributes/rustc-box.rs new file mode 100644 index 00000000000..b3726fb3867 --- /dev/null +++ b/tests/ui/attributes/rustc-box.rs @@ -0,0 +1,18 @@ +#![feature(rustc_attrs, stmt_expr_attributes)] + +fn foo(_: u32, _: u32) {} +fn bar(_: u32) {} + +fn main() { + #[rustc_box] + Box::new(1); // OK + #[rustc_box] + Box::pin(1); //~ ERROR `#[rustc_box]` attribute used incorrectly + #[rustc_box] + foo(1, 1); //~ ERROR `#[rustc_box]` attribute used incorrectly + #[rustc_box] + bar(1); //~ ERROR `#[rustc_box]` attribute used incorrectly + #[rustc_box] //~ ERROR `#[rustc_box]` attribute used incorrectly + #[rustfmt::skip] + Box::new(1); +} diff --git a/tests/ui/attributes/rustc-box.stderr b/tests/ui/attributes/rustc-box.stderr new file mode 100644 index 00000000000..073a18c7d58 --- /dev/null +++ b/tests/ui/attributes/rustc-box.stderr @@ -0,0 +1,34 @@ +error: `#[rustc_box]` attribute used incorrectly + --> $DIR/rustc-box.rs:10:5 + | +LL | Box::pin(1); + | ^^^^^^^^^^^ + | + = note: `#[rustc_box]` may only be applied to a `Box::new()` call + +error: `#[rustc_box]` attribute used incorrectly + --> $DIR/rustc-box.rs:12:5 + | +LL | foo(1, 1); + | ^^^^^^^^^ + | + = note: `#[rustc_box]` may only be applied to a `Box::new()` call + +error: `#[rustc_box]` attribute used incorrectly + --> $DIR/rustc-box.rs:14:5 + | +LL | bar(1); + | ^^^^^^ + | + = note: `#[rustc_box]` may only be applied to a `Box::new()` call + +error: `#[rustc_box]` attribute used incorrectly + --> $DIR/rustc-box.rs:15:5 + | +LL | #[rustc_box] + | ^^^^^^^^^^^^ + | + = note: no other attributes may be applied + +error: aborting due to 4 previous errors + diff --git a/tests/ui/closures/2229_closure_analysis/issue_88118.rs b/tests/ui/closures/2229_closure_analysis/issue_88118.rs index 453b7e04a36..bfb487649a3 100644 --- a/tests/ui/closures/2229_closure_analysis/issue_88118.rs +++ b/tests/ui/closures/2229_closure_analysis/issue_88118.rs @@ -1,10 +1,7 @@ // Regression test for #88118. Used to ICE. -// +// edition:2021 // check-pass -#![allow(incomplete_features)] -#![feature(capture_disjoint_fields)] - fn foo<MsU>(handler: impl FnOnce() -> MsU + Clone + 'static) { Box::new(move |value| { (|_| handler.clone()())(value); diff --git a/tests/ui/command/command-setgroups.rs b/tests/ui/command/command-setgroups.rs index aff67f91bba..7e321f2f0cd 100644 --- a/tests/ui/command/command-setgroups.rs +++ b/tests/ui/command/command-setgroups.rs @@ -3,6 +3,7 @@ // ignore-emscripten // ignore-sgx // ignore-musl - returns dummy result for _SC_NGROUPS_MAX +// ignore-nto - does not have `/bin/id`, expects groups to be i32 (not u32) #![feature(rustc_private)] #![feature(setgroups)] diff --git a/tests/ui/const-generics/issues/issue-105821.rs b/tests/ui/const-generics/issues/issue-105821.rs new file mode 100644 index 00000000000..cba2e22c460 --- /dev/null +++ b/tests/ui/const-generics/issues/issue-105821.rs @@ -0,0 +1,23 @@ +// check-pass + +#![allow(incomplete_features)] +#![feature(adt_const_params, const_ptr_read, generic_const_exprs)] +#![allow(dead_code)] + +const fn catone<const M: usize>(_a: &[u8; M]) -> [u8; M + 1] +where + [(); M + 1]:, +{ + unimplemented!() +} + +struct Catter<const A: &'static [u8]>; +impl<const A: &'static [u8]> Catter<A> +where + [(); A.len() + 1]:, +{ + const ZEROS: &'static [u8; A.len()] = &[0_u8; A.len()]; + const R: &'static [u8] = &catone(Self::ZEROS); +} + +fn main() {} diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs index 5134c672f5f..0fbd851431e 100644 --- a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs +++ b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.rs @@ -18,11 +18,85 @@ struct Burrito<F> { filling: F, } +impl<It: Iterator> T1 for Option<It> {} + +impl<'a, A: T1> T1 for &'a A {} + fn want<V: T1>(_x: V) {} +enum ExampleTuple<T> { + ExampleTupleVariant(T), +} +use ExampleDifferentTupleVariantName as ExampleYetAnotherTupleVariantName; +use ExampleTuple as ExampleOtherTuple; +use ExampleTuple::ExampleTupleVariant as ExampleDifferentTupleVariantName; +use ExampleTuple::*; + +impl<A> T1 for ExampleTuple<A> where A: T3 {} + +enum ExampleStruct<T> { + ExampleStructVariant { field: T }, +} +use ExampleDifferentStructVariantName as ExampleYetAnotherStructVariantName; +use ExampleStruct as ExampleOtherStruct; +use ExampleStruct::ExampleStructVariant as ExampleDifferentStructVariantName; +use ExampleStruct::*; + +impl<A> T1 for ExampleStruct<A> where A: T3 {} + +struct ExampleActuallyTupleStruct<T>(T, i32); +use ExampleActuallyTupleStruct as ExampleActuallyTupleStructOther; + +impl<A> T1 for ExampleActuallyTupleStruct<A> where A: T3 {} + fn example<Q>(q: Q) { want(Wrapper { value: Burrito { filling: q } }); //~^ ERROR the trait bound `Q: T3` is not satisfied [E0277] + + want(Some(())); + //~^ ERROR `()` is not an iterator [E0277] + + want(Some(q)); + //~^ ERROR `Q` is not an iterator [E0277] + + want(&Some(q)); + //~^ ERROR `Q` is not an iterator [E0277] + + want(&ExampleTuple::ExampleTupleVariant(q)); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleTupleVariant(q)); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleOtherTuple::ExampleTupleVariant(q)); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleDifferentTupleVariantName(q)); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleYetAnotherTupleVariantName(q)); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleStruct::ExampleStructVariant { field: q }); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleStructVariant { field: q }); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleOtherStruct::ExampleStructVariant { field: q }); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleDifferentStructVariantName { field: q }); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleYetAnotherStructVariantName { field: q }); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleActuallyTupleStruct(q, 0)); + //~^ ERROR `Q: T3` is not satisfied [E0277] + + want(&ExampleActuallyTupleStructOther(q, 0)); + //~^ ERROR `Q: T3` is not satisfied [E0277] } fn main() {} diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr index 27b002db130..9228a047e87 100644 --- a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr +++ b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `Q: T3` is not satisfied - --> $DIR/blame-trait-error.rs:24:46 + --> $DIR/blame-trait-error.rs:53:46 | LL | want(Wrapper { value: Burrito { filling: q } }); | ---- ^ the trait `T3` is not implemented for `Q` @@ -21,7 +21,7 @@ LL | impl<B: T2> T1 for Wrapper<B> {} | | | unsatisfied trait bound introduced here note: required by a bound in `want` - --> $DIR/blame-trait-error.rs:21:12 + --> $DIR/blame-trait-error.rs:25:12 | LL | fn want<V: T1>(_x: V) {} | ^^ required by this bound in `want` @@ -30,6 +30,373 @@ help: consider restricting type parameter `Q` LL | fn example<Q: T3>(q: Q) { | ++++ -error: aborting due to previous error +error[E0277]: `()` is not an iterator + --> $DIR/blame-trait-error.rs:56:15 + | +LL | want(Some(())); + | ---- ^^ `()` is not an iterator + | | + | required by a bound introduced by this call + | + = help: the trait `Iterator` is not implemented for `()` + = help: the trait `T1` is implemented for `Option<It>` +note: required for `Option<()>` to implement `T1` + --> $DIR/blame-trait-error.rs:21:20 + | +LL | impl<It: Iterator> T1 for Option<It> {} + | -------- ^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` + +error[E0277]: `Q` is not an iterator + --> $DIR/blame-trait-error.rs:59:15 + | +LL | want(Some(q)); + | ---- ^ `Q` is not an iterator + | | + | required by a bound introduced by this call + | +note: required for `Option<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:21:20 + | +LL | impl<It: Iterator> T1 for Option<It> {} + | -------- ^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: std::iter::Iterator>(q: Q) { + | +++++++++++++++++++++ + +error[E0277]: `Q` is not an iterator + --> $DIR/blame-trait-error.rs:62:16 + | +LL | want(&Some(q)); + | ---- ^ `Q` is not an iterator + | | + | required by a bound introduced by this call + | +note: required for `Option<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:21:20 + | +LL | impl<It: Iterator> T1 for Option<It> {} + | -------- ^^ ^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&Option<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: std::iter::Iterator>(q: Q) { + | +++++++++++++++++++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:65:45 + | +LL | want(&ExampleTuple::ExampleTupleVariant(q)); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleTuple<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:35:9 + | +LL | impl<A> T1 for ExampleTuple<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleTuple<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:68:31 + | +LL | want(&ExampleTupleVariant(q)); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleTuple<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:35:9 + | +LL | impl<A> T1 for ExampleTuple<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleTuple<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:71:50 + | +LL | want(&ExampleOtherTuple::ExampleTupleVariant(q)); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleTuple<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:35:9 + | +LL | impl<A> T1 for ExampleTuple<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleTuple<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:74:44 + | +LL | want(&ExampleDifferentTupleVariantName(q)); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleTuple<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:35:9 + | +LL | impl<A> T1 for ExampleTuple<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleTuple<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:77:45 + | +LL | want(&ExampleYetAnotherTupleVariantName(q)); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleTuple<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:35:9 + | +LL | impl<A> T1 for ExampleTuple<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleTuple<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:80:56 + | +LL | want(&ExampleStruct::ExampleStructVariant { field: q }); + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | +note: required for `ExampleStruct<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:45:9 + | +LL | impl<A> T1 for ExampleStruct<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleStruct<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:83:41 + | +LL | want(&ExampleStructVariant { field: q }); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleStruct<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:45:9 + | +LL | impl<A> T1 for ExampleStruct<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleStruct<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:86:61 + | +LL | want(&ExampleOtherStruct::ExampleStructVariant { field: q }); + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | +note: required for `ExampleStruct<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:45:9 + | +LL | impl<A> T1 for ExampleStruct<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleStruct<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:89:54 + | +LL | want(&ExampleDifferentStructVariantName { field: q }); + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | +note: required for `ExampleStruct<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:45:9 + | +LL | impl<A> T1 for ExampleStruct<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleStruct<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:92:55 + | +LL | want(&ExampleYetAnotherStructVariantName { field: q }); + | ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q` + | +note: required for `ExampleStruct<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:45:9 + | +LL | impl<A> T1 for ExampleStruct<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleStruct<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:95:38 + | +LL | want(&ExampleActuallyTupleStruct(q, 0)); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleActuallyTupleStruct<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:50:9 + | +LL | impl<A> T1 for ExampleActuallyTupleStruct<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleActuallyTupleStruct<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error[E0277]: the trait bound `Q: T3` is not satisfied + --> $DIR/blame-trait-error.rs:98:43 + | +LL | want(&ExampleActuallyTupleStructOther(q, 0)); + | ---- ^ the trait `T3` is not implemented for `Q` + | | + | required by a bound introduced by this call + | +note: required for `ExampleActuallyTupleStruct<Q>` to implement `T1` + --> $DIR/blame-trait-error.rs:50:9 + | +LL | impl<A> T1 for ExampleActuallyTupleStruct<A> where A: T3 {} + | ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- unsatisfied trait bound introduced here + = note: 1 redundant requirement hidden + = note: required for `&ExampleActuallyTupleStruct<Q>` to implement `T1` +note: required by a bound in `want` + --> $DIR/blame-trait-error.rs:25:12 + | +LL | fn want<V: T1>(_x: V) {} + | ^^ required by this bound in `want` +help: consider restricting type parameter `Q` + | +LL | fn example<Q: T3>(q: Q) { + | ++++ + +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr index 6913771f288..b6a24e12bcc 100644 --- a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr +++ b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr @@ -91,10 +91,10 @@ LL | fn example<Q: T3>(q: Q) { | ++++ error[E0277]: the trait bound `Q: T3` is not satisfied - --> $DIR/blame-trait-error-spans-on-exprs.rs:93:27 + --> $DIR/blame-trait-error-spans-on-exprs.rs:93:53 | LL | want(Wrapper { value: TacoKinds::OneTaco(false, q) }); - | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q` + | ---- ^ the trait `T3` is not implemented for `Q` | | | required by a bound introduced by this call | diff --git a/tests/ui/extenv/extenv-not-defined-default.rs b/tests/ui/extenv/extenv-not-defined-default.rs index 30a06a25465..1fb046c78f2 100644 --- a/tests/ui/extenv/extenv-not-defined-default.rs +++ b/tests/ui/extenv/extenv-not-defined-default.rs @@ -1,4 +1,4 @@ fn main() { - env!("__HOPEFULLY_NOT_DEFINED__"); - //~^ ERROR: environment variable `__HOPEFULLY_NOT_DEFINED__` not defined + env!("CARGO__HOPEFULLY_NOT_DEFINED__"); + //~^ ERROR: environment variable `CARGO__HOPEFULLY_NOT_DEFINED__` not defined } diff --git a/tests/ui/extenv/extenv-not-defined-default.stderr b/tests/ui/extenv/extenv-not-defined-default.stderr index 884875dca53..e3dce000530 100644 --- a/tests/ui/extenv/extenv-not-defined-default.stderr +++ b/tests/ui/extenv/extenv-not-defined-default.stderr @@ -1,9 +1,10 @@ -error: environment variable `__HOPEFULLY_NOT_DEFINED__` not defined +error: environment variable `CARGO__HOPEFULLY_NOT_DEFINED__` not defined at compile time --> $DIR/extenv-not-defined-default.rs:2:5 | -LL | env!("__HOPEFULLY_NOT_DEFINED__"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | env!("CARGO__HOPEFULLY_NOT_DEFINED__"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: Cargo sets build script variables at run time. Use `std::env::var("CARGO__HOPEFULLY_NOT_DEFINED__")` instead = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/ui/extenv/issue-55897.stderr b/tests/ui/extenv/issue-55897.stderr index 92e8a44b55f..5752a965e35 100644 --- a/tests/ui/extenv/issue-55897.stderr +++ b/tests/ui/extenv/issue-55897.stderr @@ -1,9 +1,10 @@ -error: environment variable `NON_EXISTENT` not defined +error: environment variable `NON_EXISTENT` not defined at compile time --> $DIR/issue-55897.rs:11:22 | LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | ^^^^^^^^^^^^^^^^^^^^ | + = help: Use `std::env::var("NON_EXISTENT")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: suffixes on string literals are invalid diff --git a/tests/ui/for/for-else-err.rs b/tests/ui/for/for-else-err.rs new file mode 100644 index 00000000000..16252e980e4 --- /dev/null +++ b/tests/ui/for/for-else-err.rs @@ -0,0 +1,8 @@ +fn main() { + for _ in 0..1 { + //~^ NOTE `else` is attached to this loop + } else { + //~^ ERROR `for...else` loops are not supported + //~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + } +} diff --git a/tests/ui/for/for-else-err.stderr b/tests/ui/for/for-else-err.stderr new file mode 100644 index 00000000000..b330d107647 --- /dev/null +++ b/tests/ui/for/for-else-err.stderr @@ -0,0 +1,17 @@ +error: `for...else` loops are not supported + --> $DIR/for-else-err.rs:4:7 + | +LL | for _ in 0..1 { + | --- `else` is attached to this loop +LL | +LL | } else { + | _______^ +LL | | +LL | | +LL | | } + | |_____^ + | + = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + +error: aborting due to previous error + diff --git a/tests/ui/for/for-else-let-else-err.rs b/tests/ui/for/for-else-let-else-err.rs new file mode 100644 index 00000000000..c0b96f97294 --- /dev/null +++ b/tests/ui/for/for-else-let-else-err.rs @@ -0,0 +1,8 @@ +fn main() { + let _ = for _ in 0..1 { + //~^ NOTE `else` is attached to this loop + } else { + //~^ ERROR `for...else` loops are not supported + //~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + }; +} diff --git a/tests/ui/for/for-else-let-else-err.stderr b/tests/ui/for/for-else-let-else-err.stderr new file mode 100644 index 00000000000..a2396a8fbb1 --- /dev/null +++ b/tests/ui/for/for-else-let-else-err.stderr @@ -0,0 +1,17 @@ +error: `for...else` loops are not supported + --> $DIR/for-else-let-else-err.rs:4:7 + | +LL | let _ = for _ in 0..1 { + | --- `else` is attached to this loop +LL | +LL | } else { + | _______^ +LL | | +LL | | +LL | | }; + | |_____^ + | + = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + +error: aborting due to previous error + diff --git a/tests/ui/impl-trait/hidden-lifetimes.stderr b/tests/ui/impl-trait/hidden-lifetimes.stderr index 3cc47e1e89d..bc8f559fdee 100644 --- a/tests/ui/impl-trait/hidden-lifetimes.stderr +++ b/tests/ui/impl-trait/hidden-lifetimes.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not a --> $DIR/hidden-lifetimes.rs:29:5 | LL | fn hide_ref<'a, 'b, T: 'static>(x: &'a mut &'b T) -> impl Swap + 'a { - | -- hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here + | -- -------------- opaque type defined here + | | + | hidden type `&'a mut &'b T` captures the lifetime `'b` as defined here LL | x | ^ | @@ -15,7 +17,9 @@ error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not a --> $DIR/hidden-lifetimes.rs:46:5 | LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a { - | -- hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here + | -- -------------- opaque type defined here + | | + | hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here LL | x | ^ | diff --git a/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr index 433b76b7afa..d56e1273f24 100644 --- a/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr +++ b/tests/ui/impl-trait/impl-fn-hrtb-bounds-2.stderr @@ -1,6 +1,8 @@ error[E0700]: hidden type for `impl Debug` captures lifetime that does not appear in bounds --> $DIR/impl-fn-hrtb-bounds-2.rs:5:9 | +LL | fn a() -> impl Fn(&u8) -> impl Debug { + | ---------- opaque type defined here LL | |x| x | --- ^ | | diff --git a/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-trait.rs b/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-trait.rs new file mode 100644 index 00000000000..dfce973d770 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/new-lowering-strategy/simple-trait.rs @@ -0,0 +1,11 @@ +// check-pass +// compile-flags: -Zlower-impl-trait-in-trait-to-assoc-ty + +#![feature(return_position_impl_trait_in_trait)] +#![allow(incomplete_features)] + +trait Foo { + fn foo() -> impl Sized; +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs index 9d27d3710a6..2fcffdf3f9a 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.rs +++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs @@ -15,6 +15,7 @@ where { fn bar(&self) -> U { //~^ ERROR method `bar` has an incompatible type for trait + //~| ERROR method with return-position `impl Trait` in trait cannot be specialized *self } } diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.stderr index 37cfd74498d..dc621d6b8a8 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr +++ b/tests/ui/impl-trait/in-trait/specialization-broken.stderr @@ -18,6 +18,14 @@ LL | fn bar(&self) -> impl Sized; = note: expected signature `fn(&U) -> impl Sized` found signature `fn(&U) -> U` -error: aborting due to previous error +error: method with return-position `impl Trait` in trait cannot be specialized + --> $DIR/specialization-broken.rs:16:5 + | +LL | fn bar(&self) -> U { + | ^^^^^^^^^^^^^^^^^^ + | + = note: specialization behaves in inconsistent and surprising ways with `#![feature(return_position_impl_trait_in_trait)]`, and for now is disallowed + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr index 90875708094..5b0b1cc5e42 100644 --- a/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr +++ b/tests/ui/impl-trait/multiple-lifetimes/error-handling-2.stderr @@ -1,6 +1,9 @@ error[E0700]: hidden type for `E<'b, 'c>` captures lifetime that does not appear in bounds --> $DIR/error-handling-2.rs:22:5 | +LL | type E<'a, 'b> = impl Sized; + | ---------- opaque type defined here +LL | LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { | -- hidden type `*mut &'a i32` captures the lifetime `'a` as defined here ... diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr index ec49a61795a..68ac22a05f4 100644 --- a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Trait<'d, 'e>` captures lifetime that does n --> $DIR/ordinary-bounds-unrelated.rs:28:33 | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> - | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here + | -- ------------------ opaque type defined here + | | + | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here ... LL | if condition() { a } else { b } | ^ diff --git a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr index c36f9bc6957..493a9e66eaf 100644 --- a/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr +++ b/tests/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Trait<'a, 'b>` captures lifetime that does n --> $DIR/ordinary-bounds-unsuited.rs:31:33 | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> - | -- hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here + | -- ------------------ opaque type defined here + | | + | hidden type `Ordinary<'b>` captures the lifetime `'b` as defined here ... LL | if condition() { a } else { b } | ^ diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 9c81791fbcb..55e3cd95064 100644 --- a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -2,8 +2,9 @@ error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear --> $DIR/must_outlive_least_region_or_bound.rs:3:35 | LL | fn elided(x: &i32) -> impl Copy { x } - | ---- ^ - | | + | ---- --------- ^ + | | | + | | opaque type defined here | hidden type `&i32` captures the anonymous lifetime defined here | help: to declare that `impl Copy` captures `'_`, you can add an explicit `'_` lifetime bound @@ -15,8 +16,9 @@ error[E0700]: hidden type for `impl Copy` captures lifetime that does not appear --> $DIR/must_outlive_least_region_or_bound.rs:6:44 | LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x } - | -- ^ - | | + | -- --------- ^ + | | | + | | opaque type defined here | hidden type `&'a i32` captures the lifetime `'a` as defined here | help: to declare that `impl Copy` captures `'a`, you can add an explicit `'a` lifetime bound @@ -100,7 +102,9 @@ error[E0700]: hidden type for `impl Fn(&'a u32)` captures lifetime that does not --> $DIR/must_outlive_least_region_or_bound.rs:38:5 | LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) { - | -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:13]` captures the lifetime `'b` as defined here + | -- ---------------- opaque type defined here + | | + | hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:13]` captures the lifetime `'b` as defined here LL | move |_| println!("{}", y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/tests/ui/impl-trait/nested-return-type4.stderr b/tests/ui/impl-trait/nested-return-type4.stderr index e761a60e79c..907822ebbc3 100644 --- a/tests/ui/impl-trait/nested-return-type4.stderr +++ b/tests/ui/impl-trait/nested-return-type4.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Future<Output = impl Sized>` captures lifeti --> $DIR/nested-return-type4.rs:4:5 | LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future<Output = impl Sized> { - | -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here + | -- --------------------------------------------- opaque type defined here + | | + | hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here LL | async move { let _s = s; } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/tests/ui/impl-trait/region-escape-via-bound.stderr b/tests/ui/impl-trait/region-escape-via-bound.stderr index 44a790cb1a4..e4556bc21a7 100644 --- a/tests/ui/impl-trait/region-escape-via-bound.stderr +++ b/tests/ui/impl-trait/region-escape-via-bound.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Trait<'y>` captures lifetime that does not a --> $DIR/region-escape-via-bound.rs:17:5 | LL | fn foo<'x, 'y>(x: Cell<&'x u32>) -> impl Trait<'y> - | -- hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here + | -- -------------- opaque type defined here + | | + | hidden type `Cell<&'x u32>` captures the lifetime `'x` as defined here ... LL | x | ^ diff --git a/tests/ui/impl-trait/static-return-lifetime-infered.stderr b/tests/ui/impl-trait/static-return-lifetime-infered.stderr index c451f8e37c4..488cb821c10 100644 --- a/tests/ui/impl-trait/static-return-lifetime-infered.stderr +++ b/tests/ui/impl-trait/static-return-lifetime-infered.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that --> $DIR/static-return-lifetime-infered.rs:7:9 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { - | ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here + | ----- ----------------------- opaque type defined here + | | + | hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | @@ -15,7 +17,9 @@ error[E0700]: hidden type for `impl Iterator<Item = u32>` captures lifetime that --> $DIR/static-return-lifetime-infered.rs:11:9 | LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> { - | -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:11:27: 11:30]>` captures the lifetime `'a` as defined here + | -- ----------------------- opaque type defined here + | | + | hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:11:27: 11:30]>` captures the lifetime `'a` as defined here LL | self.x.iter().map(|a| a.0) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index c8b1ff1dbce..b99bb39d062 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -22,7 +22,9 @@ mod rusti { target_os = "netbsd", target_os = "openbsd", target_os = "solaris", - target_os = "vxworks"))] + target_os = "vxworks", + target_os = "nto", +))] mod m { #[cfg(target_arch = "x86")] pub fn main() { diff --git a/tests/ui/let-else/let-else-brace-before-else.fixed b/tests/ui/let-else/let-else-brace-before-else.fixed index a75c770ddf2..2d85e3878cc 100644 --- a/tests/ui/let-else/let-else-brace-before-else.fixed +++ b/tests/ui/let-else/let-else-brace-before-else.fixed @@ -7,10 +7,6 @@ fn main() { //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; }; - let Some(1) = (loop { break Some(1) }) else { - //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed - return; - }; let 2 = 1 + (match 1 { n => n }) else { //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; diff --git a/tests/ui/let-else/let-else-brace-before-else.rs b/tests/ui/let-else/let-else-brace-before-else.rs index 5603b946f38..5c3375b3f28 100644 --- a/tests/ui/let-else/let-else-brace-before-else.rs +++ b/tests/ui/let-else/let-else-brace-before-else.rs @@ -7,10 +7,6 @@ fn main() { //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; }; - let Some(1) = loop { break Some(1) } else { - //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed - return; - }; let 2 = 1 + match 1 { n => n } else { //~^ ERROR right curly brace `}` before `else` in a `let...else` statement not allowed return; diff --git a/tests/ui/let-else/let-else-brace-before-else.stderr b/tests/ui/let-else/let-else-brace-before-else.stderr index cb01e4c18a1..ee53213d8c2 100644 --- a/tests/ui/let-else/let-else-brace-before-else.stderr +++ b/tests/ui/let-else/let-else-brace-before-else.stderr @@ -10,18 +10,7 @@ LL | let Some(1) = ({ Some(1) }) else { | + + error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/let-else-brace-before-else.rs:10:40 - | -LL | let Some(1) = loop { break Some(1) } else { - | ^ - | -help: wrap the expression in parentheses - | -LL | let Some(1) = (loop { break Some(1) }) else { - | + + - -error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/let-else-brace-before-else.rs:14:34 + --> $DIR/let-else-brace-before-else.rs:10:34 | LL | let 2 = 1 + match 1 { n => n } else { | ^ @@ -32,7 +21,7 @@ LL | let 2 = 1 + (match 1 { n => n }) else { | + + error: right curly brace `}` before `else` in a `let...else` statement not allowed - --> $DIR/let-else-brace-before-else.rs:18:40 + --> $DIR/let-else-brace-before-else.rs:14:40 | LL | let Some(1) = unsafe { unsafe_fn() } else { | ^ @@ -42,5 +31,5 @@ help: wrap the expression in parentheses LL | let Some(1) = (unsafe { unsafe_fn() }) else { | + + -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/lifetimes/issue-105227.stderr b/tests/ui/lifetimes/issue-105227.stderr index d2114593735..b514db461b4 100644 --- a/tests/ui/lifetimes/issue-105227.stderr +++ b/tests/ui/lifetimes/issue-105227.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime tha --> $DIR/issue-105227.rs:7:5 | LL | fn chars0(v :(& str, &str)) -> impl Iterator<Item = char> { - | ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here + | ----- -------------------------- opaque type defined here + | | + | hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here LL | LL | v.0.chars().chain(v.1.chars()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +18,9 @@ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime tha --> $DIR/issue-105227.rs:13:5 | LL | fn chars1(v0 : & str, v1 : &str) -> impl Iterator<Item = char> { - | ----- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here + | ----- -------------------------- opaque type defined here + | | + | hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here LL | LL | v0.chars().chain(v1.chars()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +35,10 @@ error[E0700]: hidden type for `impl Iterator<Item = char>` captures lifetime tha | LL | fn chars2<'b>(v0 : &str, v1 : &'_ str, v2 : &'b str) -> | ---- hidden type `std::iter::Chain<Chars<'_>, Chars<'_>>` captures the anonymous lifetime defined here -... +LL | +LL | (impl Iterator<Item = char>, &'b str) + | -------------------------- opaque type defined here +LL | { LL | (v0.chars().chain(v1.chars()), v2) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/tests/ui/lint/issue-104897.rs b/tests/ui/lint/issue-104897.rs index 5fbc658f155..2d298aff9db 100644 --- a/tests/ui/lint/issue-104897.rs +++ b/tests/ui/lint/issue-104897.rs @@ -1,6 +1,5 @@ // error-pattern: this file contains an unclosed delimiter // error-pattern: this file contains an unclosed delimiter // error-pattern: this file contains an unclosed delimiter -// error-pattern: format argument must be a string literal fn f(){(print!(á diff --git a/tests/ui/lint/issue-104897.stderr b/tests/ui/lint/issue-104897.stderr index 817a93c2f3b..728d51f34a4 100644 --- a/tests/ui/lint/issue-104897.stderr +++ b/tests/ui/lint/issue-104897.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-104897.rs:6:18 + --> $DIR/issue-104897.rs:5:18 | LL | fn f(){(print!(á | -- - ^ @@ -8,36 +8,5 @@ LL | fn f(){(print!(á | |unclosed delimiter | unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/issue-104897.rs:6:18 - | -LL | fn f(){(print!(á - | -- - ^ - | || | - | || unclosed delimiter - | |unclosed delimiter - | unclosed delimiter - -error: this file contains an unclosed delimiter - --> $DIR/issue-104897.rs:6:18 - | -LL | fn f(){(print!(á - | -- - ^ - | || | - | || unclosed delimiter - | |unclosed delimiter - | unclosed delimiter - -error: format argument must be a string literal - --> $DIR/issue-104897.rs:6:16 - | -LL | fn f(){(print!(á - | ^ - | -help: you might be missing a string literal to format with - | -LL | fn f(){(print!("{}", á - | +++++ - -error: aborting due to 4 previous errors +error: aborting due to previous error diff --git a/tests/ui/lint/unused_parens_multibyte_recovery.rs b/tests/ui/lint/unused_parens_multibyte_recovery.rs index 8fcfae22a3d..bc03faf3fce 100644 --- a/tests/ui/lint/unused_parens_multibyte_recovery.rs +++ b/tests/ui/lint/unused_parens_multibyte_recovery.rs @@ -3,7 +3,6 @@ // error-pattern: this file contains an unclosed delimiter // error-pattern: this file contains an unclosed delimiter // error-pattern: this file contains an unclosed delimiter -// error-pattern: format argument must be a string literal // // Verify that unused parens lint does not try to create a span // which points in the middle of a multibyte character. diff --git a/tests/ui/lint/unused_parens_multibyte_recovery.stderr b/tests/ui/lint/unused_parens_multibyte_recovery.stderr index a0302b17e25..adbf27fcca2 100644 --- a/tests/ui/lint/unused_parens_multibyte_recovery.stderr +++ b/tests/ui/lint/unused_parens_multibyte_recovery.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/unused_parens_multibyte_recovery.rs:11:17 + --> $DIR/unused_parens_multibyte_recovery.rs:10:17 | LL | fn f(){(print!(á | -- - ^ @@ -8,36 +8,5 @@ LL | fn f(){(print!(á | |unclosed delimiter | unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/unused_parens_multibyte_recovery.rs:11:17 - | -LL | fn f(){(print!(á - | -- - ^ - | || | - | || unclosed delimiter - | |unclosed delimiter - | unclosed delimiter - -error: this file contains an unclosed delimiter - --> $DIR/unused_parens_multibyte_recovery.rs:11:17 - | -LL | fn f(){(print!(á - | -- - ^ - | || | - | || unclosed delimiter - | |unclosed delimiter - | unclosed delimiter - -error: format argument must be a string literal - --> $DIR/unused_parens_multibyte_recovery.rs:11:16 - | -LL | fn f(){(print!(á - | ^ - | -help: you might be missing a string literal to format with - | -LL | fn f(){(print!("{}", á - | +++++ - -error: aborting due to 4 previous errors +error: aborting due to previous error diff --git a/tests/ui/loops/loop-else-break-with-value.rs b/tests/ui/loops/loop-else-break-with-value.rs new file mode 100644 index 00000000000..670d8a145c0 --- /dev/null +++ b/tests/ui/loops/loop-else-break-with-value.rs @@ -0,0 +1,10 @@ +fn main() { + let Some(1) = loop { + //~^ NOTE `else` is attached to this loop + break Some(1) + } else { + //~^ ERROR `loop...else` loops are not supported + //~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + return; + }; +} diff --git a/tests/ui/loops/loop-else-break-with-value.stderr b/tests/ui/loops/loop-else-break-with-value.stderr new file mode 100644 index 00000000000..972e2d341ec --- /dev/null +++ b/tests/ui/loops/loop-else-break-with-value.stderr @@ -0,0 +1,18 @@ +error: `loop...else` loops are not supported + --> $DIR/loop-else-break-with-value.rs:5:7 + | +LL | let Some(1) = loop { + | ---- `else` is attached to this loop +... +LL | } else { + | _______^ +LL | | +LL | | +LL | | return; +LL | | }; + | |_____^ + | + = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + +error: aborting due to previous error + diff --git a/tests/ui/loops/loop-else-err.rs b/tests/ui/loops/loop-else-err.rs new file mode 100644 index 00000000000..202a09c255c --- /dev/null +++ b/tests/ui/loops/loop-else-err.rs @@ -0,0 +1,8 @@ +fn main() { + loop { + //~^ NOTE `else` is attached to this loop + } else { + //~^ ERROR `loop...else` loops are not supported + //~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + } +} diff --git a/tests/ui/loops/loop-else-err.stderr b/tests/ui/loops/loop-else-err.stderr new file mode 100644 index 00000000000..c2c5c84cded --- /dev/null +++ b/tests/ui/loops/loop-else-err.stderr @@ -0,0 +1,17 @@ +error: `loop...else` loops are not supported + --> $DIR/loop-else-err.rs:4:7 + | +LL | loop { + | ---- `else` is attached to this loop +LL | +LL | } else { + | _______^ +LL | | +LL | | +LL | | } + | |_____^ + | + = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + +error: aborting due to previous error + diff --git a/tests/ui/loops/loop-else-let-else-err.rs b/tests/ui/loops/loop-else-let-else-err.rs new file mode 100644 index 00000000000..e828ffef549 --- /dev/null +++ b/tests/ui/loops/loop-else-let-else-err.rs @@ -0,0 +1,8 @@ +fn main() { + let _ = loop { + //~^ NOTE `else` is attached to this loop + } else { + //~^ ERROR `loop...else` loops are not supported + //~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + }; +} diff --git a/tests/ui/loops/loop-else-let-else-err.stderr b/tests/ui/loops/loop-else-let-else-err.stderr new file mode 100644 index 00000000000..a57c784ff6f --- /dev/null +++ b/tests/ui/loops/loop-else-let-else-err.stderr @@ -0,0 +1,17 @@ +error: `loop...else` loops are not supported + --> $DIR/loop-else-let-else-err.rs:4:7 + | +LL | let _ = loop { + | ---- `else` is attached to this loop +LL | +LL | } else { + | _______^ +LL | | +LL | | +LL | | }; + | |_____^ + | + = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + +error: aborting due to previous error + diff --git a/tests/ui/macros/issue-102878.rs b/tests/ui/macros/issue-102878.rs index aac5891939e..bdd9c256954 100644 --- a/tests/ui/macros/issue-102878.rs +++ b/tests/ui/macros/issue-102878.rs @@ -1,9 +1,5 @@ macro_rules!test{($l:expr,$_:r)=>({const:y y)} //~^ ERROR mismatched closing delimiter: `)` -//~| ERROR invalid fragment specifier `r` -//~| ERROR expected identifier, found keyword `const` -//~| ERROR expected identifier, found keyword `const` -//~| ERROR expected identifier, found `:` fn s(){test!(1,i)} diff --git a/tests/ui/macros/issue-102878.stderr b/tests/ui/macros/issue-102878.stderr index e0b8855a38d..034e3731b87 100644 --- a/tests/ui/macros/issue-102878.stderr +++ b/tests/ui/macros/issue-102878.stderr @@ -7,54 +7,5 @@ LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} | |unclosed delimiter | closing delimiter possibly meant for this -error: invalid fragment specifier `r` - --> $DIR/issue-102878.rs:1:27 - | -LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} - | ^^^^ - | - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis` - -error: expected identifier, found keyword `const` - --> $DIR/issue-102878.rs:1:36 - | -LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} - | ^^^^^ expected identifier, found keyword -... -LL | fn s(){test!(1,i)} - | ---------- in this macro invocation - | - = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) -help: escape `const` to use it as an identifier - | -LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)} - | ++ - -error: expected identifier, found keyword `const` - --> $DIR/issue-102878.rs:1:36 - | -LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} - | ^^^^^ expected identifier, found keyword -... -LL | fn s(){test!(1,i)} - | ---------- in this macro invocation - | - = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) -help: escape `const` to use it as an identifier - | -LL | macro_rules!test{($l:expr,$_:r)=>({r#const:y y)} - | ++ - -error: expected identifier, found `:` - --> $DIR/issue-102878.rs:1:41 - | -LL | macro_rules!test{($l:expr,$_:r)=>({const:y y)} - | ^ expected identifier -... -LL | fn s(){test!(1,i)} - | ---------- in this macro invocation - | - = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 5 previous errors +error: aborting due to previous error diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr index d42f6c179b7..93fbc9c8a44 100644 --- a/tests/ui/macros/macros-nonfatal-errors.stderr +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -150,18 +150,19 @@ error: expected string literal LL | env!(invalid); | ^^^^^^^ -error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:105:10 +error: env! takes 1 or 2 arguments + --> $DIR/macros-nonfatal-errors.rs:105:5 | LL | env!(foo, abr, baz); - | ^^^ + | ^^^^^^^^^^^^^^^^^^^ -error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined +error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time --> $DIR/macros-nonfatal-errors.rs:106:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: Use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: format argument must be a string literal diff --git a/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.stderr b/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.stderr index 0479035171e..89e0d982eaf 100644 --- a/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.stderr +++ b/tests/ui/malformed/issue-107423-unused-delim-only-one-no-pair.stderr @@ -8,25 +8,5 @@ LL | fn a(){{{ | |unclosed delimiter | unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/issue-107423-unused-delim-only-one-no-pair.rs:7:11 - | -LL | fn a(){{{ - | --- ^ - | ||| - | ||unclosed delimiter - | |unclosed delimiter - | unclosed delimiter - -error: this file contains an unclosed delimiter - --> $DIR/issue-107423-unused-delim-only-one-no-pair.rs:7:11 - | -LL | fn a(){{{ - | --- ^ - | ||| - | ||unclosed delimiter - | |unclosed delimiter - | unclosed delimiter - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/tests/ui/methods/method-call-err-msg.stderr b/tests/ui/methods/method-call-err-msg.stderr index c340c2d32b3..bd51378cf1a 100644 --- a/tests/ui/methods/method-call-err-msg.stderr +++ b/tests/ui/methods/method-call-err-msg.stderr @@ -48,14 +48,17 @@ LL | .two(0, /* isize */); error[E0599]: `Foo` is not an iterator --> $DIR/method-call-err-msg.rs:19:7 | -LL | pub struct Foo; - | -------------- - | | - | method `take` not found for this struct - | doesn't satisfy `Foo: Iterator` +LL | pub struct Foo; + | -------------- + | | + | method `take` not found for this struct + | doesn't satisfy `Foo: Iterator` ... -LL | .take() - | ^^^^ `Foo` is not an iterator +LL | / y.zero() +LL | | .take() + | | -^^^^ `Foo` is not an iterator + | |______| + | | = note: the following trait bounds were not satisfied: `Foo: Iterator` diff --git a/tests/ui/nll/issue-73159-rpit-static.stderr b/tests/ui/nll/issue-73159-rpit-static.stderr index 260b9b59772..4d3a9015316 100644 --- a/tests/ui/nll/issue-73159-rpit-static.stderr +++ b/tests/ui/nll/issue-73159-rpit-static.stderr @@ -4,6 +4,7 @@ error[E0700]: hidden type for `impl Iterator<Item = u8>` captures lifetime that LL | impl<'a> Foo<'a> { | -- hidden type `Copied<std::slice::Iter<'a, u8>>` captures the lifetime `'a` as defined here LL | fn make_it(&self) -> impl Iterator<Item = u8> { + | ------------------------ opaque type defined here LL | self.0.iter().copied() | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr b/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr index 1e6ef614dee..e0d476a33b2 100644 --- a/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr +++ b/tests/ui/nll/member-constraints/min-choice-reject-ambiguous.stderr @@ -24,7 +24,9 @@ error[E0700]: hidden type for `impl Cap<'b> + Cap<'c>` captures lifetime that do --> $DIR/min-choice-reject-ambiguous.rs:39:5 | LL | fn test_ambiguous<'a, 'b, 'c>(s: &'a u8) -> impl Cap<'b> + Cap<'c> - | -- hidden type `&'a u8` captures the lifetime `'a` as defined here + | -- ---------------------- opaque type defined here + | | + | hidden type `&'a u8` captures the lifetime `'a` as defined here ... LL | s | ^ diff --git a/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr b/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr index 6824e27ead0..483b5822b9d 100644 --- a/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr +++ b/tests/ui/nll/member-constraints/nested-impl-trait-fail.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>` --> $DIR/nested-impl-trait-fail.rs:17:5 | LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> - | -- hidden type `[&'s u8; 1]` captures the lifetime `'s` as defined here + | -- ------------------------------------------------ opaque type defined here + | | + | hidden type `[&'s u8; 1]` captures the lifetime `'s` as defined here ... LL | [a] | ^^^ @@ -20,7 +22,9 @@ error[E0700]: hidden type for `impl Cap<'a> + Cap<'b>` captures lifetime that do --> $DIR/nested-impl-trait-fail.rs:17:5 | LL | fn fail_early_bound<'s, 'a, 'b>(a: &'s u8) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> - | -- hidden type `&'s u8` captures the lifetime `'s` as defined here + | -- ---------------------- opaque type defined here + | | + | hidden type `&'s u8` captures the lifetime `'s` as defined here ... LL | [a] | ^^^ @@ -40,6 +44,8 @@ error[E0700]: hidden type for `impl IntoIterator<Item = impl Cap<'a> + Cap<'b>>` LL | fn fail_late_bound<'s, 'a, 'b>( | -- hidden type `[&'s u8; 1]` captures the lifetime `'s` as defined here ... +LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> { + | ------------------------------------------------ opaque type defined here LL | [a] | ^^^ | @@ -58,6 +64,8 @@ error[E0700]: hidden type for `impl Cap<'a> + Cap<'b>` captures lifetime that do LL | fn fail_late_bound<'s, 'a, 'b>( | -- hidden type `&'s u8` captures the lifetime `'s` as defined here ... +LL | ) -> impl IntoIterator<Item = impl Cap<'a> + Cap<'b>> { + | ---------------------- opaque type defined here LL | [a] | ^^^ | diff --git a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr index 7b9ed171d2d..7fcb68252cf 100644 --- a/tests/ui/nll/ty-outlives/impl-trait-captures.stderr +++ b/tests/ui/nll/ty-outlives/impl-trait-captures.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `Opaque(DefId(0:13 ~ impl_trait_captures[1afc]::fo --> $DIR/impl-trait-captures.rs:11:5 | LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> { - | -- hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here + | -- ------------ opaque type defined here + | | + | hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrNamed(DefId(0:12 ~ impl_trait_captures[1afc]::foo::'_), '_)) T` captures the anonymous lifetime defined here LL | x | ^ | diff --git a/tests/ui/numbers-arithmetic/issue-105626.rs b/tests/ui/numbers-arithmetic/issue-105626.rs new file mode 100644 index 00000000000..f97edd510c9 --- /dev/null +++ b/tests/ui/numbers-arithmetic/issue-105626.rs @@ -0,0 +1,17 @@ +// run-pass +// only-x86 +// min-system-llvm-version: 16 +// compile-flags: -Ctarget-feature=+sse2 + +use std::hint::black_box; + +fn main() { + let n: i64 = black_box(0x3fffffdfffffff); + let r = f32::from_bits(0x5a7fffff); + + assert_ne!((n as f64) as f32, n as f32); + + // FIXME: these assertions fail if only x87 is enabled + assert_eq!(n as i64 as f32, r); + assert_eq!(n as u64 as f32, r); +} diff --git a/tests/ui/parser/deli-ident-issue-1.rs b/tests/ui/parser/deli-ident-issue-1.rs index 54485262a0c..224ee6c09e0 100644 --- a/tests/ui/parser/deli-ident-issue-1.rs +++ b/tests/ui/parser/deli-ident-issue-1.rs @@ -15,8 +15,6 @@ impl dyn Demo { if let Some(b) = val && let Some(c) = num { && b == c { - //~^ ERROR expected struct - //~| ERROR mismatched types } } } diff --git a/tests/ui/parser/deli-ident-issue-1.stderr b/tests/ui/parser/deli-ident-issue-1.stderr index 1119edb199f..eb5073e14cf 100644 --- a/tests/ui/parser/deli-ident-issue-1.stderr +++ b/tests/ui/parser/deli-ident-issue-1.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/deli-ident-issue-1.rs:24:66 + --> $DIR/deli-ident-issue-1.rs:22:66 | LL | impl dyn Demo { | - unclosed delimiter @@ -13,25 +13,5 @@ LL | } LL | fn main() { } | ^ -error[E0574]: expected struct, variant or union type, found local variable `c` - --> $DIR/deli-ident-issue-1.rs:17:17 - | -LL | && b == c { - | ^ not a struct, variant or union type - -error[E0308]: mismatched types - --> $DIR/deli-ident-issue-1.rs:17:9 - | -LL | fn check(&self, val: Option<u32>, num: Option<u32>) { - | - expected `()` because of default return type -... -LL | / && b == c { -LL | | -LL | | -LL | | } - | |_________^ expected `()`, found `bool` - -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0574. -For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/deli-ident-issue-2.stderr b/tests/ui/parser/deli-ident-issue-2.stderr index c8f59c9d32b..e0188cdfb4a 100644 --- a/tests/ui/parser/deli-ident-issue-2.stderr +++ b/tests/ui/parser/deli-ident-issue-2.stderr @@ -1,3 +1,11 @@ +error: mismatched closing delimiter: `]` + --> $DIR/deli-ident-issue-2.rs:2:14 + | +LL | if 1 < 2 { + | ^ unclosed delimiter +LL | let _a = vec!]; + | ^ mismatched closing delimiter + error: unexpected closing delimiter: `}` --> $DIR/deli-ident-issue-2.rs:5:1 | @@ -7,13 +15,5 @@ LL | } LL | } | ^ unexpected closing delimiter -error: mismatched closing delimiter: `]` - --> $DIR/deli-ident-issue-2.rs:2:14 - | -LL | if 1 < 2 { - | ^ unclosed delimiter -LL | let _a = vec!]; - | ^ mismatched closing delimiter - error: aborting due to 2 previous errors diff --git a/tests/ui/parser/do-not-suggest-semicolon-before-array.rs b/tests/ui/parser/do-not-suggest-semicolon-before-array.rs index 7ebf3f6b0d8..7eff7f431be 100644 --- a/tests/ui/parser/do-not-suggest-semicolon-before-array.rs +++ b/tests/ui/parser/do-not-suggest-semicolon-before-array.rs @@ -2,7 +2,7 @@ fn foo() {} fn bar() -> [u8; 2] { foo() - [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,` + [1, 3) //~ ERROR mismatched closing delimiter } fn main() {} diff --git a/tests/ui/parser/do-not-suggest-semicolon-before-array.stderr b/tests/ui/parser/do-not-suggest-semicolon-before-array.stderr index a9dd526321f..7b43c77005e 100644 --- a/tests/ui/parser/do-not-suggest-semicolon-before-array.stderr +++ b/tests/ui/parser/do-not-suggest-semicolon-before-array.stderr @@ -1,8 +1,8 @@ -error: expected one of `.`, `?`, `]`, or an operator, found `,` +error: mismatched closing delimiter: `)` --> $DIR/do-not-suggest-semicolon-before-array.rs:5:5 | LL | [1, 3) - | ^ ^ help: `]` may belong here + | ^ ^ mismatched closing delimiter | | | unclosed delimiter diff --git a/tests/ui/parser/issue-103451.rs b/tests/ui/parser/issue-103451.rs index 1fdb0014881..be33213f3cb 100644 --- a/tests/ui/parser/issue-103451.rs +++ b/tests/ui/parser/issue-103451.rs @@ -1,5 +1,4 @@ // error-pattern: this file contains an unclosed delimiter -// error-pattern: expected value, found struct `R` struct R { } struct S { x: [u8; R diff --git a/tests/ui/parser/issue-103451.stderr b/tests/ui/parser/issue-103451.stderr index eb3c92fb43d..6aacd5012c1 100644 --- a/tests/ui/parser/issue-103451.stderr +++ b/tests/ui/parser/issue-103451.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-103451.rs:5:15 + --> $DIR/issue-103451.rs:4:15 | LL | struct S { | - unclosed delimiter @@ -8,25 +8,5 @@ LL | x: [u8; R | | | unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/issue-103451.rs:5:15 - | -LL | struct S { - | - unclosed delimiter -LL | x: [u8; R - | - ^ - | | - | unclosed delimiter - -error[E0423]: expected value, found struct `R` - --> $DIR/issue-103451.rs:5:13 - | -LL | struct R { } - | ------------ `R` defined here -LL | struct S { -LL | x: [u8; R - | ^ help: use struct literal syntax instead: `R {}` - -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/parser/issue-107705.rs b/tests/ui/parser/issue-107705.rs new file mode 100644 index 00000000000..b80984fcdb0 --- /dev/null +++ b/tests/ui/parser/issue-107705.rs @@ -0,0 +1,3 @@ +// compile-flags: -C debug-assertions + +fn f() {a(b:&, //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/issue-107705.stderr b/tests/ui/parser/issue-107705.stderr new file mode 100644 index 00000000000..d2d61346118 --- /dev/null +++ b/tests/ui/parser/issue-107705.stderr @@ -0,0 +1,10 @@ +error: this file contains an unclosed delimiter + --> $DIR/issue-107705.rs:3:67 + | +LL | fn f() {a(b:&, + | - - unclosed delimiter ^ + | | + | unclosed delimiter + +error: aborting due to previous error + diff --git a/tests/ui/parser/issue-108495-dec.rs b/tests/ui/parser/issue-108495-dec.rs new file mode 100644 index 00000000000..e0816f84e5c --- /dev/null +++ b/tests/ui/parser/issue-108495-dec.rs @@ -0,0 +1,39 @@ +fn test0() { + let mut i = 0; + let _ = i + i--; //~ ERROR Rust has no postfix decrement operator + // won't suggest since we can not handle the precedences +} + +fn test1() { + let mut i = 0; + let _ = i-- + i--; //~ ERROR Rust has no postfix decrement operator +} + +fn test2() { + let mut i = 0; + let _ = --i + i--; //~ ERROR Rust has no postfix decrement operator +} + +fn test3() { + let mut i = 0; + let _ = i-- + --i; //~ ERROR Rust has no postfix decrement operator +} + +fn test4() { + let mut i = 0; + let _ = (1 + 2 + i)--; //~ ERROR Rust has no postfix decrement operator +} + +fn test5() { + let mut i = 0; + let _ = (i-- + 1) + 2; //~ ERROR Rust has no postfix decrement operator +} + +fn test6(){ + let i=10; + while i != 0 { + i--; //~ ERROR Rust has no postfix decrement operator + } +} + +fn main() {} diff --git a/tests/ui/parser/issue-108495-dec.stderr b/tests/ui/parser/issue-108495-dec.stderr new file mode 100644 index 00000000000..85b29038f7c --- /dev/null +++ b/tests/ui/parser/issue-108495-dec.stderr @@ -0,0 +1,69 @@ +error: Rust has no postfix decrement operator + --> $DIR/issue-108495-dec.rs:3:18 + | +LL | let _ = i + i--; + | ^^ not a valid postfix operator + +error: Rust has no postfix decrement operator + --> $DIR/issue-108495-dec.rs:9:14 + | +LL | let _ = i-- + i--; + | ^^ not a valid postfix operator + | +help: use `-= 1` instead + | +LL | let _ = { let tmp = i; i -= 1; tmp } + i--; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no postfix decrement operator + --> $DIR/issue-108495-dec.rs:14:20 + | +LL | let _ = --i + i--; + | ^^ not a valid postfix operator + +error: Rust has no postfix decrement operator + --> $DIR/issue-108495-dec.rs:19:14 + | +LL | let _ = i-- + --i; + | ^^ not a valid postfix operator + | +help: use `-= 1` instead + | +LL | let _ = { let tmp = i; i -= 1; tmp } + --i; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no postfix decrement operator + --> $DIR/issue-108495-dec.rs:24:24 + | +LL | let _ = (1 + 2 + i)--; + | ^^ not a valid postfix operator + | +help: use `-= 1` instead + | +LL | let _ = { let tmp = (1 + 2 + i); (1 + 2 + i) -= 1; tmp }; + | +++++++++++ ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: Rust has no postfix decrement operator + --> $DIR/issue-108495-dec.rs:29:15 + | +LL | let _ = (i-- + 1) + 2; + | ^^ not a valid postfix operator + | +help: use `-= 1` instead + | +LL | let _ = ({ let tmp = i; i -= 1; tmp } + 1) + 2; + | +++++++++++ ~~~~~~~~~~~~~~~ + +error: Rust has no postfix decrement operator + --> $DIR/issue-108495-dec.rs:35:10 + | +LL | i--; + | ^^ not a valid postfix operator + | +help: use `-= 1` instead + | +LL | i -= 1; + | ~~~~ + +error: aborting due to 7 previous errors + diff --git a/tests/ui/parser/issue-68987-unmatch-issue-2.stderr b/tests/ui/parser/issue-68987-unmatch-issue-2.stderr index 2c08d41a15f..0ecb748a0a4 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-2.stderr +++ b/tests/ui/parser/issue-68987-unmatch-issue-2.stderr @@ -1,3 +1,11 @@ +error: mismatched closing delimiter: `)` + --> $DIR/issue-68987-unmatch-issue-2.rs:3:32 + | +LL | async fn obstest() -> Result<> { + | ^ unclosed delimiter +LL | let obs_connect = || -> Result<(), MyError) { + | ^ mismatched closing delimiter + error: unexpected closing delimiter: `}` --> $DIR/issue-68987-unmatch-issue-2.rs:14:1 | @@ -7,13 +15,5 @@ LL | let obs_connect = || -> Result<(), MyError) { LL | } | ^ unexpected closing delimiter -error: mismatched closing delimiter: `)` - --> $DIR/issue-68987-unmatch-issue-2.rs:3:32 - | -LL | async fn obstest() -> Result<> { - | ^ unclosed delimiter -LL | let obs_connect = || -> Result<(), MyError) { - | ^ mismatched closing delimiter - error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issue-68987-unmatch-issue-3.stderr b/tests/ui/parser/issue-68987-unmatch-issue-3.stderr index a3fc46a1e88..dfc4407ed65 100644 --- a/tests/ui/parser/issue-68987-unmatch-issue-3.stderr +++ b/tests/ui/parser/issue-68987-unmatch-issue-3.stderr @@ -1,3 +1,11 @@ +error: mismatched closing delimiter: `)` + --> $DIR/issue-68987-unmatch-issue-3.rs:5:19 + | +LL | while cnt < j { + | ^ unclosed delimiter +LL | write!&mut res, " "); + | ^ mismatched closing delimiter + error: unexpected closing delimiter: `}` --> $DIR/issue-68987-unmatch-issue-3.rs:8:1 | @@ -7,13 +15,5 @@ LL | } LL | } | ^ unexpected closing delimiter -error: mismatched closing delimiter: `)` - --> $DIR/issue-68987-unmatch-issue-3.rs:5:19 - | -LL | while cnt < j { - | ^ unclosed delimiter -LL | write!&mut res, " "); - | ^ mismatched closing delimiter - error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issue-81804.rs b/tests/ui/parser/issue-81804.rs index 803bde11e20..ebc4752a142 100644 --- a/tests/ui/parser/issue-81804.rs +++ b/tests/ui/parser/issue-81804.rs @@ -1,8 +1,5 @@ // error-pattern: this file contains an unclosed delimiter // error-pattern: this file contains an unclosed delimiter -// error-pattern: expected pattern, found `=` -// error-pattern: expected one of `)`, `,`, `->`, `where`, or `{`, found `]` -// error-pattern: expected item, found `]` fn main() {} diff --git a/tests/ui/parser/issue-81804.stderr b/tests/ui/parser/issue-81804.stderr index 19c4422c622..de3b33ecd95 100644 --- a/tests/ui/parser/issue-81804.stderr +++ b/tests/ui/parser/issue-81804.stderr @@ -1,14 +1,13 @@ -error: this file contains an unclosed delimiter - --> $DIR/issue-81804.rs:9:11 +error: mismatched closing delimiter: `}` + --> $DIR/issue-81804.rs:6:8 | LL | fn p([=(} - | -- ^ - | || - | |unclosed delimiter - | unclosed delimiter + | ^^ mismatched closing delimiter + | | + | unclosed delimiter error: this file contains an unclosed delimiter - --> $DIR/issue-81804.rs:9:11 + --> $DIR/issue-81804.rs:6:11 | LL | fn p([=(} | -- ^ @@ -16,26 +15,5 @@ LL | fn p([=(} | |unclosed delimiter | unclosed delimiter -error: expected pattern, found `=` - --> $DIR/issue-81804.rs:9:7 - | -LL | fn p([=(} - | ^ expected pattern - -error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]` - --> $DIR/issue-81804.rs:9:8 - | -LL | fn p([=(} - | ^ -^ - | | | - | | help: `)` may belong here - | unclosed delimiter - -error: expected item, found `]` - --> $DIR/issue-81804.rs:9:11 - | -LL | fn p([=(} - | ^ expected item - -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issue-81827.rs b/tests/ui/parser/issue-81827.rs index 7ec58159413..91defd12a57 100644 --- a/tests/ui/parser/issue-81827.rs +++ b/tests/ui/parser/issue-81827.rs @@ -1,6 +1,5 @@ // error-pattern: this file contains an unclosed delimiter // error-pattern: mismatched closing delimiter: `]` -// error-pattern: expected one of `)` or `,`, found `{` #![crate_name="0"] diff --git a/tests/ui/parser/issue-81827.stderr b/tests/ui/parser/issue-81827.stderr index 867244b72e8..63d135f73e6 100644 --- a/tests/ui/parser/issue-81827.stderr +++ b/tests/ui/parser/issue-81827.stderr @@ -1,15 +1,14 @@ -error: this file contains an unclosed delimiter - --> $DIR/issue-81827.rs:11:27 +error: mismatched closing delimiter: `]` + --> $DIR/issue-81827.rs:10:23 | LL | fn r()->i{0|{#[cfg(r(0{]0 - | - - - ^ - | | | | - | | | missing open `[` for this delimiter - | | unclosed delimiter - | unclosed delimiter + | - ^^ mismatched closing delimiter + | | | + | | unclosed delimiter + | closing delimiter possibly meant for this error: this file contains an unclosed delimiter - --> $DIR/issue-81827.rs:11:27 + --> $DIR/issue-81827.rs:10:27 | LL | fn r()->i{0|{#[cfg(r(0{]0 | - - - ^ @@ -18,20 +17,5 @@ LL | fn r()->i{0|{#[cfg(r(0{]0 | | unclosed delimiter | unclosed delimiter -error: mismatched closing delimiter: `]` - --> $DIR/issue-81827.rs:11:23 - | -LL | fn r()->i{0|{#[cfg(r(0{]0 - | - ^^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: expected one of `)` or `,`, found `{` - --> $DIR/issue-81827.rs:11:23 - | -LL | fn r()->i{0|{#[cfg(r(0{]0 - | ^ expected one of `)` or `,` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-104367.rs b/tests/ui/parser/issues/issue-104367.rs new file mode 100644 index 00000000000..861761b64f4 --- /dev/null +++ b/tests/ui/parser/issues/issue-104367.rs @@ -0,0 +1,6 @@ +#[derive(A)] +struct S { + d: [u32; { + #![cfg] { + #![w,) //~ ERROR mismatched closing delimiter + //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/issues/issue-104367.stderr b/tests/ui/parser/issues/issue-104367.stderr new file mode 100644 index 00000000000..e6e76535761 --- /dev/null +++ b/tests/ui/parser/issues/issue-104367.stderr @@ -0,0 +1,26 @@ +error: mismatched closing delimiter: `)` + --> $DIR/issue-104367.rs:5:15 + | +LL | #![w,) + | ^ ^ mismatched closing delimiter + | | + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/issue-104367.rs:6:71 + | +LL | struct S { + | - unclosed delimiter +LL | d: [u32; { + | - - unclosed delimiter + | | + | unclosed delimiter +LL | #![cfg] { + | - unclosed delimiter +LL | #![w,) + | - missing open `(` for this delimiter +LL | + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/issues/issue-105209.rs b/tests/ui/parser/issues/issue-105209.rs new file mode 100644 index 00000000000..6146b795de1 --- /dev/null +++ b/tests/ui/parser/issues/issue-105209.rs @@ -0,0 +1,3 @@ +// compile-flags: -Zunpretty=ast-tree +#![c={#![c[)x //~ ERROR mismatched closing delimiter + //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/issues/issue-105209.stderr b/tests/ui/parser/issues/issue-105209.stderr new file mode 100644 index 00000000000..c75eafa1833 --- /dev/null +++ b/tests/ui/parser/issues/issue-105209.stderr @@ -0,0 +1,22 @@ +error: mismatched closing delimiter: `)` + --> $DIR/issue-105209.rs:2:11 + | +LL | #![c={#![c[)x + | ^^ mismatched closing delimiter + | | + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/issue-105209.rs:3:68 + | +LL | #![c={#![c[)x + | - - - - missing open `(` for this delimiter + | | | | + | | | unclosed delimiter + | | unclosed delimiter + | unclosed delimiter +LL | + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/issues/issue-10636-2.rs b/tests/ui/parser/issues/issue-10636-2.rs index 6fb63639d5f..80d8ef65a69 100644 --- a/tests/ui/parser/issues/issue-10636-2.rs +++ b/tests/ui/parser/issues/issue-10636-2.rs @@ -1,11 +1,11 @@ +// error-pattern: mismatched closing delimiter: `}` // FIXME(31528) we emit a bunch of silly errors here due to continuing past the // first one. This would be easy-ish to address by better recovery in tokenisation. pub fn trace_option(option: Option<isize>) { option.map(|some| 42; - //~^ ERROR: expected one of + } -//~^ ERROR: expected expression, found `)` fn main() {} diff --git a/tests/ui/parser/issues/issue-10636-2.stderr b/tests/ui/parser/issues/issue-10636-2.stderr index d4f2da9e3ab..4cd4be1803e 100644 --- a/tests/ui/parser/issues/issue-10636-2.stderr +++ b/tests/ui/parser/issues/issue-10636-2.stderr @@ -1,16 +1,13 @@ -error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` - --> $DIR/issue-10636-2.rs:5:15 +error: mismatched closing delimiter: `}` + --> $DIR/issue-10636-2.rs:6:15 | +LL | pub fn trace_option(option: Option<isize>) { + | - closing delimiter possibly meant for this LL | option.map(|some| 42; - | ^ ^ help: `)` may belong here - | | - | unclosed delimiter - -error: expected expression, found `)` - --> $DIR/issue-10636-2.rs:8:1 - | + | ^ unclosed delimiter +... LL | } - | ^ expected expression + | ^ mismatched closing delimiter -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs index 25699f9fe11..a596a9f2de3 100644 --- a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs +++ b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.rs @@ -1,4 +1,5 @@ // Fixed in #66054. // ignore-tidy-trailing-newlines -// error-pattern: aborting due to 2 previous errors +// error-pattern: this file contains an unclosed delimiter +// error-pattern: aborting due to previous error #[Ѕ \ No newline at end of file diff --git a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr index 8a44ee761ed..c79e8b4fb70 100644 --- a/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr +++ b/tests/ui/parser/issues/issue-58094-missing-right-square-bracket.stderr @@ -1,16 +1,10 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-58094-missing-right-square-bracket.rs:4:4 + --> $DIR/issue-58094-missing-right-square-bracket.rs:5:4 | LL | #[Ѕ | - ^ | | | unclosed delimiter -error: expected item after attributes - --> $DIR/issue-58094-missing-right-square-bracket.rs:4:1 - | -LL | #[Ѕ - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-58856-1.rs b/tests/ui/parser/issues/issue-58856-1.rs index ea80eb8714f..799243d545a 100644 --- a/tests/ui/parser/issues/issue-58856-1.rs +++ b/tests/ui/parser/issues/issue-58856-1.rs @@ -1,8 +1,5 @@ impl A { - //~^ ERROR cannot find type `A` in this scope fn b(self> - //~^ ERROR expected one of `)`, `,`, or `:`, found `>` - //~| ERROR expected one of `->`, `where`, or `{`, found `>` -} +} //~ ERROR mismatched closing delimiter fn main() {} diff --git a/tests/ui/parser/issues/issue-58856-1.stderr b/tests/ui/parser/issues/issue-58856-1.stderr index 96151f3fe07..77ad8acbd43 100644 --- a/tests/ui/parser/issues/issue-58856-1.stderr +++ b/tests/ui/parser/issues/issue-58856-1.stderr @@ -1,29 +1,12 @@ -error: expected one of `)`, `,`, or `:`, found `>` - --> $DIR/issue-58856-1.rs:3:9 - | -LL | fn b(self> - | ^ ^ help: `)` may belong here - | | - | unclosed delimiter - -error: expected one of `->`, `where`, or `{`, found `>` - --> $DIR/issue-58856-1.rs:3:14 +error: mismatched closing delimiter: `}` + --> $DIR/issue-58856-1.rs:2:9 | LL | impl A { - | - while parsing this item list starting here -LL | + | - closing delimiter possibly meant for this LL | fn b(self> - | ^ expected one of `->`, `where`, or `{` -... + | ^ unclosed delimiter LL | } - | - the item list ends here - -error[E0412]: cannot find type `A` in this scope - --> $DIR/issue-58856-1.rs:1:6 - | -LL | impl A { - | ^ not found in this scope + | ^ mismatched closing delimiter -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/parser/issues/issue-58856-2.rs b/tests/ui/parser/issues/issue-58856-2.rs index 9356d57b0e5..5edd7263905 100644 --- a/tests/ui/parser/issues/issue-58856-2.rs +++ b/tests/ui/parser/issues/issue-58856-2.rs @@ -4,11 +4,8 @@ trait Howness {} impl Howness for () { fn how_are_you(&self -> Empty { - //~^ ERROR expected one of `)` or `,`, found `->` - //~| ERROR method `how_are_you` is not a member of trait `Howness` Empty } -} -//~^ ERROR non-item in item list +} //~ ERROR mismatched closing delimiter fn main() {} diff --git a/tests/ui/parser/issues/issue-58856-2.stderr b/tests/ui/parser/issues/issue-58856-2.stderr index 627dd389059..5fcf5bcc17e 100644 --- a/tests/ui/parser/issues/issue-58856-2.stderr +++ b/tests/ui/parser/issues/issue-58856-2.stderr @@ -1,34 +1,13 @@ -error: expected one of `)` or `,`, found `->` +error: mismatched closing delimiter: `}` --> $DIR/issue-58856-2.rs:6:19 | -LL | fn how_are_you(&self -> Empty { - | ^ -^^ - | | | - | | help: `)` may belong here - | unclosed delimiter - -error: non-item in item list - --> $DIR/issue-58856-2.rs:11:1 - | LL | impl Howness for () { - | - item list starts here + | - closing delimiter possibly meant for this +LL | fn how_are_you(&self -> Empty { + | ^ unclosed delimiter ... LL | } - | ^ - | | - | non-item starts here - | item list ends here - -error[E0407]: method `how_are_you` is not a member of trait `Howness` - --> $DIR/issue-58856-2.rs:6:5 - | -LL | / fn how_are_you(&self -> Empty { -LL | | -LL | | -LL | | Empty -LL | | } - | |_____^ not a member of trait `Howness` + | ^ mismatched closing delimiter -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0407`. diff --git a/tests/ui/parser/issues/issue-60075.rs b/tests/ui/parser/issues/issue-60075.rs index e89d78ee8a6..3c36e4d3ea7 100644 --- a/tests/ui/parser/issues/issue-60075.rs +++ b/tests/ui/parser/issues/issue-60075.rs @@ -3,9 +3,6 @@ fn main() {} trait T { fn qux() -> Option<usize> { let _ = if true { - }); -//~^ ERROR non-item in item list -//~| ERROR mismatched closing delimiter: `)` -//~| ERROR expected one of `.`, `;` + }); //~ ERROR mismatched closing delimiter Some(4) } diff --git a/tests/ui/parser/issues/issue-60075.stderr b/tests/ui/parser/issues/issue-60075.stderr index 210ef700cd4..cd8f1231fad 100644 --- a/tests/ui/parser/issues/issue-60075.stderr +++ b/tests/ui/parser/issues/issue-60075.stderr @@ -1,21 +1,3 @@ -error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}` - --> $DIR/issue-60075.rs:6:10 - | -LL | }); - | ^ expected one of `.`, `;`, `?`, `else`, or an operator - -error: non-item in item list - --> $DIR/issue-60075.rs:6:11 - | -LL | trait T { - | - item list starts here -... -LL | }); - | ^ non-item starts here -... -LL | } - | - item list ends here - error: mismatched closing delimiter: `)` --> $DIR/issue-60075.rs:4:31 | @@ -25,5 +7,5 @@ LL | let _ = if true { LL | }); | ^ mismatched closing delimiter -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-62524.rs b/tests/ui/parser/issues/issue-62524.rs index 5259dfe2e65..fa7c626f5cc 100644 --- a/tests/ui/parser/issues/issue-62524.rs +++ b/tests/ui/parser/issues/issue-62524.rs @@ -1,5 +1,5 @@ // ignore-tidy-trailing-newlines -// error-pattern: aborting due to 3 previous errors +// error-pattern: aborting due to previous error #![allow(uncommon_codepoints)] y![ diff --git a/tests/ui/parser/issues/issue-62524.stderr b/tests/ui/parser/issues/issue-62524.stderr index 55eed0402a4..0cbaacd4c64 100644 --- a/tests/ui/parser/issues/issue-62524.stderr +++ b/tests/ui/parser/issues/issue-62524.stderr @@ -6,28 +6,5 @@ LL | y![ LL | Ϥ, | ^ -error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/issue-62524.rs:5:3 - | -LL | y![ - | ___^ -LL | | Ϥ, - | |__^ - | -help: change the delimiters to curly braces - | -LL | y! { /* items */ } - | ~~~~~~~~~~~~~~~ -help: add a semicolon - | -LL | Ϥ,; - | + - -error: cannot find macro `y` in this scope - --> $DIR/issue-62524.rs:5:1 - | -LL | y![ - | ^ - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-62546.rs b/tests/ui/parser/issues/issue-62546.rs index f06b6505859..bb30d68eabd 100644 --- a/tests/ui/parser/issues/issue-62546.rs +++ b/tests/ui/parser/issues/issue-62546.rs @@ -1,3 +1 @@ -pub t(# -//~^ ERROR missing `fn` or `struct` for function or struct definition -//~ ERROR this file contains an unclosed delimiter +pub t(# //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/issues/issue-62546.stderr b/tests/ui/parser/issues/issue-62546.stderr index 32c61391e16..80c1c71689d 100644 --- a/tests/ui/parser/issues/issue-62546.stderr +++ b/tests/ui/parser/issues/issue-62546.stderr @@ -1,17 +1,8 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-62546.rs:3:52 + --> $DIR/issue-62546.rs:1:60 | LL | pub t(# - | - unclosed delimiter -LL | -LL | - | ^ + | - unclosed delimiter ^ -error: missing `fn` or `struct` for function or struct definition - --> $DIR/issue-62546.rs:1:4 - | -LL | pub t(# - | ---^- help: if you meant to call a macro, try: `t!` - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-62554.rs b/tests/ui/parser/issues/issue-62554.rs index cfd02183cb4..4b463a17333 100644 --- a/tests/ui/parser/issues/issue-62554.rs +++ b/tests/ui/parser/issues/issue-62554.rs @@ -1,5 +1,4 @@ // error-pattern:this file contains an unclosed delimiter -// error-pattern:xpected `{`, found `macro_rules` fn main() {} diff --git a/tests/ui/parser/issues/issue-62554.stderr b/tests/ui/parser/issues/issue-62554.stderr index 9e62572e388..4637c795ae5 100644 --- a/tests/ui/parser/issues/issue-62554.stderr +++ b/tests/ui/parser/issues/issue-62554.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-62554.rs:6:89 + --> $DIR/issue-62554.rs:5:89 | LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { | - - - - - ^ @@ -9,65 +9,5 @@ LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s | | | unclosed delimiter | unclosed delimiter unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/issue-62554.rs:6:89 - | -LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { - | - - - - - ^ - | | | | | | - | | | | | unclosed delimiter - | | | | unclosed delimiter - | | | unclosed delimiter - | unclosed delimiter unclosed delimiter - -error: this file contains an unclosed delimiter - --> $DIR/issue-62554.rs:6:89 - | -LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { - | - - - - - ^ - | | | | | | - | | | | | unclosed delimiter - | | | | unclosed delimiter - | | | unclosed delimiter - | unclosed delimiter unclosed delimiter - -error: this file contains an unclosed delimiter - --> $DIR/issue-62554.rs:6:89 - | -LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { - | - - - - - ^ - | | | | | | - | | | | | unclosed delimiter - | | | | unclosed delimiter - | | | unclosed delimiter - | unclosed delimiter unclosed delimiter - -error: this file contains an unclosed delimiter - --> $DIR/issue-62554.rs:6:89 - | -LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { - | - - - - - ^ - | | | | | | - | | | | | unclosed delimiter - | | | | unclosed delimiter - | | | unclosed delimiter - | unclosed delimiter unclosed delimiter - -error: expected `{`, found `macro_rules` - --> $DIR/issue-62554.rs:6:23 - | -LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { - | ^^^^^^^^^^^ expected `{` - | -note: the `if` expression is missing a block after this condition - --> $DIR/issue-62554.rs:6:20 - | -LL | fn foo(u: u8) { if u8 macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { - | ^^ -help: try placing this code inside a block - | -LL | fn foo(u: u8) { if u8 { macro_rules! u8 { (u6) => { fn uuuuuuuuuuu() { use s loo mod u8 { } - | + + - -error: aborting due to 6 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-62881.rs b/tests/ui/parser/issues/issue-62881.rs index b9204595fb9..cc80d449930 100644 --- a/tests/ui/parser/issues/issue-62881.rs +++ b/tests/ui/parser/issues/issue-62881.rs @@ -1,6 +1,3 @@ fn main() {} -fn f() -> isize { fn f() -> isize {} pub f< -//~^ ERROR missing `fn` or `struct` for function or struct definition -//~| ERROR mismatched types -//~ ERROR this file contains an unclosed delimiter +fn f() -> isize { fn f() -> isize {} pub f< //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/issues/issue-62881.stderr b/tests/ui/parser/issues/issue-62881.stderr index 87be69baadd..e57cbd1810a 100644 --- a/tests/ui/parser/issues/issue-62881.stderr +++ b/tests/ui/parser/issues/issue-62881.stderr @@ -1,26 +1,8 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-62881.rs:6:52 + --> $DIR/issue-62881.rs:3:96 | LL | fn f() -> isize { fn f() -> isize {} pub f< - | - unclosed delimiter -... -LL | - | ^ + | - unclosed delimiter ^ -error: missing `fn` or `struct` for function or struct definition - --> $DIR/issue-62881.rs:3:41 - | -LL | fn f() -> isize { fn f() -> isize {} pub f< - | ^ - -error[E0308]: mismatched types - --> $DIR/issue-62881.rs:3:29 - | -LL | fn f() -> isize { fn f() -> isize {} pub f< - | - ^^^^^ expected `isize`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression - -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/issues/issue-62894.rs b/tests/ui/parser/issues/issue-62894.rs index b9c0bf834dd..4dfa406ea2d 100644 --- a/tests/ui/parser/issues/issue-62894.rs +++ b/tests/ui/parser/issues/issue-62894.rs @@ -1,6 +1,5 @@ // Regression test for #62894, shouldn't crash. // error-pattern: this file contains an unclosed delimiter -// error-pattern: expected one of `(`, `[`, or `{`, found keyword `fn` fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! diff --git a/tests/ui/parser/issues/issue-62894.stderr b/tests/ui/parser/issues/issue-62894.stderr index 07a203bf416..700479076df 100644 --- a/tests/ui/parser/issues/issue-62894.stderr +++ b/tests/ui/parser/issues/issue-62894.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-62894.rs:7:14 + --> $DIR/issue-62894.rs:6:14 | LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! | - - - unclosed delimiter @@ -10,41 +10,5 @@ LL | LL | fn main() {} | ^ -error: this file contains an unclosed delimiter - --> $DIR/issue-62894.rs:7:14 - | -LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! - | - - - unclosed delimiter - | | | - | | unclosed delimiter - | unclosed delimiter -LL | -LL | fn main() {} - | ^ - -error: this file contains an unclosed delimiter - --> $DIR/issue-62894.rs:7:14 - | -LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! - | - - - unclosed delimiter - | | | - | | unclosed delimiter - | unclosed delimiter -LL | -LL | fn main() {} - | ^ - -error: expected one of `(`, `[`, or `{`, found keyword `fn` - --> $DIR/issue-62894.rs:7:1 - | -LL | fn f() { assert_eq!(f(), (), assert_eq!(assert_eq! - | - expected one of `(`, `[`, or `{` -LL | -LL | fn main() {} - | ^^ unexpected token - --> $SRC_DIR/core/src/macros/mod.rs:LL:COL - | - = note: while parsing argument for this `expr` macro fragment - -error: aborting due to 4 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-62895.rs b/tests/ui/parser/issues/issue-62895.rs index 53f17405d79..33511dee93e 100644 --- a/tests/ui/parser/issues/issue-62895.rs +++ b/tests/ui/parser/issues/issue-62895.rs @@ -1,11 +1,11 @@ fn main() {} -fn v() -> isize { //~ ERROR mismatched types -mod _ { //~ ERROR expected identifier -pub fn g() -> isizee { //~ ERROR cannot find type `isizee` in this scope -mod _ { //~ ERROR expected identifier -pub g() -> is //~ ERROR missing `fn` for function definition -(), w20); +fn v() -> isize { +mod _ { +pub fn g() -> isizee { +mod _ { +pub g() -> is +(), w20); //~ ERROR mismatched closing delimiter } -(), w20); //~ ERROR expected item, found `;` +(), w20); //~ ERROR mismatched closing delimiter } diff --git a/tests/ui/parser/issues/issue-62895.stderr b/tests/ui/parser/issues/issue-62895.stderr index 2e7e500f478..0ad9ac63ebd 100644 --- a/tests/ui/parser/issues/issue-62895.stderr +++ b/tests/ui/parser/issues/issue-62895.stderr @@ -1,47 +1,20 @@ -error: expected identifier, found reserved identifier `_` - --> $DIR/issue-62895.rs:4:5 +error: mismatched closing delimiter: `)` + --> $DIR/issue-62895.rs:6:7 | LL | mod _ { - | ^ expected identifier, found reserved identifier - -error: expected identifier, found reserved identifier `_` - --> $DIR/issue-62895.rs:6:5 - | -LL | mod _ { - | ^ expected identifier, found reserved identifier - -error: missing `fn` for function definition - --> $DIR/issue-62895.rs:7:4 - | + | ^ unclosed delimiter LL | pub g() -> is - | ^^^^ - | -help: add `fn` here to parse `g` as a public function - | -LL | pub fn g() -> is - | ++ - -error: expected item, found `;` - --> $DIR/issue-62895.rs:10:9 - | LL | (), w20); - | ^ help: remove this semicolon - -error[E0412]: cannot find type `isizee` in this scope - --> $DIR/issue-62895.rs:5:15 - | -LL | pub fn g() -> isizee { - | ^^^^^^ help: a builtin type with a similar name exists: `isize` + | ^ mismatched closing delimiter -error[E0308]: mismatched types - --> $DIR/issue-62895.rs:3:11 +error: mismatched closing delimiter: `)` + --> $DIR/issue-62895.rs:4:7 | -LL | fn v() -> isize { - | - ^^^^^ expected `isize`, found `()` - | | - | implicitly returns `()` as its body has no tail or `return` expression +LL | mod _ { + | ^ unclosed delimiter +... +LL | (), w20); + | ^ mismatched closing delimiter -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0412. -For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/issues/issue-62973.rs b/tests/ui/parser/issues/issue-62973.rs index 1c5d0c6f8ab..22d75457702 100644 --- a/tests/ui/parser/issues/issue-62973.rs +++ b/tests/ui/parser/issues/issue-62973.rs @@ -1,5 +1,5 @@ // ignore-tidy-trailing-newlines -// error-pattern: aborting due to 7 previous errors +// error-pattern: aborting due to 3 previous errors fn main() {} diff --git a/tests/ui/parser/issues/issue-62973.stderr b/tests/ui/parser/issues/issue-62973.stderr index 3cb6d75a675..14411a8cb78 100644 --- a/tests/ui/parser/issues/issue-62973.stderr +++ b/tests/ui/parser/issues/issue-62973.stderr @@ -1,72 +1,3 @@ -error: this file contains an unclosed delimiter - --> $DIR/issue-62973.rs:8:2 - | -LL | fn p() { match s { v, E { [) {) } - | - - - - missing open `(` for this delimiter - | | | | - | | | missing open `(` for this delimiter - | | unclosed delimiter - | unclosed delimiter -LL | -LL | - | ^ - -error: this file contains an unclosed delimiter - --> $DIR/issue-62973.rs:8:2 - | -LL | fn p() { match s { v, E { [) {) } - | - - - - missing open `(` for this delimiter - | | | | - | | | missing open `(` for this delimiter - | | unclosed delimiter - | unclosed delimiter -LL | -LL | - | ^ - -error: expected one of `,`, `:`, or `}`, found `{` - --> $DIR/issue-62973.rs:6:8 - | -LL | fn p() { match s { v, E { [) {) } - | ^ - ^ expected one of `,`, `:`, or `}` - | | | - | | while parsing this struct - | unclosed delimiter - | -help: `}` may belong here - | -LL | fn p() { match s { v, E} { [) {) } - | + -help: try naming a field - | -LL | fn p() { match s { v, E: E { [) {) } - | ++ - -error: struct literals are not allowed here - --> $DIR/issue-62973.rs:6:16 - | -LL | fn p() { match s { v, E { [) {) } - | ________________^ -LL | | -LL | | - | |_^ - | -help: surround the struct literal with parentheses - | -LL ~ fn p() { match (s { v, E { [) {) } -LL | -LL ~ ) - | - -error: expected one of `.`, `?`, `{`, or an operator, found `}` - --> $DIR/issue-62973.rs:8:2 - | -LL | fn p() { match s { v, E { [) {) } - | ----- while parsing this `match` expression -LL | -LL | - | ^ expected one of `.`, `?`, `{`, or an operator - error: mismatched closing delimiter: `)` --> $DIR/issue-62973.rs:6:27 | @@ -83,5 +14,18 @@ LL | fn p() { match s { v, E { [) {) } | | | unclosed delimiter -error: aborting due to 7 previous errors +error: this file contains an unclosed delimiter + --> $DIR/issue-62973.rs:8:2 + | +LL | fn p() { match s { v, E { [) {) } + | - - - - missing open `(` for this delimiter + | | | | + | | | missing open `(` for this delimiter + | | unclosed delimiter + | unclosed delimiter +LL | +LL | + | ^ + +error: aborting due to 3 previous errors diff --git a/tests/ui/parser/issues/issue-63116.rs b/tests/ui/parser/issues/issue-63116.rs index 430bc1d716c..6b9d9cdbeb1 100644 --- a/tests/ui/parser/issues/issue-63116.rs +++ b/tests/ui/parser/issues/issue-63116.rs @@ -1,3 +1,3 @@ // fixed by #66361 -// error-pattern: aborting due to 3 previous errors +// error-pattern: aborting due to 2 previous errors impl W <s(f;Y(;] diff --git a/tests/ui/parser/issues/issue-63116.stderr b/tests/ui/parser/issues/issue-63116.stderr index a1f8a77ffa7..27c94f337bd 100644 --- a/tests/ui/parser/issues/issue-63116.stderr +++ b/tests/ui/parser/issues/issue-63116.stderr @@ -1,3 +1,11 @@ +error: mismatched closing delimiter: `]` + --> $DIR/issue-63116.rs:3:14 + | +LL | impl W <s(f;Y(;] + | ^ ^ mismatched closing delimiter + | | + | unclosed delimiter + error: this file contains an unclosed delimiter --> $DIR/issue-63116.rs:3:18 | @@ -7,19 +15,5 @@ LL | impl W <s(f;Y(;] | | missing open `[` for this delimiter | unclosed delimiter -error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;` - --> $DIR/issue-63116.rs:3:12 - | -LL | impl W <s(f;Y(;] - | ^ expected one of 7 possible tokens - -error: mismatched closing delimiter: `]` - --> $DIR/issue-63116.rs:3:14 - | -LL | impl W <s(f;Y(;] - | ^ ^ mismatched closing delimiter - | | - | unclosed delimiter - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/parser/issues/issue-63135.rs b/tests/ui/parser/issues/issue-63135.rs index a5a8de85466..d61197dc566 100644 --- a/tests/ui/parser/issues/issue-63135.rs +++ b/tests/ui/parser/issues/issue-63135.rs @@ -1,3 +1,3 @@ -// error-pattern: aborting due to 5 previous errors - +// error-pattern: this file contains an unclosed delimiter +// error-pattern: aborting due to previous error fn i(n{...,f # diff --git a/tests/ui/parser/issues/issue-63135.stderr b/tests/ui/parser/issues/issue-63135.stderr index e0dc356d546..ff9d99c28fe 100644 --- a/tests/ui/parser/issues/issue-63135.stderr +++ b/tests/ui/parser/issues/issue-63135.stderr @@ -7,42 +7,5 @@ LL | fn i(n{...,f # | | unclosed delimiter | unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/issue-63135.rs:3:16 - | -LL | fn i(n{...,f # - | - - ^ - | | | - | | unclosed delimiter - | unclosed delimiter - -error: expected field pattern, found `...` - --> $DIR/issue-63135.rs:3:8 - | -LL | fn i(n{...,f # - | ^^^ - | -help: to omit remaining fields, use `..` - | -LL | fn i(n{..,f # - | ~~ - -error: expected `}`, found `,` - --> $DIR/issue-63135.rs:3:11 - | -LL | fn i(n{...,f # - | ---^ - | | | - | | expected `}` - | `..` must be at the end and cannot have a trailing comma - -error: expected one of `!` or `[`, found `}` - --> $DIR/issue-63135.rs:3:16 - | -LL | fn i(n{...,f # - | - ^ expected one of `!` or `[` - | | - | while parsing the fields for this pattern - -error: aborting due to 5 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-66357-unexpected-unreachable.rs b/tests/ui/parser/issues/issue-66357-unexpected-unreachable.rs index aed428bfc2a..69a2dfe6cbd 100644 --- a/tests/ui/parser/issues/issue-66357-unexpected-unreachable.rs +++ b/tests/ui/parser/issues/issue-66357-unexpected-unreachable.rs @@ -9,6 +9,4 @@ // // ended up bubbling up `Ok(true)` to `unexpected` which then used `unreachable!()`. -fn f() { |[](* } -//~^ ERROR expected one of `,` or `:`, found `(` -//~| ERROR expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` +fn f() { |[](* } //~ ERROR mismatched closing delimiter diff --git a/tests/ui/parser/issues/issue-66357-unexpected-unreachable.stderr b/tests/ui/parser/issues/issue-66357-unexpected-unreachable.stderr index 6cbab855c76..079fff37ea4 100644 --- a/tests/ui/parser/issues/issue-66357-unexpected-unreachable.stderr +++ b/tests/ui/parser/issues/issue-66357-unexpected-unreachable.stderr @@ -1,16 +1,11 @@ -error: expected one of `,` or `:`, found `(` +error: mismatched closing delimiter: `}` --> $DIR/issue-66357-unexpected-unreachable.rs:12:13 | LL | fn f() { |[](* } - | ^ expected one of `,` or `:` + | - ^ ^ mismatched closing delimiter + | | | + | | unclosed delimiter + | closing delimiter possibly meant for this -error: expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` - --> $DIR/issue-66357-unexpected-unreachable.rs:12:13 - | -LL | fn f() { |[](* } - | ^^ help: `)` may belong here - | | - | unclosed delimiter - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs b/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs index 87222ef4b59..e712160fcf8 100644 --- a/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs +++ b/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs @@ -4,9 +4,6 @@ mod a { enum Bug { V = [PhantomData; { [ () ].len() ].len() as isize, //~^ ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` } } @@ -14,10 +11,6 @@ mod b { enum Bug { V = [Vec::new; { [].len() ].len() as isize, //~^ ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR type annotations needed } } @@ -25,11 +18,6 @@ mod c { enum Bug { V = [Vec::new; { [0].len() ].len() as isize, //~^ ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR mismatched closing delimiter: `]` - //~| ERROR type annotations needed - } } -fn main() {} +fn main() {} //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr b/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr index a00f37ed606..9f631edf680 100644 --- a/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr +++ b/tests/ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.stderr @@ -8,7 +8,7 @@ LL | V = [PhantomData; { [ () ].len() ].len() as isize, | closing delimiter possibly meant for this error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:15:24 + --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:12:24 | LL | V = [Vec::new; { [].len() ].len() as isize, | - ^ ^ mismatched closing delimiter @@ -17,7 +17,7 @@ LL | V = [Vec::new; { [].len() ].len() as isize, | closing delimiter possibly meant for this error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:24 + --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:19:24 | LL | V = [Vec::new; { [0].len() ].len() as isize, | - ^ ^ mismatched closing delimiter @@ -25,104 +25,23 @@ LL | V = [Vec::new; { [0].len() ].len() as isize, | | unclosed delimiter | closing delimiter possibly meant for this -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:5:27 - | -LL | V = [PhantomData; { [ () ].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:15:24 - | -LL | V = [Vec::new; { [].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:24 - | -LL | V = [Vec::new; { [0].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:5:27 - | -LL | V = [PhantomData; { [ () ].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:15:24 - | -LL | V = [Vec::new; { [].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:24 - | -LL | V = [Vec::new; { [0].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:5:27 +error: this file contains an unclosed delimiter + --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:23:65 | LL | V = [PhantomData; { [ () ].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:15:24 - | + | - missing open `[` for this delimiter +... LL | V = [Vec::new; { [].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error: mismatched closing delimiter: `]` - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:24 - | + | - missing open `[` for this delimiter +... +LL | mod c { + | - unclosed delimiter +LL | enum Bug { LL | V = [Vec::new; { [0].len() ].len() as isize, - | - ^ ^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error[E0282]: type annotations needed - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:15:26 - | -LL | V = [Vec::new; { [].len() ].len() as isize, - | ^^ cannot infer type for type parameter `T` - -error[E0282]: type annotations needed - --> $DIR/issue-67377-invalid-syntax-in-enum-discriminant.rs:26:14 - | -LL | V = [Vec::new; { [0].len() ].len() as isize, - | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec` - | -help: consider specifying the generic argument - | -LL | V = [Vec::<T>::new; { [0].len() ].len() as isize, - | +++++ + | - missing open `[` for this delimiter +... +LL | fn main() {} + | ^ -error: aborting due to 14 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/parser/issues/issue-68629.rs b/tests/ui/parser/issues/issue-68629.rs index 672a31f12c8..af89bb58699 100644 --- a/tests/ui/parser/issues/issue-68629.rs +++ b/tests/ui/parser/issues/issue-68629.rs Binary files differdiff --git a/tests/ui/parser/issues/issue-68629.stderr b/tests/ui/parser/issues/issue-68629.stderr index 43a903e6c46..2562baa1c49 100644 --- a/tests/ui/parser/issues/issue-68629.stderr +++ b/tests/ui/parser/issues/issue-68629.stderr Binary files differdiff --git a/tests/ui/parser/issues/issue-84104.rs b/tests/ui/parser/issues/issue-84104.rs index 998949b94a4..962eb69bd83 100644 --- a/tests/ui/parser/issues/issue-84104.rs +++ b/tests/ui/parser/issues/issue-84104.rs @@ -1,3 +1,2 @@ // error-pattern: this file contains an unclosed delimiter -// error-pattern: expected one of #[i=i::<ښܖ< diff --git a/tests/ui/parser/issues/issue-84104.stderr b/tests/ui/parser/issues/issue-84104.stderr index aff31f2c971..7ad59f8450e 100644 --- a/tests/ui/parser/issues/issue-84104.stderr +++ b/tests/ui/parser/issues/issue-84104.stderr @@ -1,16 +1,10 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-84104.rs:3:13 + --> $DIR/issue-84104.rs:2:13 | LL | #[i=i::<ښܖ< | - ^ | | | unclosed delimiter -error: expected one of `>`, a const expression, lifetime, or type, found `]` - --> $DIR/issue-84104.rs:3:13 - | -LL | #[i=i::<ښܖ< - | ^ expected one of `>`, a const expression, lifetime, or type - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-84148-2.rs b/tests/ui/parser/issues/issue-84148-2.rs index 2f6a7facfb2..e677abde5f6 100644 --- a/tests/ui/parser/issues/issue-84148-2.rs +++ b/tests/ui/parser/issues/issue-84148-2.rs @@ -1,3 +1,2 @@ // error-pattern: this file contains an unclosed delimiter -// error-pattern: invalid `?` in type fn f(t:for<>t? diff --git a/tests/ui/parser/issues/issue-84148-2.stderr b/tests/ui/parser/issues/issue-84148-2.stderr index 71d543f9b73..20761180e77 100644 --- a/tests/ui/parser/issues/issue-84148-2.stderr +++ b/tests/ui/parser/issues/issue-84148-2.stderr @@ -1,27 +1,10 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-84148-2.rs:3:16 + --> $DIR/issue-84148-2.rs:2:16 | LL | fn f(t:for<>t? | - ^ | | | unclosed delimiter -error: invalid `?` in type - --> $DIR/issue-84148-2.rs:3:14 - | -LL | fn f(t:for<>t? - | ^ `?` is only allowed on expressions, not types - | -help: if you meant to express that the type might not contain a value, use the `Option` wrapper type - | -LL | fn f(t:Option<for<>t> - | +++++++ ~ - -error: expected one of `->`, `where`, or `{`, found `<eof>` - --> $DIR/issue-84148-2.rs:3:16 - | -LL | fn f(t:for<>t? - | ^ expected one of `->`, `where`, or `{` - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/issues/issue-88770.rs b/tests/ui/parser/issues/issue-88770.rs index bb69951c7b4..9341415b2d9 100644 --- a/tests/ui/parser/issues/issue-88770.rs +++ b/tests/ui/parser/issues/issue-88770.rs @@ -1,9 +1,6 @@ // Regression test for the ICE described in #88770. // error-pattern:this file contains an unclosed delimiter -// error-pattern:expected one of -// error-pattern:missing `in` in `for` loop -// error-pattern:expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e` fn m(){print!("",(c for&g u diff --git a/tests/ui/parser/issues/issue-88770.stderr b/tests/ui/parser/issues/issue-88770.stderr index 4e3a21613ec..836f44953d4 100644 --- a/tests/ui/parser/issues/issue-88770.stderr +++ b/tests/ui/parser/issues/issue-88770.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-88770.rs:11:3 + --> $DIR/issue-88770.rs:8:3 | LL | fn m(){print!("",(c for&g | - - - unclosed delimiter @@ -10,51 +10,5 @@ LL | fn m(){print!("",(c for&g LL | e | ^ -error: this file contains an unclosed delimiter - --> $DIR/issue-88770.rs:11:3 - | -LL | fn m(){print!("",(c for&g - | - - - unclosed delimiter - | | | - | | unclosed delimiter - | unclosed delimiter -... -LL | e - | ^ - -error: this file contains an unclosed delimiter - --> $DIR/issue-88770.rs:11:3 - | -LL | fn m(){print!("",(c for&g - | - - - unclosed delimiter - | | | - | | unclosed delimiter - | unclosed delimiter -... -LL | e - | ^ - -error: missing `in` in `for` loop - --> $DIR/issue-88770.rs:8:26 - | -LL | fn m(){print!("",(c for&g - | __________________________^ -LL | | u - | |_ help: try adding `in` here - -error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found keyword `for` - --> $DIR/issue-88770.rs:8:21 - | -LL | fn m(){print!("",(c for&g - | ^^^ expected one of 8 possible tokens - -error: expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e` - --> $DIR/issue-88770.rs:11:1 - | -LL | e - | - expected one of 9 possible tokens -LL | e - | ^ unexpected token - -error: aborting due to 6 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr b/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr index 689ce1eb6b7..34217e21ae9 100644 --- a/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr +++ b/tests/ui/parser/macro-mismatched-delim-paren-brace.stderr @@ -1,3 +1,12 @@ +error: mismatched closing delimiter: `}` + --> $DIR/macro-mismatched-delim-paren-brace.rs:2:10 + | +LL | foo! ( + | ^ unclosed delimiter +LL | bar, "baz", 1, 2.0 +LL | } + | ^ mismatched closing delimiter + error: unexpected closing delimiter: `}` --> $DIR/macro-mismatched-delim-paren-brace.rs:5:1 | @@ -9,14 +18,5 @@ LL | } LL | } | ^ unexpected closing delimiter -error: mismatched closing delimiter: `}` - --> $DIR/macro-mismatched-delim-paren-brace.rs:2:10 - | -LL | foo! ( - | ^ unclosed delimiter -LL | bar, "baz", 1, 2.0 -LL | } - | ^ mismatched closing delimiter - error: aborting due to 2 previous errors diff --git a/tests/ui/parser/mbe_missing_right_paren.rs b/tests/ui/parser/mbe_missing_right_paren.rs index 689176b3eb7..9a92e67da4d 100644 --- a/tests/ui/parser/mbe_missing_right_paren.rs +++ b/tests/ui/parser/mbe_missing_right_paren.rs @@ -1,3 +1,3 @@ // ignore-tidy-trailing-newlines -// error-pattern: aborting due to 3 previous errors +// error-pattern: this file contains an unclosed delimiter macro_rules! abc(ؼ \ No newline at end of file diff --git a/tests/ui/parser/mbe_missing_right_paren.stderr b/tests/ui/parser/mbe_missing_right_paren.stderr index ccaf77d3995..d2af94683ef 100644 --- a/tests/ui/parser/mbe_missing_right_paren.stderr +++ b/tests/ui/parser/mbe_missing_right_paren.stderr @@ -6,26 +6,5 @@ LL | macro_rules! abc(ؼ | | | unclosed delimiter -error: macros that expand to items must be delimited with braces or followed by a semicolon - --> $DIR/mbe_missing_right_paren.rs:3:17 - | -LL | macro_rules! abc(ؼ - | ^^ - | -help: change the delimiters to curly braces - | -LL | macro_rules! abc { /* items */ } - | ~~~~~~~~~~~~~~~ -help: add a semicolon - | -LL | macro_rules! abc(ؼ; - | + - -error: unexpected end of macro invocation - --> $DIR/mbe_missing_right_paren.rs:3:19 - | -LL | macro_rules! abc(ؼ - | ^ missing tokens in macro arguments - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs b/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs index 8f46970b1af..79de98d8b8c 100644 --- a/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs +++ b/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.rs @@ -1,13 +1,13 @@ fn main() {} -impl T for () { //~ ERROR cannot find trait `T` in this scope +impl T for () { fn foo(&self) {} -trait T { //~ ERROR trait is not supported in `trait`s or `impl`s +trait T { fn foo(&self); } -pub(crate) struct Bar<T>(); //~ ERROR struct is not supported in `trait`s or `impl`s +pub(crate) struct Bar<T>(); //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr b/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr index cc7cc0c55d5..d91a7f0542d 100644 --- a/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr +++ b/tests/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr @@ -7,28 +7,5 @@ LL | impl T for () { LL | | ^ -error: trait is not supported in `trait`s or `impl`s - --> $DIR/missing-close-brace-in-impl-trait.rs:7:1 - | -LL | trait T { - | ^^^^^^^ - | - = help: consider moving the trait out to a nearby module scope - -error: struct is not supported in `trait`s or `impl`s - --> $DIR/missing-close-brace-in-impl-trait.rs:11:1 - | -LL | pub(crate) struct Bar<T>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider moving the struct out to a nearby module scope - -error[E0405]: cannot find trait `T` in this scope - --> $DIR/missing-close-brace-in-impl-trait.rs:3:6 - | -LL | impl T for () { - | ^ not found in this scope - -error: aborting due to 4 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0405`. diff --git a/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs b/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs index 090a17b413d..88bc7257687 100644 --- a/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs +++ b/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.rs @@ -1,7 +1,7 @@ pub(crate) struct Bar<T> { foo: T, -trait T { //~ ERROR expected identifier, found keyword `trait` +trait T { fn foo(&self); } diff --git a/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr b/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr index ad1e90e43ec..d01d9ed60e4 100644 --- a/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr +++ b/tests/ui/parser/mismatched-braces/missing-close-brace-in-struct.stderr @@ -7,14 +7,5 @@ LL | pub(crate) struct Bar<T> { LL | fn main() {} | ^ -error: expected identifier, found keyword `trait` - --> $DIR/missing-close-brace-in-struct.rs:4:1 - | -LL | pub(crate) struct Bar<T> { - | --- while parsing this struct -... -LL | trait T { - | ^^^^^ expected identifier, found keyword - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs b/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs index b6932deb5c0..a05d6aa8edc 100644 --- a/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs +++ b/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.rs @@ -2,10 +2,9 @@ trait T { fn foo(&self); pub(crate) struct Bar<T>(); -//~^ ERROR struct is not supported in `trait`s or `impl`s impl T for Bar<usize> { -//~^ ERROR implementation is not supported in `trait`s or `impl`s + fn foo(&self) {} } diff --git a/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr index 7c6254356e0..7418dd64c9e 100644 --- a/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr +++ b/tests/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/missing-close-brace-in-trait.rs:12:65 + --> $DIR/missing-close-brace-in-trait.rs:11:65 | LL | trait T { | - unclosed delimiter @@ -7,21 +7,5 @@ LL | trait T { LL | fn main() {} | ^ -error: struct is not supported in `trait`s or `impl`s - --> $DIR/missing-close-brace-in-trait.rs:4:1 - | -LL | pub(crate) struct Bar<T>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider moving the struct out to a nearby module scope - -error: implementation is not supported in `trait`s or `impl`s - --> $DIR/missing-close-brace-in-trait.rs:7:1 - | -LL | impl T for Bar<usize> { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider moving the implementation out to a nearby module scope - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/missing_right_paren.rs b/tests/ui/parser/missing_right_paren.rs index 810dee9571d..e240f8c6739 100644 --- a/tests/ui/parser/missing_right_paren.rs +++ b/tests/ui/parser/missing_right_paren.rs @@ -1,3 +1,4 @@ // ignore-tidy-trailing-newlines -// error-pattern: aborting due to 4 previous errors +// error-pattern: this file contains an unclosed delimiter +// error-pattern: aborting due to previous error fn main((ؼ \ No newline at end of file diff --git a/tests/ui/parser/missing_right_paren.stderr b/tests/ui/parser/missing_right_paren.stderr index 3fe0d0f4273..994ce4d8541 100644 --- a/tests/ui/parser/missing_right_paren.stderr +++ b/tests/ui/parser/missing_right_paren.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/missing_right_paren.rs:3:11 + --> $DIR/missing_right_paren.rs:4:11 | LL | fn main((ؼ | -- ^ @@ -7,26 +7,5 @@ LL | fn main((ؼ | |unclosed delimiter | unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/missing_right_paren.rs:3:11 - | -LL | fn main((ؼ - | -- ^ - | || - | |unclosed delimiter - | unclosed delimiter - -error: expected one of `:` or `|`, found `)` - --> $DIR/missing_right_paren.rs:3:11 - | -LL | fn main((ؼ - | ^ expected one of `:` or `|` - -error: expected one of `->`, `where`, or `{`, found `<eof>` - --> $DIR/missing_right_paren.rs:3:11 - | -LL | fn main((ؼ - | ^ expected one of `->`, `where`, or `{` - -error: aborting due to 4 previous errors +error: aborting due to previous error diff --git a/tests/ui/parser/parser-recovery-1.rs b/tests/ui/parser/parser-recovery-1.rs index 7e26b4f2b6a..5f729665cb8 100644 --- a/tests/ui/parser/parser-recovery-1.rs +++ b/tests/ui/parser/parser-recovery-1.rs @@ -3,11 +3,8 @@ trait Foo { fn bar() { let x = foo(); - //~^ ERROR cannot find function `foo` in this scope } fn main() { let x = y.; - //~^ ERROR unexpected token - //~| ERROR cannot find value `y` in this scope } //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/parser/parser-recovery-1.stderr b/tests/ui/parser/parser-recovery-1.stderr index 0cb771ea39c..7045b6f5b78 100644 --- a/tests/ui/parser/parser-recovery-1.stderr +++ b/tests/ui/parser/parser-recovery-1.stderr @@ -1,35 +1,16 @@ error: this file contains an unclosed delimiter - --> $DIR/parser-recovery-1.rs:13:54 + --> $DIR/parser-recovery-1.rs:10:54 | LL | trait Foo { | - unclosed delimiter LL | fn bar() { | - this delimiter might not be properly closed... -... +LL | let x = foo(); LL | } | - ...as it matches this but it has different indentation ... LL | } | ^ -error: unexpected token: `;` - --> $DIR/parser-recovery-1.rs:10:15 - | -LL | let x = y.; - | ^ - -error[E0425]: cannot find value `y` in this scope - --> $DIR/parser-recovery-1.rs:10:13 - | -LL | let x = y.; - | ^ not found in this scope - -error[E0425]: cannot find function `foo` in this scope - --> $DIR/parser-recovery-1.rs:5:17 - | -LL | let x = foo(); - | ^^^ not found in this scope - -error: aborting due to 4 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/parser-recovery-2.rs b/tests/ui/parser/parser-recovery-2.rs index 48b22afffe7..203d8aac66c 100644 --- a/tests/ui/parser/parser-recovery-2.rs +++ b/tests/ui/parser/parser-recovery-2.rs @@ -2,11 +2,10 @@ trait Foo { fn bar() { - let x = foo(); //~ ERROR cannot find function `foo` in this scope + let x = foo(); ) //~ ERROR mismatched closing delimiter: `)` } fn main() { - let x = y.; //~ ERROR unexpected token - //~^ ERROR cannot find value `y` in this scope + let x = y.; } diff --git a/tests/ui/parser/parser-recovery-2.stderr b/tests/ui/parser/parser-recovery-2.stderr index 8829cf4c1e1..f396e5fde5b 100644 --- a/tests/ui/parser/parser-recovery-2.stderr +++ b/tests/ui/parser/parser-recovery-2.stderr @@ -1,9 +1,3 @@ -error: unexpected token: `;` - --> $DIR/parser-recovery-2.rs:10:15 - | -LL | let x = y.; - | ^ - error: mismatched closing delimiter: `)` --> $DIR/parser-recovery-2.rs:4:14 | @@ -13,18 +7,5 @@ LL | let x = foo(); LL | ) | ^ mismatched closing delimiter -error[E0425]: cannot find value `y` in this scope - --> $DIR/parser-recovery-2.rs:10:13 - | -LL | let x = y.; - | ^ not found in this scope - -error[E0425]: cannot find function `foo` in this scope - --> $DIR/parser-recovery-2.rs:5:17 - | -LL | let x = foo(); - | ^^^ not found in this scope - -error: aborting due to 4 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/unclosed-delimiter-in-dep.rs b/tests/ui/parser/unclosed-delimiter-in-dep.rs index 6db1b66e9f7..4de83ee640a 100644 --- a/tests/ui/parser/unclosed-delimiter-in-dep.rs +++ b/tests/ui/parser/unclosed-delimiter-in-dep.rs @@ -2,5 +2,4 @@ mod unclosed_delim_mod; fn main() { let _: usize = unclosed_delim_mod::new(); - //~^ ERROR mismatched types } diff --git a/tests/ui/parser/unclosed-delimiter-in-dep.stderr b/tests/ui/parser/unclosed-delimiter-in-dep.stderr index d1725c60dbb..a46d020b967 100644 --- a/tests/ui/parser/unclosed-delimiter-in-dep.stderr +++ b/tests/ui/parser/unclosed-delimiter-in-dep.stderr @@ -9,17 +9,5 @@ LL | } LL | } | ^ mismatched closing delimiter -error[E0308]: mismatched types - --> $DIR/unclosed-delimiter-in-dep.rs:4:20 - | -LL | let _: usize = unclosed_delim_mod::new(); - | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Result<Value, ()>` - | | - | expected due to this - | - = note: expected type `usize` - found enum `Result<Value, ()>` - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/use-unclosed-brace.rs b/tests/ui/parser/use-unclosed-brace.rs index 41742f37f3c..fcfe95b26f9 100644 --- a/tests/ui/parser/use-unclosed-brace.rs +++ b/tests/ui/parser/use-unclosed-brace.rs @@ -1,6 +1,4 @@ -// error-pattern: expected one of `,`, `::`, `as`, or `}`, found `;` // error-pattern: this file contains an unclosed delimiter -// error-pattern: expected item, found `}` use foo::{bar, baz; use std::fmt::Display; diff --git a/tests/ui/parser/use-unclosed-brace.stderr b/tests/ui/parser/use-unclosed-brace.stderr index 438fe9c47ea..ad5bb2de1b2 100644 --- a/tests/ui/parser/use-unclosed-brace.stderr +++ b/tests/ui/parser/use-unclosed-brace.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/use-unclosed-brace.rs:12:14 + --> $DIR/use-unclosed-brace.rs:10:14 | LL | use foo::{bar, baz; | - unclosed delimiter @@ -7,21 +7,5 @@ LL | use foo::{bar, baz; LL | fn main() {} | ^ -error: expected one of `,`, `::`, `as`, or `}`, found `;` - --> $DIR/use-unclosed-brace.rs:4:10 - | -LL | use foo::{bar, baz; - | ^ ^ - | | | - | | expected one of `,`, `::`, `as`, or `}` - | | help: `}` may belong here - | unclosed delimiter - -error: expected item, found `}` - --> $DIR/use-unclosed-brace.rs:12:14 - | -LL | fn main() {} - | ^ expected item - -error: aborting due to 3 previous errors +error: aborting due to previous error diff --git a/tests/ui/process/process-sigpipe.rs b/tests/ui/process/process-sigpipe.rs index 107eba45dc2..7ae14c6b84d 100644 --- a/tests/ui/process/process-sigpipe.rs +++ b/tests/ui/process/process-sigpipe.rs @@ -15,6 +15,7 @@ // ignore-emscripten no threads support // ignore-vxworks no 'sh' // ignore-fuchsia no 'sh' +// ignore-nto no 'yes' use std::process; use std::thread; diff --git a/tests/ui/resolve/token-error-correct-2.rs b/tests/ui/resolve/token-error-correct-2.rs index f7c7d908c78..a38755dae08 100644 --- a/tests/ui/resolve/token-error-correct-2.rs +++ b/tests/ui/resolve/token-error-correct-2.rs @@ -2,6 +2,5 @@ fn main() { if foo { - //~^ ERROR: cannot find value `foo` ) //~ ERROR: mismatched closing delimiter: `)` } diff --git a/tests/ui/resolve/token-error-correct-2.stderr b/tests/ui/resolve/token-error-correct-2.stderr index cca9f2dc88c..be5fb18a5d8 100644 --- a/tests/ui/resolve/token-error-correct-2.stderr +++ b/tests/ui/resolve/token-error-correct-2.stderr @@ -3,16 +3,8 @@ error: mismatched closing delimiter: `)` | LL | if foo { | ^ unclosed delimiter -LL | LL | ) | ^ mismatched closing delimiter -error[E0425]: cannot find value `foo` in this scope - --> $DIR/token-error-correct-2.rs:4:8 - | -LL | if foo { - | ^^^ not found in this scope - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/token-error-correct-3.rs b/tests/ui/resolve/token-error-correct-3.rs index 52934085fa1..2793f1b90ff 100644 --- a/tests/ui/resolve/token-error-correct-3.rs +++ b/tests/ui/resolve/token-error-correct-3.rs @@ -9,12 +9,9 @@ pub mod raw { callback: F) -> io::Result<bool> { if !is_directory(path.as_ref()) { - //~^ ERROR cannot find function `is_directory` callback(path.as_ref(); - //~^ ERROR expected one of fs::create_dir_all(path.as_ref()).map(|()| true) - } else { - //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `)` + } else { //~ ERROR mismatched closing delimiter Ok(false); } diff --git a/tests/ui/resolve/token-error-correct-3.stderr b/tests/ui/resolve/token-error-correct-3.stderr index 77c87c78466..79d1d4883a1 100644 --- a/tests/ui/resolve/token-error-correct-3.stderr +++ b/tests/ui/resolve/token-error-correct-3.stderr @@ -1,25 +1,13 @@ -error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` - --> $DIR/token-error-correct-3.rs:13:21 +error: mismatched closing delimiter: `}` + --> $DIR/token-error-correct-3.rs:12:21 | +LL | if !is_directory(path.as_ref()) { + | - closing delimiter possibly meant for this LL | callback(path.as_ref(); - | ^ ^ help: `)` may belong here - | | - | unclosed delimiter - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - --> $DIR/token-error-correct-3.rs:16:9 - | + | ^ unclosed delimiter LL | fs::create_dir_all(path.as_ref()).map(|()| true) - | - expected one of `.`, `;`, `?`, `}`, or an operator LL | } else { - | ^ unexpected token - -error[E0425]: cannot find function `is_directory` in this scope - --> $DIR/token-error-correct-3.rs:11:13 - | -LL | if !is_directory(path.as_ref()) { - | ^^^^^^^^^^^^ not found in this scope + | ^ mismatched closing delimiter -error: aborting due to 3 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/token-error-correct-4.fixed b/tests/ui/resolve/token-error-correct-4.fixed deleted file mode 100644 index 064b9e74e24..00000000000 --- a/tests/ui/resolve/token-error-correct-4.fixed +++ /dev/null @@ -1,10 +0,0 @@ -// run-rustfix -// Test that we do some basic error correction in the tokeniser and apply suggestions. - -fn setsuna(_: ()) {} - -fn kazusa() {} - -fn main() { - setsuna(kazusa()); //~ ERROR: expected one of -} //~ ERROR: expected expression diff --git a/tests/ui/resolve/token-error-correct-4.rs b/tests/ui/resolve/token-error-correct-4.rs index 5e31d71e7bf..49fad4bd97f 100644 --- a/tests/ui/resolve/token-error-correct-4.rs +++ b/tests/ui/resolve/token-error-correct-4.rs @@ -1,4 +1,3 @@ -// run-rustfix // Test that we do some basic error correction in the tokeniser and apply suggestions. fn setsuna(_: ()) {} @@ -6,5 +5,5 @@ fn setsuna(_: ()) {} fn kazusa() {} fn main() { - setsuna(kazusa(); //~ ERROR: expected one of -} //~ ERROR: expected expression + setsuna(kazusa(); +} //~ ERROR mismatched closing delimiter diff --git a/tests/ui/resolve/token-error-correct-4.stderr b/tests/ui/resolve/token-error-correct-4.stderr index 81e5a133691..3ec97171fd3 100644 --- a/tests/ui/resolve/token-error-correct-4.stderr +++ b/tests/ui/resolve/token-error-correct-4.stderr @@ -1,16 +1,12 @@ -error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` - --> $DIR/token-error-correct-4.rs:9:12 +error: mismatched closing delimiter: `}` + --> $DIR/token-error-correct-4.rs:8:12 | +LL | fn main() { + | - closing delimiter possibly meant for this LL | setsuna(kazusa(); - | ^ ^ help: `)` may belong here - | | - | unclosed delimiter - -error: expected expression, found `)` - --> $DIR/token-error-correct-4.rs:10:1 - | + | ^ unclosed delimiter LL | } - | ^ expected expression + | ^ mismatched closing delimiter -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/resolve/token-error-correct.rs b/tests/ui/resolve/token-error-correct.rs index 4f74df0bf1f..84ee90e3685 100644 --- a/tests/ui/resolve/token-error-correct.rs +++ b/tests/ui/resolve/token-error-correct.rs @@ -2,7 +2,6 @@ fn main() { foo(bar(; - //~^ ERROR cannot find function `bar` in this scope } //~^ ERROR: mismatched closing delimiter: `}` diff --git a/tests/ui/resolve/token-error-correct.stderr b/tests/ui/resolve/token-error-correct.stderr index ca0c4c18ad4..35b2d0b323b 100644 --- a/tests/ui/resolve/token-error-correct.stderr +++ b/tests/ui/resolve/token-error-correct.stderr @@ -5,16 +5,8 @@ LL | fn main() { | - closing delimiter possibly meant for this LL | foo(bar(; | ^ unclosed delimiter -LL | LL | } | ^ mismatched closing delimiter -error[E0425]: cannot find function `bar` in this scope - --> $DIR/token-error-correct.rs:4:9 - | -LL | foo(bar(; - | ^^^ not found in this scope - -error: aborting due to 2 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs index 2ae0dd92717..e0842bfa4cd 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs @@ -11,6 +11,8 @@ // revisions: mir thir // [thir]compile-flags: -Z thir-unsafeck +#![feature(target_feature_11)] + #[target_feature(enable = "sse2")] const fn sse2() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs index e96a3e5f6cd..a59d7c2d784 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs @@ -5,6 +5,8 @@ // [thir]compile-flags: -Z thir-unsafeck // only-x86_64 +#![feature(target_feature_11)] + #[target_feature(enable="avx")] fn also_use_avx() { println!("Hello from AVX") diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs new file mode 100644 index 00000000000..975d7a1f694 --- /dev/null +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.rs @@ -0,0 +1,6 @@ +// only-x86_64 + +#[target_feature(enable = "sse2")] //~ ERROR can only be applied to `unsafe` functions +fn foo() {} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr new file mode 100644 index 00000000000..18917fd2556 --- /dev/null +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/feature-gate-target_feature_11.stderr @@ -0,0 +1,14 @@ +error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions + --> $DIR/feature-gate-target_feature_11.rs:3:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo() {} + | -------- not an `unsafe` function + | + = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information + = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr index fa6561b74d9..b0ac5dc44ad 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/fn-ptr.rs:9:21 + --> $DIR/fn-ptr.rs:11:21 | LL | #[target_feature(enable = "sse2")] | ---------------------------------- `#[target_feature]` added here diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs index 7df172e80eb..c95d4a08e48 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs @@ -2,6 +2,8 @@ // [thir]compile-flags: -Z thir-unsafeck // only-x86_64 +#![feature(target_feature_11)] + #[target_feature(enable = "sse2")] fn foo() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr index fa6561b74d9..b0ac5dc44ad 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/fn-ptr.rs:9:21 + --> $DIR/fn-ptr.rs:11:21 | LL | #[target_feature(enable = "sse2")] | ---------------------------------- `#[target_feature]` added here diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs index 392cdc4bd36..43bda49624e 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -1,5 +1,7 @@ // only-x86_64 +#![feature(target_feature_11)] + #[target_feature(enable = "avx")] fn foo() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index aa0f57dee41..fc7bf22775d 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -1,5 +1,5 @@ error[E0277]: expected a `Fn<()>` closure, found `fn() {foo}` - --> $DIR/fn-traits.rs:22:10 + --> $DIR/fn-traits.rs:24:10 | LL | call(foo); | ---- ^^^ expected an `Fn<()>` closure, found `fn() {foo}` @@ -10,13 +10,13 @@ LL | call(foo); = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call` - --> $DIR/fn-traits.rs:9:17 + --> $DIR/fn-traits.rs:11:17 | LL | fn call(f: impl Fn()) { | ^^^^ required by this bound in `call` error[E0277]: expected a `FnMut<()>` closure, found `fn() {foo}` - --> $DIR/fn-traits.rs:23:14 + --> $DIR/fn-traits.rs:25:14 | LL | call_mut(foo); | -------- ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` @@ -27,13 +27,13 @@ LL | call_mut(foo); = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_mut` - --> $DIR/fn-traits.rs:13:21 + --> $DIR/fn-traits.rs:15:21 | LL | fn call_mut(f: impl FnMut()) { | ^^^^^^^ required by this bound in `call_mut` error[E0277]: expected a `FnOnce<()>` closure, found `fn() {foo}` - --> $DIR/fn-traits.rs:24:15 + --> $DIR/fn-traits.rs:26:15 | LL | call_once(foo); | --------- ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` @@ -44,13 +44,13 @@ LL | call_once(foo); = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_once` - --> $DIR/fn-traits.rs:17:22 + --> $DIR/fn-traits.rs:19:22 | LL | fn call_once(f: impl FnOnce()) { | ^^^^^^^^ required by this bound in `call_once` error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` - --> $DIR/fn-traits.rs:26:10 + --> $DIR/fn-traits.rs:28:10 | LL | call(foo_unsafe); | ---- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` @@ -61,13 +61,13 @@ LL | call(foo_unsafe); = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call` - --> $DIR/fn-traits.rs:9:17 + --> $DIR/fn-traits.rs:11:17 | LL | fn call(f: impl Fn()) { | ^^^^ required by this bound in `call` error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` - --> $DIR/fn-traits.rs:28:14 + --> $DIR/fn-traits.rs:30:14 | LL | call_mut(foo_unsafe); | -------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` @@ -78,13 +78,13 @@ LL | call_mut(foo_unsafe); = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_mut` - --> $DIR/fn-traits.rs:13:21 + --> $DIR/fn-traits.rs:15:21 | LL | fn call_mut(f: impl FnMut()) { | ^^^^^^^ required by this bound in `call_mut` error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` - --> $DIR/fn-traits.rs:30:15 + --> $DIR/fn-traits.rs:32:15 | LL | call_once(foo_unsafe); | --------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` @@ -95,7 +95,7 @@ LL | call_once(foo_unsafe); = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_once` - --> $DIR/fn-traits.rs:17:22 + --> $DIR/fn-traits.rs:19:22 | LL | fn call_once(f: impl FnOnce()) { | ^^^^^^^^ required by this bound in `call_once` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs index e4ee511d07f..033dcdfc08d 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs @@ -1,5 +1,7 @@ // check-pass +#![feature(target_feature_11)] + struct S<T>(T) where [T; (|| {}, 1).1]: Copy; diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr index 76b99dca842..0ef7b8b09f1 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:21:5 + --> $DIR/safe-calls.rs:23:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -7,7 +7,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:24:5 + --> $DIR/safe-calls.rs:26:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -15,7 +15,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:27:5 + --> $DIR/safe-calls.rs:29:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -23,7 +23,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:34:5 + --> $DIR/safe-calls.rs:36:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -31,7 +31,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:37:5 + --> $DIR/safe-calls.rs:39:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -39,7 +39,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:44:5 + --> $DIR/safe-calls.rs:46:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -47,7 +47,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:47:5 + --> $DIR/safe-calls.rs:49:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -55,7 +55,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:50:5 + --> $DIR/safe-calls.rs:52:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -63,7 +63,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:58:5 + --> $DIR/safe-calls.rs:60:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -71,7 +71,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:63:18 + --> $DIR/safe-calls.rs:65:18 | LL | const name: () = sse2(); | ^^^^^^ call to function with `#[target_feature]` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index de78fbf0df4..cebc6f94784 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -2,6 +2,8 @@ // [thir]compile-flags: -Z thir-unsafeck // only-x86_64 +#![feature(target_feature_11)] + #[target_feature(enable = "sse2")] const fn sse2() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr index daca221fe5d..c75ac6e8b9a 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr @@ -1,5 +1,5 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:21:5 + --> $DIR/safe-calls.rs:23:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -7,7 +7,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:24:5 + --> $DIR/safe-calls.rs:26:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -15,7 +15,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:27:5 + --> $DIR/safe-calls.rs:29:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -23,7 +23,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:34:5 + --> $DIR/safe-calls.rs:36:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -31,7 +31,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:37:5 + --> $DIR/safe-calls.rs:39:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -39,7 +39,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:44:5 + --> $DIR/safe-calls.rs:46:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -47,7 +47,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:47:5 + --> $DIR/safe-calls.rs:49:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -55,7 +55,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:50:5 + --> $DIR/safe-calls.rs:52:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -63,7 +63,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:58:5 + --> $DIR/safe-calls.rs:60:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -71,7 +71,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:63:18 + --> $DIR/safe-calls.rs:65:18 | LL | const name: () = sse2(); | ^^^^^^ call to function with `#[target_feature]` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs index 3cdbf41d878..7314fa8cced 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs @@ -1,5 +1,7 @@ // only-x86_64 +#![feature(target_feature_11)] + trait Foo { fn foo(&self); unsafe fn unsf_foo(&self); diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr index eb385d359ac..07d6e090059 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr @@ -1,5 +1,5 @@ error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/trait-impl.rs:11:5 + --> $DIR/trait-impl.rs:13:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs index 6873abc49b2..ff45ace7857 100644 --- a/tests/ui/runtime/out-of-stack.rs +++ b/tests/ui/runtime/out-of-stack.rs @@ -6,6 +6,7 @@ // ignore-emscripten no processes // ignore-sgx no processes // ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590) +// ignore-nto no stack overflow handler used (no alternate stack available) #![feature(core_intrinsics)] #![feature(rustc_private)] diff --git a/tests/ui/runtime/signal-alternate-stack-cleanup.rs b/tests/ui/runtime/signal-alternate-stack-cleanup.rs index 8a6d738959e..37c602ae0b0 100644 --- a/tests/ui/runtime/signal-alternate-stack-cleanup.rs +++ b/tests/ui/runtime/signal-alternate-stack-cleanup.rs @@ -7,6 +7,7 @@ // ignore-windows // ignore-sgx no libc // ignore-vxworks no SIGWINCH in user space +// ignore-nto no SA_ONSTACK #![feature(rustc_private)] extern crate libc; diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr index eb3d3e4a67a..944cdc5f55d 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait-async.stderr @@ -2,8 +2,9 @@ error[E0700]: hidden type for `impl Clone` captures lifetime that does not appea --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:48 | LL | async fn f(self: Pin<&Self>) -> impl Clone { self } - | ----- ^^^^^^^^ - | | + | ----- ---------- ^^^^^^^^ + | | | + | | opaque type defined here | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here | help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr index 2c0b2a0d919..8a9b397ca70 100644 --- a/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr +++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_impl_trait.stderr @@ -2,8 +2,9 @@ error[E0700]: hidden type for `impl Clone` captures lifetime that does not appea --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44 | LL | fn f(self: Pin<&Self>) -> impl Clone { self } - | ----- ^^^^ - | | + | ----- ---------- ^^^^ + | | | + | | opaque type defined here | hidden type `Pin<&Foo>` captures the anonymous lifetime defined here | help: to declare that `impl Clone` captures `'_`, you can add an explicit `'_` lifetime bound diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs index 4559da91e47..f20024e759a 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs @@ -3,16 +3,10 @@ pub struct A {} impl A { - async fn create(path: impl AsRef<std::path::Path>) { //~ ERROR `async fn` is not permitted in Rust 2015 - //~^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures] + async fn create(path: impl AsRef<std::path::Path>) { ; - crate(move || {} ).await //~ ERROR expected function, found module `crate` + crate(move || {} ).await } } -trait C{async fn new(val: T) {} //~ ERROR `async fn` is not permitted in Rust 2015 -//~^ ERROR functions in traits cannot be declared `async` -//~| ERROR cannot find type `T` in this scope -//~| WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures] - -//~ ERROR this file contains an unclosed delimiter +trait C{async fn new(val: T) {} //~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr index df1cafdb7d3..1ec8ca4275b 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr @@ -1,95 +1,8 @@ error: this file contains an unclosed delimiter - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:18:53 + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:12:85 | LL | trait C{async fn new(val: T) {} - | - unclosed delimiter -... -LL | - | ^ + | - unclosed delimiter ^ -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:5 - | -LL | async fn create(path: impl AsRef<std::path::Path>) { - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9 - | -LL | trait C{async fn new(val: T) {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0412]: cannot find type `T` in this scope - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:27 - | -LL | pub struct A {} - | ------------ similarly named struct `A` defined here -... -LL | trait C{async fn new(val: T) {} - | ^ help: a struct with a similar name exists: `A` - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9 - | -LL | trait C{async fn new(val: T) {} - | -----^^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0423]: expected function, found module `crate` - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:9:5 - | -LL | crate(move || {} ).await - | ^^^^^ not a function - -warning: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:57 - | -LL | async fn create(path: impl AsRef<std::path::Path>) { - | _____________________----_____________________________-__^ - | | | | - | | | in Rust 2018, `path` is dropped here along with the closure, but in Rust 2021 `path` is not part of the closure - | | in Rust 2018, this causes the closure to capture `path`, but in Rust 2021, it has no effect -LL | | -LL | | ; -LL | | crate(move || {} ).await -LL | | } - | |_____^ - | - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html> - = note: requested on the command line with `-W rust-2021-incompatible-closure-captures` -help: add a dummy let to cause `path` to be fully captured - | -LL | async fn create(path: impl AsRef<std::path::Path>) { let _ = &path; - | ++++++++++++++ - -warning: changes to closure capture in Rust 2021 will affect drop order - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30 - | -LL | trait C{async fn new(val: T) {} - | --- - ^^ - | | | - | | in Rust 2018, `val` is dropped here along with the closure, but in Rust 2021 `val` is not part of the closure - | in Rust 2018, this causes the closure to capture `val`, but in Rust 2021, it has no effect - | - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html> -help: add a dummy let to cause `val` to be fully captured - | -LL | trait C{async fn new(val: T) { let _ = &val;} - | +++++++++++++ - -error: aborting due to 6 previous errors; 2 warnings emitted +error: aborting due to previous error -Some errors have detailed explanations: E0412, E0423, E0670, E0706. -For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 40ede9705f1..f21c9b2c808 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -43,7 +43,9 @@ struct Outer { target_os = "netbsd", target_os = "openbsd", target_os = "solaris", - target_os = "vxworks"))] + target_os = "vxworks", + target_os = "nto", +))] mod m { #[cfg(target_arch = "x86")] pub mod m { diff --git a/tests/ui/suggestions/constrain-suggest-ice.rs b/tests/ui/suggestions/constrain-suggest-ice.rs index 69b874bed1b..d6e5263ffe0 100644 --- a/tests/ui/suggestions/constrain-suggest-ice.rs +++ b/tests/ui/suggestions/constrain-suggest-ice.rs @@ -1,11 +1,9 @@ -struct Bug<S>{ //~ ERROR parameter `S` is never used [E0392] +struct Bug<S>{ A: [(); { - let x: [u8; Self::W] = [0; Self::W]; //~ ERROR generic `Self` types are currently not permitted in anonymous constants - //~^ ERROR generic `Self` types are currently not permitted in anonymous constants - //~^^ ERROR the size for values of type `S` cannot be known at compilation time [E0277] - F //~ ERROR cannot find value `F` in this scope [E0425] + let x: [u8; Self::W] = [0; Self::W]; + F } -} //~ ERROR mismatched closing delimiter: `}` +} //~^ ERROR mismatched closing delimiter: `}` fn main() {} diff --git a/tests/ui/suggestions/constrain-suggest-ice.stderr b/tests/ui/suggestions/constrain-suggest-ice.stderr index 2af7c2f6971..9b92091de9f 100644 --- a/tests/ui/suggestions/constrain-suggest-ice.stderr +++ b/tests/ui/suggestions/constrain-suggest-ice.stderr @@ -9,64 +9,5 @@ LL | A: [(); { LL | } | ^ mismatched closing delimiter -error: mismatched closing delimiter: `}` - --> $DIR/constrain-suggest-ice.rs:2:8 - | -LL | struct Bug<S>{ - | - closing delimiter possibly meant for this -LL | A: [(); { - | ^ unclosed delimiter -... -LL | } - | ^ mismatched closing delimiter - -error[E0425]: cannot find value `F` in this scope - --> $DIR/constrain-suggest-ice.rs:6:9 - | -LL | F - | ^ help: a local variable with a similar name exists: `x` - -error: generic `Self` types are currently not permitted in anonymous constants - --> $DIR/constrain-suggest-ice.rs:3:21 - | -LL | let x: [u8; Self::W] = [0; Self::W]; - | ^^^^ - -error: generic `Self` types are currently not permitted in anonymous constants - --> $DIR/constrain-suggest-ice.rs:3:36 - | -LL | let x: [u8; Self::W] = [0; Self::W]; - | ^^^^ - -error[E0277]: the size for values of type `S` cannot be known at compilation time - --> $DIR/constrain-suggest-ice.rs:3:36 - | -LL | struct Bug<S>{ - | - this type parameter needs to be `std::marker::Sized` -LL | A: [(); { -LL | let x: [u8; Self::W] = [0; Self::W]; - | ^^^^^^^ doesn't have a size known at compile-time - | -note: required by a bound in `Bug` - --> $DIR/constrain-suggest-ice.rs:1:12 - | -LL | struct Bug<S>{ - | ^ required by this bound in `Bug` -help: consider relaxing the implicit `Sized` restriction - | -LL | struct Bug<S: ?Sized>{ - | ++++++++ - -error[E0392]: parameter `S` is never used - --> $DIR/constrain-suggest-ice.rs:1:12 - | -LL | struct Bug<S>{ - | ^ unused parameter - | - = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `S` to be a const parameter, use `const S: usize` instead - -error: aborting due to 7 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0277, E0392, E0425. -For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 679ebd61ead..da72c8ebf19 100644 --- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -17,7 +17,7 @@ note: the used `impl` has a `'static` requirement LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> { | ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self<K>(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement help: consider relaxing the implicit `'static` requirement | LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ { @@ -42,7 +42,7 @@ note: the used `impl` has a `'static` requirement LL | impl dyn ObjectTrait { | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement help: consider relaxing the implicit `'static` requirement | LL | impl dyn ObjectTrait + '_ { @@ -65,7 +65,7 @@ note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:87:26 | LL | fn use_self(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement ... LL | impl MyTrait for dyn ObjectTrait {} | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement @@ -91,7 +91,7 @@ note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:106:26 | LL | fn use_self(&self) -> &() { panic!() } - | -------- calling this method introduces the `impl`'s 'static` requirement + | -------- calling this method introduces the `impl`'s `'static` requirement ... LL | impl MyTrait for dyn ObjectTrait {} | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index c5c3f7b468c..93cfa60b5ab 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -10,7 +10,9 @@ error[E0700]: hidden type for `impl FnOnce()` captures lifetime that does not ap --> $DIR/missing-lifetimes-in-signature.rs:19:5 | LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce() - | ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 19:12]` captures the anonymous lifetime defined here + | ------ ------------- opaque type defined here + | | + | hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 19:12]` captures the anonymous lifetime defined here ... LL | / move || { LL | | diff --git a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.rs b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.rs new file mode 100644 index 00000000000..fbaf41245e9 --- /dev/null +++ b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.rs @@ -0,0 +1,8 @@ +pub struct Bar<S>(S); + +pub trait Foo {} + +impl<S> Foo for Bar<S> where for<'a> <&'a S>::Item: Foo {} +//~^ ERROR ambiguous associated type + +fn main() {} diff --git a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr new file mode 100644 index 00000000000..0ca5b9b9207 --- /dev/null +++ b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr @@ -0,0 +1,9 @@ +error[E0223]: ambiguous associated type + --> $DIR/suggest-trait-in-ufcs-in-hrtb.rs:5:38 + | +LL | impl<S> Foo for Bar<S> where for<'a> <&'a S>::Item: Foo {} + | ^^^^^^^^^^^^^ help: use the fully-qualified path: `<&'a S as IntoIterator>::Item` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index a04bb0afed5..ad1b6e96be6 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -26,6 +26,12 @@ unsafe fn foo() {} #[target_feature(enable = "sse2")] +//~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions +//~| NOTE see issue #69098 +fn bar() {} +//~^ NOTE not an `unsafe` function + +#[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function mod another {} //~^ NOTE not a function @@ -69,8 +75,8 @@ trait Quux { impl Quux for Foo { #[target_feature(enable = "sse2")] - //~^ ERROR `#[target_feature(..)]` cannot be applied to safe trait method - //~| NOTE cannot be applied to safe trait method + //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions + //~| NOTE see issue #69098 fn foo() {} //~^ NOTE not an `unsafe` function } @@ -80,8 +86,9 @@ fn main() { //~^ ERROR attribute should be applied to a function unsafe { foo(); + bar(); } - //~^^^ NOTE not a function + //~^^^^ NOTE not a function #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index 22105bcca8d..a2adfc67f08 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -5,7 +5,7 @@ LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]` error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:28:1 + --> $DIR/invalid-attribute.rs:34:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | mod another {} | -------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:33:1 + --> $DIR/invalid-attribute.rs:39:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | const FOO: usize = 7; | --------------------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:38:1 + --> $DIR/invalid-attribute.rs:44:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | struct Foo; | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:43:1 + --> $DIR/invalid-attribute.rs:49:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | enum Bar {} | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:48:1 + --> $DIR/invalid-attribute.rs:54:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:56:1 + --> $DIR/invalid-attribute.rs:62:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,18 +63,19 @@ LL | trait Baz {} | ------------ not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:79:5 + --> $DIR/invalid-attribute.rs:85:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | / unsafe { LL | | foo(); +LL | | bar(); LL | | } | |_____- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:86:5 + --> $DIR/invalid-attribute.rs:93:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,20 +101,36 @@ error: malformed `target_feature` attribute input LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` +error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions + --> $DIR/invalid-attribute.rs:28:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn bar() {} + | -------- not an `unsafe` function + | + = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information + = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:61:1 + --> $DIR/invalid-attribute.rs:67:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/invalid-attribute.rs:71:5 +error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions + --> $DIR/invalid-attribute.rs:77:5 | LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | fn foo() {} | -------- not an `unsafe` function + | + = note: see issue #69098 <https://github.com/rust-lang/rust/issues/69098> for more information + = help: add `#![feature(target_feature_11)]` to the crate attributes to enable -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/thir-print/thir-flat.stdout b/tests/ui/thir-print/thir-flat.stdout index c31e6a218ce..910c0da2737 100644 --- a/tests/ui/thir-print/thir-flat.stdout +++ b/tests/ui/thir-print/thir-flat.stdout @@ -17,21 +17,16 @@ Thir { ], exprs: [ Expr { - ty: (), - temp_lifetime: Some( - Node(2), - ), - span: $DIR/thir-flat.rs:4:15: 4:17 (#0), kind: Block { block: b0, }, - }, - Expr { ty: (), temp_lifetime: Some( Node(2), ), span: $DIR/thir-flat.rs:4:15: 4:17 (#0), + }, + Expr { kind: Scope { region_scope: Node(2), lint_level: Explicit( @@ -39,18 +34,23 @@ Thir { ), value: e0, }, - }, - Expr { ty: (), temp_lifetime: Some( Node(2), ), span: $DIR/thir-flat.rs:4:15: 4:17 (#0), + }, + Expr { kind: Scope { region_scope: Destruction(2), lint_level: Inherited, value: e1, }, + ty: (), + temp_lifetime: Some( + Node(2), + ), + span: $DIR/thir-flat.rs:4:15: 4:17 (#0), }, ], stmts: [], diff --git a/tests/ui/thread-local/tls.rs b/tests/ui/thread-local/tls.rs index fbd3413885f..f03bd3f991b 100644 --- a/tests/ui/thread-local/tls.rs +++ b/tests/ui/thread-local/tls.rs @@ -1,6 +1,7 @@ // run-pass // ignore-emscripten no threads support // compile-flags: -O +// ignore-nto Doesn't work without emulated TLS enabled (in LLVM) #![feature(thread_local)] diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs new file mode 100644 index 00000000000..3903bfe9bcf --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.rs @@ -0,0 +1,11 @@ +#![feature(non_lifetime_binders, generic_const_exprs)] +//~^ WARN the feature `non_lifetime_binders` is incomplete +//~| WARN the feature `generic_const_exprs` is incomplete + +fn foo() -> usize +where + for<T> [i32; { let _: T = todo!(); 0 }]:, + //~^ ERROR cannot capture late-bound type parameter in a constant +{} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr new file mode 100644 index 00000000000..fafff02dea6 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-bound-in-anon-ct.stderr @@ -0,0 +1,27 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/late-bound-in-anon-ct.rs:1:12 + | +LL | #![feature(non_lifetime_binders, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/late-bound-in-anon-ct.rs:1:34 + | +LL | #![feature(non_lifetime_binders, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information + +error: cannot capture late-bound type parameter in a constant + --> $DIR/late-bound-in-anon-ct.rs:7:27 + | +LL | for<T> [i32; { let _: T = todo!(); 0 }]:, + | - ^ + | | + | parameter defined here + +error: aborting due to previous error; 2 warnings emitted + diff --git a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs new file mode 100644 index 00000000000..9830241c377 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.rs @@ -0,0 +1,7 @@ +// check-pass +// compile-flags: --crate-type=lib + +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +pub fn f<T>() where for<U> (T, U): Copy {} diff --git a/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr new file mode 100644 index 00000000000..667575b72d4 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/object-lifetime-default-for-late.stderr @@ -0,0 +1,11 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/object-lifetime-default-for-late.rs:4:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information + = note: `#[warn(incomplete_features)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr index 0ed8a703b6d..e52d5f9de69 100644 --- a/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr +++ b/tests/ui/type-alias-impl-trait/imply_bounds_from_bounds_param.stderr @@ -2,7 +2,9 @@ error[E0700]: hidden type for `impl PlusOne` captures lifetime that does not app --> $DIR/imply_bounds_from_bounds_param.rs:24:5 | LL | fn test<'a>(y: &'a mut i32) -> impl PlusOne { - | -- hidden type `<&'a mut i32 as Callable>::Output` captures the lifetime `'a` as defined here + | -- ------------ opaque type defined here + | | + | hidden type `<&'a mut i32 as Callable>::Output` captures the lifetime `'a` as defined here LL | <&'a mut i32 as Callable>::call(y) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | diff --git a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr index 65a0af0d22f..d666e668d36 100644 --- a/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr +++ b/tests/ui/type-alias-impl-trait/missing_lifetime_bound.stderr @@ -1,6 +1,8 @@ error[E0700]: hidden type for `Opaque<'a, T>` captures lifetime that does not appear in bounds --> $DIR/missing_lifetime_bound.rs:4:47 | +LL | type Opaque<'a, T> = impl Sized; + | ---------- opaque type defined here LL | fn defining<'a, T>(x: &'a i32) -> Opaque<T> { x } | -- ^ | | diff --git a/tests/ui/type/issue-91268.rs b/tests/ui/type/issue-91268.rs index f1e16bc7bd3..274ea839e8b 100644 --- a/tests/ui/type/issue-91268.rs +++ b/tests/ui/type/issue-91268.rs @@ -1,8 +1,4 @@ // error-pattern: this file contains an unclosed delimiter -// error-pattern: cannot find type `ţ` in this scope -// error-pattern: parenthesized type parameters may only be used with a `Fn` trait -// error-pattern: type arguments are not allowed on builtin type `u8` -// error-pattern: mismatched types // ignore-tidy-trailing-newlines // `ţ` must be the last character in this file, it cannot be followed by a newline fn main() { diff --git a/tests/ui/type/issue-91268.stderr b/tests/ui/type/issue-91268.stderr index 6c9ee994584..a3619d863e2 100644 --- a/tests/ui/type/issue-91268.stderr +++ b/tests/ui/type/issue-91268.stderr @@ -1,5 +1,5 @@ error: this file contains an unclosed delimiter - --> $DIR/issue-91268.rs:9:12 + --> $DIR/issue-91268.rs:5:12 | LL | fn main() { | - unclosed delimiter @@ -8,56 +8,5 @@ LL | 0: u8(ţ | | | unclosed delimiter -error: this file contains an unclosed delimiter - --> $DIR/issue-91268.rs:9:12 - | -LL | fn main() { - | - unclosed delimiter -LL | 0: u8(ţ - | - ^ - | | - | unclosed delimiter - -error[E0412]: cannot find type `ţ` in this scope - --> $DIR/issue-91268.rs:9:11 - | -LL | 0: u8(ţ - | ^ expecting a type here because of type ascription - -error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-91268.rs:9:8 - | -LL | 0: u8(ţ - | ^^^^ only `Fn` traits may use parentheses - | -help: use angle brackets instead - | -LL | 0: u8<ţ> - | ~ + - -error[E0109]: type arguments are not allowed on builtin type `u8` - --> $DIR/issue-91268.rs:9:11 - | -LL | 0: u8(ţ - | -- ^ type argument not allowed - | | - | not allowed on builtin type `u8` - | -help: primitive type `u8` doesn't have generic parameters - | -LL - 0: u8(ţ -LL + 0: u8 - | - -error[E0308]: mismatched types - --> $DIR/issue-91268.rs:9:5 - | -LL | fn main() { - | - expected `()` because of default return type -LL | 0: u8(ţ - | ^^^^^^^ expected `()`, found `u8` - -error: aborting due to 6 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0109, E0214, E0308, E0412. -For more information about an error, try `rustc --explain E0109`. diff --git a/tests/ui/typeck/bad-type-in-vec-contains.rs b/tests/ui/typeck/bad-type-in-vec-contains.rs new file mode 100644 index 00000000000..4433047b75a --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-contains.rs @@ -0,0 +1,7 @@ +// The error message here still is pretty confusing. + +fn main() { + let primes = Vec::new(); + primes.contains(3); + //~^ ERROR mismatched types +} diff --git a/tests/ui/typeck/bad-type-in-vec-contains.stderr b/tests/ui/typeck/bad-type-in-vec-contains.stderr new file mode 100644 index 00000000000..0e03388d2d5 --- /dev/null +++ b/tests/ui/typeck/bad-type-in-vec-contains.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/bad-type-in-vec-contains.rs:5:21 + | +LL | primes.contains(3); + | -------- ^ + | | | + | | expected `&_`, found integer + | | help: consider borrowing here: `&3` + | arguments to this method are incorrect + | here the type of `primes` is inferred to be `[_]` + | + = note: expected reference `&_` + found type `{integer}` +note: method defined here + --> $SRC_DIR/core/src/slice/mod.rs:LL:COL + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-31173.stderr b/tests/ui/typeck/issue-31173.stderr index 8346c9a0aae..b622122f33e 100644 --- a/tests/ui/typeck/issue-31173.stderr +++ b/tests/ui/typeck/issue-31173.stderr @@ -24,8 +24,17 @@ note: required by a bound in `cloned` error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut IntoIter<u8>, [closure@issue-31173.rs:7:21]>>`, but its trait bounds were not satisfied --> $DIR/issue-31173.rs:12:10 | -LL | .collect(); - | ^^^^^^^ method cannot be called due to unsatisfied trait bounds +LL | let temp: Vec<u8> = it + | _________________________- +LL | | .take_while(|&x| { +LL | | found_e = true; +LL | | false +LL | | }) +LL | | .cloned() +LL | | .collect(); + | | -^^^^^^^ method cannot be called due to unsatisfied trait bounds + | |_________| + | --> $SRC_DIR/core/src/iter/adapters/take_while.rs:LL:COL | = note: doesn't satisfy `<_ as Iterator>::Item = &_` diff --git a/tests/ui/typeck/issue-91334.rs b/tests/ui/typeck/issue-91334.rs index bf9a5a62620..29204276bb3 100644 --- a/tests/ui/typeck/issue-91334.rs +++ b/tests/ui/typeck/issue-91334.rs @@ -1,9 +1,6 @@ // Regression test for the ICE described in issue #91334. // error-pattern: this file contains an unclosed delimiter -// error-pattern: expected one of -// error-pattern: mismatched closing delimiter -// error-pattern: mismatched types #![feature(generators)] diff --git a/tests/ui/typeck/issue-91334.stderr b/tests/ui/typeck/issue-91334.stderr index 78f392c9a8a..7cb30eea530 100644 --- a/tests/ui/typeck/issue-91334.stderr +++ b/tests/ui/typeck/issue-91334.stderr @@ -1,15 +1,14 @@ -error: this file contains an unclosed delimiter - --> $DIR/issue-91334.rs:10:23 +error: mismatched closing delimiter: `)` + --> $DIR/issue-91334.rs:7:19 | LL | fn f(){||yield(((){), - | - - - ^ - | | | | - | | | missing open `(` for this delimiter - | | unclosed delimiter - | unclosed delimiter + | - ^^ mismatched closing delimiter + | | | + | | unclosed delimiter + | closing delimiter possibly meant for this error: this file contains an unclosed delimiter - --> $DIR/issue-91334.rs:10:23 + --> $DIR/issue-91334.rs:7:23 | LL | fn f(){||yield(((){), | - - - ^ @@ -18,35 +17,5 @@ LL | fn f(){||yield(((){), | | unclosed delimiter | unclosed delimiter -error: expected one of `)`, `,`, `.`, `?`, or an operator, found `{` - --> $DIR/issue-91334.rs:10:19 - | -LL | fn f(){||yield(((){), - | ^ - | | - | expected one of `)`, `,`, `.`, `?`, or an operator - | help: missing `,` - -error: mismatched closing delimiter: `)` - --> $DIR/issue-91334.rs:10:19 - | -LL | fn f(){||yield(((){), - | - ^^ mismatched closing delimiter - | | | - | | unclosed delimiter - | closing delimiter possibly meant for this - -error[E0308]: mismatched types - --> $DIR/issue-91334.rs:10:8 - | -LL | fn f(){||yield(((){), - | -^^^^^^^^^^^^^^^ expected `()`, found generator - | | - | help: a return type might be missing here: `-> _` - | - = note: expected unit type `()` - found generator `[generator@$DIR/issue-91334.rs:10:8: 10:10]` - -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/typeck/issue-92481.rs b/tests/ui/typeck/issue-92481.rs index 0a6b1843d99..f752400bbcb 100644 --- a/tests/ui/typeck/issue-92481.rs +++ b/tests/ui/typeck/issue-92481.rs @@ -2,13 +2,8 @@ #![crate_type="lib"] -fn r({) { - Ok { //~ ERROR mismatched types [E0308] +fn r({) { //~ ERROR mismatched closing delimiter + Ok { d..||_=m } } -//~^^^^^ ERROR expected parameter name, found `{` -//~| ERROR expected one of `,`, `:`, or `}`, found `..` -//~^^^^^ ERROR cannot find value `d` in this scope [E0425] -//~| ERROR cannot find value `m` in this scope [E0425] -//~| ERROR variant `Result<_, _>::Ok` has no field named `d` [E0559] diff --git a/tests/ui/typeck/issue-92481.stderr b/tests/ui/typeck/issue-92481.stderr index c3acbd2c067..d87d3277d56 100644 --- a/tests/ui/typeck/issue-92481.stderr +++ b/tests/ui/typeck/issue-92481.stderr @@ -1,60 +1,11 @@ -error: expected parameter name, found `{` +error: mismatched closing delimiter: `)` --> $DIR/issue-92481.rs:5:6 | LL | fn r({) { - | ^ expected parameter name + | -^^ mismatched closing delimiter + | || + | |unclosed delimiter + | closing delimiter possibly meant for this -error: expected one of `,`, `:`, or `}`, found `..` - --> $DIR/issue-92481.rs:5:6 - | -LL | fn r({) { - | ^ unclosed delimiter -LL | Ok { -LL | d..||_=m - | -^ - | | - | help: `}` may belong here - -error[E0425]: cannot find value `d` in this scope - --> $DIR/issue-92481.rs:7:9 - | -LL | d..||_=m - | ^ not found in this scope - -error[E0425]: cannot find value `m` in this scope - --> $DIR/issue-92481.rs:7:16 - | -LL | d..||_=m - | ^ not found in this scope - -error[E0559]: variant `Result<_, _>::Ok` has no field named `d` - --> $DIR/issue-92481.rs:7:9 - | -LL | d..||_=m - | ^ field does not exist - --> $SRC_DIR/core/src/result.rs:LL:COL - | - = note: `Result<_, _>::Ok` defined here - | -help: `Result<_, _>::Ok` is a tuple variant, use the appropriate syntax - | -LL | Result<_, _>::Ok(/* fields */) - | - -error[E0308]: mismatched types - --> $DIR/issue-92481.rs:6:5 - | -LL | fn r({) { - | - help: a return type might be missing here: `-> _` -LL | / Ok { -LL | | d..||_=m -LL | | } - | |_____^ expected `()`, found `Result<_, _>` - | - = note: expected unit type `()` - found enum `Result<_, _>` - -error: aborting due to 6 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0308, E0425, E0559. -For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/wait-forked-but-failed-child.rs index 674c26a43f2..82a1dd63713 100644 --- a/tests/ui/wait-forked-but-failed-child.rs +++ b/tests/ui/wait-forked-but-failed-child.rs @@ -3,6 +3,7 @@ // ignore-sgx no processes // ignore-vxworks no 'ps' // ignore-fuchsia no 'ps' +// ignore-nto no 'ps' #![feature(rustc_private)] diff --git a/tests/ui/while/while-else-err.rs b/tests/ui/while/while-else-err.rs new file mode 100644 index 00000000000..36b60fbd4be --- /dev/null +++ b/tests/ui/while/while-else-err.rs @@ -0,0 +1,8 @@ +fn main() { + while false { + //~^ NOTE `else` is attached to this loop + } else { + //~^ ERROR `while...else` loops are not supported + //~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + }; +} diff --git a/tests/ui/while/while-else-err.stderr b/tests/ui/while/while-else-err.stderr new file mode 100644 index 00000000000..88f715d5666 --- /dev/null +++ b/tests/ui/while/while-else-err.stderr @@ -0,0 +1,17 @@ +error: `while...else` loops are not supported + --> $DIR/while-else-err.rs:4:7 + | +LL | while false { + | ----- `else` is attached to this loop +LL | +LL | } else { + | _______^ +LL | | +LL | | +LL | | }; + | |_____^ + | + = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + +error: aborting due to previous error + diff --git a/tests/ui/while/while-else-let-else-err.rs b/tests/ui/while/while-else-let-else-err.rs new file mode 100644 index 00000000000..6d9909347c3 --- /dev/null +++ b/tests/ui/while/while-else-let-else-err.rs @@ -0,0 +1,8 @@ +fn main() { + let _ = while false { + //~^ NOTE `else` is attached to this loop + } else { + //~^ ERROR `while...else` loops are not supported + //~| NOTE consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + }; +} diff --git a/tests/ui/while/while-else-let-else-err.stderr b/tests/ui/while/while-else-let-else-err.stderr new file mode 100644 index 00000000000..431d37c007c --- /dev/null +++ b/tests/ui/while/while-else-let-else-err.stderr @@ -0,0 +1,17 @@ +error: `while...else` loops are not supported + --> $DIR/while-else-let-else-err.rs:4:7 + | +LL | let _ = while false { + | ----- `else` is attached to this loop +LL | +LL | } else { + | _______^ +LL | | +LL | | +LL | | }; + | |_____^ + | + = note: consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run + +error: aborting due to previous error + |
