diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 1212f422f76e8..93e97b53f7720 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,3 +1,4 @@ +use std::fmt::Debug; use std::ops::Deref; use rustc_type_ir::solve::{ @@ -36,11 +37,17 @@ pub trait SolverDelegate: Deref + Sized { // FIXME: Uplift the leak check into this crate. fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; - fn evaluate_const( + /// Evaluate a const, normalizing the type of the resulting value with `normalize_ty`. + /// Returns `Ok(None)` if the const is too generic, and `Err(_)` only if `normalize_ty` + /// failed. + fn evaluate_const( &self, param_env: ::ParamEnv, alias_const: ty::AliasConst, - ) -> Option<::Const>; + normalize_ty: impl FnOnce( + ty::Unnormalized::Ty>, + ) -> Result<::Ty, E>, + ) -> Result::Const>, E>; // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! fn well_formed_goals( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 559ca0a98c58e..78d3ab86cc250 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1403,19 +1403,21 @@ where Ok(()) } - // Try to evaluate a const, or return `None` if the const is too generic. - // This doesn't mean the const isn't evaluatable, though, and should be treated - // as an ambiguity rather than no-solution. + // Try to evaluate a const and normalize the type of the resulting value, or return `None` if + // the const is too generic. This doesn't mean the const isn't evaluatable, though, and should + // be treated as an ambiguity rather than no-solution. pub(super) fn evaluate_const( &mut self, param_env: I::ParamEnv, alias_const: ty::AliasConst, - ) -> Result, RerunNonErased> { + ) -> Result, NoSolutionOrRerunNonErased> { if self.typing_mode().is_erased_not_coherence() { match self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)? {} } - Ok(self.delegate.evaluate_const(param_env, alias_const)) + self.delegate.evaluate_const(param_env, alias_const, |ty| { + self.normalize(GoalSource::Misc, param_env, ty) + }) } pub(super) fn evaluate_const_and_instantiate_projection_term( diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 18bee1b1ba7f1..9ed3975043966 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -90,12 +90,16 @@ pub mod mitigation_coverage; mod target_modifier_consistency_check { use super::*; - pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool { - let mut lparsed: SanitizerSet = Default::default(); + pub(super) fn sanitizer( + sess: &Session, + l: &TargetModifier, + r: Option<&TargetModifier>, + ) -> bool { + let mut lparsed: SanitizerSet = sess.target.options.default_sanitizers; let lval = if l.value_name.is_empty() { None } else { Some(l.value_name.as_str()) }; parse::parse_sanitizers(&mut lparsed, lval); - let mut rparsed: SanitizerSet = Default::default(); + let mut rparsed: SanitizerSet = sess.target.options.default_sanitizers; let rval = r.filter(|v| !v.value_name.is_empty()).map(|v| v.value_name.as_str()); parse::parse_sanitizers(&mut rparsed, rval); @@ -166,7 +170,7 @@ impl TargetModifier { match self.opt { OptionsTargetModifiers::UnstableOptions(unstable) => match unstable { UnstableOptionsTargetModifiers::Sanitizer => { - return target_modifier_consistency_check::sanitizer(self, other); + return target_modifier_consistency_check::sanitizer(sess, self, other); } UnstableOptionsTargetModifiers::SanitizerCfiNormalizeIntegers => { return target_modifier_consistency_check::sanitizer_cfi_normalize_integers( diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 071c62d0b5ee0..d93e3fdf853fc 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,4 +1,5 @@ use std::collections::hash_map::Entry; +use std::fmt::Debug; use std::mem; use std::ops::Deref; @@ -319,19 +320,23 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) } - fn evaluate_const( + fn evaluate_const( &self, param_env: ty::ParamEnv<'tcx>, alias_const: ty::AliasConst<'tcx>, - ) -> Option> { + normalize_ty: impl FnOnce(ty::Unnormalized<'tcx, Ty<'tcx>>) -> Result, E>, + ) -> Result>, E> { let ct = ty::Const::new_alias(self.tcx, ty::IsRigid::No, alias_const); - match crate::traits::try_evaluate_const(&self.0, ct, param_env) { - Ok(ct) => Some(ct), - Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)), + match crate::traits::try_evaluate_const(&self.0, ct, param_env, normalize_ty) { + Ok(ct) => Ok(Some(ct)), + Err(EvaluateConstErr::EvaluationFailure(e)) => { + Ok(Some(ty::Const::new_error(self.tcx, e))) + } Err( EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers, - ) => None, + ) => Ok(None), + Err(EvaluateConstErr::FailedNormalization(e)) => Err(e), } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index c885406f6dcfb..798bca8483b0a 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -853,8 +853,12 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Alias(_, alias_const) = c.kind() { - let ct = - super::try_evaluate_const(selcx.infcx, c, obligation.param_env); + let ct = super::try_evaluate_const( + selcx.infcx, + c, + obligation.param_env, + |ty| Ok::<_, !>(ty.skip_norm_wip()), + ); if let Err(EvaluateConstErr::InvalidConstParamTy(_)) = ct { let span = alias_const.kind.def_span(self.tcx); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 74413d430b1cd..2a1cb4c7ad5d3 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -67,7 +67,9 @@ pub fn is_const_evaluatable<'tcx>( tcx.dcx().span_bug(span, "evaluating `ConstKind::Expr` is not currently supported"); } ty::ConstKind::Alias(_, _) => { - match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) { + match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env, |ty| { + Ok::<_, !>(ty.skip_norm_wip()) + }) { Err(EvaluateConstErr::HasGenericsOrInfers) => { Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug( span, @@ -98,7 +100,9 @@ pub fn is_const_evaluatable<'tcx>( _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), }; - match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env) { + match crate::traits::try_evaluate_const(infcx, unexpanded_ct, param_env, |ty| { + Ok::<_, !>(ty.skip_norm_wip()) + }) { // If we're evaluating a generic foreign constant, under a nightly compiler while // the current crate does not enable `feature(generic_const_exprs)`, abort // compilation with a useful error. diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d0452052f10f6..941d80db4bbc4 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -764,6 +764,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { self.selcx.infcx, c, obligation.param_env, + |ty| Ok::<_, !>(ty.skip_norm_wip()), ) { Ok(val) => Ok(val), e @ Err(EvaluateConstErr::HasGenericsOrInfers) => { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index eda63e09b1189..e0c93a7d3af63 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -573,7 +573,7 @@ pub fn normalize_param_env_or_error<'tcx>( } #[derive(Debug)] -pub enum EvaluateConstErr { +pub enum EvaluateConstErr { /// The constant being evaluated was either a generic parameter or inference variable, *or*, /// some alias const with either generic parameters or inference variables in its /// generic arguments. @@ -585,6 +585,7 @@ pub enum EvaluateConstErr { /// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`). /// This is also used when the constant was already tainted by error. EvaluationFailure(ErrorGuaranteed), + FailedNormalization(E), } // FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine @@ -601,7 +602,7 @@ pub fn evaluate_const<'tcx>( ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> ty::Const<'tcx> { - match try_evaluate_const(infcx, ct, param_env) { + match try_evaluate_const(infcx, ct, param_env, |v| Ok::<_, !>(v.skip_norm_wip())) { Ok(ct) => ct, Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => { ty::Const::new_error(infcx.tcx, e) @@ -618,12 +619,13 @@ pub fn evaluate_const<'tcx>( /// /// You should not call this function unless you are implementing normalization itself. Prefer to use /// `normalize_erasing_regions` or the `normalize` functions on `ObligationCtxt`/`FnCtxt`/`InferCtxt`. -#[instrument(level = "debug", skip(infcx), ret)] -pub fn try_evaluate_const<'tcx>( +#[instrument(level = "debug", skip(infcx, normalize_ty), ret)] +pub fn try_evaluate_const<'tcx, E: Debug>( infcx: &InferCtxt<'tcx>, ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> Result, EvaluateConstErr> { + normalize_ty: impl FnOnce(Unnormalized<'tcx, Ty<'tcx>>) -> Result, E>, +) -> Result, EvaluateConstErr> { let tcx = infcx.tcx; let ct = infcx.resolve_vars_if_possible(ct); debug!(?ct); @@ -762,7 +764,9 @@ pub fn try_evaluate_const<'tcx>( let span = alias_const.kind.def_span(tcx); match tcx.const_eval_resolve_for_typeck(typing_env, erased_alias_const, span) { Ok(Ok(val)) => { - Ok(ty::Const::new_value(tcx, val, alias_const.type_of(tcx).skip_norm_wip())) + let ty = normalize_ty(alias_const.type_of(tcx)) + .map_err(EvaluateConstErr::FailedNormalization)?; + Ok(ty::Const::new_value(tcx, val, ty)) } Ok(Err(_)) => { let e = tcx.dcx().delayed_bug( diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 9b4ee13bf1b63..d1c579d922287 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -921,11 +921,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Alias(_, _) = c.kind() { - match crate::traits::try_evaluate_const(self.infcx, c, obligation.param_env) - { - Ok(val) => Ok(val), - Err(e) => Err(e), - } + crate::traits::try_evaluate_const( + self.infcx, + c, + obligation.param_env, + |v| Ok::<_, !>(v.skip_norm_wip()), + ) } else { Ok(c) } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh index ba1ed57491070..f2f78b04d7787 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh @@ -19,16 +19,4 @@ if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist \ gcc-dev \ gcc - # We confirm that the built GCC has support for the `retain` attribute. - # FIXME: Maybe get the path from `.x.py` instead? - gcc_path="./build/$HOSTS/gcc/$HOSTS/install/bin/gcc" - c_code='int x __attribute__((used, retain));' - if echo "$c_code" | "$gcc_path" -S -x c -o - - | grep -i '"a.*R"'; then - echo "retain attribute is supported" - else - echo "retain attribute is not supported" - # We display the generated asm just in case... - echo "$c_code" | "$gcc_path" -S -x c -o - - - exit 1 - fi fi diff --git a/src/ci/docker/scripts/build-gcc.sh b/src/ci/docker/scripts/build-gcc.sh index c1c94a89d17e7..6a96b82d3f924 100755 --- a/src/ci/docker/scripts/build-gcc.sh +++ b/src/ci/docker/scripts/build-gcc.sh @@ -4,27 +4,6 @@ set -eux source shared.sh -# We have to build our own binutils for the GCC build, because the default CentOS 7 binutils are -# too old, and they do not support `SHF_GNU_RETAIN`. -BINUTILS="2.47" -curl https://ci-mirrors.rust-lang.org/rustc/gcc/binutils-$BINUTILS.tar.xz | xzcat | tar xf - -mkdir binutils-build -cd binutils-build -hide_output ../binutils-$BINUTILS/configure --prefix=/rustroot -hide_output make -j$(nproc) -hide_output make install - -cd .. -rm -rf binutils-build binutils-$BINUTILS - -if echo '.section .test,"awR",@progbits' | as - -o /dev/null 2>/dev/null; then - echo "binutils assembler supports SHF_GNU_RETAIN" -else - echo "binutils assembler DOES NOT support SHF_GNU_RETAIN" - exit 1 -fi - - # Note: in the future when bumping to version 10.1.0, also take care of the sed block below. # This version is specified in the Dockerfile GCC=$GCC_VERSION @@ -57,7 +36,6 @@ sed -i'' 's|ftp://gcc\.gnu\.org/pub/gcc/infrastructure|https://ci-mirrors.rust-l mkdir ../gcc-build cd ../gcc-build -export PATH=/rustroot/bin:$PATH # '-fno-reorder-blocks-and-partition' is required to # enable BOLT optimization of the C++ standard library, # which is included in librustc_driver.so diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml index bdb70f215f830..804839b0f5c2e 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: - main pull_request: schedule: - # Run multiple times a day as the successfull cached links are not checked every time. + # Run multiple times a day as the successful cached links are not checked every time. - cron: "0 */8 * * *" jobs: @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest env: MDBOOK_VERSION: 0.5.2 - MDBOOK_LINKCHECK2_VERSION: 0.11.0 + MDBOOK_LINKCHECK2_VERSION: 0.13.0 MDBOOK_MERMAID_VERSION: 0.17.0 MDBOOK_OUTPUT__LINKCHECK__FOLLOW_WEB_LINKS: ${{ github.event_name != 'pull_request' }} DEPLOY_DIR: book/html diff --git a/src/doc/rustc-dev-guide/book.toml b/src/doc/rustc-dev-guide/book.toml index 5712a364f7602..1ded7aba10f96 100644 --- a/src/doc/rustc-dev-guide/book.toml +++ b/src/doc/rustc-dev-guide/book.toml @@ -26,6 +26,7 @@ level = 0 [output.linkcheck] command = "ci/linkcheck.sh" +require-md-extension = true follow-web-links = true exclude = [ "crates\\.io", @@ -57,6 +58,7 @@ cache-timeout = 90000 warning-policy = "error" [output.html.redirect] +"/backend/inline-asm.html" = "/asm.html" "/borrow_check.html" = "borrow-check.html" "/borrow_check/drop_check.html" = "/borrow-check/drop-check.html" "/borrow_check/moves_and_initialization.html" = "/borrow-check/moves-and-initialization.html" @@ -77,6 +79,7 @@ warning-policy = "error" "/early_late_parameters.html" = "early-late-parameters.html" "/generic_parameters_summary.html" = "generic-parameters-summary.html" "/implementing_new_features.html" = "implementing-new-features.html" +"/llm-guidance/index.html" = "/llm-guidance.html" "/miri.html" = "const-eval/interpret.html" "/profiling/with_perf.html" = "with-perf.html" "/profiling/with_rustc_perf.html" = "with-rustc-perf.html" diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 6a21f4bf92e28..2f175e966812d 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -e64c8a664d9da54fc239cd4404cbf67f0d624326 +2c39ff499469be916d4e45506d1afed69bbaddb7 diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 1dd08cff81a00..920fad617943a 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -32,11 +32,12 @@ - [Fuchsia](./tests/ecosystem-test-jobs/fuchsia.md) - [Rust for Linux](./tests/ecosystem-test-jobs/rust-for-linux.md) - [Codegen backend testing](./tests/codegen-backend-tests/intro.md) - - [Cranelift codegen backend](./tests/codegen-backend-tests/cg_clif.md) + - [Cranelift codegen backend (stub)](./tests/codegen-backend-tests/cg_clif.md) - [GCC codegen backend](./tests/codegen-backend-tests/cg_gcc.md) - [Performance testing](./tests/perf.md) - [Autodiff CI job](./tests/autodiff-ci-job.md) - [Pre-stabilization CI job for the next solver and polonius alpha](./tests/x86_64-gnu-next-trait-solver-polonius-ci-job.md) + - [Parallel frontend CI job](./tests/optional-x86_64-gnu-parallel-frontend.md) - [Standard library semver breakage test](./tests/stdlib-semver-check.md) - [Misc info](./tests/misc.md) - [Debugging the compiler](./compiler-debugging.md) @@ -108,7 +109,7 @@ - [Rustdoc internals](./rustdoc-internals.md) - [Search](./rustdoc-internals/search.md) - [The `rustdoc-html` test suite](./rustdoc-internals/rustdoc-html-test-suite.md) - - [The `rustdoc-gui` test suite](./rustdoc-internals/rustdoc-gui-test-suite.md) + - [The `rustdoc-gui` test suite (stub)](./rustdoc-internals/rustdoc-gui-test-suite.md) - [The `rustdoc-json` test suite](./rustdoc-internals/rustdoc-json-test-suite.md) - [GPU offload internals](./offload/internals.md) - [Installation](./offload/installation.md) @@ -225,8 +226,9 @@ - [Member constraints](./borrow-check/region-inference/member-constraints.md) - [Placeholders and universes](./borrow-check/region-inference/placeholders-and-universes.md) - [Closure constraints](./borrow-check/region-inference/closure-constraints.md) - - [Error reporting](./borrow-check/region-inference/error-reporting.md) + - [Error reporting (stub)](./borrow-check/region-inference/error-reporting.md) - [Two-phase-borrows](./borrow-check/two-phase-borrows.md) + - [Debugging the borrow checker](./borrow-check/debugging.md) - [Closure capture inference](./closure.md) - [Async closures/"coroutine-closures"](coroutine-closures.md) @@ -249,12 +251,12 @@ - [LLVM codegen](./debuginfo/llvm-codegen.md) - [Debugger internals](./debuginfo/debugger-internals.md) - [LLDB internals](./debuginfo/lldb-internals.md) - - [GDB internals](./debuginfo/gdb-internals.md) + - [GDB internals (stub)](./debuginfo/gdb-internals.md) - [Debugger visualizers](./debuginfo/debugger-visualizers.md) - [LLDB - Python Providers](./debuginfo/lldb-visualizers.md) - [GDB - Python Providers](./debuginfo/gdb-visualizers.md) - - [CDB - Natvis](./debuginfo/natvis-visualizers.md) - - [Testing](./debuginfo/testing.md) + - [CDB - Natvis (stub)](./debuginfo/natvis-visualizers.md) + - [Testing (stub)](./debuginfo/testing.md) - [(Lecture notes) Debugging support in the Rust compiler](./debugging-support-in-rustc.md) - [Libraries and metadata](./backend/libs-and-metadata.md) - [Profile-guided optimization](./profile-guided-optimization.md) diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index efa354ecd6b3c..651c8a539e265 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -31,7 +31,7 @@ There are several parts to this guide: 1. [Appendices][p9] at the end with useful reference information. There are a few of these with different information, including a glossary. -[p1]: ./building/how-to-build-and-run.html +[p1]: ./building/how-to-build-and-run.md [p2]: ./contributing.md [p3]: ./building/bootstrapping/intro.md [p4]: ./part-2-intro.md diff --git a/src/doc/rustc-dev-guide/src/appendix/background.md b/src/doc/rustc-dev-guide/src/appendix/background.md index e76285080394d..16400127e1983 100644 --- a/src/doc/rustc-dev-guide/src/appendix/background.md +++ b/src/doc/rustc-dev-guide/src/appendix/background.md @@ -264,7 +264,7 @@ don't actually do this in `rustc` though!): Check out the subtyping chapter from the [Rust Nomicon](https://doc.rust-lang.org/nomicon/subtyping.html). -See the [variance](../variance.html) chapter of this guide for more info on how +See the [variance](../variance.md) chapter of this guide for more info on how the type checker handles variance. diff --git a/src/doc/rustc-dev-guide/src/appendix/code-index.md b/src/doc/rustc-dev-guide/src/appendix/code-index.md index 25c770d4fbe8c..1808a8e000c32 100644 --- a/src/doc/rustc-dev-guide/src/appendix/code-index.md +++ b/src/doc/rustc-dev-guide/src/appendix/code-index.md @@ -29,15 +29,15 @@ Item | Kind | Short description | Chapter | `Ty<'tcx>` | struct | This is the internal representation of a type used for type checking | [Type checking] | [compiler/rustc_middle/src/ty/mod.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html) `TyCtxt<'tcx>` | struct | The "typing context". This is the central data structure in the compiler. It is the context that you use to perform all manner of queries | [The `ty` modules] | [compiler/rustc_middle/src/ty/context.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html) -[The HIR]: ../hir.html -[Identifiers in the HIR]: ../hir.html#hir-id -[The parser]: ../the-parser.html -[The Rustc Driver and Interface]: ../rustc-driver/intro.html -[Type checking]: ../hir-typeck/summary.html -[The `ty` modules]: ../ty.html -[Rustdoc]: ../rustdoc.html -[Emitting Diagnostics]: ../diagnostics.html -[Macro expansion]: ../macro-expansion.html -[Name resolution]: ../name-resolution.html -[Parameter Environment]: ../typing-parameter-envs.html -[Trait Solving: Goals and Clauses]: ../traits/goals-and-clauses.html#domain-goals +[The HIR]: ../hir.md +[Identifiers in the HIR]: ../hir.md#hir-id +[The parser]: ../the-parser.md +[The Rustc Driver and Interface]: ../rustc-driver/intro.md +[Type checking]: ../hir-typeck/summary.md +[The `ty` modules]: ../ty.md +[Rustdoc]: ../rustdoc.md +[Emitting Diagnostics]: ../diagnostics.md +[Macro expansion]: ../macro-expansion.md +[Name resolution]: ../name-resolution.md +[Parameter Environment]: ../typing-parameter-envs.md +[Trait Solving: Goals and Clauses]: ../traits/goals-and-clauses.md#domain-goals diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index 0ddb65a2e2b20..e8f22bdf2fb15 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -92,7 +92,7 @@ Term | Meaning span | A location in the user's source code, used for error reporting primarily. These are like a file-name/line-number/column tuple on steroids: they carry a start/end point, and also track macro expansions and compiler desugaring. All while being packed into a few bytes (really, it's an index into a table). See the [`Span`] datatype for more. subst 👎 | The act of _substituting_ the generic parameters inside of a type, constant expression, etc. with concrete generic arguments by supplying [substs](#substs). Nowadays referred to as _instantiating_ in the compiler. substs 👎 | The _substitutions_ for a given generic item (e.g. the `i32`, `u32` in `HashMap`). Nowadays referred to as the list of _generic arguments_ in the compiler (but note that strictly speaking these two concepts differ, see the literature). -sysroot | The directory for build artifacts that are loaded by the compiler at runtime. ([see more](../building/bootstrapping/what-bootstrapping-does.html#what-is-a-sysroot)) +sysroot | The directory for build artifacts that are loaded by the compiler at runtime. ([see more](../building/bootstrapping/what-bootstrapping-does.md#what-is-a-sysroot)) tag | The "tag" of an enum/generator encodes the [discriminant](#discriminant) of the active variant/state. Tags can either be "direct" (simply storing the discriminant in a field) or use a ["niche"](#niche). TAIT | Short for _type-alias `impl Trait`_. Introduced in [RFC 2515]. `tcx` | Standard variable name for the "typing context" (`TyCtxt`), main data structure of the compiler. ([see more](../ty.md)) diff --git a/src/doc/rustc-dev-guide/src/backend/codegen.md b/src/doc/rustc-dev-guide/src/backend/codegen.md index e2c92430e6f0c..2bf3cd5437634 100644 --- a/src/doc/rustc-dev-guide/src/backend/codegen.md +++ b/src/doc/rustc-dev-guide/src/backend/codegen.md @@ -6,8 +6,7 @@ Usually, rustc uses LLVM for code generation, but there is also support for [Cranelift] and [GCC]. The key is that rustc doesn't implement codegen itself. It's worth noting, though, that in the Rust source code, -many parts of the backend have `codegen` in their names -(there are no hard boundaries). +many parts of the backend have `codegen` in their names (there are no hard boundaries). [Cranelift]: https://github.com/bytecodealliance/wasmtime/tree/main/cranelift [GCC]: https://github.com/rust-lang/rustc_codegen_gcc @@ -20,28 +19,29 @@ many parts of the backend have `codegen` in their names ## What is LLVM? [LLVM](https://llvm.org) is "a collection of modular and reusable compiler and -toolchain technologies". In particular, the LLVM project contains a pluggable +toolchain technologies". +In particular, the LLVM project contains a pluggable compiler backend (also called "LLVM"), which is used by many compiler projects, including the `clang` C compiler and our beloved `rustc`. -LLVM takes input in the form of LLVM IR. It is basically assembly code with -additional low-level types and annotations added. These annotations are helpful -for doing optimizations on the LLVM IR and outputted machine code. The end -result of all this is (at long last) something executable (e.g. an ELF object, +LLVM takes input in the form of LLVM IR. +It is basically assembly code with additional low-level types and annotations added. +These annotations are helpful for doing optimizations on the LLVM IR and outputted machine code. +The end result of all this is (at long last) something executable (e.g. an ELF object, an EXE, or wasm). There are a few benefits to using LLVM: -- We don't have to write a whole compiler backend. This reduces implementation - and maintenance burden. +- We don't have to write a whole compiler backend. + This reduces implementation and maintenance burden. - We benefit from the large suite of advanced optimizations that the LLVM project has been collecting. -- We can automatically compile Rust to any of the platforms for which LLVM has - support. For example, as soon as LLVM added support for wasm, voila! rustc, - clang, and a bunch of other languages were able to compile to wasm! (Well, - there was some extra stuff to be done, but we were 90% there anyway). -- We and other compiler projects benefit from each other. For example, when the - [Spectre and Meltdown security vulnerabilities][spectre] were discovered, +- We can automatically compile Rust to any of the platforms for which LLVM has support. + For example, as soon as LLVM added support for wasm, voila! + rustc, clang, and a bunch of other languages were able to compile to wasm! + (Well, there was some extra stuff to be done, but we were 90% there anyway). +- We and other compiler projects benefit from each other. + For example, when the [Spectre and Meltdown security vulnerabilities][spectre] were discovered, only LLVM needed to be patched. [spectre]: https://meltdownattack.com/ @@ -49,27 +49,25 @@ There are a few benefits to using LLVM: ## Running LLVM, linking, and metadata generation Once LLVM IR for all of the functions and statics, etc is built, it is time to -start running LLVM and its optimization passes. LLVM IR is grouped into -"modules". Multiple "modules" can be codegened at the same time to aid in -multi-core utilization. These "modules" are what we refer to as _codegen -units_. These units were established way back during monomorphization -collection phase. +start running LLVM and its optimization passes. +LLVM IR is grouped into "modules". +Multiple "modules" can be codegened at the same time to aid in multi-core utilization. +These "modules" are what we refer to as _codegen units_. +These units were established way back during monomorphization collection phase. Once LLVM produces objects from these modules, these objects are passed to the -linker along with, optionally, the metadata object and an archive or an -executable is produced. - -It is not necessarily the codegen phase described above that runs the -optimizations. With certain kinds of LTO, the optimization might happen at the -linking time instead. It is also possible for some optimizations to happen -before objects are passed on to the linker and some to happen during the -linking. - -This all happens towards the very end of compilation. The code for this can be -found in [`rustc_codegen_ssa::back`][ssaback] and -[`rustc_codegen_llvm::back`][llvmback]. Sadly, this piece of code is not -really well-separated into LLVM-dependent code; the [`rustc_codegen_ssa`][ssa] -contains a fair amount of code specific to the LLVM backend. +linker along with, optionally, the metadata object and an archive or an executable is produced. + +It is not necessarily the codegen phase described above that runs the optimizations. +With certain kinds of LTO, the optimization might happen during linking time instead. +It is also possible for some optimizations to happen +before objects are passed on to the linker and some to happen during the linking. + +This all happens towards the very end of compilation. +The code for this can be found in [`rustc_codegen_ssa::back`][ssaback] and +[`rustc_codegen_llvm::back`][llvmback]. +Sadly, this piece of code is not really well-separated into LLVM-dependent code; +the [`rustc_codegen_ssa`][ssa] contains a fair amount of code specific to the LLVM backend. Once these components are done with their work you end up with a number of files in your filesystem corresponding to the outputs you have requested. diff --git a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md index 9ca4bcab078e0..909c00ea40cff 100644 --- a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md +++ b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md @@ -1,8 +1,8 @@ # Implicit caller location Approved in [RFC 2091], this feature enables the accurate reporting of caller location during panics -initiated from functions like `Option::unwrap`, `Result::expect`, and `Index::index`. This feature -adds the [`#[track_caller]`][attr-reference] attribute for functions, the +initiated from functions like `Option::unwrap`, `Result::expect`, and `Index::index`. +This feature adds the [`#[track_caller]`][attr-reference] attribute for functions, the [`caller_location`][intrinsic] intrinsic, and the stabilization-friendly [`core::panic::Location::caller`][wrapper] wrapper. @@ -40,14 +40,16 @@ library which propagate caller information. ## Reading caller location Previously, `panic!` made use of the `file!()`, `line!()`, and `column!()` macros to construct a -[`Location`] pointing to where the panic occurred. These macros couldn't be given an overridden -location, so functions which intentionally invoked `panic!` couldn't provide their own location, +[`Location`] pointing to where the panic occurred. +These macros couldn't be given an overridden location, +so functions which intentionally invoked `panic!` couldn't provide their own location, hiding the actual source of error. Internally, `panic!()` now calls [`core::panic::Location::caller()`][wrapper] to find out where it -was expanded. This function is itself annotated with `#[track_caller]` and wraps the -[`caller_location`][intrinsic] compiler intrinsic implemented by rustc. This intrinsic is easiest -explained in terms of how it works in a `const` context. +was expanded. +This function is itself annotated with `#[track_caller]` and wraps the +[`caller_location`][intrinsic] compiler intrinsic implemented by rustc. +This intrinsic is easiest explained in terms of how it works in a `const` context. ## Caller location in `const` @@ -57,35 +59,38 @@ to find the right location and allocating a const value to return. ### Finding the right `Location` In a const context we "walk up the stack" from where the intrinsic is invoked, stopping when we -reach the first function call in the stack which does *not* have the attribute. This walk is in -[`InterpCx::find_closest_untracked_caller_location()`][const-find-closest]. +reach the first function call in the stack which does *not* have the attribute. +This walk is in [`InterpCx::find_closest_untracked_caller_location()`][const-find-closest]. Starting at the bottom, we iterate up over stack [`Frame`][const-frame]s in the [`InterpCx::stack`][const-stack], calling [`InstanceKind::requires_caller_location`][requires-location] on the -[`Instance`s from each `Frame`][frame-instance]. We stop once we find one that returns `false` and +[`Instance`s from each `Frame`][frame-instance]. +We stop once we find one that returns `false` and return the span of the *previous* frame which was the "topmost" tracked function. ### Allocating a static `Location` Once we have a `Span`, we need to allocate static memory for the `Location`, which is performed by -the [`TyCtxt::const_caller_location()`][const-location-query] query. Internally this calls -[`InterpCx::alloc_caller_location()`][alloc-location] and results in a unique -[memory kind][location-memory-kind] (`MemoryKind::CallerLocation`). The SSA codegen backend is able -to emit code for these same values, and we use this code there as well. +the [`TyCtxt::const_caller_location()`][const-location-query] query. +Internally this calls [`InterpCx::alloc_caller_location()`][alloc-location] and results in a unique +[memory kind][location-memory-kind] (`MemoryKind::CallerLocation`). +The SSA codegen backend is able to emit code for these same values, +and we use this code there as well. Once our `Location` has been allocated in static memory, our intrinsic returns a reference to it. ## Generating code for `#[track_caller]` callees To generate efficient code for a tracked function and its callers, we need to provide the same -behavior from the intrinsic's point of view without having a stack to walk up at runtime. We invert -the approach: as we grow the stack down we pass an additional argument to calls of tracked functions -rather than walking up the stack when the intrinsic is called. That additional argument can be -returned wherever the caller location is queried. - -The argument we append is of type `&'static core::panic::Location<'static>`. A reference was chosen -to avoid unnecessary copying because a pointer is a third the size of +behavior from the intrinsic's point of view without having a stack to walk up at runtime. +We invert the approach: +as we grow the stack down we pass an additional argument to calls of tracked functions +rather than walking up the stack when the intrinsic is called. +That additional argument can be returned wherever the caller location is queried. + +The argument we append is of type `&'static core::panic::Location<'static>`. +A reference was chosen to avoid unnecessary copying because a pointer is a third the size of `std::mem::size_of::() == 24` at time of writing. When generating a call to a function which is tracked, we pass the location argument the value of @@ -105,7 +110,8 @@ stack downward. ### Codegen examples -What does this transformation look like in practice? Take this example which uses the new feature: +What does this transformation look like in practice? +Take this example which uses the new feature: ```rust #![feature(track_caller)] @@ -139,13 +145,15 @@ fn main() { ### Dynamic dispatch In codegen contexts we have to modify the callee ABI to pass this information down the stack, but -the attribute expressly does *not* modify the type of the function. The ABI change must be -transparent to type checking and remain sound in all uses. +the attribute expressly does *not* modify the type of the function. +The ABI change must be transparent to type checking and remain sound in all uses. Direct calls to tracked functions will always know the full codegen flags for the callee and can -generate appropriate code. Indirect callers won't have this information and it's not encoded in +generate appropriate code. +Indirect callers won't have this information and it's not encoded in the type of the function pointer they call, so we generate a [`ReifyShim`] around the function -whenever taking a pointer to it. This shim isn't able to report the actual location of the indirect +whenever taking a pointer to it. +This shim isn't able to report the actual location of the indirect call (the function's definition site is reported instead), but it prevents miscompilation and is probably the best we can do without modifying fully-stabilized type signatures. @@ -163,16 +171,18 @@ function: * is not a closure * is not `#[naked]` -If the use is valid, we set [`CodegenFnAttrsFlags::TRACK_CALLER`][attrs-flags]. This flag influences -the return value of [`InstanceKind::requires_caller_location`][requires-location] which is in turn +If the use is valid, we set [`CodegenFnAttrsFlags::TRACK_CALLER`][attrs-flags]. +This flag influences the return value of +[`InstanceKind::requires_caller_location`][requires-location] which is in turn used in both const and codegen contexts to ensure correct propagation. ### Traits When applied to trait method implementations, the attribute works as it does for regular functions. -When applied to a trait method prototype, the attribute applies to all implementations of the -method. When applied to a default trait method implementation, the attribute takes effect on +When applied to a trait method prototype, +the attribute applies to all implementations of the method. +When applied to a default trait method implementation, the attribute takes effect on that implementation *and* any overrides. Examples: @@ -235,26 +245,29 @@ fn main() { } ``` -## Background/History +## Background/history Broadly speaking, this feature's goal is to improve common Rust error messages without breaking stability guarantees, requiring modifications to end-user source, relying on platform-specific debug-info, or preventing user-defined types from having the same error-reporting benefits. Improving the output of these panics has been a goal of proposals since at least mid-2016 (see -[non-viable alternatives] in the approved RFC for details). It took two more years until RFC 2091 -was approved, much of its [rationale] for this feature's design having been discovered through the +[non-viable alternatives] in the approved RFC for details). +It took two more years until RFC 2091 was approved, +much of its [rationale] for this feature's design having been discovered through the discussion around several earlier proposals. The design in the original RFC limited itself to implementations that could be done inside the -compiler at the time without significant refactoring. However in the year and a half between the -approval of the RFC and the actual implementation work, a [revised design] was proposed and written -up on the tracking issue. During the course of implementing that, it was also discovered that an +compiler at the time without significant refactoring. +However in the year and a half between the approval of the RFC and the actual implementation work, +a [revised design] was proposed and written up on the tracking issue. +During the course of implementing that, it was also discovered that an implementation was possible without modifying the number of arguments in a function's MIR, which would simplify later stages and unlock use in traits. Because the RFC's implementation strategy could not readily support traits, the semantics were not -originally specified. They have since been implemented following the path which seemed most correct +originally specified. +They have since been implemented following the path which seemed most correct to the author and reviewers. [RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md diff --git a/src/doc/rustc-dev-guide/src/backend/inline-asm.md b/src/doc/rustc-dev-guide/src/backend/inline-asm.md deleted file mode 100644 index f1a64b5ee1d61..0000000000000 --- a/src/doc/rustc-dev-guide/src/backend/inline-asm.md +++ /dev/null @@ -1,5 +0,0 @@ -# Inline Assembly - -**TODO**: You can find more info -[here](https://github.com/rust-lang/rust/pull/69171#issue-375572066) -[#1162](https://github.com/rust-lang/rustc-dev-guide/issues/1162) diff --git a/src/doc/rustc-dev-guide/src/backend/lowering-mir.md b/src/doc/rustc-dev-guide/src/backend/lowering-mir.md index 8b9dbe7ce2a59..ade8a411ec213 100644 --- a/src/doc/rustc-dev-guide/src/backend/lowering-mir.md +++ b/src/doc/rustc-dev-guide/src/backend/lowering-mir.md @@ -1,14 +1,14 @@ # Lowering MIR to a Codegen IR Now that we have a list of symbols to generate from the collector, we need to -generate some sort of codegen IR. In this chapter, we will assume LLVM IR, -since that's what rustc usually uses. The actual monomorphization is performed -as we go, while we do the translation. +generate some sort of codegen IR. +In this chapter, we will assume LLVM IR, +since that's what rustc usually uses. +The actual monomorphization is performed as we go, while we do the translation. -Recall that the backend is started by -[`rustc_codegen_ssa::base::codegen_crate`][codegen1]. Eventually, this reaches -[`rustc_codegen_ssa::mir::codegen_mir`][codegen2], which does the lowering from -MIR to LLVM IR. +Recall that the backend is started by [`rustc_codegen_ssa::base::codegen_crate`][codegen1]. +Eventually, this reaches +[`rustc_codegen_ssa::mir::codegen_mir`][codegen2], which does the lowering from MIR to LLVM IR. [codegen1]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/base/fn.codegen_crate.html [codegen2]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/fn.codegen_mir.html @@ -16,8 +16,9 @@ MIR to LLVM IR. The code is split into modules which handle particular MIR primitives: - [`rustc_codegen_ssa::mir::block`][mirblk] will deal with translating - blocks and their terminators. The most complicated and also the most - interesting thing this module does is generating code for function calls, + blocks and their terminators. + The most complicated and also the most interesting thing this module does + is generating code for function calls, including the necessary unwinding handling IR. - [`rustc_codegen_ssa::mir::statement`][mirst] translates MIR statements. - [`rustc_codegen_ssa::mir::operand`][mirop] translates MIR operands. @@ -31,25 +32,27 @@ The code is split into modules which handle particular MIR primitives: [mirrv]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/rvalue/index.html Before a function is translated a number of simple and primitive analysis -passes will run to help us generate simpler and more efficient LLVM IR. An -example of such an analysis pass would be figuring out which variables are +passes will run to help us generate simpler and more efficient LLVM IR. +An example of such an analysis pass would be figuring out which variables are SSA-like, so that we can translate them to SSA directly rather than relying on -LLVM's `mem2reg` for those variables. The analysis can be found in -[`rustc_codegen_ssa::mir::analyze`][mirana]. +LLVM's `mem2reg` for those variables. +The analysis can be found in [`rustc_codegen_ssa::mir::analyze`][mirana]. [mirana]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/analyze/index.html Usually a single MIR basic block will map to a LLVM basic block, with very few exceptions: intrinsic or function calls and less basic MIR statements like -`assert` can result in multiple basic blocks. This is a perfect lede into the -non-portable LLVM-specific part of the code generation. Intrinsic generation is -fairly easy to understand as it involves very few abstraction levels in between +`assert` can result in multiple basic blocks. +This is a perfect lede into the non-portable LLVM-specific part of the code generation. +Intrinsic generation is fairly easy to understand +as it involves very few abstraction levels in between and can be found in [`rustc_codegen_llvm::intrinsic`][llvmint]. [llvmint]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/intrinsic/index.html -Everything else will use the [builder interface][builder]. This is the code that gets -called in the [`rustc_codegen_ssa::mir::*`][ssamir] modules discussed above. +Everything else will use the [builder interface][builder]. +This is the code that gets called in the +[`rustc_codegen_ssa::mir::*`][ssamir] modules discussed above. [builder]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_llvm/builder/index.html [ssamir]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/mir/index.html diff --git a/src/doc/rustc-dev-guide/src/backend/monomorph.md b/src/doc/rustc-dev-guide/src/backend/monomorph.md index e9d98597ee0d9..670614fe51379 100644 --- a/src/doc/rustc-dev-guide/src/backend/monomorph.md +++ b/src/doc/rustc-dev-guide/src/backend/monomorph.md @@ -1,33 +1,33 @@ # Monomorphization As you probably know, Rust has a very expressive type system that has extensive -support for generic types. But of course, assembly is not generic, so we need -to figure out the concrete types of all the generics before the code can -execute. - -Different languages handle this problem differently. For example, in some -languages, such as Java, we may not know the most precise type of value until -runtime. In the case of Java, this is ok because (almost) all variables are +support for generic types. +But of course, assembly is not generic, so we need +to figure out the concrete types of all the generics before the code can execute. + +Different languages handle this problem differently. +For example, in some languages, such as Java, +we may not know the most precise type of value until runtime. +In the case of Java, this is ok because (almost) all variables are reference values anyway (i.e. pointers to a heap allocated object). This flexibility comes at the cost of performance, since all accesses to an object must dereference a pointer. -Rust takes a different approach: it _monomorphizes_ all generic types. This -means that compiler stamps out a different copy of the code of a generic -function for each concrete type needed. For example, if I use a `Vec` and -a `Vec` in my code, then the generated binary will have two copies of -the generated code for `Vec`: one for `Vec` and another for `Vec`. +Rust takes a different approach: it _monomorphizes_ all generic types. +This means that compiler stamps out a different copy of the code of a generic +function for each concrete type needed. +For example, if I use a `Vec` and a `Vec` in my code, +then the generated binary will have two copies of the generated code for `Vec`: +one for `Vec` and another for `Vec`. The result is fast programs, but it comes at the cost of compile time (creating -all those copies can take a while) and binary size (all those copies might take -a lot of space). +all those copies can take a while) and binary size (all those copies might take a lot of space). Monomorphization is the first step in the backend of the Rust compiler. ## Collection -First, we need to figure out what concrete types we need for all the generic -things in our program. This is called _collection_, and the code that does this -is called the _monomorphization collector_. +First, we need to figure out what concrete types we need for all the generic things in our program. +This is called _collection_, and the code that does this is called the _monomorphization collector_. Take this example: @@ -42,8 +42,9 @@ fn main() { ``` The monomorphization collector will give you a list of `[main, banana, -peach::]`. These are the functions that will have machine code generated -for them. Collector will also add things like statics to that list. +peach::]`. +These are the functions that will have machine code generated for them. +Collector will also add things like statics to that list. See [the collector rustdocs][collect] for more info. @@ -52,8 +53,7 @@ See [the collector rustdocs][collect] for more info. The monomorphization collector is run just before MIR lowering and codegen. [`rustc_codegen_ssa::base::codegen_crate`][codegen1] calls the [`collect_and_partition_mono_items`][mono] query, which does monomorphization -collection and then partitions them into [codegen -units](../appendix/glossary.md#codegen-unit). +collection and then partitions them into [codegen units](../appendix/glossary.md#codegen-unit). ## Codegen Unit (CGU) partitioning diff --git a/src/doc/rustc-dev-guide/src/borrow-check.md b/src/doc/rustc-dev-guide/src/borrow-check.md index 826bcf8582ca8..a46cb5f958c69 100644 --- a/src/doc/rustc-dev-guide/src/borrow-check.md +++ b/src/doc/rustc-dev-guide/src/borrow-check.md @@ -1,22 +1,21 @@ # MIR borrow check -The borrow check is Rust's "secret sauce" – it is tasked with -enforcing a number of properties: +The borrow check is Rust's "secret sauce" – it is tasked with enforcing a number of properties: - That all variables are initialized before they are used. - That you can't move the same value twice. - That you can't move a value while it is borrowed. -- That you can't access a place while it is mutably borrowed (except through - the reference). +- That you can't access a place while it is mutably borrowed (except through the reference). - That you can't mutate a place while it is immutably borrowed. - etc -The borrow checker operates on the MIR. An older implementation operated on the -HIR. Doing borrow checking on MIR has several advantages: +The borrow checker operates on the MIR. +An older implementation operated on the HIR. +Doing borrow checking on MIR has several advantages: - The MIR is *far* less complex than the HIR; the radical desugaring - helps prevent bugs in the borrow checker. (If you're curious, you - can see + helps prevent bugs in the borrow checker. + (If you're curious, you can see [a list of bugs that the MIR-based borrow checker fixes here][47366].) - Even more importantly, using the MIR enables ["non-lexical lifetimes"][nll], which are regions derived from the control-flow graph. @@ -24,36 +23,38 @@ HIR. Doing borrow checking on MIR has several advantages: [47366]: https://github.com/rust-lang/rust/issues/47366 [nll]: https://rust-lang.github.io/rfcs/2094-nll.html -### Major phases of the borrow checker +## Major phases of the borrow checker -The borrow checker source is found in -[the `rustc_borrowck` crate][b_c]. The main entry point is -the [`mir_borrowck`] query. +The borrow checker source is found in [the `rustc_borrowck` crate][b_c]. +The main entry point is the [`mir_borrowck`] query. [b_c]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/index.html [`mir_borrowck`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/fn.mir_borrowck.html -- We first create a **local copy** of the MIR. In the coming steps, +- We first create a **local copy** of the MIR. + In the coming steps, we will modify this copy in place to modify the types and things to include references to the new regions that we are computing. - We then invoke [`replace_regions_in_mir`] to modify our local MIR. Among other things, this function will replace all of the [regions](./appendix/glossary.md#region) in the MIR with fresh [inference variables](./appendix/glossary.md#inf-var). -- Next, we perform a number of - [dataflow analyses](./appendix/background.md#dataflow) that +- Next, we perform a number of [dataflow analyses](./appendix/background.md#dataflow) that compute what data is moved and when. - We then do a [second type check](borrow-check/type-check.md) across the MIR: - the purpose of this type check is to determine all of the constraints between - different regions. + the purpose of this type check is to determine all of the constraints between different regions. - Next, we do [region inference](borrow-check/region-inference.md), which computes the values of each region — basically, the points in the control-flow graph where each lifetime must be valid according to the constraints we collected. - At this point, we can compute the "borrows in scope" at each point. -- Finally, we do a second walk over the MIR, looking at the actions it - does and reporting errors. For example, if we see a statement like - `*a + 1`, then we would check that the variable `a` is initialized - and that it is not mutably borrowed, as either of those would - require an error to be reported. Doing this check requires the results of all - the previous analyses. +- Finally, we do a second walk over the MIR, looking at the actions it does and reporting errors. + For example, if we see a statement like `*a + 1`, + we would check that the variable `a` is initialized and that it is not mutably borrowed, + as either of those would require an error to be reported. + Doing this check requires the results of all the previous analyses. [`replace_regions_in_mir`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_borrowck/nll/fn.replace_regions_in_mir.html + + +## Debugging the borrow checker + +See [Debugging the borrow checker](borrow-check/debugging.md) and [MIR Debugging](mir/debugging.md). diff --git a/src/doc/rustc-dev-guide/src/borrow-check/debugging.md b/src/doc/rustc-dev-guide/src/borrow-check/debugging.md new file mode 100644 index 0000000000000..306b0056a6cc5 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/borrow-check/debugging.md @@ -0,0 +1,31 @@ +# Debugging the borrow checker + +## Region Constraint Graphs and Their Strongly Connected Components + +![A graph showing a small number of regions with their outlives relations](../img/region-graphviz.png) + +With `-Z dump-mir-graphviz=yes`, you will also get Graphviz files for the outlives constraints +of the MIR bodies you asked for, as well as the strongly connected components (SCCs) on them. +They are available as `mir_dump/rs-file-name.function-name.-------.nll.0.regioncx.all.dot` and +`mir_dump/rs-file-name.function-name.-------.nll.0.regioncx.scc.dot` respectively. +For both graphs, named region variables will be shown with their external name (such as `'static`) +shown in parenthesis. +For region inference variables in universes other than the root universe, +they will be shown as `/U13` (for universe 13). +In the region graph, +edges are labelled with the MIR location where the relationship is required to hold, +or `All` if the constraint should always be true. + +![A graph showing a small number of strongly connected components on the region- +outlives-graph above](../img/scc-graphviz.png) + +**Note:** There are implicit edges from `'static` to every region, but those are not rendered +in the region graph to avoid clutter. +They _do_ however show up in the SCC graph. +This is why there are outgoing edges from `SCC(5)` in the SCC graph that do not seem +to have corresponding edges in the region outlives graph above. + +## See also + +The [general instructions on debugging dataflow](../mir/dataflow.md) also apply to +graphs generated from borrowcheck data. diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md index ab5e0cd68cfa4..0db0e07d4e7be 100644 --- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md +++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md @@ -1,22 +1,21 @@ # Procedures for breaking changes This page defines the best practices procedure for making bug fixes or soundness -corrections in the compiler that can cause existing code to stop compiling. This -text is based on -[RFC 1589](https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md). +corrections in the compiler that can cause existing code to stop compiling. +This text is based on [RFC 1589]. # Motivation [motivation]: #motivation From time to time, we encounter the need to make a bug fix, soundness -correction, or other change in the compiler which will cause existing code to -stop compiling. When this happens, it is important that we handle the change in -a way that gives users of Rust a smooth transition. What we want to avoid is -that existing programs suddenly stop compiling with opaque error messages: we -would prefer to have a gradual period of warnings, with clear guidance as to -what the problem is, how to fix it, and why the change was made. This RFC -describes the procedure that we have been developing for handling breaking +correction, or other change in the compiler which will cause existing code to stop compiling. +When this happens, it is important that we handle the change in +a way that gives users of Rust a smooth transition. +What we want to avoid is that existing programs suddenly stop compiling with opaque error messages: +we would prefer to have a gradual period of warnings, with clear guidance as to +what the problem is, how to fix it, and why the change was made. +This RFC describes the procedure that we have been developing for handling breaking changes that aims to achieve that kind of smooth transition. One of the key points of this policy is that (a) warnings should be issued @@ -24,23 +23,23 @@ initially rather than hard errors if at all possible and (b) every change that causes existing code to stop compiling will have an associated tracking issue. This issue provides a point to collect feedback on the results of that change. Sometimes changes have unexpectedly large consequences or there may be a way to -avoid the change that was not considered. In those cases, we may decide to -change course and roll back the change, or find another solution (if warnings -are being used, this is particularly easy to do). +avoid the change that was not considered. +In those cases, +we may decide to change course and roll back the change, +or find another solution (and if warnings are being used, this is particularly easy to do). ### What qualifies as a bug fix? Note that this RFC does not try to define when a breaking change is permitted. -That is already covered under [RFC 1122][]. This document assumes that the -change being made is in accordance with those policies. Here is a summary of the -conditions from RFC 1122: +That is already covered under [RFC 1122]. +This document assumes that the change being made is in accordance with those policies. +Here is a summary of the conditions from RFC 1122: - **Soundness changes:** Fixes to holes uncovered in the type system. - **Compiler bugs:** Places where the compiler is not implementing the specified semantics found in an RFC or lang-team decision. - **Underspecified language semantics:** Clarifications to grey areas where the - compiler behaves inconsistently and no formal behavior had been previously - decided. + compiler behaves inconsistently and no formal behavior had been previously decided. Please see [the RFC][rfc 1122] for full details! @@ -53,10 +52,10 @@ described in more detail below): 1. Do a **crater run** to assess the impact of the change. 2. Make a **special tracking issue** dedicated to the change. -3. Do not report an error right away. Instead, **issue forwards-compatibility - lint warnings**. - - Sometimes this is not straightforward. See the text below for suggestions - on different techniques we have employed in the past. +3. Do not report an error right away. + Instead, **issue forwards-compatibility lint warnings**. + - Sometimes this is not straightforward. + See the text below for suggestions on different techniques we have employed in the past. - For cases where warnings are infeasible: - Report errors, but make every effort to give a targeted error message that directs users to the tracking issue @@ -67,31 +66,31 @@ described in more detail below): **stabilize the change**, converting those warnings into errors. Finally, for changes to `rustc_ast` that will affect plugins, the general policy -is to batch these changes. That is discussed below in more detail. +is to batch these changes. +That is discussed below in more detail. ### Tracking issue -Every breaking change should be accompanied by a **dedicated tracking issue** -for that change. The main text of this issue should describe the change being -made, with a focus on what users must do to fix their code. The issue should be -approachable and practical; it may make sense to direct users to an RFC or some -other issue for the full details. The issue also serves as a place where users -can comment with questions or other concerns. +Every breaking change should be accompanied by a **dedicated tracking issue** for that change. +The main text of this issue should describe the change being +made, with a focus on what users must do to fix their code. +The issue should be approachable and practical; it may make sense to direct users to an RFC or some +other issue for the full details. +The issue also serves as a place where users can comment with questions or other concerns. -A template for these breaking-change tracking issues can be found -[here][template]. An example of how such an issue should look can be [found -here][breaking-change-issue]. +A template for these breaking-change tracking issues can be found [here][template]. +An example of how such an issue should look can be [found here][breaking-change-issue]. [template]: https://github.com/rust-lang/rust/issues/new?template=tracking_issue_future.md ### Issuing future compatibility warnings -The best way to handle a breaking change is to begin by issuing -future-compatibility warnings. These are a special category of lint warning. +The best way to handle a breaking change is to begin by issuing future-compatibility warnings. +These are a special category of lint warning. Adding a new future-compatibility warning can be done as follows. ```rust -// 1. Define the lint in `compiler/rustc_lint/src/builtin.rs` and +// 1. Define the lint in `compiler/rustc_lint/src/builtin.rs` and // add the metadata for the future incompatibility: declare_lint! { pub YOUR_LINT_HERE, @@ -110,7 +109,7 @@ pub struct MyLintPass { ... } -impl {Early,Late}LintPass for MyLintPass { +impl {Early,Late}LintPass for MyLintPass { ... } @@ -128,15 +127,15 @@ cx.emit_span_lint( ``` -Finally, register the lint in `compiler/rustc_lint/src/lib.rs`. +Finally, register the lint in `compiler/rustc_lint/src/lib.rs`. There are many examples in that file that already show how to do so. #### Helpful techniques -It can often be challenging to filter out new warnings from older, pre-existing -errors. One technique that has been used in the past is to run the older code -unchanged and collect the errors it would have reported. You can then issue -warnings for any errors you would give which do not appear in that original set. +It can often be challenging to filter out new warnings from older, pre-existing errors. +One technique that has been used in the past is to run the older code +unchanged and collect the errors it would have reported. +You can then issue warnings for any errors you would give which do not appear in that original set. Another option is to abort compilation after the original code completes if errors are reported: then you know that your new code will only execute when there were no errors before. @@ -144,41 +143,43 @@ there were no errors before. #### Crater and crates.io [Crater] is a bot that will compile all crates.io crates and many -public github repos with the compiler with your changes. A report will then be -generated with crates that ceased to compile with or began to compile with your -changes. Crater runs can take a few days to complete. +public github repos with the compiler with your changes. +A report will then be generated with crates that ceased to compile with, +or began to compile with your changes. +Crater runs can take a few days to complete. [Crater]: ./tests/crater.md -We should always do a crater run to assess impact. It is polite and considerate -to at least notify the authors of affected crates the breaking change. If we can -submit PRs to fix the problem, so much the better. +We should always do a crater run to assess impact. +It is polite and considerate to notify the authors of crates affected by the breaking change. +It is even better to submit PRs fixing the breakage. #### Is it ever acceptable to go directly to issuing errors? -Changes that are believed to have negligible impact can go directly to issuing -an error. One rule of thumb would be to check against `crates.io`: if fewer than -10 **total** affected projects are found (**not** root errors), we can move -straight to an error. In such cases, we should still make the "breaking change" +Changes that are believed to have negligible impact can go directly to issuing an error. +One rule of thumb would be to check against `crates.io`: if fewer than +10 **total** affected projects are found (**not** root errors), we can move straight to an error. +In such cases, we should still make the "breaking change" page as before, and we should ensure that the error directs users to this page. In other words, everything should be the same except that users are getting an -error, and not a warning. Moreover, we should submit PRs to the affected -projects (ideally before the PR implementing the change lands in rustc). +error, and not a warning. +Moreover, we should submit PRs to the affected projects +(ideally before the PR implementing the change lands in rustc). If the impact is not believed to be negligible (e.g., more than 10 crates are affected), then warnings are required (unless the compiler team agrees to grant -a special exemption in some particular case). If implementing warnings is not -feasible, then we should make an aggressive strategy of migrating crates before -we land the change so as to lower the number of affected crates. Here are some -techniques for approaching this scenario: +a special exemption in some particular case). +If implementing warnings is not feasible, +then we should make an aggressive strategy of migrating crates before +we land the change so as to lower the number of affected crates. +Here are some techniques for approaching this scenario: 1. Issue warnings for subparts of the problem, and reserve the new errors for the smallest set of cases you can. 2. Try to give a very precise error message that suggests how to fix the problem and directs users to the tracking issue. 3. It may also make sense to layer the fix: - - First, add warnings where possible and let those land before proceeding to - issue errors. + - First, add warnings where possible and let those land before proceeding to issue errors. - Work with authors of affected crates to ensure that corrected versions are available _before_ the fix lands, so that downstream users can use them. @@ -190,12 +191,11 @@ that we use for unstable features: - After a new release is made, we will go through the outstanding tracking issues corresponding to breaking changes and nominate some of them for **final comment period** (FCP). -- The FCP for such issues lasts for one cycle. In the final week or two of the - cycle, we will review comments and make a final determination: +- The FCP for such issues lasts for one cycle. + In the final week or two of the cycle, we will review comments and make a final determination: - Convert to error: the change should be made into a hard error. - - Revert: we should remove the warning and continue to allow the older code to - compile. + - Revert: we should remove the warning and continue to allow the older code to compile. - Defer: can't decide yet, wait longer, or try other strategies. Ideally, breaking changes should have landed on the **stable branch** of the @@ -206,10 +206,12 @@ compiler before they are finalized. ### Removing a lint Once we have decided to make a "future warning" into a hard error, we need a PR -that removes the custom lint. As an example, here are the steps required to -remove the `overlapping_inherent_impls` compatibility lint. First, convert the -name of the lint to uppercase (`OVERLAPPING_INHERENT_IMPLS`) ripgrep through the -source for that string. We will basically by converting each place where this +that removes the custom lint. +As an example, here are the steps required to +remove the `overlapping_inherent_impls` compatibility lint. +First, convert the name of the lint to uppercase (`OVERLAPPING_INHERENT_IMPLS`); +search the source for that string. +We will basically by converting each place where this lint name is mentioned (in the compiler, we use the upper-case name, and a macro automatically generates the lower-case string; so searching for `overlapping_inherent_impls` would not find much). @@ -234,8 +236,9 @@ declare_lint! { } ``` -This `declare_lint!` macro creates the relevant data structures. Remove it. You -will also find that there is a mention of `OVERLAPPING_INHERENT_IMPLS` later in +This `declare_lint!` macro creates the relevant data structures. +Remove it. +You will also find that there is a mention of `OVERLAPPING_INHERENT_IMPLS` later in the file as [part of a `lint_array!`][lintarraysource]; remove it too. [lintarraysource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc/lint/builtin.rs#L252-L290 @@ -255,8 +258,9 @@ where `#36889` is the tracking issue for your lint. Finally, the last class of references you will see are the places that actually **trigger** the lint itself (i.e., what causes the warnings to appear). These -you do not want to delete. Instead, you want to convert them into errors. In -this case, the [`add_lint` call][addlintsource] looks like this: +you do not want to delete. +Instead, you want to convert them into errors. +In this case, the [`add_lint` call][addlintsource] looks like this: ```rust self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, @@ -267,16 +271,16 @@ self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, You'll also often find `node_span_lint` used for this. -We want to convert this into an error. In some cases, there may be an -existing error for this scenario. In others, we will need to allocate a -fresh diagnostic code. [Instructions for allocating a fresh diagnostic +We want to convert this into an error. +In some cases, there may be an existing error for this scenario. +In others, we will need to allocate a fresh diagnostic code. + [Instructions for allocating a fresh diagnostic code can be found here.](./diagnostics/error-codes.md) You may want to mention in the extended description that the compiler behavior -changed on this point, and include a reference to the tracking issue for -the change. +changed on this point, and include a reference to the tracking issue for the change. -Let's say that we've adopted `E0592` as our code. Then we can change the -`add_lint()` call above to something like: +Let's say that we've adopted `E0592` as our code. +Then we can change the `add_lint()` call above to something like: ```rust struct_span_code_err!(self.dcx(), self.tcx.span_of_impl(item1).unwrap(), E0592, msg) @@ -296,9 +300,10 @@ struct MyDiagnostic { #### Update tests -Finally, run the test suite. These should be some tests that used to reference -the `overlapping_inherent_impls` lint, those will need to be updated. In -general, if the test used to have `#[deny(overlapping_inherent_impls)]`, that +Finally, run the test suite. +These should be some tests that used to reference +the `overlapping_inherent_impls` lint; those will need to be updated. +In general, if the test used to have `#[deny(overlapping_inherent_impls)]`, that can just be removed. ``` @@ -307,7 +312,7 @@ can just be removed. #### All done! -Open a PR. =) +Open a PR. [addlintsource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc_typeck/coherence/inherent.rs#L300-L303 [futuresource]: https://github.com/rust-lang/rust/blob/085d71c3efe453863739c1fb68fd9bd1beff214f/src/librustc_lint/lib.rs#L202-L205 @@ -316,3 +321,4 @@ Open a PR. =) [rfc 1122]: https://github.com/rust-lang/rfcs/blob/master/text/1122-language-semver.md [breaking-change-issue]: https://gist.github.com/nikomatsakis/631ec8b4af9a18b5d062d9d9b7d3d967 +[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md index e4704a10e0a78..f722385c07afe 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md @@ -5,12 +5,12 @@ More accurately, it means using an older compiler to compile a newer version of This raises a chicken-and-egg paradox: where did the first compiler come from? It must have been written in a different language. -In Rust's case it was [written in OCaml]. +In Rust's case, it was [written in OCaml][ocaml-compiler]. However, it was abandoned long ago, and the -only way to build a modern version of rustc is with a slightly less modern version. +only way to build a modern version of `rustc` is with a slightly less modern version. -This is exactly how `x.py` works: it downloads the current beta release of -rustc, then uses it to compile the new compiler. +This is exactly how Rust's bootstrap build system works: it downloads the current beta release of +`rustc`, then uses it to compile the new compiler. In this section, we give a high-level overview of [what Bootstrap does](./what-bootstrapping-does.md), followed by a high-level @@ -19,4 +19,4 @@ introduction to [how Bootstrap does it](./how-bootstrap-does-it.md). Additionally, see [debugging bootstrap](./debugging-bootstrap.md) to learn about debugging methods. [*Bootstrapping*]: https://en.wikipedia.org/wiki/Bootstrapping_(compilers) -[written in OCaml]: https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216f8aaa5b388d98da6480/src/boot +[ocaml-compiler]: https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216f8aaa5b388d98da6480/src/boot diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md index 011afa2de948c..b986895c3b100 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/what-bootstrapping-does.md @@ -1,20 +1,6 @@ # What Bootstrapping does -[*Bootstrapping*][boot] is the process of using a compiler to compile itself. -More accurately, it means using an older compiler to compile a newer version of the same compiler. - -This raises a chicken-and-egg paradox: where did the first compiler come from? -It must have been written in a different language. -In Rust's case, it was [written in OCaml][ocaml-compiler]. -However, it was abandoned long ago, and the -only way to build a modern version of `rustc` is with a slightly less modern version. - -This is exactly how [`./x.py`] works: it downloads the current beta release of -`rustc`, then uses it to compile the new compiler. - -[`./x.py`]: https://github.com/rust-lang/rust/blob/HEAD/x.py - -Note that this documentation mostly covers user-facing information. +NOTE: this documentation mostly covers user-facing information. See [bootstrap/README.md][bootstrap-internals] to read about bootstrap internals. [bootstrap-internals]: https://github.com/rust-lang/rust/blob/HEAD/src/bootstrap/README.md @@ -61,8 +47,8 @@ graph TD ### Stage 0: the pre-compiled compiler The stage0 compiler is by default the very recent _beta_ `rustc` compiler and its -associated dynamic libraries, which `./x.py` will download for you. -(You can also configure `./x.py` to change stage0 to something else.) +associated dynamic libraries, which bootstrap will download for you. +(You can also configure this in `bootstrap.toml` to change stage0 to something else.) The precompiled stage0 compiler is then used only to compile [`src/bootstrap`] and [`compiler/rustc`] with precompiled stage0 std. @@ -103,7 +89,7 @@ build the new compiler with an older compiler and then use that to build the new compiler with itself. For development, you usually only want to use `--stage 1` flag to build things. -See [Building the compiler](../how-to-build-and-run.html#building-the-compiler). +See [Building the compiler](../how-to-build-and-run.md#building-the-compiler). ### Stage 3: the same-result test @@ -155,7 +141,6 @@ There are two methods used: [boot]: https://en.wikipedia.org/wiki/Bootstrapping_(compilers) [intrinsics]: ../../appendix/glossary.md#intrinsic -[ocaml-compiler]: https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216f8aaa5b388d98da6480/src/boot ## Understanding stages of bootstrap diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index fccc3600f13b6..e9bcfb34e03d4 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -21,7 +21,7 @@ implementing a maintainable fix is taking some time. -The compiler is built using a tool called `x.py`. +The compiler is built using a tool called `bootstrap`. You will need to have Python installed to run it. ## Quick Start @@ -94,60 +94,32 @@ cd rust > For example, `git bisect` and `git blame` require access to the commit history, > so they don't work if the repository was cloned with `--depth 1`. -## What is `x.py`? +## What is bootstrap? -`x.py` is the build tool for the `rust` repository. +Bootstrap is the build tool for the `rust` repository. It can build docs, run tests, and build the compiler and standard library. This chapter focuses on the basics to be productive, but -if you want to learn more about `x.py`, [read this chapter][bootstrap]. +if you want to learn more about bootstrap, [read this chapter][bootstrap]. [bootstrap]: ./bootstrapping/intro.md [windows-security-exclusions]: https://support.microsoft.com/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26 -Also, using `x` rather than `x.py` is recommended as: +### Running bootstrap -> `./x` is the most likely to work on every system (on Unix it runs the shell script -> that does python version detection, on Windows it will probably run the -> powershell script - certainly less likely to break than `./x.py` which often just -> opens the file in an editor).[^1] - -(You can find the platform related scripts around the `x.py`, like `x.ps1`) - -Notice that this is not absolute. -For instance, using Nushell in VSCode on Win10, -typing `x` or `./x` still opens `x.py` in an editor rather than invoking the program. - -In the rest of this guide, we use `x` rather than `x.py` directly. -The following command: - -```bash -./x check -``` - -could be replaced by: - -```bash -./x.py check -``` - -### Running `x.py` - -The `x.py` command can be run directly on most Unix systems in the following format: +Bootstrap can be run on most systems (Unix, Windows if configured) in this way: ```sh ./x [flags] ``` -This is how the documentation and examples assume you are running `x.py`. +This is how the documentation and examples assume you are running bootstrap. Some alternative ways are: ```sh -# On a Unix shell if you don't have the necessary `python3` command -./x [flags] - -# In Windows Powershell (if powershell is configured to run scripts) +# In Windows PowerShell (if PowerShell is configured to run scripts) ./x [flags] +# In NuShell (if PowerShell is configured to run scripts). `./x` does not work in NuShell if `.py` files are not configured to run Python. ./x.ps1 [flags] # On the Windows Command Prompt (if .py files are configured to run Python) @@ -155,9 +127,12 @@ x.py [flags] # You can also run Python yourself, e.g.: python x.py [flags] + +# On a Unix shell if you have `python3` but an `sh` that doesn't support `local`, e.g. on Solaris +./x.py [flags] ``` -On Windows, the Powershell commands may give you an error that looks like this: +On Windows, the PowerShell commands may give you an error that looks like this: ``` PS C:\Users\vboxuser\rust> ./x ./x : File C:\Users\vboxuser\rust\x.ps1 cannot be loaded because running scripts is disabled on this system. For more @@ -169,25 +144,19 @@ At line:1 char:1 + FullyQualifiedErrorId : UnauthorizedAccess ``` -You can avoid this error by allowing powershell to run local scripts: +You can avoid this error by allowing PowerShell to run local scripts: ``` Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser ``` -#### Running `x.py` slightly more conveniently +#### Running bootstrap slightly more conveniently -There is a binary that wraps `x.py` called `x` in `src/tools/x`. -All it does is run `x.py`, but it can be installed system-wide and run from any subdirectory -of a checkout. -It also looks up the appropriate version of `python` to use. +There is a binary that wraps bootstrap called `x`. +All it does is run `./x`, but it can be installed system-wide and run from any subdirectory of a checkout. +It also looks up the appropriate version of Python to use and avoids depending on which shell you're currently using. You can install it with `cargo install --path src/tools/x`. -To clarify that this is another global installed binary util, which is -similar to the one declared in section [What is `x.py`](#what-is-xpy), but -it works as an independent process to execute the `x.py` rather than calling the -shell to run the platform related scripts. - ## Create a `bootstrap.toml` To start, run `./x setup` and select the `compiler` defaults. @@ -228,7 +197,7 @@ and `src/tools` directories. So, you can simply run `x test tidy` instead of `x test src/tools/tidy`. Or, `x build std` instead of `x build library/std`. -[rust-analyzer]: suggested.html#configuring-rust-analyzer-for-rustc +[rust-analyzer]: suggested.md#configuring-rust-analyzer-for-rustc See the chapters on [testing](../tests/running.md) and [rustdoc](../rustdoc.md) for more details. @@ -404,7 +373,7 @@ We'll cover some of them in detail in other sections: - `./x build` – builds everything using the stage 1 compiler, not just up to `std` - `./x build --stage 2` – builds everything with the stage 2 compiler including `rustdoc` -- Running tests (see the [section on running tests](../tests/running.html) for more details): +- Running tests (see the [section on running tests](../tests/running.md) for more details): - `./x test library/std` – runs the unit tests and integration tests from `std` - `./x test tests/ui` – runs the `ui` test suite - `./x test tests/ui/const-generics` - runs all the tests in @@ -441,5 +410,3 @@ Occasionally, you may need to: - Remove `build-rust-analyzer/` directory (if you have a separate rust-analyzer build directory). - Uninstall unnecessary toolchains if you use `cargo-bisect-rustc`. You can check which toolchains are installed with `rustup toolchain list`. - -[^1]: issue[#1707](https://github.com/rust-lang/rustc-dev-guide/issues/1707) diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md index a9c19fa58589f..f10f7ae1c2659 100644 --- a/src/doc/rustc-dev-guide/src/building/optimized-build.md +++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md @@ -120,7 +120,7 @@ Here is an example of how can `opt-dist` be used locally (outside of CI): --target-triple \ # select target, e.g. "x86_64-unknown-linux-gnu" --checkout-dir \ # path to rust checkout, e.g. "." --llvm-dir \ # path to built LLVM toolchain, e.g. "/foo/bar/llvm/install" - -- python3 x.py dist # pass the actual build command + -- ./x dist # pass the actual build command ``` You can run `--help` to see further parameters that you can modify. diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index bc4779db98b84..0b0cabaca6616 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -163,6 +163,8 @@ Steps for this can be [found here][r-a nvim lsp]. 2. Run `./x setup editor`, and select `vscode` to create a `.vscode/settings.json` file. `neoconf` is able to read and update rust-analyzer settings automatically when the project is opened when this file is detected. + Neovim does not expand VS Code's `${workspaceFolder}` variable, so replace each occurrence + in the generated file with the absolute path to your rust repository. #### coc.nvim @@ -346,7 +348,7 @@ into the `rlib` files, or if you are editing things that wind up in the metadata (such as the definition of the MIR). That is, you might get weird behavior from a compile when using -`--keep-stage-std=1`, for example, strange [ICEs](../appendix/glossary.html#ice) or other panics. +`--keep-stage-std=1`, for example, strange [ICEs](../appendix/glossary.md#ice) or other panics. In that case, you should simply remove the `--keep-stage-std=1` from the command and rebuild. You can also use `--keep-stage-std=1` when running tests. @@ -473,11 +475,11 @@ pkgs.mkShell { ## Shell Completions If you use Bash, Zsh, Fish or PowerShell, you can find automatically-generated shell -completion scripts for `x.py` in +completion scripts for `./x` in [`src/etc/completions`](https://github.com/rust-lang/rust/tree/HEAD/src/etc/completions). -You can use `source ./src/etc/completions/x.py.` to load completions -for your shell of choice, or `& .\src\etc\completions\x.py.ps1` for PowerShell. +You can use `source ./src/etc/completions/x.` to load completions +for your shell of choice, or `& .\src\etc\completions\x.ps1` for PowerShell. Adding this to your shell's startup script (e.g. `.bashrc`) will automatically load this completion. diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index 1a97b093489db..79f2145afce1b 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -4,8 +4,7 @@ This chapter contains a few tips to debug the compiler. These tips aim to be useful no matter what you are working on. Some of the other chapters have advice about specific parts of the compiler (e.g. the [Queries Debugging and -Testing chapter](./incrcomp-debugging.html) or the [LLVM Debugging -chapter](./backend/debugging.md)). +Testing chapter](./incrcomp-debugging.md) or the [LLVM Debugging chapter](./backend/debugging.md)). ## Configuring the compiler @@ -315,7 +314,23 @@ $ dot -T pdf maybe_init_suffix.dot > maybe_init_suffix.pdf $ firefox maybe_init_suffix.pdf # Or your favorite pdf viewer ``` -### Debugging type layouts +Graphviz also comes with a preprocessor program, +[`unflatten`](https://graphviz.org/docs/cli/unflatten/), that +sometimes helps making the outputs look less oddly spread out. +It reads a dot file and outputs another dot file, so you can use it in a pipe, +e.g: +``` +$ unflatten mir_dump/*.foo.-------.nll.0.regioncx.all.dot | dot -Tpdf -o foo-outlives.pdf +``` + +This is particularly useful for complicated region outlives graphs from +[the borrow checker](borrow-check/debugging.md). + +[An online Graphviz editor and visualiser is +also available](https://dreampuf.github.io/GraphvizOnline). + + +## Narrowing (Bisecting) Regressions The internal attribute `#[rustc_dump_layout(...)]` can be used to dump the [`Layout`] of the type it is attached to. @@ -376,6 +391,9 @@ error: aborting due to previous error [`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_public/abi/struct.Layout.html +## Debugging borrowcheck + +Debugging the borrow checker has [its own chapter](borrow-check/debugging.md). ## Configuring CodeLLDB for debugging `rustc` diff --git a/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md index 58d4bd068f5bb..eca949f5c3e8e 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/lldb-visualizers.md @@ -116,8 +116,7 @@ The bool returned from this function is somewhat complicated, see: [`update` caching](#update-caching) below for more info. When in doubt, return `False`/`None`. As of Nov 2025, -none of the visualizers return `True`, but that may change as the debug info -test suite is improved. +none of the visualizers return `True`, but that may change as the debug info test suite is improved. #### `update` caching @@ -347,12 +346,10 @@ The category we use will be called `Rust`. > TIP: all LLDB commands can be prefixed with `help` (e.g. `help type synthetic add`) for a brief description, list of arguments, and examples. -As of Nov 2025, -we use `command source ...`, which executes a series of CLI commands from the -file [`lldb_commands`](https://github.com/rust-lang/rust/blob/main/src/etc/lldb_commands) to add -providers. -This file is somewhat unwieldy, and will soon be supplanted by the Python API equivalent -outlined below. +In the past, we used `command source ...`, which executes a series of CLI commands from the +file `lldb_commands` to add providers. +This file was somewhat unwieldy, +and has been supplanted by the Python API equivalent outlined below. ## `__lldb_init_module` diff --git a/src/doc/rustc-dev-guide/src/debuginfo/testing.md b/src/doc/rustc-dev-guide/src/debuginfo/testing.md index 293a5d2a5cfbc..bcbe960034b02 100644 --- a/src/doc/rustc-dev-guide/src/debuginfo/testing.md +++ b/src/doc/rustc-dev-guide/src/debuginfo/testing.md @@ -1,8 +1,232 @@ # Testing -The debug info test suite is undergoing a substantial rewrite. -This section will be filled out as the rewrite makes progress. - -Please see [this tracking issue][148483] for more information. +> [!IMPORTANT] +> The debug info test suite is undergoing a substantial rewrite. This section will be filled out as +> the rewrite makes progress. +> +> Please see [this tracking issue][148483] for more information. [148483]: https://github.com/rust-lang/rust/issues/148483 + +Debug info tests check a few important things: + +* Are we outputting the information in the way we expect? +* Is what we output readable by the debugger? +* Do our visualizers work the way we expect? + +The first question is typically answered by `tests/codegen-llvm`, but debug info generation is often +tested incidentally, rather than deliberately. +As of Jul 2026, there is a much larger focus on the latter two questions, +and those will be covered in detail here. +The tests that answer those questions live in `tests/debuginfo`, which is executed by `compiletest`. + +For much of the test suite's lifespan, debuggers were discovered automatically, and tests were +tests were comprised of `$DEBUGGER-command` and `$DEBUGGER-check` directives (i.e. raw string +comparisons) that checked variable printing, breakpoint locations, etc. Put bluntly, this system was +a nightmare and lead to a [litany of issues](https://github.com/rust-lang/rust/issues/134682). +To help remedy this: + +1. [`tests/debuginfo` is now opt-in](https://github.com/rust-lang/rust/pull/159455) for GDB and LLDB. +2. a new directive was added: `$DEBUGGER-repr`. + This directive dispatches to custom logic that polls + the debugger for additional information that isn't visible in the printed output. + It also automatically separates output by target, + allowing the tests to be run on different platforms without conflicts. + +# The `repr` directive + +> [!IMPORTANT] +> As of July 2026, this command is only supported by LLDB. GDB support is planned, but +> has not been implemented. It is unclear whether this directive will ever be suited for use with +> CDB. + +In short, `$DEBUGGER-repr` commands are desugared to: + +``` +//@ $DEBUGGER-command:repr $VAR_NAME +//@ $DEBUGGER-check:$VAR_NAME ok +``` + +When the commands are passed to the debugger, our test framework intercepts `repr` pseudo-commands +and runs special logic on them, testing against data stored in +`tests/debuginfo//input/_input/.json`. + +"Target groups" cover the set of targets where we cannot guarantee identical output. +Those targets are defined by the + [`Target` enum in `common.py`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L54). +As of Jul 2026, this list includes `non_windows`, `windows_gnu`, and `windows_msvc`. +It is intentionally kept as short as possible, +since each target is a new set of test data that must be updated when changes are made. +There is still not a perfect solution for how tests can be +`--bless`-ed by contributors who do not have access to all of the targets. + +The input data can be automatically updated for expected changes by adding `--bless` to the test +invocation (e.g. `./x test tests/debuginfo/basic-types/main.rs --bless`). +`--bless` updates the in-memory representation, tests against it, +and if no errors occur, saves the data back to the target file (or creates a new file if necessary). + +The schema of the input data is defined by the classes in +[`common.py`](https://github.com/rust-lang/rust/blob/be3d26db984c6f96335faca1f254dc04873cb1c1/src/etc/lldb_batchmode/common.py). +The top-level container is `TargetData`. +This schema is identical for all debuggers. + +## Converting existing tests + +Nearly any time a variable is tested, the `repr` directive should be preferred over `command` + +`check`. +As of Jul 2026, only a single test has been converted over, but more will follow as +part of the test rewrite mentioned above. +Thankfully, the conversion process is fairly easy. +For a given check: + +``` +//@ lldb-command:v foo +//@ lldb-check: +``` + +The equivalent `repr` test is: + +``` +//@ lldb-repr:foo +``` + +Once all `command` + `checks` are converted to `repr`, run the tests with the `--bless` option. +If you have access to additional targets, `--bless` the data for the remainder of the target groups +as well (e.g. if you are on a Windows machine, bless once for `x86_64-pc-windows-msvc`, once for +`x86_64-pc-windows-gnu`, and use WSL to bless for `x86_64-unknown-linux-gnu`). + + +## Implementation + +### Ser/De + +`TargetData` is converted to a dictionary with `dataclasses.asdict`, and is serialized with Python's +built-in JSON library. +When testing, the data is read into a `dict`, converted to a `TargetData`, +and stored in the top level `INPUT_DATA` variable. +The current deserialization logic should be resilient to changes in the schema, +but requires that all fields contain ONLY types that can be +directly serialized/deserialized by `json.dumps`. +The acceptable types are those that make up +[`common.JsonType`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L17) + +Since the serialization/deserialization is decoupled from the debugger logic, we can easily switch +to an alternative format if we find a better alternative to json. + +The conversion logic from the debugger's internal representation to our schema classes lives in +`from_$DEBUGGER.py`. + +Once imported, `common` automatically deserializes any existing input data and [stores it in the +global variable `INPUT_DATA`](https://github.com/rust-lang/rust/blob/bf9944f0b8006b152ef4d5f408ae75a0dde3d044/src/etc/lldb_batchmode/common.py#L523). +This data is what we test against. + +> [!NOTE] +> Special care was taken to prevent `lldb_batchmode` from importing `common` unless a `repr` command +> was actually processed. This saves us from reading/writing input data for tests that don't need +> it. + +#### Format minutae + +Since type information is unique and unchanging once the debug session has begun, types are only +stored once at the top level, and are referred to by name everywhere else. + +Pointer values change from run to run. +To prevent mismatches, pointer variables do not store their value. +This is equivalent to the wildcard `[...]` used in `-check` directives. + +`BlessMetadata` is included in `TargetData`, but is not tested against. +It exists solely as a record of how the test data was generated, +to help in diagnosing issues that may occur due to Python or the debugger changing versions. + +### Entry point and `--bless` + +Upon encountering a `repr` pseudo-command, `lldb_batchmode.main` dispatches to +`check_$DEBUGGER.check()`. +If the `--bless` option was specified, the variable is converted from +the in-memory representation to our equivalent schema class. +This includes the variable's type, +visualizers, children, the children's types, etc. +Once inserted into `TargetData`, +the variable is tested against the data that was just saved to `TargetData`. + +If no exception or errors occurred and the `--bless` option was specified, `INPUT_DATA` is written +to the appropriate file just before `lldb_batchmode` exits. +If errors occur, `INPUT_DATA` is simply discarded. + +Currently, the `repr` pseudo-command is checked for directly. +GDB and LLDB both support creating custom CLI commands via Python code. +In the future, `repr` may be implemented as a CLI command for one or both debuggers. + +### Check logic + +`check_$DEBUGGER.check` converts the debugger's variable object into a `Variable` object and +compares the two. +If any mismatches are found, further processing is done to report errors in a more helpful manner. +This means that errors are encountered and reported immediately, which has a number of advantages. +Most importantly, since the debugger state has not changed since the failure, and we +still have access to the debugger's variable object, we can poll the debugger for more information +to provide more useful error messages. + +For example, LLDB can be a bit coy when it comes to reporting errors that occur within +synthetic/summary provider calls. +This is especially true when running the command within another +command, as the tests do by calling `script import lldb_batchmode; lldb_batchmode.main()` and +executing commands in that context. + +When we encounter an error, we can import the appropriate summary provider, pass the variable object +to it, and print the exception ourselves. +We can also inspect the synthetic provider class to make +sure it implements all the mandatory functions. + +Errors *do not* immediately end the test. +This is especially important now that a `--bless` option has been added. +`--bless` updates all of the input data, so we need to print all of the errors so the reader can +make an informed decision about whether or not there are further changes that need to be made. +We absolutely do not want people accidentally blessing bad data +purely because the first error happened to be an expected change. + +Errors are printed directly to `stdout` to appear as visible output from the `repr` pseudo command. +There are [several error helper functions](https://github.com/rust-lang/rust/blob/e7b595554e664e6bd281c8cf881093d6c71bc0e1/src/etc/lldb_batchmode/common.py#L35-L51) +to keep formatting consistent. + +> [!NOTE] +> When LLDB is running a `script` command, it does not print the Python interpreter's `stderr`. +> If the interpreter exits with an exception, it will print that, but none of the rest of `stderr`. +> Instead, if we decide we want to print to `stderr`, we can use the debugger's by calling +> `lldb.debugger.GetErrorFileHandle` which returns a Python `io.TextIoWrapper`. + +If no errors occurred for a given variable, `$VAR_NAME ok` is printed to `stdout` for `compiletest` +to match against. + +Before `lldb_batchmode` exits, one last check is done to ensure that all the types and variables +that were present in `INPUT_DATA` have been checked against. +If this check fails, the script reports the untested types/variables and exits with an error code. + +# LLDB versioning + +Apple distributes a fork of LLDB with Xcode that contains Swift support. +This fork of LLDB does not use the same versioning scheme as LLVM's LLDB: + +``` +# Apple: +lldb-1703.0.236.21 Apple Swift version 6.2.3 (swiftlang-6.2.3.3.21 clang-1700.6.3.2) +# LLVM: +lldb version 22.1.2 (https://github.com/llvm/llvm-project revision 1ab49a973e210e97d61e5db6557180dcb92c3e98) + clang revision 1ab49a973e210e97d61e5db6557180dcb92c3e98 + llvm revision 1ab49a973e210e97d61e5db6557180dcb92c3e98 +``` + +It does not appear that the Apple LLDB's version is derived from LLVM's version, so we cannot easily +or automatically convert between the two. +Luckily, we can still check the base LLVM version manually +by checking the appropriate release branch in the Swift LLVM repo. +For our example above, no branch exists for `Swift 6.2.3`, but there is one for `6.2.2`. +The LLVM version is located in +[`llvm/utils/gn/secondary/llvm/version.gni`](https://github.com/swiftlang/llvm-project/blob/swift/release/6.2.2/llvm/utils/gn/secondary/llvm/version.gni). +As we can see from that example, the Apple LLDB version above corresponds to (roughly) LLVM LLDB +`19.1.5`. + +This can be useful when diagnosing or writing new tests, as it allows us to get a better idea of +what features are available in the Apple LLDB used in CI. +For example, LLDB 19 was the first version to support Type Recognizer functions, +so we can assume our example Apple LLDB supports them. diff --git a/src/doc/rustc-dev-guide/src/fuzzing.md b/src/doc/rustc-dev-guide/src/fuzzing.md index 635c01d21aeec..2287b1c670779 100644 --- a/src/doc/rustc-dev-guide/src/fuzzing.md +++ b/src/doc/rustc-dev-guide/src/fuzzing.md @@ -99,7 +99,7 @@ Here are a few things you can do to help the Rust project after filing an ICE: See also [applying and removing labels][labeling]. [bisect]: https://rust-lang.github.io/cargo-bisect-rustc/ -[crash test]: tests/compiletest.html#crash-tests +[crash test]: tests/compiletest.md#crash-tests [labeling]: https://forge.rust-lang.org/release/issue-triaging.html#applying-and-removing-labels ## Minimization diff --git a/src/doc/rustc-dev-guide/src/generic-parameters-summary.md b/src/doc/rustc-dev-guide/src/generic-parameters-summary.md index 29a07e297e5e6..ea9a6327842ae 100644 --- a/src/doc/rustc-dev-guide/src/generic-parameters-summary.md +++ b/src/doc/rustc-dev-guide/src/generic-parameters-summary.md @@ -1,12 +1,17 @@ # Generic parameter definitions -This chapter will discuss how rustc tracks what generic parameters are introduced. For example given some `struct Foo` how does rustc track that `Foo` defines some type parameter `T` (and no other generic parameters). +This chapter will discuss how rustc tracks what generic parameters are introduced. +For example, given some `struct Foo`, +how does rustc track that `Foo` defines some type parameter `T` (and no other generic parameters). This will *not* cover how we track generic parameters introduced via `for<'a>` syntax (e.g. in where clauses or `fn` types), which is covered elsewhere in the [chapter on `Binder`s ][ch_binders]. # `ty::Generics` -The generic parameters introduced by an item are tracked by the [`ty::Generics`] struct. Sometimes items allow usage of generics defined on parent items, this is accomplished via the `ty::Generics` struct having an optional field to specify a parent item to inherit generic parameters of. For example given the following code: +The generic parameters introduced by an item are tracked by the [`ty::Generics`] struct. +Sometimes items allow usage of generics defined on parent items, +and this is accomplished via the `ty::Generics` struct having an optional field to specify a parent item to inherit generic parameters of. +For example, given the following code: ```rust,ignore trait Trait { @@ -14,13 +19,15 @@ trait Trait { } ``` -The `ty::Generics` used for `foo` would contain `[U]` and a parent of `Some(Trait)`. `Trait` would have a `ty::Generics` containing `[Self, T]` with a parent of `None`. +The `ty::Generics` used for `foo` would contain `[U]` and a parent of `Some(Trait)`. +`Trait` would have a `ty::Generics` containing `[Self, T]` with a parent of `None`. The [`GenericParamDef`] struct is used to represent each individual generic parameter in a `ty::Generics` listing. The `GenericParamDef` struct contains information about the generic parameter, for example its name, defid, what kind of parameter it is (i.e. type, const, lifetime). `GenericParamDef` also contains a `u32` index representing what position the parameter is (starting from the outermost parent), this is the value used to represent usages of generic parameters (more on this in the [chapter on representing types][ch_representing_types]). -Interestingly, `ty::Generics` does not currently contain _every_ generic parameter defined on an item. In the case of functions it only contains the _early bound_ parameters. +Interestingly, `ty::Generics` does not currently contain _every_ generic parameter defined on an item. +In the case of functions, it only contains the _early bound_ parameters. [ch_representing_types]: ./ty.md [`ty::Generics`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Generics.html diff --git a/src/doc/rustc-dev-guide/src/getting-started.md b/src/doc/rustc-dev-guide/src/getting-started.md index 12167347d44ef..b143beb9e0648 100644 --- a/src/doc/rustc-dev-guide/src/getting-started.md +++ b/src/doc/rustc-dev-guide/src/getting-started.md @@ -186,7 +186,7 @@ The following tasks are doable without much background knowledge but are incredi - Answer questions on [users.rust-lang.org][users], or on [Stack Overflow][so]. - Participate in the [RFC process](https://github.com/rust-lang/rfcs). - Find a [requested community library][community-library], build it, and publish - it to [Crates.io](http://crates.io). + it to [Crates.io](https://crates.io). Easier said than done, but very, very valuable! [users]: https://users.rust-lang.org/ diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md b/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md index c63c64f5f945d..b977e8f3082be 100644 --- a/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/coercions.md @@ -1,7 +1,9 @@ # Coercions - -Coercions are implicit operations which transform a value into a different type. A coercion *site* is a position where a coercion is able to be implicitly performed. There are two kinds of coercion sites: + +Coercions are implicit operations which transform a value into a different type. +A coercion *site* is a position where a coercion is able to be implicitly performed. +There are two kinds of coercion sites: - one-to-one - LUB (Least-Upper-Bound) @@ -18,15 +20,18 @@ See the Reference page on coercions for descriptions of what coercions exist and ## one-to-one coercions -With a one-to-one coercion we coerce from one singular type to a known target type. In the above example this would be the coercion from `&mut u32` to `&u32`. +With a one-to-one coercion, we coerce from one singular type to a known target type. +In the above example this would be the coercion from `&mut u32` to `&u32`. A one-to-one coercion can be performed by calling [`FnCtxt::coerce`][fnctxt_coerce]. ## LUB coercions -With a LUB coercion we coerce a set of source types to some unknown target type. Unlike one-to-one coercions, a LUB coercion *produces* the target type that all of the source types coerce to. +With a LUB coercion, we coerce a set of source types to some unknown target type. +Unlike one-to-one coercions, a LUB coercion *produces* the target type that all of the source types coerce to. -In the above example this would be the LUB coercion of both `&mut i32` and `&i32`, where we produce the target type `&i32`. +In the above example this would be the LUB coercion of both `&mut i32` and `&i32`, +where we produce the target type `&i32`. The name "LUB coercion" (Least-Upper-Bound coercion) comes from how this coercion takes a set of types and computes the least coerced/subtyped type that both source types are coercable/subtypeable into. @@ -34,7 +39,7 @@ The general process for performing a LUB coercion is as follows: ```rust ignore // * 1 -let mut coerce = CoerceMany::new(intial_lub_ty); +let mut coerce = CoerceMany::new(initial_lub_ty); for expr in exprs { // * 2 let expr_ty = fcx.check_expr_with_expectation(expr, expectation); @@ -51,11 +56,17 @@ There are a few key steps here: ### Step 1 -First we create a [`CoerceMany`][coerce_many] value, this stores all of the state required for the LUB coercion. Unlike one-to-one coercions, a LUB coercion isn't a single function call as we want to intermix typechecking with advancing the LUB coercion. +First we create a [`CoerceMany`][coerce_many] value. +This stores all of the state required for the LUB coercion. +Unlike one-to-one coercions, +a LUB coercion isn't a single function call as we want to intermix typechecking with advancing the LUB coercion. -Creating a `CoerceMany` takes some `initial_lub` type. This is different from the *target* of the coercion which is an output of a LUB coercion rather than an input (unlike a one-to-one coercion). +Creating a `CoerceMany` takes some `initial_lub` type. +This is different from the *target* of the coercion, +which is an output of a LUB coercion rather than an input (unlike a one-to-one coercion). -The initial lub ty should be derived from the [`Expectation`][expectation] for whatever expression this LUB coercion is for. It allows for inference constraints from computing the LUB coercion to propagate into the `Expectation`s used for type checking later expressions participating in the LUB coercion. +The initial lub ty should be derived from the [`Expectation`][expectation] for whatever expression this LUB coercion is for. +It allows for inference constraints from computing the LUB coercion to propagate into the `Expectation`s used for type checking later expressions participating in the LUB coercion. See the ["unnecessary inference constraints"][unnecessary_inference_constraints] header for some more information about the effects this has. @@ -65,17 +76,21 @@ If there's no `Expectation` to use then some new infer var should be made for th Next, for each expression participating in the LUB coercion, we typecheck it then invoke [`CoerceMany::coerce`][coerce_many_coerce] with its type. -In some cases the expression participating in the LUB coercion doesn't actually exist in the HIR. For example when handling an operand-less `break` or `return` expression we need `()` to participate in the LUB coercion. +In some cases, the expression participating in the LUB coercion doesn't actually exist in the HIR. +For example, when handling an operand-less `break` or `return` expression, +we need `()` to participate in the LUB coercion. In these cases the [`CoerceMany::coerce_forced_unit`][coerce_many_coerce_forced_unit] method can be used. -The `CoerceMany::coerce` and `coerce_forced_unit` methods will both emit errors if the new type causes the LUB coercion to be unsatisfiable. In this case the final type of the LUB coercion will be an error type. +The `CoerceMany::coerce` and `coerce_forced_unit` methods will both emit errors if the new type causes the LUB coercion to be unsatisfiable. +In this case the final type of the LUB coercion will be an error type. ### Step 3 Finally once all expressions have been coerced the final type of the LUB coercion can be obtained by calling [`CoerceMany::complete`][coerce_many_complete]. -The resulting type of the LUB coercion is meaningfully different from the initial lub type passed in when constructing the [`CoerceMany`][coerce_many]. You should always take the resulting type of the LUB coercion and perform any necessary checks on it. +The resulting type of the LUB coercion is meaningfully different from the initial lub type passed in when constructing the [`CoerceMany`][coerce_many]. +You should always take the resulting type of the LUB coercion and perform any necessary checks on it. ## Implementation nuances @@ -83,13 +98,18 @@ The resulting type of the LUB coercion is meaningfully different from the initia When a coerce operation succeeds we record what kind of coercion it was, for example an unsize coercion or an autoderef etc. This is handled as part of the coerce operation by writing a list of *adjustments* into the in-progress [`TypeckResults`][typeck_results]. -When building THIR we take the adjustments stored in the `TypeckResults` and make all of the coercion steps explicit. After this point in the compiler there isn't really a notion of coercions, only explicit casts and subtyping in the MIR. +When building THIR, +we take the adjustments stored in the `TypeckResults` and make all of the coercion steps explicit. +After this point in the compiler, +there isn't really a notion of coercions, only explicit casts and subtyping in the MIR. TODO: write and link to an adjustments chapter here ### How does `CoerceMany` work -[`CoerceMany`][coerce_many] works by repeatedly taking the current lub ty and some new source type, and computing a new lub ty which both types can coerce to. The core logic of taking a pair of types and computing some new third type can be found in [`try_find_coercion_lub`][try_find_coercion_lub]. +[`CoerceMany`][coerce_many] works by repeatedly taking the current lub ty and some new source type, +and computing a new lub ty which both types can coerce to. +The core logic of taking a pair of types and computing some new third type can be found in [`try_find_coercion_lub`][try_find_coercion_lub]. ```rust fn foo() {} @@ -102,19 +122,31 @@ let a = match my_bool { } ``` -In this example when type checking the `match` expression a LUB coercion is performed. This LUB coercion starts out with an initial lub ty of some inference variable `?x` due to the let statement having no known type. - -There are three expressions that participate in this LUB coercion. The first expression of a LUB coercion is special, instead of computing a new type with the existing initial lub ty, we coerce directly from the first expression to the initial lub ty. - -1. After type checking `true => foo,` we wind up with the type `FnDef(Foo)`. We then call [`CoerceMany::coerce`][coerce_many_coerce] which will perform a one-to-one coercion of `FnDef(Foo)` to `?x`. This infers `?x=FnDef(Foo)` giving us a new lub ty for the LUB coercion. -2. After type checking `true if other_bool => foo,` we once again wind up with the type `FnDef(Foo)`. We'll then call `CoerceMany::coerce` which will attempt to compute a new lub ty from our previous lub ty (`FnDef(Foo)`) and the type of this expression (`FnDef(Foo)`). This gives us a lub ty of `FnDef(Foo)`. -3. After type checking `false => bar,` we'll wind up with the type `FnDef(Bar)`. We'll then call `CoerceMany::coerce` which will attempt to compute a new lub ty from our previous lub ty (`FnDef(Foo)`) and the type of this expression (`FnDef(Bar)`). In this case we get the type `fn() -> ()` as we choose to coerce both function item types to a function pointer. +In this example, when type checking the `match` expression, a LUB coercion is performed. +This LUB coercion starts out with an initial lub ty of some inference variable `?x` due to the let statement having no known type. + +There are three expressions that participate in this LUB coercion. +The first expression of a LUB coercion is special; +instead of computing a new type with the existing initial lub ty, +we coerce directly from the first expression to the initial lub ty. + +1. After type checking `true => foo,` we wind up with the type `FnDef(Foo)`. + We then call [`CoerceMany::coerce`][coerce_many_coerce], + which will perform a one-to-one coercion of `FnDef(Foo)` to `?x`. + This infers `?x=FnDef(Foo)` giving us a new lub ty for the LUB coercion. +2. After type checking `true if other_bool => foo,` we once again wind up with the type `FnDef(Foo)`. + We'll then call `CoerceMany::coerce` which will attempt to compute a new lub ty from our previous lub ty (`FnDef(Foo)`) and the type of this expression (`FnDef(Foo)`). + This gives us a lub ty of `FnDef(Foo)`. +3. After type checking `false => bar,` we'll wind up with the type `FnDef(Bar)`. + We'll then call `CoerceMany::coerce` which will attempt to compute a new lub ty from our previous lub ty (`FnDef(Foo)`) and the type of this expression (`FnDef(Bar)`). + In this case we get the type `fn() -> ()` as we choose to coerce both function item types to a function pointer. This gives us a final type for the LUB coercion of `fn() -> ()`. ### Transitive coercions -[`CoerceMany`][coerce_many]'s algorithm of repeatedly attempting to coerce the currrent target type to the new type currently results in "Transitive Coercions". It's possible for a step in a LUB coercion to coerce an expression, and then a later step to coerce that expression further. +[`CoerceMany`][coerce_many]'s algorithm of repeatedly attempting to coerce the current target type to the new type currently results in "Transitive Coercions". +It's possible for a step in a LUB coercion to coerce an expression, and then a later step to coerce that expression further. ```rust struct Foo; @@ -123,7 +155,7 @@ use std::ops::Deref; impl Deref for Foo { type Target = [u8; 2]; - + fn deref(&self) -> &[u8; 2] { &[1; _] } @@ -138,17 +170,25 @@ fn main() { } ``` -Here we have a LUB coercion with an initial lub ty of `?x`. In the first step we do a one-to-one coercion of `&Foo` to `?x` (reminder the first step is special). +Here we have a LUB coercion with an initial lub ty of `?x`. +In the first step we do a one-to-one coercion of `&Foo` to `?x` (reminder the first step is special). -In the second step we compute a new lub ty from the current lub ty of `&Foo` and the new type of `&[u8; 2]`. This new lub ty would be `&[u8; 2]` by performing a deref coercion of `&Foo` to `&[u8; 2]` on the first expression. +In the second step we compute a new lub ty from the current lub ty of `&Foo` and the new type of `&[u8; 2]`. +This new lub ty would be `&[u8; 2]` by performing a deref coercion of `&Foo` to `&[u8; 2]` on the first expression. -In the third step we compute a new lub ty from the current lub ty of `&[u8; 2]` and the new type of `&[u8]`. This new lub ty would be `&[u8]` by performing an unsizing coercion of `&[u8; 2]` to `&[u8]` on the first two expressions. +In the third step we compute a new lub ty from the current lub ty of `&[u8; 2]` and the new type of `&[u8]`. +This new lub ty would be `&[u8]` by performing an unsizing coercion of `&[u8; 2]` to `&[u8]` on the first two expressions. -Note how the first expression is coerced twice. Once a deref coercion from `&Foo` to `&[u8; 2]`, and then an unsizing coercion from `&[u8; 2]` to `&[u8]`. +Note how the first expression is coerced twice. +Once a deref coercion from `&Foo` to `&[u8; 2]`, and then an unsizing coercion from `&[u8; 2]` to `&[u8]`. -The current implementation of transitive coercions is broken, the previous example actually ICEs on stable. While the logic for performing a LUB coercion can produce transitive coercions just fine, the rest of the compiler is not set up to handle them. +The current implementation of transitive coercions is broken, the previous example actually ICEs on stable. +While the logic for performing a LUB coercion can produce transitive coercions just fine, the rest of the compiler is not set up to handle them. + +One-to-one coercions are also not capable of producing a lot of the kinds of transitive coercions that LUB coercions can. +For example, if we take the previous example and turn it into a one-to-one coercion, +we get a compile error: -One-to-one coercions are also not capable of producing a lot of the kinds of transitive coercions that LUB coercions can. For example if we take the previous example and turn it into a one-to-one coercion we get a compile error: ```rust struct Foo; @@ -156,7 +196,7 @@ use std::ops::Deref; impl Deref for Foo { type Target = [u8; 2]; - + fn deref(&self) -> &[u8; 2] { &[1; _] } @@ -176,7 +216,7 @@ There are three ways that we can compute a new lub ty for a LUB coercion: 2. Coerce the current lub ty to the new type (or vice versa) 3. Compute a mutual supertype of the current lub ty and the new type -Unfortunately the actual implementation obsfucates this a fair amount. +Unfortunately the actual implementation obfuscates this a fair amount. Computing a mutual supertype happens implicitly due to reusing the logic for one-to-one coercions which already handles subtyping if coercing fails. @@ -188,15 +228,23 @@ There is likely room for improving the structure of this function to make it mor The implementation of one-to-one coercions is reused as part of LUB coercions. -It would be wrong for LUB coercions to use one way subtyping when relating signatures or falling back to subtyping in the case of no coercions being possible. Instead we want to compute a mutual supertype of the two types. +It would be wrong for LUB coercions to use one way subtyping when relating signatures, +or falling back to subtyping in the case of no coercions being possible. +Instead, we want to compute a mutual supertype of the two types. -The `use_lub` field on [`Coerce`][coerce_ty] exists to toggle whether to perform normal subtyping (in the case of a one-to-one coercion), or whether to compute a mutual supertype (in the case of a LUB coercion). +The `use_lub` field on [`Coerce`][coerce_ty] exists to toggle whether to perform normal subtyping (in the case of a one-to-one coercion), +or whether to compute a mutual supertype (in the case of a LUB coercion). ### Lubbing -In theory computing a mutual supertype should be as simple as creating some new infer var `?mutual_sup` and then requiring `lub_ty <: ?mutual_sup` and `new_ty <: ?mutual_sup`. In reality LUB coercions use a special [`TypeRelation`][type_relation], [`LatticeOp`][lattice_op]. +In theory, +computing a mutual supertype should be as simple as creating some new infer var `?mutual_sup`, +and then requiring `lub_ty <: ?mutual_sup` and `new_ty <: ?mutual_sup`. +In reality, LUB coercions use a special [`TypeRelation`][type_relation], [`LatticeOp`][lattice_op]. -This is primarily to work around subtyping/generalization for higher ranked types being fairly broken. Unlike normal subtyping, when encountering higher ranked types the lub type relation will switch to invariance. +This is primarily to work around subtyping/generalization for higher ranked types being fairly broken. +Unlike normal subtyping, when encountering higher ranked types, +the lub type relation will switch to invariance. This enforces that the binders of the higher ranked types are equivalent which avoids the need to pick a "most general" binder, which would be quite difficult to do. @@ -204,7 +252,8 @@ It also avoids the process of computing a mutual supertype being *order dependen The current issues with higher ranked types and subtyping would cause this property to not hold if we were to use the naive method of computing a mutual supertype. -Coercions being turned into explicit MIR operations during MIR building means that the process of computing the final type of a LUB coercion only occurs during HIR typeck. This also means the behaviour of computing a mutual supertype only matters for type inference, and is not soundness relevant. +Coercions being turned into explicit MIR operations during MIR building means that the process of computing the final type of a LUB coercion only occurs during HIR typeck. +This also means the behaviour of computing a mutual supertype only matters for type inference, and is not soundness relevant. ## Cautionary notes @@ -214,17 +263,22 @@ Care should be taken when coercing from inside of a probe as both one-to-one coe LUB coercions will emit error when a coercion step fails, this makes it entirely suitable for use inside of probes. -1-to-1 and LUB coercions will both apply *adjustments* to the coerced expressions on success. This means that if inside of a probe and an attempt to coerce succeeds, then the probe must not rollback anything. +1-to-1 and LUB coercions will both apply *adjustments* to the coerced expressions on success. +This means that if inside of a probe and an attempt to coerce succeeds, +then the probe must not rollback anything. -It's therefore correct to wrap a [`FnCtxt::coerce`][fnctxt_coerce] call inside of a [`commit_if_ok`][commit_if_ok], but would be wrong to do so if returning `Err` after the coerce call. It would also be wrong to call `FnCtxt::coerce` from within a [`probe`][probe]. +It's therefore correct to wrap a [`FnCtxt::coerce`][fnctxt_coerce] call inside of a [`commit_if_ok`][commit_if_ok], but would be wrong to do so if returning `Err` after the coerce call. +It would also be wrong to call `FnCtxt::coerce` from within a [`probe`][probe]. [`CoerceMany`][coerce_many] should never be used from within a `probe` or `commit_if_ok`. ### Never-to-Any coercions -Coercing from the never type (`!`) to an inference variable will result in a [`NeverToAny`][never_to_any] coercion with a target type of the inference variable. This is subtly different from *unifying* the inference variable with the never type. +Coercing from the never type (`!`) to an inference variable will result in a [`NeverToAny`][never_to_any] coercion with a target type of the inference variable. +This is subtly different from *unifying* the inference variable with the never type. -Unifying some infer var `?x` with `!` requires that `?x` actually be *equal* to `!`. However, a `NeverToAny` coercion allows for `?x` to be inferred to any possible type. +Unifying some infer var `?x` with `!` requires that `?x` actually be *equal* to `!`. +However, a `NeverToAny` coercion allows for `?x` to be inferred to any possible type. This distinction means that in cases where the initial lub ty of a coercion is an inference variable (e.g. there's no [`Expectation`][expectation] to use for the initial lub ty), it's still important to use a coercion instead of subtyping. @@ -234,13 +288,16 @@ See PR [#147834](https://github.com/rust-lang/rust/pull/147834) which fixes a bu Even though subtyping is not a coercion, both [`FnCtxt::coerce`][fnctxt_coerce] and [`CoerceMany::coerce`][coerce_many_coerce]/[`coerce_forced_unit`][coerce_many_coerce_forced_unit] are able to succeed due to subtyping. -For one-to-one coercions we will try to enforce the source type is a subtype of the target type. For LUB coercions we will try to compute a type that is a supertype of all the existing types. +For one-to-one coercions we will try to enforce the source type is a subtype of the target type. +For LUB coercions we will try to compute a type that is a supertype of all the existing types. -For example performing a one-to-one coercion of `?x` to `u32` will fallback to subtyping, inferring `?x eq u32`. This means that when a coercion fails there's no need to attempt subtyping afterwards. +For example performing a one-to-one coercion of `?x` to `u32` will fallback to subtyping, inferring `?x eq u32`. +This means that when a coercion fails there's no need to attempt subtyping afterwards. ### Unnecessary inference constraints -Using types from [`Expectation`][expectation]s as the initial lub ty can cause infer vars to be constrained by the types of the expressions participating in the LUB coercion. This is not always desirable as these infer vars actually only need to be constrained by the final type of the LUB coercion. +Using types from [`Expectation`][expectation]s as the initial lub ty can cause infer vars to be constrained by the types of the expressions participating in the LUB coercion. +This is not always desirable as these infer vars actually only need to be constrained by the final type of the LUB coercion. ```rust fn foo(_: T) {} @@ -254,19 +311,26 @@ foo::(match my_bool { }) ``` -Here we have a LUB coercion with the first expression being of type `FnDef(a)` and the second expression being of type `FnDef(b)`. If we use `?x` as the initial lub ty of the LUB coercion then we would get the following behaviour: +Here we have a LUB coercion with the first expression being of type `FnDef(a)` and the second expression being of type `FnDef(b)`. +If we use `?x` as the initial lub ty of the LUB coercion then we would get the following behaviour: - expression 1: infer `?x=FnDef(a)` - expression 2: find a coercion lub between `FnDef(a), FnDef(b)` resulting in `fn() -> ()` -- the final type of the LUB coercion is `fn() -> ()`. equate `?x eq fn() -> ()`, where `?x` actually already has been inferred to `FnDef(a)`, so this is actually equating `FnDef(a) eq fn() -> ()` which does not hold - -To avoid some (but not all) of these undesirable inference constraints, if the `Expectation` for the LUB coercion is an inference variable then we won't use it as the initial lub ty. Instead we create a new infer var, for example in the above code snippet we would actually make some new infer var `?y` for the initial lub ty instead of using `?x`. +- the final type of the LUB coercion is `fn() -> ()`. + equate `?x eq fn() -> ()`, where `?x` actually already has been inferred to `FnDef(a)`, + so this is actually equating `FnDef(a) eq fn() -> ()` which does not hold + +To avoid some (but not all) of these undesirable inference constraints, +if the `Expectation` for the LUB coercion is an inference variable then we won't use it as the initial lub ty. +Instead we create a new infer var, for example in the above code snippet, +we would actually make some new infer var `?y` for the initial lub ty instead of using `?x`. - expression 1: infer `?y=FnDef(a)` - expression 2: find a coercion lub between `FnDef(a), FnDef(b)` resulting in `fn() -> ()` - the final type of the LUB coercion is `fn() -> ()`, infer `?x=fn() -> ()` See [#140283](https://github.com/rust-lang/rust/pull/140283) for a case where we had undesirable inference constraints caused by not creating a new infer var. -This doesn't avoid unnecessary constraints in *all* cases, only the most common case of having an infer var as our `Expectation`. In theory it would be desirable to avoid these constraints in all cases but it would be quite involved to do so. +This doesn't avoid unnecessary constraints in *all* cases, only the most common case of having an infer var as our `Expectation`. +In theory it would be desirable to avoid these constraints in all cases but it would be quite involved to do so. [coerce_many]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/coercion/struct.CoerceMany.html [coerce_many_coerce]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/coercion/struct.CoerceMany.html#method.coerce diff --git a/src/doc/rustc-dev-guide/src/hir-typeck/method-lookup.md b/src/doc/rustc-dev-guide/src/hir-typeck/method-lookup.md index c8d529a32b532..6204f7f24ed45 100644 --- a/src/doc/rustc-dev-guide/src/hir-typeck/method-lookup.md +++ b/src/doc/rustc-dev-guide/src/hir-typeck/method-lookup.md @@ -1,9 +1,9 @@ # Method lookup Method lookup can be rather complex due to the interaction of a number -of factors, such as self types, autoderef, trait lookup, etc. This -file provides an overview of the process. More detailed notes are in -the code itself, naturally. +of factors, such as self types, autoderef, trait lookup, etc. +This file provides an overview of the process. +More detailed notes are in the code itself, naturally. One way to think of method lookup is that we convert an expression of the form `receiver.method(...)` into a more explicit [fully-qualified syntax][] @@ -19,16 +19,16 @@ particular unsizing (e.g., converting from `[T; n]` to `[T]`). Method lookup is divided into two major phases: -1. Probing ([`probe.rs`][probe]). The probe phase is when we decide what method - to call and how to adjust the receiver. -2. Confirmation ([`confirm.rs`][confirm]). The confirmation phase "applies" - this selection, updating the side-tables, unifying type variables, and - otherwise doing side-effectful things. +1. Probing ([`probe.rs`][probe]). + The probe phase is when we decide what method to call and how to adjust the receiver. +2. Confirmation ([`confirm.rs`][confirm]). + The confirmation phase "applies" this selection, updating the side-tables, + unifying type variables, and otherwise doing side-effectful things. -One reason for this division is to be more amenable to caching. The -probe phase produces a "pick" (`probe::Pick`), which is designed to be -cacheable across method-call sites. Therefore, it does not include -inference variables or other information. +One reason for this division is to be more amenable to caching. +The probe phase produces a "pick" (`probe::Pick`), +which is designed to be cacheable across method-call sites. +Therefore, it does not include inference variables or other information. [fully-qualified syntax]: https://doc.rust-lang.org/nightly/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name [UFCS]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md @@ -41,9 +41,8 @@ inference variables or other information. The first thing that the probe phase does is to create a series of *steps*. This is done by progressively dereferencing the receiver type -until it cannot be deref'd anymore, as well as applying an optional -"unsize" step. So if the receiver has type `Rc>`, this -might yield: +until it cannot be deref'd anymore, as well as applying an optional "unsize" step. +So if the receiver has type `Rc>`, this might yield: 1. `Rc>` 2. `Box<[T; 3]>` @@ -53,26 +52,24 @@ might yield: ### Candidate assembly We then search along those steps to create a list of *candidates*. A -`Candidate` is a method item that might plausibly be the method being -invoked. For each candidate, we'll derive a "transformed self type" -that takes into account explicit self. +`Candidate` is a method item that might plausibly be the method being invoked. +For each candidate, we'll derive a "transformed self type" that takes into account explicit self. Candidates are grouped into two kinds, inherent and extension. -**Inherent candidates** are those that are derived from the -type of the receiver itself. So, if you have a receiver of some -nominal type `Foo` (e.g., a struct), any methods defined within an -impl like `impl Foo` are inherent methods. Nothing needs to be -imported to use an inherent method, they are associated with the type -itself (note that inherent impls can only be defined in the same -crate as the type itself). +**Inherent candidates** are those that are derived from the type of the receiver itself. +So, if you have a receiver of some nominal type `Foo` (e.g., a struct), +any methods defined within an impl like `impl Foo` are inherent methods. +Nothing needs to be imported to use an inherent method; +they are associated with the type itself. +Note that inherent impls can only be defined in the same crate as the type itself. -**Extension candidates** are derived from imported traits. If I have -the trait `ToString` imported, and I call `to_string()` as a method, -then we will list the `to_string()` definition in each impl of -`ToString` as a candidate. These kinds of method calls are called -"extension methods". +**Extension candidates** are derived from imported traits. +If I have the trait `ToString` imported, and I call `to_string()` as a method, +then we will list the `to_string()` definition in each impl of `ToString` as a candidate. +These kinds of method calls are called "extension methods". -So, let's continue our example. Imagine that we were calling a method +So, let's continue our example. +Imagine that we were calling a method `foo` with the receiver `Rc>` and there is a trait `Foo` that defines it with `&self` for the type `Rc` as well as a method -on the type `Box` that defines `foo` but with `&mut self`. Then we -might have two candidates: +on the type `Box` that defines `foo` but with `&mut self`. +Then we might have two candidates: - `&Rc` as an extension candidate - `&mut Box` as an inherent candidate @@ -98,18 +95,17 @@ might have two candidates: ### Candidate search Finally, to actually pick the method, we will search down the steps, -trying to match the receiver type against the candidate types. At -each step, we also consider an auto-ref and auto-mut-ref to see whether -that makes any of the candidates match. For each resulting receiver -type, we consider inherent candidates before extension candidates. +trying to match the receiver type against the candidate types. +At each step, we also consider an auto-ref and auto-mut-ref to see whether +that makes any of the candidates match. +For each resulting receiver type, we consider inherent candidates before extension candidates. If there are multiple matching candidates in a group, we report an -error, except that multiple impls of the same trait are treated as a -single match. Otherwise we pick the first match we find. +error, except that multiple impls of the same trait are treated as a single match. +Otherwise we pick the first match we find. In the case of our example, the first step is `Rc>`, -which does not itself match any candidate. But when we autoref it, we -get the type `&Rc>` which matches `&Rc`. We would then -recursively consider all where-clauses that appear on the impl: if -those match (or we cannot rule out that they do), then this is the -method we would pick. Otherwise, we would continue down the series of -steps. +which does not itself match any candidate. +But when we autoref it, we get the type `&Rc>` which matches `&Rc`. +We would then recursively consider all where-clauses that appear on the impl: if +those match (or we cannot rule out that they do), then this is the method we would pick. +Otherwise, we would continue down the series of steps. diff --git a/src/doc/rustc-dev-guide/src/img/region-graphviz.png b/src/doc/rustc-dev-guide/src/img/region-graphviz.png new file mode 100644 index 0000000000000..b63f30f53a0e6 Binary files /dev/null and b/src/doc/rustc-dev-guide/src/img/region-graphviz.png differ diff --git a/src/doc/rustc-dev-guide/src/img/scc-graphviz.png b/src/doc/rustc-dev-guide/src/img/scc-graphviz.png new file mode 100644 index 0000000000000..50f5c321cfce5 Binary files /dev/null and b/src/doc/rustc-dev-guide/src/img/scc-graphviz.png differ diff --git a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md index 8b5b889bc6af3..ef4e2e60a8d25 100644 --- a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md +++ b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md @@ -9,7 +9,7 @@ These are used in [ui] tests to test whether the expected set of paths exist in the dependency graph. [`tests/ui/dep-graph/dep-graph-caller-callee.rs`]: https://github.com/rust-lang/rust/blob/HEAD/tests/ui/dep-graph/dep-graph-caller-callee.rs -[ui]: tests/ui.html +[ui]: tests/ui.md As an example, see [`tests/ui/dep-graph/dep-graph-caller-callee.rs`], or the tests below. diff --git a/src/doc/rustc-dev-guide/src/licenses.md b/src/doc/rustc-dev-guide/src/licenses.md index c4fc59d27cb16..feb6f7d9a193f 100644 --- a/src/doc/rustc-dev-guide/src/licenses.md +++ b/src/doc/rustc-dev-guide/src/licenses.md @@ -25,8 +25,8 @@ that is compatible with Rust’s license. Examples -- Porting C code from a GPL project, like GNU binutils, is not allowed. That would require Rust -itself to be licensed under the GPL. +- Porting C code from a GPL project, like GNU binutils, is not allowed. + That would require Rust itself to be licensed under the GPL. - Copying code from an algorithms text book may be allowed, but some algorithms are patented. ## Porting diff --git a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md index 439b1d809e706..6ca7b7eabe7ca 100644 --- a/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md +++ b/src/doc/rustc-dev-guide/src/llm-guidance/reviewing.md @@ -44,7 +44,7 @@ Ultimately, this is up to your judgement as a reviewer. [joel-wrong]: https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/ -You are still expected to respect your [r+ rights](../compiler-team.html#r-rights). +You are still expected to respect your [r+ rights](../compiler-team.md#r-rights). Please do not merge PRs unless you are confident in that part of that code, even if the maintainer does not wish to review LLM PRs. diff --git a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md index 8e94928c8a1a0..6ae72de006bc6 100644 --- a/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md +++ b/src/doc/rustc-dev-guide/src/llvm-coverage-instrumentation.md @@ -129,4 +129,4 @@ and `mir-opt` tests can be refreshed by running: [`tests/coverage`]: https://github.com/rust-lang/rust/tree/HEAD/tests/coverage [`src/tools/coverage-dump`]: https://github.com/rust-lang/rust/tree/HEAD/src/tools/coverage-dump [`tests/coverage-run-rustdoc`]: https://github.com/rust-lang/rust/tree/HEAD/tests/coverage-run-rustdoc -[`tests/codegen-llvm/instrument-coverage/testprog.rs`]: https://github.com/rust-lang/rust/blob/HEAD/tests/mir-opt/coverage/instrument_coverage.rs +[`tests/codegen-llvm/instrument-coverage/testprog.rs`]: https://github.com/rust-lang/rust/blob/HEAD/tests/codegen-llvm/instrument-coverage/testprog.rs diff --git a/src/doc/rustc-dev-guide/src/macro-expansion.md b/src/doc/rustc-dev-guide/src/macro-expansion.md index 40b6ef27f9b82..a3c6d9ff691d4 100644 --- a/src/doc/rustc-dev-guide/src/macro-expansion.md +++ b/src/doc/rustc-dev-guide/src/macro-expansion.md @@ -237,7 +237,7 @@ only within the macro (i.e. it should not be visible outside the macro). [code_mp]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/mbe/macro_parser [code_mr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/mbe/macro_rules [code_parse_int]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_expand/mbe/macro_parser/struct.TtParser.html#method.parse_tt -[parsing]: ./the-parser.html +[parsing]: ./the-parser.md The context is attached to AST nodes. All AST nodes generated by macros have context attached. diff --git a/src/doc/rustc-dev-guide/src/memory.md b/src/doc/rustc-dev-guide/src/memory.md index 6056f09ab2593..14601e47b81c9 100644 --- a/src/doc/rustc-dev-guide/src/memory.md +++ b/src/doc/rustc-dev-guide/src/memory.md @@ -60,7 +60,7 @@ represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`). [`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TraitRef.html [`AdtDef` and `DefId`]: ./ty.md#adts-representation [`def-id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html -[`GenericArgs`]: ./generic_arguments.html#GenericArgs +[`GenericArgs`]: ./generic_arguments.md#GenericArgs [`mk_args`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.mk_args [`AdtDef and DefId`]: ./ty-module/generic-arguments.md#adtdef-and-defid [`Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Predicate.html diff --git a/src/doc/rustc-dev-guide/src/mir/construction.md b/src/doc/rustc-dev-guide/src/mir/construction.md index b9b5f0a346416..d68406622fdd6 100644 --- a/src/doc/rustc-dev-guide/src/mir/construction.md +++ b/src/doc/rustc-dev-guide/src/mir/construction.md @@ -145,8 +145,8 @@ This is essentially equivalent to one assignment statement per aggregate field plus an assignment to the discriminant in the case of `enum`s. -[MIR]: ./index.html -[HIR]: ../hir.html +[MIR]: ./index.md +[HIR]: ../hir.md [THIR]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/index.html [`rustc_mir_build::thir::cx::expr`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_build/thir/cx/expr/index.html diff --git a/src/doc/rustc-dev-guide/src/mir/debugging.md b/src/doc/rustc-dev-guide/src/mir/debugging.md index 7e1d5b4fa9da3..244e06c6f935b 100644 --- a/src/doc/rustc-dev-guide/src/mir/debugging.md +++ b/src/doc/rustc-dev-guide/src/mir/debugging.md @@ -89,4 +89,4 @@ control-flow diagram for the whole crate: TODO: anything else? -[dataflow state]: ./dataflow.html#graphviz-diagrams +[dataflow state]: ./dataflow.md#graphviz-diagrams diff --git a/src/doc/rustc-dev-guide/src/mir/index.md b/src/doc/rustc-dev-guide/src/mir/index.md index 45d72226807a7..b5b5b20500f39 100644 --- a/src/doc/rustc-dev-guide/src/mir/index.md +++ b/src/doc/rustc-dev-guide/src/mir/index.md @@ -1,7 +1,7 @@ # The MIR (Mid-level IR) MIR is Rust's _Mid-level Intermediate Representation_. -It is constructed from [HIR](../hir.html). +It is constructed from [HIR](../hir.md). MIR was introduced in [RFC 1211]. It is a radically simplified form of Rust that is used for certain flow-sensitive safety checks – notably the borrow checker! @@ -28,7 +28,7 @@ Some of the key characteristics of MIR are: - It does not have nested expressions. - All types in MIR are fully explicit. -[cfg]: ../appendix/background.html#cfg +[cfg]: ../appendix/background.md#cfg ## Key MIR vocabulary @@ -334,7 +334,7 @@ See the const-eval WG's [docs on promotion](https://github.com/rust-lang/const-e [mirmanip_transform]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/index.html [mirmanip_dataflow]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_dataflow/index.html [`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/struct.Body.html -[newtype'd]: ../appendix/glossary.html#newtype +[newtype'd]: ../appendix/glossary.md#newtype [basicblocks]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/struct.Body.html#structfield.basic_blocks [`BasicBlock`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/struct.BasicBlock.html [`BasicBlockData`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/struct.BasicBlockData.html diff --git a/src/doc/rustc-dev-guide/src/mir/passes.md b/src/doc/rustc-dev-guide/src/mir/passes.md index 2ee7a4df5c9f4..bd200217c7f90 100644 --- a/src/doc/rustc-dev-guide/src/mir/passes.md +++ b/src/doc/rustc-dev-guide/src/mir/passes.md @@ -167,7 +167,7 @@ would cause a panic. Therefore, with this stealing mechanism, `mir_promoted` should guarantee any `mir_const_qualif*` queries are called before it actually steals, thus ensuring that the reads have already happened -(remember that [queries are memoized](../query.html), so executing a query twice +(remember that [queries are memoized](../query.md), so executing a query twice simply loads from a cache the second time). [rust-lang/rust#41710]: https://github.com/rust-lang/rust/issues/41710 @@ -182,4 +182,4 @@ simply loads from a cache the second time). [cleanup-pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir_transform/cleanup_post_borrowck/struct.CleanupPostBorrowck.html [cleanup-source]: https://github.com/rust-lang/rust/blob/e2b52ff73edc8b0b7c74bc28760d618187731fe8/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs#L27 [pass-register]: https://github.com/rust-lang/rust/blob/e2b52ff73edc8b0b7c74bc28760d618187731fe8/compiler/rustc_mir_transform/src/lib.rs#L413 -[MIR visitor]: ./visitor.html +[MIR visitor]: ./visitor.md diff --git a/src/doc/rustc-dev-guide/src/offload/contributing.md b/src/doc/rustc-dev-guide/src/offload/contributing.md index 5211bdf4303d9..66679d92af5a4 100644 --- a/src/doc/rustc-dev-guide/src/offload/contributing.md +++ b/src/doc/rustc-dev-guide/src/offload/contributing.md @@ -15,9 +15,11 @@ set -e # inputs: # lib.ll (host code) + host.out (device) -# You only need to run the first three commands once to generate lib.ll and host.out from your rust code. +# You only need to run the commands below once to generate lib.ll and host.out from your rust code. -# RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Device -Csave-temps -Zunstable-options" cargo +offload build -Zunstable-options -v --target amdgcn-amd-amdhsa -Zbuild-std=core -r +# RUSTFLAGS="--emit=llvm-bc,llvm-ir -Csave-temps -Zoffload=HostMetadata=/absolute/path/to/offload.manifest -Zunstable-options" cargo +offload build -r +# +# RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Device=/absolute/path/to/offload.manifest -Csave-temps -Zunstable-options" cargo +offload build -Zunstable-options -v --target amdgcn-amd-amdhsa -Zbuild-std=core -r # # RUSTFLAGS="--emit=llvm-bc,llvm-ir -Csave-temps -Zoffload=Host=/absolute/path/to/project/target/amdgcn-amd-amdhsa/release/deps/host.out -Zunstable-options" cargo +offload build -r # diff --git a/src/doc/rustc-dev-guide/src/offload/internals.md b/src/doc/rustc-dev-guide/src/offload/internals.md index 78a1a852d21b3..da6333f984aa6 100644 --- a/src/doc/rustc-dev-guide/src/offload/internals.md +++ b/src/doc/rustc-dev-guide/src/offload/internals.md @@ -14,12 +14,20 @@ users will need to call other compilers like clang to finish the compilation pro ## High-level compilation design: -We use a single-source, two-pass compilation approach. - -First we compile all functions that should be offloaded for the device -(e.g nvptx64, amdgcn-amd-amdhsa, intel in the future). +We use a single-source, three-pass compilation approach. + +First we compile the host code (e.g. x86-64) to find out which kernel +instantiations the host code requires, including generic ones. +This pass does not perform codegen; instead it writes a manifest that records every +`#[offload_kernel]` instance (with its concrete generic arguments) needed by the host code. + +We then compile all functions that should be offloaded for the device +(e.g nvptx64, amdgcn-amd-amdhsa, intel in the future), passing the manifest via +`-Zoffload=Device=`. +The recorded kernel instances are added as monomorphization roots, so the required generic +kernels are codegened. Currently we require cumbersome `#cfg(target_os="")` annotations, but we intend to recognize those in the future based on our offload intrinsic. -This first compilation currently does not leverage rustc's internal Query system, so it will always recompile your kernels at the moment. +This device compilation currently does not leverage rustc's internal Query system, so it will always recompile your kernels at the moment. This should be easy to fix, but we prioritize features and runtime performance improvements at the moment. Please reach out if you want to implement it, though! @@ -31,9 +39,9 @@ from the device, or both (e.g. `&mut [f64]`). We then launch the kernel, after which we inform the runtime to end this environment and move data back (as far as needed). -The second pass for the host will load the kernel artifacts from the previous compilation. +The third pass for the host will load the kernel artifacts from the device compilation. rustc in general may not "guess" or hardcode the build directory layout, -and as such it must be told the path to the kernel artifacts in the second invocation. +and as such it must be told the paths to the kernel artifacts and the manifest in the respective invocations. The logic for this could be integrated into cargo, but it also only requires a trivial cargo wrapper, which we could trivially provide via crates.io till we see larger adoption. diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index a8ff7c3d33d2f..77b8935fab837 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -30,13 +30,16 @@ use core::arch::nvptx::{ _block_dim_x as block_dim_x, _block_idx_x as block_idx_x, _thread_idx_x as thread_idx_x, }; +// Kernels can be generic, like any other Rust function. +// The concrete instantiations required by the host code are collected in a +// manifest, which the device compilation then reads (see below). #[offload_kernel] -fn kernel(x: *mut [f64; 256]) { +fn kernel(x: *mut [T; 256], value: T) { unsafe { let n = (*x).len(); let i = (thread_idx_x() + block_idx_x() * block_dim_x()) as usize; if i < n { - (*x)[i] = i as f64; + (*x)[i] = value; } } } @@ -45,9 +48,13 @@ fn kernel(x: *mut [f64; 256]) { #[unsafe(no_mangle)] fn main() { let mut x = [0.0f64; 256]; - core::intrinsics::offload::<_, _, ()>(kernel, [256, 1, 1], [1, 1, 1], (&mut x as *mut [f64; 256],)); + core::offload::offload! { + kernel = kernel, + workgroup_dim = [256, 1, 1], + args = (&mut x as *mut [f64; 256], 2.5), + } for i in 0..x.len() { - assert_eq!(x[i], i as f64); + assert_eq!(x[i], 2.5); } unsafe { libc::printf(c"all checks passed".as_ptr()); } } @@ -58,7 +65,12 @@ It is important to use a clang compiler build on the same LLVM as rustc. Just calling clang without the full path will likely use your system clang, which probably will be incompatible. So either substitute clang/lld invocations below with absolute path, or set your `PATH` accordingly. -First we generate the device (GPU) code. +The compilation runs three passes: +1. `HostMetadata`: compile the host code, writing a manifest that lists the kernel + instantiations (including generic ones) required by the host code. +2. `Device`: compile the kernels for the GPU, reading the manifest so the recorded generic + instantiations are codegened. +3. `Host`: generate the final host code, embedding the device artifact.
@@ -67,8 +79,15 @@ These are often referred to as "LLVM target names"[^list].
+First we generate the manifest from the host code: +``` +RUSTFLAGS="--emit=llvm-bc,llvm-ir -Csave-temps -Zoffload=HostMetadata=/absolute/path/to/offload.manifest -Zunstable-options" cargo +offload build -r +``` +This pass only writes the manifest. + +Now we generate the device (GPU) code, passing the manifest: ``` -RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Device -Csave-temps -Zunstable-options" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core +RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Device=/absolute/path/to/offload.manifest -Csave-temps -Zunstable-options" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core ``` You might afterwards need to copy your target/release/deps/.bc to lib.bc for now, before the next step. diff --git a/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md b/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md index ac908493ee564..b9f10ec5700ce 100644 --- a/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md +++ b/src/doc/rustc-dev-guide/src/opaque-types-impl-trait-inference.md @@ -5,7 +5,7 @@ This kind of type inference is particularly complex because, unlike other kinds of type inference, it can work across functions and function bodies. -[hidden type]: ./borrow-check/region-inference/member-constraints.html?highlight=%22hidden%20type%22#member-constraints +[hidden type]: ./borrow-check/region-inference/member-constraints.md?highlight=%22hidden%20type%22#member-constraints [opaque type]: ./opaque-types-type-alias-impl-trait.md ## Running example diff --git a/src/doc/rustc-dev-guide/src/part-4-intro.md b/src/doc/rustc-dev-guide/src/part-4-intro.md index 6a84331641757..db692012cfbe3 100644 --- a/src/doc/rustc-dev-guide/src/part-4-intro.md +++ b/src/doc/rustc-dev-guide/src/part-4-intro.md @@ -1,12 +1,14 @@ # Analysis This part discusses the many analyses that the compiler uses to check various -properties of the code and to inform later stages. Typically, this is what people -mean when they talk about "Rust's type system". This includes the -representation, inference, and checking of types, the trait system, and the -borrow checker. These analyses do not happen as one big pass or set of -contiguous passes. Rather, they are spread out throughout various parts of the -compilation process and use different intermediate representations. For example, +properties of the code and to inform later stages. +Typically, this is what people mean when they talk about "Rust's type system". +This includes the representation, inference, and checking of types, the trait system, and the +borrow checker. +These analyses do not happen as one big pass or set of contiguous passes. +Rather, they are spread out throughout various parts of the +compilation process and use different intermediate representations. +For example, type checking happens on the HIR, while borrow checking happens on the MIR. Nonetheless, for the sake of presentation, we will discuss all of these analyses in this part of the guide. diff --git a/src/doc/rustc-dev-guide/src/profiling/with-perf.md b/src/doc/rustc-dev-guide/src/profiling/with-perf.md index becaec831230c..dd802d71c0404 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with-perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with-perf.md @@ -13,7 +13,7 @@ This is a guide for how to profile rustc with [perf](https://perf.wiki.kernel.or - Make a rustup toolchain pointing to that result - see [the "build and run" section for instructions][b-a-r] -[b-a-r]: ../building/how-to-build-and-run.html#toolchain +[b-a-r]: ../building/how-to-build-and-run.md#toolchain ## Gathering a perf profile diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md index 28618cbb082a0..9893edd54b950 100644 --- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md +++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md @@ -491,7 +491,7 @@ respect to incremental compilation: `Crate` object available), and then retrieve it as any other crate. Thus, function definitions for these queries do not exist. -[mod]: ../query.html#adding-a-new-kind-of-query +[mod]: ../query.md#adding-a-new-kind-of-query ## The projection query pattern @@ -558,5 +558,5 @@ so including it in query result will increase the chance that the result won't b See for more information. -[query-model]: ./query-evaluation-model-in-detail.html +[query-model]: ./query-evaluation-model-in-detail.md [try_mark_green]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/dep_graph/graph.rs.html diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index df0c21c9d719a..e58ea4e3e41e9 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -313,7 +313,7 @@ Let's go over these elements one by one: query is processed (mostly with respect to [incremental compilation][incrcomp]). [QueryKey]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/keys/trait.QueryKey.html -[incrcomp]: queries/incremental-compilation-in-detail.html#query-modifiers +[incrcomp]: queries/incremental-compilation-in-detail.md#query-modifiers So, to add a query: diff --git a/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md index bf0d4fe3a11b7..f6be619bc1094 100644 --- a/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md +++ b/src/doc/rustc-dev-guide/src/solve/sharing-crates-with-rust-analyzer.md @@ -143,6 +143,124 @@ solver. This infrastructure is used by the external fuzzing project: . + +## Derived Traits + +- [`trait TypeVisitable` and `TypeVisitable_Generic`][type-visitable-trait-macro] +- [`trait TypeFoldable` and `TypeFoldable_Generic`][type-foldable-trait-macro] +- [`trait Lift` and `Lift_Generic`][lift-trait-macro] +- [`trait GenericTypeVisitable`][generictypevisitable] + +These traits are used heavily in `rustc_type_ir`, their associated macros +primarily exist to reduce the amount of boilerplate otherwise required to +implement `Lift`, `TypeFoldable`, `TypeVisitable` and `GenericTypeVisitable`. + +### `trait TypeVisitable` and `TypeVisitable_Generic` +[type-visitable-trait-macro]: #type-visitable-trait-macro + +This trait requires a struct or enum implements the method `visit_with(...)`, +which in turn will transfer control to `TypeVisitor`, this can be +[seen in detail here][rustc_typevisitable]. + +While ostensibly similar due to their names, `TypeVisitable_Generic` and +[`GenericTypeVisitable`][generictypevisitable] they implement two different +visiting systems. + +- `TypeVisitable_Generic` means: derive the ordinary `TypeVisitable` trait + generically over an `Interner`. +- `GenericTypeVisitable` means: derive the separate `GenericTypeVisitable` trait + used by non-nightly consumers such as rust-analyzer. + +#### `TypeVisitable_Generic` +[typevisitable_generic]: #typevisitable_generic + +It visits the value's fields in declaration order, delegating each field to that +field's own `TypeVisitable` implementation. The traversal can stop early if +the visitor returns a residual result. + +Use `#[type_visitable(ignore)]` to ignore a field; it will not be part of the +traversal and will not need to implement `TypeVisitable`. This should only +be used when the field does not need to be traversed. + +### `trait TypeFoldable` and `TypeFoldable_Generic` +[type-foldable-trait-macro]: #type-foldable-trait-macro + +The trait is implemented by things that need to embed types. This concept is +discussed in detail [here](../ty-fold.md) and can be +[followed in the source][rustc_typefoldable]. + +`TypeFoldable_Generic` derives `rustc_type_ir::TypeFoldable` for a struct or +enum. + +It consumes a value and reconstructs the same struct or enum variant after +folding its fields. It generates both fallible and infallible folding methods. + +Use `#[type_foldable(identity)]` for a field whose value must be preserved +unchanged. The macro moves that field directly into the reconstructed value +instead of passing it to the folder. Its type therefore does not need to +implement `TypeFoldable`. + +For an enum, the generated match contains one reconstruction arm per variant. + +### `trait Lift` and `Lift_Generic` +[lift-trait-macro]: #lift-trait-macro + +The trait has a method `lift_to_interner(...)`. As the name suggests, it should +'lift' something to the interner. [See here](../memory.md) to read more about +the interner [and here for the source][rustc_lift]. + +The macro `Lift_Generic` derives `Lift` for a struct or enum, with three +non-obvious considerations: + +1. The generic parameters `I` and `J` are reserved for `I: Interner` and `J` + being the interner it is being lifted to. +2. `PhantomData` is handled automatically, creating a new `PhantomData` but + _has_ to be included in the file through; `use std::marker::PhantomData;` + you cannot use `std::marker::PhantomData` directly on the field of a struct. +3. The bounds are deliberately written as associated type bounds on the `Interner` + trait rather than as `where` clauses on `LiftInto`. Given only `I: LiftInto`, + Rust can then treat bounds such as the following as implied: + +```rust +I::Ty: Lift +I::Const: Lift +``` + +This allows `Lift_Generic` to emit the bound `I: LiftInto` while still +calling `lift_to_interner` on fields of type `I::Ty`, `I::Const`, and the other +declared associated types. It also guarantees that each call produces the +destination field type expected after the derive rewrites `I::Assoc` to +`J::Assoc`. + +Without `declare_lift_into!`, the derive would need to generate a separate bound +for every interner-associated type used by every field. If a new `Interner` +associated type is expected to work with `Lift_Generic`, it needs an appropriate +`Lift` implementation and normally needs to be included in the +`declare_lift_into!` invocation. + +If you want to ignore a field, such as a primitive like a `u32` which can't be +lifted you can skip the field with `#[lift(ignore)]`. + +### `trait GenericTypeVisitable` +[generictypevisitable]: #generictypevisitable + +This a separate more general traversal trait purely used by `rust-analyzer`. +The visitor type is a parameter of the trait rather than a parameter of the +method, and visiting neither returns a result nor supports short-circuiting. + +As such a struct or enum can derive both `TypeVisitable_Generic` and +`GenericTypeVisitable` + +There is intentionally no ignore attribute. The traversal must visit every +field. This is a soundness requirement for rust-analyzer's use of the traversal +when tracing and garbage-collecting interned types. + +When the macro crate's `nightly` feature is enabled, the derive macro remains +registered but emits no tokens. The `GenericTypeVisitable` trait and its +traversal module are also excluded from the nightly configuration of +`rustc_type_ir`; they exist only in its non-nightly configuration. + + ## Long-term plans for supporting rust-analyzer In general, we aim to support rust-analyzer just as well as rustc in these shared crates—provided @@ -189,4 +307,7 @@ There are still duplicated implementations between rustc and rust-analyzer—suc [rustc oblctxt]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_trait_selection/src/traits/engine.rs#L48-L386 [r-a oblctxt]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/next_solver/obligation_ctxt.rs [rustc coerce]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_hir_typeck/src/coercion.rs -[r-a coerce]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/infer/coerce.rs \ No newline at end of file +[r-a coerce]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/infer/coerce.rs +[rustc_lift]: https://github.com/rust-lang/rust/blob/0913b18e489ac1011b580e31fa5559654be12bfc/compiler/rustc_type_ir/src/lift.rs#L18 +[rustc_typevisitable]: https://github.com/rust-lang/rust/blob/0913b18e489ac1011b580e31fa5559654be12bfc/compiler/rustc_type_ir/src/visit.rs#L62 +[rustc_typefoldable]: https://github.com/rust-lang/rust/blob/0913b18e489ac1011b580e31fa5559654be12bfc/compiler/rustc_type_ir/src/fold.rs#L71 \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 8e416c9a8be95..4573a04d0281c 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -216,9 +216,14 @@ A simple example of a test using `rustc_clean` is the [hello_world test]. ### Debuginfo tests -The tests in [`tests/debuginfo`] test debuginfo generation. -They build a program, launch a debugger, and issue commands to the debugger. -A single test can work with cdb, gdb, and lldb. +>[!IMPORTANT] +> As of [#159455](https://github.com/rust-lang/rust/pull/159455) These tests were made +> opt-in. For further context, see: +> [Stabilizing the state of the debuginfo test suite](https://github.com/rust-lang/compiler-team/issues/1012) + +The tests in [`tests/debuginfo`] test how debuginfo is interpreted by the supported debuggers, and +confirm our visualizers still work as expected. They build a program, launch a debugger, and issue +commands to the debugger. A single test can work with cdb, gdb, and lldb. Most tests should have the `//@ compile-flags: -g` directive or something similar to generate the appropriate debuginfo. @@ -228,20 +233,16 @@ To set a breakpoint on a line, add a `// #break` comment on the line. The debuginfo tests consist of a series of debugger commands along with "check" lines which specify output that is expected from the debugger. -The commands are comments of the form `// $DEBUGGER-command:$COMMAND` where +The commands are comments of the form `//@ $DEBUGGER-command:$COMMAND` where `$DEBUGGER` is the debugger being used and `$COMMAND` is the debugger command to execute. The debugger values can be: - `cdb` - `gdb` -- `gdbg` — GDB without Rust support (versions older than 7.11) -- `gdbr` — GDB with Rust support - `lldb` -- `lldbg` — LLDB without Rust support -- `lldbr` — LLDB with Rust support (this no longer exists) -The command to check the output are of the form `// $DEBUGGER-check:$OUTPUT` +The command to check the output are of the form `//@ $DEBUGGER-check:$OUTPUT` where `$OUTPUT` is the output to expect. For example, the following will build the test, start the debugger, set a @@ -262,6 +263,35 @@ fn main() { fn b() {} ``` +Additionally, there is a special command, `//@ $DEBUGGER-repr:$VAR_NAME` intended to verify +variables (and their visualizers) with more granularity than can be achieved with simple string +comparison. This directive should be preferred over the `-command`/`-check` whenever possible. + +> [!NOTE] +> At time of writing (July 2026) this command is limited to LLDB, with an implementation coming soon +> for GDB. There are not firm plans to port the logic to CDB. + +This command effectivly desugars into: + +``` +//@ $DEBUGGER-command:repr $VAR_NAME +//@ $DEBUGGER-check:$VAR_NAME ok +``` + +The `repr $VAR_NAME` command is intercepted by special logic that uses the debuggers' API to inspect +data that isn't reflected in the variable's printed output. The variable in memory is compared +against input data stored in +`tests/debuginfo//input/_input/.json` and +provides detailed error messages on failure. + +> [!IMPORTANT] +> `-repr` directives **are** compatible with the `--bless` option, unlike `-command`/`-check`. +> `--bless`-ing a file with `-repr` commands will automatically create/update the appropriate +> target's input data file. + +The implementation details of this command are further described in +[the Testing section of the Debug Info chapter](../debuginfo/testing.md). + The following [directives](directives.md) are available to disable a test based on the debugger currently being used: @@ -272,7 +302,11 @@ the debugger currently being used: to the given version - `ignore-gdb-version: 7.11.90 - 8.0.9` — ignores the test if the version of gdb is in a range (inclusive) -- `min-lldb-version: 310` — ignores the test if the version of lldb is below the given version +- `min-apple-lldb-version: 1703.0.236.21`/`min-llvm-lldb-version: 21.1.0` — ignores the test if the + version of lldb is below the given version. + Note: Apple's fork of LLDB (distributed with Xcode) uses a different versioning scheme that is not + easily mappable to LLVM's LLDB version numbers. As such, the version gates are specified by + vendor. Further info on manually checking version equivalence is available [here](../debuginfo/testing.md#lldb-versioning) - `rust-lldb` — ignores the test if lldb is not contain the Rust plugin. NOTE: The "Rust" version of LLDB doesn't exist anymore, so this will always be ignored. This should probably be removed. @@ -343,7 +377,7 @@ If you need to work with `#![no_std]` cross-compiling tests, consult the ### Assembly tests The tests in [`tests/assembly-llvm`] test LLVM assembly output. -They compile the test with the `--emit=asm` flag to emit a `.s` file with the assembly output. +They compile the test with the `--emit asm` flag to emit a `.s` file with the assembly output. They then run the LLVM [FileCheck] tool. Each test should be annotated with the `//@ assembly-output:` directive with a @@ -562,7 +596,7 @@ some reason, use the `//@ ignore-coverage-map` or `//@ ignore-coverage-run` dire In `coverage-map` mode, these tests verify the mappings between source code regions and coverage counters that are emitted by LLVM. -They compile the test with `--emit=llvm-ir`, then use a custom tool ([`src/tools/coverage-dump`]) to +They compile the test with `--emit llvm-ir`, then use a custom tool ([`src/tools/coverage-dump`]) to extract and pretty-print the coverage mappings embedded in the IR. These tests don't require the profiler runtime, so they run in PR CI jobs and are easy to run/bless locally. @@ -679,12 +713,11 @@ However, it uses the `--extern` flag to link to the extern crate to make the crate be available as an extern prelude. That allows you to specify the additional syntax of the `--extern` flag, such as renaming a dependency. -For example, `//@ aux-crate:foo=bar.rs` will compile -`auxiliary/bar.rs` and make it available under then name `foo` within the test. +For example, `//@ aux-crate: foo=bar.rs` will compile +`auxiliary/bar.rs` and make it available under the name `foo` within the test. This is similar to how Cargo does dependency renaming. -It is also possible to -specify [`--extern` modifiers](https://github.com/rust-lang/rust/issues/98405). -For example, `//@ aux-crate:noprelude:foo=bar.rs`. +It is also possible to specify [`--extern` modifiers]. +For example, `//@ aux-crate: noprelude:foo=bar.rs`. `aux-bin` is similar to `aux-build` but will build a binary instead of a library. The binary will be available in `auxiliary/bin` relative to the working directory of the test. @@ -702,7 +735,7 @@ same parent folder as the main test file. However, it also has four additional preset behavior compared to `aux-build` for the proc-macro test auxiliary: -1. The aux test file is built with `--crate-type=proc-macro`. +1. The aux test file is built with `--crate-type proc-macro`. 2. The aux test file is built without `-C prefer-dynamic`, i.e. it will not try to produce a dylib for the aux crate. 3. The aux crate is made available to the test file via extern prelude with @@ -871,3 +904,5 @@ Where `N` is the number of threads to use for the parallel frontend, and `M` is Also, when running with `--parallel-frontend-threads`, the `compare-output-by-lines` directive would be implied for all tests, since the output from the parallel frontend can be non-deterministic in terms of the order of lines. The parallel frontend is available in UI tests only at the moment, and is not currently supported in other test suites. + +[`--extern` modifiers]: https://github.com/rust-lang/rust/issues/98405 diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 5468fff2b7775..cca649fbfdd40 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -51,7 +51,7 @@ Directives can generally be found by browsing the ### Auxiliary builds -See [Building auxiliary crates](compiletest.html#building-auxiliary-crates) +See [Building auxiliary crates](compiletest.md#building-auxiliary-crates) | Directive | Explanation | Supported test suites | Possible values | |-----------------------|-------------------------------------------------------------------------------------------------------|----------------------------------------|--------------------------------------------------------------------| @@ -62,7 +62,7 @@ See [Building auxiliary crates](compiletest.html#building-auxiliary-crates) | `proc-macro` | Similar to `aux-build`, but for aux forces host and don't use `-Cprefer-dynamic`[^pm]. | All except `run-make`/`run-make-cargo` | Path to auxiliary proc-macro `.rs` file | | `build-aux-docs` | Build docs for auxiliaries as well. Note that this only works with `aux-build`, not `aux-crate`. | All except `run-make`/`run-make-cargo` | N/A | -[^pm]: please see the [Auxiliary proc-macro section](compiletest.html#auxiliary-proc-macro) in the compiletest chapter for specifics. +[^pm]: please see the [Auxiliary proc-macro section](compiletest.md#auxiliary-proc-macro) in the compiletest chapter for specifics. ### Controlling outcome expectations @@ -309,7 +309,7 @@ separate tools. For more information, please read their respective chapters as linked above. [rustdoc-html-tests]: ../rustdoc-internals/rustdoc-html-test-suite.md -[rustdoc-js-tests]: ../rustdoc-internals/search.html#testing-the-search-engine +[rustdoc-js-tests]: ../rustdoc-internals/search.md#testing-the-search-engine [rustdoc-json-tests]: ../rustdoc-internals/rustdoc-json-test-suite.md ### Pretty printing diff --git a/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md b/src/doc/rustc-dev-guide/src/tests/optional-x86_64-gnu-parallel-frontend.md similarity index 92% rename from src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md rename to src/doc/rustc-dev-guide/src/tests/optional-x86_64-gnu-parallel-frontend.md index e8c91044be1d7..20dc5adeaa484 100644 --- a/src/doc/rustc-dev-guide/src/tests/x86_64-gnu-parallel-frontend.md +++ b/src/doc/rustc-dev-guide/src/tests/optional-x86_64-gnu-parallel-frontend.md @@ -1,5 +1,7 @@ # Parallel frontend testing on CI +NOTE: this job is optional and allowed to fail. + If you see any test failures in `tests/ui` from the CI job `x86_64-gnu-parallel-frontend`, please add `//@ ignore-parallel-frontend triage` to the failing test, even if your PR is otherwise entirely unrelated to parallel compiler or its testing. diff --git a/src/doc/rustc-dev-guide/src/traits/caching.md b/src/doc/rustc-dev-guide/src/traits/caching.md index be72f6e89f9ac..6c3f94d96e3fd 100644 --- a/src/doc/rustc-dev-guide/src/traits/caching.md +++ b/src/doc/rustc-dev-guide/src/traits/caching.md @@ -24,7 +24,7 @@ On the other hand, if there is no hit, we need to go through the [selection process] from scratch. Suppose, we come to the conclusion that the only possible impl is this one, with def-id 22: -[selection process]: ./resolution.html#selection +[selection process]: ./resolution.md#selection ```rust,ignore impl Foo for usize { ... } // Impl #22 @@ -34,7 +34,7 @@ We would then record in the cache `usize : Foo<$0> => ImplCandidate(22)`. Next we would [confirm] `ImplCandidate(22)`, which would (as a side-effect) unify `$t` with `isize`. -[confirm]: ./resolution.html#confirmation +[confirm]: ./resolution.md#confirmation Now, at some later time, we might come along and see a `usize : Foo<$u>`. When replaced with a placeholder, this would yield `usize : Foo<$0>`, just as @@ -61,7 +61,7 @@ to be pretty clearly safe and also still retains a very high hit rate **TODO**: it looks like `pick_candidate_cache` no longer exists. In general, is this section still accurate at all? -[`ParamEnv`]: ../typing-parameter-envs.html -[`tcx`]: ../ty.html +[`ParamEnv`]: ../typing-parameter-envs.md +[`tcx`]: ../ty.md [#18290]: https://github.com/rust-lang/rust/issues/18290 [#22019]: https://github.com/rust-lang/rust/issues/22019 diff --git a/src/doc/rustc-dev-guide/src/traits/canonical-queries.md b/src/doc/rustc-dev-guide/src/traits/canonical-queries.md index 389f380e4b8de..06b41e27c644a 100644 --- a/src/doc/rustc-dev-guide/src/traits/canonical-queries.md +++ b/src/doc/rustc-dev-guide/src/traits/canonical-queries.md @@ -3,7 +3,7 @@ The "start" of the trait system is the **canonical query** (these are both queries in the more general sense of the word – something you would like to know the answer to – and in the -[rustc-specific sense](../query.html)). The idea is that the type +[rustc-specific sense](../query.md)). The idea is that the type checker or other parts of the system, may in the course of doing their thing want to know whether some trait is implemented for some type (e.g., is `u32: Debug` true?). Or they may want to @@ -244,4 +244,3 @@ don't know what that type is yet!). error at this point, since the element types of `t` and `u` are still not yet known, even though they are known to be the same.) - diff --git a/src/doc/rustc-dev-guide/src/traits/canonicalization.md b/src/doc/rustc-dev-guide/src/traits/canonicalization.md index 616636d616647..4bd56a020f14f 100644 --- a/src/doc/rustc-dev-guide/src/traits/canonicalization.md +++ b/src/doc/rustc-dev-guide/src/traits/canonicalization.md @@ -1,7 +1,7 @@ # Canonicalization > **NOTE**: FIXME: The content of this chapter has some overlap with -> [Next-gen trait solving Canonicalization chapter](../solve/canonicalization.html). +> [Next-gen trait solving Canonicalization chapter](../solve/canonicalization.md). > It is suggested to reorganize these contents in the future. Canonicalization is the process of **isolating** an inference value @@ -10,7 +10,7 @@ from its context. It is a key part of implementing to get more context. Canonicalization is really based on a very simple concept: every -[inference variable](../type-inference.html#vars) is always in one of +[inference variable](../type-inference.md#vars) is always in one of two states: either it is **unbound**, in which case we don't know yet what type it is, or it is **bound**, in which case we do. So to isolate some data-structure T that contains types/regions from its @@ -20,7 +20,7 @@ starting from zero and numbered in a fixed order (left to right, for the most part, but really it doesn't matter as long as it is consistent). -[cq]: ./canonical-queries.html +[cq]: ./canonical-queries.md So, for example, if we have the type `X = (?T, ?U)`, where `?T` and `?U` are distinct, unbound inference variables, then the canonical @@ -45,7 +45,7 @@ trait query: `?A: Foo<'static, ?B>`, where `?A` and `?B` are unbound. This query contains two unbound variables, but it also contains the lifetime `'static`. The trait system generally ignores all lifetimes and treats them equally, so when canonicalizing, we will *also* -replace any [free lifetime](../appendix/background.html#free-vs-bound) with a +replace any [free lifetime](../appendix/background.md#free-vs-bound) with a canonical variable (Note that `'static` is actually a _free_ lifetime variable here. We are not considering it in the typing context of the whole program but only in the context of this trait reference. Mathematically, we @@ -111,7 +111,7 @@ suffice to say that it will compute a [certainty value][cqqr] (`Proven` or `Ambiguous`) and have side-effects on the inference variables we've created. For example, if there were only one impl of `Foo`, like so: -[cqqr]: ./canonical-queries.html#query-response +[cqqr]: ./canonical-queries.md#query-response ```rust,ignore impl<'a, X> Foo<'a, X> for Vec @@ -257,4 +257,3 @@ cases where the value is just a canonical variable. In our example, `values[2]` is `?C`, so that means we can deduce that `?C := ?B` and `'?D := 'static`. This gives us a partial set of values. Anything for which we do not find a value, we create an inference variable.) - diff --git a/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md b/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md index 9dbb62a7e3af8..ffab13374c9cc 100644 --- a/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md +++ b/src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md @@ -2,7 +2,7 @@ In logic programming terms, a **goal** is something that you must prove and a **clause** is something that you know is true. As -described in the [lowering to logic](./lowering-to-logic.html) +described in the [lowering to logic](./lowering-to-logic.md) chapter, Rust's trait solver is based on an extension of hereditary harrop (HH) clauses, which extend traditional Prolog Horn clauses with a few new superpowers. diff --git a/src/doc/rustc-dev-guide/src/traits/hrtb.md b/src/doc/rustc-dev-guide/src/traits/hrtb.md index aa85448afea5c..1d671e3ebcf71 100644 --- a/src/doc/rustc-dev-guide/src/traits/hrtb.md +++ b/src/doc/rustc-dev-guide/src/traits/hrtb.md @@ -41,7 +41,7 @@ subtyping, we recommend you read the paper). There are a few parts: 3. Check for _placeholder leaks_. [hrsubtype]: ./hrtb.md -[placeholder]: ../appendix/glossary.html#placeholder +[placeholder]: ../appendix/glossary.md#placeholder [paper by SPJ]: https://www.microsoft.com/en-us/research/publication/practical-type-inference-for-arbitrary-rank-types So let's work through our example. diff --git a/src/doc/rustc-dev-guide/src/traits/resolution.md b/src/doc/rustc-dev-guide/src/traits/resolution.md index f668d6ccf6198..394d800b5f868 100644 --- a/src/doc/rustc-dev-guide/src/traits/resolution.md +++ b/src/doc/rustc-dev-guide/src/traits/resolution.md @@ -6,7 +6,7 @@ some non-obvious things. **Note:** This chapter (and its subchapters) describe how the trait solver **currently** works. However, we are in the process of designing a new trait solver. If you'd prefer to read about *that*, -see [*this* subchapter](./chalk.html). +see [*this* subchapter](./chalk.md). ## Major concepts @@ -181,7 +181,7 @@ in that list. If so, it is considered satisfied. More precisely, we want to check whether there is a where-clause obligation that is for the same trait (or some subtrait) and which can match against the obligation. -[parameter environment]: ../typing-parameter-envs.html +[parameter environment]: ../typing-parameter-envs.md Consider this simple example: diff --git a/src/doc/rustc-dev-guide/src/type-inference.md b/src/doc/rustc-dev-guide/src/type-inference.md index 24982a209fd0d..196fcdd9190c3 100644 --- a/src/doc/rustc-dev-guide/src/type-inference.md +++ b/src/doc/rustc-dev-guide/src/type-inference.md @@ -116,7 +116,7 @@ actual return type is not `()`, but rather `InferOk<()>`. The to ensure that these are fulfilled (typically by enrolling them in a fulfillment context). See the [trait chapter] for more background on that. -[trait chapter]: traits/resolution.html +[trait chapter]: traits/resolution.md You can similarly enforce subtyping through `infcx.at(..).sub(..)`. The same basic concepts as above apply. diff --git a/src/doc/rustc-dev-guide/src/variance.md b/src/doc/rustc-dev-guide/src/variance.md index 96fde1d87cca5..de259d38c3ec0 100644 --- a/src/doc/rustc-dev-guide/src/variance.md +++ b/src/doc/rustc-dev-guide/src/variance.md @@ -2,7 +2,7 @@ For a more general background on variance, see the [background] appendix. -[background]: ./appendix/background.html +[background]: ./appendix/background.md During type checking, we must infer the variance of type and lifetime parameters. The algorithm is taken from Section 4 of the paper ["Taming the @@ -139,7 +139,7 @@ crate (through `crate_variances`), but since most changes will not result in a change to the actual results from variance inference, the `variances_of` query will wind up being considered green after it is re-evaluated. -[rga]: ./queries/incremental-compilation.html +[rga]: ./queries/incremental-compilation.md diff --git a/src/doc/rustc-dev-guide/src/walkthrough.md b/src/doc/rustc-dev-guide/src/walkthrough.md index 212fb298fd0b3..b7eb2b56617bc 100644 --- a/src/doc/rustc-dev-guide/src/walkthrough.md +++ b/src/doc/rustc-dev-guide/src/walkthrough.md @@ -244,7 +244,7 @@ There are a couple of things that may happen for some PRs during the review proc some merge conflicts with other PRs that happen to get merged first. You should fix these merge conflicts using the normal git procedures. -[crater]: ./tests/crater.html +[crater]: ./tests/crater.md If you are not doing a new feature or something like that (e.g. if you are fixing a bug), then that's it! diff --git a/src/doc/rustc/src/platform-support/avr-none.md b/src/doc/rustc/src/platform-support/avr-none.md index 1862890ca43f3..58144d058db1b 100644 --- a/src/doc/rustc/src/platform-support/avr-none.md +++ b/src/doc/rustc/src/platform-support/avr-none.md @@ -66,7 +66,7 @@ recommended to always use `--release` to avoid running out of space. Also, please note that specifying `-C target-cpu`[^1] is required - here's a list of the possible variants: -https://github.com/llvm/llvm-project/blob/093d4db2f3c874d4683fb01194b00dbb20e5c713/clang/lib/Basic/Targets/AVR.cpp#L32 +[https://github.com/llvm/llvm-project/blob/d5a6124259b55789bc49489632efa7c168a4f6cb/clang/lib/Basic/Targets/AVR.cpp#L48](https://github.com/llvm/llvm-project/blob/d5a6124259b55789bc49489632efa7c168a4f6cb/clang/lib/Basic/Targets/AVR.cpp#L48) Note that devices that have no SRAM are not supported, same as when compiling C/C++ programs with avr-gcc or Clang. @@ -86,4 +86,4 @@ $ simavr -m atmega328p ./target/avr-none/release/your-project.elf ``` Alternatively, if you want to write a couple of actual `#[test]`s, you can use -[`avr-tester`](https://github.com/Patryk27/avr-tester). +[`avr-tester`](https://crates.io/crates/avr-tester). diff --git a/tests/ui/target_modifiers/auxiliary/sanitizer_default_explicit.rs b/tests/ui/target_modifiers/auxiliary/sanitizer_default_explicit.rs new file mode 100644 index 0000000000000..831c681179b9a --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/sanitizer_default_explicit.rs @@ -0,0 +1,10 @@ +// This represents an rlib where SCS is explicitly provided as a -Zsanitizer flag. + +//@ no-prefer-dynamic +//@ compile-flags: --target riscv64gc-unknown-fuchsia -Zsanitizer=shadow-call-stack +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/auxiliary/sanitizer_default_implicit.rs b/tests/ui/target_modifiers/auxiliary/sanitizer_default_implicit.rs new file mode 100644 index 0000000000000..6aac2294283f8 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/sanitizer_default_implicit.rs @@ -0,0 +1,11 @@ +// This represents an rlib where SCS is not explicitly provided as a -Zsanitizer flag. +// SCS is a default_sanitizer on riscv64gc-unknown-fuchsia. + +//@ no-prefer-dynamic +//@ compile-flags: --target riscv64gc-unknown-fuchsia +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/auxiliary/sanitizer_non_default.rs b/tests/ui/target_modifiers/auxiliary/sanitizer_non_default.rs new file mode 100644 index 0000000000000..c04ab13b310ff --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/sanitizer_non_default.rs @@ -0,0 +1,11 @@ +// This represents an rlib where CFI is explicitly provided as a -Zsanitizer flag. +// CFI is not a default_sanitizer for riscv64gc-unknown-fuchsia. + +//@ no-prefer-dynamic +//@ compile-flags: --target riscv64gc-unknown-fuchsia -Zsanitizer=cfi -Clinker-plugin-lto +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/sanitizer_default.explicit_mismatch.stderr b/tests/ui/target_modifiers/sanitizer_default.explicit_mismatch.stderr new file mode 100644 index 0000000000000..aa194b329b684 --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer_default.explicit_mismatch.stderr @@ -0,0 +1,9 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default` + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zsanitizer=shadow-call-stack` in this crate is incompatible with `-Zsanitizer=cfi` in dependency `sanitizer_non_default` + = help: set `-Zsanitizer=cfi` in this crate or `-Zsanitizer=shadow-call-stack` in `sanitizer_non_default` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizer_default.implicit_mismatch.stderr b/tests/ui/target_modifiers/sanitizer_default.implicit_mismatch.stderr new file mode 100644 index 0000000000000..cb3ebf06d892f --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer_default.implicit_mismatch.stderr @@ -0,0 +1,9 @@ +error: mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default` + | + = help: the `-Zsanitizer` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zsanitizer` is unset in this crate which is incompatible with `-Zsanitizer=cfi` in dependency `sanitizer_non_default` + = help: set `-Zsanitizer=cfi` in this crate or unset `-Zsanitizer` in `sanitizer_non_default` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=sanitizer` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/sanitizer_default.rs b/tests/ui/target_modifiers/sanitizer_default.rs new file mode 100644 index 0000000000000..5b3b1f4d7b6e5 --- /dev/null +++ b/tests/ui/target_modifiers/sanitizer_default.rs @@ -0,0 +1,36 @@ +// Test that we do not get an ABI mismatch error when a default sanitizer is not +// explicitly provided via a -Zsanitizer flag. +// +// riscv64gc-unknown-fuchsia has shadow-call-stack as a default sanitizer. +// Compiling one crate without `-Zsanitizer` and another crate with the target's +// default sanitizer explicitly specified (-Zsanitizer=shadow-call-stack) +// must be accepted. + +//@ aux-build:sanitizer_default_implicit.rs +//@ aux-build:sanitizer_default_explicit.rs +//@ aux-build:sanitizer_non_default.rs +//@ compile-flags: --target riscv64gc-unknown-fuchsia +//@ needs-llvm-components: riscv +//@ ignore-backends: gcc + +//@ revisions: implicit_default explicit_default implicit_mismatch explicit_mismatch +//@[implicit_default] check-pass +//@[explicit_default] compile-flags: -Zsanitizer=shadow-call-stack +//@[explicit_default] check-pass +//@[explicit_mismatch] compile-flags: -Zsanitizer=shadow-call-stack + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] + +#[cfg(any(implicit_default, explicit_default))] +extern crate sanitizer_default_implicit; + +#[cfg(any(implicit_default, explicit_default))] +extern crate sanitizer_default_explicit; + +// We still expect the normal mismatch error with a non-default sanitizer. +#[cfg(any(implicit_mismatch, explicit_mismatch))] +extern crate sanitizer_non_default; +//[implicit_mismatch]~? ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default` +//[explicit_mismatch]~? ERROR mixing `-Zsanitizer` will cause an ABI mismatch in crate `sanitizer_default` diff --git a/tests/ui/traits/next-solver/adt-const-param-projection.rs b/tests/ui/traits/next-solver/adt-const-param-projection.rs new file mode 100644 index 0000000000000..926451bae2c3d --- /dev/null +++ b/tests/ui/traits/next-solver/adt-const-param-projection.rs @@ -0,0 +1,26 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ build-pass +//@ compile-flags: --crate-type=lib +//@ edition: 2015 + +// Regression test for https://github.com/rust-lang/rust/issues/156294. +// We used to not normalize the type we get back from const evaluation, so the value of +// `EMPTY_MATRIX` had the type `::Matrix` instead of `[usize; 1]`. Nobody +// normalized it later on either, so we ended up ICEing when mangling the symbol name of +// `Walk::::new`. + +#![feature(adt_const_params)] + +pub const EMPTY_MATRIX: ::Matrix = [1]; +pub struct Walk::Matrix>; +impl Walk { + pub fn new() {} +} +pub enum Type {} +pub trait Trait { + type Matrix; +} +impl Trait for Type { + type Matrix = [usize; 1]; +} diff --git a/tests/ui/traits/next-solver/normalize-const-item-type.rs b/tests/ui/traits/next-solver/normalize-const-item-type.rs new file mode 100644 index 0000000000000..873b0bb690e4c --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-const-item-type.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -Znext-solver +#![feature(generic_const_items)] +#![feature(min_generic_const_args)] +#![feature(generic_const_args)] + +use std::marker::PhantomData; + +trait Project1<'a> { + type Assoc1; +} + +impl<'a, T> Project1<'a> for T { + type Assoc1 = (); +} + +trait Project2 { + type Assoc2; +} + +impl> Project2 for PhantomData { + type Assoc2 = usize; +} + +const N: as Project2>::Assoc2 = 2_usize; + +fn func(_: [(); core::direct_const_arg!(N::)]) +//~^ ERROR: type mismatch resolving `N == _` [E0271] +//~| ERROR: the type `[(); N::]` is not well-formed +//~| ERROR: type mismatch resolving `N == _` [E0271] +where + for<'a> u32: Project1<'a>, +{} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize-const-item-type.stderr b/tests/ui/traits/next-solver/normalize-const-item-type.stderr new file mode 100644 index 0000000000000..67f4f596f40bf --- /dev/null +++ b/tests/ui/traits/next-solver/normalize-const-item-type.stderr @@ -0,0 +1,23 @@ +error[E0271]: type mismatch resolving `N == _` + --> $DIR/normalize-const-item-type.rs:26:12 + | +LL | fn func(_: [(); core::direct_const_arg!(N::)]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + +error: the type `[(); N::]` is not well-formed + --> $DIR/normalize-const-item-type.rs:26:12 + | +LL | fn func(_: [(); core::direct_const_arg!(N::)]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0271]: type mismatch resolving `N == _` + --> $DIR/normalize-const-item-type.rs:26:12 + | +LL | fn func(_: [(); core::direct_const_arg!(N::)]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0271`.