diff --git a/Cargo.lock b/Cargo.lock index 52c9269fa87f0..818743b135b51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,6 +186,48 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "askama" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash 2.1.1", + "serde", + "serde_derive", + "syn 2.0.100", +] + +[[package]] +name = "askama_parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow 0.7.4", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -1345,8 +1387,8 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", + "askama", "cargo_metadata 0.18.1", - "rinja", "serde", "serde_json", "thiserror 1.0.69", @@ -3069,9 +3111,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5" dependencies = [ - "humansize", "itoa", - "percent-encoding", "rinja_derive", ] @@ -4628,6 +4668,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "arrayvec", + "askama", "base64", "expect-test", "indexmap", @@ -4636,7 +4677,6 @@ dependencies = [ "pulldown-cmark 0.9.6", "pulldown-cmark-escape", "regex", - "rinja", "rustdoc-json-types", "serde", "serde_json", @@ -5426,7 +5466,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -6437,6 +6477,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +dependencies = [ + "memchr", +] + [[package]] name = "winsplit" version = "0.1.0" diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 2a98821f22529..0927f648635ce 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -28,7 +28,7 @@ # - A new option # - A change in the default values # -# If the change-id does not match the version currently in use, x.py will +# If the change-id does not match the version currently in use, x.py will # display the changes made to the bootstrap. # To suppress these warnings, you can set change-id = "ignore". #change-id = @@ -442,6 +442,9 @@ # What custom diff tool to use for displaying compiletest tests. #compiletest-diff-tool = +# Whether to use the precompiled stage0 libtest with compiletest. +#compiletest-use-stage0-libtest = true + # Indicates whether ccache is used when building certain artifacts (e.g. LLVM). # Set to `true` to use the first `ccache` in PATH, or set an absolute path to use # a specific version. diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 7e355b6406aed..eade9e52de95a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -9,6 +9,7 @@ use rustc_middle::mir::{self, ConstValue}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, span_bug}; +use rustc_session::config::OptLevel; use tracing::{debug, instrument}; use super::place::{PlaceRef, PlaceValue}; @@ -496,6 +497,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), }; + // Layout ensures that we only get here for cases where the discriminant + // value and the variant index match, since that's all `Niche` can encode. + // But for emphasis and debugging, let's double-check one anyway. + debug_assert_eq!( + self.layout + .ty + .discriminant_for_variant(bx.tcx(), untagged_variant) + .unwrap() + .val, + u128::from(untagged_variant.as_u32()), + ); + let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); // We have a subrange `niche_start..=niche_end` inside `range`. @@ -537,6 +550,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { relative_discr, bx.cx().const_uint(tag_llty, relative_max as u64), ); + + // Thanks to parameter attributes and load metadata, LLVM already knows + // the general valid range of the tag. It's possible, though, for there + // to be an impossible value *in the middle*, which those ranges don't + // communicate, so it's worth an `assume` to let the optimizer know. + if niche_variants.contains(&untagged_variant) + && bx.cx().sess().opts.optimize != OptLevel::No + { + let impossible = + u64::from(untagged_variant.as_u32() - niche_variants.start().as_u32()); + let impossible = bx.cx().const_uint(tag_llty, impossible); + let ne = bx.icmp(IntPredicate::IntNE, relative_discr, impossible); + bx.assume(ne); + } + (is_niche, cast_tag, niche_variants.start().as_u32() as u128) }; @@ -553,7 +581,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { ); // In principle we could insert assumes on the possible range of `discr`, but - // currently in LLVM this seems to be a pessimization. + // currently in LLVM this isn't worth it because the original `tag` will + // have either a `range` parameter attribute or `!range` metadata, + // or come from a `transmute` that already `assume`d it. discr } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 194f2cd04e468..2f7c3cb3c7d80 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -486,6 +486,9 @@ hir_analysis_self_in_impl_self = `Self` is not valid in the self type of an impl block .note = replace `Self` with a different type +hir_analysis_self_in_type_alias = `Self` is not allowed in type aliases + .label = `Self` is only available in impls, traits, and concrete type definitions + hir_analysis_self_ty_not_captured = `impl Trait` must mention the `Self` type of the trait in `use<...>` .label = `Self` type parameter is implicitly captured by this `impl Trait` .note = currently, all type parameters are required to be mentioned in the precise captures list diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f2560f22874bc..e6090a128b1c8 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1707,3 +1707,11 @@ pub(crate) enum SupertraitItemShadowee { traits: DiagSymbolList, }, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_self_in_type_alias, code = E0411)] +pub(crate) struct SelfInTypeAlias { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index aeebe45f881ff..e64cd8ec302c7 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -16,6 +16,7 @@ use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; use super::HirTyLowerer; +use crate::errors::SelfInTypeAlias; use crate::hir_ty_lowering::{ GenericArgCountMismatch, GenericArgCountResult, PredicateFilter, RegionInferReason, }; @@ -125,6 +126,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // ``` let mut projection_bounds = FxIndexMap::default(); for (proj, proj_span) in elaborated_projection_bounds { + let proj = proj.map_bound(|mut b| { + if let Some(term_ty) = &b.term.as_type() { + let references_self = term_ty.walk().any(|arg| arg == dummy_self.into()); + if references_self { + // With trait alias and type alias combined, type resolver + // may not be able to catch all illegal `Self` usages (issue 139082) + let guar = tcx.dcx().emit_err(SelfInTypeAlias { span }); + b.term = replace_dummy_self_with_error(tcx, b.term, guar); + } + } + b + }); + let key = ( proj.skip_binder().projection_term.def_id, tcx.anonymize_bound_vars( diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index c01b81563dcf7..64c1a78bd1c8b 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt, TypingMode, fold_regions}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode, fold_regions}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::debug; @@ -77,6 +77,15 @@ fn diagnostic_hir_wf_check<'tcx>( let tcx_ty = fold_regions(self.tcx, tcx_ty, |r, _| { if r.is_bound() { self.tcx.lifetimes.re_erased } else { r } }); + + // We may be checking the WFness of a type in an opaque with a non-lifetime bound. + // Perhaps we could rebind all the escaping bound vars, but they're coming from + // arbitrary debruijn indices and aren't particularly important anyways, since they + // are only coming from `feature(non_lifetime_binders)` anyways. + if tcx_ty.has_escaping_bound_vars() { + return; + } + let cause = traits::ObligationCause::new( ty.span, self.def_id, diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index a0faa5e8429e5..780c27d45954d 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -24,8 +24,8 @@ pub(super) fn infer_predicates( // If new predicates were added then we need to re-calculate // all crates since there could be new implied predicates. - loop { - let mut predicates_added = false; + for i in 0.. { + let mut predicates_added = vec![]; // Visit all the crates and infer predicates for id in tcx.hir_free_items() { @@ -83,14 +83,27 @@ pub(super) fn infer_predicates( .get(&item_did.to_def_id()) .map_or(0, |p| p.as_ref().skip_binder().len()); if item_required_predicates.len() > item_predicates_len { - predicates_added = true; + predicates_added.push(item_did); global_inferred_outlives .insert(item_did.to_def_id(), ty::EarlyBinder::bind(item_required_predicates)); } } - if !predicates_added { + if predicates_added.is_empty() { + // We've reached a fixed point. break; + } else if !tcx.recursion_limit().value_within_limit(i) { + let msg = if let &[id] = &predicates_added[..] { + format!("overflow computing implied lifetime bounds for `{}`", tcx.def_path_str(id),) + } else { + "overflow computing implied lifetime bounds".to_string() + }; + tcx.dcx() + .struct_span_fatal( + predicates_added.iter().map(|id| tcx.def_span(*id)).collect::>(), + msg, + ) + .emit(); } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 952a2e231e405..3475d15e94832 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2205,8 +2205,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap(); self.dcx() .struct_span_err( - span.shrink_to_hi(), - format!("missing mandatory field{s} {fields}"), + span.shrink_to_lo(), + format!("missing field{s} {fields} in initializer"), + ) + .with_span_label( + span.shrink_to_lo(), + "fields that do not have a defaulted value must be provided explicitly", ) .emit(); return; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 3b0861a9942a6..fafd1b1ae007e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -782,9 +782,16 @@ impl<'a> Parser<'a> { // Recovery is disabled when parsing macro arguments, so it must // also be disabled when reparsing pasted macro arguments, // otherwise we get inconsistent results (e.g. #137874). - let res = self.with_recovery(Recovery::Forbidden, |this| { - f(this).expect("failed to reparse {mv_kind:?}") - }); + let res = self.with_recovery(Recovery::Forbidden, |this| f(this)); + + let res = match res { + Ok(res) => res, + Err(err) => { + // This can occur in unusual error cases, e.g. #139445. + err.delay_as_bug(); + return None; + } + }; if let token::CloseDelim(delim) = self.token.kind && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim @@ -793,7 +800,12 @@ impl<'a> Parser<'a> { self.bump(); Some(res) } else { - panic!("no close delim when reparsing {mv_kind:?}"); + // This can occur when invalid syntax is passed to a decl macro. E.g. see #139248, + // where the reparse attempt of an invalid expr consumed the trailing invisible + // delimiter. + self.dcx() + .span_delayed_bug(self.token.span, "no close delim with reparsing {mv_kind:?}"); + None } } else { None diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2cb7d2d893135..9d5eb551fe6f7 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1090,26 +1090,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. - let iter = data_a - .principal() - .filter(|_| { - // optionally drop the principal, if we're unsizing to no principal - data_b.principal().is_some() - }) - .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) - .into_iter() - .chain( + let existential_predicates = if data_b.principal().is_some() { + tcx.mk_poly_existential_predicates_from_iter( data_a - .projection_bounds() - .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + .principal() + .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) + .into_iter() + .chain( + data_a + .projection_bounds() + .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), + ) + .chain( + data_b + .auto_traits() + .map(ty::ExistentialPredicate::AutoTrait) + .map(ty::Binder::dummy), + ), ) - .chain( + } else { + // If we're unsizing to a dyn type that has no principal, then drop + // the principal and projections from the type. We use the auto traits + // from the RHS type since as we noted that we've checked for auto + // trait compatibility during unsizing. + tcx.mk_poly_existential_predicates_from_iter( data_b .auto_traits() .map(ty::ExistentialPredicate::AutoTrait) .map(ty::Binder::dummy), - ); - let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(iter); + ) + }; let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b, dyn_a); // Require that the traits involved in this upcast are **equal**; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 7fa57df9928c3..933b5aec70c63 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -5,15 +5,11 @@ //! //! # Const intrinsics //! -//! Note: any changes to the constness of intrinsics should be discussed with the language team. -//! This includes changes in the stability of the constness. -//! -//! //FIXME(#132735) "old" style intrinsics support has been removed -//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new" -//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the -//! implementation from to +//! In order to make an intrinsic unstable usable at compile-time, copy the implementation from +//! to //! -//! and make the intrinsic declaration a `const fn`. +//! and make the intrinsic declaration below a `const fn`. This should be done in coordination with +//! wg-const-eval. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, //! `#[rustc_intrinsic_const_stable_indirect]` needs to be added to the intrinsic. Such a change requires diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml index 7b381b416ca8a..f2cbe512b5e4a 100644 --- a/src/bootstrap/defaults/bootstrap.dist.toml +++ b/src/bootstrap/defaults/bootstrap.dist.toml @@ -7,6 +7,8 @@ test-stage = 2 doc-stage = 2 # When compiling from source, you usually want all tools. extended = true +# Use libtest built from the source tree instead of the precompiled one from stage 0. +compiletest-use-stage0-libtest = false # Most users installing from source want to build all parts of the project from source. [llvm] diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index e67bc62a60352..b191d0f6b306b 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -369,6 +369,69 @@ impl Step for RustAnalyzer { } } +/// Compiletest is implicitly "checked" when it gets built in order to run tests, +/// so this is mainly for people working on compiletest to run locally. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Compiletest { + pub target: TargetSelection, +} + +impl Step for Compiletest { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/compiletest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Compiletest { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) { + let mode = if builder.config.compiletest_use_stage0_libtest { + Mode::ToolBootstrap + } else { + Mode::ToolStd + }; + + let compiler = builder.compiler( + if mode == Mode::ToolBootstrap { 0 } else { builder.top_stage }, + builder.config.build, + ); + + if mode != Mode::ToolBootstrap { + builder.ensure(Rustc::new(self.target, builder)); + } + + let mut cargo = prepare_tool_cargo( + builder, + compiler, + mode, + self.target, + builder.kind, + "src/tools/compiletest", + SourceType::InTree, + &[], + ); + + cargo.allow_features("test"); + + // For ./x.py clippy, don't run with --all-targets because + // linting tests and benchmarks can produce very noisy results + if builder.kind != Kind::Clippy { + cargo.arg("--all-targets"); + } + + let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, self.target)) + .with_prefix("compiletest-check"); + + let _guard = builder.msg_check("compiletest artifacts", self.target); + run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + } +} + macro_rules! tool_check_step { ( $name:ident { @@ -464,7 +527,3 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false }); - -// Compiletest is implicitly "checked" when it gets built in order to run tests, -// so this is mainly for people working on compiletest to run locally. -tool_check_step!(Compiletest { path: "src/tools/compiletest", default: false }); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 18b5d4426b1ee..dab58fccf5e68 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -2398,7 +2398,9 @@ pub fn run_cargo( // Ok now we need to actually find all the files listed in `toplevel`. We've // got a list of prefix/extensions and we basically just need to find the // most recent file in the `deps` folder corresponding to each one. - let contents = t!(target_deps_dir.read_dir()) + let contents = target_deps_dir + .read_dir() + .unwrap_or_else(|e| panic!("Couldn't read {}: {}", target_deps_dir.display(), e)) .map(|e| t!(e)) .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata()))) .collect::>(); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index cd57e06ae04a3..b58d279359e30 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -425,11 +425,14 @@ macro_rules! bootstrap_tool { } )* + let is_unstable = false $(|| $unstable)*; + let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest; + builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, tool: $tool_name, - mode: if false $(|| $unstable)* { + mode: if is_unstable && !compiletest_wants_stage0 { // use in-tree libraries for unstable features Mode::ToolStd } else { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1712be7f947fa..d83731e0f0898 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -417,6 +417,9 @@ pub struct Config { /// Command for visual diff display, e.g. `diff-tool --color=always`. pub compiletest_diff_tool: Option, + /// Whether to use the precompiled stage0 libtest with compiletest. + pub compiletest_use_stage0_libtest: bool, + pub is_running_on_ci: bool, } @@ -983,6 +986,7 @@ define_config! { optimized_compiler_builtins: Option = "optimized-compiler-builtins", jobs: Option = "jobs", compiletest_diff_tool: Option = "compiletest-diff-tool", + compiletest_use_stage0_libtest: Option = "compiletest-use-stage0-libtest", ccache: Option = "ccache", exclude: Option> = "exclude", } @@ -1682,6 +1686,7 @@ impl Config { optimized_compiler_builtins, jobs, compiletest_diff_tool, + compiletest_use_stage0_libtest, mut ccache, exclude, } = toml.build.unwrap_or_default(); @@ -2415,6 +2420,7 @@ impl Config { config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); config.compiletest_diff_tool = compiletest_diff_tool; + config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true); let download_rustc = config.download_rustc_commit.is_some(); config.explicit_stage_from_cli = flags.stage.is_some(); diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 244391739f38a..48b6f77e8a587 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -391,4 +391,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "You can now use `change-id = \"ignore\"` to suppress `change-id ` warnings in the console.", }, + ChangeInfo { + change_id: 139386, + severity: ChangeSeverity::Info, + summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.", + }, ]; diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs index dbfd6f47dc67f..aa564b4a04513 100644 --- a/src/bootstrap/src/utils/proc_macro_deps.rs +++ b/src/bootstrap/src/utils/proc_macro_deps.rs @@ -5,6 +5,7 @@ pub static CRATES: &[&str] = &[ // tidy-alphabetical-start "annotate-snippets", "anstyle", + "askama_parser", "basic-toml", "block-buffer", "bumpalo", @@ -64,6 +65,7 @@ pub static CRATES: &[&str] = &[ "wasm-bindgen-backend", "wasm-bindgen-macro-support", "wasm-bindgen-shared", + "winnow", "yoke", "zerofrom", "zerovec", diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml index 3593b3f7df633..d81be88b70872 100644 --- a/src/ci/citool/tests/test-jobs.yml +++ b/src/ci/citool/tests/test-jobs.yml @@ -27,7 +27,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 8bb7116c3ec58..418408e9242ae 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -47,6 +47,7 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ ENV SCRIPT \ python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \ /scripts/check-default-config-profiles.sh && \ + python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py check --target=x86_64-pc-windows-gnu --host=x86_64-pc-windows-gnu && \ python3 ../x.py clippy ci && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 89806634c6c26..05c90af780732 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -101,4 +101,5 @@ COPY scripts/shared.sh /scripts/ # the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ + python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \ python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 68e680a1b1b79..fbda749b6a2a8 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -58,7 +58,7 @@ runners: <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 # Ensure that host tooling is tested on our minimum supported macOS version. diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index a0e38f340f581..9e59dd889985c 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -53,7 +53,8 @@ Various intrinsics have native MIR operations that they correspond to. Instead o backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass will convert the calls to the MIR operation. Backends do not need to know about these intrinsics at all. These intrinsics only make sense without a body, and can be declared as a `#[rustc_intrinsic]`. -The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses. +The body is never used as the lowering pass implements support for all backends, so we never have to +use the fallback logic. ## Intrinsics without fallback logic diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 909b81a723b48..27ae0553c60de 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } -rinja = { version = "0.3", default-features = false, features = ["config"] } +askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" itertools = "0.12" indexmap = "2" diff --git a/src/librustdoc/rinja.toml b/src/librustdoc/askama.toml similarity index 100% rename from src/librustdoc/rinja.toml rename to src/librustdoc/askama.toml diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index df70df062fe0b..44b3be23914c2 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,7 +1,7 @@ use std::fmt::{self, Display}; use std::path::PathBuf; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::FxIndexMap; use super::static_files::{STATIC_FILES, StaticFiles}; diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 5f69e79f3ab1f..e2d1f58a37ecb 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -5,7 +5,7 @@ use std::io; use std::path::{Path, PathBuf}; use std::sync::mpsc::{Receiver, channel}; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 2237e0f987bc5..3512dff0865c5 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -43,7 +43,7 @@ use std::iter::Peekable; use std::path::PathBuf; use std::{fs, str}; -use rinja::Template; +use askama::Template; use rustc_attr_parsing::{ ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 3c5c2ce19767d..96847f13f655c 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2,7 +2,7 @@ use std::cmp::Ordering; use std::fmt::{self, Display, Write as _}; use std::iter; -use rinja::Template; +use askama::Template; use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir as hir; @@ -37,7 +37,7 @@ use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::render::{document_full, document_item_info}; use crate::html::url_parts_builder::UrlPartsBuilder; -/// Generates a Rinja template struct for rendering items with common methods. +/// Generates an Askama template struct for rendering items with common methods. /// /// Usage: /// ```ignore (illustrative) @@ -301,7 +301,7 @@ fn toggle_close(mut w: impl fmt::Write) { w.write_str("").unwrap(); } -trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display { +trait ItemTemplate<'a, 'cx: 'a>: askama::Template + Display { fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>); } @@ -1867,7 +1867,7 @@ fn item_proc_macro(cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) -> } } } - Ok(()) + fmt::Result::Ok(()) })?; write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) }) @@ -1944,7 +1944,7 @@ fn item_constant( } } } - Ok(()) + Ok::<(), fmt::Error>(()) })?; write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 89ff61ecb03e4..cd0c9775f5c97 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use std::cmp::Ordering; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::CtorKind; use rustc_hir::def_id::{DefIdMap, DefIdSet}; @@ -123,10 +123,10 @@ impl<'a> Link<'a> { pub(crate) mod filters { use std::fmt::{self, Display}; - use rinja::filters::Safe; + use askama::filters::Safe; use crate::html::escape::EscapeBodyTextWithWbr; - pub(crate) fn wrapped(v: T) -> rinja::Result> + pub(crate) fn wrapped(v: T) -> askama::Result> where T: Display, { diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index a1ee5c8c548b7..fb1f0271c2ad7 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -1,6 +1,6 @@ use std::fmt; -use rinja::Template; +use askama::Template; use rustc_abi::{Primitive, TagEncoding, Variants}; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index cbbd4b01d83ed..095795c711d9c 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -3,7 +3,7 @@ use std::ffi::OsStr; use std::path::{Component, Path, PathBuf}; use std::{fmt, fs}; -use rinja::Template; +use askama::Template; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md index 32bacb11475cf..12c2553cffdbb 100644 --- a/src/librustdoc/html/templates/STYLE.md +++ b/src/librustdoc/html/templates/STYLE.md @@ -1,13 +1,13 @@ # Style for Templates -This directory has templates in the [Rinja templating language][rinjadoc], which is very +This directory has templates in the [Askama templating language][askamadoc], which is very similar to [Jinja2][jinjadoc]. [jinjadoc]: https://jinja.palletsprojects.com/en/3.1.x/templates/ -[rinjadoc]: https://docs.rs/rinja/latest/rinja/ +[askamadoc]: https://docs.rs/askama/latest/askama/ We want our rendered output to have as little unnecessary whitespace as -possible, so that pages load quickly. To achieve that we use Rinja's +possible, so that pages load quickly. To achieve that we use Askama's [whitespace control] features. By default, whitespace characters are removed around jinja tags (`{% %}` for example). At the end of most lines, we put an empty comment tag: `{# #}`. This causes all whitespace between the end of the @@ -18,7 +18,7 @@ remove following whitespace but not preceding. We also use the whitespace control characters in most instances of tags with control flow, for example `{% if foo %}`. -[whitespace control]: https://rinja.readthedocs.io/en/stable/configuration.html#whitespace-control +[whitespace control]: https://askama.readthedocs.io/en/stable/configuration.html#whitespace-control We want our templates to be readable, so we use indentation and newlines liberally. We indent by four spaces after opening an HTML tag _or_ a Jinja @@ -26,11 +26,11 @@ tag. In most cases an HTML tag should be followed by a newline, but if the tag has simple contents and fits with its close tag on a single line, the contents don't necessarily need a new line. -Rinja templates support quite sophisticated control flow. To keep our templates +Askama templates support quite sophisticated control flow. To keep our templates simple and understandable, we use only a subset: `if` and `for`. In particular -we avoid [assignments in the template logic][assignments] and [Rinja +we avoid [assignments in the template logic][assignments] and [Askama macros][macros]. This also may make things easier if we switch to a different Jinja-style template system in the future. -[assignments]: https://rinja.readthedocs.io/en/stable/template_syntax.html#assignments -[macros]: https://rinja.readthedocs.io/en/stable/template_syntax.html#macros +[assignments]: https://askama.readthedocs.io/en/stable/template_syntax.html#assignments +[macros]: https://askama.readthedocs.io/en/stable/template_syntax.html#macros diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index 404101abd41bf..ab76d0fc01e78 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -8,8 +8,8 @@ description = "Produces a manifest of all the copyrighted materials in the Rust [dependencies] anyhow = "1.0.65" +askama = "0.13.0" cargo_metadata = "0.18.1" -rinja = "0.3.0" serde = { version = "1.0.147", features = ["derive"] } serde_json = "1.0.85" thiserror = "1" diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs index 79e90d88f4446..d6ed7261b7c87 100644 --- a/src/tools/generate-copyright/src/main.rs +++ b/src/tools/generate-copyright/src/main.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use anyhow::Error; -use rinja::Template; +use askama::Template; mod cargo_metadata; @@ -117,7 +117,7 @@ struct Metadata { } /// Describes one node in our metadata tree -#[derive(serde::Deserialize, rinja::Template, Clone, Debug, PartialEq, Eq)] +#[derive(serde::Deserialize, Template, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "kebab-case", tag = "type")] #[template(path = "Node.html")] pub(crate) enum Node { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 5dfd826d7f966..80a2d4690d4a2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -6882,85 +6882,14 @@ pub fn foo() {} #[test] fn hover_feature() { - check( - r#"#![feature(intrinsics$0)]"#, - expect![[r#" - *intrinsics* - ``` - intrinsics - ``` - ___ - - # `intrinsics` - - The tracking issue for this feature is: None. - - Intrinsics are rarely intended to be stable directly, but are usually - exported in some sort of stable manner. Prefer using the stable interfaces to - the intrinsic directly when you can. - - ------------------------ - - - ## Intrinsics with fallback logic - - Many intrinsics can be written in pure rust, albeit inefficiently or without supporting - some features that only exist on some backends. Backends can simply not implement those - intrinsics without causing any code miscompilations or failures to compile. - All intrinsic fallback bodies are automatically made cross-crate inlineable (like `#[inline]`) - by the codegen backend, but not the MIR inliner. - - ```rust - #![feature(intrinsics)] - #![allow(internal_features)] - - #[rustc_intrinsic] - const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} - ``` - - Since these are just regular functions, it is perfectly ok to create the intrinsic twice: - - ```rust - #![feature(intrinsics)] - #![allow(internal_features)] - - #[rustc_intrinsic] - const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} - - mod foo { - #[rustc_intrinsic] - const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) { - panic!("noisy const dealloc") - } - } - - ``` - - The behaviour on backends that override the intrinsic is exactly the same. On other - backends, the intrinsic behaviour depends on which implementation is called, just like - with any regular function. - - ## Intrinsics lowered to MIR instructions - - Various intrinsics have native MIR operations that they correspond to. Instead of requiring - backends to implement both the intrinsic and the MIR operation, the `lower_intrinsics` pass - will convert the calls to the MIR operation. Backends do not need to know about these intrinsics - at all. These intrinsics only make sense without a body, and can be as a `#[rustc_intrinsic]`. - The body is never used, as calls to the intrinsic do not exist anymore after MIR analyses. - - ## Intrinsics without fallback logic - - These must be implemented by all backends. - - ### `#[rustc_intrinsic]` declarations - - These are written like intrinsics with fallback bodies, but the body is irrelevant. - Use `loop {}` for the body or call the intrinsic recursively and add - `#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't - invoke the body. - - "#]], - ) + let (analysis, position) = fixture::position(r#"#![feature(intrinsics$0)]"#); + analysis + .hover( + &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, + FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + ) + .unwrap() + .unwrap(); } #[test] diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs index a24b98050d232..6e185cf89329c 100644 --- a/tests/codegen/enum/enum-match.rs +++ b/tests/codegen/enum/enum-match.rs @@ -1,21 +1,26 @@ //@ compile-flags: -Copt-level=1 -//@ only-x86_64 +//@ only-64bit #![crate_type = "lib"] +#![feature(core_intrinsics)] // Check each of the 3 cases for `codegen_get_discr`. +// FIXME: once our min-bar LLVM has `range` attributes, update the various +// tests here to no longer have the `range`s and `nsw`s as optional. + // Case 0: One tagged variant. pub enum Enum0 { A(bool), B, } -// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0{{.*}} +// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0) // CHECK-NEXT: start: -// CHECK-NEXT: %1 = icmp eq i8 %0, 2 -// CHECK-NEXT: %2 = and i8 %0, 1 -// CHECK-NEXT: %{{.+}} = select i1 %1, i8 13, i8 %2 +// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2 +// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1 +// CHECK-NEXT: %[[R:.+]] = select i1 %[[IS_B]], i8 13, i8 %[[TRUNC]] +// CHECK-NEXT: ret i8 %[[R]] #[no_mangle] pub fn match0(e: Enum0) -> u8 { use Enum0::*; @@ -32,13 +37,14 @@ pub enum Enum1 { C, } -// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1{{.*}} +// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0) // CHECK-NEXT: start: -// CHECK-NEXT: %1 = add{{( nsw)?}} i8 %0, -2 -// CHECK-NEXT: %2 = zext i8 %1 to i64 -// CHECK-NEXT: %3 = icmp ult i8 %1, 2 -// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1 -// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0 +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 2 +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 +// CHECK-NEXT: switch i64 %[[DISCR]] #[no_mangle] pub fn match1(e: Enum1) -> u8 { use Enum1::*; @@ -92,14 +98,14 @@ pub enum Enum2 { E, } -// CHECK: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2{{.*}} +// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0) // CHECK-NEXT: start: -// CHECK-NEXT: %1 = add i8 %0, 2 -// CHECK-NEXT: %2 = zext i8 %1 to i64 -// CHECK-NEXT: %3 = icmp ult i8 %1, 4 -// CHECK-NEXT: %4 = add nuw nsw i64 %2, 1 -// CHECK-NEXT: %_2 = select i1 %3, i64 %4, i64 0 -// CHECK-NEXT: switch i64 %_2, label {{.*}} [ +// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 4 +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 1 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 0 +// CHECK-NEXT: switch i64 %[[DISCR]] #[no_mangle] pub fn match2(e: Enum2) -> u8 { use Enum2::*; @@ -111,3 +117,357 @@ pub fn match2(e: Enum2) -> u8 { E => 250, } } + +// And make sure it works even if the niched scalar is a pointer. +// (For example, that we don't try to `sub` on pointers.) + +// CHECK-LABEL: define noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null +// CHECK-NEXT: br i1 %[[IS_NULL]] +#[no_mangle] +pub fn match3(e: Option<&u8>) -> i16 { + match e { + Some(r) => *r as _, + None => -1, + } +} + +// If the untagged variant is in the middle, there's an impossible value that's +// not reflected in the `range` parameter attribute, so we assume it away. + +#[derive(PartialEq)] +pub enum MiddleNiche { + A, + B, + C(bool), + D, + E, +} + +// CHECK-LABEL: define noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i8 %[[REL_VAR]], i8 2 +// CHECK-NEXT: switch i8 %[[DISCR]] +#[no_mangle] +pub fn match4(e: MiddleNiche) -> u8 { + use MiddleNiche::*; + match e { + A => 13, + B => 100, + C(b) => b as u8, + D => 200, + E => 250, + } +} + +// CHECK-LABEL: define{{.+}}i1 @match4_is_c(i8{{.+}}%e) +// CHECK-NEXT: start +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %e, -2 +// CHECK-NEXT: %[[NOT_NICHE:.+]] = icmp ugt i8 %[[REL_VAR]], 4 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 2 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: ret i1 %[[NOT_NICHE]] +#[no_mangle] +pub fn match4_is_c(e: MiddleNiche) -> bool { + // Before #139098, this couldn't optimize out the `select` because it looked + // like it was possible for a `2` to be produced on both sides. + + std::intrinsics::discriminant_value(&e) == 2 +} + +// You have to do something pretty obnoxious to get a variant index that doesn't +// fit in the tag size, but it's possible + +pub enum Never {} + +pub enum HugeVariantIndex { + V000(Never), + V001(Never), + V002(Never), + V003(Never), + V004(Never), + V005(Never), + V006(Never), + V007(Never), + V008(Never), + V009(Never), + V010(Never), + V011(Never), + V012(Never), + V013(Never), + V014(Never), + V015(Never), + V016(Never), + V017(Never), + V018(Never), + V019(Never), + V020(Never), + V021(Never), + V022(Never), + V023(Never), + V024(Never), + V025(Never), + V026(Never), + V027(Never), + V028(Never), + V029(Never), + V030(Never), + V031(Never), + V032(Never), + V033(Never), + V034(Never), + V035(Never), + V036(Never), + V037(Never), + V038(Never), + V039(Never), + V040(Never), + V041(Never), + V042(Never), + V043(Never), + V044(Never), + V045(Never), + V046(Never), + V047(Never), + V048(Never), + V049(Never), + V050(Never), + V051(Never), + V052(Never), + V053(Never), + V054(Never), + V055(Never), + V056(Never), + V057(Never), + V058(Never), + V059(Never), + V060(Never), + V061(Never), + V062(Never), + V063(Never), + V064(Never), + V065(Never), + V066(Never), + V067(Never), + V068(Never), + V069(Never), + V070(Never), + V071(Never), + V072(Never), + V073(Never), + V074(Never), + V075(Never), + V076(Never), + V077(Never), + V078(Never), + V079(Never), + V080(Never), + V081(Never), + V082(Never), + V083(Never), + V084(Never), + V085(Never), + V086(Never), + V087(Never), + V088(Never), + V089(Never), + V090(Never), + V091(Never), + V092(Never), + V093(Never), + V094(Never), + V095(Never), + V096(Never), + V097(Never), + V098(Never), + V099(Never), + V100(Never), + V101(Never), + V102(Never), + V103(Never), + V104(Never), + V105(Never), + V106(Never), + V107(Never), + V108(Never), + V109(Never), + V110(Never), + V111(Never), + V112(Never), + V113(Never), + V114(Never), + V115(Never), + V116(Never), + V117(Never), + V118(Never), + V119(Never), + V120(Never), + V121(Never), + V122(Never), + V123(Never), + V124(Never), + V125(Never), + V126(Never), + V127(Never), + V128(Never), + V129(Never), + V130(Never), + V131(Never), + V132(Never), + V133(Never), + V134(Never), + V135(Never), + V136(Never), + V137(Never), + V138(Never), + V139(Never), + V140(Never), + V141(Never), + V142(Never), + V143(Never), + V144(Never), + V145(Never), + V146(Never), + V147(Never), + V148(Never), + V149(Never), + V150(Never), + V151(Never), + V152(Never), + V153(Never), + V154(Never), + V155(Never), + V156(Never), + V157(Never), + V158(Never), + V159(Never), + V160(Never), + V161(Never), + V162(Never), + V163(Never), + V164(Never), + V165(Never), + V166(Never), + V167(Never), + V168(Never), + V169(Never), + V170(Never), + V171(Never), + V172(Never), + V173(Never), + V174(Never), + V175(Never), + V176(Never), + V177(Never), + V178(Never), + V179(Never), + V180(Never), + V181(Never), + V182(Never), + V183(Never), + V184(Never), + V185(Never), + V186(Never), + V187(Never), + V188(Never), + V189(Never), + V190(Never), + V191(Never), + V192(Never), + V193(Never), + V194(Never), + V195(Never), + V196(Never), + V197(Never), + V198(Never), + V199(Never), + V200(Never), + V201(Never), + V202(Never), + V203(Never), + V204(Never), + V205(Never), + V206(Never), + V207(Never), + V208(Never), + V209(Never), + V210(Never), + V211(Never), + V212(Never), + V213(Never), + V214(Never), + V215(Never), + V216(Never), + V217(Never), + V218(Never), + V219(Never), + V220(Never), + V221(Never), + V222(Never), + V223(Never), + V224(Never), + V225(Never), + V226(Never), + V227(Never), + V228(Never), + V229(Never), + V230(Never), + V231(Never), + V232(Never), + V233(Never), + V234(Never), + V235(Never), + V236(Never), + V237(Never), + V238(Never), + V239(Never), + V240(Never), + V241(Never), + V242(Never), + V243(Never), + V244(Never), + V245(Never), + V246(Never), + V247(Never), + V248(Never), + V249(Never), + V250(Never), + V251(Never), + V252(Never), + V253(Never), + V254(Never), + V255(Never), + V256(Never), + + Possible257, + Bool258(bool), + Possible259, +} + +// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0) +// CHECK-NEXT: start: +// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2 +// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64 +// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 3 +// CHECK-NEXT: %[[NOT_IMPOSSIBLE:.+]] = icmp ne i8 %[[REL_VAR]], 1 +// CHECK-NEXT: call void @llvm.assume(i1 %[[NOT_IMPOSSIBLE]]) +// CHECK-NEXT: %[[NICHE_DISCR:.+]] = add nuw nsw i64 %[[REL_VAR_WIDE]], 257 +// CHECK-NEXT: %[[DISCR:.+]] = select i1 %[[IS_NICHE]], i64 %[[NICHE_DISCR]], i64 258 +// CHECK-NEXT: switch i64 %[[DISCR]], +// CHECK-NEXT: i64 257, +// CHECK-NEXT: i64 258, +// CHECK-NEXT: i64 259, +#[no_mangle] +pub fn match5(e: HugeVariantIndex) -> u8 { + use HugeVariantIndex::*; + match e { + Possible257 => 13, + Bool258(b) => b as u8, + Possible259 => 100, + } +} diff --git a/tests/codegen/enum/enum-two-variants-match.rs b/tests/codegen/enum/enum-two-variants-match.rs index 21ae1f96bca7a..12d9edc4d6234 100644 --- a/tests/codegen/enum/enum-two-variants-match.rs +++ b/tests/codegen/enum/enum-two-variants-match.rs @@ -1,8 +1,12 @@ //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -//@ only-x86_64 (because these discriminants are isize) +//@ only-64bit (because these discriminants are isize) #![crate_type = "lib"] +// This directly tests what we emit for these matches, rather than what happens +// after optimization, so it doesn't need to worry about extra flags on the +// instructions and is less susceptible to being broken on LLVM updates. + // CHECK-LABEL: @option_match #[no_mangle] pub fn option_match(x: Option) -> u16 { @@ -51,3 +55,76 @@ pub fn result_match(x: Result) -> u16 { Ok(_) => 42, } } + +// CHECK-LABEL: @option_bool_match( +#[no_mangle] +pub fn option_bool_match(x: Option) -> char { + // CHECK: %[[RAW:.+]] = load i8, ptr %x + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: %[[FIELD:.+]] = load i8, ptr %x + // CHECK: %[[FIELD_T:.+]] = trunc nuw i8 %[[FIELD]] to i1 + // CHECK: br i1 %[[FIELD_T]] + match x { + None => 'n', + Some(false) => 'f', + Some(true) => 't', + } +} + +use std::cmp::Ordering::{self, *}; +// CHECK-LABEL: @option_ordering_match( +#[no_mangle] +pub fn option_ordering_match(x: Option) -> char { + // CHECK: %[[RAW:.+]] = load i8, ptr %x + // CHECK: %[[IS_NONE:.+]] = icmp eq i8 %[[RAW]], 2 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: %[[FIELD:.+]] = load i8, ptr %x + // CHECK: switch i8 %[[FIELD]], label %[[UNREACHABLE:.+]] [ + // CHECK-NEXT: i8 -1, label + // CHECK-NEXT: i8 0, label + // CHECK-NEXT: i8 1, label + // CHECK-NEXT: ] + + // CHECK: [[UNREACHABLE]]: + // CHECK-NEXT: unreachable + match x { + None => '?', + Some(Less) => '<', + Some(Equal) => '=', + Some(Greater) => '>', + } +} + +// CHECK-LABEL: @option_nonzero_match( +#[no_mangle] +pub fn option_nonzero_match(x: Option>) -> u16 { + // CHECK: %[[OUT:.+]] = alloca [2 x i8] + + // CHECK: %[[IS_NONE:.+]] = icmp eq i16 %x, 0 + // CHECK: %[[OPT_DISCR:.+]] = select i1 %[[IS_NONE]], i64 0, i64 1 + // CHECK: %[[OPT_DISCR_T:.+]] = trunc nuw i64 %[[OPT_DISCR]] to i1 + // CHECK: br i1 %[[OPT_DISCR_T]], label %[[BB_SOME:.+]], label %[[BB_NONE:.+]] + + // CHECK: [[BB_SOME]]: + // CHECK: store i16 987, ptr %[[OUT]] + + // CHECK: [[BB_NONE]]: + // CHECK: store i16 123, ptr %[[OUT]] + + // CHECK: %[[RET:.+]] = load i16, ptr %[[OUT]] + // CHECK: ret i16 %[[RET]] + + match x { + None => 123, + Some(_) => 987, + } +} diff --git a/tests/ui/dyn-compatibility/trait-alias-self-projection.rs b/tests/ui/dyn-compatibility/trait-alias-self-projection.rs new file mode 100644 index 0000000000000..0badb738809e9 --- /dev/null +++ b/tests/ui/dyn-compatibility/trait-alias-self-projection.rs @@ -0,0 +1,12 @@ +#![feature(trait_alias)] +trait B = Fn() -> Self; +type D = &'static dyn B; +//~^ ERROR E0411 + +fn a() -> D { + unreachable!(); +} + +fn main() { + _ = a(); +} diff --git a/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr b/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr new file mode 100644 index 0000000000000..dccee02e9cd18 --- /dev/null +++ b/tests/ui/dyn-compatibility/trait-alias-self-projection.stderr @@ -0,0 +1,9 @@ +error[E0411]: `Self` is not allowed in type aliases + --> $DIR/trait-alias-self-projection.rs:3:19 + | +LL | type D = &'static dyn B; + | ^^^^^ `Self` is only available in impls, traits, and concrete type definitions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0411`. diff --git a/tests/ui/implied-bounds/overflow.rs b/tests/ui/implied-bounds/overflow.rs new file mode 100644 index 0000000000000..7c36998dd4d3b --- /dev/null +++ b/tests/ui/implied-bounds/overflow.rs @@ -0,0 +1,11 @@ +trait Tailed<'a>: 'a { + type Tail: Tailed<'a>; +} + +struct List<'a, T: Tailed<'a>> { + //~^ ERROR overflow computing implied lifetime bounds for `List` + next: Box>, + node: &'a T, +} + +fn main() {} diff --git a/tests/ui/implied-bounds/overflow.stderr b/tests/ui/implied-bounds/overflow.stderr new file mode 100644 index 0000000000000..2e5a9ab141cf8 --- /dev/null +++ b/tests/ui/implied-bounds/overflow.stderr @@ -0,0 +1,8 @@ +error: overflow computing implied lifetime bounds for `List` + --> $DIR/overflow.rs:5:1 + | +LL | struct List<'a, T: Tailed<'a>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/failed-to-reparse-issue-139445.rs b/tests/ui/macros/failed-to-reparse-issue-139445.rs new file mode 100644 index 0000000000000..babe26b9d293e --- /dev/null +++ b/tests/ui/macros/failed-to-reparse-issue-139445.rs @@ -0,0 +1,6 @@ +fn main() { + assert_eq!(3, 'a,) + //~^ ERROR expected `while`, `for`, `loop` or `{` after a label + //~| ERROR expected `while`, `for`, `loop` or `{` after a label + //~| ERROR expected expression, found `` +} diff --git a/tests/ui/macros/failed-to-reparse-issue-139445.stderr b/tests/ui/macros/failed-to-reparse-issue-139445.stderr new file mode 100644 index 0000000000000..6f7d88fb34466 --- /dev/null +++ b/tests/ui/macros/failed-to-reparse-issue-139445.stderr @@ -0,0 +1,24 @@ +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/failed-to-reparse-issue-139445.rs:2:21 + | +LL | assert_eq!(3, 'a,) + | ^ expected `while`, `for`, `loop` or `{` after a label + +error: expected `while`, `for`, `loop` or `{` after a label + --> $DIR/failed-to-reparse-issue-139445.rs:2:5 + | +LL | assert_eq!(3, 'a,) + | ^^^^^^^^^^^^^^^^^^ expected `while`, `for`, `loop` or `{` after a label + | + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected expression, found `` + --> $DIR/failed-to-reparse-issue-139445.rs:2:5 + | +LL | assert_eq!(3, 'a,) + | ^^^^^^^^^^^^^^^^^^ expected expression + | + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/no-close-delim-issue-139248.rs b/tests/ui/macros/no-close-delim-issue-139248.rs new file mode 100644 index 0000000000000..86583b2724ed0 --- /dev/null +++ b/tests/ui/macros/no-close-delim-issue-139248.rs @@ -0,0 +1,14 @@ +// This code caused a "no close delim when reparsing Expr" ICE in #139248. + +macro_rules! m { + (static a : () = $e:expr) => { + static a : () = $e; + //~^ ERROR macro expansion ends with an incomplete expression: expected expression + } +} + +m! { static a : () = (if b) } +//~^ ERROR expected `{`, found `)` +//~| ERROR expected `{`, found `)` + +fn main() {} diff --git a/tests/ui/macros/no-close-delim-issue-139248.stderr b/tests/ui/macros/no-close-delim-issue-139248.stderr new file mode 100644 index 0000000000000..6ed41ae9b46a6 --- /dev/null +++ b/tests/ui/macros/no-close-delim-issue-139248.stderr @@ -0,0 +1,33 @@ +error: expected `{`, found `)` + --> $DIR/no-close-delim-issue-139248.rs:10:27 + | +LL | m! { static a : () = (if b) } + | ^ expected `{` + | +note: the `if` expression is missing a block after this condition + --> $DIR/no-close-delim-issue-139248.rs:10:26 + | +LL | m! { static a : () = (if b) } + | ^ + +error: expected `{`, found `)` + --> $DIR/no-close-delim-issue-139248.rs:10:27 + | +LL | m! { static a : () = (if b) } + | ^ expected `{` + | +note: the `if` expression is missing a block after this condition + --> $DIR/no-close-delim-issue-139248.rs:10:26 + | +LL | m! { static a : () = (if b) } + | ^ + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: macro expansion ends with an incomplete expression: expected expression + --> $DIR/no-close-delim-issue-139248.rs:5:28 + | +LL | static a : () = $e; + | ^ expected expression + +error: aborting due to 3 previous errors + diff --git a/tests/ui/structs/default-field-values/failures.rs b/tests/ui/structs/default-field-values/failures.rs index 1e94eecb4f870..4461302e841d0 100644 --- a/tests/ui/structs/default-field-values/failures.rs +++ b/tests/ui/structs/default-field-values/failures.rs @@ -1,4 +1,4 @@ -#![feature(default_field_values)] + #![feature(default_field_values)] #[derive(Debug)] pub struct S; @@ -50,7 +50,8 @@ enum E { fn main () { let _ = Foo { .. }; // ok let _ = Foo::default(); // ok - let _ = Bar { .. }; //~ ERROR mandatory field + let _ = Bar { .. }; //~ ERROR missing field + let _ = Bar { baz: 0, .. }; //~ ERROR missing field let _ = Bar::default(); // silenced let _ = Bar { bar: S, .. }; // ok let _ = Qux::<4> { .. }; diff --git a/tests/ui/structs/default-field-values/failures.stderr b/tests/ui/structs/default-field-values/failures.stderr index 58f7baee4b284..21c9bfb44b435 100644 --- a/tests/ui/structs/default-field-values/failures.stderr +++ b/tests/ui/structs/default-field-values/failures.stderr @@ -27,14 +27,20 @@ LL + #[derive(Default)] LL | pub struct S; | -error: missing mandatory field `bar` - --> $DIR/failures.rs:53:21 +error: missing field `bar` in initializer + --> $DIR/failures.rs:53:19 | LL | let _ = Bar { .. }; - | ^ + | ^ fields that do not have a defaulted value must be provided explicitly + +error: missing field `bar` in initializer + --> $DIR/failures.rs:54:27 + | +LL | let _ = Bar { baz: 0, .. }; + | ^ fields that do not have a defaulted value must be provided explicitly error[E0308]: mismatched types - --> $DIR/failures.rs:57:17 + --> $DIR/failures.rs:58:17 | LL | let _ = Rak(..); | --- ^^ expected `i32`, found `RangeFull` @@ -47,19 +53,19 @@ note: tuple struct defined here LL | pub struct Rak(i32 = 42); | ^^^ help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal - --> $DIR/failures.rs:57:17 + --> $DIR/failures.rs:58:17 | LL | let _ = Rak(..); | ^^ error[E0061]: this struct takes 1 argument but 2 arguments were supplied - --> $DIR/failures.rs:59:13 + --> $DIR/failures.rs:60:13 | LL | let _ = Rak(0, ..); | ^^^ -- unexpected argument #2 of type `RangeFull` | help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal - --> $DIR/failures.rs:59:20 + --> $DIR/failures.rs:60:20 | LL | let _ = Rak(0, ..); | ^^ @@ -75,13 +81,13 @@ LL + let _ = Rak(0); | error[E0061]: this struct takes 1 argument but 2 arguments were supplied - --> $DIR/failures.rs:61:13 + --> $DIR/failures.rs:62:13 | LL | let _ = Rak(.., 0); | ^^^ -- unexpected argument #1 of type `RangeFull` | help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal - --> $DIR/failures.rs:61:17 + --> $DIR/failures.rs:62:17 | LL | let _ = Rak(.., 0); | ^^ @@ -96,7 +102,7 @@ LL - let _ = Rak(.., 0); LL + let _ = Rak(0); | -error: aborting due to 7 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0061, E0277, E0308. For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/traits/dyn-drop-principal-with-projections.rs b/tests/ui/traits/dyn-drop-principal-with-projections.rs new file mode 100644 index 0000000000000..912061847c69f --- /dev/null +++ b/tests/ui/traits/dyn-drop-principal-with-projections.rs @@ -0,0 +1,13 @@ +//@ check-pass + +trait Tr { + type Assoc; +} + +impl Tr for () { + type Assoc = (); +} + +fn main() { + let x = &() as &(dyn Tr + Send) as &dyn Send; +} diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs new file mode 100644 index 0000000000000..74c23a59bee9e --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs @@ -0,0 +1,18 @@ +// Make sure not to construct predicates with escaping bound vars in `diagnostic_hir_wf_check`. +// Regression test for . + +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +trait A {} +impl A for () {} + +trait B {} +struct W(T); + +fn b() -> (W<()>, impl for A) { (W(()), ()) } +//~^ ERROR the trait bound `(): B` is not satisfied +//~| ERROR the trait bound `(): B` is not satisfied +//~| ERROR the trait bound `(): B` is not satisfied + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr new file mode 100644 index 0000000000000..df99f4a67abb2 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr @@ -0,0 +1,65 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/diagnostic-hir-wf-check.rs:4:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `(): B` is not satisfied + --> $DIR/diagnostic-hir-wf-check.rs:13:12 + | +LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } + | ^^^^^ the trait `B` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/diagnostic-hir-wf-check.rs:10:1 + | +LL | trait B {} + | ^^^^^^^ +note: required by a bound in `W` + --> $DIR/diagnostic-hir-wf-check.rs:11:13 + | +LL | struct W(T); + | ^ required by this bound in `W` + +error[E0277]: the trait bound `(): B` is not satisfied + --> $DIR/diagnostic-hir-wf-check.rs:13:42 + | +LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } + | - ^^ the trait `B` is not implemented for `()` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/diagnostic-hir-wf-check.rs:10:1 + | +LL | trait B {} + | ^^^^^^^ +note: required by a bound in `W` + --> $DIR/diagnostic-hir-wf-check.rs:11:13 + | +LL | struct W(T); + | ^ required by this bound in `W` + +error[E0277]: the trait bound `(): B` is not satisfied + --> $DIR/diagnostic-hir-wf-check.rs:13:40 + | +LL | fn b() -> (W<()>, impl for A) { (W(()), ()) } + | ^^^^^ the trait `B` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/diagnostic-hir-wf-check.rs:10:1 + | +LL | trait B {} + | ^^^^^^^ +note: required by a bound in `W` + --> $DIR/diagnostic-hir-wf-check.rs:11:13 + | +LL | struct W(T); + | ^ required by this bound in `W` + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`.